@touchcastllc/napster-companion-api-dev 1.0.0-alpha.82 → 1.0.0-alpha.83
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/README.md +3 -3
- package/lib/button/element.d.ts +6 -0
- package/lib/button/index.d.ts +46 -0
- package/lib/components/MicPermission/index.d.ts +17 -0
- package/lib/index.css +1 -1
- package/lib/index.d.ts +37 -9
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/lib/index.standalone.js +1 -1
- package/lib/persistence/index.d.ts +59 -0
- package/lib/services/audioDeviceLog.d.ts +15 -0
- package/lib/services/audioDeviceSelection.d.ts +40 -0
- package/lib/services/edge-mcp/edge-mcp-bridge.d.ts +1 -0
- package/lib/types/index.d.ts +66 -17
- package/lib/utils/debug.d.ts +22 -2
- package/lib/utils/mediaError.d.ts +14 -0
- package/lib/utils/normalizeConfig.d.ts +2 -0
- package/package.json +1 -1
- package/lib/shell/mount-shell.d.ts +0 -102
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import "./Persistence.css";
|
|
2
|
+
import type { PersistenceOptions } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Well-known event a site (or its WebMCP tools) dispatches on `window` to request an
|
|
5
|
+
* IN-SESSION navigation under `iframeOnNavigate` — instead of a full top-level load that
|
|
6
|
+
* would end the session. The engine listens while native (before the first wrap); on the
|
|
7
|
+
* event it wraps into the iframe and loads `detail.url`, then calls `preventDefault()` so
|
|
8
|
+
* the caller knows it was handled and skips its own `location.assign`. Dispatch it
|
|
9
|
+
* cancelable and check `defaultPrevented`:
|
|
10
|
+
*
|
|
11
|
+
* const e = new CustomEvent('napster:persist:navigate', { detail: { url }, cancelable: true });
|
|
12
|
+
* window.dispatchEvent(e);
|
|
13
|
+
* if (!e.defaultPrevented) location.assign(url); // nothing handled it — navigate normally
|
|
14
|
+
*
|
|
15
|
+
* Only meaningful top-level (a tool inside the wrapped iframe should navigate the iframe
|
|
16
|
+
* directly). Excluded URLs (persistence.exclude) are ignored so they still break out.
|
|
17
|
+
*/
|
|
18
|
+
export declare const PERSIST_NAVIGATE_EVENT = "napster:persist:navigate";
|
|
19
|
+
/**
|
|
20
|
+
* Class marking the same-origin iframe the site is wrapped into under persistence. Owned
|
|
21
|
+
* here (this module creates the frame); the frame guard below and both entry points key
|
|
22
|
+
* off it, so the marker is defined in exactly one place.
|
|
23
|
+
*/
|
|
24
|
+
export declare const SITE_FRAME_CLASS = "np_site-frame";
|
|
25
|
+
/**
|
|
26
|
+
* True when the current window is running INSIDE our own persistence site frame (the
|
|
27
|
+
* `.np_site-frame` iframe) rather than the top document or a third-party embed. Both entry
|
|
28
|
+
* points call it to no-op the framed copy of the snippet. Guarded against a cross-origin
|
|
29
|
+
* parent, where reading `frameElement` throws.
|
|
30
|
+
*/
|
|
31
|
+
export declare function isInOwnSiteFrame(): boolean;
|
|
32
|
+
/** What the persistence engine needs from whoever drives the session. */
|
|
33
|
+
export interface PersistenceHooks {
|
|
34
|
+
/** The avatar root (`#np_companion-sdk-root`). The iframe is inserted before it, and it's kept visible while the rest of the page is hidden. */
|
|
35
|
+
root: HTMLElement;
|
|
36
|
+
/** Re-target the Edge MCP bridge onto the site iframe (or `null` for the top document). */
|
|
37
|
+
setEdgeMcpIframe: (iframe: HTMLIFrameElement | null) => void;
|
|
38
|
+
/** End the live session — called when a break-out link forces the tab out of the persisted site. */
|
|
39
|
+
endSession: () => void;
|
|
40
|
+
}
|
|
41
|
+
export interface PersistenceController {
|
|
42
|
+
/** The site iframe while active, else `null`. */
|
|
43
|
+
getIframe(): HTMLIFrameElement | null;
|
|
44
|
+
/** Eager mode: wrap the current page into the iframe now (before the session connects). */
|
|
45
|
+
wrapNow(): void;
|
|
46
|
+
/** On-navigate mode: arm the interceptor so the first allowed link wraps the site. */
|
|
47
|
+
armOnNavigate(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Session ended: unwrap onto the page the user is on (a real top-level navigation, so
|
|
50
|
+
* the page reloads without the iframe). Returns `true` if it navigated; `false` if
|
|
51
|
+
* there was nothing to unwrap (no iframe, or unreadable), so the caller can reveal
|
|
52
|
+
* whatever it had underneath.
|
|
53
|
+
*/
|
|
54
|
+
end(): boolean;
|
|
55
|
+
/** Remove the iframe + listeners WITHOUT navigating (for a full teardown/destroy). */
|
|
56
|
+
teardown(): void;
|
|
57
|
+
}
|
|
58
|
+
/** Build the persistence engine. `config.enabled` is assumed `true` by the caller. */
|
|
59
|
+
export declare function createPersistence(config: PersistenceOptions, hooks: PersistenceHooks): PersistenceController;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function shortId(id?: string): string;
|
|
2
|
+
export declare function kindLabel(kind: string): string;
|
|
3
|
+
export declare function describeDevice(device: MediaDeviceInfo): string;
|
|
4
|
+
export interface DeviceChangeReport {
|
|
5
|
+
/**
|
|
6
|
+
* Groups touched by an addition in this pass. A group lands here when any of
|
|
7
|
+
* its entries is new, so a headset whose input and output show up in separate
|
|
8
|
+
* events is reported on whichever pass completes it.
|
|
9
|
+
*/
|
|
10
|
+
connectedGroupIds: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface DeviceChangeReporter {
|
|
13
|
+
report(devices: MediaDeviceInfo[]): DeviceChangeReport;
|
|
14
|
+
}
|
|
15
|
+
export declare function createDeviceChangeReporter(): DeviceChangeReporter;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which microphone the session should be capturing from, decided purely from a
|
|
3
|
+
* device list snapshot. No IO and no state, so the whole decision table is
|
|
4
|
+
* testable with plain data — see audioDeviceSelection.test.ts.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isExplicitDevice(deviceId?: string): deviceId is string;
|
|
7
|
+
export declare function defaultOutputGroupId(devices: MediaDeviceInfo[]): string | undefined;
|
|
8
|
+
export declare function inputInGroup(devices: MediaDeviceInfo[], groupId: string): string | undefined;
|
|
9
|
+
export declare function outputInGroup(devices: MediaDeviceInfo[], groupId: string): string | undefined;
|
|
10
|
+
export type MicSelectionReason = "already-on-selected-device" | "selected-device-available" | "selected-device-gone-keeping-live-mic" | "selected-device-gone-and-mic-dead" | "already-paired-with-playback" | "pair-with-playback" | "pair-with-newly-connected-device" | "mic-dead-no-pairing-available" | "playback-device-has-no-input" | "default-device-not-identifiable";
|
|
11
|
+
export interface MicSelection {
|
|
12
|
+
action: "keep" | "acquire";
|
|
13
|
+
/** Only set for "acquire"; undefined means "follow the system default". */
|
|
14
|
+
deviceId?: string;
|
|
15
|
+
reason: MicSelectionReason;
|
|
16
|
+
/** Group of the current default output, when the browser exposes it. */
|
|
17
|
+
playbackGroupId?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface MicSelectionInput {
|
|
20
|
+
devices: MediaDeviceInfo[];
|
|
21
|
+
/** Explicit user choice, if any. Outranks the system default. */
|
|
22
|
+
pinnedDeviceId?: string;
|
|
23
|
+
/** Device the live track is currently capturing from. */
|
|
24
|
+
currentDeviceId?: string;
|
|
25
|
+
/** False once the device behind the track disappeared. */
|
|
26
|
+
trackLive: boolean;
|
|
27
|
+
/** The "ended" event already told us the device is gone. */
|
|
28
|
+
trackEnded: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Groups that gained a device in this pass. Only consulted when the browser
|
|
31
|
+
* exposes no "default" pseudo-entries to read the system default from.
|
|
32
|
+
*/
|
|
33
|
+
connectedGroupIds?: string[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Priority: an explicit user choice, then the input paired with the device the
|
|
37
|
+
* user is listening through, then the raw system default. A dead track is always
|
|
38
|
+
* replaced; a live one is only replaced when a better device is identifiable.
|
|
39
|
+
*/
|
|
40
|
+
export declare function selectMicrophoneInput(input: MicSelectionInput): MicSelection;
|
|
@@ -40,6 +40,7 @@ export declare class EdgeMcpBridge {
|
|
|
40
40
|
private lastInlineSig;
|
|
41
41
|
private sessionReady;
|
|
42
42
|
private disposed;
|
|
43
|
+
private targetEpoch;
|
|
43
44
|
private readonly options;
|
|
44
45
|
constructor(options: EdgeMcpBridgeOptions);
|
|
45
46
|
/** The document whose `modelContext` we read — the target iframe's, or this window's. */
|
package/lib/types/index.d.ts
CHANGED
|
@@ -292,6 +292,41 @@ export interface avatarStyleConfig {
|
|
|
292
292
|
* Allows both string and number values for CSS properties.
|
|
293
293
|
*/
|
|
294
294
|
export type StyleObject = Partial<CSSStyleDeclaration>;
|
|
295
|
+
/**
|
|
296
|
+
* Cross-page persistence options. Works with BOTH entry points — `init` and
|
|
297
|
+
* `initWithButton` share the same persistence engine.
|
|
298
|
+
*/
|
|
299
|
+
export interface PersistenceOptions {
|
|
300
|
+
/** Turn persistence on. Required — there is no boolean shorthand. */
|
|
301
|
+
enabled: boolean;
|
|
302
|
+
/**
|
|
303
|
+
* Defer the iframe wrap until the user first navigates. The landing page stays
|
|
304
|
+
* fully native — no iframe — and the wrap happens on the first allowed link click.
|
|
305
|
+
* Default: `false` (eager wrap on connect). Off by default because on-navigate only
|
|
306
|
+
* catches anchor clicks: a programmatic redirect on the landing page would fall
|
|
307
|
+
* through and end the session.
|
|
308
|
+
*/
|
|
309
|
+
iframeOnNavigate?: boolean;
|
|
310
|
+
/**
|
|
311
|
+
* URLs/domains excluded from persistence: instead of loading inside the iframe they
|
|
312
|
+
* open as a normal top-level navigation (which ends the session). Use for pages that
|
|
313
|
+
* can't be framed (auth / SSO) or shouldn't be (checkout, signout). Cross-origin
|
|
314
|
+
* links always open top-level by default, so this only matters for same-origin.
|
|
315
|
+
*/
|
|
316
|
+
exclude?: {
|
|
317
|
+
/** Hostnames to exclude (exact host or a parent domain, e.g. `"napster.com"`). */
|
|
318
|
+
domains?: string[];
|
|
319
|
+
/** URLs to exclude: an absolute `"https://…"` (exact/prefix) or a same-origin path prefix. */
|
|
320
|
+
urls?: string[];
|
|
321
|
+
};
|
|
322
|
+
/** Value for the site iframe's `allow` attribute (Permissions Policy). Default: `"autoplay; clipboard-write"`. */
|
|
323
|
+
iframeAllowAttribute?: string;
|
|
324
|
+
/**
|
|
325
|
+
* While a persisted session is active, mirror the iframe's path into the address bar
|
|
326
|
+
* and follow parent back/forward into the iframe. Same-origin only. Default: `true`.
|
|
327
|
+
*/
|
|
328
|
+
syncHistory?: boolean;
|
|
329
|
+
}
|
|
295
330
|
/**
|
|
296
331
|
* Main configuration object passed to `init(token, config)`.
|
|
297
332
|
* All fields are optional; sensible defaults are used by the SDK.
|
|
@@ -340,12 +375,33 @@ export interface NapsterCompanionApiConfig {
|
|
|
340
375
|
/** @internal */
|
|
341
376
|
iceServers?: RTCIceServer[];
|
|
342
377
|
/**
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
*
|
|
346
|
-
*
|
|
378
|
+
* `targetOrigin` used when the SDK relays data-channel messages to
|
|
379
|
+
* `window.parent` (the `"avatar-data-channel-message"` event).
|
|
380
|
+
*
|
|
381
|
+
* Defaults to the current origin, so private session data (chat transcripts,
|
|
382
|
+
* avatar state) is only ever delivered to a same-origin parent. When the SDK
|
|
383
|
+
* is embedded cross-origin, set this to the trusted embedder's origin (e.g.
|
|
384
|
+
* `"https://app.example.com"`). Setting it to `"*"` broadcasts to any parent
|
|
385
|
+
* origin and is insecure — use only if you understand the exposure.
|
|
347
386
|
*/
|
|
348
|
-
|
|
387
|
+
parentOrigin?: string;
|
|
388
|
+
/**
|
|
389
|
+
* Keep the session alive across page navigation. When enabled, the page is wrapped in
|
|
390
|
+
* a same-origin iframe so navigation happens inside it while the avatar stays in the
|
|
391
|
+
* top document, which never reloads. Works with both `init` and `initWithButton`.
|
|
392
|
+
* When on, `mountContainer` is ignored — the avatar must live in the top document.
|
|
393
|
+
*/
|
|
394
|
+
persistence?: PersistenceOptions;
|
|
395
|
+
/**
|
|
396
|
+
* The click-to-start button's appearance. **Only used by `initWithButton()`** —
|
|
397
|
+
* passing it to `init()` (which connects immediately, with no button) throws.
|
|
398
|
+
*/
|
|
399
|
+
button?: {
|
|
400
|
+
/** Button text. Default: `"Talk to an agent"`. */
|
|
401
|
+
label?: string;
|
|
402
|
+
/** Optional companion picture shown on the button. */
|
|
403
|
+
avatarUrl?: string;
|
|
404
|
+
};
|
|
349
405
|
/** Analytics configuration controls analytics delivery and tracking. */
|
|
350
406
|
analytics?: AnalyticsConfig;
|
|
351
407
|
/** Lifecycle callbacks. All are optional. */
|
|
@@ -383,14 +439,6 @@ export interface NapsterCompanionApiInstance {
|
|
|
383
439
|
avatarIsVisible: () => boolean;
|
|
384
440
|
/** Tear down the SDK, remove DOM nodes and clean up resources. */
|
|
385
441
|
destroy: () => void;
|
|
386
|
-
/**
|
|
387
|
-
* Re-target the Edge MCP bridge at runtime: read the site's WebMCP tools from the given
|
|
388
|
-
* same-origin iframe's `document.modelContext`, or pass `null` to read them from this
|
|
389
|
-
* window's document. Used by the persistent-agent shell's frame-on-navigate mode, where
|
|
390
|
-
* the site is only wrapped in an iframe on the first navigation. No-op if the bridge is
|
|
391
|
-
* inactive.
|
|
392
|
-
*/
|
|
393
|
-
setEdgeMcpIframe: (iframe: HTMLIFrameElement | null) => void;
|
|
394
442
|
/**
|
|
395
443
|
* The current session identifier. Available after a connection is established
|
|
396
444
|
* and reset to `undefined` once the connection is closed.
|
|
@@ -476,11 +524,12 @@ export interface NapsterCompanionApiSDK {
|
|
|
476
524
|
*/
|
|
477
525
|
init(token: string, config?: Partial<NapsterCompanionApiConfig>): Promise<NapsterCompanionApiInstance>;
|
|
478
526
|
/**
|
|
479
|
-
*
|
|
480
|
-
*
|
|
481
|
-
* session survives navigation. No-op
|
|
527
|
+
* Render a button and connect on click (instead of connecting immediately like
|
|
528
|
+
* `init`). Returns a `NapsterCompanionApiController` synchronously — nothing connects
|
|
529
|
+
* until the user clicks. With `persistence`, the session survives navigation. No-op
|
|
530
|
+
* when run inside the persistence site frame.
|
|
482
531
|
*/
|
|
483
|
-
|
|
532
|
+
initWithButton(getToken: () => Promise<string>, config?: Partial<NapsterCompanionApiConfig>): import("../button").NapsterCompanionApiController;
|
|
484
533
|
/** The SDK version string (useful for diagnostics). */
|
|
485
534
|
version: string;
|
|
486
535
|
}
|
package/lib/utils/debug.d.ts
CHANGED
|
@@ -17,7 +17,10 @@ declare class DebugLogger {
|
|
|
17
17
|
*/
|
|
18
18
|
private isDebugEnabled;
|
|
19
19
|
/**
|
|
20
|
-
* Generic log method
|
|
20
|
+
* Generic log method. Every level — including warn and error — is gated behind
|
|
21
|
+
* debug mode, so a published SDK stays silent on host pages unless the integrator
|
|
22
|
+
* opts in with `debug: true`. Messages that must ALWAYS surface (genuine integrator
|
|
23
|
+
* misconfiguration) go through `critical_warn` / `critical_error`, which bypass this.
|
|
21
24
|
*/
|
|
22
25
|
private log;
|
|
23
26
|
/**
|
|
@@ -52,6 +55,11 @@ declare class DebugLogger {
|
|
|
52
55
|
* Log Avatar-related debug information
|
|
53
56
|
*/
|
|
54
57
|
avatar(...args: unknown[]): void;
|
|
58
|
+
/**
|
|
59
|
+
* Log audio device plug/unplug and the resulting input/output selection.
|
|
60
|
+
* Separate from `avatar`/`webrtc` so device churn can be read on its own.
|
|
61
|
+
*/
|
|
62
|
+
devices(...args: unknown[]): void;
|
|
55
63
|
/**
|
|
56
64
|
* Log connection-related debug information
|
|
57
65
|
*/
|
|
@@ -61,7 +69,7 @@ declare class DebugLogger {
|
|
|
61
69
|
*/
|
|
62
70
|
features(...args: unknown[]): void;
|
|
63
71
|
/**
|
|
64
|
-
* Log data
|
|
72
|
+
* Log WebRTC data-channel messaging (send/receive over the peer connection).
|
|
65
73
|
*/
|
|
66
74
|
data(...args: unknown[]): void;
|
|
67
75
|
/**
|
|
@@ -72,6 +80,18 @@ declare class DebugLogger {
|
|
|
72
80
|
* Log cleanup-related debug information
|
|
73
81
|
*/
|
|
74
82
|
cleanup(...args: unknown[]): void;
|
|
83
|
+
/**
|
|
84
|
+
* Log Edge MCP bridge information
|
|
85
|
+
*/
|
|
86
|
+
edgeMcp(...args: unknown[]): void;
|
|
87
|
+
/**
|
|
88
|
+
* Log button-entry-point information
|
|
89
|
+
*/
|
|
90
|
+
button(...args: unknown[]): void;
|
|
91
|
+
/**
|
|
92
|
+
* Log cross-page persistence information (iframe wrap/unwrap, break-out, history sync).
|
|
93
|
+
*/
|
|
94
|
+
persistence(...args: unknown[]): void;
|
|
75
95
|
}
|
|
76
96
|
/**
|
|
77
97
|
* Global debug logger instance
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name of the original DOMException behind a media failure. The microphone
|
|
3
|
+
* manager wraps it in a MediaError, so the discriminator an app actually needs
|
|
4
|
+
* — "NotAllowedError" (user blocked) vs "NotFoundError" (no device) — sits one
|
|
5
|
+
* level down in `context.error`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function rootCauseName(error: unknown): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Whether a media failure leaves the user with a recoverable permission
|
|
10
|
+
* problem. Both flavors land on the same "access blocked" screen: a denied
|
|
11
|
+
* prompt is fixable in site settings, and a missing device is equally fatal to
|
|
12
|
+
* a voice session, so neither may negotiate a session the agent cannot hear.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isMicUnavailable(error: unknown): boolean;
|
package/package.json
CHANGED
|
@@ -1,102 +0,0 @@
|
|
|
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 {};
|