From beb3e5b4e81cf99929a50f8a1000691b4836d006 Mon Sep 17 00:00:00 2001 From: Bonanza Date: Thu, 13 Aug 2026 20:34:31 -0700 Subject: [PATCH] =?UTF-8?q?fix(plugin-types):=20correct=20globals=20docblo?= =?UTF-8?q?ck=20=E2=80=94=20pre-encoded=20query=20values=20round-trip=20ve?= =?UTF-8?q?rbatim=20on=20href?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The globals subpath docblock (and the plugin-types README) taught the %3A → %253A percent-encoding double-encode as a pinned href round-trip divergence of the host URL shim. That was disproven during fn-182.5's review: the shim's URL(string:) → absoluteString href path preserves pre-encoded query values VERBATIM (Desktop pins this via JSCURLCoherenceTests.testPreEncodedQueryRoundTripComputedRow); the double-encode reproduces only via Foundation's URLComponents.queryItems construction path, which the shim never uses. The corrected epic contract forbids teaching it as shim behavior. - href accessor docblock: verbatim round-trip statement replaces the double-encode claim - constructor divergence list: double-encode bullet removed; explicit "NOT a divergence" note explains the queryItems-only artifact - README divergence bullet aligned Also pre-stages the lockstep 3.0.2 bump (npm version 3.0.2 --workspaces --include-workspace-root --no-git-tag-version --allow-same-version), matching the 3.0.1 release-prep pattern; release.sh tolerates the pre-staged bump. Publish remains user-authorized (./release.sh 3.0.2 post-merge). --- package-lock.json | 10 +++++----- package.json | 2 +- packages/plugin-types/README.md | 6 ++++-- packages/plugin-types/package.json | 2 +- packages/plugin-types/src/globals.ts | 15 +++++++++++---- packages/plugin-utils/package.json | 2 +- packages/view-builders/package.json | 2 +- 7 files changed, 24 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index c10320a..7264601 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@appos.space/plugin-sdk", - "version": "3.0.1", + "version": "3.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@appos.space/plugin-sdk", - "version": "3.0.1", + "version": "3.0.2", "workspaces": [ "packages/*" ], @@ -140,7 +140,7 @@ }, "packages/plugin-types": { "name": "@appos.space/plugin-types", - "version": "3.0.1", + "version": "3.0.2", "license": "MIT", "devDependencies": { "typescript": "^5.4.0" @@ -148,7 +148,7 @@ }, "packages/plugin-utils": { "name": "@appos.space/plugin-utils", - "version": "3.0.1", + "version": "3.0.2", "license": "MIT", "devDependencies": { "@types/node": "^25.5.2", @@ -157,7 +157,7 @@ }, "packages/view-builders": { "name": "@appos.space/view-builders", - "version": "3.0.1", + "version": "3.0.2", "license": "MIT", "dependencies": { "@appos.space/plugin-types": "*" diff --git a/package.json b/package.json index c72680f..9a76e94 100644 --- a/package.json +++ b/package.json @@ -22,5 +22,5 @@ "engines": { "node": ">=18" }, - "version": "3.0.1" + "version": "3.0.2" } diff --git a/packages/plugin-types/README.md b/packages/plugin-types/README.md index 531ca12..531dfbd 100644 --- a/packages/plugin-types/README.md +++ b/packages/plugin-types/README.md @@ -69,8 +69,10 @@ Notes: - **Foundation (RFC 3986) semantics, not a WHATWG polyfill.** The pinned divergences are documented in the subpath's docblock: default ports retained in `href`/`port`, empty path stays `""`, out-of-range ports - accepted, double-encode on href round-trip of pre-encoded query values, - `hostname` lowercased with IPv6 unbracketed (`host`/`origin` re-bracket). + accepted, `hostname` lowercased with IPv6 unbracketed (`host`/`origin` + re-bracket). Pre-encoded query values round-trip verbatim on href + (`%3A` stays `%3A`) — the `%3A` → `%253A` double-encode seen via + Foundation's `URLComponents.queryItems` does not apply to this API. - **`url.searchParams` is NOT in the v1 subset** — the type omits it and the runtime getter throws a `TypeError`; parse `url.search` manually. `URL.parse` is likewise absent, and all accessors are readonly. diff --git a/packages/plugin-types/package.json b/packages/plugin-types/package.json index 85cc393..178f823 100644 --- a/packages/plugin-types/package.json +++ b/packages/plugin-types/package.json @@ -1,6 +1,6 @@ { "name": "@appos.space/plugin-types", - "version": "3.0.1", + "version": "3.0.2", "description": "TypeScript type definitions for the AppOS Plugin API", "main": "dist/index.d.ts", "types": "dist/index.d.ts", diff --git a/packages/plugin-types/src/globals.ts b/packages/plugin-types/src/globals.ts index 95575d6..fd6098b 100644 --- a/packages/plugin-types/src/globals.ts +++ b/packages/plugin-types/src/globals.ts @@ -47,8 +47,9 @@ declare global { * `toString()` and `toJSON()`, so template literals, `String(u)` and * `JSON.stringify(u)` all yield the href. * - * Pinned divergence: pre-percent-encoded query values are DOUBLE-encoded - * on an href round-trip (`%3A` → `%253A`). + * Pre-percent-encoded query values round-trip VERBATIM (`%3A` stays + * `%3A`) — no double-encoding on the href path. See the {@link URL} var + * declaration's divergence notes. */ readonly href: string; /** Lowercased scheme followed by `":"` (e.g. `"https:"`). */ @@ -163,8 +164,6 @@ declare global { * - Default ports are RETAINED in `href`/`port` (`:443` is not dropped). * - An empty path stays `""` (WHATWG would give `"/"`). * - Out-of-range ports are accepted. - * - Pre-percent-encoded query values double-encode on an href round-trip - * (`%3A` → `%253A`). * - `hostname` is lowercased and IPv6 literals come WITHOUT brackets; * `host`/`origin` re-bracket them (`https://[::1]:8443/x` → hostname * `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`). @@ -172,6 +171,14 @@ declare global { * (scheme-less inputs like `"not a url"` are rejected by the validity * predicate, not by Foundation's parser). * + * NOT a divergence: pre-percent-encoded query values round-trip VERBATIM + * on href (`%3A` stays `%3A`, matching WHATWG). The widely-reported + * `%3A` → `%253A` double-encode reproduces only via Foundation's + * `URLComponents.queryItems` construction path, which this API never + * uses — the host parses with `URL(string:)` and serializes with + * `absoluteString`, and pins the verbatim round-trip in its coherence + * tests. + * * ## Out-of-subset surface (fails loudly, never silently wrong) * * - `url.searchParams`: absent from these types; the runtime getter diff --git a/packages/plugin-utils/package.json b/packages/plugin-utils/package.json index 5b7a2db..8e9082f 100644 --- a/packages/plugin-utils/package.json +++ b/packages/plugin-utils/package.json @@ -1,6 +1,6 @@ { "name": "@appos.space/plugin-utils", - "version": "3.0.1", + "version": "3.0.2", "description": "Common utility functions for AppOS plugins", "type": "module", "main": "dist/index.js", diff --git a/packages/view-builders/package.json b/packages/view-builders/package.json index 5924e64..f59330a 100644 --- a/packages/view-builders/package.json +++ b/packages/view-builders/package.json @@ -1,6 +1,6 @@ { "name": "@appos.space/view-builders", - "version": "3.0.1", + "version": "3.0.2", "description": "Typed ViewDescriptor builder helpers for AppOS plugins", "type": "module", "main": "dist/index.js",