From e79c2a94720ab05f2bda471325f35b7d1d2c9b76 Mon Sep 17 00:00:00 2001 From: evgeny Date: Fri, 18 Sep 2026 09:21:13 +0100 Subject: [PATCH] Rename AblyRest to PubSubHttpClient PDR-091d renames the client class so it states what it is rather than repeating the vendor name. This is the last public-API change before the 2.0.0 integration branch merges, and the only one that touches consumers' type hints and DI bindings. src/AblyRest.php moves to src/PubSubHttpClient.php to preserve the PSR-4 file/class mapping, and the two test classes follow; every use statement, type hint and docblock in src/ and tests/ is updated, so Server::createHttpClient() now returns \Ably\PubSub\PubSubHttpClient. The rest-prefixed ClientOptions keys are deliberately left alone: restHost and idempotentRestPublishing are cross-SDK spec names (RSC11, TO3n), and renaming them would leave PHP the only SDK spelling them differently. CHANGELOG gains a breaking-change entry; UPDATING.md gains a mapping row and loses its draft banner now the naming is settled. plan.md goes too: it sequenced the split work, which this commit completes. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 3 +- UPDATING.md | 12 +- plan.md | 207 ------------------ src/Auth.php | 6 +- src/Channel.php | 4 +- src/Channels.php | 4 +- src/Http.php | 2 +- src/Models/HttpPaginatedResponse.php | 6 +- src/Models/PaginatedResult.php | 4 +- src/Presence.php | 4 +- src/{AblyRest.php => PubSubHttpClient.php} | 10 +- src/Push.php | 4 +- src/PushAdmin.php | 4 +- src/PushChannelSubscriptions.php | 4 +- src/PushDeviceRegistrations.php | 4 +- src/Server.php | 4 +- tests/AppStatsTest.php | 4 +- tests/AuthTest.php | 48 ++-- tests/ChannelHistoryTest.php | 4 +- tests/ChannelIdempotentTest.php | 6 +- tests/ChannelMessagesTest.php | 12 +- tests/ChannelStatusTest.php | 4 +- tests/ClientIdTest.php | 40 ++-- tests/HttpTest.php | 22 +- tests/LogTest.php | 10 +- tests/PresenceTest.php | 4 +- ...st.php => PubSubHttpClientRequestTest.php} | 6 +- ...yRestTest.php => PubSubHttpClientTest.php} | 60 ++--- tests/PushAdminTest.php | 4 +- tests/PushChannelSubscriptionsTest.php | 4 +- tests/PushDeviceRegistrationsTest.php | 4 +- tests/TokenTest.php | 14 +- tests/TypesTest.php | 2 +- tests/factories/TestApp.php | 2 +- 34 files changed, 162 insertions(+), 370 deletions(-) delete mode 100644 plan.md rename src/{AblyRest.php => PubSubHttpClient.php} (98%) rename tests/{AblyRestRequestTest.php => PubSubHttpClientRequestTest.php} (93%) rename tests/{AblyRestTest.php => PubSubHttpClientTest.php} (92%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07ab5bd..f300625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,8 @@ the full mapping table. **Breaking changes:** - The package is now `ably/pubsub-server`, installed with `composer require ably/pubsub-server`. `ably/ably-php` is superseded and receives security and critical-bug fixes only for one year from this release, from the `maintenance/1.x` branch. -- The namespace is now `Ably\PubSub\`. Every class keeps its name, so `Ably\Models\Message` becomes `Ably\PubSub\Models\Message`. +- The namespace is now `Ably\PubSub\`. Every class other than the client keeps its name, so `Ably\Models\Message` becomes `Ably\PubSub\Models\Message`. +- The client class `Ably\AblyRest` is now `Ably\PubSub\PubSubHttpClient` ([PDR-091d](https://ably.atlassian.net/wiki/spaces/product/pages/5363957781)). Applications that only construct through `Server::createHttpClient()` are unaffected; type hints and DI bindings naming the class must be updated. - Clients are constructed through `Ably\PubSub\Server::createHttpClient()`, which declares the server side on the wire. It accepts everything the constructor accepted: an options array, an API key string, a token string, or a `ClientOptions` instance. A client constructed directly declares no side, and is rejected on accounts with monthly-active-user pricing enabled. - Removed `AblyRest::setAblyAgentHeader()` and `AblyRest::setLibraryFlavourString()`, replaced by the per-client `agents` client option. - Removed `ably-loader.php`; Composer's autoloader is the only supported install path. diff --git a/UPDATING.md b/UPDATING.md index 53dbfce..f669df4 100644 --- a/UPDATING.md +++ b/UPDATING.md @@ -2,13 +2,11 @@ ## 1.x (`ably/ably-php`) → 2.0.0 (`ably/pubsub-server`) -> **Status: draft.** The final public API naming is still under review; [PDR-091d](https://ably.atlassian.net/wiki/spaces/product/pages/5363957781) may rename `AblyRest` to `HttpClient` before the 2.0.0 GA release. This section will be finalized before GA. - Version 2.0.0 ships from a new package, `ably/pubsub-server`, under a new namespace, `Ably\PubSub\`. `ably/ably-php` is superseded: it receives security and critical-bug fixes only for one year from the 2.0.0 release date, and is then end-of-life. Under monthly-active-user pricing the platform has to classify every connection as device-side or server-side. The new package declares that automatically, on every request, in the `Ably-Agent` header; the old constructor cannot declare anything. That is the forcing function for this migration: once monthly-active-user pricing is live, `new Ably\AblyRest(...)` from `ably/ably-php` is rejected on accounts where it is enabled. -The client `Server::createHttpClient()` returns is the same REST client as before. Channels, message publishing, history, presence, authentication, push admin, crypto and every `ClientOptions` key behave exactly as they did in 1.x. For most applications the migration is confined to the `composer require` line, the `use` statements, and the constructor call. +The client `Server::createHttpClient()` returns is the same REST client as before, renamed from `AblyRest` to `PubSubHttpClient`. Channels, message publishing, history, presence, authentication, push admin, crypto and every `ClientOptions` key behave exactly as they did in 1.x. For most applications the migration is confined to the `composer require` line, the `use` statements, and the constructor call. ### Mapping @@ -21,9 +19,9 @@ The client `Server::createHttpClient()` returns is the same REST client as befor | `AblyRest::setLibraryFlavourString('x')` | removed — use the `agents` option | | `require 'ably-loader.php';` | removed — use Composer's autoloader (`vendor/autoload.php`) | | PHP 7.2 – 8.0 | PHP `^8.1` (tested on 8.1 – 8.5) | -| ⚠️ [091d](https://ably.atlassian.net/wiki/spaces/product/pages/5363957781): `\Ably\AblyRest` type hints | `\Ably\PubSub\HttpClient` (not yet decided) | +| `\Ably\AblyRest` type hints | `\Ably\PubSub\PubSubHttpClient` ([091d](https://ably.atlassian.net/wiki/spaces/product/pages/5363957781)) | -Every class moves namespace and keeps its name, so the rename is mechanical: replace the prefix `Ably\` with `Ably\PubSub\` throughout, including in type hints, `catch` blocks and fully-qualified string class names. +Every class moves namespace, and `AblyRest` is the only one that also changes name, so the rename is mechanical: replace the prefix `Ably\` with `Ably\PubSub\` throughout — including in type hints, `catch` blocks and fully-qualified string class names — and then `AblyRest` with `PubSubHttpClient`. ### Example @@ -45,7 +43,7 @@ $ably->channel('test-channel')->publish('test-event', 'hello world'); ### Declaring the side -Construct through the door. `new Ably\PubSub\AblyRest(...)` still works — the library and its own tests use it — but it declares no side, and will be rejected on monthly-active-user-enabled accounts just as the 1.x constructor is. The door produces: +Construct through the door. `new Ably\PubSub\PubSubHttpClient(...)` still works — the library and its own tests use it — but it declares no side, and will be rejected on monthly-active-user-enabled accounts just as the 1.x constructor is. The door produces: ``` Ably-Agent: ably-pubsub-php/2.0.0 php/8.3.4 ably-pubsub-server @@ -72,7 +70,7 @@ The `agents` option is per-client, unlike the process-global static setters it r * The `demo/` Heroku application and its `Procfile`. * PHP 7.2 – 8.0 support. -`Auth::authorise()`, the British-spelling alias deprecated in favour of `Auth::authorize()`, is still present in 2.0.0. It may be removed in the 091d pass before GA. +`Auth::authorise()`, the British-spelling alias deprecated in favour of `Auth::authorize()`, is still present in 2.0.0. ### Unchanged diff --git a/plan.md b/plan.md deleted file mode 100644 index aec7352..0000000 --- a/plan.md +++ /dev/null @@ -1,207 +0,0 @@ -# ably-php → ably-pubsub-php: PubSub package split plan - -Execution plan for applying PDR-091b (PubSub package split, major releases) to the PHP SDK. - -**Sources of truth:** -- [PDR-091: SDK naming and MAU classification](https://ably.atlassian.net/wiki/spaces/product/pages/5220106242) — parent, DECIDED IN PRINCIPLE. Device/server split, factory doors, the agent header as the declaration mechanism. Names `ably-php → ably-pubsub-php` explicitly as a rename-in-place repo. -- [PDR-091b companion: PubSub package split (major releases)](https://ably.atlassian.net/wiki/spaces/product/pages/5362810886) — DECIDED. New majors on a new core, not thin wrappers; repo renames; old packages "not touched at all" and EOL after one year. Names the PHP-specific publishing rebind: "Packagist (ably-php) — GitHub webhook/App install tied to the repo; needs re-pointing." -- [PDR-091b2: Per-SDK rollout plan v2](https://ably.atlassian.net/wiki/spaces/product/pages/5348425729) — IN REVIEW. PHP section, verbatim: "Repo: ably-php → ably-pubsub-php. New package: `ably/pubsub-server`. Factory door: `createHttpClient(...)` only." Owner field is blank. **No core package is named for PHP** — the only SDK row without one (see step 1). The agent-identifier convention (per-language family rename + cross-SDK versionless side flags) is Umair's footer comment on this page (2026-09-02). -- [PDR-091c companion: high-level SDKs stay unified](https://ably.atlassian.net/wiki/spaces/product/pages/5363499015) — DECIDED. PHP has two Ably-owned wrapper packages, `ably/ably-php-laravel` and `ably/laravel-broadcaster`; they stay unified, ship a new major depending on the new package, and construct through the door (step 27). -- [PDR-091d companion: public API renaming](https://ably.atlassian.net/wiki/spaces/product/pages/5363957781) — **IN REVIEW** (steps marked ⚠️091d are conditional on it being decided). Names `AblyRest → HttpClient` explicitly. -- [SDK device/server split — step sequence doc](https://docs.google.com/document/d/1r96vOSOft1yT84NxbdpCh0IomTwzIpKskQ-wA5e28M0) — the 12-step order this plan follows. -- Reference implementations: [ably-js#2293](https://github.com/ably/ably-js/pull/2293) (split, MERGED to `integration/v3`), [#2294](https://github.com/ably/ably-js/pull/2294) (UTS per side), [#2296](https://github.com/ably/ably-js/pull/2296) (lockstep release), [#2297](https://github.com/ably/ably-js/pull/2297) (versionless side flags + `ably-pubsub-js` identifier); [ably-ruby#453/#454/#455/#457](https://github.com/ably/ably-ruby/pulls) and `Git/ably-ruby/plan.md`; [ably-python#683/#684/#685/#686/#682](https://github.com/ably/ably-python/pulls) and `Git/ably-python/plan.md` (server-only siblings; Python's `ably_pubsub` namespace decision is the closest analogue to PHP's, step 2). Also ably-dotnet#1333–1335 and ably-java#1232–1235 for the door/agent shape. -- Agent registry: [ably-common#361](https://github.com/ably/ably-common/pull/361) — **OPEN** as of 2026-09-09. Registers `ably-pubsub-server`/`ably-pubsub-device` (versionless flags, `type: runtime`) and `ably-pubsub-php` (versioned `sdk`, `source: https://github.com/ably/ably-php` — update the source to the renamed repo before or after merge). Today's registry has `ably-php` only, plus the wrapper entries `ably-php-laravel` and `laravel-broadcaster`. -- Infra prerequisite: [infrastructure#13005](https://github.com/ably/infrastructure/pull/13005) — **MERGED 2026-09-01**; `ably-sdk-builds-ably-pubsub-php` IAM role exists (the `ably-php` role stays). [infrastructure#13054](https://github.com/ably/infrastructure/pull/13054) added the ID-qualified OIDC subject. -- Already open in this repo: [ably-php#222](https://github.com/ably/ably-php/pull/222) (`pubsub-split/rename-references` → `main`) — `features.yml` repository-name + README licence link. **Merge only in the rename freeze window** (step 17). There is no prior thin-wrapper PR to close (unlike ably-python#681 / ably-js#2291). - -**What PHP ships (per PDR-091b2):** PHP is a **server-only, REST-only** SDK (no realtime client exists; the README points realtime users at the MQTT adapter). One new public Composer package, **`ably/pubsub-server`**, with a single factory door, **`createHttpClient(...)`**. No device package, no realtime door. Repo renamed `ably-php → ably-pubsub-php` (direct rename — Packagist identity is the `vendor/name` in `composer.json`, not the repo URL, so the ably-go/ably-cocoa copy-first exception does not apply). Today's `ably/ably-php` package (currently 1.1.12) enters a 1-year maintenance window, then EOL. - -**Current repo facts the plan relies on (verified 2026-09-09):** -- Single flat package: `composer.json` `name: ably/ably-php`, PSR-4 `Ably\\ → src/`, `tests\\ → tests/`; 3.3k lines in `src/`, 28 test files. No `composer.json` version field — Packagist derives versions from git tags (`1.1.12`, no `v` prefix). **The only version site is `Defaults::LIB_VERSION`** (`src/Defaults.php:6`). -- Requires `php: ^7.2 || ^8.0`; CI matrix tests 7.2–8.4 × JSON/msgpack (`check.yml`). PHP 7.x and 8.0 are EOL upstream. -- Agent string is built in one place, `AblyRest::ablyAgentHeader()` (`src/AblyRest.php:37`): `ably-php/ php/` plus entries from a **static, process-global** `AblyRest::$agents` map set via `AblyRest::setAblyAgentHeader($name, $version)` (and the `@deprecated` `setLibraryFlavourString`). Sent as `Ably-Agent` from `src/AblyRest.php:187`. **There is no per-client `agents` option.** `tests/HttpTest.php:52-85` asserts the exact current shape (RSC7d), including the `laravel customLib/2.3.5` static-append form. -- Both Laravel wrappers rely on the static setter: `ably-php-laravel` calls `AblyRest::setAblyAgentHeader('laravel', $laravelVersion)` then `new AblyRest(config('ably'))`; `laravel-broadcaster` sets `laravel-broadcaster/` and `laravel/` the same way and type-hints `\Ably\AblyRest` in `AblyBroadcaster::__construct`. They require `ably/ably-php: ~1.1.9` and `^1.1` respectively. -- Publishing today is **manual and tag-driven**: bump `LIB_VERSION`, update `CHANGELOG.md`, push tag, create a GitHub release; Packagist auto-updates via the legacy repo webhook `https://packagist.org/api/github?username=ably` (`push` events). There is **no release workflow** and no trusted publishing concept on Packagist. Packagist maintainer account: `ably`. `ably/ably-php` has ~8.7M total / ~387k monthly downloads. -- `features.yml` uploads via `ably/features` with `repository-name` (already `ably-pubsub-php` on PR #222's branch). No docs workflow. -- Non-Composer extras that carry the old identity: `ably-loader.php` (hand-rolled autoloader for `Ably\`), `demo/index.php` + `Procfile` (Heroku demo using `new \Ably\AblyRest`), `ably-common` submodule at the repo root (test fixtures). -- Known `@deprecated` surface today: `Auth::authorise` (→ `authorize`), `AblyRest::setLibraryFlavourString`. No `endpoint` client option exists yet (ADR-119 was never applied to PHP), so `restHost`/`environment` are **not** deprecated here and are not deletion candidates. -- Packagist names: `ably/pubsub-server` (and `ably/pubsub-core`) do not exist. Packagist has **no name reservation**; a package exists once it is submitted against a repository whose default branch `composer.json` carries that name. -- **Packagist mechanics, verified against the composer/packagist and composer/composer sources (2026-09-09):** - - Uniqueness is by **package name only** (`UniquePackageValidator` → `findOneByName`). Two Packagist packages may point at the same repository URL. The name is read from the default branch's `composer.json` at submission (`Package::setRepository` → `getComposerInformation(getRootIdentifier())`). - - **There is no name-based filtering of versions.** Composer's `VcsRepository::preProcess` deliberately overwrites every tag's and branch's `name` with the default branch's name ("this ensures that a package can be renamed in one place and that all old tags will still be installable using that new name"), and Packagist's `Updater` then stamps its own package name on every version. Consequence: **every Packagist package bound to a repository indexes every Composer-valid tag and every branch of that repository, whatever their `composer.json` says.** Tags whose name is not a valid version (e.g. `pubsub-server/2.0.0`) are skipped ("Skipped tag …, invalid tag name"). - - Repository renames are handled: the GitHub webhook resolves a package by URL first, then by the stored GitHub repository ID (`remoteId`), and on an ID match **rewrites the stored URL and schedules a full re-crawl** (`ApiController::findGitHubPackagesByRepository`). The updater also refreshes the URL from the driver. So auto-update does **not** silently stop at a rename; editing the URL by hand is optional (and `PopularPackageSafetyValidator` allows it for a same-ID rename even on a package with >50k downloads). Re-pointing a >50k-download package at a *different* repository is blocked for maintainers and needs Packagist support; a crawl that finds a different repository ID **freezes** the package (`RemoteIdMismatch`). - - Maintainers can delete individual versions (`delete_version`); maintainer-pulled rows stay deleted across re-crawls. Maintainers can mark a package **abandoned with a replacement package**, which Composer prints on every install. - ---- - -## Phase 0 — Decisions and prerequisites (before writing code) - -1. **Packaging shape on Packagist — ONE published package, `ably/pubsub-server`, no `ably/pubsub-core`, published from a read-only distribution mirror.** This is the PHP-specific fork from the pattern, and PDR-091b2 already lists only `ably/pubsub-server` for PHP; record the reasoning in the b2 PHP section so it is a decision rather than an omission: - - **Why no core:** a core buys nothing in PHP — there is no device package to share it with, and PHP cannot re-export types (no `export … from`, only `class_alias`), so a separate core would force consumers to type-hint `Ably\PubSub\Core\Models\Message` from a package whose description says "do not depend on this". The high-level consumers (the two Laravel wrappers, PDR-091c) can depend on `ably/pubsub-server` directly: 091c's reason for depending on core types — not picking a side — does not arise when there is exactly one side. Each extra Composer package is also an extra mirror repo (below). - - **Why a mirror:** Packagist indexes **every** Composer-valid tag and branch of a repository under **every** package bound to that repository, ignoring the `composer.json` name (verified, see repo facts). If `ably/pubsub-server` were registered against this repo, it would serve `1.1.12` (old namespace, old name) as an installable version; and `ably/ably-php` would serve `2.0.0` (new namespace) as its latest — any `ably/ably-php: *` or `>=1.1` consumer would upgrade into a broken install. Neither can be prevented by naming or by the updater; only by maintainers deleting versions by hand after every release. So the two packages **cannot share a repository**, and the legacy package must stay on this repository (its ~8.7M downloads put it behind `PopularPackageSafetyValidator`, so its URL cannot be moved to a different repository without Packagist support, and a repo-ID change would freeze it). Therefore: - - `ably/ably-php` stays bound to this repo (renamed to `ably-pubsub-php`; Packagist follows the rename by repository ID). It keeps indexing `1.x` tags from `maintenance/1.x`. - - `ably/pubsub-server` is bound to a **read-only distribution mirror repo**, e.g. `ably/ably-pubsub-php-dist` (name is the owner's call; it is a build artifact, not a development repo, so PDR-091's "repo names never carry side" does not apply, and its README says "read-only mirror — develop and file issues at ably-pubsub-php"). `release.yml` pushes the release commit and the `2.0.0` tag there (step 15). No subtree split is needed because the package is the whole repo; the mirror is a plain push of `main` at the release commit. - - **Release tags in this repo must not be Composer-valid versions**, or `ably/ably-php` indexes them. Use a namespaced tag, `pubsub-server/2.0.0`, for the GitHub release and CHANGELOG compare links here; the plain `2.0.0` tag exists only on the mirror. Composer skips the namespaced tag as an invalid version name (`VcsRepository::validateTag`). - - Rejected alternatives: register both packages on this repo and prune versions by hand after every release (a window on every release where `composer require ably/ably-php` resolves to 2.x, and ongoing toil); move the legacy package to a mirror of `maintenance/1.x` instead (needs Packagist support because of the download threshold, changes the repo ID, and puts the high-traffic package on the moving part); the ably-go/ably-cocoa copy-under-old-name route (a new repo at `ably/ably-php` would destroy GitHub's redirects and the legacy Packagist entry would resolve to a repo with a different ID and be frozen). - - **Surface this to the programme:** PDR-091b states registry identity "is not tied to the repo URL" for Packagist. Identity is not, but *version discovery* is — every tag of the repo belongs to every package on it — which is why PHP needs the mirror. Add it to the b2 PHP row so no one plans a second Composer package from this repo later. -2. **PHP namespace — recommend `Ably\PubSub\`.** The legacy package owns the PSR-4 prefix `Ably\` → `src/`. Composer installs `ably/ably-php` and `ably/pubsub-server` side by side (a Laravel app mid-migration, or a transitive dependency still on 1.x), and if both declared `Ably\` the autoloader would resolve `Ably\AblyRest` to whichever prefix path is searched first — a silent mismatch, and PDR-091b also says the old package is "not re-exported or reused". So the new package uses a distinct root: implementation and public types under **`Ably\PubSub\`** (`Ably\PubSub\Models\Message`, `Ably\PubSub\Models\ClientOptions`, …), the door at **`Ably\PubSub\Server`**. Rejected: keeping `Ably\` (clobbers the legacy package); `Ably\PubSub\Core\` for the implementation (the types are public surface in PHP whether we like it or not, and "Core" in every consumer's `use` line contradicts "internal"). Record in PDR-091b2. -3. **Factory-door surface** — record it in PDR-091b2 and fill in the blank Owner field. Proposal, matching the agreed door name in PHP idiom: - - `Ably\PubSub\Server::createHttpClient(array|string|ClientOptions $options): \Ably\PubSub\AblyRest` (⚠️091d: returns `HttpClient`). Accepts exactly what the constructor accepts today — an options array, a `ClientOptions`, or a bare key/token string (reuse the constructor's `strpos(':')` disambiguation rather than duplicating it). - - Only door. No `createRealtimeClient` (no realtime client exists) and no device door. Say so explicitly in b2 so nobody expects a stub. - - The client constructor stays public (a `final` static door with a private constructor is not idiomatic for a class other Ably code and tests construct), but is marked `@internal` with a docblock pointing at the door, and the README/docs never show it. Consequence to state in the guide: a bare `new AblyRest(...)` from the new package sends no side flag and will be rejected on MAU accounts once pricing is live. -4. **New major version — `2.0.0`.** Current is 1.1.12. Tags keep the repo's existing no-`v` convention (`2.0.0`, `2.0.0-rc1`). Composer treats `-rc1`/`-beta1` as non-stable, so `composer require ably/pubsub-server` never resolves a prerelease unless `minimum-stability` allows it. Single package, so "lockstep" reduces to one tag and one version site. -5. **PHP floor — recommend `php: ^8.1`** for the new package, CI matrix 8.1–8.5 (8.5 is current; `curl_close` deprecation fix already in 1.1.12). 7.2–8.0 are EOL and Laravel 10+ requires 8.1; a major is the only place to raise this. Keep `rybakit/msgpack`, `ext-json`, `ext-curl`, `ext-openssl`. Modern-PHP cleanups (typed properties, `readonly`, enums) are **not** in scope — this is a repackaging, not a rewrite. Owner's call; if they want to keep 7.x support, that is a one-line change in `composer.json` and the matrix. -6. **⚠️091d — build on current names, rename last.** Phases 2–5 use `AblyRest`/`Channel`/`Presence`; if PDR-091d is approved, the new package ships `HttpClient` (and the owner decides whether `Channel`/`Channels`/`Presence` become `HttpChannel`/`HttpChannels`/`HttpPresence` for cross-SDK consistency — PHP never had a `Rest` prefix on them) and the deprecated surface is deleted rather than ported — as one final mechanical PR (Phase 6, step 18). -7. **Register the agent identifiers.** Both strings PHP will send must be in the ably-common registry before any prerelease ships them: the versionless side flag `ably-pubsub-server` and the versioned family identifier `ably-pubsub-php`. Both are in ably-common#361 (OPEN) — track it to merge; if it stalls, split the PHP entries into their own PR. Ask for the `ably-pubsub-php` `source` to be the renamed URL. The `-server` suffix is load-bearing: realtime grants the MAU server exemption on API-key auth by matching an agent entry ending in `-server`. Then bump the `ably-common` submodule pin in this repo. The wrapper identifiers `laravel`, `laravel-broadcaster`, `ably-php-laravel` are secondary identifiers and keep their names. -8. **Get the MAU pricing release date** from the [MAU pricing release plan (DRAFT, 2026-08-27)](https://ably.atlassian.net/wiki/spaces/PRICE/pages/5315690510) / project hub — it drives the GA target and the forcing-function messaging in the migration guide. -9. **Packagist account and mirror-push credentials.** Confirm who holds the `ably` Packagist account (1Password / SDK team) — it is needed to submit `ably/pubsub-server` against the mirror (step 15c), to pull `dev-main` from the legacy package (step 22), and to mark the legacy package abandoned at EOL (step 26). Confirm the webhook secret on this repo's Packagist hook is that account's API token (it survives the rename; the hook is repo-bound). Create the mirror repo and a credential that lets `release.yml` push to it (a GitHub App installation or a fine-grained PAT scoped to the mirror, stored as a repo secret here — the default `GITHUB_TOKEN` cannot push cross-repo). Set the mirror up with the same Packagist webhook. - -## Phase 1 — Open the integration branch - -10. Create a long-lived **`integration/v2`** branch off `main` (ably-ruby uses `integration/v2` for the same bump; ably-js `integration/v3`, ably-python `integration/v4`). All split work lands there as **stacked PRs**; nothing ships from it until Phase 7. Apply the same branch protection/required checks as `main`. `check.yml` and `features.yml` trigger on `pull_request` regardless of base so PRs into the integration branch get CI for free; add `integration/v2` to their `push:` branch lists so the merged state is also checked. -10b. **The PR stack.** Mirror ably-ruby (#453 → #454; #455/#457 straight to `main`) and ably-python (#683 → #684 → #686; #685/#682 to `main`): each PR is based on the one before it so they review independently and merge in order into `integration/v2`; the workflow/rename PRs go to `main` directly because they must exist on the default branch to be useful. Branch names `pubsub-split/`. - - | # | Branch | Base | Contents | Plan steps | - | --- | --- | --- | --- | --- | - | 1 ([#223](https://github.com/ably/ably-php/pull/223)) | `pubsub-split/restructure` | `integration/v2` | `composer.json` (name, PSR-4 `Ably\\PubSub\\`, php floor), namespace move `Ably\` → `Ably\PubSub\` across `src/` and `tests/`, `Server::createHttpClient` door, per-client `agents` option + family identifier rename + side stamping, agent assertions, packaging-invariant tests, delete `ably-loader.php`/`demo/`/`Procfile` | 11, 12, 13, 14, 14b, 14c | - | 2 ([#225](https://github.com/ably/ably-php/pull/225)) | `pubsub-split/release-tooling` | PR 1's branch | `release.yml` (dispatch, pre-flight, mirror push + `2.0.0` tag, namespaced tag + GitHub release here, Packagist visibility poll), `release-dry-run` job in `check.yml`, `CONTRIBUTING.md` release section, `.gitattributes` export-ignore | 15, 15b, 15c | - | 3 ([#226](https://github.com/ably/ably-php/pull/226)) | `pubsub-split/release-workflow-on-main` | **`main`** | cherry-pick of PR 2's `release.yml` only, so `workflow_dispatch` is registered while the split still lives on `integration/v2`. Pre-flight refuses a ref whose `composer.json` is still `ably/ably-php`, so it is inert on `main`. **Merge precondition: the 1.x maintenance branch (step 24) is cut first** | 15b, 24 | - | 4 ([#222](https://github.com/ably/ably-php/pull/222)) | `pubsub-split/rename-references` | **`main`** | `features.yml` repository-name, README licence link; merged in the rename freeze window, then merged forward into `integration/v2` | 17 | - | 5 ([#224](https://github.com/ably/ably-php/pull/224)) | `pubsub-split/docs` | PR 2's branch | README rewrite, `UPDATING.md` 1.x→2.0 migration section, `CHANGELOG.md` 2.0.0 entry | 19, 20 | - | 6 | `pubsub-split/api-rename` (⚠️091d) | PR 5's branch | `AblyRest`→`HttpClient` etc., deprecated-surface deletions, test/doc updates — opened only once 091d is decided | 18 | - - Rules for the stack: PR 1's namespace move is a mechanical `sed` over ~60 files — keep it in its own commit, separate from the door/agent commits, so reviewers can diff behaviour without the noise (ably-python's "pure move, no behaviour" commit rule). Each PR's description links the plan step it implements. When a lower PR merges into `integration/v2`, retarget the next one. Merge `main` into `integration/v2` after PRs 3 and 4 land. Periodically merge `main` forward so the integration branch never drifts far from released fixes. - -## Phase 2 — Repo restructure: the `ably/pubsub-server` package - -11. **Re-identify the package** — same flat layout, new identity: - ``` - composer.json # name: ably/pubsub-server; description names the door and says "for servers"; - # php ^8.1; autoload psr-4 "Ably\\PubSub\\": "src/"; autoload-dev "tests\\": "tests/" - src/ - Server.php # the door: Ably\PubSub\Server::createHttpClient() - AblyRest.php … # today's src/**, namespace Ably\ → Ably\PubSub\ (⚠️091d renames land in Phase 6) - Defaults.php # LIB_VERSION = '2.0.0' — still the only version site - tests/ # namespace tests\ unchanged; `use Ably\…` → `use Ably\PubSub\…` - ably-common/ # submodule stays (test fixtures) - ``` - - No `core/`/`server/` directory split: with one Composer package it would be cosmetic (Packagist needs `composer.json` at the root), and it would make the `git mv` diff larger for no packaging gain. If step 1's fallback (a published core) is ever taken, the split can be introduced then. - - Delete `ably-loader.php` (hand-rolled autoloader; Composer is the only supported install path and the README already says so), `demo/` and `Procfile` (unmaintained Heroku demo). List them in the migration guide as removed. - - `keywords` gain `pubsub`, `server`; `homepage` stays; add `support.source` pointing at this repo (not the mirror) so `composer info` sends people to the development repo. `composer validate --strict` must pass (add `--strict` to CI — today it is plain `composer validate`). - - Add a `.gitattributes` with `export-ignore` for `tests/`, `ably-common/`, `.github/`, `phpunit.xml`, `plan.md` — Packagist dist archives are GitHub zipballs and honour it, so consumers stop downloading the test suite and submodule. -12. **Implement the door in `src/Server.php`:** - - `Server::createHttpClient($options)`: normalise the argument exactly as the constructor does (string → `['key'=>…]`/`['token'=>…]`, `ClientOptions` instance passed through), merge the side entry into `agents` (step 13), construct and return the client. Nothing else — it is a door, not a room. - - `final class Server` with a private constructor and the single static method; a `SERVER_AGENT_IDENTIFIER = 'ably-pubsub-server'` constant carrying the suffix-is-load-bearing comment copied in spirit from ably-ruby's `server.rb` / ably-python's `server/__init__.py`. - - Docblock: the two-sentence "servers are trusted environments, exempt from MAU counting; this package names that side" statement the siblings use, so the generated API docs say the same thing in every language. -13. **Agent plumbing.** Rework the static header to match the ably-js contract (`packages/shared/side.ts` / `getAgentString`) and the convention in ably-common#361: - - Add an additive **`agents` client option** (`ClientOptions::$agents`, `array`). `ablyAgentHeader()` becomes an instance method reading `$this->options->agents`, rendering each entry as `name/version`, or a bare `name` when the value is `null` or `''` (a flag, like `browser`). Single seam: `src/AblyRest.php:187` is the only place the header is sent. - - **Remove the static `$agents` map, `setAblyAgentHeader()` and the deprecated `setLibraryFlavourString()`.** Process-global mutable state that leaks between client instances is the wrong shape for a per-client declaration, and the only callers (the two Laravel wrappers) are being re-released on this package anyway (step 27). `setAblyAgentHeader` is not currently deprecated, so this is a stated owner decision, not a silent drop — record it in the b2 PHP section and the deletion list (step 18) with this reason. - - Rename the family identifier `ably-php` → **`ably-pubsub-php`** (versioned with `LIB_VERSION`) — on the integration branch, before any prerelease, so even prerelease traffic partitions cleanly from legacy `ably-php/*` traffic. The maintenance branch keeps `ably-php`. - - The door appends `ably-pubsub-server => null`. Target wire shape: `ably-pubsub-php/2.0.0 php/8.3.4 ably-pubsub-server`; with a wrapper: `ably-pubsub-php/2.0.0 php/8.3.4 ably-pubsub-server laravel/11.0.0 laravel-broadcaster/1.0.4`. - - The side entry is applied last and wins any collision on its own identifier — the side is the package's to declare, not the caller's. Caller-supplied `agents` entries are preserved in order. - - Keep `.ably/capabilities.yaml`'s `Agent Identifier: Agents:` (already declared; now true per-client rather than per-process). - -## Phase 3 — Tests and conformance - -14. Rework the test suite to the new namespace (`use Ably\PubSub\…`), keep the matrix green on the new floor (8.1–8.5 × JSON/msgpack), and run the full sandbox suite (`TestApp` against `ABLY_ENV=sandbox`) from the integration branch. PHP has no UTS, so the existing PHPUnit suite is the conformance pass. Update the `features.yml` job only if `ably/features` needs the new layout (it reads `.ably/capabilities.yaml`, which is unchanged). -14b. **Add explicit agent assertions that fail loudly** (this is what billing reads), in `tests/HttpTest.php` via the existing `HttpMock`: - - `Server::createHttpClient(...)`: the `Ably-Agent` request header matches `^ably-pubsub-php/\d+\.\d+\.\d+(\S*)? php/\S+ ably-pubsub-server$`, contains the versionless `ably-pubsub-server` token, and contains **no** `ably-pubsub-server/` form (the `name/undefined` regression ably-js#2297 guards against — in PHP the equivalent trap is `'ably-pubsub-server' => ''` or `null` rendering as `ably-pubsub-server/`). - - A bare `new AblyRest(...)` from the new package declares **no** side (asserts the door is the only stamping path). - - `agents => ['my-sdk' => '1.0']` survives and precedes the side entry; `agents => ['ably-pubsub-server' => 'x']` cannot override the side entry (renders versionless). - - Rewrite the RSC7d assertions at `tests/HttpTest.php:61` and `:80` for the new family identifier and the option-based (not static) wrapper form. -14c. **Add packaging-invariant tests** (PHPUnit, cheap, run on every PR): - - `composer.json` `name` is `ably/pubsub-server`; PSR-4 maps only `Ably\\PubSub\\`; no file under `src/` declares `namespace Ably;` or any namespace outside `Ably\PubSub\` (a missed file in the move would silently collide with the legacy package in a mixed install). - - `Defaults::LIB_VERSION` matches the top `CHANGELOG.md` entry (the release pre-flight checks this against the tag too; this catches it at PR time). - - Every class name in `src/` is loadable through Composer's generated autoloader (`composer dump-autoload -o` then `class_exists` over the map) — the PHP analogue of "the wheel contains the files it should". - -## Phase 4 — Release tooling: auto-publishing - -15. **Add `release.yml`** — PHP has no upload step (Packagist indexes git tags), so "publishing" is: push the release commit and version tag to the mirror, tag and release here, and prove Packagist saw it. `workflow_dispatch` with a required `version` input: - - **Pre-flight before anything is pushed:** version input is valid semver; equals `Defaults::LIB_VERSION`; equals the top `CHANGELOG.md` heading; `composer.json` `name` is `ably/pubsub-server` (refuses the legacy layout — this is what makes PR 3 inert on `main`); `composer validate --strict`; neither `pubsub-server/` here nor `` on the mirror already exists. Run the unit-level tests (mocked HTTP) as part of the pre-flight; the sandbox matrix already ran on the merged PR. - - **Publish to the mirror:** push the dispatched commit to the mirror's `main` and create the annotated tag `` there (this is the only place a Composer-valid `2.x` tag ever exists). Then create the namespaced tag `pubsub-server/` here and a GitHub release on it with the CHANGELOG section as body (`contents: write`). Prereleases (`-rc1`) are GitHub prereleases; Composer treats them as non-stable. - - **Post-publish check:** poll `https://repo.packagist.org/p2/ably/pubsub-server.json` until the version appears, with a bounded timeout; fail loudly if it does not. This is the automated proof that the mirror's Packagist webhook fired and the package resolved. - - **Re-run safety:** each step checks for its own artifact (mirror tag, local tag, GitHub release) and skips if present, so a run that failed part-way is completed by re-running it at the same version. - - **Guard against the one thing that must never happen:** the pre-flight also fails if a Composer-valid tag (`^v?\d+\.\d+\.\d+`) exists in this repo at or above `2.0.0` — that would mean someone tagged a 2.x release here by hand and `ably/ably-php` is now serving it. The `release-dry-run` job checks the same on every PR. -15b. **Make the workflow dispatchable early.** `workflow_dispatch` only registers once the file exists on the **default branch** — and this work merges to `integration/v2` until Phase 7 — so **cherry-pick `release.yml` to `main`** (PR 3), inert there because the pre-flight refuses `ably/ably-php`. Add a `release-dry-run` job to `check.yml` that runs the same pre-flight logic (minus pushes) on every PR so version-site/CHANGELOG drift surfaces continuously. Deliberately test the guardrails from a throwaway branch: mismatched version (aborts, nothing pushed), and a re-run at an existing version (skips to the poll). -15c. **Create the mirror and register `ably/pubsub-server` on Packagist — this can happen before the integration branch merges.** Because the mirror is its own repository, its default branch can carry `name: ably/pubsub-server` from day one: seed it with the first dispatch from `integration/v2` (a `2.0.0-rc1` or a throwaway `0.0.1-alpha1`), submit the mirror URL on packagist.org, confirm the derived name, add the SDK-team maintainers, and confirm the webhook updates it. This decouples the Packagist path from the `main` flip (step 22) and lets the prerelease (step 21) be a real Packagist install. -16. **Rewrite `CONTRIBUTING.md`'s release process** for the new flow (bump `LIB_VERSION` + CHANGELOG in a PR → merge → dispatch `release.yml`; no manual tagging), and state plainly **why no one may ever push a plain `2.x.y` tag to this repository** (the legacy Packagist package would serve it) and that 1.x maintenance tags stay plain because the legacy package depends on them. (The current CONTRIBUTING has no release section at all — it is the five-line fork/branch/PR list.) - -## Phase 5 — Repo rename and publishing rebind - -17. **Rename the repo `ably-php` → `ably-pubsub-php`** (direct rename; GitHub redirects cover clones and web links). The IAM prerequisite (infrastructure#13005) is merged, so this can happen any time — the natural slot is after PRs 1–2 merge to `integration/v2`, coordinated with the programme's cross-SDK rename freeze window (check with Evgenii whether renames are batched; ably-ruby is already renamed), and before Packagist is touched. Announce the freeze window to the SDK team first. In the same pass: - - Merge PR #222 (`features.yml` `repository-name: ably-pubsub-php`, README licence link) immediately after the rename, then merge `main` forward into `integration/v2`. On the integration branch also update README badges/links, `CONTRIBUTING.md`, `.ably/capabilities.yaml` links and `composer.json` `support.source`/`issues` if added. Leave historic `CHANGELOG.md` links alone (redirects cover them). - - **Legacy `ably/ably-php` Packagist entry — verify, do not rebind.** The repo webhook survives the rename and its payload carries the new URL plus the unchanged GitHub repository ID; Packagist falls back to matching by that ID, rewrites the stored URL itself and schedules a full re-crawl (verified in `ApiController::findGitHubPackagesByRepository`). So the PDR-091b line "Packagist … needs re-pointing" is satisfied automatically for PHP. Push a no-op commit to `maintenance/1.x` after the rename and confirm the package page shows the new repository URL and a fresh "last updated". Only if it does not, edit the URL by hand (allowed for a same-ID rename despite the download threshold). Update PR #222's description, which currently tells the reader to expect a stale URL. - - **Never recreate a repo named `ably/ably-php` afterwards.** A new repo under the old name destroys GitHub's redirect for every existing clone and link. PHP is a direct-rename SDK (the maintenance branch lives in the renamed repo), so the old name stays vacant forever. - - **Done when:** clone and web redirects verified (`git ls-remote` on an existing checkout, plus web URLs for the repo, a PR, and a file permalink); CI fully green post-rename (`check.yml` matrix on both `main` and `integration/v2`); `features.yml` runs clean with the new repository-name **and its upload lands** at `sdk.ably.com/builds/ably/ably-pubsub-php/main/…` (proves the new IAM role — this failure mode is otherwise silent); Packagist `ably/ably-php` shows the new repository URL and auto-updated on the no-op push. The mirror is unaffected by the rename. - -## Phase 6 — Public API pass (⚠️091d) — last change on the integration branch - -18. **This is deliberately the final code change before the integration branch merges**, gated on PDR-091d being approved — everything in Phases 2–5 is built and kept green on the current names, then this lands as one mechanical pass on top: - - Rename `Ably\PubSub\AblyRest` → `Ably\PubSub\HttpClient` (the door's return type follows). Owner decides on `Channel`/`Channels`/`Presence` → `HttpChannel`/`HttpChannels`/`HttpPresence` (091d's `RestChannel → HttpChannel` row; PHP's classes carry no prefix today, so this is consistency, not a rename of a wrong name). `PaginatedResult`, `HttpPaginatedResponse`, models and `Push*` classes stay. - - Produce the PHP deprecated-surface deletion list and delete rather than port. Known today: `Auth::authorise` (deprecated since 1.0), `AblyRest::setLibraryFlavourString` (deprecated) — plus the step-13 owner decision to drop the static `setAblyAgentHeader`, and the step-11 deletions (`ably-loader.php`, `demo/`, `Procfile`). Anything already deprecated is a deletion candidate by default; keeping it requires a stated reason. Nothing not currently deprecated is silently dropped. - - Re-run the full Phase 3 pass after the rename. - - Record the full old-name → new-name table in PDR-091b2's PHP section (it feeds the migration guide, step 20, and the Laravel wrappers' type hints, step 27). - - If 091d is **declined**, skip this phase and ship the surface as-is (the door returns `AblyRest`). If it is **still undecided** when the rest of the branch is done, escalate to the programme before merging: renaming later costs another major. - -## Phase 7 — Docs, prerelease, GA - -19. Rewrite `README.md` for the new package: `composer require ably/pubsub-server`; a single door quickstart (`use Ably\PubSub\Server; $ably = Server::createHttpClient(['key' => …]);`); a **Package** section saying what "server" means here (trusted runtime, API-key auth, MAU-exempt, the wire agent shape); the Laravel section pointing at the new wrapper majors; supported PHP versions table on the new floor; a "Migrating from `ably/ably-php` 1.x" section pointing at `UPDATING.md`; badges moved to `ably/pubsub-server` (they resolve once the package exists on Packagist, step 15c). Add one line for 1.x users pointing at `maintenance/1.x`, since the legacy Packagist page renders this README after step 22. Keep the "REST only, MQTT for realtime" note — it is still true. -20. **Migration guide** (new `UPDATING.md`, section "1.x (`ably/ably-php`) → 2.0.0 (`ably/pubsub-server`)"): machine-applicable mapping table — - - | 1.x (`ably/ably-php`) | 2.0 (`ably/pubsub-server`) | - | --- | --- | - | `composer require ably/ably-php` | `composer require ably/pubsub-server` | - | `use Ably\AblyRest;` / `new AblyRest($opts)` | `use Ably\PubSub\Server;` / `Server::createHttpClient($opts)` | - | `use Ably\Models\Message;` (any type) | `use Ably\PubSub\Models\Message;` | - | `AblyRest::setAblyAgentHeader('x', 'v')` | `Server::createHttpClient(['agents' => ['x' => 'v'], …])` | - | `require 'ably-loader.php'` | removed — use Composer's autoloader | - | ⚠️091d: `\Ably\AblyRest` type hints | `\Ably\PubSub\HttpClient` | - - Plus the deleted-API list, the statement that the returned client is the same REST client (channels, history, presence, auth, push admin unchanged), the MAU forcing function, and the EOL date. All samples rewritten onto the new package; the 23 PHP-bearing pages in the `docs` repo (`getting-started/php.mdx`, `getting-started/laravel.mdx`, `api/rest-sdk*.mdx`, auth/*, channels/*, …) and LLM-facing docs are the docs team's cross-SDK pass — hand them the table. -21. **Prerelease `2.0.0-rc1`** via `release.yml` from `integration/v2` — a real Packagist release through the mirror (step 15c), so the consumer-side check is the real path: in a clean container, `composer require ably/pubsub-server:2.0.0-rc1` from Packagist (no VCS repository stanza), construct through the door and assert the `Ably-Agent` value against a sandbox app. Confirm `composer require ably/pubsub-server` with default stability does **not** pick the rc. Install it **alongside** `ably/ably-php:1.1.12` in one project and confirm both autoload without collision (the step-2 rationale). Check the `ably/ably-php` Packagist page afterwards: it must show **no** `2.0.0-rc1` (proves the namespaced-tag rule in step 1 holds). -22. **Merge `integration/v2` to `main`.** New development continues on `main` under the renamed repo. From this moment the legacy `ably/ably-php` Packagist entry indexes `main` as `dev-main` carrying 2.x code (Composer forces the default branch's name onto every version, so this is not a mismatch it can detect), and its package page renders the 2.0 README. Mitigate: a maintainer pulls the `dev-main` version from `ably/ably-php` on packagist.org once (pulled rows stay pulled), and the 2.0 README carries a line pointing 1.x users at `maintenance/1.x`. Stable 1.x versions are unaffected — verify on the page, and in Phase 8 by the trivial 1.x patch release (step 25). -23. **GA release `2.0.0`, coordinated.** Dispatch `release.yml` at `main`; the Packagist poll is the proof. Released in the org-wide coordinated window with the other SDKs (rollout date is set by the programme, keyed to the MAU pricing date — do not GA unilaterally). GitHub release notes (on `pubsub-server/2.0.0` here) point at `UPDATING.md`. - -## Phase 8 — Maintenance window for the old `ably/ably-php` package - -24. Cut a maintenance branch from the last 1.x release (`1.1.12`, which is today's `main` less PR #222; naming TBC org-wide, e.g. `maintenance/1.x`) **before PR 3 (step 10b) merges to `main`**. Nothing on PHP's `main` breaks legacy releases as early as it does for Python (there is no tag-triggered publish to replace), but cutting it first keeps the rule uniform across SDKs and means a 1.x fix never has to be untangled from split work. The `ably/ably-php` package's future security/critical fixes are tagged from this branch only (`1.1.13`, …), by the existing manual process (or a copy of `release.yml` with the pre-flight pinned to `ably/ably-php`, owner's choice). No new features, **no deprecation notice in code, no runtime side-detection** — 091b says the existing packages are "not touched at all"; once MAU pricing is live the old constructor is rejected server-side, which is the intended forcing function. Its agent string stays `ably-php/1.x`, its namespace stays `Ably\`, its `composer.json` name stays `ably/ably-php`. -25. Cut a trivial patch release (`1.1.13`, plain tag) from the maintenance branch **after** steps 17 and 22 and confirm it appears on Packagist under `ably/ably-php` **and not** under `ably/pubsub-server` (the mirror never receives maintenance commits) — this proves the post-rename webhook path (step 17) and the two-repository separation (step 1) with a harmless release rather than at the first real security fix. -26. Publish the support policy: README banner + CHANGELOG entry on the maintenance branch and on `main` stating maintenance-only status, the EOL date (GA date + 1 year), and a link to the migration guide. When the programme issues deprecation notices (PDR-091 deferred decision D3, after MAU is live), mark `ably/ably-php` **abandoned on Packagist with `ably/pubsub-server` as the replacement** — Composer then prints "Package ably/ably-php is abandoned, you should avoid using it. Use ably/pubsub-server instead." on every install, which is the most effective migration nudge PHP has. In ably-common, add the sunset for `ably-php` (all versions) at the EOL date. The Laravel wrappers' 1.x lines EOL on the same date (step 27). - -## Phase 9 — Dependent Ably packages (PDR-091c; outside this repo, but this repo's owner drives them) - -27. **`ably/ably-php-laravel` and `ably/laravel-broadcaster` each ship a new major** depending on `ably/pubsub-server: ^2.0` (091c: unified, no split, dependency change only). Changes in each: replace `AblyRest::setAblyAgentHeader(...)` + `new AblyRest($config)` with `Server::createHttpClient($config + ['agents' => ['laravel' => $laravelVersion, 'laravel-broadcaster' => LIB_VERSION]])`; `laravel-broadcaster` retypes `AblyBroadcaster::__construct(AblyRest $ably, …)` to the new class (⚠️091d: `HttpClient`); READMEs and the `getting-started/laravel.mdx` page follow. Their agent identifiers keep their names (secondary identifiers). Their current majors enter the same 1-year maintenance window. Sequence: open their PRs once PR 1 here is merged and the namespace is fixed; release them in the same GA window, pinned to `2.0.0`, so a Laravel user never sees a wrapper that cannot resolve its dependency. - ---- - -## Cross-cutting checklist - -- [ ] Single-package shape (no `ably/pubsub-core`), the distribution mirror, and the namespaced-tag rule recorded in PDR-091b2; the "Packagist version discovery is repo-bound" finding raised with the programme (step 1) -- [ ] Mirror repo created, push credential in place, Packagist webhook on the mirror (step 9) -- [ ] Namespace `Ably\PubSub\` recorded in PDR-091b2 (step 2) -- [ ] Door signature `Server::createHttpClient(...)`, constructor `@internal`, static-agent removal recorded; Owner field filled (steps 3, 13) -- [ ] Version `2.0.0`, PHP floor `^8.1` (or owner's alternative) decided (steps 4, 5) -- [ ] `ably-pubsub-server` + `ably-pubsub-php` present in ably-common registry with the renamed `source`; submodule bumped (step 7; ably-common#361) -- [ ] MAU release date known; GA window agreed with programme (steps 8, 23) -- [ ] Packagist `ably` account access confirmed (step 9) -- [ ] ⚠️091d outcome tracked; Phase 6 executed, skipped, or escalated accordingly (step 18) -- [ ] Agent assertions in CI fail loudly, incl. the no-`ably-pubsub-server/` regression and the bare-constructor-declares-nothing check (step 14b) -- [ ] `release.yml` on `main` (inert), dry-run job on every PR, guardrails deliberately tested (steps 15, 15b) -- [ ] `ably/pubsub-server` registered on Packagist against the mirror; webhook proven (step 15c) -- [ ] Post-rename: redirects, CI, features upload (IAM), Packagist `ably/ably-php` URL auto-followed and auto-update proven; PR #222 description corrected (step 17) -- [ ] `2.0.0-rc1` proven via a real Packagist install, default-stability check, side-by-side install, and absence from `ably/ably-php` (step 21) -- [ ] `dev-main` pulled from `ably/ably-php` after the `main` flip (step 22) -- [ ] Maintenance branch cut before PR 3 merges; `1.1.13` proves the legacy Packagist path; EOL policy published; registry sunset added (steps 24–26) -- [ ] Laravel wrapper majors opened and released in the GA window (step 27) - -## Sequencing notes / risks - -- **Packagist is the PHP-specific trap, and it is about tags, not names.** Every package bound to a repository indexes every Composer-valid tag of that repository (Composer rewrites each version's name to the default branch's; Packagist stamps its own). So `ably/ably-php` and `ably/pubsub-server` cannot share this repository, the new package ships from a distribution mirror, and **a plain `2.x.y` tag must never be pushed here** — the `release.yml` pre-flight and the dry-run job refuse if one exists. The only residual leak is `dev-main` of the legacy package after the `main` flip, handled by a one-time maintainer pull (step 22). -- **The rename itself is benign for Packagist.** Auto-update follows the repository ID and self-corrects the URL; PR #222's warning about stale URLs is over-cautious and its description should be corrected. The rename still needs the freeze-window choreography for the features upload (IAM role), and a no-op push to prove the webhook path (step 17). -- **The mirror is one more thing to own:** a push credential, a webhook, a README banner, and the rule that issues and PRs are never accepted there. Put all four in `CONTRIBUTING.md`. -- **The agent-registry PR (step 7) is the only step worth doing immediately**; everything else flows through the integration branch. The `-server` suffix must never be changed without preserving the suffix (billing classifies by it) — the comment on the constant says so. -- **Namespace clobbering.** The new package must not declare anything under bare `Ably\`; the packaging test (14c) asserts it at PR time and the side-by-side install (21) proves it against real Composer resolution. -- **Static agent state goes away.** Both Laravel wrappers break on the new package until their own majors ship (step 27) — this is intended (they are being re-released regardless), but it means the wrapper PRs must be open before the PHP GA, not after. -- **PHP has one version site and one package**, so the lockstep pre-flight is small; the value of `release.yml` here is auto-publishing (PDR-091b's forcing function), the mirror push that no human should do by hand, and the Packagist visibility proof, not lockstep. -- **091d is the only rename that touches consumers' type hints** (`AblyRest` in `laravel-broadcaster`'s constructor and in every customer's DI container). Keep Phase 6 last so the wrapper PRs can be opened against a stable namespace and only the class name changes if 091d lands. -- **No realtime, no UTS, no device package**: PHP is the smallest split in the programme. The risk is not code volume, it is the registry/rename choreography above and getting the Laravel wrappers out in the same window. diff --git a/src/Auth.php b/src/Auth.php index caf6ba2..1584698 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -9,7 +9,7 @@ use Ably\PubSub\Models\TokenRequest; /** - * Provides authentification methods for AblyRest instances + * Provides authentification methods for PubSubHttpClient instances * @property-read string|null $clientId ClientId currently in use. Null if not * authenticated yet or when using anonymous auth. */ @@ -23,7 +23,7 @@ class Auth { protected $ably; const TOKEN_EXPIRY_MARGIN = 15000; // a token is considered expired a bit earlier to prevent race conditions - public function __construct( AblyRest $ably, ClientOptions $options ) { + public function __construct( PubSubHttpClient $ably, ClientOptions $options ) { $this->defaultAuthOptions = new AuthOptions($options); $this->defaultTokenParams = $options->defaultTokenParams; $this->ably = $ably; @@ -31,7 +31,7 @@ public function __construct( AblyRest $ably, ClientOptions $options ) { $this->basicAuth = empty( $this->defaultAuthOptions->useTokenAuth ) && $this->defaultAuthOptions->key; if ( $this->defaultAuthOptions->key && $this->defaultAuthOptions->clientId == '*' ) { - throw new AblyException ('Instantiating AblyRest with a wildcard clientId (`*`) not allowed.', 40012, 400); + throw new AblyException ('Instantiating PubSubHttpClient with a wildcard clientId (`*`) not allowed.', 40012, 400); } // Basic authentication diff --git a/src/Channel.php b/src/Channel.php index 4db9b1a..f089ca8 100644 --- a/src/Channel.php +++ b/src/Channel.php @@ -29,12 +29,12 @@ class Channel { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance * @param string $name Channel's name * @param ChannelOptions|array|null $options Channel options (for encrypted channels) * @throws AblyException */ - public function __construct( AblyRest $ably, $name, $options = [] ) { + public function __construct( PubSubHttpClient $ably, $name, $options = [] ) { $this->ably = $ably; $this->name = $name; $this->channelPath = "/channels/" . urlencode( $name ); diff --git a/src/Channels.php b/src/Channels.php index 8d6c12d..55bb092 100644 --- a/src/Channels.php +++ b/src/Channels.php @@ -8,9 +8,9 @@ class Channels { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance */ - public function __construct( AblyRest $ably ) { + public function __construct( PubSubHttpClient $ably ) { $this->ably = $ably; } diff --git a/src/Http.php b/src/Http.php index fba81ae..240404f 100644 --- a/src/Http.php +++ b/src/Http.php @@ -1,7 +1,7 @@ ably = $ably; $this->model = $model; diff --git a/src/Presence.php b/src/Presence.php index c62e232..867ec3d 100644 --- a/src/Presence.php +++ b/src/Presence.php @@ -10,10 +10,10 @@ class Presence { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance * @param Channel $channel Associated channel */ - public function __construct( AblyRest $ably, Channel $channel ) { + public function __construct( PubSubHttpClient $ably, Channel $channel ) { $this->ably = $ably; $this->channel = $channel; } diff --git a/src/AblyRest.php b/src/PubSubHttpClient.php similarity index 98% rename from src/AblyRest.php rename to src/PubSubHttpClient.php index 1b8a6ce..78560bd 100644 --- a/src/AblyRest.php +++ b/src/PubSubHttpClient.php @@ -13,7 +13,7 @@ /** * Ably REST client */ -class AblyRest { +class PubSubHttpClient { public $options; @@ -138,7 +138,7 @@ public function time() { /** * Does a GET request, automatically injecting auth headers and handling fallback on server failure - * @see AblyRest::request() + * @see PubSubHttpClient::request() */ public function get( $path, $headers = [], $params = [], $returnHeaders = false, $auth = true ) { return $this->requestInternal( 'GET', $path, $headers, $params, $returnHeaders, $auth ); @@ -146,7 +146,7 @@ public function get( $path, $headers = [], $params = [], $returnHeaders = false, /** * Does a POST request, automatically injecting auth headers and handling fallback on server failure - * @see AblyRest::request() + * @see PubSubHttpClient::request() */ public function post( $path, $headers = [], $params = [], $returnHeaders = false, $auth = true ) { return $this->requestInternal( 'POST', $path, $headers, $params, $returnHeaders, $auth ); @@ -154,7 +154,7 @@ public function post( $path, $headers = [], $params = [], $returnHeaders = false /** * Does a PUT request, automatically injecting auth headers and handling fallback on server failure - * @see AblyRest::request() + * @see PubSubHttpClient::request() */ public function put( $path, $headers = [], $params = [], $returnHeaders = false, $auth = true ) { return $this->requestInternal( 'PUT', $path, $headers, $params, $returnHeaders, $auth ); @@ -162,7 +162,7 @@ public function put( $path, $headers = [], $params = [], $returnHeaders = false, /** * Does a DELETE request, automatically injecting auth headers and handling fallback on server failure - * @see AblyRest::request() + * @see PubSubHttpClient::request() */ public function delete( $path, $headers = [], $params = [], $returnHeaders = false, $auth = true ) { return $this->requestInternal( 'DELETE', $path, $headers, $params, $returnHeaders, $auth ); diff --git a/src/Push.php b/src/Push.php index 907ff9f..caed260 100644 --- a/src/Push.php +++ b/src/Push.php @@ -8,9 +8,9 @@ class Push { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance */ - public function __construct( AblyRest $ably ) { + public function __construct( PubSubHttpClient $ably ) { $this->ably = $ably; $this->admin = new PushAdmin( $ably ); } diff --git a/src/PushAdmin.php b/src/PushAdmin.php index 7f6a5bc..de04ff5 100644 --- a/src/PushAdmin.php +++ b/src/PushAdmin.php @@ -9,9 +9,9 @@ class PushAdmin { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance */ - public function __construct( AblyRest $ably ) { + public function __construct( PubSubHttpClient $ably ) { $this->ably = $ably; $this->deviceRegistrations = new PushDeviceRegistrations( $ably ); $this->channelSubscriptions = new PushChannelSubscriptions ( $ably ); diff --git a/src/PushChannelSubscriptions.php b/src/PushChannelSubscriptions.php index cee026e..1f0531b 100644 --- a/src/PushChannelSubscriptions.php +++ b/src/PushChannelSubscriptions.php @@ -10,9 +10,9 @@ class PushChannelSubscriptions { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance */ - public function __construct( AblyRest $ably ) { + public function __construct( PubSubHttpClient $ably ) { $this->ably = $ably; } diff --git a/src/PushDeviceRegistrations.php b/src/PushDeviceRegistrations.php index 8328f6c..e478155 100644 --- a/src/PushDeviceRegistrations.php +++ b/src/PushDeviceRegistrations.php @@ -10,9 +10,9 @@ class PushDeviceRegistrations { /** * Constructor - * @param AblyRest $ably Ably API instance + * @param PubSubHttpClient $ably Ably API instance */ - public function __construct( AblyRest $ably ) { + public function __construct( PubSubHttpClient $ably ) { $this->ably = $ably; } diff --git a/src/Server.php b/src/Server.php index cdf3b71..b425e55 100644 --- a/src/Server.php +++ b/src/Server.php @@ -49,10 +49,10 @@ private function __construct() {} * ClientOptions instance, or a string holding an API key or a token. * * @param \Ably\PubSub\Models\ClientOptions|array|string $options - * @return \Ably\PubSub\AblyRest + * @return \Ably\PubSub\PubSubHttpClient */ public static function createHttpClient( $options = [] ) { - return new AblyRest( self::withSideAgent( $options ) ); + return new PubSubHttpClient( self::withSideAgent( $options ) ); } /** diff --git a/tests/AppStatsTest.php b/tests/AppStatsTest.php index a12dac7..475a395 100644 --- a/tests/AppStatsTest.php +++ b/tests/AppStatsTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); diff --git a/tests/AuthTest.php b/tests/AuthTest.php index 6d6a0f4..c992597 100644 --- a/tests/AuthTest.php +++ b/tests/AuthTest.php @@ -1,6 +1,6 @@ expectException(AblyException::class); $this->expectExceptionCode(40103); - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'tls' => false, ] ) ); @@ -48,21 +48,21 @@ public function testNoAuthParams() { $this->expectException(AblyException::class); $this->expectExceptionCode(40103); - $ably = new AblyRest( ); + $ably = new PubSubHttpClient( ); } /** * Init library with a token */ public function testAuthWithToken() { - $ably_for_token = new AblyRest( array_merge( self::$defaultOptions, [ + $ably_for_token = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $tokenDetails = $ably_for_token->auth->requestToken(); $this->assertNotNull($tokenDetails->token, 'Expected token id' ); - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $tokenDetails, ] ) ); @@ -75,7 +75,7 @@ public function testAuthWithToken() { * Init library with a key, force use of token with useTokenAuth */ public function testAuthWithKeyForceToken() { - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => 'fake.key:totallyFake', 'useTokenAuth' => true, ] ); @@ -90,7 +90,7 @@ public function testAuthEmptyForceToken() { $this->expectException(AblyException::class); $this->expectExceptionCode(40103); - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'useTokenAuth' => true, ] ); } @@ -99,14 +99,14 @@ public function testAuthEmptyForceToken() { * Verify than token auth works without TLS */ public function testTokenWithoutTLS() { - $ably_for_token = new AblyRest( array_merge( self::$defaultOptions, [ + $ably_for_token = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $tokenDetails = $ably_for_token->auth->requestToken(); $this->assertNotNull($tokenDetails->token, 'Expected token id' ); - $ablyInsecure = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyInsecure = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $tokenDetails, 'tls' => false, ] ) ); @@ -122,7 +122,7 @@ public function testTokenWithoutTLS() { public function testTokenRequestWithAuthCallbackReturningSignedRequest() { $callbackCalled = false; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authCallback' => function( $tokenParams ) use( &$callbackCalled ) { $callbackCalled = true; @@ -149,7 +149,7 @@ public function testTokenRequestWithAuthCallbackReturningSignedRequest() { public function testTokenRequestWithAuthCallbackReturningTokenDetails() { $callbackCalled = false; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authCallback' => function( $tokenParams ) use( &$callbackCalled ) { $callbackCalled = true; @@ -175,7 +175,7 @@ public function testTokenRequestWithAuthCallbackReturningTokenDetails() { public function testTokenRequestWithAuthCallbackReturningTokenString() { $callbackCalled = false; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authCallback' => function( $tokenParams ) use( &$callbackCalled ) { $callbackCalled = true; @@ -197,7 +197,7 @@ public function testTokenRequestWithAuthCallbackReturningTokenString() { public function testTokenRequestWithAuthUrlReturningSignedRequest() { $method = 'POST'; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authUrl' => 'https://TEST/tokenRequest', 'httpClass' => 'authTest\HttpMock', ] ) ); @@ -212,7 +212,7 @@ public function testTokenRequestWithAuthUrlReturningSignedRequest() { * Init library with an authUrl that returns TokenDetails */ public function testTokenRequestWithAuthUrlReturningTokenDetails() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authUrl' => 'https://TEST/tokenDetails', 'httpClass' => 'authTest\HttpMock', ] ) ); @@ -227,7 +227,7 @@ public function testTokenRequestWithAuthUrlReturningTokenDetails() { * Init library with an authUrl that returns a token string */ public function testTokenRequestWithAuthUrlReturningTokenString() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authUrl' => 'https://TEST/tokenString', 'httpClass' => 'authTest\HttpMock', ] ) ); @@ -250,7 +250,7 @@ public function testTokenRequestWithAuthUrlParams() { $expectedAuthParams = [ 'param1' => 'value1', 'test' => 1, 'ttl' => 360000 ]; $method = 'POST'; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authUrl' => 'https://TEST/tokenRequest', 'authHeaders' => $headers, 'authParams' => $authParams, @@ -285,7 +285,7 @@ public function testTokenRequestWithAuthUrlParams() { * and checks if ttl can be left blank */ public function testCreateTokenRequestValidity() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); @@ -298,7 +298,7 @@ public function testCreateTokenRequestValidity() { $timestamp = $ably->time(); - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'authCallback' => function( $tokenParams ) use( $tokenRequest ) { return $tokenRequest; }, @@ -327,7 +327,7 @@ private function stripTokenRequestVariableParams($tokenRequest) { * Verify that createTokenRequest() supports tokenparams, authparams and overrides values correctly */ public function testCreateTokenRequestParams() { - $ablyKey = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyKey = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'httpClass' => 'authTest\HttpMock', 'clientId' => 'libClientId', @@ -413,7 +413,7 @@ public function testCreateTokenRequestParams() { * keeps using the same token, and renews it when forced */ public function testAuthorize() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'authClass' => 'authTest\AuthMock' ] ) ); @@ -440,7 +440,7 @@ public function testAuthorize() { * Verify that all the parameters are supported and saved as defaults */ public function testAuthorizeParams() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'authClass' => 'authTest\AuthMock' ] ) ); @@ -516,7 +516,7 @@ public function testAuthorizeParams() { * Verify that authorize() stores the provided parameters and uses them as defaults from then on */ public function testAuthorizeRememberDefaults() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'clientId' => 'originalClientId', ] ) ); @@ -541,7 +541,7 @@ public function testAuthorizeRememberDefaults() { */ public function testHTTPHeadersKey() { $fakeKey = 'fake.key:totallyFake'; - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => $fakeKey, 'httpClass' => 'authTest\HttpMock', ] ); @@ -556,7 +556,7 @@ public function testHTTPHeadersKey() { */ public function testHTTPHeadersToken() { $fakeToken = 'fakeToken'; - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'token' => $fakeToken, 'httpClass' => 'authTest\HttpMock', ] ); diff --git a/tests/ChannelHistoryTest.php b/tests/ChannelHistoryTest.php index 915eaf5..76f21bf 100644 --- a/tests/ChannelHistoryTest.php +++ b/tests/ChannelHistoryTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } diff --git a/tests/ChannelIdempotentTest.php b/tests/ChannelIdempotentTest.php index 08367c9..a8e23ee 100644 --- a/tests/ChannelIdempotentTest.php +++ b/tests/ChannelIdempotentTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'idempotentRestPublishing' => true, ] ) ); @@ -163,7 +163,7 @@ public function testIdempotentMixedIds() { * RSL1k4 */ public function testIdempotentLibraryGeneratedPublish() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'idempotentRestPublishing' => true, 'httpClass' => 'tests\HttpMockIdempotent', diff --git a/tests/ChannelMessagesTest.php b/tests/ChannelMessagesTest.php index 3c253a4..638ec98 100644 --- a/tests/ChannelMessagesTest.php +++ b/tests/ChannelMessagesTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } @@ -192,7 +192,7 @@ public function testMessageArraySingleRequest() { $messages[] = $msg; } - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'httpClass' => 'tests\HttpMockMsgCounter', ] ) ); @@ -327,7 +327,7 @@ public function testPublishExtras() { public function testEncryptedMessageUnencryptedHistory() { $errorLogged = false; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'logHandler' => function( $level, $args ) use ( &$errorLogged ) { if ( $level == Log::ERROR ) { @@ -378,7 +378,7 @@ public function testUnencryptedMessageEncryptedHistory() { public function testEncryptionKeyMismatch() { $errorLogged = false; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'logHandler' => function( $level, $args ) use ( &$errorLogged ) { if ( $level == Log::ERROR ) { @@ -552,7 +552,7 @@ public function testEncodingInteroperabilityAblyToRaw() { * Test if null name and data elements are allowed when publishing messages */ public function testNullData() { - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'httpClass' => 'tests\HttpSaveWrapper', ] ) ); diff --git a/tests/ChannelStatusTest.php b/tests/ChannelStatusTest.php index 2c1ac7b..178f364 100644 --- a/tests/ChannelStatusTest.php +++ b/tests/ChannelStatusTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest(array_merge(self::$defaultOptions, [ + self::$ably = new PubSubHttpClient(array_merge(self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ])); } diff --git a/tests/ClientIdTest.php b/tests/ClientIdTest.php index 533dde6..7f70f1f 100644 --- a/tests/ClientIdTest.php +++ b/tests/ClientIdTest.php @@ -1,6 +1,6 @@ self::$testApp->getAppKeyDefault()->string, 'clientId' => 'testClientId', ] ) ); @@ -48,7 +48,7 @@ public function testInitWithWildcardClientId() { $this->expectException(AblyException::class); $this->expectExceptionCode(40012); - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'clientId' => '*', ] ) ); @@ -59,7 +59,7 @@ public function testInitWithWildcardClientId() { */ public function testGetClientIdNull() { // no clientId provided anywhere, should be null - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); @@ -69,7 +69,7 @@ public function testGetClientIdNull() { $this->assertNull( $ably->auth->clientId, 'Expected clientId to be null' ); // test not yet authorised lib without a clientId specified on ClientOptions - $ablyImplicitCId = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyImplicitCId = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'defaultTokenParams' => new TokenParams( [ 'clientId' => 'testClientId', @@ -89,13 +89,13 @@ public function testGetClientIdNull() { */ public function testGetClientIdNonNull() { // test wildcard clientId provided via tokenDetails - $ablyKey = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyKey = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $wildcardToken = $ablyKey->auth->requestToken( [ 'clientId' => '*' ] ); - $ablyWildcard = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyWildcard = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $wildcardToken, ] ) ); @@ -104,7 +104,7 @@ public function testGetClientIdNonNull() { $this->assertEquals( '*', $ablyWildcard->auth->clientId, 'Expected clientId to be *' ); // test specified clientId specified in ClientOptions - $ablyCid = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyCid = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'clientId' => 'testClientId', ] ) ); @@ -124,13 +124,13 @@ public function testGetClientIdNonNull() { * Check if messages can be assigned a clientId with a wildcard lib instance */ public function testWildcardClientIdMsg() { - $ablyKey = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyKey = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $wildcardToken = $ablyKey->auth->requestToken( [ 'clientId' => '*' ] ); - $ablyWildcard = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyWildcard = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $wildcardToken, ] ) ); @@ -157,7 +157,7 @@ public function testWildcardClientIdMsg() { public function testClientIdLib() { $clientId = 'testClientId'; - $ablyCId = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyCId = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'clientId' => $clientId, 'useTokenAuth' => true, @@ -201,7 +201,7 @@ public function testClientIdLib() { * operations */ public function testClientIdPrecedence() { - $ablyCId = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyCId = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'useTokenAuth' => true, 'clientId' => 'overriddenClientId', @@ -227,13 +227,13 @@ public function testClientIdPrecedence() { * have a clientId. Check that Auth#clientId is null */ public function testRSA8f1() { - $ablyMain = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyMain = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $tokenDetails = $ablyMain->auth->requestToken(); - $ablyClient = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyClient = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $tokenDetails, ] ) ); @@ -250,13 +250,13 @@ public function testRSA8f1() { * publish a message with an explicit clientId value, and ensure that the message is rejected */ public function testRSA8f2() { - $ablyMain = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyMain = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $tokenDetails = $ablyMain->auth->requestToken(); - $ablyClient = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyClient = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $tokenDetails, ] ) ); @@ -273,13 +273,13 @@ public function testRSA8f2() { * a clientId. Check that Auth#clientId is a string with value '*'. */ public function testRSA8f3() { - $ablyMain = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyMain = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $tokenDetails = $ablyMain->auth->requestToken( [ 'clientId' => '*' ] ); - $ablyClient = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyClient = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $tokenDetails, ] ) ); @@ -297,13 +297,13 @@ public function testRSA8f3() { * the provided clientId */ public function testRSA8f4() { - $ablyMain = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyMain = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); $tokenDetails = $ablyMain->auth->requestToken( [ 'clientId' => '*' ] ); - $ablyClient = new AblyRest( array_merge( self::$defaultOptions, [ + $ablyClient = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'tokenDetails' => $tokenDetails, ] ) ); diff --git a/tests/HttpTest.php b/tests/HttpTest.php index e40c7f4..132b57c 100644 --- a/tests/HttpTest.php +++ b/tests/HttpTest.php @@ -1,7 +1,7 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } @@ -38,7 +38,7 @@ public function testVersionHeaderPresence() { 'key' => 'fake.key:totallyFake', 'httpClass' => 'tests\HttpMock', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $curlParams = $ably->http->getCurlLastParams(); @@ -84,13 +84,13 @@ private static function expectedPrefix() { * Verify proper agent header is set as per RSC7d */ public function testAblyAgentHeader() { - $ably = new AblyRest( self::mockOptions() ); + $ably = new PubSubHttpClient( self::mockOptions() ); $this->assertSame( self::expectedPrefix(), self::sentAgentHeader( $ably ), 'Expected Ably agent header in HTTP request' ); // a second client renders the same header: no state leaks between instances - $ably = new AblyRest( self::mockOptions() ); + $ably = new PubSubHttpClient( self::mockOptions() ); $this->assertSame( self::expectedPrefix(), self::sentAgentHeader( $ably ), 'Expected Ably agent header in HTTP request' ); @@ -101,7 +101,7 @@ public function testAblyAgentHeader() { * process-global static state (RSC7d). */ public function testAblyAgentHeaderWithAgentsOption() { - $ably = new AblyRest( self::mockOptions( [ + $ably = new PubSubHttpClient( self::mockOptions( [ 'agents' => [ 'laravel' => null, 'customLib' => '2.3.5' ], ] ) ); @@ -159,7 +159,7 @@ public function sideAgentVersionProvider() { * the constructor directly declares none. */ public function testBareConstructorDeclaresNoSide() { - $agentHeader = self::sentAgentHeader( new AblyRest( self::mockOptions() ) ); + $agentHeader = self::sentAgentHeader( new PubSubHttpClient( self::mockOptions() ) ); $this->assertStringNotContainsString( 'ably-pubsub-server', $agentHeader, 'A directly constructed client must not declare the server side' ); @@ -220,7 +220,7 @@ public function testGET() { 'clientId' => 'test', ]; - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => 'fake.key:totallyFake', 'authUrl' => 'http://test.test/tokenRequest', 'authParams' => $authParams, @@ -250,7 +250,7 @@ public function testPOST() { 'clientId' => 'test', ]; - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => 'fake.key:totallyFake', 'authUrl' => 'http://test.test/tokenRequest', 'authParams' => $authParams, @@ -271,7 +271,7 @@ public function testPOST() { } /** - * RSC19 Test basic AblyRest::request functionality + * RSC19 Test basic PubSubHttpClient::request functionality */ public function testRequestBasic() { $ably = self::$ably; @@ -313,7 +313,7 @@ public function testRequestBasic() { * RSC19 - Test that Response handles various returned structures properly */ public function testRequestReturnValues() { - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => 'fake.key:totallyFake', 'httpClass' => 'tests\HttpMockReturnData', ] ); diff --git a/tests/LogTest.php b/tests/LogTest.php index 8fd6a57..766ce59 100644 --- a/tests/LogTest.php +++ b/tests/LogTest.php @@ -1,6 +1,6 @@ 'fake.key:totallyFake' ] ); } @@ -33,7 +33,7 @@ public function testLogDefault() { $out .= $args[0] . "\n"; }, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $this->logMessages(); @@ -58,7 +58,7 @@ public function testLogVerbose() { }, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $this->logMessages(); $this->assertIsInt( strpos($out, 'This is a test warning.'), 'Expected warning level to be logged.' ); @@ -80,7 +80,7 @@ public function testLogNone() { }, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $this->logMessages(); $this->assertFalse( $called, 'Log handler incorrectly called' ); } diff --git a/tests/PresenceTest.php b/tests/PresenceTest.php index b2cc0a7..f674841 100644 --- a/tests/PresenceTest.php +++ b/tests/PresenceTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); diff --git a/tests/AblyRestRequestTest.php b/tests/PubSubHttpClientRequestTest.php similarity index 93% rename from tests/AblyRestRequestTest.php rename to tests/PubSubHttpClientRequestTest.php index 81a87d5..24a9f2b 100644 --- a/tests/AblyRestRequestTest.php +++ b/tests/PubSubHttpClientRequestTest.php @@ -1,9 +1,9 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } diff --git a/tests/AblyRestTest.php b/tests/PubSubHttpClientTest.php similarity index 92% rename from tests/AblyRestTest.php rename to tests/PubSubHttpClientTest.php index f2890e2..0436bca 100644 --- a/tests/AblyRestTest.php +++ b/tests/PubSubHttpClientTest.php @@ -1,6 +1,6 @@ assertTrue( $ably->auth->isUsingBasicAuth(), 'Expected basic auth to be used' ); } @@ -40,7 +40,7 @@ public function testInitLibWithKeyString() { */ public function testInitLibWithKeyOption() { $key = 'fake.key:veryFake'; - $ably = new AblyRest( ['key' => $key ] ); + $ably = new PubSubHttpClient( ['key' => $key ] ); $this->assertTrue( $ably->auth->isUsingBasicAuth(), 'Expected basic auth to be used' ); } @@ -49,7 +49,7 @@ public function testInitLibWithKeyOption() { */ public function testInitLibWithTokenString() { $token = 'fake_token'; // token string never contains a colon - $ably = new AblyRest( $token ); + $ably = new PubSubHttpClient( $token ); $this->assertFalse( $ably->auth->isUsingBasicAuth(), 'Expected token auth to be used' ); } @@ -57,7 +57,7 @@ public function testInitLibWithTokenString() { * Init library with a token string in options */ public function testInitLibWithTokenOption() { - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'token' => "this_is_not_really_a_token", ] ); @@ -68,7 +68,7 @@ public function testInitLibWithTokenOption() { * Init library with a tokenDetails in options */ public function testInitLibWithTokenDetailsOption() { - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'tokenDetails' => new TokenDetails( "this_is_not_really_a_token" ), ] ); @@ -84,7 +84,7 @@ public function testInitLibWithSpecifiedHost() { 'restHost' => 'some.other.host', 'httpClass' => 'tests\HttpMockInitTest', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $this->assertMatchesRegularExpression( '/^https?:\/\/some\.other\.host/', $ably->http->lastUrl, 'Unexpected host mismatch' ); } @@ -99,7 +99,7 @@ public function testInitLibWithSpecifiedPort() { 'tlsPort' => 999, 'httpClass' => 'tests\HttpMockInitTest', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $this->assertStringContainsString( 'https://' . $opts['restHost'] . ':' . $opts['tlsPort'], @@ -114,7 +114,7 @@ public function testInitLibWithSpecifiedPort() { 'tls' => false, 'httpClass' => 'tests\HttpMockInitTest', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $this->assertStringContainsString( 'http://' . $opts['restHost'] . ':' . $opts['port'], @@ -127,7 +127,7 @@ public function testInitLibWithSpecifiedPort() { * Init library with specified environment */ public function testInitLibWithSpecifiedEnv() { - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => 'fake.key:veryFake', 'environment' => 'sandbox', 'httpClass' => 'tests\HttpMockInitTest', @@ -144,7 +144,7 @@ public function testTLSDefaultIsTrue() { 'key' => 'fake.key:veryFake', 'httpClass' => 'tests\HttpMockInitTest', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $this->assertMatchesRegularExpression( '/^https:\/\/rest\.ably\.io/', $ably->http->lastUrl, 'Unexpected scheme/url mismatch' ); } @@ -158,7 +158,7 @@ public function testTLSCanBeFalse() { 'httpClass' => 'tests\HttpMockInitTest', 'tls' => false, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $this->assertMatchesRegularExpression( '/^http:\/\/rest\.ably\.io/', $ably->http->lastUrl, 'Unexpected scheme/url mismatch' ); } @@ -172,7 +172,7 @@ public function testTLSExplicitTrue() { 'httpClass' => 'tests\HttpMockInitTest', 'tls' => true, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->time(); // make a request $this->assertMatchesRegularExpression( '/^https:\/\/rest\.ably\.io/', $ably->http->lastUrl, 'Unexpected scheme/url mismatch' ); } @@ -189,7 +189,7 @@ public function testMaxRetryCount() { 'httpMaxRetryCount' => 2, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -208,7 +208,7 @@ public function testFallbackHosts() { 'httpClass' => 'tests\HttpMockInitTestTimeout', 'httpMaxRetryCount' => 5, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -237,7 +237,7 @@ public function testEnvFallbackHosts() { 'httpMaxRetryCount' => 5, 'environment' => 'alpha' ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -266,7 +266,7 @@ public function testNoFallbackOnEmptyCustomFallbacks() { 'restHost' => 'custom.host.com', 'fallbackHosts' => [], ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -296,7 +296,7 @@ public function testCustomHostAndFallbacks() { 'httpClass' => 'tests\HttpMockInitTestTimeout', 'httpMaxRetryCount' => 3, ]); - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -323,7 +323,7 @@ public function testNoFallbackOnClientError() { 'httpClass' => 'tests\HttpMockInitTestTimeout', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->http->httpErrorCode = 401; $ably->http->errorCode = 40101; // auth error @@ -346,7 +346,7 @@ public function testNoFallbackOnCustomHost() { 'httpClass' => 'tests\HttpMockInitTestTimeout', 'restHost' => 'custom.host.com', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -366,7 +366,7 @@ public function testFallbackHostsFailFirst3() { 'httpClass' => 'tests\HttpMockInitTestTimeout', 'httpMaxRetryCount' => 5, ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $ably->http->hostFailures = 3; $data = $ably->time(); // make a request @@ -390,7 +390,7 @@ public function testFallbackHostHeader() { 'key' => 'fake.key:veryFake', 'httpClass' => 'tests\HttpMockInitTestTimeout' ]); - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); try { $ably->time(); // make a request $this->fail('Expected the request to fail'); @@ -408,7 +408,7 @@ public function testFallbackHostHeader() { */ public function testCachedFallback() { $fallbackCacheTimeoutInMs = 1999; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, 'fallbackRetryTimeout' => $fallbackCacheTimeoutInMs, 'httpClass' => 'tests\HttpMockCachedFallback', @@ -440,14 +440,14 @@ public function testCachedFallback() { /** * Verify accuracy of time (to within 2 seconds of actual time) * - * RSC16 RestClient#time function sends a get request to rest.ably.io/time + * RSC16 PubSubHttpClient#time function sends a get request to rest.ably.io/time * and returns the server time in milliseconds since epoch */ public function testTimeAndAccuracy() { $opts = [ 'key' => 'fake.key:veryFake', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $time = $ably->time(); $this->assertIsInt( $time ); @@ -465,7 +465,7 @@ public function testActiveInternetConnection() { $opts = [ 'key' => 'fake.key:veryFake', ]; - $ably = new AblyRest( $opts ); + $ably = new PubSubHttpClient( $opts ); $this->assertTrue($ably ->hasActiveInternetConnection()); } @@ -473,7 +473,7 @@ public function testActiveInternetConnection() { * Verify that time fails without valid host */ public function testTimeFailsWithInvalidHost() { - $ablyInvalidHost = new AblyRest( [ + $ablyInvalidHost = new PubSubHttpClient( [ 'key' => 'fake.key:veryFake', 'restHost' => 'this.host.does.not.exist', ]); @@ -487,11 +487,11 @@ public function testTimeFailsWithInvalidHost() { * Connection/open timeout not reliably testable. */ public function testHttpTimeout() { - $ably = new AblyRest( [ + $ably = new PubSubHttpClient( [ 'key' => 'fake.key:veryFake', ]); - $ablyTimeout = new AblyRest( [ + $ablyTimeout = new PubSubHttpClient( [ 'key' => 'fake.key:veryFake', 'httpRequestTimeout' => 20, // 20 ms ]); diff --git a/tests/PushAdminTest.php b/tests/PushAdminTest.php index 3293399..0c28dc0 100644 --- a/tests/PushAdminTest.php +++ b/tests/PushAdminTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } diff --git a/tests/PushChannelSubscriptionsTest.php b/tests/PushChannelSubscriptionsTest.php index caa826b..252edf8 100644 --- a/tests/PushChannelSubscriptionsTest.php +++ b/tests/PushChannelSubscriptionsTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } diff --git a/tests/PushDeviceRegistrationsTest.php b/tests/PushDeviceRegistrationsTest.php index b85dd8f..ee5f358 100644 --- a/tests/PushDeviceRegistrationsTest.php +++ b/tests/PushDeviceRegistrationsTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); } diff --git a/tests/TokenTest.php b/tests/TokenTest.php index 074761c..74e1072 100644 --- a/tests/TokenTest.php +++ b/tests/TokenTest.php @@ -1,6 +1,6 @@ getOptions(); - self::$ably = new AblyRest( array_merge( self::$defaultOptions, [ + self::$ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => self::$testApp->getAppKeyDefault()->string, ] ) ); @@ -143,7 +143,7 @@ public function testTokenGenerationWithSpecifiedKey() { 'key' => $key->string, ]; - $ably = new AblyRest( array_merge( self::$defaultOptions, [ + $ably = new PubSubHttpClient( array_merge( self::$defaultOptions, [ 'key' => 'fake.key:veryFake', ] ) ); @@ -211,7 +211,7 @@ public function testTokenRenewalKnownExpiration() { } ] ); - $ablyTokenAuth = new AblyRest( $options ); + $ablyTokenAuth = new PubSubHttpClient( $options ); $ablyTokenAuth->auth->authorize(); $tokenBefore = $ablyTokenAuth->auth->getTokenDetails()->token; @@ -248,7 +248,7 @@ public function testTokenRenewalUnknownExpiration() { } ] ); - $ablyTokenAuth = new AblyRest( $options ); + $ablyTokenAuth = new PubSubHttpClient( $options ); $ablyTokenAuth->auth->authorize(); $tokenBefore = $ablyTokenAuth->auth->getTokenDetails()->token; @@ -285,7 +285,7 @@ public function testTokenRenewalUnknownExpirationFailure() { } ] ); - $ablyTokenAuth = new AblyRest( $options ); + $ablyTokenAuth = new PubSubHttpClient( $options ); $channel = $ablyTokenAuth->channel( 'testchannel' ); // do an authorised request with the valid token @@ -312,7 +312,7 @@ public function testFailingTokenRenewalUnknownExpiration() { $options = array_merge( self::$defaultOptions, [ 'token' => $tokenDetails->token, ] ); - $ablyTokenAuth = new AblyRest( $options ); + $ablyTokenAuth = new PubSubHttpClient( $options ); $channel = $ablyTokenAuth->channel( 'testchannel' ); $channel->publish( 'test', 'test' ); // this should work diff --git a/tests/TypesTest.php b/tests/TypesTest.php index 7f71bbe..ec3196f 100644 --- a/tests/TypesTest.php +++ b/tests/TypesTest.php @@ -1,6 +1,6 @@