hooman-mirghasemi/laravel-iran-sms
Laravel package for integrating Iranian SMS providers into your application. It offers a simple, unified API for sending messages, configurable gateways, and easy setup so you can add SMS notifications, OTP codes, and transactional messaging to Laravel apps.
This release (1.4.2) removes the ghasedak Composer dependency and reimplements every Ghasedak API call inside the package itself. Practically, that means the package is now a self-contained HTTP client wrapper rather than a thin adapter around a vendor SDK — which changes how you install, configure, and especially how you test it.
Minimal steps:
composer require <vendor>/<package> and let Composer drop the transitive ghasedak/* package. Run composer why ghasedak/ghasedak afterwards — it should return nothing. If it still resolves, you have another package (or a stale lock entry) pulling it in.php artisan vendor:publish --tag=<package>-config. Look immediately for the API key, base URL, sender/line-number, and timeout keys. Because the vendor SDK is gone, config values that used to live in the SDK's own config or were hardcoded in it must now come from this file..env and confirm the config file reads them via env() — a common regression when a package inlines an SDK is that the env key name silently changes (e.g. GHASEDAK_API_KEY vs GHASEDAK_KEY).Where to look first, in order:
src/ for the new HTTP client / API class — this is the code that replaced the SDK and is where any behaviour drift will surface.First use case: OTP / verification codes. That is the dominant Ghasedak use case and exercises the send endpoint, the template/pattern parameter, and the response object — enough to validate the rewrite end-to-end.
Notification channel (recommended default). Route transactional messages through Laravel's notification system so the package stays a transport detail. Define a toGhasedak() method (or whatever the channel exposes) on the notification class and keep the sender/line in config, not in the notification.
Facade for imperative sends. For one-off sends outside the notification pipeline (alerts, admin tooling), inject or resolve the package's client and call it directly. Prefer constructor injection over the facade in application code so the call sites are mockable.
Wrap it in your own interface. This release is a good argument for a thin SmsSender interface in your app with a package-backed implementation. The 1.4.2 rewrite is exactly the kind of change that alters exception types and response shapes; an app-level interface means the next transport change is a one-file diff.
Testing with Http::fake(). This is the biggest workflow win from the release. The old vendor SDK used its own HTTP layer, which meant you either hit the network in tests or wrote awkward mocks against SDK internals. Now that the package issues requests through Laravel's HTTP client, you can:
Http::fake([
'*api*' => Http::response(['result' => ['code' => 200, 'message' => 'ok']], 200),
]);
Use Http::preventStrayRequests() in your test suite to guarantee no test escapes to the real API. Assert on the outgoing payload with Http::assertSent() to lock down parameter names (receptor, message, sender/line number, template name) — these are the exact things a from-scratch rewrite is most likely to get subtly wrong.
Queueing. Notifications are queued by default; make sure the channel is queue-safe (no resolving request-scoped state, no reading auth()->user() inside the transport). For high-volume OTP, set a dedicated queue and a timeout shorter than the package's HTTP timeout so failures surface as your job timeout, not a hanging request.
Multi-driver setups. If the package supports driver selection (Ghasedak plus local/log drivers), bind the driver in config per environment and use the log driver in local/CI. Verify the rewrite didn't leave the non-Ghasedak drivers depending on the removed package.
Integration tip — observability. Because the package now owns the HTTP call, you can attach Laravel HTTP client events/middleware globally (logging, timing, correlation IDs) and see SMS traffic in the same place as your other outbound calls. Take advantage of it; you couldn't before.
Treat 1.4.2 as a behavioural change despite the patch version. Removing a dependency and reimplementing every API is a rewrite of the transport layer. Even with an unchanged public API, the following can differ:
Illuminate\Http\Client\RequestException, ConnectionException, or a package-specific exception. Any catch block referencing a Ghasedak\... exception class will now be dead code or a fatal error. Grep your codebase for the vendor namespace — including composer.json require entries and any use statements — before upgrading.Response instances, accessors like $response->getId() may be gone. Check the return type of the send method.->retry() and ->timeout() at your call site or in config; don't assume the old resilience carried over.Config quirks to verify after upgrade. The base URL, HTTP timeout, and sender/line number may have moved out of the deleted SDK's config into the package config. Diff your published config against the new stub (vendor:publish --force into a scratch dir and compare). Also confirm the API key env var name is unchanged — a renamed key fails at runtime with an auth error that looks like a credentials problem, not a config problem.
Silent failures. Ghasedak's API returns HTTP 200 with an error code in the body for many failure modes. Make sure the rewrite interprets the response body, not just the status code. Test explicitly with a faked 200-plus-error-body response and confirm your code treats it as a failure. This is the single most likely regression in a hand-rolled client.
Debugging. Enable the HTTP client's debug output or log the raw response body on failure, but mask the API key — it typically travels in a header or query string and will otherwise land in your logs. During rollout, log the request payload at debug level only, and be aware that SMS bodies frequently contain OTPs and PII.
Rate limits and cost. There's no client-side throttling guarantee in a hand-rolled client. If you send OTPs in bulk, add a RateLimiter or Bus::batch() chunking yourself. A rewrite that drops an SDK also drops any incidental backoff behaviour it had.
Extension points. With the vendor package gone, you have fewer seams but more control. Check whether the client is bound to an interface in the container — if so, you can swap in a decorator for logging, metrics, or a circuit breaker without touching the package. If it's a concrete class with new inside, that's a limitation worth noting. Look for a macroable trait or a Http::globalRequestMiddleware hook as alternatives.
Version pinning. Given this is a full reimplementation shipped as a patch release, pin to ~1.4.2 rather than ^1.0 and upgrade deliberately with tests covering your send path. A rewrite of this scope in a patch version signals the maintainer treats it as an internal detail — reasonable, but it means you should not rely on the patch number to communicate risk.
Rollout checklist for existing installs: grep for the vendor namespace → remove the lock entry → publish/diff config → run the suite with Http::preventStrayRequests() → send one real SMS to a canary number in staging → check failure-path handling with a faked error body → deploy.
How can I help you explore Laravel packages today?