Skip to content

chore(messaging): absorb utopia-php/messaging#67

Merged
loks0n merged 397 commits into
mainfrom
feat/absorb-messaging
Jul 14, 2026
Merged

chore(messaging): absorb utopia-php/messaging#67
loks0n merged 397 commits into
mainfrom
feat/absorb-messaging

Conversation

@loks0n

@loks0n loks0n commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Absorbs utopia-php/messaging with full history via bin/monorepo absorb.

Changes on the way in

  • QA hoisted: pint/phpstan/phpunit deps, QA scripts, library CI workflows removed; mirror.yml PR-redirect + README banner added; mirror ruleset normalised (classic-protection app bypass already applied).
  • Test contract: composer test = network-free unit tier (41 tests); composer test:e2e = host-run against compose services — mailcatcher (11025/11080) and request-catcher (15000). The in-container test runner (Dockerfile + tests compose service) and the 15 provider tests requiring org secrets are deleted, per the storage precedent. The Email Mock adapter gains backward-compatible host/port constructor params so tests can target host-mapped ports.
  • composer.json: unit/e2e script split, prefer-stable, and a direct utopia-php/pools ^1.0 dependency (src uses Utopia\Pools\Adapter\Swoole directly but previously only received pools transitively via client).
  • Bug fix: Discord webhook query string built with http_build_query — multiple params were previously concatenated without &.
  • Rector/pint sweep applied; expectation-less PHPUnit mocks converted to stubs.

Net −3,425 LoC.

⚠️ Merge with a merge commit, never squash — the subtree annotation lives in the import commit.

🤖 Generated with Claude Code

christyjacob4 and others added 30 commits November 8, 2023 22:52
# Conflicts:
#	src/Utopia/Messaging/Adapter/SMS/GEOSMS.php
#	src/Utopia/Messaging/Adapter/SMS/GEOSMS/CallingCode.php
#	tests/Messaging/Adapter/Email/SendgridTest.php
#	tests/Messaging/Adapter/SMS/GEOSMS/CallingCodeTest.php
#	tests/Messaging/Adapter/SMS/GEOSMSTest.php
feat: add sms from override to constructor
Use default false bool sandbox instead of endpoint param
# Conflicts:
#	composer.json
#	composer.lock
#	src/Utopia/Messaging/Adapter/Push/APNS.php
#	src/Utopia/Messaging/Messages/Email.php
#	src/Utopia/Messaging/Messages/Push.php
#	src/Utopia/Messaging/Messages/SMS.php
#	tests/Messaging/Adapter/Email/EmailTest.php
#	tests/Messaging/Adapter/Email/MailgunTest.php
#	tests/Messaging/Adapter/Email/SendgridTest.php
#	tests/Messaging/Adapter/Push/APNSTest.php
#	tests/Messaging/Adapter/Push/FCMTest.php
#	tests/Messaging/Adapter/SMS/GEOSMS/CallingCodeTest.php
#	tests/Messaging/Adapter/SMS/GEOSMSTest.php
#	tests/Messaging/Adapter/SMS/Msg91Test.php
#	tests/Messaging/Adapter/SMS/SMSTest.php
#	tests/Messaging/Adapter/SMS/TelesignTest.php
#	tests/Messaging/Adapter/SMS/TelnyxTest.php
#	tests/Messaging/Adapter/SMS/TwilioTest.php
#	tests/Messaging/Adapter/SMS/VonageTest.php
ChiragAgg5k and others added 23 commits June 16, 2026 08:32
(feat): surface transport error details in FCM push results
Adapter::request() now builds PSR-7 requests via utopia-php/psr7's Request\Factory and sends them through the client's cURL adapter. Adapter::requestMulti() fans out over Swoole coroutines with a bounded Utopia\Client\Pool instead of curl_multi + HTTP/2 multiplexing. Both keep the legacy result array shape so adapters and tests are unaffected.

Also: PHP >= 8.5 and ext-swoole required, Mailgun attachments use multipart Part::file, unused Adapter::getCountryCode() removed along with the libphonenumber dependency, phpstan upgraded to 2.x, and the test image switched to appwrite/utopia-base (ships Swoole, no io_uring).
…rors

APNs only accepts HTTP/2, which Swoole's Coroutine\Http\Client cannot negotiate (connection reset). The requestMulti() pool now uses the client's cURL adapter with CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0; Swoole's native-curl hook (enabled by Coroutine\run and by Appwrite's runtime) keeps sends concurrent per coroutine. APNS error extraction now falls back to the transport error or 'Unknown error' instead of passing null to Response::addResult().
Adapter now takes an optional Psr\Http\Client\ClientInterface (constructor param + setClient(), mirroring the telemetry pattern). Consumers can inject any PSR-18 implementation — pooled/retry-decorated utopia clients, or an in-memory mock for network-free tests. When none is injected, the previous defaults are built internally (HTTP/2 cURL adapter; pooled for requestMulti). The User-Agent moved from client config onto the request so injected clients send the same identity. Injected clients must negotiate HTTP/2 for APNs (documented on the constructor).
… docblock

requestMulti() uses null-coalescing instead of the elvis operator so an explicit empty-array body is still sent; the result shape docblocks now declare error as string since null is never produced.
Adapter now takes (Closure(): ClientInterface)|null $clientFactory (constructor param + setClientFactory()) instead of a single ClientInterface. requestMulti() always pools internally, calling the factory once per pooled connection — so consumers describe how to build one client and the adapter owns concurrency, removing the inject-a-Pool-or-serialize caveat. The pool is consumed via Pools\Pool::use() directly since consumer factories only promise PSR-18, not the streaming interface Utopia\Client\Pool requires.
(feat): replace raw curl transport with utopia-php/client
…f01b933eb7'

git-subtree-dir: packages/messaging
git-subtree-mainline: 1cb61dd
git-subtree-split: 8890c3b
Strip hoisted QA tooling, replace library CI with the mirror redirect
workflow, and normalise composer.json (unit/e2e script split, direct
utopia-php/pools dependency, prefer-stable).

Test contract: unit tier runs network-free (GEOSMS, CallingCode,
Telemetry, SES/Resend routing, SES signing); e2e tier runs host-side
against compose services (mailcatcher 11025/11080, request-catcher
15000). The in-container test runner (Dockerfile, tests service) and
the 15 provider tests requiring org secrets are deleted; the Email
Mock adapter gains host/port constructor params so tests can target
the host-mapped ports.

Fixes on the way in: Discord webhook query string built with
http_build_query (multiple params were previously joined without
'&'); expectation-less mocks converted to stubs (PHPUnit 12 notices).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR absorbs the utopia-php/messaging repository into the monorepo with full git history. The absorb process correctly hoists QA tooling, splits unit/e2e test suites, fixes the Discord webhook query-string bug, and brings the HTTP layer to PSR-18 with Swoole-based concurrent request dispatch.

  • Most adapters are well-implemented: FCM, APNS, SES, SMTP, and Resend all guard against file_get_contents/filesize returning false and support in-memory attachments.
  • Sendgrid (Sendgrid.php): filesize() and file_get_contents() return values are not checked, in-memory content attachments are not handled, and passing false to base64_encode() causes a TypeError on PHP 8.5+.
  • Mailgun (Mailgun.php): the same filesize() omission silently allows oversized attachments to bypass the size guard; in-memory content attachments are not handled; the truncated exception message is missing the limit value.

Confidence Score: 4/5

Safe to merge pending fixes to Sendgrid and Mailgun attachment handling.

The Sendgrid adapter passes the raw false return of file_get_contents() directly into base64_encode(), which is a TypeError on PHP 8.5 (the minimum required version). The Mailgun adapter silently treats an unreadable file as 0 bytes and truncates its own error message. Every other adapter in the PR handles these cases correctly, making these two outliers clearly unintentional gaps.

Sendgrid.php and Mailgun.php: both attachment-handling paths need filesize() false-return guards, in-memory content checks, and (for Sendgrid) a file_get_contents() false-return guard.

Important Files Changed

Filename Overview
packages/messaging/src/Utopia/Messaging/Adapter/Email/Sendgrid.php Does not handle in-memory attachments and does not check whether filesize() or file_get_contents() return false, causing a TypeError on PHP 8.5+ when an attachment file is unreadable
packages/messaging/src/Utopia/Messaging/Adapter/Email/Mailgun.php Attachment handling has two bugs: filesize() return value not checked (false coerces to 0, silently breaking the size guard), and the exception message for oversized attachments is incomplete
packages/messaging/src/Utopia/Messaging/Adapter/Push/FCM.php Token response is now properly guarded before access; looks correct
packages/messaging/src/Utopia/Messaging/Adapter/Push/APNS.php process() correctly declared protected; JWT and requestMulti usage look correct
packages/messaging/src/Utopia/Messaging/Adapter.php Core adapter with PSR-18 HTTP, Swoole requestMulti, telemetry; $bodyCount > 0 guard prevents empty-bodies padding crash
packages/messaging/src/Utopia/Messaging/Adapter/Email/SES.php Hand-rolled SigV4 signing, template-based bulk send, proper attachment size checks with false-return guards
packages/messaging/src/Utopia/Messaging/Adapter/Email/SMTP.php Correctly checks file_get_contents and filesize return values for false; handles in-memory content attachments
packages/messaging/src/Utopia/Messaging/Adapter/Chat/Discord.php Query-string construction fixed to use http_build_query; URL validation is thorough
packages/messaging/src/Utopia/Messaging/Adapter/Email/Resend.php Properly handles both in-memory and file-path attachments; batch vs. individual send routing is clear
packages/messaging/composer.json Unit/e2e test split, PHP 8.5+, direct utopia-php/pools dependency added

Reviews (2): Last reviewed commit: "fix(messaging): address review findings" | Re-trigger Greptile

Comment thread packages/messaging/src/Utopia/Messaging/Adapter/Push/FCM.php
Comment thread packages/messaging/src/Utopia/Messaging/Adapter/Email/SMTP.php
Comment thread packages/messaging/src/Utopia/Messaging/Adapter/Push/APNS.php Outdated
Comment thread packages/messaging/src/Utopia/Messaging/Adapter.php
- FCM: throw a meaningful exception when the Google token request
  fails instead of fataling on a null response
- SMTP: check filesize/file_get_contents for false before use
  (matches the SES pattern)
- APNS: process() protected like every other adapter
- Adapter: requestMulti no longer reads bodies[0] when bodies is empty

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@loks0n loks0n merged commit 7d07309 into main Jul 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.