@memberjunction/realtime-runtime 6.2.0-edge.3 → 6.2.0-edge.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 +75 -0
- package/dist/channels/base-realtime-channel-client.d.ts +535 -28
- package/dist/channels/base-realtime-channel-client.d.ts.map +1 -1
- package/dist/channels/base-realtime-channel-client.js +864 -10
- package/dist/channels/base-realtime-channel-client.js.map +1 -1
- package/dist/channels/channel-action-dispatcher.d.ts +70 -0
- package/dist/channels/channel-action-dispatcher.d.ts.map +1 -0
- package/dist/channels/channel-action-dispatcher.js +136 -0
- package/dist/channels/channel-action-dispatcher.js.map +1 -0
- package/dist/channels/channel-catalog-note.d.ts +48 -0
- package/dist/channels/channel-catalog-note.d.ts.map +1 -0
- package/dist/channels/channel-catalog-note.js +119 -0
- package/dist/channels/channel-catalog-note.js.map +1 -0
- package/dist/channels/channel-contract-types.d.ts +107 -0
- package/dist/channels/channel-contract-types.d.ts.map +1 -0
- package/dist/channels/channel-contract-types.js +12 -0
- package/dist/channels/channel-contract-types.js.map +1 -0
- package/dist/channels/channel-descriptor-synthesis.d.ts +56 -0
- package/dist/channels/channel-descriptor-synthesis.d.ts.map +1 -0
- package/dist/channels/channel-descriptor-synthesis.js +90 -0
- package/dist/channels/channel-descriptor-synthesis.js.map +1 -0
- package/dist/channels/channel-perception.d.ts +82 -0
- package/dist/channels/channel-perception.d.ts.map +1 -0
- package/dist/channels/channel-perception.js +120 -0
- package/dist/channels/channel-perception.js.map +1 -0
- package/dist/channels/channel-schema-format.d.ts +17 -0
- package/dist/channels/channel-schema-format.d.ts.map +1 -0
- package/dist/channels/channel-schema-format.js +45 -0
- package/dist/channels/channel-schema-format.js.map +1 -0
- package/dist/channels/channel-state-delta.d.ts +59 -0
- package/dist/channels/channel-state-delta.d.ts.map +1 -0
- package/dist/channels/channel-state-delta.js +116 -0
- package/dist/channels/channel-state-delta.js.map +1 -0
- package/dist/channels/channel-surface-placement.d.ts +25 -0
- package/dist/channels/channel-surface-placement.d.ts.map +1 -0
- package/dist/channels/channel-surface-placement.js +29 -0
- package/dist/channels/channel-surface-placement.js.map +1 -0
- package/dist/channels/channel-visual-pump.d.ts +126 -0
- package/dist/channels/channel-visual-pump.d.ts.map +1 -0
- package/dist/channels/channel-visual-pump.js +174 -0
- package/dist/channels/channel-visual-pump.js.map +1 -0
- package/dist/hosts/IRealtimeMediaHost.d.ts +61 -4
- package/dist/hosts/IRealtimeMediaHost.d.ts.map +1 -1
- package/dist/hosts/IRealtimeMediaHost.js +2 -1
- package/dist/hosts/IRealtimeMediaHost.js.map +1 -1
- package/dist/index.d.ts +21 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -1
- package/dist/session/RealtimeSessionRuntime.d.ts +727 -74
- package/dist/session/RealtimeSessionRuntime.d.ts.map +1 -1
- package/dist/session/RealtimeSessionRuntime.js +1732 -242
- package/dist/session/RealtimeSessionRuntime.js.map +1 -1
- package/dist/session/RecordingShardQueue.d.ts +77 -0
- package/dist/session/RecordingShardQueue.d.ts.map +1 -0
- package/dist/session/RecordingShardQueue.js +172 -0
- package/dist/session/RecordingShardQueue.js.map +1 -0
- package/dist/session/app-client-tool-registry.d.ts +76 -0
- package/dist/session/app-client-tool-registry.d.ts.map +1 -0
- package/dist/session/app-client-tool-registry.js +100 -0
- package/dist/session/app-client-tool-registry.js.map +1 -0
- package/dist/session/avatar-notice.d.ts +43 -0
- package/dist/session/avatar-notice.d.ts.map +1 -0
- package/dist/session/avatar-notice.js +60 -0
- package/dist/session/avatar-notice.js.map +1 -0
- package/dist/session/call-end.d.ts +21 -0
- package/dist/session/call-end.d.ts.map +1 -0
- package/dist/session/call-end.js +19 -0
- package/dist/session/call-end.js.map +1 -0
- package/dist/session/channel-exposure-preferences.d.ts +70 -0
- package/dist/session/channel-exposure-preferences.d.ts.map +1 -0
- package/dist/session/channel-exposure-preferences.js +138 -0
- package/dist/session/channel-exposure-preferences.js.map +1 -0
- package/dist/session/channel-session-scope.d.ts +142 -0
- package/dist/session/channel-session-scope.d.ts.map +1 -0
- package/dist/session/channel-session-scope.js +128 -0
- package/dist/session/channel-session-scope.js.map +1 -0
- package/dist/session/client-session-deadline.d.ts +28 -0
- package/dist/session/client-session-deadline.d.ts.map +1 -0
- package/dist/session/client-session-deadline.js +50 -0
- package/dist/session/client-session-deadline.js.map +1 -0
- package/dist/session/realtime-captures.d.ts +236 -0
- package/dist/session/realtime-captures.d.ts.map +1 -0
- package/dist/session/realtime-captures.js +383 -0
- package/dist/session/realtime-captures.js.map +1 -0
- package/dist/session/realtime-microphone.d.ts +50 -0
- package/dist/session/realtime-microphone.d.ts.map +1 -0
- package/dist/session/realtime-microphone.js +51 -0
- package/dist/session/realtime-microphone.js.map +1 -0
- package/dist/session/session-event-hub.d.ts +72 -0
- package/dist/session/session-event-hub.d.ts.map +1 -0
- package/dist/session/session-event-hub.js +151 -0
- package/dist/session/session-event-hub.js.map +1 -0
- package/dist/session/session-launcher.d.ts +128 -0
- package/dist/session/session-launcher.d.ts.map +1 -0
- package/dist/session/session-launcher.js +160 -0
- package/dist/session/session-launcher.js.map +1 -0
- package/package.json +9 -9
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RecordingShardQueue.js","sourceRoot":"","sources":["../../src/session/RecordingShardQueue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The **owner-keyed registry of app client tools** a host registers with a realtime
|
|
3
|
+
* session (the tools the `ContextTool` proxy can run in the browser).
|
|
4
|
+
*
|
|
5
|
+
* The first version of this registry had one operation: *replace everything*. That is a trap the
|
|
6
|
+
* moment a host has two sources of tools. Explorer has two — a set of always-available globals
|
|
7
|
+
* (navigate, open a record, set the theme) and the tools of whichever surface the user is looking
|
|
8
|
+
* at — and registering the surface's tools replaced the globals unless the caller remembered to
|
|
9
|
+
* merge them back, and left the *previous* surface's tools registered if it forgot to clear them
|
|
10
|
+
* (the stale-tools-after-app-switch bug).
|
|
11
|
+
*
|
|
12
|
+
* The fix is ownership. Each source registers under an **owner key** and a registration replaces
|
|
13
|
+
* **only that owner's set**:
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* Register('explorer.global', [NavigateToApp, NavigateToRecord, …]) // once
|
|
17
|
+
* Register('explorer.surface', [SetFilter, …]) // on every surface change
|
|
18
|
+
* Register('explorer.surface', []) // surface gone → ONLY its tools go
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* When two owners register a tool with the same name, the **later-registered owner wins** (an
|
|
22
|
+
* owner keeps its slot when it re-registers, so precedence does not flip every time a surface
|
|
23
|
+
* refreshes) — the more specific source is registered after the more general one.
|
|
24
|
+
*
|
|
25
|
+
* @module @memberjunction/realtime-runtime
|
|
26
|
+
*/
|
|
27
|
+
import type { ClientToolMetadata } from '@memberjunction/ai-core-plus';
|
|
28
|
+
/** Runs a client tool in the browser and returns its result (may be sync or async). */
|
|
29
|
+
export type RealtimeAppClientToolHandler = (params: Record<string, unknown>) => Promise<unknown> | unknown;
|
|
30
|
+
/**
|
|
31
|
+
* One tool a host registers. Only `Name` and `Handler` are required; the optional metadata makes the
|
|
32
|
+
* tool describable (in "available tools" error messages and the resolved capability set) without the
|
|
33
|
+
* host publishing a separate manifest.
|
|
34
|
+
*/
|
|
35
|
+
export interface AppClientToolRegistration {
|
|
36
|
+
/** The tool name the model calls (matched case-insensitively). */
|
|
37
|
+
Name: string;
|
|
38
|
+
/** Executes the tool. */
|
|
39
|
+
Handler: RealtimeAppClientToolHandler;
|
|
40
|
+
/** What the tool does, for the model. */
|
|
41
|
+
Description?: string;
|
|
42
|
+
/** JSON Schema of the tool's parameters. */
|
|
43
|
+
InputSchema?: Record<string, unknown>;
|
|
44
|
+
/** Grouping label. */
|
|
45
|
+
Category?: string;
|
|
46
|
+
}
|
|
47
|
+
/** The owner key used by the single-argument `RegisterAppClientTools(tools)` form. */
|
|
48
|
+
export declare const DEFAULT_APP_TOOL_OWNER = "default";
|
|
49
|
+
/** Owner-keyed registry; see the module documentation. */
|
|
50
|
+
export declare class AppClientToolRegistry {
|
|
51
|
+
/** Owner → (lower-cased tool name → registration). Map insertion order = owner precedence (later wins). */
|
|
52
|
+
private readonly owners;
|
|
53
|
+
/**
|
|
54
|
+
* Replaces the tool set of ONE owner; every other owner's tools are untouched. Invalid entries
|
|
55
|
+
* (no name, no handler) are skipped. An empty list clears the owner's tools (it keeps its place in the
|
|
56
|
+
* precedence order; {@link Unregister} gives the place up too).
|
|
57
|
+
*
|
|
58
|
+
* @param owner A stable key naming the source (`'explorer.surface'`). Blank → {@link DEFAULT_APP_TOOL_OWNER}.
|
|
59
|
+
* @param tools The owner's complete current set.
|
|
60
|
+
*/
|
|
61
|
+
Register(owner: string, tools: ReadonlyArray<AppClientToolRegistration>): void;
|
|
62
|
+
/** Removes one owner's tools (no-op when it has none). */
|
|
63
|
+
Unregister(owner: string): void;
|
|
64
|
+
/** Removes every owner's tools. */
|
|
65
|
+
Clear(): void;
|
|
66
|
+
/** Finds a tool by name (case-insensitive); on a collision the later-registered owner wins. */
|
|
67
|
+
Find(name: string): AppClientToolRegistration | undefined;
|
|
68
|
+
/** The distinct registered tool names, in registration form. */
|
|
69
|
+
Names(): string[];
|
|
70
|
+
/**
|
|
71
|
+
* The registered tools as {@link ClientToolMetadata} — the *session tier* of `ResolveClientTools`.
|
|
72
|
+
* Ordered later-owner-first, so the resolver's first-match-wins agrees with {@link Find}.
|
|
73
|
+
*/
|
|
74
|
+
ToMetadata(): ClientToolMetadata[];
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=app-client-tool-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-client-tool-registry.d.ts","sourceRoot":"","sources":["../../src/session/app-client-tool-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,uFAAuF;AACvF,MAAM,MAAM,4BAA4B,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;AAE3G;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACtC,kEAAkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,yBAAyB;IACzB,OAAO,EAAE,4BAA4B,CAAC;IACtC,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,sBAAsB;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,sFAAsF;AACtF,eAAO,MAAM,sBAAsB,YAAY,CAAC;AAEhD,0DAA0D;AAC1D,qBAAa,qBAAqB;IAC9B,2GAA2G;IAC3G,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6D;IAEpF;;;;;;;OAOG;IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,CAAC,yBAAyB,CAAC,GAAG,IAAI;IAarF,0DAA0D;IACnD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAItC,mCAAmC;IAC5B,KAAK,IAAI,IAAI;IAIpB,+FAA+F;IACxF,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,yBAAyB,GAAG,SAAS;IAShE,gEAAgE;IACzD,KAAK,IAAI,MAAM,EAAE;IAUxB;;;OAGG;IACI,UAAU,IAAI,kBAAkB,EAAE;CAW5C"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The **owner-keyed registry of app client tools** a host registers with a realtime
|
|
3
|
+
* session (the tools the `ContextTool` proxy can run in the browser).
|
|
4
|
+
*
|
|
5
|
+
* The first version of this registry had one operation: *replace everything*. That is a trap the
|
|
6
|
+
* moment a host has two sources of tools. Explorer has two — a set of always-available globals
|
|
7
|
+
* (navigate, open a record, set the theme) and the tools of whichever surface the user is looking
|
|
8
|
+
* at — and registering the surface's tools replaced the globals unless the caller remembered to
|
|
9
|
+
* merge them back, and left the *previous* surface's tools registered if it forgot to clear them
|
|
10
|
+
* (the stale-tools-after-app-switch bug).
|
|
11
|
+
*
|
|
12
|
+
* The fix is ownership. Each source registers under an **owner key** and a registration replaces
|
|
13
|
+
* **only that owner's set**:
|
|
14
|
+
*
|
|
15
|
+
* ```
|
|
16
|
+
* Register('explorer.global', [NavigateToApp, NavigateToRecord, …]) // once
|
|
17
|
+
* Register('explorer.surface', [SetFilter, …]) // on every surface change
|
|
18
|
+
* Register('explorer.surface', []) // surface gone → ONLY its tools go
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* When two owners register a tool with the same name, the **later-registered owner wins** (an
|
|
22
|
+
* owner keeps its slot when it re-registers, so precedence does not flip every time a surface
|
|
23
|
+
* refreshes) — the more specific source is registered after the more general one.
|
|
24
|
+
*
|
|
25
|
+
* @module @memberjunction/realtime-runtime
|
|
26
|
+
*/
|
|
27
|
+
/** The owner key used by the single-argument `RegisterAppClientTools(tools)` form. */
|
|
28
|
+
export const DEFAULT_APP_TOOL_OWNER = 'default';
|
|
29
|
+
/** Owner-keyed registry; see the module documentation. */
|
|
30
|
+
export class AppClientToolRegistry {
|
|
31
|
+
constructor() {
|
|
32
|
+
/** Owner → (lower-cased tool name → registration). Map insertion order = owner precedence (later wins). */
|
|
33
|
+
this.owners = new Map();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Replaces the tool set of ONE owner; every other owner's tools are untouched. Invalid entries
|
|
37
|
+
* (no name, no handler) are skipped. An empty list clears the owner's tools (it keeps its place in the
|
|
38
|
+
* precedence order; {@link Unregister} gives the place up too).
|
|
39
|
+
*
|
|
40
|
+
* @param owner A stable key naming the source (`'explorer.surface'`). Blank → {@link DEFAULT_APP_TOOL_OWNER}.
|
|
41
|
+
* @param tools The owner's complete current set.
|
|
42
|
+
*/
|
|
43
|
+
Register(owner, tools) {
|
|
44
|
+
const key = normalizeOwner(owner);
|
|
45
|
+
const set = new Map();
|
|
46
|
+
for (const tool of tools) {
|
|
47
|
+
if (tool?.Name?.trim() && typeof tool.Handler === 'function') {
|
|
48
|
+
set.set(tool.Name.trim().toLowerCase(), tool);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Map#set on an existing key keeps its insertion slot, so an owner that re-registers (even with
|
|
52
|
+
// an empty set) keeps its place in the precedence order; only Unregister() gives the slot up.
|
|
53
|
+
this.owners.set(key, set);
|
|
54
|
+
}
|
|
55
|
+
/** Removes one owner's tools (no-op when it has none). */
|
|
56
|
+
Unregister(owner) {
|
|
57
|
+
this.owners.delete(normalizeOwner(owner));
|
|
58
|
+
}
|
|
59
|
+
/** Removes every owner's tools. */
|
|
60
|
+
Clear() {
|
|
61
|
+
this.owners.clear();
|
|
62
|
+
}
|
|
63
|
+
/** Finds a tool by name (case-insensitive); on a collision the later-registered owner wins. */
|
|
64
|
+
Find(name) {
|
|
65
|
+
const wanted = (name ?? '').trim().toLowerCase();
|
|
66
|
+
let found;
|
|
67
|
+
for (const set of this.owners.values()) {
|
|
68
|
+
found = set.get(wanted) ?? found;
|
|
69
|
+
}
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
/** The distinct registered tool names, in registration form. */
|
|
73
|
+
Names() {
|
|
74
|
+
const names = new Map();
|
|
75
|
+
for (const set of this.owners.values()) {
|
|
76
|
+
for (const [lower, tool] of set) {
|
|
77
|
+
names.set(lower, tool.Name);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return [...names.values()];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The registered tools as {@link ClientToolMetadata} — the *session tier* of `ResolveClientTools`.
|
|
84
|
+
* Ordered later-owner-first, so the resolver's first-match-wins agrees with {@link Find}.
|
|
85
|
+
*/
|
|
86
|
+
ToMetadata() {
|
|
87
|
+
const ordered = [...this.owners.values()].reverse();
|
|
88
|
+
return ordered.flatMap((set) => [...set.values()].map((tool) => ({
|
|
89
|
+
Name: tool.Name,
|
|
90
|
+
Description: tool.Description ?? '',
|
|
91
|
+
InputSchema: tool.InputSchema ?? {},
|
|
92
|
+
Category: tool.Category,
|
|
93
|
+
})));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Normalizes an owner key; blank falls back to the default owner. */
|
|
97
|
+
function normalizeOwner(owner) {
|
|
98
|
+
return owner?.trim() ? owner.trim() : DEFAULT_APP_TOOL_OWNER;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=app-client-tool-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-client-tool-registry.js","sourceRoot":"","sources":["../../src/session/app-client-tool-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Whether a connected call tells the user it shows no avatar, and why.
|
|
3
|
+
*
|
|
4
|
+
* The server decides the reasons it can see at mint (the model renders no avatar, the persona has no face for it, a
|
|
5
|
+
* custom avatar, an app that said at mint it shows no agent video: `host`) and returns them as the session's avatar
|
|
6
|
+
* status. Two more show only in the browser, once the call is connected: the app asked for no agent video (`host`), or
|
|
7
|
+
* it asked and the browser could not play it (`browser`). {@link ResolveAvatarNotice} puts the three facts together; the
|
|
8
|
+
* runtime publishes the result once per call.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/realtime-runtime
|
|
11
|
+
*/
|
|
12
|
+
import type { ClientRealtimeSessionConfig, ParsedRealtimeAvatarStatus, RealtimeAvatarUnavailableReason } from '@memberjunction/ai';
|
|
13
|
+
/** Why a call shows no avatar, told once after it connects. A host turns the reason into words. */
|
|
14
|
+
export interface RealtimeAvatarNotice {
|
|
15
|
+
/**
|
|
16
|
+
* Why the call is audio only. Absent when the mint gave a reason this version doesn't know, such as a newer server's:
|
|
17
|
+
* the avatar was asked for and isn't shown, and a host says so without a reason.
|
|
18
|
+
*/
|
|
19
|
+
readonly Reason?: RealtimeAvatarUnavailableReason;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Whether a connected call should say it shows no avatar, and why.
|
|
23
|
+
*
|
|
24
|
+
* - No status, or the session asked for no avatar: nothing to say.
|
|
25
|
+
* - Asked for and not granted: the status's reason; a notice without one when the reason is one this version doesn't
|
|
26
|
+
* know (`ReasonUnknown`); nothing when the status gives no reason.
|
|
27
|
+
* - Granted, but the app asked for no agent video: `host`.
|
|
28
|
+
* - Granted and asked for, but the agent's video track is not live: `browser`.
|
|
29
|
+
* - Granted, asked for and live: nothing to say; the avatar shows.
|
|
30
|
+
*
|
|
31
|
+
* @param status The mint's avatar status as `ParseRealtimeAvatarStatus` reads it, or `null` when the mint reported none.
|
|
32
|
+
* @param requested Whether the session asked for the agent's video (an outbound video track).
|
|
33
|
+
* @param established Whether the agent's video track is live once connected.
|
|
34
|
+
* @returns The notice, or `null` when there is nothing to say.
|
|
35
|
+
*/
|
|
36
|
+
export declare function ResolveAvatarNotice(status: ParsedRealtimeAvatarStatus | null, requested: boolean, established: boolean): RealtimeAvatarNotice | null;
|
|
37
|
+
/**
|
|
38
|
+
* Whether a client config asks for the agent's video: an outbound video track among the tracks the session requests.
|
|
39
|
+
*
|
|
40
|
+
* @param config The config the session connected with.
|
|
41
|
+
*/
|
|
42
|
+
export declare function RequestsAgentVideo(config: ClientRealtimeSessionConfig): boolean;
|
|
43
|
+
//# sourceMappingURL=avatar-notice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-notice.d.ts","sourceRoot":"","sources":["../../src/session/avatar-notice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,2BAA2B,EAAa,0BAA0B,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AAG9I,mGAAmG;AACnG,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,+BAA+B,CAAC;CACnD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,0BAA0B,GAAG,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,GAAG,oBAAoB,GAAG,IAAI,CAcpJ;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAG/E"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Whether a connected call tells the user it shows no avatar, and why.
|
|
3
|
+
*
|
|
4
|
+
* The server decides the reasons it can see at mint (the model renders no avatar, the persona has no face for it, a
|
|
5
|
+
* custom avatar, an app that said at mint it shows no agent video: `host`) and returns them as the session's avatar
|
|
6
|
+
* status. Two more show only in the browser, once the call is connected: the app asked for no agent video (`host`), or
|
|
7
|
+
* it asked and the browser could not play it (`browser`). {@link ResolveAvatarNotice} puts the three facts together; the
|
|
8
|
+
* runtime publishes the result once per call.
|
|
9
|
+
*
|
|
10
|
+
* @module @memberjunction/realtime-runtime
|
|
11
|
+
*/
|
|
12
|
+
import { REQUESTED_TRACKS_SESSION_KEY } from '@memberjunction/ai-realtime-client';
|
|
13
|
+
/**
|
|
14
|
+
* Whether a connected call should say it shows no avatar, and why.
|
|
15
|
+
*
|
|
16
|
+
* - No status, or the session asked for no avatar: nothing to say.
|
|
17
|
+
* - Asked for and not granted: the status's reason; a notice without one when the reason is one this version doesn't
|
|
18
|
+
* know (`ReasonUnknown`); nothing when the status gives no reason.
|
|
19
|
+
* - Granted, but the app asked for no agent video: `host`.
|
|
20
|
+
* - Granted and asked for, but the agent's video track is not live: `browser`.
|
|
21
|
+
* - Granted, asked for and live: nothing to say; the avatar shows.
|
|
22
|
+
*
|
|
23
|
+
* @param status The mint's avatar status as `ParseRealtimeAvatarStatus` reads it, or `null` when the mint reported none.
|
|
24
|
+
* @param requested Whether the session asked for the agent's video (an outbound video track).
|
|
25
|
+
* @param established Whether the agent's video track is live once connected.
|
|
26
|
+
* @returns The notice, or `null` when there is nothing to say.
|
|
27
|
+
*/
|
|
28
|
+
export function ResolveAvatarNotice(status, requested, established) {
|
|
29
|
+
if (!status?.Requested) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
if (!status.Granted) {
|
|
33
|
+
if (status.Reason) {
|
|
34
|
+
return { Reason: status.Reason };
|
|
35
|
+
}
|
|
36
|
+
return status.ReasonUnknown ? {} : null;
|
|
37
|
+
}
|
|
38
|
+
if (!requested) {
|
|
39
|
+
return { Reason: 'host' };
|
|
40
|
+
}
|
|
41
|
+
return established ? null : { Reason: 'browser' };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether a client config asks for the agent's video: an outbound video track among the tracks the session requests.
|
|
45
|
+
*
|
|
46
|
+
* @param config The config the session connected with.
|
|
47
|
+
*/
|
|
48
|
+
export function RequestsAgentVideo(config) {
|
|
49
|
+
const tracks = config.SessionConfig[REQUESTED_TRACKS_SESSION_KEY];
|
|
50
|
+
return Array.isArray(tracks) && tracks.some(isAgentVideoTrack);
|
|
51
|
+
}
|
|
52
|
+
/** Whether a requested-track entry is the agent's video: outbound, video. */
|
|
53
|
+
function isAgentVideoTrack(raw) {
|
|
54
|
+
if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const modality = raw['Modality'];
|
|
58
|
+
return raw['Direction'] === 'outbound' && typeof modality === 'string' && modality.trim().toLowerCase() === 'video';
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=avatar-notice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-notice.js","sourceRoot":"","sources":["../../src/session/avatar-notice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AAWlF;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAyC,EAAE,SAAkB,EAAE,WAAoB;IACrH,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACnC,CAAC;QACD,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1C,CAAC;IACD,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAC5B,CAAC;IACD,OAAO,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAmC;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,aAAa,CAAC,4BAA4B,CAAC,CAAC;IAClE,OAAO,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;AACjE,CAAC;AAED,6EAA6E;AAC7E,SAAS,iBAAiB,CAAC,GAAc;IACvC,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,QAAQ,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC,WAAW,CAAC,KAAK,UAAU,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;AACtH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type RealtimeClientError } from '@memberjunction/ai-realtime-client';
|
|
2
|
+
/** How a host words why a call ended: a short status label, and a sentence for a screen or a notice. */
|
|
3
|
+
export interface RealtimeCallEndDescription {
|
|
4
|
+
/** A short status label, such as a call bar's state chip shows. */
|
|
5
|
+
Label: string;
|
|
6
|
+
/** A sentence saying what happened and what to do next. */
|
|
7
|
+
Message: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* What a call says when it ended because its session reached its time limit (MJAPI's relay ends a relayed call at
|
|
11
|
+
* 30 minutes, or sooner when the session has a shorter cap), in place of a connection error.
|
|
12
|
+
*/
|
|
13
|
+
export declare const REALTIME_CALL_TIME_LIMIT_END: Readonly<RealtimeCallEndDescription>;
|
|
14
|
+
/**
|
|
15
|
+
* Why a call ended, in words a host can show, when the call's client said why (`RealtimeSessionRuntime.LastSessionError`);
|
|
16
|
+
* `null` when it ended for a reason with no words of its own, such as a dropped connection, which a host words itself.
|
|
17
|
+
*
|
|
18
|
+
* @param error The call's fatal client error, or `null` when it reported none.
|
|
19
|
+
*/
|
|
20
|
+
export declare function DescribeCallEnd(error: RealtimeClientError | null): Readonly<RealtimeCallEndDescription> | null;
|
|
21
|
+
//# sourceMappingURL=call-end.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-end.d.ts","sourceRoot":"","sources":["../../src/session/call-end.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyC,KAAK,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAErH,wGAAwG;AACxG,MAAM,WAAW,0BAA0B;IACvC,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,eAAO,MAAM,4BAA4B,EAAE,QAAQ,CAAC,0BAA0B,CAG5E,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,GAAG,QAAQ,CAAC,0BAA0B,CAAC,GAAG,IAAI,CAE9G"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { REALTIME_CLIENT_TIME_LIMIT_ERROR_CODE } from '@memberjunction/ai-realtime-client';
|
|
2
|
+
/**
|
|
3
|
+
* What a call says when it ended because its session reached its time limit (MJAPI's relay ends a relayed call at
|
|
4
|
+
* 30 minutes, or sooner when the session has a shorter cap), in place of a connection error.
|
|
5
|
+
*/
|
|
6
|
+
export const REALTIME_CALL_TIME_LIMIT_END = Object.freeze({
|
|
7
|
+
Label: 'Time limit reached',
|
|
8
|
+
Message: 'This call reached its time limit. Start a new call to keep talking.',
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Why a call ended, in words a host can show, when the call's client said why (`RealtimeSessionRuntime.LastSessionError`);
|
|
12
|
+
* `null` when it ended for a reason with no words of its own, such as a dropped connection, which a host words itself.
|
|
13
|
+
*
|
|
14
|
+
* @param error The call's fatal client error, or `null` when it reported none.
|
|
15
|
+
*/
|
|
16
|
+
export function DescribeCallEnd(error) {
|
|
17
|
+
return error?.Code === REALTIME_CLIENT_TIME_LIMIT_ERROR_CODE ? REALTIME_CALL_TIME_LIMIT_END : null;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=call-end.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"call-end.js","sourceRoot":"","sources":["../../src/session/call-end.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAA4B,MAAM,oCAAoC,CAAC;AAUrH;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAyC,MAAM,CAAC,MAAM,CAAC;IAC5F,KAAK,EAAE,oBAAoB;IAC3B,OAAO,EAAE,qEAAqE;CACjF,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAiC;IAC7D,OAAO,KAAK,EAAE,IAAI,KAAK,qCAAqC,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,IAAI,CAAC;AACvG,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The user's own choice of how much of each channel the agent may perceive.
|
|
3
|
+
*
|
|
4
|
+
* Exposure policy has four layers (see `ResolveChannelExposure` in `@memberjunction/ai-core-plus`); the
|
|
5
|
+
* fourth is the USER's, set from the "agent can see" control in the realtime overlay and remembered per
|
|
6
|
+
* channel key so a person who turned the agent's view of their whiteboard off does not have to do it
|
|
7
|
+
* again next call.
|
|
8
|
+
*
|
|
9
|
+
* Where it is remembered is the host's business, which is why this is an interface: the runtime is
|
|
10
|
+
* framework-neutral and does not know whether the person is signed in. Signed-in hosts back it with the
|
|
11
|
+
* user's persisted settings (`mj.realtime.visualPerception.v1`, via `UserInfoEngine`); an anonymous
|
|
12
|
+
* principal or a connect-only embed has no settings to write to and uses the in-memory store, so the
|
|
13
|
+
* choice lasts for the page and no longer.
|
|
14
|
+
*
|
|
15
|
+
* @module @memberjunction/realtime-runtime
|
|
16
|
+
*/
|
|
17
|
+
import { type RealtimeChannelExposure } from '@memberjunction/ai-core-plus';
|
|
18
|
+
/**
|
|
19
|
+
* The `UserInfoEngine` setting key the choices are persisted under, per user. The `v1` is the shape of
|
|
20
|
+
* the stored JSON ({@link SerializeExposurePreferences}); bump it if that shape ever changes so old
|
|
21
|
+
* values can be read and migrated rather than misread.
|
|
22
|
+
*/
|
|
23
|
+
export declare const VISUAL_PERCEPTION_SETTING_KEY = "mj.realtime.visualPerception.v1";
|
|
24
|
+
/** Where the user's per-channel exposure choices are kept. */
|
|
25
|
+
export interface IChannelExposurePreferences {
|
|
26
|
+
/** The user's choice for a channel (key matched case-insensitively), or `undefined` when they made none. */
|
|
27
|
+
Get(channelKey: string): RealtimeChannelExposure | undefined;
|
|
28
|
+
/** Records the user's choice for a channel. `undefined` clears it (back to "no choice"). */
|
|
29
|
+
Set(channelKey: string, level: RealtimeChannelExposure | undefined): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Reads persisted choices tolerantly: a hand-edited or corrupt value contributes nothing (never throws), and
|
|
33
|
+
* only valid levels survive. Keys come back normalized.
|
|
34
|
+
*
|
|
35
|
+
* @param json The stored setting value, or `undefined`/`null`/blank when there is none.
|
|
36
|
+
*/
|
|
37
|
+
export declare function ParseExposurePreferences(json: string | null | undefined): Map<string, RealtimeChannelExposure>;
|
|
38
|
+
/**
|
|
39
|
+
* Serializes choices for persistence. Only the choices themselves are stored (`{"whiteboard":"state"}`):
|
|
40
|
+
* a channel the user never touched has no entry, so a later change to a channel's default is not
|
|
41
|
+
* frozen in by an old write.
|
|
42
|
+
*/
|
|
43
|
+
export declare function SerializeExposurePreferences(preferences: ReadonlyMap<string, RealtimeChannelExposure>): string;
|
|
44
|
+
/** The default store: choices last for this object's lifetime only. */
|
|
45
|
+
export declare class InMemoryChannelExposurePreferences implements IChannelExposurePreferences {
|
|
46
|
+
private readonly values;
|
|
47
|
+
Get(channelKey: string): RealtimeChannelExposure | undefined;
|
|
48
|
+
Set(channelKey: string, level: RealtimeChannelExposure | undefined): void;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The default store: persisted in the signed-in user's settings (`MJ: User Settings`, key
|
|
52
|
+
* {@link VISUAL_PERCEPTION_SETTING_KEY}) via `UserInfoEngine`, so the choice follows the person across
|
|
53
|
+
* devices; kept in memory when there is no user to persist for (an anonymous principal, a connect-only embed).
|
|
54
|
+
*
|
|
55
|
+
* Writes always go to memory first, so a choice takes effect and is read back even if persisting it
|
|
56
|
+
* fails or is not possible. Reads prefer the persisted value when persistence is available, since
|
|
57
|
+
* `UserInfoEngine.GetSetting` is a synchronous cache hit that already reflects a pending debounced write.
|
|
58
|
+
*/
|
|
59
|
+
export declare class UserSettingsExposurePreferences implements IChannelExposurePreferences {
|
|
60
|
+
private readonly canPersist;
|
|
61
|
+
private readonly memory;
|
|
62
|
+
private warnedAboutRead;
|
|
63
|
+
/** @param canPersist Whether user settings can be read and written right now (a signed-in user on a metadata-bearing provider). */
|
|
64
|
+
constructor(canPersist: () => boolean);
|
|
65
|
+
Get(channelKey: string): RealtimeChannelExposure | undefined;
|
|
66
|
+
Set(channelKey: string, level: RealtimeChannelExposure | undefined): void;
|
|
67
|
+
/** The persisted choices; empty (and logged once) when the settings cache cannot be read. */
|
|
68
|
+
private readPersisted;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=channel-exposure-preferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-exposure-preferences.d.ts","sourceRoot":"","sources":["../../src/session/channel-exposure-preferences.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAwC,KAAK,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAElH;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,oCAAoC,CAAC;AAE/E,8DAA8D;AAC9D,MAAM,WAAW,2BAA2B;IAC1C,4GAA4G;IAC5G,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAAC;IAC7D,4FAA4F;IAC5F,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,IAAI,CAAC;CAC3E;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAqB9G;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,uBAAuB,CAAC,GAAG,MAAM,CAS9G;AAED,uEAAuE;AACvE,qBAAa,kCAAmC,YAAW,2BAA2B;IACpF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8C;IAE9D,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAI5D,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,IAAI;CAQjF;AAED;;;;;;;;GAQG;AACH,qBAAa,+BAAgC,YAAW,2BAA2B;IAKrE,OAAO,CAAC,QAAQ,CAAC,UAAU;IAJvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4C;IACnE,OAAO,CAAC,eAAe,CAAS;IAEhC,mIAAmI;gBACtG,UAAU,EAAE,MAAM,OAAO;IAE/C,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAO5D,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,uBAAuB,GAAG,SAAS,GAAG,IAAI;IAehF,6FAA6F;IAC7F,OAAO,CAAC,aAAa;CAWtB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview The user's own choice of how much of each channel the agent may perceive.
|
|
3
|
+
*
|
|
4
|
+
* Exposure policy has four layers (see `ResolveChannelExposure` in `@memberjunction/ai-core-plus`); the
|
|
5
|
+
* fourth is the USER's, set from the "agent can see" control in the realtime overlay and remembered per
|
|
6
|
+
* channel key so a person who turned the agent's view of their whiteboard off does not have to do it
|
|
7
|
+
* again next call.
|
|
8
|
+
*
|
|
9
|
+
* Where it is remembered is the host's business, which is why this is an interface: the runtime is
|
|
10
|
+
* framework-neutral and does not know whether the person is signed in. Signed-in hosts back it with the
|
|
11
|
+
* user's persisted settings (`mj.realtime.visualPerception.v1`, via `UserInfoEngine`); an anonymous
|
|
12
|
+
* principal or a connect-only embed has no settings to write to and uses the in-memory store, so the
|
|
13
|
+
* choice lasts for the page and no longer.
|
|
14
|
+
*
|
|
15
|
+
* @module @memberjunction/realtime-runtime
|
|
16
|
+
*/
|
|
17
|
+
import { UserInfoEngine } from '@memberjunction/core-entities';
|
|
18
|
+
import { IsExposureLevel, NormalizeChannelKey } from '@memberjunction/ai-core-plus';
|
|
19
|
+
/**
|
|
20
|
+
* The `UserInfoEngine` setting key the choices are persisted under, per user. The `v1` is the shape of
|
|
21
|
+
* the stored JSON ({@link SerializeExposurePreferences}); bump it if that shape ever changes so old
|
|
22
|
+
* values can be read and migrated rather than misread.
|
|
23
|
+
*/
|
|
24
|
+
export const VISUAL_PERCEPTION_SETTING_KEY = 'mj.realtime.visualPerception.v1';
|
|
25
|
+
/**
|
|
26
|
+
* Reads persisted choices tolerantly: a hand-edited or corrupt value contributes nothing (never throws), and
|
|
27
|
+
* only valid levels survive. Keys come back normalized.
|
|
28
|
+
*
|
|
29
|
+
* @param json The stored setting value, or `undefined`/`null`/blank when there is none.
|
|
30
|
+
*/
|
|
31
|
+
export function ParseExposurePreferences(json) {
|
|
32
|
+
const result = new Map();
|
|
33
|
+
if (typeof json !== 'string' || json.trim().length === 0) {
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = JSON.parse(json);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
47
|
+
const id = NormalizeChannelKey(key);
|
|
48
|
+
if (id.length > 0 && IsExposureLevel(value)) {
|
|
49
|
+
result.set(id, value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Serializes choices for persistence. Only the choices themselves are stored (`{"whiteboard":"state"}`):
|
|
56
|
+
* a channel the user never touched has no entry, so a later change to a channel's default is not
|
|
57
|
+
* frozen in by an old write.
|
|
58
|
+
*/
|
|
59
|
+
export function SerializeExposurePreferences(preferences) {
|
|
60
|
+
const record = {};
|
|
61
|
+
for (const [key, level] of preferences) {
|
|
62
|
+
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
record[key] = level;
|
|
66
|
+
}
|
|
67
|
+
return JSON.stringify(record);
|
|
68
|
+
}
|
|
69
|
+
/** The default store: choices last for this object's lifetime only. */
|
|
70
|
+
export class InMemoryChannelExposurePreferences {
|
|
71
|
+
constructor() {
|
|
72
|
+
this.values = new Map();
|
|
73
|
+
}
|
|
74
|
+
Get(channelKey) {
|
|
75
|
+
return this.values.get(NormalizeChannelKey(channelKey));
|
|
76
|
+
}
|
|
77
|
+
Set(channelKey, level) {
|
|
78
|
+
const id = NormalizeChannelKey(channelKey);
|
|
79
|
+
if (level === undefined) {
|
|
80
|
+
this.values.delete(id);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.values.set(id, level);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The default store: persisted in the signed-in user's settings (`MJ: User Settings`, key
|
|
89
|
+
* {@link VISUAL_PERCEPTION_SETTING_KEY}) via `UserInfoEngine`, so the choice follows the person across
|
|
90
|
+
* devices; kept in memory when there is no user to persist for (an anonymous principal, a connect-only embed).
|
|
91
|
+
*
|
|
92
|
+
* Writes always go to memory first, so a choice takes effect and is read back even if persisting it
|
|
93
|
+
* fails or is not possible. Reads prefer the persisted value when persistence is available, since
|
|
94
|
+
* `UserInfoEngine.GetSetting` is a synchronous cache hit that already reflects a pending debounced write.
|
|
95
|
+
*/
|
|
96
|
+
export class UserSettingsExposurePreferences {
|
|
97
|
+
/** @param canPersist Whether user settings can be read and written right now (a signed-in user on a metadata-bearing provider). */
|
|
98
|
+
constructor(canPersist) {
|
|
99
|
+
this.canPersist = canPersist;
|
|
100
|
+
this.memory = new InMemoryChannelExposurePreferences();
|
|
101
|
+
this.warnedAboutRead = false;
|
|
102
|
+
}
|
|
103
|
+
Get(channelKey) {
|
|
104
|
+
if (!this.canPersist()) {
|
|
105
|
+
return this.memory.Get(channelKey);
|
|
106
|
+
}
|
|
107
|
+
return this.readPersisted().get(NormalizeChannelKey(channelKey)) ?? this.memory.Get(channelKey);
|
|
108
|
+
}
|
|
109
|
+
Set(channelKey, level) {
|
|
110
|
+
this.memory.Set(channelKey, level);
|
|
111
|
+
if (!this.canPersist()) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const persisted = this.readPersisted();
|
|
115
|
+
const id = NormalizeChannelKey(channelKey);
|
|
116
|
+
if (level === undefined) {
|
|
117
|
+
persisted.delete(id);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
persisted.set(id, level);
|
|
121
|
+
}
|
|
122
|
+
UserInfoEngine.Instance.SetSettingDebounced(VISUAL_PERCEPTION_SETTING_KEY, SerializeExposurePreferences(persisted));
|
|
123
|
+
}
|
|
124
|
+
/** The persisted choices; empty (and logged once) when the settings cache cannot be read. */
|
|
125
|
+
readPersisted() {
|
|
126
|
+
try {
|
|
127
|
+
return ParseExposurePreferences(UserInfoEngine.Instance.GetSetting(VISUAL_PERCEPTION_SETTING_KEY));
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (!this.warnedAboutRead) {
|
|
131
|
+
this.warnedAboutRead = true;
|
|
132
|
+
console.warn('[RealtimeSession] Could not read the saved visual-perception choices; using this page\'s choices only:', error);
|
|
133
|
+
}
|
|
134
|
+
return new Map();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=channel-exposure-preferences.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channel-exposure-preferences.js","sourceRoot":"","sources":["../../src/session/channel-exposure-preferences.ts"],"names":[],"mappings":"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"}
|