diff --git a/plugins/appos-dev/compiled/manifest.json b/plugins/appos-dev/compiled/manifest.json index 1aacc46..fff39ad 100644 --- a/plugins/appos-dev/compiled/manifest.json +++ b/plugins/appos-dev/compiled/manifest.json @@ -2,13 +2,13 @@ "schema": 1, "artifacts": { "cli-chat-system-prompt.md": "0ace5e39d569fac84ca22e244bfb5dae8242b14e059395894f16f712b1ecc170", - "plugin-factory-context.md": "229f7fc7d15a6650f0923cf33d88e0712ecbb20a184df24e22d26a2c34783720" + "plugin-factory-context.md": "389a4fc99cdc0fee665ac63bc1600332865b6f3fd7ff5314bd18a54065bf5bec" }, "sources": { "SKILL.md": "f4868a887ab7726ca8c6463b90953a1efb82712fb1a3df5e68888f9b43644cd6", "reference/extension-api.md": "b37b24cd2a5e02345b361ee08aea29a885084ebfb4a8a73358036a91572c49e8", - "reference/patterns.md": "93fc7e840176ab625fe848fb6df92f1c98301b5e13811906696eca3be91822f9", - "reference/plugin-api/index.d.ts": "7299f52226d577aa8ad6160357a8dee2e02f90bb19a18f93ec31d605f5756b27", + "reference/patterns.md": "15be968192b19bbd74735a03571322df1a7c4fece579c6d2b3105eabb270f40a", + "reference/plugin-api/index.d.ts": "cbdd7a4aa96001d3fe664427ffc30039ce09ba80dca2eee32960c5c925c4d8d4", "reference/plugin-api/core.d.ts": "3e951ef56e6148879fbe92d592399711f4bad5556f1549233ec3d32d0d9c49f9", "reference/plugin-api/views.d.ts": "323f8570fe1c0e6140b5ee1f46cf79f368dc4d920e4b14544e5bf5753ae05f1e", "reference/plugin-api/namespaces.d.ts": "467e6374fced48f027c22e9d01fe6daa68839b2f9881726725b901c66ccc8b1f", diff --git a/plugins/appos-dev/compiled/plugin-factory-context.md b/plugins/appos-dev/compiled/plugin-factory-context.md index 3894cce..febb26d 100644 --- a/plugins/appos-dev/compiled/plugin-factory-context.md +++ b/plugins/appos-dev/compiled/plugin-factory-context.md @@ -2849,8 +2849,8 @@ void activate; **File**: `src/services/validate.ts` -AppOS hosts 1.1.0+ inject a native `URL` global — a Foundation-bridged -implementation (macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill. +AppOS hosts 1.1.0+ inject a native `URL` global — Foundation-bridged +(macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill. Guard EVERY use, exactly like the timer guard in §8: older hosts never had it, users can switch it off (`appos.jsc.urlGlobal.disabled`), and menu-bar contexts do not carry it in v1 — `minHostVersion` removes only the @@ -2862,9 +2862,8 @@ const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']); function isValidMediaUrl(raw: string): boolean { if (typeof URL !== 'function') { // Older host / kill switch / menu-bar context: URL is absent. - // Decide the fallback per feature — fail CLOSED for - // security-shaped checks like this one, or hand-parse when the - // feature must still work without URL. + // Fail CLOSED for security-shaped checks like this one, or + // hand-parse when the feature must work without URL. return false; } // canParse never throws (unlike the constructor), so probe first. @@ -2878,16 +2877,17 @@ void isValidMediaUrl; **Key points:** - `typeof URL === 'function'` before EVERY use — same contract as the - timer guard (§8); the §18 ambient file's `| undefined` typing turns an + timer guard (§8); the §18 ambient `| undefined` typing turns an unguarded `new URL(...)` into a compile error, not a runtime surprise. -- **Parse coherence**: `u.hostname` is lowercased and, for the same input, - is the exact host string that enters the AppOS host's own security - normalizers (permission validation, initial-hop network checks) — - plugin-side URL validation parses identically to host-side enforcement. +- **Parse coherence**: `u.hostname` is lowercased and is the exact host + string entering the host's security normalizers — plugin-side URL + validation parses identically to host-side enforcement. - `URL.canParse(input, base?)` returns a boolean and NEVER throws; `new URL(...)` throws a real `TypeError` - (`e instanceof TypeError === true`) on scheme-less or unparseable input, - and validates a supplied `base` first. + (`e instanceof TypeError === true`) on unparseable input, and on + scheme-less/scheme-relative input lacking a valid absolute `base` + (`new URL('/api', 'https://x.test')` resolves); a bad `base` throws + first. - Instances are immutable (readonly accessors; assignment is a sloppy-mode no-op). `String(u)`, template literals, and `JSON.stringify(u)` all yield `u.href`. @@ -2896,11 +2896,11 @@ void isValidMediaUrl; malformed percent sequences, so wrap it in try/catch). - Pinned Foundation-vs-WHATWG divergences (intended — do not "fix"): default ports are RETAINED (`https://x:443/` keeps port `"443"`), an - empty path stays `""` (not `"/"`), IPv6 hostnames come WITHOUT brackets - while `host`/`origin` re-bracket them (`https://[::1]:8443/x` → - hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`), - and pre-encoded query values double-encode on an href round-trip - (`%3A` → `%253A`). + empty path stays `""` (not `"/"`), and IPv6 hostnames come WITHOUT + brackets while `host`/`origin` re-bracket them (`https://[::1]:8443/x` + → hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`). + (The `%3A` → `%253A` double-encode is `URLComponents.queryItems`-only; + `href` round-trips preserve pre-encoded query values verbatim.) ## Further reading diff --git a/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md b/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md index 7065dd3..48e3ab0 100644 --- a/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md +++ b/plugins/appos-dev/skills/appos-plugin-dev/reference/patterns.md @@ -1372,8 +1372,8 @@ void activate; **File**: `src/services/validate.ts` -AppOS hosts 1.1.0+ inject a native `URL` global — a Foundation-bridged -implementation (macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill. +AppOS hosts 1.1.0+ inject a native `URL` global — Foundation-bridged +(macOS `URL(string:)`, RFC 3986), NOT a WHATWG polyfill. Guard EVERY use, exactly like the timer guard in §8: older hosts never had it, users can switch it off (`appos.jsc.urlGlobal.disabled`), and menu-bar contexts do not carry it in v1 — `minHostVersion` removes only the @@ -1385,9 +1385,8 @@ const ALLOWED_PROTOCOLS = new Set(['http:', 'https:']); function isValidMediaUrl(raw: string): boolean { if (typeof URL !== 'function') { // Older host / kill switch / menu-bar context: URL is absent. - // Decide the fallback per feature — fail CLOSED for - // security-shaped checks like this one, or hand-parse when the - // feature must still work without URL. + // Fail CLOSED for security-shaped checks like this one, or + // hand-parse when the feature must work without URL. return false; } // canParse never throws (unlike the constructor), so probe first. @@ -1401,16 +1400,17 @@ void isValidMediaUrl; **Key points:** - `typeof URL === 'function'` before EVERY use — same contract as the - timer guard (§8); the §18 ambient file's `| undefined` typing turns an + timer guard (§8); the §18 ambient `| undefined` typing turns an unguarded `new URL(...)` into a compile error, not a runtime surprise. -- **Parse coherence**: `u.hostname` is lowercased and, for the same input, - is the exact host string that enters the AppOS host's own security - normalizers (permission validation, initial-hop network checks) — - plugin-side URL validation parses identically to host-side enforcement. +- **Parse coherence**: `u.hostname` is lowercased and is the exact host + string entering the host's security normalizers — plugin-side URL + validation parses identically to host-side enforcement. - `URL.canParse(input, base?)` returns a boolean and NEVER throws; `new URL(...)` throws a real `TypeError` - (`e instanceof TypeError === true`) on scheme-less or unparseable input, - and validates a supplied `base` first. + (`e instanceof TypeError === true`) on unparseable input, and on + scheme-less/scheme-relative input lacking a valid absolute `base` + (`new URL('/api', 'https://x.test')` resolves); a bad `base` throws + first. - Instances are immutable (readonly accessors; assignment is a sloppy-mode no-op). `String(u)`, template literals, and `JSON.stringify(u)` all yield `u.href`. @@ -1419,11 +1419,11 @@ void isValidMediaUrl; malformed percent sequences, so wrap it in try/catch). - Pinned Foundation-vs-WHATWG divergences (intended — do not "fix"): default ports are RETAINED (`https://x:443/` keeps port `"443"`), an - empty path stays `""` (not `"/"`), IPv6 hostnames come WITHOUT brackets - while `host`/`origin` re-bracket them (`https://[::1]:8443/x` → - hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`), - and pre-encoded query values double-encode on an href round-trip - (`%3A` → `%253A`). + empty path stays `""` (not `"/"`), and IPv6 hostnames come WITHOUT + brackets while `host`/`origin` re-bracket them (`https://[::1]:8443/x` + → hostname `"::1"`, host `"[::1]:8443"`, origin `"https://[::1]:8443"`). + (The `%3A` → `%253A` double-encode is `URLComponents.queryItems`-only; + `href` round-trips preserve pre-encoded query values verbatim.) ## Further reading