feat: add W3DS Gateway embeddable web component and notification helpers#890
feat: add W3DS Gateway embeddable web component and notification helpers#890
Conversation
📝 WalkthroughWalkthroughAdds a new package Changes
Sequence Diagram(s)sequenceDiagram
participant User as User (Browser)
participant Modal as W3dsGatewayChooser
participant Resolver as Resolver
participant Registry as Registry API
participant App as Target App
User->>Modal: open() / click "Open Chooser"
Modal->>Modal: emit gateway-open
Modal->>Resolver: resolveEName(ename, schemaId, options)
Resolver->>Registry: GET /platforms (if registryUrl provided)
Registry-->>Resolver: platformUrls map
Resolver->>Resolver: merge URLs (defaults + registry + overrides)
Resolver->>Resolver: select handlers & build app URLs
Resolver-->>Modal: GatewayResolveResult (apps, schemaLabel)
Modal->>Modal: render app list
User->>Modal: click app entry
Modal->>Modal: emit gateway-select / gateway-close
Modal->>App: navigate to resolved URL
App-->>User: open content
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (7)
test.html (2)
37-46: Consider importing schema definitions to avoid drift.The schema IDs are hardcoded here and could become out of sync with the actual
SchemaIdsdefined in the package. For a test page this is acceptable, but consider adding a comment noting that these should match the values inschemas.ts.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test.html` around lines 37 - 46, The hardcoded schema ID list in the local variable "schemas" can drift from the canonical SchemaIds; update the test to import or reference the authoritative values (SchemaIds) from schemas.ts instead of duplicating literals, or at minimum add a clear inline comment above the "schemas" array stating these IDs must match SchemaIds in schemas.ts; refer to the "schemas" constant and the "SchemaIds"/schemas.ts export when making the change.
19-19: Remove or uncomment the unused paragraph.Line 19 contains a commented-out paragraph. Either remove it or uncomment it if the guidance is helpful for users of the test page.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test.html` at line 19, There is a commented-out paragraph element ("<!-- <p>Click a content type, then "Open Chooser" to see which apps can handle it.</p> -->"); either delete this commented <p> entirely if it’s unnecessary, or uncomment it by removing the comment markers so the paragraph becomes an active <p> element for users; update the surrounding HTML accordingly (the commented-out paragraph is the unique element to change).packages/w3ds-gateway/src/icons.ts (1)
79-84: Consider adding a note about trusted input forletterIcon.The
letterIconfunction interpolatesletter,bg, andfgdirectly into the SVG template without escaping. While all current usages (line 86) use hardcoded trusted strings, adding a JSDoc note about requiring trusted input would help prevent future misuse if the function is exposed more broadly.📝 Suggested documentation addition
// ─── Lettermark fallback (for platforms without a brand SVG) ──────────────── +/** + * Generates a lettermark icon SVG. + * `@param` letter - The letter(s) to display (trusted input only) + * `@param` bg - Background color (trusted input only) + * `@param` fg - Foreground/text color (trusted input only) + * `@internal` This function does not escape inputs - use only with trusted values. + */ function letterIcon(letter: string, bg: string, fg: string): string {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/icons.ts` around lines 79 - 84, The SVG template in letterIcon directly interpolates letter, bg, and fg without escaping, so annotate the function with a JSDoc comment on letterIcon stating that letter, bg, and fg must be trusted or pre-escaped (or validated) before being passed in; mention the injection risk and list expected formats (e.g., single-character plain text for letter, valid CSS color strings for bg and fg) so future callers know to sanitize or escape input if coming from untrusted sources.packages/w3ds-gateway/src/__tests__/modal.test.ts (1)
112-113: Consider usingvi.waitForor explicit promise-based waiting.Using
setTimeoutwith arbitrary delays (50ms, 100ms) for async resolution can lead to flaky tests. Vitest providesvi.waitForor you could await the actual resolution promise if exposed.💡 Example using waitFor pattern
- el.open(); - // Wait for async resolve - await new Promise((r) => setTimeout(r, 50)); + el.open(); + // Wait for error to appear + await vi.waitFor(() => { + const error = el.shadowRoot!.querySelector(".gateway-error"); + expect(error).not.toBeNull(); + }); - const error = el.shadowRoot!.querySelector(".gateway-error"); - expect(error).not.toBeNull();This pattern would need to be applied to lines 126, 142, 162, and 187 as well.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/__tests__/modal.test.ts` around lines 112 - 113, Replace arbitrary setTimeout-based waits (e.g. await new Promise((r) => setTimeout(r, 50))) in the modal tests with deterministic waits: use vitest's vi.waitFor to wait for the specific condition/assertion to become true (e.g. await vi.waitFor(() => expect(...) or check DOM changes) or, when available, await the actual resolution promise returned by the function under test; update every occurrence of the setTimeout snippet (the one used in these tests) so tests no longer rely on fixed delays.packages/w3ds-gateway/src/capabilities.ts (1)
339-374: Module-level mutable state may cause issues in SSR or parallel test environments.The
_platformUrlsstate is shared across all consumers. In SSR scenarios or parallel test runs, mutations from one context could leak into another.Consider providing a
resetPlatformUrls()function for testing, or documenting that this is intentionally singleton state for browser-only use.♻️ Optional: Add reset function for testing
let _platformUrls: Record<string, string> = { ...DEFAULT_PLATFORM_URLS }; + +/** + * Reset platform URLs to defaults. Useful for testing. + * `@internal` + */ +export function resetPlatformUrls(): void { + _platformUrls = { ...DEFAULT_PLATFORM_URLS }; +}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/capabilities.ts` around lines 339 - 374, The module-level mutable _platformUrls may leak across SSR or tests; add and export a reset function (e.g., resetPlatformUrls) that restores _platformUrls to { ...DEFAULT_PLATFORM_URLS } so tests/servers can explicitly reset state, and update configurePlatformUrls (and its JSDoc) to mention singleton behavior and recommend calling resetPlatformUrls in test teardown; reference the _platformUrls variable and the configurePlatformUrls function when adding the new resetPlatformUrls utility.packages/w3ds-gateway/src/notifications.ts (1)
149-155: Consider consolidatingescapeHtmlandescapeAttr.Both functions escape the same four characters (
&,<,>,") and produce identical output. You could use a single helper for both contexts or keep them separate for semantic clarity if you anticipate them diverging.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/notifications.ts` around lines 149 - 155, escapeHtml and escapeAttr perform identical escaping; consolidate them by keeping a single helper (e.g., escapeHtml) and have the other function delegate to it or remove the duplicate. Update references to escapeAttr to call escapeHtml (or rename to a neutral name like escapeForHtml) and keep a comment indicating semantic aliasing if you want to preserve both names for clarity; ensure function signatures remain the same and include both function names (escapeHtml, escapeAttr) in your change so callers can be found and updated.packages/w3ds-gateway/src/modal.ts (1)
62-126: Code duplication withresolver.ts.The
fetchRegistryPlatforms,buildUrl, andresolvefunctions duplicate logic fromresolver.ts. Consider importing and reusing the resolver functions to avoid maintenance burden.♻️ Proposed refactor to reuse resolver
-import { - PLATFORM_CAPABILITIES, - getPlatformUrls, -} from "./capabilities.js"; +import { resolveEName, resolveENameSync } from "./resolver.js"; import { SchemaLabels } from "./schemas.js"; import { PLATFORM_ICONS, FALLBACK_ICON } from "./icons.js"; import type { ResolvedApp } from "./types.js"; import type { SchemaId } from "./schemas.js"; - -// ... remove fetchRegistryPlatforms, buildUrl, resolve functions ...Then in
doResolve():- const result = await resolve(ename, schemaId, entityId, registryUrl); + const result = await resolveEName( + { ename, schemaId, entityId }, + { registryUrl } + );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/modal.ts` around lines 62 - 126, The local implementations of fetchRegistryPlatforms, buildUrl, and resolve duplicate logic from resolver.ts; remove these local functions and import the canonical implementations from resolver.ts (e.g., import { fetchRegistryPlatforms, buildUrl, resolve } from "resolver") and update any callers (such as doResolve) to call the imported resolve; ensure you merge platform URL overrides the same way resolver does and keep using the existing symbols platformUrls, SchemaLabels, and PLATFORM_CAPABILITIES so callers and types remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/w3ds-gateway/src/notifications.ts`:
- Around line 128-129: The href attribute value in the attrs array is not
escaped for HTML attribute context, so update the code that builds attrs (where
`href="${uri}"` is created) to HTML-attribute-escape the `uri` returned from
`buildGatewayUri` (escape &, ", ', <, > at minimum) before interpolation; either
call an existing sanitizer (e.g., `escapeHtmlAttr`) or add a small helper and
use it when constructing `attrs` so the attribute value cannot break the HTML.
In `@packages/w3ds-gateway/src/resolver.ts`:
- Around line 56-80: The mapping in resolver.ts uses a brittle positional array
keyOrder to pair with the Registry response `urls`, causing silent mismatches;
update the code to stop relying on positional order by requesting/expecting a
keyed object from the Registry (e.g., { pictique: "...", blabsy: "..." }) or by
locating platform identifiers in the response instead of using `keyOrder`+`urls`
pairing, then adapt the resolver function (and the duplicate logic in modal.ts)
to build the result by key lookup, add validation/fallback when keys are
missing, and centralize the platform keys into a single exported constant
(replace both local `keyOrder` arrays) so changes to platform list are made in
one place.
---
Nitpick comments:
In `@packages/w3ds-gateway/src/__tests__/modal.test.ts`:
- Around line 112-113: Replace arbitrary setTimeout-based waits (e.g. await new
Promise((r) => setTimeout(r, 50))) in the modal tests with deterministic waits:
use vitest's vi.waitFor to wait for the specific condition/assertion to become
true (e.g. await vi.waitFor(() => expect(...) or check DOM changes) or, when
available, await the actual resolution promise returned by the function under
test; update every occurrence of the setTimeout snippet (the one used in these
tests) so tests no longer rely on fixed delays.
In `@packages/w3ds-gateway/src/capabilities.ts`:
- Around line 339-374: The module-level mutable _platformUrls may leak across
SSR or tests; add and export a reset function (e.g., resetPlatformUrls) that
restores _platformUrls to { ...DEFAULT_PLATFORM_URLS } so tests/servers can
explicitly reset state, and update configurePlatformUrls (and its JSDoc) to
mention singleton behavior and recommend calling resetPlatformUrls in test
teardown; reference the _platformUrls variable and the configurePlatformUrls
function when adding the new resetPlatformUrls utility.
In `@packages/w3ds-gateway/src/icons.ts`:
- Around line 79-84: The SVG template in letterIcon directly interpolates
letter, bg, and fg without escaping, so annotate the function with a JSDoc
comment on letterIcon stating that letter, bg, and fg must be trusted or
pre-escaped (or validated) before being passed in; mention the injection risk
and list expected formats (e.g., single-character plain text for letter, valid
CSS color strings for bg and fg) so future callers know to sanitize or escape
input if coming from untrusted sources.
In `@packages/w3ds-gateway/src/modal.ts`:
- Around line 62-126: The local implementations of fetchRegistryPlatforms,
buildUrl, and resolve duplicate logic from resolver.ts; remove these local
functions and import the canonical implementations from resolver.ts (e.g.,
import { fetchRegistryPlatforms, buildUrl, resolve } from "resolver") and update
any callers (such as doResolve) to call the imported resolve; ensure you merge
platform URL overrides the same way resolver does and keep using the existing
symbols platformUrls, SchemaLabels, and PLATFORM_CAPABILITIES so callers and
types remain unchanged.
In `@packages/w3ds-gateway/src/notifications.ts`:
- Around line 149-155: escapeHtml and escapeAttr perform identical escaping;
consolidate them by keeping a single helper (e.g., escapeHtml) and have the
other function delegate to it or remove the duplicate. Update references to
escapeAttr to call escapeHtml (or rename to a neutral name like escapeForHtml)
and keep a comment indicating semantic aliasing if you want to preserve both
names for clarity; ensure function signatures remain the same and include both
function names (escapeHtml, escapeAttr) in your change so callers can be found
and updated.
In `@test.html`:
- Around line 37-46: The hardcoded schema ID list in the local variable
"schemas" can drift from the canonical SchemaIds; update the test to import or
reference the authoritative values (SchemaIds) from schemas.ts instead of
duplicating literals, or at minimum add a clear inline comment above the
"schemas" array stating these IDs must match SchemaIds in schemas.ts; refer to
the "schemas" constant and the "SchemaIds"/schemas.ts export when making the
change.
- Line 19: There is a commented-out paragraph element ("<!-- <p>Click a content
type, then "Open Chooser" to see which apps can handle it.</p> -->"); either
delete this commented <p> entirely if it’s unnecessary, or uncomment it by
removing the comment markers so the paragraph becomes an active <p> element for
users; update the surrounding HTML accordingly (the commented-out paragraph is
the unique element to change).
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (16)
packages/w3ds-gateway/README.mdpackages/w3ds-gateway/package.jsonpackages/w3ds-gateway/src/__tests__/modal.test.tspackages/w3ds-gateway/src/__tests__/notifications.test.tspackages/w3ds-gateway/src/__tests__/resolver.test.tspackages/w3ds-gateway/src/capabilities.tspackages/w3ds-gateway/src/icons.tspackages/w3ds-gateway/src/index.tspackages/w3ds-gateway/src/modal.tspackages/w3ds-gateway/src/notifications.tspackages/w3ds-gateway/src/resolver.tspackages/w3ds-gateway/src/schemas.tspackages/w3ds-gateway/src/types.tspackages/w3ds-gateway/tsconfig.build.jsonpackages/w3ds-gateway/tsconfig.jsontest.html
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
packages/w3ds-gateway/src/modal.ts (1)
63-121: Reuseresolver.tsinstead of maintaining inline resolver duplication.This duplicates fetch/build/resolve logic already present in
packages/w3ds-gateway/src/resolver.ts, increasing drift risk and double-fix burden.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/modal.ts` around lines 63 - 121, This file duplicates resolver logic — replace the local implementations of fetchRegistryPlatforms, buildUrl, and resolve with the shared implementations from packages/w3ds-gateway/src/resolver.ts: remove the in-file functions fetchRegistryPlatforms, buildUrl, and resolve, import the corresponding exported functions (or a single resolver export) from resolver.ts, and update any call sites to use the imported symbols so behavior is delegated to the canonical resolver implementation; ensure exported types like ResolvedApp/SchemaId (or equivalents) are also imported if needed.packages/w3ds-gateway/src/resolver.ts (1)
47-53: Add a timeout to Registry fetch to avoid hanging resolution paths.The external call currently has no timeout; stalled requests can block UI resolution indefinitely.
Suggested change
async function fetchRegistryPlatforms( registryUrl: string, fetchFn: typeof globalThis.fetch, ): Promise<Record<string, string>> { try { - const response = await fetchFn(`${registryUrl}/platforms`); + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 5000); + const response = await fetchFn(`${registryUrl}/platforms`, { signal: controller.signal }); + clearTimeout(timeout); if (!response.ok) return {};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/resolver.ts` around lines 47 - 53, The fetchRegistryPlatforms function performs an external fetch without a timeout; update it to use an AbortController to enforce a timeout (e.g., 3–5s), pass the controller.signal to fetchFn(`${registryUrl}/platforms`, { signal }), and clear the timer after response or error; on timeout (abort) or any fetch error return an empty object and ensure the controller timer is cleaned up to avoid leaks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/w3ds-gateway/src/capabilities.ts`:
- Around line 345-359: DEFAULT_PLATFORM_URLS currently contains hardcoded
localhost fallbacks which can leak into production; change the default to an
empty map and ensure runtime requires explicit configuration/hydration instead
of falling back to localhost. Replace the contents of DEFAULT_PLATFORM_URLS with
an empty object ({}), update the initial _platformUrls initialization to mirror
that empty default, and audit any code that assumes those keys exist (e.g.,
places referencing DEFAULT_PLATFORM_URLS or _platformUrls) so they handle
missing entries or throw a clear error prompting explicit configuration.
In `@packages/w3ds-gateway/src/modal.ts`:
- Around line 81-86: The buildUrl/template resolution can produce non-http(s)
URLs from resolver/override base URLs; before assigning to link.href (places
that call buildUrl and set link.href), parse the resolved string with the URL
constructor and validate url.protocol is "http:" or "https:" and only then
assign link.href; if the protocol is invalid or parsing throws, do not set
link.href (or set to a safe fallback like an empty string) and render the link
as non-clickable. Update code paths that call buildUrl (and the code that sets
link.href around lines 81-86 and 531-535) to perform this validation and handle
failures safely.
- Around line 384-389: connectedCallback() always calls render() which appends a
new shadow DOM and event listeners on every reconnect; change
connectedCallback() to first detect if the element is already rendered (e.g.,
check this.shadowRoot or a boolean like this._isRendered) and only call render()
when not rendered, or alternatively have render() clear existing shadowRoot
before appending; ensure open() is still invoked when the component has the
"open" attribute after the guarded render. Apply the same guard to the other
affected block referenced (lines 448-499) so render() and event wiring are
idempotent.
- Around line 501-573: doResolve can race: a slower previous resolve() may
overwrite UI from a later run; fix by adding a per-instance "currentResolveId"
(or similar) counter/nonce on the class, increment it at the start of
doResolve(), capture the id in a local const before awaiting resolve(), and
after every await (both success and in catch) check that the captured id matches
this.currentResolveId before mutating DOM (headerText, body, footer) so stale
results are ignored; reference doResolve, resolve, this.headerText, this.body,
this.footer and ensure the check is applied both in the try path (before
updating header/apps/footer) and in the catch path (before showing error).
In `@packages/w3ds-gateway/src/resolver.ts`:
- Around line 73-83: The buildUrl function currently interpolates baseUrl
unsafely; before trimming or using baseUrl in buildUrl, parse it with the URL
constructor and ensure url.protocol is exactly "http:" or "https:" and reject
otherwise (throw a clear Error or skip emitting the link). Apply the same
validation logic to the other URL-building sites referenced (the functions at
the other ranges: lines 132-143 and 174-185) so all resolved app link builders
validate baseUrl's scheme before constructing or returning the final URL.
---
Nitpick comments:
In `@packages/w3ds-gateway/src/modal.ts`:
- Around line 63-121: This file duplicates resolver logic — replace the local
implementations of fetchRegistryPlatforms, buildUrl, and resolve with the shared
implementations from packages/w3ds-gateway/src/resolver.ts: remove the in-file
functions fetchRegistryPlatforms, buildUrl, and resolve, import the
corresponding exported functions (or a single resolver export) from resolver.ts,
and update any call sites to use the imported symbols so behavior is delegated
to the canonical resolver implementation; ensure exported types like
ResolvedApp/SchemaId (or equivalents) are also imported if needed.
In `@packages/w3ds-gateway/src/resolver.ts`:
- Around line 47-53: The fetchRegistryPlatforms function performs an external
fetch without a timeout; update it to use an AbortController to enforce a
timeout (e.g., 3–5s), pass the controller.signal to
fetchFn(`${registryUrl}/platforms`, { signal }), and clear the timer after
response or error; on timeout (abort) or any fetch error return an empty object
and ensure the controller timer is cleaned up to avoid leaks.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
packages/w3ds-gateway/src/capabilities.tspackages/w3ds-gateway/src/index.tspackages/w3ds-gateway/src/modal.tspackages/w3ds-gateway/src/notifications.tspackages/w3ds-gateway/src/resolver.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/w3ds-gateway/src/notifications.ts
- packages/w3ds-gateway/src/index.ts
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/w3ds-gateway/src/modal.ts (2)
109-117: MissingisSafeUrlfilter in inline resolve function.Unlike
resolver.tswhich filters unsafe URLs during app list construction, this inlineresolvefunction includes all apps regardless of URL safety. The safety check happens later at render time (line 542), so there's no security issue, but this inconsistency could cause confusion if the resolve function is used elsewhere.Consider adding the
isSafeUrlfilter here for consistency:const apps: ResolvedApp[] = handlers - .filter((h) => platformUrls[h.platformKey]) + .filter((h) => platformUrls[h.platformKey] && isSafeUrl(platformUrls[h.platformKey])) .map((h) => ({🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/modal.ts` around lines 109 - 117, The apps construction in the inline resolve is missing the same URL safety filtering used elsewhere: update the handlers -> map pipeline that produces the apps array (the const apps: ResolvedApp[] assignment) to filter out entries whose built URL is not safe by applying isSafeUrl(buildUrl(...)) (use handlers, buildUrl, platformUrls, entityId, ename and platformKey to create the URL) before mapping so only safe URLs are included in apps; keep the existing properties (platformName, platformKey, url, label, icon) unchanged.
64-87: Consider extracting shared resolver utilities to avoid duplication.
fetchRegistryPlatformsandbuildUrlare duplicated betweenmodal.tsandresolver.ts. Consider importing these from the resolver module or extracting to a shared internal module to maintain a single source of truth.Additionally, note the subtle behavioral difference:
resolver.tsfilters out apps with unsafe URLs entirely (line 134), whilemodal.tsincludes them but renders them disabled (lines 541-553). This is reasonable UX, but be aware of the inconsistency if the resolver is used for non-UI purposes.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/w3ds-gateway/src/modal.ts` around lines 64 - 87, The functions fetchRegistryPlatforms and buildUrl are duplicated between modal.ts and resolver.ts; extract them into a shared internal utility module (e.g., export from a new file or the existing resolver module) and import those utilities into both modal.ts and resolver.ts to avoid duplication and keep a single source of truth; ensure you move both the fetchRegistryPlatforms implementation (including the try/catch and REGISTRY_PLATFORM_KEY_ORDER usage) and the buildUrl implementation, then adjust modal.ts to import and use them, and if preserving UI-specific behavior, keep modal.ts logic that disables unsafe URLs while resolver.ts continues to filter them so behavior remains intentional and documented.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/w3ds-gateway/src/modal.ts`:
- Around line 109-117: The apps construction in the inline resolve is missing
the same URL safety filtering used elsewhere: update the handlers -> map
pipeline that produces the apps array (the const apps: ResolvedApp[] assignment)
to filter out entries whose built URL is not safe by applying
isSafeUrl(buildUrl(...)) (use handlers, buildUrl, platformUrls, entityId, ename
and platformKey to create the URL) before mapping so only safe URLs are included
in apps; keep the existing properties (platformName, platformKey, url, label,
icon) unchanged.
- Around line 64-87: The functions fetchRegistryPlatforms and buildUrl are
duplicated between modal.ts and resolver.ts; extract them into a shared internal
utility module (e.g., export from a new file or the existing resolver module)
and import those utilities into both modal.ts and resolver.ts to avoid
duplication and keep a single source of truth; ensure you move both the
fetchRegistryPlatforms implementation (including the try/catch and
REGISTRY_PLATFORM_KEY_ORDER usage) and the buildUrl implementation, then adjust
modal.ts to import and use them, and if preserving UI-specific behavior, keep
modal.ts logic that disables unsafe URLs while resolver.ts continues to filter
them so behavior remains intentional and documented.
ℹ️ Review info
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
packages/w3ds-gateway/src/capabilities.tspackages/w3ds-gateway/src/modal.tspackages/w3ds-gateway/src/resolver.tspackages/w3ds-gateway/src/utils.tstest.html
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/w3ds-gateway/src/capabilities.ts
Description of change
w3ds-gateway — a new self-contained package that translates W3DS eNames into application URLs and presents an "Open with..." chooser.
What it solves: Given an eName (W3ID) and a content type (schema ID from the Ontology), the package determines which platforms can handle that content and builds deep links into each one.
A REST API was the obvious first approach, but the capability map (which schema opens on which platform) is static and already known at build time. Platform URLs are already available from the Registry's existing GET /platforms. A dedicated backend endpoint would just be a pass-through wrapper with an extra network hop and a new service to maintain.
Going frontend-first means platforms can drop in the Web Component and resolve entirely client-side, with no new infrastructure. The resolver still supports the Registry for live URL hydration. A REST wrapper around resolveEName() remains trivial to add for any server-side use case — but it's not the default path.
Issue Number
Closes #780
Type of change
How the change has been tested
Tested with vitest and test page to simulate notifications
Change checklist
Summary by CodeRabbit