@burdenoff/fe-libs 2026.1024.3 → 2026.1026.1
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/dist/shared/assistant/avatar/live/LiveAvatarMinutes.d.ts +24 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarMinutes.js +161 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarStage.js +95 -74
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.d.ts +6 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +195 -172
- package/dist/shared/assistant/avatar/live/avatarPorts.d.ts +9 -0
- package/dist/shared/assistant/avatar/live/avatarSessionClient.d.ts +77 -1
- package/dist/shared/assistant/avatar/live/avatarSessionClient.js +193 -72
- package/dist/shared/assistant/avatar/live/avatarTransport.d.ts +25 -3
- package/dist/shared/assistant/avatar/live/avatarTransport.js +29 -2
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +35 -4
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +136 -79
- package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +79 -3
- package/dist/shared/assistant/avatar/live/liveAvatarController.js +424 -245
- package/dist/shared/assistant/avatar/live/liveAvatarMinutesView.d.ts +127 -0
- package/dist/shared/assistant/avatar/live/liveAvatarMinutesView.js +168 -0
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +3 -0
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +11 -7
- package/dist/shared/assistant/avatar/live/liveKitAvatarRoom.js +6 -1
- package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +127 -2
- package/dist/shared/assistant/avatar/useAvatarCopy.js +116 -7
- package/dist/shared/assistant/i18nManifest.d.ts +32 -1
- package/dist/shared/assistant/i18nManifest.js +55 -24
- package/dist/shared/assistant/index.d.ts +2 -0
- package/dist/shared/assistant/ui/AssistantChatArea.js +17 -17
- package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts +5 -2
- package/dist/shared/assistant/ui/assistantLiveAvatarSeam.d.ts +11 -3
- package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.js +78 -76
- package/dist/shared/assistant/ui/avatar/avatarAskGate.d.ts +2 -0
- package/dist/shared/assistant/ui/avatar/avatarAskGate.js +1 -0
- package/dist/shared/events/index.d.ts +2 -1
- package/dist/shared-assistant.js +227 -225
- package/package.json +1 -1
|
@@ -19,6 +19,63 @@ export type AvatarAvailabilityReason = (typeof AVAILABILITY_REASONS)[number];
|
|
|
19
19
|
*/
|
|
20
20
|
declare const BUDGET_SCOPES: readonly ["person", "workspace", "everyone"];
|
|
21
21
|
export type AvatarBudgetScope = (typeof BUDGET_SCOPES)[number];
|
|
22
|
+
/** BOFF-9446: the only `minutes.version` this client reads (contract v2). A block of any other version reads as no block. */
|
|
23
|
+
export declare const AVATAR_MINUTES_CONTRACT_VERSION = 2;
|
|
24
|
+
/** BOFF-9446: the states of an availability `minutes` block. Any other value reads as no block. */
|
|
25
|
+
export declare const AVATAR_MINUTES_STATES: readonly ["AVAILABLE", "IN_USE", "EXHAUSTED", "UNAVAILABLE"];
|
|
26
|
+
export type AvatarMinutesState = (typeof AVATAR_MINUTES_STATES)[number];
|
|
27
|
+
/**
|
|
28
|
+
* BOFF-9446: why no credits are left for this person. `FREE_CEILING`: their free credits for the month are used (plan credits would
|
|
29
|
+
* still work); `ZERO_SESSION_LIMIT`: too many sessions today that charged nothing (a 402 only, until the next UTC midnight; a plan does
|
|
30
|
+
* not lift it); `NOT_INCLUDED`: this workspace has no avatar credits at all; `OWN_SESSION`: the credits left are held by this person's
|
|
31
|
+
* own session on another device (a block's IN_USE only). Any other value reads as none.
|
|
32
|
+
*/
|
|
33
|
+
export declare const AVATAR_MINUTES_REASONS: readonly ["FREE_CEILING", "ZERO_SESSION_LIMIT", "NOT_INCLUDED", "OWN_SESSION"];
|
|
34
|
+
export type AvatarMinutesReason = (typeof AVATAR_MINUTES_REASONS)[number];
|
|
35
|
+
/**
|
|
36
|
+
* BOFF-9446: the balance of an AVAILABLE, IN_USE or EXHAUSTED block, the workspace's. Counts are whole credits (1 credit = 1 minute of
|
|
37
|
+
* avatar time), 0 or more.
|
|
38
|
+
*/
|
|
39
|
+
export interface AvatarMinutesBalance {
|
|
40
|
+
/** Credits left for this person now: carried, then free within their ceiling, then plan. */
|
|
41
|
+
readonly availableMinutes: number;
|
|
42
|
+
/** Reserved by open sessions in the workspace. */
|
|
43
|
+
readonly heldMinutes: number;
|
|
44
|
+
/** The workspace's free credits each month; 0 without a free allowance. */
|
|
45
|
+
readonly freeMinutesPerMonth: number;
|
|
46
|
+
/** The workspace's free credits left this month, before the person's ceiling. */
|
|
47
|
+
readonly freeRemaining: number;
|
|
48
|
+
/** The credits the workspace's counted plans give each month, summed. */
|
|
49
|
+
readonly planMinutesPerMonth: number;
|
|
50
|
+
readonly planRemaining: number;
|
|
51
|
+
/** Credits given back by a full-session credit, still unused. */
|
|
52
|
+
readonly carriedRemaining: number;
|
|
53
|
+
/** The free credits one person may use each month, across workspaces; null while billing has the ceiling off. */
|
|
54
|
+
readonly personFreeCeiling: number | null;
|
|
55
|
+
/** This person's free credits left this month; null while billing has the ceiling off. */
|
|
56
|
+
readonly personFreeRemaining: number | null;
|
|
57
|
+
/** When the free and plan credits reset (the next 1st, 00:00 UTC), as UTC epoch milliseconds: shown as a UTC date, never local. */
|
|
58
|
+
readonly resetsAt: number;
|
|
59
|
+
/** A plan with more avatar credits exists for this app: display only (it offers "See plans"), never an entitlement. */
|
|
60
|
+
readonly morePlanCreditsAvailable: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** BOFF-9446: the availability `minutes` block, as the client keeps it. */
|
|
63
|
+
export interface AvatarMinutes {
|
|
64
|
+
readonly state: AvatarMinutesState;
|
|
65
|
+
/** When the server gave one the client knows, where it may stand: OWN_SESSION with IN_USE, FREE_CEILING or NOT_INCLUDED with EXHAUSTED. */
|
|
66
|
+
readonly reason: AvatarMinutesReason | null;
|
|
67
|
+
/** With AVAILABLE, IN_USE and EXHAUSTED; null with UNAVAILABLE, which carries no numbers. */
|
|
68
|
+
readonly balance: AvatarMinutesBalance | null;
|
|
69
|
+
/** W, the seconds of the stale-presence margin the counting rules name (20 to 120); null when the answer had none in that range. */
|
|
70
|
+
readonly staleSeconds: number | null;
|
|
71
|
+
}
|
|
72
|
+
/** BOFF-9446: what a start answer says about the session's minutes (enforce only). */
|
|
73
|
+
export interface AvatarSessionMinutes {
|
|
74
|
+
/** The minutes reserved for this session, 1 or more. */
|
|
75
|
+
readonly reserved: number;
|
|
76
|
+
/** The session's length D' is shorter than the server's D: a session that reaches D' ends because its minutes ran out. */
|
|
77
|
+
readonly limitedByBalance: boolean;
|
|
78
|
+
}
|
|
22
79
|
export interface AvatarAvailability {
|
|
23
80
|
readonly available: boolean;
|
|
24
81
|
readonly reason: AvatarAvailabilityReason | null;
|
|
@@ -28,6 +85,8 @@ export interface AvatarAvailability {
|
|
|
28
85
|
readonly consentVersion: string;
|
|
29
86
|
/** The server's session cap, D. */
|
|
30
87
|
readonly maxSessionSeconds: number;
|
|
88
|
+
/** ★ BOFF-9446: the avatar-minutes block (enforce only). Absent when the answer had none, or none the client can read. */
|
|
89
|
+
readonly minutes?: AvatarMinutes;
|
|
31
90
|
}
|
|
32
91
|
export interface AvatarSessionStart {
|
|
33
92
|
readonly sessionId: string;
|
|
@@ -40,6 +99,10 @@ export interface AvatarSessionStart {
|
|
|
40
99
|
readonly connectBy: number;
|
|
41
100
|
/** Wall-clock milliseconds: the server's hard end (create + D - 5 s). */
|
|
42
101
|
readonly endsAt: number;
|
|
102
|
+
/** ★ BOFF-9446: D', this session's own length in seconds (enforce only): its hard end is create + D' - 5 s. */
|
|
103
|
+
readonly maxSessionSeconds?: number;
|
|
104
|
+
/** ★ BOFF-9446: the session's minutes (enforce only). */
|
|
105
|
+
readonly minutes?: AvatarSessionMinutes;
|
|
43
106
|
}
|
|
44
107
|
export type AvatarSessionState = 'starting' | 'ready' | 'ending' | 'ended' | 'failed' | 'canceled';
|
|
45
108
|
export interface AvatarSessionStatus {
|
|
@@ -58,11 +121,15 @@ export declare class AvatarApiError extends Error {
|
|
|
58
121
|
readonly retryAfterSeconds: number | null;
|
|
59
122
|
/** On `budget_exhausted` only, whose budget the body names when it is one of the three we know; null in every other answer. */
|
|
60
123
|
readonly scope: AvatarBudgetScope | null;
|
|
124
|
+
/** ★ BOFF-9446: on `minutes_exhausted` only, the body's reason when the client knows it; null otherwise. */
|
|
125
|
+
readonly minutesReason: AvatarMinutesReason | null;
|
|
61
126
|
constructor(status: number,
|
|
62
127
|
/** The server's or the gateway's code, `invalid_response` for a body we refused, `network` for no answer. */
|
|
63
128
|
code: string, retryAfterSeconds: number | null,
|
|
64
129
|
/** On `budget_exhausted` only, whose budget the body names when it is one of the three we know; null in every other answer. */
|
|
65
|
-
scope?: AvatarBudgetScope | null
|
|
130
|
+
scope?: AvatarBudgetScope | null,
|
|
131
|
+
/** ★ BOFF-9446: on `minutes_exhausted` only, the body's reason when the client knows it; null otherwise. */
|
|
132
|
+
minutesReason?: AvatarMinutesReason | null);
|
|
66
133
|
}
|
|
67
134
|
export interface AvatarSessionClientOptions {
|
|
68
135
|
/** `https://<gateway>/api/avatar/v1` (avatarApiBaseFromTtsEndpoint). */
|
|
@@ -120,6 +187,8 @@ export interface AvatarRefusal {
|
|
|
120
187
|
* Absent when it named none (today's server) and with every other refusal: the person is then told the general line.
|
|
121
188
|
*/
|
|
122
189
|
readonly scope?: AvatarBudgetScope;
|
|
190
|
+
/** ★ BOFF-9446: with `minutes-exhausted`, the reason the server gave, when the client knows it. Absent otherwise. */
|
|
191
|
+
readonly minutesReason?: AvatarMinutesReason;
|
|
123
192
|
}
|
|
124
193
|
/**
|
|
125
194
|
* The person's side of every failure (§3.4): the normal voice always continues; this says what to show. 404 means "not here" (the module
|
|
@@ -132,4 +201,11 @@ export declare function avatarRefusalFor(error: unknown): AvatarRefusal;
|
|
|
132
201
|
* enabled, not permitted), or only not now when the gateway could not check the permission (`unavailable`): the toggle stays.
|
|
133
202
|
*/
|
|
134
203
|
export declare function avatarAvailabilityRefusal(reason: AvatarAvailabilityReason | null): AvatarRefusal;
|
|
204
|
+
/**
|
|
205
|
+
* ★ BOFF-9446: what a minutes block means for a start, as the server's create would answer it: EXHAUSTED and IN_USE cannot start a
|
|
206
|
+
* session, so the person is told why instead of sending a create that would be refused (and, for IN_USE with OWN_SESSION, that would
|
|
207
|
+
* meet the person's own session on another device). AVAILABLE can, and UNAVAILABLE stays startable as the retry (the server decides).
|
|
208
|
+
* No block, today's answers: nothing in the way. Never a reason to hide, and no time (an availability answer carries no Retry-After).
|
|
209
|
+
*/
|
|
210
|
+
export declare function avatarMinutesRefusal(minutes: AvatarMinutes | null | undefined): AvatarRefusal | null;
|
|
135
211
|
export {};
|
|
@@ -23,16 +23,34 @@ var o = [
|
|
|
23
23
|
"person",
|
|
24
24
|
"workspace",
|
|
25
25
|
"everyone"
|
|
26
|
-
], c =
|
|
26
|
+
], c = 2, l = [
|
|
27
|
+
"AVAILABLE",
|
|
28
|
+
"IN_USE",
|
|
29
|
+
"EXHAUSTED",
|
|
30
|
+
"UNAVAILABLE"
|
|
31
|
+
], u = [
|
|
32
|
+
"FREE_CEILING",
|
|
33
|
+
"ZERO_SESSION_LIMIT",
|
|
34
|
+
"NOT_INCLUDED",
|
|
35
|
+
"OWN_SESSION"
|
|
36
|
+
], d = {
|
|
37
|
+
IN_USE: ["OWN_SESSION"],
|
|
38
|
+
EXHAUSTED: ["FREE_CEILING", "NOT_INCLUDED"]
|
|
39
|
+
}, f = [
|
|
40
|
+
"FREE_CEILING",
|
|
41
|
+
"ZERO_SESSION_LIMIT",
|
|
42
|
+
"NOT_INCLUDED"
|
|
43
|
+
], p = class extends Error {
|
|
27
44
|
status;
|
|
28
45
|
code;
|
|
29
46
|
retryAfterSeconds;
|
|
30
47
|
scope;
|
|
31
|
-
|
|
32
|
-
|
|
48
|
+
minutesReason;
|
|
49
|
+
constructor(e, t, n, r = null, i = null) {
|
|
50
|
+
super(`avatar api ${e} ${t}`), this.status = e, this.code = t, this.retryAfterSeconds = n, this.scope = r, this.minutesReason = i, this.name = "AvatarApiError";
|
|
33
51
|
}
|
|
34
52
|
};
|
|
35
|
-
function
|
|
53
|
+
function m(e = globalThis.crypto) {
|
|
36
54
|
if (e && typeof e.randomUUID == "function") return e.randomUUID();
|
|
37
55
|
let t = new Uint8Array(16);
|
|
38
56
|
if (e && typeof e.getRandomValues == "function") e.getRandomValues(t);
|
|
@@ -41,43 +59,96 @@ function l(e = globalThis.crypto) {
|
|
|
41
59
|
let n = [...t].map((e) => e.toString(16).padStart(2, "0")).join("");
|
|
42
60
|
return `${n.slice(0, 8)}-${n.slice(8, 12)}-${n.slice(12, 16)}-${n.slice(16, 20)}-${n.slice(20)}`;
|
|
43
61
|
}
|
|
44
|
-
function
|
|
62
|
+
function h(e) {
|
|
45
63
|
return typeof e == "object" && !!e && !Array.isArray(e);
|
|
46
64
|
}
|
|
47
|
-
function
|
|
65
|
+
function g(e, t) {
|
|
48
66
|
let n = e.headers.get("retry-after"), r = n === null || n.trim() === "" ? NaN : Number(n);
|
|
49
67
|
if (Number.isFinite(r) && r >= 0) return r;
|
|
50
|
-
let i =
|
|
68
|
+
let i = h(t) && h(t.error) ? Number(t.error.retryAfterSeconds) : NaN;
|
|
51
69
|
return Number.isFinite(i) && i >= 0 ? i : null;
|
|
52
70
|
}
|
|
53
|
-
async function
|
|
71
|
+
async function _(e) {
|
|
54
72
|
try {
|
|
55
73
|
return await e.json();
|
|
56
74
|
} catch {
|
|
57
75
|
return null;
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
|
-
function
|
|
61
|
-
if (e !== "budget_exhausted" || !
|
|
78
|
+
function v(e, t) {
|
|
79
|
+
if (e !== "budget_exhausted" || !h(t) || !h(t.error)) return null;
|
|
62
80
|
let { scope: n } = t.error;
|
|
63
81
|
return s.find((e) => e === n) ?? null;
|
|
64
82
|
}
|
|
65
|
-
async function
|
|
66
|
-
let t = await
|
|
67
|
-
return new
|
|
83
|
+
async function y(e) {
|
|
84
|
+
let t = await _(e), n = h(t) && h(t.error) && typeof t.error.code == "string" ? t.error.code : "http_error", r = n === "minutes_exhausted" && h(t) && h(t.error) ? b(t.error.reason, f) : null;
|
|
85
|
+
return new p(e.status, n, g(e, t), v(n, t), r);
|
|
68
86
|
}
|
|
69
|
-
function
|
|
70
|
-
|
|
71
|
-
|
|
87
|
+
function b(e, t) {
|
|
88
|
+
return t.find((t) => t === e) ?? null;
|
|
89
|
+
}
|
|
90
|
+
function x(e) {
|
|
91
|
+
return typeof e == "number" && Number.isSafeInteger(e) && e >= 0 ? e : null;
|
|
92
|
+
}
|
|
93
|
+
function S(e) {
|
|
94
|
+
return e === null ? null : x(e) ?? void 0;
|
|
95
|
+
}
|
|
96
|
+
function C(e) {
|
|
97
|
+
if (typeof e != "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(e)) return null;
|
|
98
|
+
let t = Date.parse(e);
|
|
99
|
+
return Number.isFinite(t) && new Date(t).toISOString() === e ? t : null;
|
|
100
|
+
}
|
|
101
|
+
function w(e) {
|
|
102
|
+
let t = x(e.availableMinutes), n = x(e.heldMinutes), r = x(e.freeMinutesPerMonth), i = x(e.freeRemaining), a = x(e.planMinutesPerMonth), o = x(e.planRemaining), s = x(e.carriedRemaining), c = S(e.personFreeCeiling), l = S(e.personFreeRemaining), u = C(e.resetsAt), { morePlanCreditsAvailable: d } = e;
|
|
103
|
+
return t === null || n === null || r === null || i === null || a === null || o === null || s === null || c === void 0 || l === void 0 || u === null || typeof d != "boolean" ? null : {
|
|
104
|
+
availableMinutes: t,
|
|
105
|
+
heldMinutes: n,
|
|
106
|
+
freeMinutesPerMonth: r,
|
|
107
|
+
freeRemaining: i,
|
|
108
|
+
planMinutesPerMonth: a,
|
|
109
|
+
planRemaining: o,
|
|
110
|
+
carriedRemaining: s,
|
|
111
|
+
personFreeCeiling: c,
|
|
112
|
+
personFreeRemaining: l,
|
|
113
|
+
resetsAt: u,
|
|
114
|
+
morePlanCreditsAvailable: d
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function T(e) {
|
|
118
|
+
if (!h(e) || e.version !== 2) return null;
|
|
119
|
+
let t = l.find((t) => t === e.state);
|
|
120
|
+
if (t === void 0) return null;
|
|
121
|
+
let n = null;
|
|
122
|
+
if (t !== "UNAVAILABLE" && (n = w(e), n === null || (t === "AVAILABLE" ? n.availableMinutes < 1 : n.availableMinutes !== 0))) return null;
|
|
123
|
+
let r = e.staleSeconds;
|
|
124
|
+
return {
|
|
125
|
+
state: t,
|
|
126
|
+
reason: b(e.reason, d[t] ?? []),
|
|
127
|
+
balance: n,
|
|
128
|
+
staleSeconds: typeof r == "number" && Number.isSafeInteger(r) && r >= 20 && r <= 120 ? r : null
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function E(e) {
|
|
132
|
+
if (!h(e)) return null;
|
|
133
|
+
let t = x(e.reserved);
|
|
134
|
+
return t === null || t < 1 || typeof e.limitedByBalance != "boolean" ? null : {
|
|
135
|
+
reserved: t,
|
|
136
|
+
limitedByBalance: e.limitedByBalance
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function D(e) {
|
|
140
|
+
if (!h(e) || typeof e.available != "boolean") throw new p(200, "invalid_response", null);
|
|
141
|
+
let t = Array.isArray(e.avatars) ? e.avatars.flatMap((e) => h(e) && typeof e.id == "string" && r.test(e.id) ? [e.id] : []) : [], n = o.find((t) => t === e.reason) ?? null, i = typeof e.consentVersion == "string" ? e.consentVersion : "", a = typeof e.maxSessionSeconds == "number" && Number.isFinite(e.maxSessionSeconds) ? e.maxSessionSeconds : 0, s = e.available && t.length > 0 && i !== "" && a > 0, c = T(e.minutes);
|
|
72
142
|
return {
|
|
73
143
|
available: s,
|
|
74
144
|
reason: s ? null : n ?? "not_enabled",
|
|
75
145
|
avatars: t,
|
|
76
146
|
consentVersion: i,
|
|
77
|
-
maxSessionSeconds: a
|
|
147
|
+
maxSessionSeconds: a,
|
|
148
|
+
...c === null ? {} : { minutes: c }
|
|
78
149
|
};
|
|
79
150
|
}
|
|
80
|
-
function
|
|
151
|
+
function O(e) {
|
|
81
152
|
try {
|
|
82
153
|
let n = new URL(e);
|
|
83
154
|
return n.protocol === "wss:" ? !0 : n.protocol === "ws:" && t.has(n.hostname.toLowerCase());
|
|
@@ -85,20 +156,23 @@ function g(e) {
|
|
|
85
156
|
return !1;
|
|
86
157
|
}
|
|
87
158
|
}
|
|
88
|
-
function
|
|
89
|
-
if (!
|
|
90
|
-
let { sessionId: t, livekitUrl: r, participantToken: i, avatarIdentity: a, connectBy: o, endsAt: s } = e,
|
|
91
|
-
if (typeof t != "string" || !n.test(t) || typeof r != "string" || !
|
|
159
|
+
function k(e) {
|
|
160
|
+
if (!h(e)) throw new p(201, "invalid_response", null);
|
|
161
|
+
let { sessionId: t, livekitUrl: r, participantToken: i, avatarIdentity: a, connectBy: o, endsAt: s } = e, c = typeof o == "string" ? Date.parse(o) : NaN, l = typeof s == "string" ? Date.parse(s) : NaN;
|
|
162
|
+
if (typeof t != "string" || !n.test(t) || typeof r != "string" || !O(r) || typeof i != "string" || i === "" || typeof a != "string" || a === "" || !Number.isFinite(c) || !Number.isFinite(l)) throw new p(201, "invalid_response", null);
|
|
163
|
+
let { maxSessionSeconds: u } = e, d = typeof u == "number" && Number.isSafeInteger(u) && u > 0 ? u : null, f = E(e.minutes);
|
|
92
164
|
return {
|
|
93
165
|
sessionId: t,
|
|
94
166
|
livekitUrl: r,
|
|
95
167
|
participantToken: i,
|
|
96
168
|
avatarIdentity: a,
|
|
97
|
-
connectBy:
|
|
98
|
-
endsAt:
|
|
169
|
+
connectBy: c,
|
|
170
|
+
endsAt: l,
|
|
171
|
+
...d === null ? {} : { maxSessionSeconds: d },
|
|
172
|
+
...f === null ? {} : { minutes: f }
|
|
99
173
|
};
|
|
100
174
|
}
|
|
101
|
-
var
|
|
175
|
+
var A = [
|
|
102
176
|
"starting",
|
|
103
177
|
"ready",
|
|
104
178
|
"ending",
|
|
@@ -106,22 +180,22 @@ var v = [
|
|
|
106
180
|
"failed",
|
|
107
181
|
"canceled"
|
|
108
182
|
];
|
|
109
|
-
function
|
|
110
|
-
if (!
|
|
183
|
+
function j(e, t) {
|
|
184
|
+
if (!h(e) || !A.includes(e.state)) throw new p(200, "invalid_response", null);
|
|
111
185
|
return {
|
|
112
186
|
sessionId: t,
|
|
113
187
|
state: e.state,
|
|
114
188
|
endedReason: typeof e.endedReason == "string" ? e.endedReason : null
|
|
115
189
|
};
|
|
116
190
|
}
|
|
117
|
-
var
|
|
191
|
+
var M = (e) => new Promise((t) => {
|
|
118
192
|
setTimeout(t, e);
|
|
119
193
|
});
|
|
120
|
-
function
|
|
121
|
-
let t = e.fetchImpl ?? ((e, t) => fetch(e, t)), a = e.sleep ??
|
|
122
|
-
async function
|
|
194
|
+
function N(e) {
|
|
195
|
+
let t = e.fetchImpl ?? ((e, t) => fetch(e, t)), a = e.sleep ?? M, o = e.now ?? (() => Date.now()), s = e.startInProgressBudgetMs ?? 15e3, c = e.baseUrl.replace(/\/+$/, "");
|
|
196
|
+
async function l(t, n = null) {
|
|
123
197
|
let r = e.getAuthorization();
|
|
124
|
-
if (!r) throw new
|
|
198
|
+
if (!r) throw new p(401, "unauthenticated", null);
|
|
125
199
|
let i = { authorization: r };
|
|
126
200
|
if (t) {
|
|
127
201
|
let t = await e.getWorkspaceAuthorization(n === null ? { fresh: !1 } : {
|
|
@@ -133,7 +207,7 @@ function x(e) {
|
|
|
133
207
|
}
|
|
134
208
|
return i;
|
|
135
209
|
}
|
|
136
|
-
async function
|
|
210
|
+
async function u(e, n) {
|
|
137
211
|
try {
|
|
138
212
|
return await t(e, {
|
|
139
213
|
...n,
|
|
@@ -142,20 +216,20 @@ function x(e) {
|
|
|
142
216
|
redirect: "error"
|
|
143
217
|
});
|
|
144
218
|
} catch (e) {
|
|
145
|
-
throw n.signal?.aborted ? e : new
|
|
219
|
+
throw n.signal?.aborted ? e : new p(0, "network", null);
|
|
146
220
|
}
|
|
147
221
|
}
|
|
148
222
|
return {
|
|
149
223
|
async availability(e) {
|
|
150
224
|
let t = null;
|
|
151
225
|
for (;;) {
|
|
152
|
-
let n = await
|
|
226
|
+
let n = await l(!0, t), r = await u(`${c}/availability`, {
|
|
153
227
|
method: "GET",
|
|
154
228
|
headers: n,
|
|
155
229
|
signal: e
|
|
156
230
|
});
|
|
157
|
-
if (r.ok) return
|
|
158
|
-
let i = await
|
|
231
|
+
if (r.ok) return D(await _(r));
|
|
232
|
+
let i = await y(r);
|
|
159
233
|
if (r.status === 401 && t === null) {
|
|
160
234
|
t = {
|
|
161
235
|
error: i,
|
|
@@ -167,16 +241,16 @@ function x(e) {
|
|
|
167
241
|
}
|
|
168
242
|
},
|
|
169
243
|
async create(e, t) {
|
|
170
|
-
if (!r.test(e.avatarId) || !i.test(e.idempotencyKey)) throw new
|
|
244
|
+
if (!r.test(e.avatarId) || !i.test(e.idempotencyKey)) throw new p(400, "invalid_request", null);
|
|
171
245
|
let n = JSON.stringify({
|
|
172
246
|
avatarId: e.avatarId,
|
|
173
247
|
consentVersion: e.consentVersion
|
|
174
|
-
}),
|
|
248
|
+
}), d = o(), f = null, m = !1, h = !1, g = null;
|
|
175
249
|
for (;;) {
|
|
176
|
-
let r = await
|
|
177
|
-
if (
|
|
178
|
-
if (r["x-workspace-authorization"] === void 0) throw new
|
|
179
|
-
let i = await
|
|
250
|
+
let r = await l(!0, f);
|
|
251
|
+
if (f = null, g !== null && o() - d > s) throw g;
|
|
252
|
+
if (r["x-workspace-authorization"] === void 0) throw new p(403, "workspace_context_required", null);
|
|
253
|
+
let i = await u(`${c}/sessions`, {
|
|
180
254
|
method: "POST",
|
|
181
255
|
headers: {
|
|
182
256
|
...r,
|
|
@@ -186,41 +260,41 @@ function x(e) {
|
|
|
186
260
|
body: n,
|
|
187
261
|
signal: t
|
|
188
262
|
});
|
|
189
|
-
if (i.status === 201) return
|
|
190
|
-
let
|
|
191
|
-
if (i.status === 401 && !
|
|
192
|
-
|
|
193
|
-
error:
|
|
263
|
+
if (i.status === 201) return k(await _(i));
|
|
264
|
+
let v = await y(i);
|
|
265
|
+
if (i.status === 401 && !m) {
|
|
266
|
+
m = !0, f = {
|
|
267
|
+
error: v,
|
|
194
268
|
workspace: r["x-workspace-authorization"]
|
|
195
269
|
};
|
|
196
270
|
continue;
|
|
197
271
|
}
|
|
198
|
-
if (i.status === 409 &&
|
|
199
|
-
let e = Math.max(250, (
|
|
200
|
-
if (o() -
|
|
201
|
-
|
|
272
|
+
if (i.status === 409 && v.code === "start_in_progress") {
|
|
273
|
+
let e = Math.max(250, (v.retryAfterSeconds ?? 1) * 1e3);
|
|
274
|
+
if (o() - d + e > s || (await a(e), t?.aborted)) throw v;
|
|
275
|
+
g = v;
|
|
202
276
|
continue;
|
|
203
277
|
}
|
|
204
|
-
if (i.status === 502 && !
|
|
205
|
-
|
|
278
|
+
if (i.status === 502 && !h) {
|
|
279
|
+
h = !0;
|
|
206
280
|
continue;
|
|
207
281
|
}
|
|
208
|
-
throw
|
|
282
|
+
throw v;
|
|
209
283
|
}
|
|
210
284
|
},
|
|
211
285
|
async status(e, t) {
|
|
212
|
-
if (!n.test(e)) throw new
|
|
213
|
-
let r = await
|
|
286
|
+
if (!n.test(e)) throw new p(400, "invalid_request", null);
|
|
287
|
+
let r = await l(!1), i = await u(`${c}/sessions/${e}`, {
|
|
214
288
|
method: "GET",
|
|
215
289
|
headers: r,
|
|
216
290
|
signal: t
|
|
217
291
|
});
|
|
218
|
-
if (!i.ok) throw await
|
|
219
|
-
return
|
|
292
|
+
if (!i.ok) throw await y(i);
|
|
293
|
+
return j(await _(i), e);
|
|
220
294
|
},
|
|
221
295
|
async end(e, { reason: t, keepalive: r = !1 }) {
|
|
222
|
-
if (!n.test(e)) throw new
|
|
223
|
-
let i = await
|
|
296
|
+
if (!n.test(e)) throw new p(400, "invalid_request", null);
|
|
297
|
+
let i = await l(!1), a = await u(`${c}/sessions/${e}/end`, {
|
|
224
298
|
method: "POST",
|
|
225
299
|
headers: {
|
|
226
300
|
...i,
|
|
@@ -229,28 +303,34 @@ function x(e) {
|
|
|
229
303
|
body: JSON.stringify({ reason: t }),
|
|
230
304
|
keepalive: r
|
|
231
305
|
});
|
|
232
|
-
if (!a.ok) throw await
|
|
233
|
-
return
|
|
306
|
+
if (!a.ok) throw await y(a);
|
|
307
|
+
return j(await _(a), e);
|
|
234
308
|
}
|
|
235
309
|
};
|
|
236
310
|
}
|
|
237
|
-
var
|
|
311
|
+
var P = new Set([
|
|
238
312
|
"capacity",
|
|
239
313
|
"rate-limited",
|
|
240
|
-
"budget-exhausted"
|
|
314
|
+
"budget-exhausted",
|
|
315
|
+
"minutes-in-use",
|
|
316
|
+
"minutes-in-use-self",
|
|
317
|
+
"minutes-unavailable"
|
|
241
318
|
]);
|
|
242
|
-
function
|
|
243
|
-
|
|
319
|
+
function F(e) {
|
|
320
|
+
return e.problem === null ? !1 : P.has(e.problem) ? !0 : e.problem === "minutes-exhausted" && e.minutesReason === "ZERO_SESSION_LIMIT";
|
|
321
|
+
}
|
|
322
|
+
function I(e) {
|
|
323
|
+
if (!(e instanceof p)) return {
|
|
244
324
|
problem: "connection",
|
|
245
325
|
hide: !1
|
|
246
326
|
};
|
|
247
|
-
let t =
|
|
248
|
-
return
|
|
327
|
+
let t = L(e);
|
|
328
|
+
return F(t) && e.retryAfterSeconds !== null ? {
|
|
249
329
|
...t,
|
|
250
330
|
retryAfterSeconds: e.retryAfterSeconds
|
|
251
331
|
} : t;
|
|
252
332
|
}
|
|
253
|
-
function
|
|
333
|
+
function L(e) {
|
|
254
334
|
if (e.status === 0) return {
|
|
255
335
|
problem: "connection",
|
|
256
336
|
hide: !1
|
|
@@ -312,6 +392,26 @@ function w(e) {
|
|
|
312
392
|
hide: !1,
|
|
313
393
|
scope: e.scope
|
|
314
394
|
};
|
|
395
|
+
case "minutes_exhausted": return e.minutesReason === null ? {
|
|
396
|
+
problem: "minutes-exhausted",
|
|
397
|
+
hide: !1
|
|
398
|
+
} : {
|
|
399
|
+
problem: "minutes-exhausted",
|
|
400
|
+
hide: !1,
|
|
401
|
+
minutesReason: e.minutesReason
|
|
402
|
+
};
|
|
403
|
+
case "minutes_in_use": return {
|
|
404
|
+
problem: "minutes-in-use",
|
|
405
|
+
hide: !1
|
|
406
|
+
};
|
|
407
|
+
case "minutes_in_use_self": return {
|
|
408
|
+
problem: "minutes-in-use-self",
|
|
409
|
+
hide: !1
|
|
410
|
+
};
|
|
411
|
+
case "minutes_unavailable": return {
|
|
412
|
+
problem: "minutes-unavailable",
|
|
413
|
+
hide: !1
|
|
414
|
+
};
|
|
315
415
|
case "avatar_unavailable": return {
|
|
316
416
|
problem: "unavailable",
|
|
317
417
|
hide: !1
|
|
@@ -345,7 +445,7 @@ function w(e) {
|
|
|
345
445
|
};
|
|
346
446
|
}
|
|
347
447
|
}
|
|
348
|
-
function
|
|
448
|
+
function R(e) {
|
|
349
449
|
return e === "unavailable" ? {
|
|
350
450
|
problem: "capacity",
|
|
351
451
|
hide: !1
|
|
@@ -354,5 +454,26 @@ function T(e) {
|
|
|
354
454
|
hide: !0
|
|
355
455
|
};
|
|
356
456
|
}
|
|
457
|
+
function z(e) {
|
|
458
|
+
if (e == null) return null;
|
|
459
|
+
switch (e.state) {
|
|
460
|
+
case "EXHAUSTED": return e.reason === null ? {
|
|
461
|
+
problem: "minutes-exhausted",
|
|
462
|
+
hide: !1
|
|
463
|
+
} : {
|
|
464
|
+
problem: "minutes-exhausted",
|
|
465
|
+
hide: !1,
|
|
466
|
+
minutesReason: e.reason
|
|
467
|
+
};
|
|
468
|
+
case "IN_USE": return e.reason === "OWN_SESSION" ? {
|
|
469
|
+
problem: "minutes-in-use-self",
|
|
470
|
+
hide: !1
|
|
471
|
+
} : {
|
|
472
|
+
problem: "minutes-in-use",
|
|
473
|
+
hide: !1
|
|
474
|
+
};
|
|
475
|
+
default: return null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
357
478
|
//#endregion
|
|
358
|
-
export { e as AVATAR_API_PATH, c as AvatarApiError, a as avatarApiBaseFromTtsEndpoint,
|
|
479
|
+
export { e as AVATAR_API_PATH, c as AVATAR_MINUTES_CONTRACT_VERSION, u as AVATAR_MINUTES_REASONS, l as AVATAR_MINUTES_STATES, p as AvatarApiError, a as avatarApiBaseFromTtsEndpoint, R as avatarAvailabilityRefusal, m as avatarIdempotencyKey, z as avatarMinutesRefusal, I as avatarRefusalFor, N as createAvatarSessionClient };
|
|
@@ -51,6 +51,11 @@ export type AvatarTransportEvent = {
|
|
|
51
51
|
readonly type: 'audioPlayback';
|
|
52
52
|
readonly canPlay: boolean;
|
|
53
53
|
}
|
|
54
|
+
/** ★ BOFF-9696: the browser refused (or allowed again) the avatar's video, e.g. iOS in Low Power Mode until a user gesture. */
|
|
55
|
+
| {
|
|
56
|
+
readonly type: 'videoPlayback';
|
|
57
|
+
readonly canPlay: boolean;
|
|
58
|
+
}
|
|
54
59
|
/** Result of the readiness probe at connect (see AvatarReadinessProbeOptions). */
|
|
55
60
|
| {
|
|
56
61
|
readonly type: 'readiness';
|
|
@@ -168,6 +173,8 @@ export declare class LiveKitAvatarTransport {
|
|
|
168
173
|
private videoPresent;
|
|
169
174
|
private degraded;
|
|
170
175
|
private audioElement;
|
|
176
|
+
/** ★ BOFF-9696 (S1): the browser paused the avatar's audio element on its own (see watchAudioElement). */
|
|
177
|
+
private elementPaused;
|
|
171
178
|
private disposed;
|
|
172
179
|
private rejectReady;
|
|
173
180
|
private mediaReady;
|
|
@@ -218,15 +225,30 @@ export declare class LiveKitAvatarTransport {
|
|
|
218
225
|
get transportState(): AvatarTransportState;
|
|
219
226
|
/** The readiness probe's result once connect() has resolved; null before. */
|
|
220
227
|
get readiness(): AvatarReadinessStatus | null;
|
|
221
|
-
/**
|
|
228
|
+
/**
|
|
229
|
+
* True while the browser blocks the avatar's audio: by autoplay policy, or by pausing its element on its own (an interruption, the lock
|
|
230
|
+
* screen). resumeAudio() from a user gesture is needed.
|
|
231
|
+
*/
|
|
222
232
|
get audioBlocked(): boolean;
|
|
233
|
+
/** ★ BOFF-9696: true while the browser refuses the avatar's video (resumeVideo() from a user gesture plays it). */
|
|
234
|
+
get videoBlocked(): boolean;
|
|
223
235
|
subscribe(handler: (event: AvatarTransportEvent) => void): AvatarUnsubscribe;
|
|
224
236
|
private emit;
|
|
225
237
|
/**
|
|
226
|
-
* Resume audio playback. Call it synchronously from
|
|
227
|
-
*
|
|
238
|
+
* Resume audio playback. Call it synchronously from a user gesture (the browser's autoplay policy requires one): today the
|
|
239
|
+
* "tap to enable sound" control (`controller.resumeAudio()`), shown when audioPlayback reports canPlay=false.
|
|
228
240
|
*/
|
|
229
241
|
resumeAudio(): Promise<void>;
|
|
242
|
+
/** ★ BOFF-9696: play a refused video. Call it synchronously from a user gesture, like resumeAudio(). */
|
|
243
|
+
resumeVideo(): Promise<void>;
|
|
244
|
+
/**
|
|
245
|
+
* ★ BOFF-9696 (S1): an element the browser PAUSED on its own while the avatar is on (an interruption such as a call or Siri, the lock
|
|
246
|
+
* screen, or WebKit pausing it when it is unmuted). The SDK only learns of a blocked playback from a failed play(), so without this the
|
|
247
|
+
* avatar would lip-sync with no voice and no way back. The pause reports the sound blocked; the existing tap (resumeAudio: the SDK's
|
|
248
|
+
* startAudio plays every attached element) plays it again, and its 'playing' reports it back. Only while ready and fed: a release
|
|
249
|
+
* (srcObject null) or a teardown is not a block.
|
|
250
|
+
*/
|
|
251
|
+
private watchAudioElement;
|
|
230
252
|
/** Mute or unmute the avatar's audio element instantly (used to silence output on cancel before the provider confirms). */
|
|
231
253
|
setOutputMuted(muted: boolean): void;
|
|
232
254
|
connect(params: AvatarConnectParams): Promise<void>;
|