v1.3.0 - #24
Merged
Merged
v1.3.0#24
Conversation
Pulls in the 1.4.0 beta of the Connect PHP SDK so testers can verify the new SDK against the WordPress plugin. Shipped via the beta prerelease channel only; not published to WordPress.org. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# [1.3.0-beta.1](v1.2.2...v1.3.0-beta.1) (2026-06-15) ### Features * bump connect-sdk-php to 1.4.0-beta.1 for testing ([719cb58](719cb58))
## Summary Replicates the last beta-release flow (a `feat:` commit on `beta` → semantic-release auto-cuts the next prerelease) for enabling analytics. - Passes `analyticsEnabled: true` to the `SupertabConnect` constructor in `Plugin::init_bot_protection()`, so the plugin emits one analytics event per bot request. - The beta SDK (`getsupertab/connect-sdk-php` `1.4.0-beta.1`) is **already pinned on this branch** from the previous beta, so no dependency change is needed here — this is a one-line enablement. ## Release impact `beta` is currently at `v1.3.0-beta.1`. Merging this `feat:` commit triggers `release.yml` → semantic-release, which will cut **`v1.3.0-beta.2`** automatically. (WordPress.org deploy only runs for `main`, not `beta`.) ## Verification - `composer lint` ✅ — no syntax errors - `composer phpcs` ✅ — no violations (also enforced by pre-commit hook) - `composer phpstan` ✅ — no errors - `composer test` ✅ — 58/58 unit tests passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# [1.3.0-beta.2](v1.3.0-beta.1...v1.3.0-beta.2) (2026-06-17) ### Features * enable bot traffic analytics by default ([#11](#11)) ([2aaa352](2aaa352))
## Summary Updates `getsupertab/connect-sdk-php` from `1.4.0-beta.1` to `1.4.0-beta.3`. Pre-release only — targets the `beta` branch. ## Changes - **`composer.json` / `composer.lock`** — bump the SDK pin to `1.4.0-beta.3`. - **`src/class-plugin.php`** — the SDK renamed the `EnforcementMode` enum cases (`SOFT`/`STRICT` → `OBSERVE`/`ENFORCE`). Updated the default in `Plugin::get_enforcement_mode()` from `EnforcementMode::SOFT` to `EnforcementMode::OBSERVE` (the equivalent monitor-but-don't-block mode, and the SDK's own constructor default). ## Compatibility note The wire values backing the enum also changed (`soft`/`strict` → `observe`/`enforce`). Any site overriding the mode via the `SUPERTAB_CONNECT_ENFORCEMENT_MODE` constant must use the new values (`observe`/`enforce`); old values now fall through to the default. Acceptable for a pre-release. ## Verification - `composer lint` — no syntax errors - `composer phpcs` — no violations - `composer phpstan` — no errors - `composer test` — 58 tests, 65 assertions pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
# [1.3.0-beta.3](v1.3.0-beta.2...v1.3.0-beta.3) (2026-06-30) ### Features * updated PHP SDK ([390cb54](390cb54))
This PR updates PHP SDK to 1.4.0-beta.5 with async analytics transport layer.
# [1.3.0-beta.4](v1.3.0-beta.3...v1.3.0-beta.4) (2026-06-30) ### Features * update getsupertab/connect-sdk-php to 1.4.0-beta.5 ([#13](#13)) ([ca12083](ca12083))
## Problem Analytics events emitted by the plugin reached the relay identifying as `WordPress/<ver>; <site_url>` rather than the SDK. `WP_Http_Client` (the plugin's `HttpClientInterface` adapter) never set a `User-Agent`, so `wp_remote_get()` / `wp_remote_post()` fell back to WordPress's default UA on **every** outbound SDK call — analytics (`/ingest/events`), JWKS, billing events, and license-token requests. The SDK's native curl client sets `supertab-connect-sdk-php/<version>` via `CURLOPT_USERAGENT`, but the plugin injects this WP wrapper instead, so that identity was silently dropped. ## Fix Set `'user-agent' => HttpClient::resolveUserAgent()` on both `get()` and `post()`. WordPress honors the `user-agent` arg (overriding its default) and it passes through `vip_safe_wp_remote_get()` on VIP. Outbound requests now identify as `supertab-connect-sdk-php/<version>`, matching the native client. Note: this is the *transport* User-Agent the relay observes. The visitor/bot UA recorded in the analytics event payload (`userAgent`) is unaffected. ## Tests - New `tests/WPHttpClientTest.php` (written test-first — verified it failed on the missing `user-agent` key before the fix). - Added WP HTTP API stubs (`wp_remote_post`/`wp_remote_get`/`is_wp_error`/`wp_remote_retrieve_*`) that capture outbound args. - `composer test`: 61/61 pass · `lint`, `phpcs`, `phpstan`: clean.
# [1.3.0-beta.5](v1.3.0-beta.4...v1.3.0-beta.5) (2026-06-30) ### Bug Fixes * send SDK user-agent on plugin HTTP requests ([#14](#14)) ([9891e03](9891e03))
# [1.3.0-beta.6](v1.3.0-beta.5...v1.3.0-beta.6) (2026-07-01) ### Features * update PHP SDK to v1.4.0-beta.6 ([b01f004](b01f004))
This PR adds an opt-in WordPress job queue for analytics delivery — gated behind the `SUPERTAB_CONNECT_USE_WP_QUEUE` constant — so the analytics POST runs off the visitor request when enabled, dispatched by Action Scheduler or WP-Cron. ## Context Bot protection emits one analytics event per classified request. The plugin passes `analyticsEnabled: true`, so the SDK builds its default `DeferredAnalyticsTransport`, which only takes the POST off the request on FastCGI SAPIs. On mod_php/apache2handler (including `.wp-env`), `fastcgi_finish_request()` is absent, so the POST to `/ingest/events` runs **synchronously on the visitor request**, adding latency to every classified page view. ## Key Changes - **Opt-in via `SUPERTAB_CONNECT_USE_WP_QUEUE`** (`src/class-plugin.php`): define it truthy in `wp-config.php` to route analytics through the queue. When unset or falsy, the plugin injects a `null` transport and the SDK falls back to its default — **behavior is identical to before this PR**. - **`src/class-analytics-dispatcher.php`** (new `Analytics_Dispatcher`): `enqueue()` selects the best available backend — **Action Scheduler** (`as_enqueue_async_action`, near-real-time async loopback) → **WP-Cron** (`wp_schedule_single_event`) → **inline** best-effort last resort. `dispatch()` (the registered job handler) rehydrates via `AnalyticsEvent::fromArray()` and POSTs through the SDK's `HttpAnalyticsTransport`. Fail-open throughout. - **`src/class-plugin.php`**: when the queue is enabled, the job handler is registered in **all** request contexts (admin-ajax for AS async, `wp-cron.php` for the WP-Cron/AS queue runner, front-end) so the runner can deliver wherever it executes; an injected `CallbackAnalyticsTransport` replaces the default transport. Bot-protection interception stays front-end-only and skips REST + cron. - **`supertab-connect.php`**: deactivation hook clears pending work args-agnostically (`wp_unschedule_hook()` + hook-only `as_unschedule_all_actions()`). - The WP-Cron fallback is best-effort — without Action Scheduler each event serializes into the autoloaded `cron` option, so AS (bundled with WooCommerce / available on VIP) is the intended production path and is auto-selected when present. No delivery retries (deliver-once, fail-open), matching current SDK semantics. ## Verification - `composer test` — **67/67 unit tests passing** (100 assertions); `lint`, `phpcs` (WordPress-VIP-Go), `phpstan` (level 5) clean. - End-to-end in a running WordPress (with `SUPERTAB_CONNECT_USE_WP_QUEUE` enabled: bot request → enqueue → `cron event run` → dispatch) not yet exercised live.
# [1.3.0-beta.7](v1.3.0-beta.6...v1.3.0-beta.7) (2026-07-03) ### Features * queue analytics dispatch via Action Scheduler / WP-Cron ([#15](#15)) ([5397d46](5397d46))
This PR exposes `GET /.well-known/supertab/status` so the Supertab Connect API can probe a merchant site and learn what's running there — plugin version, bundled PHP SDK version, effective enforcement mode, and whether event reporting is active. It's the WordPress counterpart of getsupertab/connect-sdk-typescript#40 and pairs with the backend's per-component version resolver, which maps `component.kind: "wordpress-plugin"` to the wordpress.org update registry. ## Context The backend's live-health check probes sites with a backend-minted ES256 challenge JWT (`Authorization: Bearer`, purpose `status-probe`, `aud` = the site origin, verifiable against the platform JWKS). A valid challenge gets the live config; anything else gets a minimal `404 {"supertab": true}` decoy, so the endpoint discloses nothing to anyone without a challenge. Without a `component` identity, the backend's legacy shim would resolve a WordPress site's version against npm — wrong registry, wrong label. The PHP SDK's own `handleRequest()` also serves this path, but in this plugin it only runs when bot protection is enabled and the path matches active patterns — and it reports the SDK's identity, not the plugin's. The plugin needs to own its component identity and answer probes regardless of bot-protection state. ## Key Changes - **`Status_Handler`** (new, mirrors `RSL_License_Handler`): hooks `parse_request` at priority 5 — before `Bot_Protection`'s 9, so probes never reach bot detection or analytics — exact-matches `.well-known/supertab/status`, verifies the challenge via the SDK's `StatusChallengeVerifier` (JWKS cached in WP transients, refresh-and-retry on key rotation), and responds: - invalid/missing challenge → `404` `{"supertab": true}` (fail-closed: every verification failure, including JWKS fetch errors, resolves to the decoy) - valid challenge → `200` with `{runtime: null, sdkVersion, component: {kind: "wordpress-plugin", version}, enforcement, eventReporting}` - both with `Content-Type: application/json` + `Cache-Control: no-store` - **Registered unconditionally** in `Plugin::init()` (like the RSL handler), so the backend can learn the plugin version even when bot protection is off; `enforcement`/`eventReporting` honestly report `disabled`/`false` in that case. - **SDK bump `1.4.0-beta.6` → `1.4.0-beta.8`** for `StatusChallengeVerifier`/`JwksProvider`. - **`Bot_Protection` now serves the SDK's `RespondResult`** (new in beta.8) instead of leaking its headers onto the next rendered page — relevant on plain-permalink sites, where the SDK's URL-based status check fires instead of the plugin's handler. - **Tests**: 14 new unit tests (decoy paths, fail-closed behavior incl. throwing verifier, payload shape, hook priority, header filtering) plus an integration test proving WP's rewrite pipeline delivers the dot-prefixed path to `parse_request`. Verified end-to-end in wp-env: unauthenticated and garbage-bearer probes return the exact decoy with correct headers. Reachability was verified live against a WP Engine production site (theleek.demo.supertab.co): the path passes through Cloudflare and WP Engine's proxy into WordPress's front controller. ## Notes Both degradation modes fail closed and look like "plugin not installed" to the backend (which degrades to "show version, no nudge"): - **Plain permalinks**: `$wp->request` isn't populated without rewrite rules, so the plugin handler can't match (same constraint as `license.xml`); with bot protection on, the SDK's own status response answers instead (without `component`).
# [1.3.0-beta.8](v1.3.0-beta.7...v1.3.0-beta.8) (2026-07-14) ### Features * serve /.well-known/supertab/status self-report endpoint ([#18](#18)) ([d44a344](d44a344)), closes [getsupertab/connect-sdk-typescript#40](getsupertab/connect-sdk-typescript#40)
…Status_Handler (#19) This PR fixes the self-report status endpoint silently serving the 404 decoy to the backend's challenge probes on hosts where Apache withholds the `Authorization` header from `$_SERVER` — which is why the live self-report check fails for sites on WP Engine despite running 1.3.0-beta.8. ## Context The backend's health check probes `/.well-known/supertab/status` with a challenge JWT in the `Authorization` header. `Status_Handler::get_authorization_header()` read only `$_SERVER['HTTP_AUTHORIZATION']` / `REDIRECT_HTTP_AUTHORIZATION` — but Apache withholds `Authorization` from the CGI-style `$_SERVER` variables (a CGI-era behavior), while `getallheaders()` still exposes it. Since every verification failure fails closed to the decoy, the endpoint looked healthy from outside while every valid probe was rejected. Stock WordPress masks this: since WP 5.6 the core `.htaccess` rewrite block includes `RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]`, which re-exports the header. Hosts that generate their own server config without that rule (WP Engine among them) hit the bug. That's also why the original wp-env verification couldn't catch it — wp-env's stock `.htaccess` carries the compensating rule. This is the same defect fixed in the SDK by getsupertab/connect-sdk-php#24, found live on the vanilla-PHP self-report demo; the plugin duplicated the pre-fix header reading instead of going through the SDK. ## Key Changes - **SDK bump `1.4.0-beta.9` → `1.4.0-beta.10`**, which ships `RequestContext::resolveAuthorizationHeader()` (and fixes the same bug inside the SDK's own `handleRequest()` path used by `Bot_Protection` for license-token checks). - **`Status_Handler::get_authorization_header()`** now delegates to the SDK resolver: `$_SERVER` wins when populated, otherwise the raw request headers are searched case-insensitively. New protected `get_raw_request_headers()` seam wraps `getallheaders()` (guarded by `function_exists`; unavailable under the CLI SAPI) so tests can inject headers. - **3 regression tests**: fallback to raw headers when `$_SERVER` lacks the header, `$_SERVER` precedence, and empty result when absent everywhere. Verified end-to-end in wp-env (Apache + mod_php) via A/B: with the core `.htaccess` auth rule removed to mirror affected hosts, the old code never delivered the bearer to the verifier (no JWKS activity, decoy served); with this fix the same probe reaches `StatusChallengeVerifier`, fetches the platform JWKS, and fails only on the (deliberately) unverifiable test token — decoy behavior for invalid/missing challenges is unchanged.
# [1.3.0-beta.9](v1.3.0-beta.8...v1.3.0-beta.9) (2026-07-14) ### Bug Fixes * resolve Authorization via the SDK's getallheaders() fallback in Status_Handler ([#19](#19)) ([d515452](d515452)), closes [getsupertab/connect-sdk-php#24](getsupertab/connect-sdk-php#24)
…#17) This PR replaces the per-event analytics queue jobs with a custom-table buffer drained hourly in batches of up to 500 events, using the `/ingest/events` endpoint's new batch support (JSON array body → `BatchIngestEventResponse`). ## Context With `SUPERTAB_CONNECT_USE_WP_QUEUE` enabled, every classified bot request scheduled its own queue job (Action Scheduler async → WP-Cron fallback), and each job POSTed a single event to `/ingest/events`. On busy sites that means one AS table write plus one loopback request plus one outbound POST per event. The API now accepts up to 500 events per request, so events can be accumulated and delivered in hourly batches instead. ## Key Changes - **`src/class-analytics-queue-table.php`** (new `Analytics_Queue_Table`): owns `{$wpdb->prefix}supertab_connect_analytics_queue` (`id`, `payload` LONGTEXT, `created_at`). `install()` is dbDelta-based and version-gated via `supertab_connect_db_version` (autoload=no); `insert()` is one atomic row write; `claim_batch( $limit )` SELECTs oldest-first and DELETEs the claimed rows in the same call — **delete-before-send**, so delivery is deliver-once with no double-send window. - **`src/class-analytics-dispatcher.php`** (rewritten): `enqueue()` now INSERTs a JSON row instead of scheduling a job (row cap 10,000 → drop; insert failure → inline single-event fallback). New `flush()` drains up to 10 batches × 500 events per run and POSTs each batch as a JSON array to `/ingest/events` (Bearer auth via the existing `WP_Http_Client`). Non-2xx, partial rejections (`rejected_count`), timeouts: debug-logged and dropped — fail-open, no retries, matching SDK semantics. The legacy per-event hook stays registered so jobs queued by a previous version drain gracefully. - **Scheduling**: one hourly recurring `supertab_connect_flush_analytics` action — `as_schedule_recurring_action()` when Action Scheduler is present, `wp_schedule_event()` fallback — ensured idempotently on admin/cron requests (front-end requests do no schema or schedule work), with automatic migration of a stale WP-Cron recurrence when AS appears. Deactivation unschedules both hooks in both backends. - **Lifecycle**: activation provisions the table; already-active installs self-heal on the first admin/cron request after update; `uninstall.php` drops the table and version option. - Behavior with `SUPERTAB_CONNECT_USE_WP_QUEUE` unset/falsy is unchanged (SDK default transport path untouched). ## Verification - `composer test` — **92/92 unit tests passing** (165 assertions); `lint`, `phpcs` (WordPress-VIP-Go), `phpstan` (level 5) clean. - End-to-end in `.wp-env`: activation creates the table; a `GPTBot` request buffers a row; `wp cron event run supertab_connect_flush_analytics` drains the buffer to zero with a single batch POST; deactivation removes the cron entry. The POST was exercised against the live sandbox API with an invalid key — real HTTP 401, event dropped fail-open as designed. - Not yet verified live: a 2xx batch delivery with a valid sandbox merchant key.
# [1.3.0-beta.10](v1.3.0-beta.9...v1.3.0-beta.10) (2026-07-15) ### Features * batch analytics events via custom-table buffer and hourly flush ([#17](#17)) ([d125194](d125194))
#20) This PR adds real-database integration coverage for `Analytics_Queue_Table` — the SQL semantics the unit suite's in-memory `wpdb` spy records but cannot execute. **Stacked on #17** (base: `feat/analytics-batch-buffer`): review only the test diff here; the stack lands on `beta` as one work package once #17 merges. ## Context #17 gained two SQL-level behaviors late in review — the `FOR UPDATE` claim transaction and the O(1) id-span capacity probe — that nothing executes against a real database. The existing integration suite (WP tests lib + MySQL 8.0 in CI, WP 6.4/7.0 × PHP 8.1/8.4) is the right home for that proof. ## Key Changes `tests/integration/AnalyticsQueueTableTest.php` (new, 6 tests): - **Schema** — `install()` materializes the exact dbDelta schema (`DESCRIBE`-verified) and records the version option; a version-current re-run provably leaves existing rows untouched. - **Round-trip** — payloads survive byte-for-byte (multibyte UTF-8 included); `created_at` is current UTC. - **Drain** — `claim_batch()` returns oldest-first, deletes what it returns, and reports a drained buffer as an empty claim. - **Capacity probe** — `is_full()` boundary at the cap, plus the documented id-span early-trip: a carved id gap trips the cap with only 2 rows present (the fail-open direction, pinned as intended). - **`FOR UPDATE` claim** — a second mysqli session holds locks on the oldest rows while the main connection claims: the contending claim must return nothing (never the locked rows, `innodb_lock_wait_timeout = 1` to fail fast); after the holder deletes-and-commits, a follow-up claim returns exactly the survivors. Asserts claims are disjoint and exhaustive — no double delivery, no loss. Test-framework notes (documented in the file header): the suite's `CREATE TEMPORARY TABLE` rewrite is disabled (temporary tables are invisible to the second connection) and cleanup is explicit, since `claim_batch()`'s own `COMMIT` ends the per-test rollback wrapper. ## Verification - `composer lint`, `phpcs` (WordPress-VIP-Go), `phpstan` (level 5) clean. - The WP tests lib + MySQL harness is CI-only (same as #18's `StatusRoutingTest`) — the Integration matrix on this PR is the gate.
This PR makes analytics opt-in: a new "Enable analytics" checkbox on the plugin settings screen, off by default. Only when checked does the plugin pass `analyticsEnabled: true` to the SDK or register the batch-buffer delivery machinery. ## Context Analytics was implicitly always on: whenever CAP ran, `Plugin::init()` passed a hardcoded `analyticsEnabled: true` to the SDK, and (with the WP queue enabled) buffered and delivered events. Merchants had no control. This PR gives them the switch and defaults it to off. ## Key Changes - **`Settings`** — new option `supertab_connect_analytics_enabled` with `is_analytics_enabled()` / `set_analytics_enabled()`, mirroring the CAP pair; cleared by `Settings::delete()` and on uninstall. - **Settings screen** — "Enable analytics" checkbox inside the CAP section (hidden with it when CAP is off). Saved on the same form branch as CAP; reset to off when the API key is cleared. - **`Plugin::init()`** — the misnamed `$analytics_enabled` local (it actually gated bot protection) is renamed `$bot_protection_active`; a real `$analytics_enabled = $bot_protection_active && is_analytics_enabled()` now gates the batch-buffer dispatcher, and the SDK receives the derived flag instead of hardcoded `true`. With analytics off there is no queue registration, no flush schedule, and the SDK builds its noop transport. **CAP behavior is unchanged by the toggle.** - **Status self-report** — `eventReporting` in `/.well-known/supertab/status` now also requires the opt-in, so the backend prober sees the truth on analytics-off sites (found in review; `enforcement` reporting unchanged). ## Verification - `composer test` — 116/116 passing (213 assertions); lint, phpcs (WordPress-VIP-Go), phpstan (level 5) clean. - wp-env smoke: default (option absent) → GPTBot request buffers **no** analytics row; option on → row buffered as before; Playwright round-trip of the settings screen (checkbox renders in the CAP section, saves both ways, hides with the CAP toggle); status endpoint reports `eventReporting: false` until opted in.
# [1.3.0-beta.11](v1.3.0-beta.10...v1.3.0-beta.11) (2026-07-16) ### Features * make analytics opt-in via a settings checkbox ([#21](#21)) ([9df74f0](9df74f0))
This PR fixes the hourly analytics flush never being scheduled on sites where Action Scheduler is installed, which left buffered events stranded in the queue table and nothing ever reaching the relay or merchant dashboard. ## Context Action Scheduler's data store only initializes on `init` priority 1, but the plugin boots on `plugins_loaded` and `Analytics_Dispatcher::register()` called `ensure_scheduled()` synchronously right there. Called that early, `as_has_scheduled_action()` returns `false` and `as_schedule_recurring_action()` returns `0` without scheduling anything (both guarded by `ActionScheduler::is_initialized()`, with a `_doing_it_wrong` notice). Because Action Scheduler's functions *exist* at that point, `action_scheduler_available()` was true and the WP-Cron fallback was never reached either — the flush job ended up scheduled in neither backend. Reproduced on a live install (1.3.0-beta.11, queue constant on, analytics opted in): events buffer into the queue table while neither Scheduled Actions nor `wp cron event list` contains `supertab_connect_flush_analytics`. wp-env never caught it because Action Scheduler isn't installed there, so the code fell back to `wp_schedule_event()`, which works fine at `plugins_loaded`. ## Solution `register()` now hooks `ensure_scheduled()` to `init` instead of calling it inline. The plugin boots at `plugins_loaded`, which always precedes `init` (including on cron requests), so the deferred check runs once Action Scheduler is ready; the WP-Cron fallback path is unaffected. `ensure_scheduled()` becomes public so WordPress can invoke it as a hook callback. Verified end-to-end in wp-env with the `action-scheduler` plugin installed and `SUPERTAB_CONNECT_USE_WP_QUEUE` on: after the fix an admin request schedules the pending recurring action (no `_doing_it_wrong` notices), and firing the hook drains the buffer and POSTs the batch to `/ingest/events`. Events already buffered on affected installs will be delivered by the first flush after deploy; no migration needed.
# [1.3.0-beta.12](v1.3.0-beta.11...v1.3.0-beta.12) (2026-07-16) ### Bug Fixes * defer the analytics flush schedule check to init ([#22](#22)) ([8322a84](8322a84))
# [1.3.0-beta.13](v1.3.0-beta.12...v1.3.0-beta.13) (2026-07-17) ### Bug Fixes * add vertical spacing between the CAP and analytics checkboxes ([a12bf0c](a12bf0c))
# [1.3.0-beta.14](v1.3.0-beta.13...v1.3.0-beta.14) (2026-07-17) ### Bug Fixes * copy for enabling agent & bot classification ([817fd05](817fd05))
…ngest service (#23) * feat: update PHP SDK to v2.0.1 and route analytics to the dedicated ingest service * fix: accept legacy soft/strict enforcement mode values from 1.2.x configs
# [1.3.0-beta.15](v1.3.0-beta.14...v1.3.0-beta.15) (2026-08-27) ### Features * update PHP SDK to v2.0.1 and route analytics to the dedicated ingest service ([#23](#23)) ([90b6c69](90b6c69))
|
🎉 This PR is included in version 1.3.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR promotes the beta line to the stable 1.3.0 release.
Context
The 1.3.0 beta series has been running through fourteen prereleases and is ready to ship. Main is a strict ancestor of beta, so this promotion is a clean fast-forward with no divergent history. PR #23 (SDK 2.0.1 bump plus the legacy enforcement value mapping) should be merged into beta before this PR; once it lands, this PR picks it up automatically.
What 1.3.0 brings over 1.2.2
Versioning
No commit in the beta history carries a breaking-change marker, so semantic-release computes 1.3.0 on merge. Please use a merge commit rather than a squash for this promotion, so semantic-release sees the individual conventional commits on main.