@touchcastllc/napster-companion-api-dev 1.6.0-alpha.2 → 1.6.0-alpha.4
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 +74 -2
- package/lib/button/element.d.ts +8 -0
- package/lib/button/navigationHold.d.ts +7 -0
- package/lib/button/session.d.ts +45 -0
- package/lib/button/trigger.d.ts +21 -0
- package/lib/index.css +1 -1
- package/lib/index.d.ts +103 -8
- package/lib/index.esm.js +1 -1
- package/lib/index.js +1 -1
- package/lib/index.standalone.js +1 -1
- package/lib/services/micGate.d.ts +7 -0
- package/lib/types/index.d.ts +82 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,11 +50,83 @@ No bundler? Drop in the standalone build with a `<script>` tag — styles are in
|
|
|
50
50
|
```html
|
|
51
51
|
<script src="https://unpkg.com/@touchcastllc/napster-companion-api"></script>
|
|
52
52
|
<script>
|
|
53
|
-
//
|
|
54
|
-
|
|
53
|
+
// The SDK mints the token itself, once microphone permission has settled —
|
|
54
|
+
// connection tokens are short-lived, so they must not be minted any earlier.
|
|
55
|
+
napsterCompanionApiSDK.init(() => fetchConnectionToken());
|
|
55
56
|
</script>
|
|
56
57
|
```
|
|
57
58
|
|
|
59
|
+
### Click-to-start
|
|
60
|
+
|
|
61
|
+
By default `init()` connects immediately. To show an entry point and connect on
|
|
62
|
+
click, opt in with `button.enabled`:
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
const widget = await napsterCompanionApiSDK.init(() => fetchConnectionToken(), {
|
|
66
|
+
button: {
|
|
67
|
+
enabled: true,
|
|
68
|
+
label: "Talk to an agent",
|
|
69
|
+
description: "Ask about your order",
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
widget.getInstance(); // null — nothing has connected yet
|
|
74
|
+
|
|
75
|
+
// Later, once the visitor clicks (or you call start() yourself):
|
|
76
|
+
await widget.start(); // resolves the instance, or null on failure — never rejects
|
|
77
|
+
widget.end(); // back to idle; the entry point reappears and can start another session
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`start()` never throws — a failed attempt is reported through your `onError` callback
|
|
81
|
+
and the entry point returns to idle, so there is nothing to catch around it.
|
|
82
|
+
|
|
83
|
+
The controller return type is selected from the config **literal**:
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
// ✅ Inferred as a controller
|
|
87
|
+
const widget = await napsterCompanionApiSDK.init(() => fetchConnectionToken(), {
|
|
88
|
+
button: { enabled: true },
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Hoisting the config to a variable first widens `enabled` to `boolean`, so TypeScript
|
|
93
|
+
picks the instance overload — even though you still get a controller at runtime:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
// ❌ Typed as an instance, though a controller is what you get
|
|
97
|
+
const options = { button: { enabled: true } };
|
|
98
|
+
const widget = await napsterCompanionApiSDK.init(() => fetchConnectionToken(), options);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`as const` keeps the literal type, so the overload resolves correctly:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// ✅ Typed as a controller
|
|
105
|
+
const options = { button: { enabled: true } } as const;
|
|
106
|
+
const widget = await napsterCompanionApiSDK.init(() => fetchConnectionToken(), options);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Already have a button in your design system? Point the SDK at it and it renders
|
|
110
|
+
nothing of its own — it binds the click, sets `data-np-state`, and hides the node
|
|
111
|
+
while the session is live:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
await napsterCompanionApiSDK.init(() => fetchConnectionToken(), {
|
|
115
|
+
button: { enabled: true, element: "#my-cta" },
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The entry point survives every way a session can end — the visitor pressing **End**,
|
|
120
|
+
the inactivity timeout, a dropped connection, `instance.destroy()` — and returns to
|
|
121
|
+
idle so the next session is one click away.
|
|
122
|
+
|
|
123
|
+
> **Caveat: `button` and `persistence` do not compose yet.** Ending a session under
|
|
124
|
+
> persistence has to unwrap the page, and unwrapping is a real top-level navigation.
|
|
125
|
+
> That page load takes the entry point with it, so the visitor gets a fresh load of
|
|
126
|
+
> the page rather than the button reappearing in place — and any navigation they did
|
|
127
|
+
> inside the persisted frame is lost. The SDK warns when both flags are on. Use one
|
|
128
|
+
> or the other until this is resolved.
|
|
129
|
+
|
|
58
130
|
For framework-specific setup, version pinning and the first working session, see
|
|
59
131
|
**[developers.napster.com/docs/sdks/web-sdk/installation](https://developers.napster.com/docs/sdks/web-sdk/installation)**.
|
|
60
132
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface NavigationHold {
|
|
2
|
+
/** Start intercepting same-origin link clicks. No-op when persistence is off. */
|
|
3
|
+
hold(): void;
|
|
4
|
+
/** Stop intercepting. `connected` decides what happens to a held navigation. */
|
|
5
|
+
release(connected: boolean): void;
|
|
6
|
+
}
|
|
7
|
+
export declare function createNavigationHold(enabled: boolean, navigate?: (url: string) => void): NavigationHold;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { NapsterCompanionApiConfig, NapsterCompanionApiController, NapsterCompanionApiInstance } from "../types";
|
|
2
|
+
export interface ButtonSessionDeps {
|
|
3
|
+
/** The SDK-owned root the card mounts into. */
|
|
4
|
+
root: HTMLElement;
|
|
5
|
+
/** Run one session attempt: epoch, mic gate, mint, connect. Resolves when connected. */
|
|
6
|
+
startSession: () => Promise<NapsterCompanionApiInstance>;
|
|
7
|
+
/** End the live session but keep the root and trigger mounted. */
|
|
8
|
+
endSession: () => void;
|
|
9
|
+
/**
|
|
10
|
+
* Abandon an attempt that is still connecting: bump the session epoch so the
|
|
11
|
+
* in-flight gate/mint drops out at its next check, and drop whatever the
|
|
12
|
+
* attempt already mounted (the embed, a microphone-recovery card), keeping the
|
|
13
|
+
* root and trigger. Without this, end() during connect was a silent no-op and
|
|
14
|
+
* the session came up anyway a moment later.
|
|
15
|
+
*/
|
|
16
|
+
abortAttempt: () => void;
|
|
17
|
+
/** Tear down the session AND the root. */
|
|
18
|
+
disposeSession: () => void;
|
|
19
|
+
/**
|
|
20
|
+
* Register a handler fired when the avatar reports ready. Returns an
|
|
21
|
+
* unsubscribe. The trigger's "active" state follows this, not start()'s
|
|
22
|
+
* promise: a denied microphone leaves the attempt alive behind the recovery
|
|
23
|
+
* card, and the entry point must stay in "connecting" until a session is
|
|
24
|
+
* genuinely up.
|
|
25
|
+
*/
|
|
26
|
+
onAvatarReady: (handler: (isReady: boolean) => void) => () => void;
|
|
27
|
+
/**
|
|
28
|
+
* Register a handler for an attempt that failed after the gate had already
|
|
29
|
+
* granted — including a "Check again" retry, where no caller is awaiting
|
|
30
|
+
* start(). Returns an unsubscribe.
|
|
31
|
+
*/
|
|
32
|
+
onSessionFailed: (handler: (error: Error) => void) => () => void;
|
|
33
|
+
/**
|
|
34
|
+
* Register a handler for a session the SDK ended on its own — the control
|
|
35
|
+
* bar's End button, the inactivity overlay, a server termination, a fatal
|
|
36
|
+
* transport error, or a host calling `instance.destroy()`. None of these go
|
|
37
|
+
* through `end()`, so without this channel the controller would keep a stale
|
|
38
|
+
* instance and a trigger stranded on "active". Returns an unsubscribe.
|
|
39
|
+
*
|
|
40
|
+
* This is a normal end, not a failure: the handler returns the entry point to
|
|
41
|
+
* idle and must NOT report through `onError`.
|
|
42
|
+
*/
|
|
43
|
+
onSessionEnded: (handler: () => void) => () => void;
|
|
44
|
+
}
|
|
45
|
+
export declare function createButtonSession(deps: ButtonSessionDeps, config: Partial<NapsterCompanionApiConfig>): NapsterCompanionApiController;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ButtonConfig } from "../types";
|
|
2
|
+
export type TriggerState = "idle" | "connecting" | "active";
|
|
3
|
+
export interface Trigger {
|
|
4
|
+
setState(state: TriggerState): void;
|
|
5
|
+
/** Release the trigger. SDK-owned nodes are removed; host-owned nodes are restored. */
|
|
6
|
+
destroy(): void;
|
|
7
|
+
}
|
|
8
|
+
/** Resolve a configured trigger to a live element, or fail loudly. */
|
|
9
|
+
export declare function resolveTriggerNode(element: HTMLElement | string): HTMLElement;
|
|
10
|
+
/**
|
|
11
|
+
* The SDK's own card, rendered into the root it already owns. The card and the
|
|
12
|
+
* avatar swap via the root's `data-np-state`, which createButtonSession sets —
|
|
13
|
+
* so all this has to do is keep the card from taking a second click.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createSdkTrigger(root: HTMLElement, config: ButtonConfig, onClick: () => void): Trigger;
|
|
16
|
+
/**
|
|
17
|
+
* A host-owned node. The SDK never moves, reparents or restyles it beyond
|
|
18
|
+
* hiding it for the duration of a session — and puts back exactly what it
|
|
19
|
+
* found on destroy, because the host owns this element.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createHostTrigger(node: HTMLElement, onClick: () => void): Trigger;
|
package/lib/index.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.np_companion-live-container,.np_companion-preview-container{height:100%;margin:0;padding:0;position:absolute;transition:opacity .3s ease-in-out;width:100%}.np_companion-preview-container{opacity:1;z-index:2}.np_companion-preview-container.np_companion-fade-out{opacity:0;pointer-events:none;transition:opacity .5s ease-out}.np_companion-live-container{opacity:0;z-index:1}.np_companion-live-container.np_companion-fade-in{opacity:1;z-index:3}:root{--base-border-radius:10px;--base-gap:20px}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box}::-webkit-input-placeholder{color:hsla(0,0%,100%,.4)}::-moz-placeholder{color:hsla(0,0%,100%,.4)}:-ms-input-placeholder{color:hsla(0,0%,100%,.4)}:-moz-placeholder{color:hsla(0,0%,100%,.4)}a,input{outline:none}.np_companion-hide{display:none!important}.np_companion-align-middle{align-items:center;display:flex;justify-content:center}.np_companion-align-between{align-items:center;display:flex;justify-content:space-between}.np_companion-align-end{align-items:center;display:flex;justify-content:flex-end}.np_companion-align-start{align-items:flex-start;display:flex;justify-content:flex-start}.np_companion__d-none{display:none!important}#np_companion-sdk-root.np_companion-container-fixed{height:500px;position:fixed;transition:top .3s ease-in-out,right .3s ease-in-out,bottom .3s ease-in-out,left .3s ease-in-out,width .3s ease-in-out,height .3s ease-in-out;width:400px;z-index:9999}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-rectangle{height:400px;width:340px}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-silhouette{height:400px}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-round{height:360px;width:250px}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-round.np_companion_disclaimer-disabled{height:320px!important}#np_companion-sdk-root.np_companion-container-fixed.np_companion-bottom-right{bottom:0;right:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-bottom-left{bottom:0;left:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-bottom-center{bottom:0;left:50%;transform:translateX(-50%)}#np_companion-sdk-root.np_companion-container-fixed.np_companion-top-right{right:0;top:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-top-left{left:0;top:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-top-center{left:50%;top:0;transform:translateX(-50%)}#np_companion-sdk-root.np_companion-container-fixed.np_companion-center{left:50%;top:50%;transform:translate(-50%,-50%)}#np_companion-sdk-root.np_companion-container-inline{aspect-ratio:4/5;height:100%;position:relative;width:100%}#np_companion-sdk-root.np_companion-container-inline.np_companion-view-round{aspect-ratio:1/1;container-type:size}.np_companion-avatar{height:100%;position:relative;width:100%}#np_companion-avatar-container{background:transparent;border-radius:var(--base-border-radius);height:100%;overflow:hidden;position:absolute;width:100%}#np_companion-avatar-container:not(.np_companion-view-silhouette){box-shadow:0 0 #0000,0 0 #0000,0 0 #0000,0 0 #0000,0 10px 15px -3px color-mix(in oklab,#00000080 100%,transparent),0 4px 6px -4px color-mix(in oklab,#00000080 100%,transparent)}.np_companion-avatar.np_companion-bg-transparent #np_companion-avatar-container.np_companion-view-silhouette{filter:drop-shadow(0 10px 15px rgba(0,0,0,.5)) drop-shadow(0 4px 6px rgba(0,0,0,.5))}.np_companion-container-fixed #np_companion-avatar-container.np_companion-view-round{border-radius:50%;height:212px;left:50%;transform:translate(-50%,12%);width:212px}.np_companion-container-fixed #np_companion-avatar-container.np_companion-view-rectangle,.np_companion-container-fixed #np_companion-avatar-container.np_companion-view-silhouette{left:50%;transform:translateX(-50%)}.np_companion-container-inline #np_companion-avatar-container.np_companion-view-round{border-radius:50%;height:min(100cqw,calc(100cqh - var(--np-controls-band, 88px)));left:50%;top:0;transform:translateX(-50%);width:min(100cqw,calc(100cqh - var(--np-controls-band, 88px)))}.np_companion-avatar-video{height:100%;inset:0;object-fit:cover;pointer-events:none;position:absolute;transition:opacity .3s ease-in-out;width:100%;z-index:10}.np_companion-avatar-video.no-opacity{opacity:0}.np_companion-avatar-canvas{background:transparent;height:100%;object-fit:cover;position:relative;width:100%;z-index:1}#np_companion-avatar-container.np_companion-loader-pulse:after,.np_companion-container-fixed #np_companion-avatar-container.np_companion-loader-pulse:after{animation:pulse 1.5s ease-in-out infinite;background-color:var(--np-loader-bg-color);border-radius:var(--base-border-radius);content:"";display:block;height:100%;left:0;opacity:.6;overflow:hidden;position:absolute;top:0;width:100%}.np_companion-avatar.np_companion-bg-transparent #np_companion-avatar-container:after{display:none}.np_companion-avatar:has(#np_companion-avatar-container.np_companion-view-round):after{display:none}#np_companion-avatar-container.np_companion-loader-pulse.loader-container.np_companion-view-round:after{animation:pulse 1.5s ease-in-out infinite;background-color:var(--np-loader-bg-color);border-radius:50%;content:"";display:block;height:100%;left:0;opacity:.6;overflow:hidden;position:absolute;top:0;width:100%}.np_companion-avatar.np_companion-bg-transparent #np_companion-avatar-container.np_companion-view-round:after{display:none}@keyframes pulse{0%,to{opacity:.5}50%{opacity:.2}}.np_companion-disclaimer-text{-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;color:#fff;font-size:10px;line-height:12px;margin:auto auto 16px;max-width:940px;opacity:.7;overflow:hidden;padding:0 16px;text-align:center;z-index:12}.np_companion-disclaimer-text a{color:#fff}.np_companion-disclaimer-text a:hover{color:#fff;text-decoration:underline}.np_companion-disclaimer-text a:focus,.np_companion-disclaimer-text a:visited{color:#fff}.np_companion-action-btn-container-wrapper{pointer-events:auto;width:100%}.np_companion-avatar-control-container{backdrop-filter:blur(19px);background:none;background-color:rgba(52,51,51,.6);border-radius:16px;bottom:0;box-shadow:0 4px 4px 0 rgba(0,0,0,.25),2px 2px 8px 0 rgba(0,0,0,.12);left:50%;max-width:90%;min-width:210px;opacity:1;position:absolute;transform:translateX(-50%);transition:opacity .4s cubic-bezier(.4,0,.2,1);z-index:99}.np_companion-avatar-control-container.np_companion-action-btn-container-collapse{opacity:0}.np_companion-avatar-control-container:not(.np_companion-avatar-control-view-round){bottom:16px}.np_companion-avatar:not(.np_companion-bg-transparent) .np_companion-loader-spinner:not(.np_companion-view-silhouette){backdrop-filter:blur(19px);background-color:color-mix(in oklab,var(--np-loader-bg-color) 100%,transparent)!important;filter:none!important;height:100%;width:100%}.np_companion-loader-spinner .loader-container{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.np_companion-loader-spinner .loader-container .loader{--_m:conic-gradient(#0000 10%,#000),linear-gradient(#000 0 0) content-box;animation:l3 1s linear infinite;aspect-ratio:1;background:var(--np-loader-color);border-radius:50%;-webkit-mask:var(--_m);mask:var(--_m);-webkit-mask-composite:source-out;mask-composite:subtract;padding:4px;width:24px}@keyframes l3{to{transform:rotate(1turn)}}.np_companion-loader-spinner.np_companion-view-round .loader-container .loader{padding:4px;width:212px}.np_companion-bg-transparent .np_companion-loader-spinner .loader-container{display:none}.np_companion-controls-container{align-items:center;background:hsla(0,0%,100%,.3);border:.5px solid #fff;border-radius:12px;bottom:20px;box-shadow:0 1px 1px rgba(0,0,0,.267),0 2px 5px rgba(0,0,0,.267),0 3px 8px rgba(0,0,0,.267);display:flex;gap:8px;left:50%;max-width:360px;pointer-events:auto;position:absolute;transform:translateX(-50%);transform-origin:bottom center;transition:width .3s ease-in-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:auto;z-index:99}.np_companion-controls-container.collapsed{gap:0}.np_companion-time-running{color:#fff}.np_companion-controls-time-action-btn-container{align-items:center;background:hsla(0,0%,100%,.1);border-radius:8px;display:flex;filter:grayscale(1);flex-shrink:0;gap:8px;height:32px;padding-left:8px;padding-right:8px;transition:filter .3s ease}.np_companion-controls-mic-control,.np_companion-controls-stop-control{cursor:pointer;display:flex;margin:0 5px;overflow:hidden;transition:opacity .3s ease-in-out,width .3s ease-in-out;width:47px}.np_companion-controls-mic-control.visible,.np_companion-controls-stop-control.visible{opacity:1}.np_companion-controls-mic-control.visible{width:1em}.np_companion-controls-stop-control.visible{width:1.5em}.np_companion-controls-mic-control.hidden,.np_companion-controls-stop-control.hidden{margin:0;opacity:0;padding:0;pointer-events:none;width:0}.np_companion-controls-mic-control:hover svg path{fill:red}.np_companion-controls-stop-control{display:flex;margin:0 5px 0 0}.np_companion-controls-stop-control:hover svg .stop-circle{fill:red}.np_companion-controls-stop-control:hover svg .stop-square{fill:#fff}.np_companion-mic-dropdown{background:#2b2c32;border-radius:4px;border-radius:6px;bottom:35px;box-shadow:0 10px 15px -3px rgba(0,0,0,.2),0 4px 6px -4px rgba(0,0,0,.2),0 0 0 1px #46464d;color:#fff;font-size:14px;list-style-type:none;margin:0;max-height:200px;min-width:300px;overflow-y:auto;overflow:auto;padding:5px;pointer-events:auto;position:absolute;width:auto;z-index:1000}.np_companion-mic-dropdown li{cursor:pointer;padding:8px 12px}.np_companion-mic-dropdown li:hover{background-color:#000}.np_companion-action-btn-container-container{background:transparent;border-radius:80px;gap:8px;padding:16px 16px 12px;transition:all .3s ease-in-out}.np_companion-action-btn-container-container.np_companion_disclaimer-disabled{padding-bottom:16px}.np_companion-action-btn-container-container .np_companion-chat-question-bar-container{border-radius:16px;gap:8px}.np_companion-action-btn-container-container .np_companion-action-btn-container-left{transition:all .3s ease-in-out;width:40px}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon{border-radius:80px;cursor:pointer;height:40px;transition:all .3s ease-in-out;width:40px}.np_companion-dark-grey-bg{background:linear-gradient(0deg,#5e5e5e14 0 100%),#ffffff0f}.np_companion-grey-bg{background:linear-gradient(0deg,rgba(94,94,94,.07),rgba(94,94,94,.07)),hsla(0,0%,100%,.04)}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon svg{height:auto;width:22px}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon.muted svg.np_companion-mic-muted,.np_companion-action-btn-container-container .np_companion-action-btn-container-icon:not(.muted) svg.np_companion-mic-unmuted{display:flex}.np_companion-action-btn-container-container .np_companion-action-btn-container-right{gap:8px;transition:all .3s ease-in-out}.np_companion-action-btn-container-container .np_companion-action-btn-container-left .np_companion-action-btn-container-icon:hover,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon.active,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:hover{background-color:#fff!important}.np_companion-action-btn-container-container .np_companion-action-btn-container-left .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color):hover svg path{fill:#000}.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon.np_companion-action-btn-container-call-end svg{height:auto;width:16px}.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color).np_companion-action-btn-container-call-end:hover svg path{stroke:#000}.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color).active svg path,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color).np_companion-action-btn-container-toggle:hover svg path,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color):hover svg path{fill:#000}.np_companion-mobile-mode{bottom:15px;scale:.7}.np_companion-mobile-mode .np_companion-action-btn-container-left{opacity:1;width:40px}.np_companion-mobile-mode .np_companion-action-btn-container-right{opacity:1}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon.np_companion-talking{background:rgba(52,199,89,.25);box-shadow:0 0 0 2px rgba(52,199,89,.4);transition:background .2s ease,box-shadow .2s ease}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon.np_companion-talking svg path{fill:#34c759}.np_companion-inactive-overlay{align-items:center;bottom:0;display:flex;justify-content:center;left:0;pointer-events:auto;position:absolute;right:0;top:0;z-index:9999}.np_companion-inactive-dialog{backdrop-filter:blur(19px);background:hsla(0,0%,50%,.3);background-blend-mode:luminosity;border-radius:16px;max-width:500px;overflow:hidden;padding:24px 16px;position:relative;text-align:center;width:100%}@supports (-moz-appearance:none){.np_companion-inactive-dialog{background:rgba(32,32,34,.88);background-blend-mode:normal}}.np_companion-inactive-dialog:before{background:linear-gradient(180deg,hsla(0,0%,100%,.4),hsla(0,0%,100%,0),hsla(0,0%,100%,0),hsla(0,0%,100%,.1));border-radius:16px;content:"";inset:0;-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:destination-out;mask-composite:exclude;padding:1.473px;pointer-events:none;position:absolute}.np_companion-inactive-message{color:#fff;font-size:16px;line-height:1.5;margin-bottom:24px;margin-top:0}.np_companion-inactive-timer{display:flex;justify-content:center;margin:24px 0;pointer-events:none}.np_companion-timer-circle{align-items:center;display:flex;height:80px;justify-content:center;position:relative;width:80px}.np_companion-timer-circle svg{height:100%;transform:rotate(-90deg);width:100%}.np_companion-timer-circle path{transition:stroke-dasharray .3s ease}.np_companion-timer-number{color:#fff;font-size:24px;font-weight:500;position:absolute}.np_companion-inactive-buttons{display:flex;gap:12px;justify-content:center}.np_companion-inactive-buttons button{border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:500;padding:12px 24px;transition:background-color .2s ease}.np_companion-end-button{background:hsla(0,0%,100%,.1);color:#fff}.np_companion-end-button:hover{background:hsla(0,0%,100%,.2)}.np_companion-continue-button{background:#3c19cd;color:#fff}.np_companion-continue-button:hover{background:#2f13a0}.np_companion-mic-permission{--np-mic-permission-accent:#be369d;--np-mic-permission-accent-hover:#a62d88;--np-mic-permission-card-bg:hsla(0,0%,4%,.8);--np-mic-permission-card-radius:27px;align-items:flex-end;display:flex;inset:0;justify-content:center;padding:8px;pointer-events:auto;position:absolute;z-index:9999}.np_companion-mic-permission-card{backdrop-filter:blur(19px);background:var(--np-mic-permission-card-bg);border-radius:var(--np-mic-permission-card-radius);box-sizing:border-box;max-width:386px;padding:15px;text-align:center;width:100%}.np_companion-mic-permission-pagination{align-items:center;display:flex;gap:4px;justify-content:center;margin-bottom:8px}.np_companion-mic-permission-pagination[hidden]{display:none}.np_companion-mic-permission-dot{background:hsla(0,0%,100%,.4);border-radius:2px;height:4px;transition:width .2s ease,background .2s ease;width:4px}.np_companion-mic-permission-dot--active{background:#fff;width:16px}.np_companion-mic-permission-heading{color:#fff;font-family:inherit;font-size:18px;font-style:normal;font-weight:700;letter-spacing:-.18px;line-height:21.6px;margin:0 0 4px;text-transform:none}.np_companion-mic-permission-subheading{color:hsla(0,0%,100%,.5);font-family:inherit;font-size:14px;font-style:normal;font-weight:400;letter-spacing:-.28px;line-height:19.6px;margin:0 0 20px;text-transform:none}.np_companion-mic-permission-em--semibold{font-weight:600}.np_companion-mic-permission-em--bold{font-weight:700}.np_companion-mic-permission-actions{align-items:stretch;display:flex;flex-direction:column;gap:8px}.np_companion-mic-permission-actions button{border:0;color:#fff;cursor:pointer;font-family:inherit;font-style:normal;font-weight:600;text-transform:none;transition:background .2s ease}.np_companion-mic-permission-actions button:disabled{cursor:progress;opacity:.6}.np_companion-mic-permission-actions button:focus-visible{outline:2px solid #fff;outline-offset:2px}.np_companion-mic-permission-primary{background:var(--np-mic-permission-accent);border-radius:999px;font-size:15px;letter-spacing:-.15px;line-height:22px;min-height:48px;padding:7px 15px}.np_companion-mic-permission-primary:hover:not(:disabled){background:var(--np-mic-permission-accent-hover)}.np_companion-mic-permission-secondary{background:transparent;font-size:14px;letter-spacing:-.14px;line-height:19.6px;min-height:32px;padding:4px}.np_companion-mic-permission-secondary:hover:not(:disabled){color:hsla(0,0%,100%,.8)}.np_companion-mic-permission-live{clip:rect(0,0,0,0);border:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}.np_site-frame{backface-visibility:hidden;border:0;height:100vh;height:100dvh;inset:0;position:fixed;transform:translateZ(0);width:100%;z-index:100000000}.np_site-progress{animation:np_site-progress-grow 6s cubic-bezier(.15,.75,.25,1) forwards;background:var(--np-persist-progress-color,#be369d);border-end-end-radius:3px;box-shadow:0 0 10px var(--np-persist-progress-color,#be369d);height:var(--np-persist-progress-height,3px);left:0;pointer-events:none;position:fixed;top:0;width:0;z-index:100000002}@keyframes np_site-progress-grow{0%{width:0}to{width:92%}}.np_site-progress--done{animation:none;opacity:0;transition:width .14s ease-out,opacity .24s ease-out .12s;width:100%}@media (prefers-reduced-motion:reduce){.np_site-progress{animation:none;width:92%}.np_site-progress--done{transition:opacity .14s linear}}
|
|
1
|
+
.np_companion-live-container,.np_companion-preview-container{height:100%;margin:0;padding:0;position:absolute;transition:opacity .3s ease-in-out;width:100%}.np_companion-preview-container{opacity:1;z-index:2}.np_companion-preview-container.np_companion-fade-out{opacity:0;pointer-events:none;transition:opacity .5s ease-out}.np_companion-live-container{opacity:0;z-index:1}.np_companion-live-container.np_companion-fade-in{opacity:1;z-index:3}:root{--base-border-radius:10px;--base-gap:20px}*,:after,:before{-webkit-box-sizing:border-box;box-sizing:border-box}::-webkit-input-placeholder{color:hsla(0,0%,100%,.4)}::-moz-placeholder{color:hsla(0,0%,100%,.4)}:-ms-input-placeholder{color:hsla(0,0%,100%,.4)}:-moz-placeholder{color:hsla(0,0%,100%,.4)}a,input{outline:none}.np_companion-hide{display:none!important}.np_companion-align-middle{align-items:center;display:flex;justify-content:center}.np_companion-align-between{align-items:center;display:flex;justify-content:space-between}.np_companion-align-end{align-items:center;display:flex;justify-content:flex-end}.np_companion-align-start{align-items:flex-start;display:flex;justify-content:flex-start}.np_companion__d-none{display:none!important}#np_companion-sdk-root.np_companion-container-fixed{height:500px;position:fixed;transition:top .3s ease-in-out,right .3s ease-in-out,bottom .3s ease-in-out,left .3s ease-in-out,width .3s ease-in-out,height .3s ease-in-out;width:400px;z-index:9999}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-rectangle{height:400px;width:340px}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-silhouette{height:400px}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-round{height:360px;width:250px}#np_companion-sdk-root.np_companion-container-fixed.np_companion-view-round.np_companion_disclaimer-disabled{height:320px!important}#np_companion-sdk-root.np_companion-container-fixed.np_companion-bottom-right{bottom:0;right:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-bottom-left{bottom:0;left:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-bottom-center{bottom:0;left:50%;transform:translateX(-50%)}#np_companion-sdk-root.np_companion-container-fixed.np_companion-top-right{right:0;top:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-top-left{left:0;top:0}#np_companion-sdk-root.np_companion-container-fixed.np_companion-top-center{left:50%;top:0;transform:translateX(-50%)}#np_companion-sdk-root.np_companion-container-fixed.np_companion-center{left:50%;top:50%;transform:translate(-50%,-50%)}#np_companion-sdk-root.np_companion-container-inline{aspect-ratio:4/5;height:100%;position:relative;width:100%}#np_companion-sdk-root.np_companion-container-inline.np_companion-view-round{aspect-ratio:1/1;container-type:size}.np_companion-avatar{height:100%;position:relative;width:100%}#np_companion-avatar-container{background:transparent;border-radius:var(--base-border-radius);height:100%;overflow:hidden;position:absolute;width:100%}#np_companion-avatar-container:not(.np_companion-view-silhouette){box-shadow:0 0 #0000,0 0 #0000,0 0 #0000,0 0 #0000,0 10px 15px -3px color-mix(in oklab,#00000080 100%,transparent),0 4px 6px -4px color-mix(in oklab,#00000080 100%,transparent)}.np_companion-avatar.np_companion-bg-transparent #np_companion-avatar-container.np_companion-view-silhouette{filter:drop-shadow(0 10px 15px rgba(0,0,0,.5)) drop-shadow(0 4px 6px rgba(0,0,0,.5))}.np_companion-container-fixed #np_companion-avatar-container.np_companion-view-round{border-radius:50%;height:212px;left:50%;transform:translate(-50%,12%);width:212px}.np_companion-container-fixed #np_companion-avatar-container.np_companion-view-rectangle,.np_companion-container-fixed #np_companion-avatar-container.np_companion-view-silhouette{left:50%;transform:translateX(-50%)}.np_companion-container-inline #np_companion-avatar-container.np_companion-view-round{border-radius:50%;height:min(100cqw,calc(100cqh - var(--np-controls-band, 88px)));left:50%;top:0;transform:translateX(-50%);width:min(100cqw,calc(100cqh - var(--np-controls-band, 88px)))}.np_companion-avatar-video{height:100%;inset:0;object-fit:cover;pointer-events:none;position:absolute;transition:opacity .3s ease-in-out;width:100%;z-index:10}.np_companion-avatar-video.no-opacity{opacity:0}.np_companion-avatar-canvas{background:transparent;height:100%;object-fit:cover;position:relative;width:100%;z-index:1}#np_companion-avatar-container.np_companion-loader-pulse:after,.np_companion-container-fixed #np_companion-avatar-container.np_companion-loader-pulse:after{animation:pulse 1.5s ease-in-out infinite;background-color:var(--np-loader-bg-color);border-radius:var(--base-border-radius);content:"";display:block;height:100%;left:0;opacity:.6;overflow:hidden;position:absolute;top:0;width:100%}.np_companion-avatar.np_companion-bg-transparent #np_companion-avatar-container:after{display:none}.np_companion-avatar:has(#np_companion-avatar-container.np_companion-view-round):after{display:none}#np_companion-avatar-container.np_companion-loader-pulse.loader-container.np_companion-view-round:after{animation:pulse 1.5s ease-in-out infinite;background-color:var(--np-loader-bg-color);border-radius:50%;content:"";display:block;height:100%;left:0;opacity:.6;overflow:hidden;position:absolute;top:0;width:100%}.np_companion-avatar.np_companion-bg-transparent #np_companion-avatar-container.np_companion-view-round:after{display:none}@keyframes pulse{0%,to{opacity:.5}50%{opacity:.2}}.np_companion-disclaimer-text{-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;color:#fff;font-size:10px;line-height:12px;margin:auto auto 16px;max-width:940px;opacity:.7;overflow:hidden;padding:0 16px;text-align:center;z-index:12}.np_companion-disclaimer-text a{color:#fff}.np_companion-disclaimer-text a:hover{color:#fff;text-decoration:underline}.np_companion-disclaimer-text a:focus,.np_companion-disclaimer-text a:visited{color:#fff}.np_companion-action-btn-container-wrapper{pointer-events:auto;width:100%}.np_companion-avatar-control-container{backdrop-filter:blur(19px);background:none;background-color:rgba(52,51,51,.6);border-radius:16px;bottom:0;box-shadow:0 4px 4px 0 rgba(0,0,0,.25),2px 2px 8px 0 rgba(0,0,0,.12);left:50%;max-width:90%;min-width:210px;opacity:1;position:absolute;transform:translateX(-50%);transition:opacity .4s cubic-bezier(.4,0,.2,1);z-index:99}.np_companion-avatar-control-container.np_companion-action-btn-container-collapse{opacity:0}.np_companion-avatar-control-container:not(.np_companion-avatar-control-view-round){bottom:16px}.np_companion-avatar:not(.np_companion-bg-transparent) .np_companion-loader-spinner:not(.np_companion-view-silhouette){backdrop-filter:blur(19px);background-color:color-mix(in oklab,var(--np-loader-bg-color) 100%,transparent)!important;filter:none!important;height:100%;width:100%}.np_companion-loader-spinner .loader-container{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%)}.np_companion-loader-spinner .loader-container .loader{--_m:conic-gradient(#0000 10%,#000),linear-gradient(#000 0 0) content-box;animation:l3 1s linear infinite;aspect-ratio:1;background:var(--np-loader-color);border-radius:50%;-webkit-mask:var(--_m);mask:var(--_m);-webkit-mask-composite:source-out;mask-composite:subtract;padding:4px;width:24px}@keyframes l3{to{transform:rotate(1turn)}}.np_companion-loader-spinner.np_companion-view-round .loader-container .loader{padding:4px;width:212px}.np_companion-bg-transparent .np_companion-loader-spinner .loader-container{display:none}.np_companion-controls-container{align-items:center;background:hsla(0,0%,100%,.3);border:.5px solid #fff;border-radius:12px;bottom:20px;box-shadow:0 1px 1px rgba(0,0,0,.267),0 2px 5px rgba(0,0,0,.267),0 3px 8px rgba(0,0,0,.267);display:flex;gap:8px;left:50%;max-width:360px;pointer-events:auto;position:absolute;transform:translateX(-50%);transform-origin:bottom center;transition:width .3s ease-in-out;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:auto;z-index:99}.np_companion-controls-container.collapsed{gap:0}.np_companion-time-running{color:#fff}.np_companion-controls-time-action-btn-container{align-items:center;background:hsla(0,0%,100%,.1);border-radius:8px;display:flex;filter:grayscale(1);flex-shrink:0;gap:8px;height:32px;padding-left:8px;padding-right:8px;transition:filter .3s ease}.np_companion-controls-mic-control,.np_companion-controls-stop-control{cursor:pointer;display:flex;margin:0 5px;overflow:hidden;transition:opacity .3s ease-in-out,width .3s ease-in-out;width:47px}.np_companion-controls-mic-control.visible,.np_companion-controls-stop-control.visible{opacity:1}.np_companion-controls-mic-control.visible{width:1em}.np_companion-controls-stop-control.visible{width:1.5em}.np_companion-controls-mic-control.hidden,.np_companion-controls-stop-control.hidden{margin:0;opacity:0;padding:0;pointer-events:none;width:0}.np_companion-controls-mic-control:hover svg path{fill:red}.np_companion-controls-stop-control{display:flex;margin:0 5px 0 0}.np_companion-controls-stop-control:hover svg .stop-circle{fill:red}.np_companion-controls-stop-control:hover svg .stop-square{fill:#fff}.np_companion-mic-dropdown{background:#2b2c32;border-radius:4px;border-radius:6px;bottom:35px;box-shadow:0 10px 15px -3px rgba(0,0,0,.2),0 4px 6px -4px rgba(0,0,0,.2),0 0 0 1px #46464d;color:#fff;font-size:14px;list-style-type:none;margin:0;max-height:200px;min-width:300px;overflow-y:auto;overflow:auto;padding:5px;pointer-events:auto;position:absolute;width:auto;z-index:1000}.np_companion-mic-dropdown li{cursor:pointer;padding:8px 12px}.np_companion-mic-dropdown li:hover{background-color:#000}.np_companion-action-btn-container-container{background:transparent;border-radius:80px;gap:8px;padding:16px 16px 12px;transition:all .3s ease-in-out}.np_companion-action-btn-container-container.np_companion_disclaimer-disabled{padding-bottom:16px}.np_companion-action-btn-container-container .np_companion-chat-question-bar-container{border-radius:16px;gap:8px}.np_companion-action-btn-container-container .np_companion-action-btn-container-left{transition:all .3s ease-in-out;width:40px}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon{border-radius:80px;cursor:pointer;height:40px;transition:all .3s ease-in-out;width:40px}.np_companion-dark-grey-bg{background:linear-gradient(0deg,#5e5e5e14 0 100%),#ffffff0f}.np_companion-grey-bg{background:linear-gradient(0deg,rgba(94,94,94,.07),rgba(94,94,94,.07)),hsla(0,0%,100%,.04)}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon svg{height:auto;width:22px}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon.muted svg.np_companion-mic-muted,.np_companion-action-btn-container-container .np_companion-action-btn-container-icon:not(.muted) svg.np_companion-mic-unmuted{display:flex}.np_companion-action-btn-container-container .np_companion-action-btn-container-right{gap:8px;transition:all .3s ease-in-out}.np_companion-action-btn-container-container .np_companion-action-btn-container-left .np_companion-action-btn-container-icon:hover,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon.active,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:hover{background-color:#fff!important}.np_companion-action-btn-container-container .np_companion-action-btn-container-left .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color):hover svg path{fill:#000}.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon.np_companion-action-btn-container-call-end svg{height:auto;width:16px}.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color).np_companion-action-btn-container-call-end:hover svg path{stroke:#000}.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color).active svg path,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color).np_companion-action-btn-container-toggle:hover svg path,.np_companion-action-btn-container-container .np_companion-action-btn-container-right .np_companion-action-btn-container-icon:not(.np_companion-persist-fill-color):hover svg path{fill:#000}.np_companion-mobile-mode{bottom:15px;scale:.7}.np_companion-mobile-mode .np_companion-action-btn-container-left{opacity:1;width:40px}.np_companion-mobile-mode .np_companion-action-btn-container-right{opacity:1}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon.np_companion-talking{background:rgba(52,199,89,.25);box-shadow:0 0 0 2px rgba(52,199,89,.4);transition:background .2s ease,box-shadow .2s ease}.np_companion-action-btn-container-container .np_companion-action-btn-container-icon.np_companion-talking svg path{fill:#34c759}.np_companion-inactive-overlay{align-items:center;bottom:0;display:flex;justify-content:center;left:0;pointer-events:auto;position:absolute;right:0;top:0;z-index:9999}.np_companion-inactive-dialog{backdrop-filter:blur(19px);background:hsla(0,0%,50%,.3);background-blend-mode:luminosity;border-radius:16px;max-width:500px;overflow:hidden;padding:24px 16px;position:relative;text-align:center;width:100%}@supports (-moz-appearance:none){.np_companion-inactive-dialog{background:rgba(32,32,34,.88);background-blend-mode:normal}}.np_companion-inactive-dialog:before{background:linear-gradient(180deg,hsla(0,0%,100%,.4),hsla(0,0%,100%,0),hsla(0,0%,100%,0),hsla(0,0%,100%,.1));border-radius:16px;content:"";inset:0;-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:destination-out;mask-composite:exclude;padding:1.473px;pointer-events:none;position:absolute}.np_companion-inactive-message{color:#fff;font-size:16px;line-height:1.5;margin-bottom:24px;margin-top:0}.np_companion-inactive-timer{display:flex;justify-content:center;margin:24px 0;pointer-events:none}.np_companion-timer-circle{align-items:center;display:flex;height:80px;justify-content:center;position:relative;width:80px}.np_companion-timer-circle svg{height:100%;transform:rotate(-90deg);width:100%}.np_companion-timer-circle path{transition:stroke-dasharray .3s ease}.np_companion-timer-number{color:#fff;font-size:24px;font-weight:500;position:absolute}.np_companion-inactive-buttons{display:flex;gap:12px;justify-content:center}.np_companion-inactive-buttons button{border:none;border-radius:8px;cursor:pointer;font-size:14px;font-weight:500;padding:12px 24px;transition:background-color .2s ease}.np_companion-end-button{background:hsla(0,0%,100%,.1);color:#fff}.np_companion-end-button:hover{background:hsla(0,0%,100%,.2)}.np_companion-continue-button{background:#3c19cd;color:#fff}.np_companion-continue-button:hover{background:#2f13a0}#np_companion-sdk-root[data-np-state=active] .np_button,#np_companion-sdk-root[data-np-state=connecting] .np_button,#np_companion-sdk-root[data-np-state=idle] .np_companion-live-container{display:none}#np_companion-sdk-root[data-np-state=idle].np_companion-container-fixed{height:auto;width:auto}.np_button{align-items:center;background:#16c784;border:0;border-radius:999px;box-shadow:0 10px 30px rgba(0,0,0,.45);color:#000;cursor:pointer;display:inline-flex;font:inherit;font-size:14px;font-weight:700;gap:10px;line-height:1;padding:13px 20px}.np_button:focus-visible{outline:2px solid #063;outline-offset:2px}.np_button--pending{cursor:progress;opacity:.7}.np_button-avatar{border-radius:50%;flex:none;height:24px;object-fit:cover;width:24px}.np_button-label{white-space:nowrap}.np_button-dot{background:#063;border-radius:50%;box-shadow:0 0 0 4px rgba(22,199,132,.22);flex:none;height:9px;width:9px}.np_button--pending .np_button-dot{animation:np_button-pulse 1s ease-in-out infinite}@keyframes np_button-pulse{0%,to{opacity:1}50%{opacity:.3}}@media (prefers-reduced-motion:reduce){.np_button--pending .np_button-dot{animation:none}}.np_button-description{display:block;font-size:12px;line-height:1.35;margin-top:2px;opacity:.72}.np_button-text{align-items:flex-start;display:flex;flex-direction:column;min-width:0}.np_site-frame{backface-visibility:hidden;border:0;height:100vh;height:100dvh;inset:0;position:fixed;transform:translateZ(0);width:100%;z-index:100000000}.np_site-progress{animation:np_site-progress-grow 6s cubic-bezier(.15,.75,.25,1) forwards;background:var(--np-persist-progress-color,#be369d);border-end-end-radius:3px;box-shadow:0 0 10px var(--np-persist-progress-color,#be369d);height:var(--np-persist-progress-height,3px);left:0;pointer-events:none;position:fixed;top:0;width:0;z-index:100000002}@keyframes np_site-progress-grow{0%{width:0}to{width:92%}}.np_site-progress--done{animation:none;opacity:0;transition:width .14s ease-out,opacity .24s ease-out .12s;width:100%}@media (prefers-reduced-motion:reduce){.np_site-progress{animation:none;width:92%}.np_site-progress--done{transition:opacity .14s linear}}.np_companion-mic-permission{--np-mic-permission-accent:#be369d;--np-mic-permission-accent-hover:#a62d88;--np-mic-permission-card-bg:hsla(0,0%,4%,.8);--np-mic-permission-card-radius:27px;align-items:flex-end;display:flex;inset:0;justify-content:center;padding:8px;pointer-events:auto;position:absolute;z-index:9999}.np_companion-mic-permission-card{backdrop-filter:blur(19px);background:var(--np-mic-permission-card-bg);border-radius:var(--np-mic-permission-card-radius);box-sizing:border-box;max-width:386px;padding:15px;text-align:center;width:100%}.np_companion-mic-permission-pagination{align-items:center;display:flex;gap:4px;justify-content:center;margin-bottom:8px}.np_companion-mic-permission-pagination[hidden]{display:none}.np_companion-mic-permission-dot{background:hsla(0,0%,100%,.4);border-radius:2px;height:4px;transition:width .2s ease,background .2s ease;width:4px}.np_companion-mic-permission-dot--active{background:#fff;width:16px}.np_companion-mic-permission-heading{color:#fff;font-family:inherit;font-size:18px;font-style:normal;font-weight:700;letter-spacing:-.18px;line-height:21.6px;margin:0 0 4px;text-transform:none}.np_companion-mic-permission-subheading{color:hsla(0,0%,100%,.5);font-family:inherit;font-size:14px;font-style:normal;font-weight:400;letter-spacing:-.28px;line-height:19.6px;margin:0 0 20px;text-transform:none}.np_companion-mic-permission-em--semibold{font-weight:600}.np_companion-mic-permission-em--bold{font-weight:700}.np_companion-mic-permission-actions{align-items:stretch;display:flex;flex-direction:column;gap:8px}.np_companion-mic-permission-actions button{border:0;color:#fff;cursor:pointer;font-family:inherit;font-style:normal;font-weight:600;text-transform:none;transition:background .2s ease}.np_companion-mic-permission-actions button:disabled{cursor:progress;opacity:.6}.np_companion-mic-permission-actions button:focus-visible{outline:2px solid #fff;outline-offset:2px}.np_companion-mic-permission-primary{background:var(--np-mic-permission-accent);border-radius:999px;font-size:15px;letter-spacing:-.15px;line-height:22px;min-height:48px;padding:7px 15px}.np_companion-mic-permission-primary:hover:not(:disabled){background:var(--np-mic-permission-accent-hover)}.np_companion-mic-permission-secondary{background:transparent;font-size:14px;letter-spacing:-.14px;line-height:19.6px;min-height:32px;padding:4px}.np_companion-mic-permission-secondary:hover:not(:disabled){color:hsla(0,0%,100%,.8)}.np_companion-mic-permission-live{clip:rect(0,0,0,0);border:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;white-space:nowrap;width:1px}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NapsterCompanionApiSDK, NapsterCompanionApiConfig, NapsterCompanionApiInstance } from "./types";
|
|
1
|
+
import type { NapsterCompanionApiSDK, NapsterCompanionApiConfig, NapsterCompanionApiInstance, NapsterCompanionApiController, ButtonConfig } from "./types";
|
|
2
2
|
declare global {
|
|
3
3
|
interface Window {
|
|
4
4
|
napsterCompanionApiSDK: NapsterCompanionApiSDK;
|
|
@@ -12,6 +12,7 @@ declare class NapsterCompanionApiSdkVanilla implements NapsterCompanionApiSDK {
|
|
|
12
12
|
private embed;
|
|
13
13
|
private micGate;
|
|
14
14
|
private getTokenFn;
|
|
15
|
+
private sessionEpoch;
|
|
15
16
|
private webrtcController;
|
|
16
17
|
private screenShareController;
|
|
17
18
|
private faceTrackingController;
|
|
@@ -21,43 +22,137 @@ declare class NapsterCompanionApiSdkVanilla implements NapsterCompanionApiSDK {
|
|
|
21
22
|
private pipController;
|
|
22
23
|
private edgeMcpBridge;
|
|
23
24
|
private persistCtl;
|
|
25
|
+
private onSessionFailedHandler;
|
|
26
|
+
private onSessionEndedHandler;
|
|
27
|
+
private buttonMode;
|
|
24
28
|
private lastFaceDetected;
|
|
25
29
|
private userMutedDuringFaceTracking;
|
|
26
30
|
private faceTrackingLastDispatchedMute;
|
|
27
31
|
private muteStoreUnsubscribe;
|
|
28
32
|
static getInstance(): NapsterCompanionApiSdkVanilla;
|
|
29
33
|
constructor();
|
|
34
|
+
/**
|
|
35
|
+
* Per-session setup that destroyInstance() tears down but only init() itself
|
|
36
|
+
* used to rebuild: the feature dispatch, the features-update callback, and the
|
|
37
|
+
* WebMCP bridge. Must run before renderApp() — the embed reads features from
|
|
38
|
+
* the store, and both the embed and a persisted iframe read `this.edgeMcpBridge`.
|
|
39
|
+
*
|
|
40
|
+
* A preserveRoot teardown (button mode's endSession/failToMintToken) clears all
|
|
41
|
+
* three even though it keeps the root, so this also runs from the button-mode
|
|
42
|
+
* restore path before every session after the first — otherwise a host's
|
|
43
|
+
* `features` config and WebMCP tool access would silently work only once.
|
|
44
|
+
*
|
|
45
|
+
* The feature dispatch and the features-update callback re-apply on every call —
|
|
46
|
+
* they are cheap and genuinely per-session. The WebMCP bridge is the one guarded
|
|
47
|
+
* block: see the comment at its construction for why it skips instead of
|
|
48
|
+
* rebuilding. Deliberately asymmetric — do not "tidy" the two to match.
|
|
49
|
+
*/
|
|
50
|
+
private setupSessionServices;
|
|
51
|
+
/**
|
|
52
|
+
* Wrap the page for cross-navigation persistence, if configured. Must run
|
|
53
|
+
* AFTER renderApp() — it needs `this.rootEl`, which renderApp() creates on
|
|
54
|
+
* first use. Same rebuild requirement as setupSessionServices(): a
|
|
55
|
+
* preserveRoot teardown clears `persistCtl` too, so this also runs from the
|
|
56
|
+
* button-mode restore path before every session after the first.
|
|
57
|
+
*
|
|
58
|
+
* Idempotent, but by early-returning rather than rebuilding: there is no
|
|
59
|
+
* teardown between init() and the FIRST start(), so `this.persistCtl` is
|
|
60
|
+
* still the live, correctly-wrapped-and-armed controller init() built.
|
|
61
|
+
* Rebuilding it here (as setupSessionServices() does for the bridge) would
|
|
62
|
+
* wrap the page a SECOND time in a second iframe the first controller can't
|
|
63
|
+
* see, arm a second on-navigate interceptor, and drop the first controller
|
|
64
|
+
* from `this.persistCtl` with its `teardown()` never called.
|
|
65
|
+
*/
|
|
66
|
+
private setupPersistence;
|
|
30
67
|
private renderApp;
|
|
68
|
+
/**
|
|
69
|
+
* One session attempt: open a new epoch, settle the microphone, mint, connect.
|
|
70
|
+
* Errors propagate — button mode awaits this directly so a failed attempt
|
|
71
|
+
* (denied mic, failed mint) reaches its own caller instead of being reported
|
|
72
|
+
* here.
|
|
73
|
+
*/
|
|
74
|
+
private runSessionAttempt;
|
|
75
|
+
/**
|
|
76
|
+
* Immediate mode's kickoff: the same attempt as runSessionAttempt(), but
|
|
77
|
+
* fire-and-forget — errors are reported via onError rather than thrown,
|
|
78
|
+
* since renderApp() has no caller to catch them.
|
|
79
|
+
*/
|
|
80
|
+
private startSession;
|
|
31
81
|
/**
|
|
32
82
|
* Acquire the microphone, then connect. On failure the widget stays mounted and
|
|
33
83
|
* hands over to the permission-recovery flow, which drives the retry.
|
|
34
84
|
*/
|
|
35
85
|
private startSessionWhenMicAvailable;
|
|
36
86
|
/**
|
|
37
|
-
* Called once the microphone gate grants access
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
87
|
+
* Called once the microphone gate grants access: mint a fresh token (as late
|
|
88
|
+
* as possible, since tokens live ~5s) and connect with it.
|
|
89
|
+
*
|
|
90
|
+
* `epoch` is the session this mint belongs to. It is re-checked after the
|
|
91
|
+
* await because getToken() is the host's code and may take arbitrarily long —
|
|
92
|
+
* long enough for the host to destroy and re-init underneath us.
|
|
41
93
|
*/
|
|
42
94
|
private mintTokenAndConnect;
|
|
43
95
|
/**
|
|
44
96
|
* getToken() failed (or returned nothing) after the mic gate already granted access and
|
|
45
97
|
* the embed is mounted and waiting. Left alone the widget would sit in its connecting UI
|
|
46
98
|
* forever — there is no later retry path once the mic gate has already dismissed itself.
|
|
47
|
-
*
|
|
99
|
+
*
|
|
100
|
+
* Tear down BEFORE reporting: the obvious host recovery is to call init() again from
|
|
101
|
+
* inside onError, and that only works once isInitialized has been cleared. destroyInstance()
|
|
102
|
+
* already models this ordering for its own onDestroy callback.
|
|
103
|
+
*
|
|
104
|
+
* revealOnly rather than end(): under persistence the page is already wrapped by the time
|
|
105
|
+
* the gate settles, so a failed mint should reveal it in place rather than navigate.
|
|
106
|
+
*
|
|
107
|
+
* `preserveRoot` (== button mode) reports through the failure channel
|
|
108
|
+
* (onSessionFailedHandler) instead of onError directly. Unlike a thrown rejection,
|
|
109
|
+
* this reaches the controller whether or not anything is awaiting the attempt —
|
|
110
|
+
* covering both a click still in flight AND an unawaited "Check again" retry driven
|
|
111
|
+
* from inside the mic-recovery card.
|
|
48
112
|
*/
|
|
49
113
|
private failToMintToken;
|
|
114
|
+
/**
|
|
115
|
+
* Hand the freshly minted token to the transport the config declared.
|
|
116
|
+
*
|
|
117
|
+
* Only webrtc exists today and normalizeConfig() has already rejected
|
|
118
|
+
* anything else, so this reads as a formality — but it is the branch point a
|
|
119
|
+
* second transport plugs into, and keeping it here means `transport` is a
|
|
120
|
+
* field the connect path actually consults rather than decoration.
|
|
121
|
+
*/
|
|
122
|
+
private connectSessionTransport;
|
|
50
123
|
private connectWebRTC;
|
|
51
124
|
private handleScreenShareToggle;
|
|
52
125
|
private initializeWebRTC;
|
|
53
126
|
private destroyWebRTC;
|
|
54
127
|
private destroyInstance;
|
|
55
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Initialize the SDK in click-to-start mode: resolves with a controller, and
|
|
130
|
+
* nothing connects until `start()` or a click on the entry point.
|
|
131
|
+
*
|
|
132
|
+
* `getToken` is called by the SDK itself once the microphone permission has
|
|
133
|
+
* settled — on every attempt, including a "Check again" retry — so the
|
|
134
|
+
* connection token is always fresh when signaling starts. A pre-minted token
|
|
135
|
+
* string is not accepted: minting it before the mic prompt lets it go stale
|
|
136
|
+
* while the user is deciding.
|
|
137
|
+
*/
|
|
138
|
+
init(getToken: () => Promise<string>, config: Partial<NapsterCompanionApiConfig> & {
|
|
139
|
+
button: ButtonConfig & {
|
|
140
|
+
enabled: true;
|
|
141
|
+
};
|
|
142
|
+
}): Promise<NapsterCompanionApiController>;
|
|
143
|
+
/**
|
|
144
|
+
* Initialize the SDK and connect immediately: resolves once the session is up.
|
|
145
|
+
*
|
|
146
|
+
* `getToken` is called by the SDK itself once the microphone permission has
|
|
147
|
+
* settled, so the connection token is always fresh when signaling starts. A
|
|
148
|
+
* pre-minted token string is not accepted.
|
|
149
|
+
*/
|
|
150
|
+
init(getToken: () => Promise<string>, config?: Partial<NapsterCompanionApiConfig>): Promise<NapsterCompanionApiInstance>;
|
|
56
151
|
private createInstanceMethods;
|
|
57
152
|
}
|
|
58
153
|
declare const NapsterCompanionApiSdk: NapsterCompanionApiSdkVanilla;
|
|
59
154
|
export { NapsterCompanionApiSdk };
|
|
60
|
-
export type { NapsterCompanionApiConfig, NapsterCompanionApiInstance, PersistenceOptions, CompanionFunction, FeatureConfig, StyleObject, FaceTrackingConfig, FaceTrackingData, FaceTrackingController, MouthLandmarks, } from "./types";
|
|
155
|
+
export type { NapsterCompanionApiConfig, NapsterCompanionApiInstance, NapsterCompanionApiController, PersistenceOptions, ButtonConfig, CompanionFunction, FeatureConfig, StyleObject, FaceTrackingConfig, FaceTrackingData, FaceTrackingController, MouthLandmarks, } from "./types";
|
|
61
156
|
export { Position } from "./types";
|
|
62
157
|
export { DataChannelMessageType } from "./constants/events";
|
|
63
158
|
export { checkPiPSupport, resetPiPSupportCache } from "./utils/PiPManager";
|