@touchcastllc/napster-companion-api-dev 1.0.0-alpha.74 → 1.0.0-alpha.77
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.css +1 -1
- package/lib/index.d.ts +10 -0
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/lib/index.standalone.js +1 -1
- package/lib/services/edge-mcp/edge-mcp-bridge.d.ts +30 -0
- package/lib/services/edge-mcp/edge-mcp-discovery.d.ts +13 -6
- package/lib/shell/mount-shell.d.ts +102 -0
- package/lib/types/index.d.ts +21 -0
- package/package.json +1 -1
|
@@ -20,6 +20,14 @@ export interface EdgeMcpBridgeOptions {
|
|
|
20
20
|
* false to manage the agent's function list yourself. Default: `true`.
|
|
21
21
|
*/
|
|
22
22
|
registerInlineFunctions?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Read tools from a same-origin child iframe's `document.modelContext` instead of
|
|
25
|
+
* this window's. Used by the persistent-agent shell: the avatar + bridge live in the
|
|
26
|
+
* top-level document while the SITE (and its tools) live in the wrapped iframe. The
|
|
27
|
+
* bridge re-discovers on each iframe `load` (navigation) and routes tool calls into
|
|
28
|
+
* it (`executeTool` runs in the iframe's realm, so the site operates itself).
|
|
29
|
+
*/
|
|
30
|
+
iframe?: HTMLIFrameElement;
|
|
23
31
|
}
|
|
24
32
|
export declare class EdgeMcpBridge {
|
|
25
33
|
private mc;
|
|
@@ -27,12 +35,25 @@ export declare class EdgeMcpBridge {
|
|
|
27
35
|
private onToolChange;
|
|
28
36
|
private onResourceUpdated;
|
|
29
37
|
private onResourceListChanged;
|
|
38
|
+
private onIframeLoad;
|
|
30
39
|
private readonly seededUris;
|
|
31
40
|
private lastInlineSig;
|
|
32
41
|
private sessionReady;
|
|
33
42
|
private disposed;
|
|
34
43
|
private readonly options;
|
|
35
44
|
constructor(options: EdgeMcpBridgeOptions);
|
|
45
|
+
/** The document whose `modelContext` we read — the target iframe's, or this window's. */
|
|
46
|
+
private targetDoc;
|
|
47
|
+
/**
|
|
48
|
+
* Switch the bridge's target to a different iframe (or back to this window's document)
|
|
49
|
+
* at runtime, then re-discover the model context there. Used by the persistent-agent
|
|
50
|
+
* shell's frame-on-navigate mode: the site starts UN-framed — its WebMCP tools live on
|
|
51
|
+
* the top-level `document.modelContext` — and only gets wrapped in an iframe on the first
|
|
52
|
+
* navigation, at which point the bridge must re-target from the top-level document to the
|
|
53
|
+
* new iframe. Detaches the old iframe's `load` listener, installs one on the new iframe,
|
|
54
|
+
* and calls `reattach()` (which polls, so a not-yet-loaded iframe still binds once ready).
|
|
55
|
+
*/
|
|
56
|
+
setIframe(iframe: HTMLIFrameElement | null): void;
|
|
36
57
|
/**
|
|
37
58
|
* Discover `document.modelContext` in the page, cache its tools, and wire up
|
|
38
59
|
* the `toolchange` / `resourceupdated` listeners. Returns the model context,
|
|
@@ -40,6 +61,15 @@ export declare class EdgeMcpBridge {
|
|
|
40
61
|
* failure is silent and non-fatal.
|
|
41
62
|
*/
|
|
42
63
|
attach(): Promise<EdgeMcpModelContext | null>;
|
|
64
|
+
/** Remove listeners from the current model context and drop the ref (no state reset). */
|
|
65
|
+
private unbind;
|
|
66
|
+
/**
|
|
67
|
+
* Re-discover and re-bind after the target iframe navigated to a NEW document (its old
|
|
68
|
+
* `document.modelContext` is dead). Keeps `sessionReady` (the avatar session in the parent
|
|
69
|
+
* survives), but resets the per-document dedupe so tools + resources re-register for the
|
|
70
|
+
* new page.
|
|
71
|
+
*/
|
|
72
|
+
private reattach;
|
|
43
73
|
/** Attach to a known model context: cache tools and subscribe to events. */
|
|
44
74
|
private bind;
|
|
45
75
|
/**
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import type { EdgeMcpModelContext } from "./edge-mcp-types";
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Read `modelContext` from a document, falling back to the deprecated navigator alias.
|
|
4
|
+
*
|
|
5
|
+
* `doc` defaults to the ambient `document`. Pass a same-origin child frame's
|
|
6
|
+
* `contentDocument` to read ITS surface instead (the shell targets the wrapped
|
|
7
|
+
* iframe this way). Cross-origin access throws — caught and returned as `null`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getModelContext(doc?: Document | null): EdgeMcpModelContext | null;
|
|
4
10
|
/**
|
|
5
11
|
* Discover `document.modelContext`, polling briefly if it is not present yet.
|
|
6
12
|
*
|
|
7
13
|
* Resolves with the model context if found, or `null` after `timeoutMs` if no
|
|
8
14
|
* WebMCP surface shows up. Never rejects.
|
|
9
15
|
*
|
|
10
|
-
* @param timeoutMs How long to wait for a late-installing polyfill. Default
|
|
11
|
-
*
|
|
12
|
-
*
|
|
16
|
+
* @param timeoutMs How long to wait for a late-installing polyfill. Default 1500ms.
|
|
17
|
+
* @param getDoc Optional getter for the document to read (re-evaluated each poll,
|
|
18
|
+
* since a targeted iframe's `contentDocument` changes as it navigates).
|
|
19
|
+
* Omit to use the ambient `document`.
|
|
13
20
|
*/
|
|
14
|
-
export declare function discoverModelContext(timeoutMs?: number): Promise<EdgeMcpModelContext | null>;
|
|
21
|
+
export declare function discoverModelContext(timeoutMs?: number, getDoc?: () => Document | null): Promise<EdgeMcpModelContext | null>;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { NapsterCompanionApiConfig, NapsterCompanionApiInstance } from "../types";
|
|
2
|
+
export interface ShellOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Returns a fresh connection token. The site implements this (typically a POST to
|
|
5
|
+
* its own endpoint that mints a token server-side). Required.
|
|
6
|
+
*/
|
|
7
|
+
getToken: () => Promise<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Persist the session across page navigation by wrapping the current page in a
|
|
10
|
+
* same-origin iframe on connect (needed for multi-page apps). Default: `false` —
|
|
11
|
+
* the avatar mounts inline in the current page and a full page navigation ends the
|
|
12
|
+
* session (a normal in-page widget). Turn on only when you need cross-navigation
|
|
13
|
+
* persistence.
|
|
14
|
+
*/
|
|
15
|
+
persist?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Defer the iframe wrap until the user first navigates (requires `persist`). Instead of
|
|
18
|
+
* wrapping the current page on connect, the landing page stays fully native — no iframe —
|
|
19
|
+
* and the avatar mounts in the top-level document. The shell intercepts the first in-site
|
|
20
|
+
* link click and, if the target is allowed (not matched by `persistConfig`), wraps the site
|
|
21
|
+
* into an iframe THEN, loading the clicked page, so the session persists from that point on.
|
|
22
|
+
*
|
|
23
|
+
* Only anchor clicks are caught. Programmatic navigation (`location.assign`, `location.href=`),
|
|
24
|
+
* address-bar/bookmark loads, modified/`_blank` clicks, and links matched by `persistConfig`
|
|
25
|
+
* fall through to a normal top-level navigation, which ends the session (as a plain widget would).
|
|
26
|
+
*
|
|
27
|
+
* Default: `false` (wrap eagerly on connect). Ignored unless `persist` is on.
|
|
28
|
+
*/
|
|
29
|
+
frameOnNavigate?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The ONLY URLs that break out of the iframe (open at the top window and end the session).
|
|
32
|
+
* A link is opened inside the iframe unless it matches this denylist — use it for URLs that
|
|
33
|
+
* can't be framed, e.g. an identity / SSO subdomain, or same-origin paths that redirect
|
|
34
|
+
* off-site. Everything not listed (including other cross-origin links) navigates in the iframe.
|
|
35
|
+
*/
|
|
36
|
+
persistConfig?: {
|
|
37
|
+
/**
|
|
38
|
+
* Hostnames to force out of the iframe. Matched as the exact host OR a parent domain —
|
|
39
|
+
* e.g. `"napster.com"` also matches `"identity.napster.com"`.
|
|
40
|
+
*/
|
|
41
|
+
domains?: string[];
|
|
42
|
+
/**
|
|
43
|
+
* URLs to force out of the iframe: an absolute `"https://…"` (exact or prefix match), or a
|
|
44
|
+
* same-origin path prefix like `"/signout"`.
|
|
45
|
+
*/
|
|
46
|
+
urls?: string[];
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* SECOND persistence variant (no iframe). When a session is active and the user navigates
|
|
50
|
+
* (a normal full page load), automatically start a NEW session on the next page — so the
|
|
51
|
+
* avatar "follows" the user across pages. Each page is a fresh connection (the backend can
|
|
52
|
+
* resume the conversation by externalClientId). The intent is remembered in sessionStorage
|
|
53
|
+
* and cleared when the user ends the session. Ignored when `persist` (the iframe variant)
|
|
54
|
+
* is on. Default: `false`.
|
|
55
|
+
*/
|
|
56
|
+
reconnectOnNavigation?: boolean;
|
|
57
|
+
/** When `persist` is on, the URL to load in the iframe. Default: the current page (`location.href`). */
|
|
58
|
+
siteUrl?: string;
|
|
59
|
+
/** Element to build the launcher/iframe into. Default: `document.body`. */
|
|
60
|
+
mount?: HTMLElement;
|
|
61
|
+
/** Avatar config forwarded to `init()`. `mountContainer`/`layout` are managed by the shell. */
|
|
62
|
+
avatar?: Partial<NapsterCompanionApiConfig>;
|
|
63
|
+
/** The iframe `allow` attribute (Permissions Policy for the site). Default: `"autoplay; clipboard-write"`. */
|
|
64
|
+
iframeAllow?: string;
|
|
65
|
+
/** Launcher button label. Default: `"Talk to an agent"`. */
|
|
66
|
+
launcherLabel?: string;
|
|
67
|
+
/** Start a session immediately instead of showing a launcher. Default: `false`. */
|
|
68
|
+
autoConnect?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* While a session is active, mirror the iframe's path into the address bar (so inner
|
|
71
|
+
* pages stay shareable/bookmarkable) and follow parent back/forward into the iframe.
|
|
72
|
+
* Same-origin only. Default: `true`.
|
|
73
|
+
*/
|
|
74
|
+
syncHistory?: boolean;
|
|
75
|
+
/** Log shell lifecycle to the console. Default: `false`. */
|
|
76
|
+
debug?: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface ShellController {
|
|
79
|
+
/** `true` if this call built the launcher (top-level); `false` if it no-oped (framed content). */
|
|
80
|
+
isShell: boolean;
|
|
81
|
+
/** The live avatar instance once connected, else `null`. */
|
|
82
|
+
getInstance(): NapsterCompanionApiInstance | null;
|
|
83
|
+
/** The site iframe while a session is active, else `null`. */
|
|
84
|
+
getIframe(): HTMLIFrameElement | null;
|
|
85
|
+
/** Start a session: connect the avatar (and, with `persist`, wrap the current page in the iframe). */
|
|
86
|
+
connect(): Promise<void>;
|
|
87
|
+
/** End the session (and, if wrapped, unwrap back to the plain site). */
|
|
88
|
+
disconnect(): void;
|
|
89
|
+
/** Remove the launcher and any active session/iframe. */
|
|
90
|
+
destroy(): void;
|
|
91
|
+
}
|
|
92
|
+
type InitFn = (token: string, config?: Partial<NapsterCompanionApiConfig>) => Promise<NapsterCompanionApiInstance>;
|
|
93
|
+
/**
|
|
94
|
+
* Build the lazy persistent-agent shell. Returns a {@link ShellController}.
|
|
95
|
+
*
|
|
96
|
+
* A no-op (returns a controller with `isShell: false`) when run inside the shell
|
|
97
|
+
* iframe (framed content), so the same snippet is safe to include on every page.
|
|
98
|
+
*
|
|
99
|
+
* `init` is the SDK's `init` method, wired by the SDK.
|
|
100
|
+
*/
|
|
101
|
+
export declare function mountShell(init: InitFn, options: ShellOptions): ShellController;
|
|
102
|
+
export {};
|
package/lib/types/index.d.ts
CHANGED
|
@@ -335,6 +335,13 @@ export interface NapsterCompanionApiConfig {
|
|
|
335
335
|
functions?: CompanionFunction[];
|
|
336
336
|
/** Enable debug logging throughout the SDK. When enabled, detailed logs will be output to the console. */
|
|
337
337
|
debug?: boolean;
|
|
338
|
+
/**
|
|
339
|
+
* Read WebMCP tools from a same-origin child iframe's `document.modelContext` instead of
|
|
340
|
+
* this window's. Set by the persistent-agent shell (`mountShell` with `persist`) so the
|
|
341
|
+
* avatar in the top-level document operates the SITE running inside the wrapped iframe.
|
|
342
|
+
* Leave unset for a normal same-page integration.
|
|
343
|
+
*/
|
|
344
|
+
edgeMcpIframe?: HTMLIFrameElement;
|
|
338
345
|
/** Analytics configuration controls analytics delivery and tracking. */
|
|
339
346
|
analytics?: AnalyticsConfig;
|
|
340
347
|
/** Lifecycle callbacks. All are optional. */
|
|
@@ -372,6 +379,14 @@ export interface NapsterCompanionApiInstance {
|
|
|
372
379
|
avatarIsVisible: () => boolean;
|
|
373
380
|
/** Tear down the SDK, remove DOM nodes and clean up resources. */
|
|
374
381
|
destroy: () => void;
|
|
382
|
+
/**
|
|
383
|
+
* Re-target the Edge MCP bridge at runtime: read the site's WebMCP tools from the given
|
|
384
|
+
* same-origin iframe's `document.modelContext`, or pass `null` to read them from this
|
|
385
|
+
* window's document. Used by the persistent-agent shell's frame-on-navigate mode, where
|
|
386
|
+
* the site is only wrapped in an iframe on the first navigation. No-op if the bridge is
|
|
387
|
+
* inactive.
|
|
388
|
+
*/
|
|
389
|
+
setEdgeMcpIframe: (iframe: HTMLIFrameElement | null) => void;
|
|
375
390
|
/**
|
|
376
391
|
* The current session identifier. Available after a connection is established
|
|
377
392
|
* and reset to `undefined` once the connection is closed.
|
|
@@ -456,6 +471,12 @@ export interface NapsterCompanionApiSDK {
|
|
|
456
471
|
* Returns a Promise that resolves to a controllable `NapsterCompanionApiInstance`.
|
|
457
472
|
*/
|
|
458
473
|
init(token: string, config?: Partial<NapsterCompanionApiConfig>): Promise<NapsterCompanionApiInstance>;
|
|
474
|
+
/**
|
|
475
|
+
* Mount a persistent-agent shell for multi-page apps: renders the site in a
|
|
476
|
+
* same-origin iframe with the avatar in the top-level shell, so the agent
|
|
477
|
+
* session survives navigation. No-op when run as the framed content.
|
|
478
|
+
*/
|
|
479
|
+
mountShell(options: import("../shell/mount-shell").ShellOptions): import("../shell/mount-shell").ShellController;
|
|
459
480
|
/** The SDK version string (useful for diagnostics). */
|
|
460
481
|
version: string;
|
|
461
482
|
}
|