@convai/web-sdk 1.8.0-beta.7 → 1.8.0
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 +44 -194
- package/dist/core/ConvaiClient.d.ts +1 -190
- package/dist/core/ConvaiClient.d.ts.map +1 -1
- package/dist/core/ConvaiClient.js +286 -1306
- package/dist/core/ConvaiClient.js.map +1 -1
- package/dist/core/MessageHandler.d.ts +1 -19
- package/dist/core/MessageHandler.d.ts.map +1 -1
- package/dist/core/MessageHandler.js +27 -378
- package/dist/core/MessageHandler.js.map +1 -1
- package/dist/core/connectRequest.d.ts +4 -17
- package/dist/core/connectRequest.d.ts.map +1 -1
- package/dist/core/connectRequest.js +17 -28
- package/dist/core/connectRequest.js.map +1 -1
- package/dist/core/index.d.ts +1 -6
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -7
- package/dist/core/index.js.map +1 -1
- package/dist/core/logicalTurn.d.ts +6 -4
- package/dist/core/logicalTurn.d.ts.map +1 -1
- package/dist/core/logicalTurn.js +4 -29
- package/dist/core/logicalTurn.js.map +1 -1
- package/dist/core/modelOutput.d.ts.map +1 -1
- package/dist/core/modelOutput.js +2 -2
- package/dist/core/modelOutput.js.map +1 -1
- package/dist/core/types.d.ts +22 -860
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/embed/chat-embed-v1.js +9 -10
- package/dist/embed/chat-embed-v1.js.map +4 -4
- package/dist/react/components/ConvaiWidget.d.ts.map +1 -1
- package/dist/react/components/ConvaiWidget.js +1 -6
- package/dist/react/components/ConvaiWidget.js.map +1 -1
- package/dist/react/components/rtc-widget/components/AudioVisualizer.d.ts.map +1 -1
- package/dist/react/components/rtc-widget/components/AudioVisualizer.js +1 -28
- package/dist/react/components/rtc-widget/components/AudioVisualizer.js.map +1 -1
- package/dist/react/components/rtc-widget/components/MarkdownRenderer.d.ts.map +1 -1
- package/dist/react/components/rtc-widget/components/MarkdownRenderer.js +44 -39
- package/dist/react/components/rtc-widget/components/MarkdownRenderer.js.map +1 -1
- package/dist/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.d.ts.map +1 -1
- package/dist/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.js +49 -93
- package/dist/react/components/rtc-widget/components/conviComponents/VoiceModeOverlay.js.map +1 -1
- package/dist/react/hooks/useConvaiClient.d.ts.map +1 -1
- package/dist/react/hooks/useConvaiClient.js +2 -17
- package/dist/react/hooks/useConvaiClient.js.map +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/vanilla/AudioRenderer.d.ts +1 -3
- package/dist/vanilla/AudioRenderer.d.ts.map +1 -1
- package/dist/vanilla/AudioRenderer.js +2 -8
- package/dist/vanilla/AudioRenderer.js.map +1 -1
- package/dist/vanilla/ConvaiWidget.d.ts.map +1 -1
- package/dist/vanilla/ConvaiWidget.js +300 -994
- package/dist/vanilla/ConvaiWidget.js.map +1 -1
- package/dist/vanilla/WidgetEventSubscriptions.d.ts +1 -1
- package/dist/vanilla/WidgetEventSubscriptions.d.ts.map +1 -1
- package/dist/vanilla/WidgetEventSubscriptions.js +0 -5
- package/dist/vanilla/WidgetEventSubscriptions.js.map +1 -1
- package/dist/vanilla/icons.d.ts.map +1 -1
- package/dist/vanilla/icons.js +15 -62
- package/dist/vanilla/icons.js.map +1 -1
- package/dist/vanilla/index.d.ts +2 -4
- package/dist/vanilla/index.d.ts.map +1 -1
- package/dist/vanilla/index.js +1 -3
- package/dist/vanilla/index.js.map +1 -1
- package/dist/vanilla/styles.d.ts +1 -18
- package/dist/vanilla/styles.d.ts.map +1 -1
- package/dist/vanilla/styles.js +29 -129
- package/dist/vanilla/styles.js.map +1 -1
- package/dist/vanilla/types.d.ts +0 -74
- package/dist/vanilla/types.d.ts.map +1 -1
- package/dist/vanilla/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +8 -13
- package/dist/core/CharacterRoster.d.ts +0 -84
- package/dist/core/CharacterRoster.d.ts.map +0 -1
- package/dist/core/CharacterRoster.js +0 -348
- package/dist/core/CharacterRoster.js.map +0 -1
- package/dist/core/CharacterVersionManager.d.ts +0 -100
- package/dist/core/CharacterVersionManager.d.ts.map +0 -1
- package/dist/core/CharacterVersionManager.js +0 -227
- package/dist/core/CharacterVersionManager.js.map +0 -1
- package/dist/core/ConvaiRoomError.d.ts +0 -48
- package/dist/core/ConvaiRoomError.d.ts.map +0 -1
- package/dist/core/ConvaiRoomError.js +0 -111
- package/dist/core/ConvaiRoomError.js.map +0 -1
- package/dist/core/SSESession.d.ts +0 -59
- package/dist/core/SSESession.d.ts.map +0 -1
- package/dist/core/SSESession.js +0 -289
- package/dist/core/SSESession.js.map +0 -1
- package/dist/core/characterReference.d.ts +0 -40
- package/dist/core/characterReference.d.ts.map +0 -1
- package/dist/core/characterReference.js +0 -72
- package/dist/core/characterReference.js.map +0 -1
- package/dist/core/rosterRequest.d.ts +0 -57
- package/dist/core/rosterRequest.d.ts.map +0 -1
- package/dist/core/rosterRequest.js +0 -210
- package/dist/core/rosterRequest.js.map +0 -1
- package/dist/utils/inlineMarkdown.d.ts +0 -38
- package/dist/utils/inlineMarkdown.d.ts.map +0 -1
- package/dist/utils/inlineMarkdown.js +0 -106
- package/dist/utils/inlineMarkdown.js.map +0 -1
|
@@ -1,348 +0,0 @@
|
|
|
1
|
-
const PROVISIONING_STATUSES = [
|
|
2
|
-
"dispatch_queued",
|
|
3
|
-
"dispatch_accepted",
|
|
4
|
-
"dispatch_failed",
|
|
5
|
-
];
|
|
6
|
-
/**
|
|
7
|
-
* Coerce a wire status into the closed union.
|
|
8
|
-
*
|
|
9
|
-
* An unrecognised value becomes `dispatch_queued`, the one state that promises
|
|
10
|
-
* nothing: it means "still working", so a client waits for `bot-ready` rather
|
|
11
|
-
* than acting. Mapping to `dispatch_accepted` would imply an actor exists, and
|
|
12
|
-
* to `dispatch_failed` would hide a member that is actually coming up.
|
|
13
|
-
*/
|
|
14
|
-
function toProvisioningStatus(value) {
|
|
15
|
-
return typeof value === "string" && PROVISIONING_STATUSES.includes(value)
|
|
16
|
-
? value
|
|
17
|
-
: "dispatch_queued";
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Convert a wire entry into an instance, or null when it cannot be attributed.
|
|
21
|
-
*
|
|
22
|
-
* A member with no `membership_id` is unaddressable: it cannot be targeted,
|
|
23
|
-
* removed, or matched to a participant. The contract's rule throughout is to
|
|
24
|
-
* fail closed rather than guess, so it is dropped instead of being given a
|
|
25
|
-
* synthesised id that would later collide.
|
|
26
|
-
*/
|
|
27
|
-
function toInstance(raw) {
|
|
28
|
-
if (!raw?.membership_id)
|
|
29
|
-
return null;
|
|
30
|
-
return {
|
|
31
|
-
membershipId: raw.membership_id,
|
|
32
|
-
characterId: raw.character_id ?? "",
|
|
33
|
-
sessionId: raw.session_id ?? null,
|
|
34
|
-
characterSessionId: raw.character_session_id ?? null,
|
|
35
|
-
// Identity is derivable and always `character:{membership_id}`. Falling
|
|
36
|
-
// back to it is safe; falling back to a positional name or a LiveKit SID
|
|
37
|
-
// would not be, so those are never used.
|
|
38
|
-
participantIdentity: raw.participant_identity || `character:${raw.membership_id}`,
|
|
39
|
-
isInitial: raw.is_initial === true,
|
|
40
|
-
provisioningStatus: toProvisioningStatus(raw.provisioning_status),
|
|
41
|
-
displayName: raw.display_name ?? null,
|
|
42
|
-
description: raw.description ?? null,
|
|
43
|
-
failureCode: raw.failure_code ?? null,
|
|
44
|
-
isReady: false,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
export class CharacterRoster {
|
|
48
|
-
constructor() {
|
|
49
|
-
this._characters = [];
|
|
50
|
-
this._activeMembershipId = null;
|
|
51
|
-
this._roomSessionId = null;
|
|
52
|
-
this._roomName = null;
|
|
53
|
-
this._requestTraceId = null;
|
|
54
|
-
this._routeEpoch = 0;
|
|
55
|
-
this._rosterEpoch = 0;
|
|
56
|
-
this._partialDispatch = false;
|
|
57
|
-
}
|
|
58
|
-
/** Character instances in roster order. Empty in single-character mode. */
|
|
59
|
-
get characters() {
|
|
60
|
-
return this._characters;
|
|
61
|
-
}
|
|
62
|
-
/** Membership currently receiving user turns, or null. */
|
|
63
|
-
get activeMembershipId() {
|
|
64
|
-
return this._activeMembershipId;
|
|
65
|
-
}
|
|
66
|
-
get roomSessionId() {
|
|
67
|
-
return this._roomSessionId;
|
|
68
|
-
}
|
|
69
|
-
get routeEpoch() {
|
|
70
|
-
return this._routeEpoch;
|
|
71
|
-
}
|
|
72
|
-
get rosterEpoch() {
|
|
73
|
-
return this._rosterEpoch;
|
|
74
|
-
}
|
|
75
|
-
/** True once a multi-character connect response has been applied. */
|
|
76
|
-
get isMultiCharacter() {
|
|
77
|
-
return this._characters.length > 0;
|
|
78
|
-
}
|
|
79
|
-
/** The server-owned snapshot, or null for a single-character session. */
|
|
80
|
-
get roomSession() {
|
|
81
|
-
if (!this._roomSessionId)
|
|
82
|
-
return null;
|
|
83
|
-
return {
|
|
84
|
-
roomSessionId: this._roomSessionId,
|
|
85
|
-
roomName: this._roomName,
|
|
86
|
-
requestTraceId: this._requestTraceId,
|
|
87
|
-
activeMembershipId: this._activeMembershipId,
|
|
88
|
-
routeEpoch: this._routeEpoch,
|
|
89
|
-
rosterEpoch: this._rosterEpoch,
|
|
90
|
-
partialDispatch: this._partialDispatch,
|
|
91
|
-
characters: this._characters,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
find(membershipId) {
|
|
95
|
-
return this._characters.find((c) => c.membershipId === membershipId);
|
|
96
|
-
}
|
|
97
|
-
/** Members that have sent their own `bot-ready`. */
|
|
98
|
-
get readyCharacters() {
|
|
99
|
-
return this._characters.filter((c) => c.isReady);
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Mark a member ready from its own `bot-ready`, filling in any detail the
|
|
103
|
-
* connect response did not yet have.
|
|
104
|
-
*
|
|
105
|
-
* Returns whether anything changed, so the caller only pushes state when it
|
|
106
|
-
* did. A single-character `bot-ready` also carries these fields, so nothing
|
|
107
|
-
* is tracked until a roster is actually seeded.
|
|
108
|
-
*/
|
|
109
|
-
applyBotReady(about) {
|
|
110
|
-
if (!about || !this.isMultiCharacter)
|
|
111
|
-
return false;
|
|
112
|
-
const incoming = toInstance(about);
|
|
113
|
-
if (!incoming)
|
|
114
|
-
return false;
|
|
115
|
-
const index = this._characters.findIndex((c) => c.membershipId === incoming.membershipId);
|
|
116
|
-
if (index === -1) {
|
|
117
|
-
// A member added at runtime announces itself this way.
|
|
118
|
-
this._characters = [...this._characters, { ...incoming, isReady: true }];
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
const existing = this._characters[index];
|
|
122
|
-
const merged = {
|
|
123
|
-
...existing,
|
|
124
|
-
characterSessionId: incoming.characterSessionId ?? existing.characterSessionId,
|
|
125
|
-
sessionId: incoming.sessionId ?? existing.sessionId,
|
|
126
|
-
displayName: incoming.displayName ?? existing.displayName,
|
|
127
|
-
participantIdentity: incoming.participantIdentity || existing.participantIdentity,
|
|
128
|
-
isReady: true,
|
|
129
|
-
};
|
|
130
|
-
if (existing.isReady &&
|
|
131
|
-
merged.characterSessionId === existing.characterSessionId &&
|
|
132
|
-
merged.sessionId === existing.sessionId &&
|
|
133
|
-
merged.participantIdentity === existing.participantIdentity) {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
this._characters = [
|
|
137
|
-
...this._characters.slice(0, index),
|
|
138
|
-
merged,
|
|
139
|
-
...this._characters.slice(index + 1),
|
|
140
|
-
];
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Apply a `character-status` transition. Readiness recorded here is
|
|
145
|
-
* bookkeeping for replacement selection; `bot-ready` remains what gates
|
|
146
|
-
* interaction.
|
|
147
|
-
*/
|
|
148
|
-
applyCharacterStatus(status) {
|
|
149
|
-
const index = this._characters.findIndex((c) => c.membershipId === status.membershipId);
|
|
150
|
-
if (index === -1)
|
|
151
|
-
return false;
|
|
152
|
-
const existing = this._characters[index];
|
|
153
|
-
const next = {
|
|
154
|
-
...existing,
|
|
155
|
-
...(status.status === "failed"
|
|
156
|
-
? {
|
|
157
|
-
provisioningStatus: "dispatch_failed",
|
|
158
|
-
failureCode: status.failureCode ?? existing.failureCode,
|
|
159
|
-
isReady: false,
|
|
160
|
-
}
|
|
161
|
-
: {}),
|
|
162
|
-
};
|
|
163
|
-
if (next.provisioningStatus === existing.provisioningStatus &&
|
|
164
|
-
next.failureCode === existing.failureCode &&
|
|
165
|
-
next.isReady === existing.isReady) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
this._characters = [
|
|
169
|
-
...this._characters.slice(0, index),
|
|
170
|
-
next,
|
|
171
|
-
...this._characters.slice(index + 1),
|
|
172
|
-
];
|
|
173
|
-
if (status.status === "failed")
|
|
174
|
-
this._partialDispatch = true;
|
|
175
|
-
return true;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Pick a member to take over routing when the active one is removed.
|
|
179
|
-
*
|
|
180
|
-
* The runtime refuses a replacement that has not sent `bot-ready`
|
|
181
|
-
* (`replacement_target_unavailable`), so ready survivors come first. Falling
|
|
182
|
-
* back to any survivor at least produces a nameable rejection rather than
|
|
183
|
-
* `replacement_target_required`.
|
|
184
|
-
*/
|
|
185
|
-
pickReplacement(removing) {
|
|
186
|
-
const removed = new Set(removing);
|
|
187
|
-
const survivors = this._characters.filter((c) => !removed.has(c.membershipId));
|
|
188
|
-
return (survivors.find((c) => c.isReady)?.membershipId ?? survivors[0]?.membershipId);
|
|
189
|
-
}
|
|
190
|
-
/** Payload that switches the active member. */
|
|
191
|
-
buildInteractionTarget(membershipId, commandId) {
|
|
192
|
-
return {
|
|
193
|
-
room_session_id: this._roomSessionId,
|
|
194
|
-
target_membership_id: membershipId,
|
|
195
|
-
expected_route_epoch: this._routeEpoch,
|
|
196
|
-
command_id: commandId,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
/** Payload that adds and removes members. */
|
|
200
|
-
buildRosterUpdate(options, commandId) {
|
|
201
|
-
const add = (options.add ?? []).map((spec) => ({
|
|
202
|
-
character_id: spec.characterId.trim(),
|
|
203
|
-
...(spec.characterSessionId
|
|
204
|
-
? { character_session_id: spec.characterSessionId }
|
|
205
|
-
: {}),
|
|
206
|
-
}));
|
|
207
|
-
return {
|
|
208
|
-
room_session_id: this._roomSessionId,
|
|
209
|
-
expected_roster_epoch: this._rosterEpoch,
|
|
210
|
-
command_id: commandId,
|
|
211
|
-
...(add.length > 0 && { add }),
|
|
212
|
-
...(options.remove?.length && { remove_membership_ids: options.remove }),
|
|
213
|
-
...(options.replacementTarget && {
|
|
214
|
-
replacement_target_membership_id: options.replacementTarget,
|
|
215
|
-
}),
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Adopt the server's authoritative epochs and active member from any
|
|
220
|
-
* response, errors included.
|
|
221
|
-
*
|
|
222
|
-
* A `stale_route_epoch` rejection carries the real epoch, and adopting it is
|
|
223
|
-
* precisely what makes the single retry meaningful rather than a repeat of
|
|
224
|
-
* the same losing bet.
|
|
225
|
-
*/
|
|
226
|
-
adoptEpochs(extras) {
|
|
227
|
-
if (!extras)
|
|
228
|
-
return;
|
|
229
|
-
if (typeof extras.route_epoch === "number")
|
|
230
|
-
this._routeEpoch = extras.route_epoch;
|
|
231
|
-
if (typeof extras.roster_epoch === "number")
|
|
232
|
-
this._rosterEpoch = extras.roster_epoch;
|
|
233
|
-
if (extras.active_membership_id !== undefined) {
|
|
234
|
-
this._activeMembershipId = extras.active_membership_id ?? null;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Apply a successful `interaction-target` ack. Returns the change even when
|
|
239
|
-
* the target did not move, so a caller awaiting the promise always learns the
|
|
240
|
-
* authoritative state.
|
|
241
|
-
*/
|
|
242
|
-
applyInteractionTarget(extras) {
|
|
243
|
-
const previous = extras?.previous_membership_id !== undefined
|
|
244
|
-
? extras.previous_membership_id
|
|
245
|
-
: this._activeMembershipId;
|
|
246
|
-
this.adoptEpochs(extras);
|
|
247
|
-
return {
|
|
248
|
-
previous: previous ?? null,
|
|
249
|
-
active: this._activeMembershipId,
|
|
250
|
-
routeEpoch: this._routeEpoch,
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/** Apply a successful `character-roster-update` ack, mutating the roster. */
|
|
254
|
-
applyRosterUpdate(extras) {
|
|
255
|
-
const added = (Array.isArray(extras?.added) ? extras.added : [])
|
|
256
|
-
.map((c) => toInstance(c))
|
|
257
|
-
.filter((c) => c !== null);
|
|
258
|
-
const removedIds = new Set(Array.isArray(extras?.removed_membership_ids)
|
|
259
|
-
? extras.removed_membership_ids
|
|
260
|
-
: []);
|
|
261
|
-
// Prefer the roster's own record of a removed member: the ack echoes only
|
|
262
|
-
// its id, and the caller wants the instance it had been rendering.
|
|
263
|
-
const removed = [...removedIds].map((id) => this.find(id) ?? {
|
|
264
|
-
membershipId: id,
|
|
265
|
-
characterId: "",
|
|
266
|
-
sessionId: null,
|
|
267
|
-
characterSessionId: null,
|
|
268
|
-
participantIdentity: `character:${id}`,
|
|
269
|
-
isInitial: false,
|
|
270
|
-
provisioningStatus: "dispatch_failed",
|
|
271
|
-
displayName: null,
|
|
272
|
-
description: null,
|
|
273
|
-
failureCode: null,
|
|
274
|
-
isReady: false,
|
|
275
|
-
});
|
|
276
|
-
const addedIds = new Set(added.map((c) => c.membershipId));
|
|
277
|
-
this._characters = [
|
|
278
|
-
...this._characters.filter((c) => !removedIds.has(c.membershipId) && !addedIds.has(c.membershipId)),
|
|
279
|
-
...added,
|
|
280
|
-
];
|
|
281
|
-
this.adoptEpochs(extras);
|
|
282
|
-
// A removal can retire the member that was active; the ack names the
|
|
283
|
-
// survivor, and adoptEpochs has already taken it.
|
|
284
|
-
if (this._activeMembershipId &&
|
|
285
|
-
!this.find(this._activeMembershipId)) {
|
|
286
|
-
this._activeMembershipId = this._characters[0]?.membershipId ?? null;
|
|
287
|
-
}
|
|
288
|
-
return {
|
|
289
|
-
added,
|
|
290
|
-
removed,
|
|
291
|
-
characters: this._characters,
|
|
292
|
-
rosterEpoch: this._rosterEpoch,
|
|
293
|
-
routeEpoch: this._routeEpoch,
|
|
294
|
-
activeMembershipId: this._activeMembershipId,
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
reset() {
|
|
298
|
-
this._characters = [];
|
|
299
|
-
this._activeMembershipId = null;
|
|
300
|
-
this._roomSessionId = null;
|
|
301
|
-
this._roomName = null;
|
|
302
|
-
this._requestTraceId = null;
|
|
303
|
-
this._routeEpoch = 0;
|
|
304
|
-
this._rosterEpoch = 0;
|
|
305
|
-
this._partialDispatch = false;
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Seed the roster from a `/connect` response, for either a create or a join.
|
|
309
|
-
*
|
|
310
|
-
* Returns false for a response with no `characters` array — that is an
|
|
311
|
-
* ordinary single-character session, and the roster stays empty so
|
|
312
|
-
* `isMultiCharacter` keeps distinguishing the two.
|
|
313
|
-
*/
|
|
314
|
-
applyConnectResponse(data) {
|
|
315
|
-
const raw = data?.characters;
|
|
316
|
-
if (!Array.isArray(raw) || raw.length === 0)
|
|
317
|
-
return false;
|
|
318
|
-
const characters = raw
|
|
319
|
-
.map((c) => toInstance(c))
|
|
320
|
-
.filter((c) => c !== null);
|
|
321
|
-
if (characters.length === 0)
|
|
322
|
-
return false;
|
|
323
|
-
this._characters = characters;
|
|
324
|
-
this._roomSessionId = asString(data.room_session_id);
|
|
325
|
-
this._roomName = asString(data.room_name);
|
|
326
|
-
this._requestTraceId = asString(data.request_trace_id);
|
|
327
|
-
// The server names the active member. Falling back to the initial entry,
|
|
328
|
-
// then to position zero, matches the rule that `characters[0]` is initial.
|
|
329
|
-
this._activeMembershipId =
|
|
330
|
-
asString(data.active_membership_id) ??
|
|
331
|
-
characters.find((c) => c.isInitial)?.membershipId ??
|
|
332
|
-
characters[0]?.membershipId ??
|
|
333
|
-
null;
|
|
334
|
-
this._routeEpoch = asNumber(data.route_epoch) ?? 0;
|
|
335
|
-
this._rosterEpoch = asNumber(data.roster_epoch) ?? 0;
|
|
336
|
-
this._partialDispatch =
|
|
337
|
-
data.partial_dispatch === true ||
|
|
338
|
-
characters.some((c) => c.provisioningStatus === "dispatch_failed");
|
|
339
|
-
return true;
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
function asString(value) {
|
|
343
|
-
return typeof value === "string" && value ? value : null;
|
|
344
|
-
}
|
|
345
|
-
function asNumber(value) {
|
|
346
|
-
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
347
|
-
}
|
|
348
|
-
//# sourceMappingURL=CharacterRoster.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CharacterRoster.js","sourceRoot":"","sources":["../../src/core/CharacterRoster.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ActiveCharacterChange,\n CharacterProvisioningStatus,\n CharacterRosterChange,\n ConvaiCharacterInstance,\n ConvaiCharacterSpec,\n ConvaiRoomSession,\n ServerResponseExtras,\n UpdateCharacterRosterOptions,\n} from \"./types\";\n\n/**\n * Roster state for a multi-character room: which character instances exist,\n * which one receives user turns, and the epochs that fence concurrent changes.\n *\n * Pure state — it owns no transport. `ConvaiClient` feeds it from the connect\n * response, from per-instance readiness events, and from server acks, and\n * publishes whatever commands it builds.\n *\n * Slice A populates the read half below. Roster mutation (`interaction-target`,\n * `character-roster-update`) grows this same class rather than a second home\n * for the same state.\n */\n\n/** A roster entry as it appears on the wire, in any of the places it appears. */\ninterface RawCharacter {\n membership_id?: string;\n character_id?: string;\n session_id?: string | null;\n character_session_id?: string | null;\n participant_identity?: string;\n is_initial?: boolean;\n provisioning_status?: string;\n failure_code?: string | null;\n display_name?: string | null;\n description?: string | null;\n}\n\nconst PROVISIONING_STATUSES: readonly string[] = [\n \"dispatch_queued\",\n \"dispatch_accepted\",\n \"dispatch_failed\",\n];\n\n/**\n * Coerce a wire status into the closed union.\n *\n * An unrecognised value becomes `dispatch_queued`, the one state that promises\n * nothing: it means \"still working\", so a client waits for `bot-ready` rather\n * than acting. Mapping to `dispatch_accepted` would imply an actor exists, and\n * to `dispatch_failed` would hide a member that is actually coming up.\n */\nfunction toProvisioningStatus(value: unknown): CharacterProvisioningStatus {\n return typeof value === \"string\" && PROVISIONING_STATUSES.includes(value)\n ? (value as CharacterProvisioningStatus)\n : \"dispatch_queued\";\n}\n\n/**\n * Convert a wire entry into an instance, or null when it cannot be attributed.\n *\n * A member with no `membership_id` is unaddressable: it cannot be targeted,\n * removed, or matched to a participant. The contract's rule throughout is to\n * fail closed rather than guess, so it is dropped instead of being given a\n * synthesised id that would later collide.\n */\nfunction toInstance(raw: RawCharacter | undefined): ConvaiCharacterInstance | null {\n if (!raw?.membership_id) return null;\n return {\n membershipId: raw.membership_id,\n characterId: raw.character_id ?? \"\",\n sessionId: raw.session_id ?? null,\n characterSessionId: raw.character_session_id ?? null,\n // Identity is derivable and always `character:{membership_id}`. Falling\n // back to it is safe; falling back to a positional name or a LiveKit SID\n // would not be, so those are never used.\n participantIdentity:\n raw.participant_identity || `character:${raw.membership_id}`,\n isInitial: raw.is_initial === true,\n provisioningStatus: toProvisioningStatus(raw.provisioning_status),\n displayName: raw.display_name ?? null,\n description: raw.description ?? null,\n failureCode: raw.failure_code ?? null,\n isReady: false,\n };\n}\n\nexport class CharacterRoster {\n private _characters: ConvaiCharacterInstance[] = [];\n private _activeMembershipId: string | null = null;\n private _roomSessionId: string | null = null;\n private _roomName: string | null = null;\n private _requestTraceId: string | null = null;\n private _routeEpoch = 0;\n private _rosterEpoch = 0;\n private _partialDispatch = false;\n\n /** Character instances in roster order. Empty in single-character mode. */\n get characters(): ConvaiCharacterInstance[] {\n return this._characters;\n }\n\n /** Membership currently receiving user turns, or null. */\n get activeMembershipId(): string | null {\n return this._activeMembershipId;\n }\n\n get roomSessionId(): string | null {\n return this._roomSessionId;\n }\n\n get routeEpoch(): number {\n return this._routeEpoch;\n }\n\n get rosterEpoch(): number {\n return this._rosterEpoch;\n }\n\n /** True once a multi-character connect response has been applied. */\n get isMultiCharacter(): boolean {\n return this._characters.length > 0;\n }\n\n /** The server-owned snapshot, or null for a single-character session. */\n get roomSession(): ConvaiRoomSession | null {\n if (!this._roomSessionId) return null;\n return {\n roomSessionId: this._roomSessionId,\n roomName: this._roomName,\n requestTraceId: this._requestTraceId,\n activeMembershipId: this._activeMembershipId,\n routeEpoch: this._routeEpoch,\n rosterEpoch: this._rosterEpoch,\n partialDispatch: this._partialDispatch,\n characters: this._characters,\n };\n }\n\n find(membershipId: string): ConvaiCharacterInstance | undefined {\n return this._characters.find((c) => c.membershipId === membershipId);\n }\n\n /** Members that have sent their own `bot-ready`. */\n get readyCharacters(): ConvaiCharacterInstance[] {\n return this._characters.filter((c) => c.isReady);\n }\n\n /**\n * Mark a member ready from its own `bot-ready`, filling in any detail the\n * connect response did not yet have.\n *\n * Returns whether anything changed, so the caller only pushes state when it\n * did. A single-character `bot-ready` also carries these fields, so nothing\n * is tracked until a roster is actually seeded.\n */\n applyBotReady(about: Record<string, unknown> | undefined): boolean {\n if (!about || !this.isMultiCharacter) return false;\n const incoming = toInstance(about as RawCharacter);\n if (!incoming) return false;\n\n const index = this._characters.findIndex(\n (c) => c.membershipId === incoming.membershipId,\n );\n if (index === -1) {\n // A member added at runtime announces itself this way.\n this._characters = [...this._characters, { ...incoming, isReady: true }];\n return true;\n }\n\n const existing = this._characters[index]!;\n const merged: ConvaiCharacterInstance = {\n ...existing,\n characterSessionId:\n incoming.characterSessionId ?? existing.characterSessionId,\n sessionId: incoming.sessionId ?? existing.sessionId,\n displayName: incoming.displayName ?? existing.displayName,\n participantIdentity:\n incoming.participantIdentity || existing.participantIdentity,\n isReady: true,\n };\n if (\n existing.isReady &&\n merged.characterSessionId === existing.characterSessionId &&\n merged.sessionId === existing.sessionId &&\n merged.participantIdentity === existing.participantIdentity\n ) {\n return false;\n }\n this._characters = [\n ...this._characters.slice(0, index),\n merged,\n ...this._characters.slice(index + 1),\n ];\n return true;\n }\n\n /**\n * Apply a `character-status` transition. Readiness recorded here is\n * bookkeeping for replacement selection; `bot-ready` remains what gates\n * interaction.\n */\n applyCharacterStatus(status: {\n membershipId: string;\n status: \"starting\" | \"ready\" | \"failed\";\n failureCode: string | null;\n }): boolean {\n const index = this._characters.findIndex(\n (c) => c.membershipId === status.membershipId,\n );\n if (index === -1) return false;\n const existing = this._characters[index]!;\n\n const next: ConvaiCharacterInstance = {\n ...existing,\n ...(status.status === \"failed\"\n ? {\n provisioningStatus: \"dispatch_failed\" as const,\n failureCode: status.failureCode ?? existing.failureCode,\n isReady: false,\n }\n : {}),\n };\n if (\n next.provisioningStatus === existing.provisioningStatus &&\n next.failureCode === existing.failureCode &&\n next.isReady === existing.isReady\n ) {\n return false;\n }\n this._characters = [\n ...this._characters.slice(0, index),\n next,\n ...this._characters.slice(index + 1),\n ];\n if (status.status === \"failed\") this._partialDispatch = true;\n return true;\n }\n\n /**\n * Pick a member to take over routing when the active one is removed.\n *\n * The runtime refuses a replacement that has not sent `bot-ready`\n * (`replacement_target_unavailable`), so ready survivors come first. Falling\n * back to any survivor at least produces a nameable rejection rather than\n * `replacement_target_required`.\n */\n pickReplacement(removing: string[]): string | undefined {\n const removed = new Set(removing);\n const survivors = this._characters.filter(\n (c) => !removed.has(c.membershipId),\n );\n return (\n survivors.find((c) => c.isReady)?.membershipId ?? survivors[0]?.membershipId\n );\n }\n\n /** Payload that switches the active member. */\n buildInteractionTarget(\n membershipId: string | null,\n commandId: string,\n ): Record<string, unknown> {\n return {\n room_session_id: this._roomSessionId,\n target_membership_id: membershipId,\n expected_route_epoch: this._routeEpoch,\n command_id: commandId,\n };\n }\n\n /** Payload that adds and removes members. */\n buildRosterUpdate(\n options: UpdateCharacterRosterOptions,\n commandId: string,\n ): Record<string, unknown> {\n const add = (options.add ?? []).map((spec: ConvaiCharacterSpec) => ({\n character_id: spec.characterId.trim(),\n ...(spec.characterSessionId\n ? { character_session_id: spec.characterSessionId }\n : {}),\n }));\n return {\n room_session_id: this._roomSessionId,\n expected_roster_epoch: this._rosterEpoch,\n command_id: commandId,\n ...(add.length > 0 && { add }),\n ...(options.remove?.length && { remove_membership_ids: options.remove }),\n ...(options.replacementTarget && {\n replacement_target_membership_id: options.replacementTarget,\n }),\n };\n }\n\n /**\n * Adopt the server's authoritative epochs and active member from any\n * response, errors included.\n *\n * A `stale_route_epoch` rejection carries the real epoch, and adopting it is\n * precisely what makes the single retry meaningful rather than a repeat of\n * the same losing bet.\n */\n adoptEpochs(extras: ServerResponseExtras | null | undefined): void {\n if (!extras) return;\n if (typeof extras.route_epoch === \"number\") this._routeEpoch = extras.route_epoch;\n if (typeof extras.roster_epoch === \"number\") this._rosterEpoch = extras.roster_epoch;\n if (extras.active_membership_id !== undefined) {\n this._activeMembershipId = (extras.active_membership_id as string) ?? null;\n }\n }\n\n /**\n * Apply a successful `interaction-target` ack. Returns the change even when\n * the target did not move, so a caller awaiting the promise always learns the\n * authoritative state.\n */\n applyInteractionTarget(\n extras: ServerResponseExtras | null | undefined,\n ): ActiveCharacterChange {\n const previous =\n extras?.previous_membership_id !== undefined\n ? (extras.previous_membership_id as string | null)\n : this._activeMembershipId;\n this.adoptEpochs(extras);\n return {\n previous: previous ?? null,\n active: this._activeMembershipId,\n routeEpoch: this._routeEpoch,\n };\n }\n\n /** Apply a successful `character-roster-update` ack, mutating the roster. */\n applyRosterUpdate(\n extras: ServerResponseExtras | null | undefined,\n ): CharacterRosterChange {\n const added = (Array.isArray(extras?.added) ? extras!.added : [])\n .map((c) => toInstance(c as RawCharacter))\n .filter((c): c is ConvaiCharacterInstance => c !== null);\n\n const removedIds = new Set<string>(\n Array.isArray(extras?.removed_membership_ids)\n ? (extras!.removed_membership_ids as string[])\n : [],\n );\n // Prefer the roster's own record of a removed member: the ack echoes only\n // its id, and the caller wants the instance it had been rendering.\n const removed = [...removedIds].map(\n (id) =>\n this.find(id) ?? {\n membershipId: id,\n characterId: \"\",\n sessionId: null,\n characterSessionId: null,\n participantIdentity: `character:${id}`,\n isInitial: false,\n provisioningStatus: \"dispatch_failed\" as const,\n displayName: null,\n description: null,\n failureCode: null,\n isReady: false,\n },\n );\n\n const addedIds = new Set(added.map((c) => c.membershipId));\n this._characters = [\n ...this._characters.filter(\n (c) => !removedIds.has(c.membershipId) && !addedIds.has(c.membershipId),\n ),\n ...added,\n ];\n this.adoptEpochs(extras);\n // A removal can retire the member that was active; the ack names the\n // survivor, and adoptEpochs has already taken it.\n if (\n this._activeMembershipId &&\n !this.find(this._activeMembershipId)\n ) {\n this._activeMembershipId = this._characters[0]?.membershipId ?? null;\n }\n return {\n added,\n removed,\n characters: this._characters,\n rosterEpoch: this._rosterEpoch,\n routeEpoch: this._routeEpoch,\n activeMembershipId: this._activeMembershipId,\n };\n }\n\n reset(): void {\n this._characters = [];\n this._activeMembershipId = null;\n this._roomSessionId = null;\n this._roomName = null;\n this._requestTraceId = null;\n this._routeEpoch = 0;\n this._rosterEpoch = 0;\n this._partialDispatch = false;\n }\n\n /**\n * Seed the roster from a `/connect` response, for either a create or a join.\n *\n * Returns false for a response with no `characters` array — that is an\n * ordinary single-character session, and the roster stays empty so\n * `isMultiCharacter` keeps distinguishing the two.\n */\n applyConnectResponse(data: Record<string, unknown>): boolean {\n const raw = data?.characters;\n if (!Array.isArray(raw) || raw.length === 0) return false;\n\n const characters = raw\n .map((c) => toInstance(c as RawCharacter))\n .filter((c): c is ConvaiCharacterInstance => c !== null);\n if (characters.length === 0) return false;\n\n this._characters = characters;\n this._roomSessionId = asString(data.room_session_id);\n this._roomName = asString(data.room_name);\n this._requestTraceId = asString(data.request_trace_id);\n // The server names the active member. Falling back to the initial entry,\n // then to position zero, matches the rule that `characters[0]` is initial.\n this._activeMembershipId =\n asString(data.active_membership_id) ??\n characters.find((c) => c.isInitial)?.membershipId ??\n characters[0]?.membershipId ??\n null;\n this._routeEpoch = asNumber(data.route_epoch) ?? 0;\n this._rosterEpoch = asNumber(data.roster_epoch) ?? 0;\n this._partialDispatch =\n data.partial_dispatch === true ||\n characters.some((c) => c.provisioningStatus === \"dispatch_failed\");\n return true;\n }\n}\n\nfunction asString(value: unknown): string | null {\n return typeof value === \"string\" && value ? value : null;\n}\n\nfunction asNumber(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) ? value : null;\n}\n"]}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import type { CharacterDraftBootstrapResult, CharacterVersionInfo, CharacterVersionList, CharacterVersionManagerOptions, CharacterVersionRawDiff, CharacterVersionSemanticDiff, CreateCharacterVersionOptions, DiscardCharacterDraftResult, ForkCharacterVersionResult, ResolveCharacterVersionOptions, ResolvedCharacterVersion, RevertCharacterChangeOptions, RevertCharacterChangeResult } from "./types.js";
|
|
2
|
-
import { type CharacterVersionSelector } from "./characterReference.js";
|
|
3
|
-
export declare const DEFAULT_CHARACTER_API_URL = "https://api2.convai.com";
|
|
4
|
-
/**
|
|
5
|
-
* Error raised when the Character REST platform answers with a non-2xx
|
|
6
|
-
* status. `status` carries the HTTP code; `detail` carries the parsed body
|
|
7
|
-
* (`{ detail: string }` for most failures, a validation list for 422).
|
|
8
|
-
*/
|
|
9
|
-
export declare class CharacterApiError extends Error {
|
|
10
|
-
readonly status: number;
|
|
11
|
-
readonly detail: unknown;
|
|
12
|
-
constructor(message: string, status: number, detail: unknown);
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Authoring client for character versions.
|
|
16
|
-
*
|
|
17
|
-
* Every character has an editable **draft** and, once released, a set of
|
|
18
|
-
* immutable **tagged versions** (`1.0`, `1.1`, …). `latest` is a movable
|
|
19
|
-
* pointer that the runtime follows when a client connects without a
|
|
20
|
-
* selector. The lifecycle is:
|
|
21
|
-
*
|
|
22
|
-
* 1. edit the draft (Playground, `/character/update`, MCP);
|
|
23
|
-
* 2. {@link diff} the draft against `latest` to review the change;
|
|
24
|
-
* 3. {@link create} a tag from the draft, optionally making it latest;
|
|
25
|
-
* 4. {@link promote} an older tag to roll back, or {@link discardDraft} to
|
|
26
|
-
* throw unreleased edits away.
|
|
27
|
-
*
|
|
28
|
-
* Connect to any of these with `characterVersion` in `ConvaiConfig`.
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* const versions = new CharacterVersionManager({
|
|
33
|
-
* apiKey: 'YOUR_API_KEY',
|
|
34
|
-
* characterId: 'YOUR_CHARACTER_ID',
|
|
35
|
-
* });
|
|
36
|
-
* const { has_unpublished_changes } = await versions.list();
|
|
37
|
-
* if (has_unpublished_changes) {
|
|
38
|
-
* await versions.create('1.1', { makeLatest: true });
|
|
39
|
-
* }
|
|
40
|
-
* ```
|
|
41
|
-
*/
|
|
42
|
-
export declare class CharacterVersionManager {
|
|
43
|
-
private readonly apiKey;
|
|
44
|
-
private readonly personalAccessToken;
|
|
45
|
-
private readonly baseUrl;
|
|
46
|
-
private readonly workspaceId;
|
|
47
|
-
readonly characterId: string;
|
|
48
|
-
constructor(options: CharacterVersionManagerOptions);
|
|
49
|
-
/** List released tags plus the current latest and draft revisions. */
|
|
50
|
-
list(): Promise<CharacterVersionList>;
|
|
51
|
-
/**
|
|
52
|
-
* Resolve a reference to the configuration snapshot the runtime would run.
|
|
53
|
-
* Omit `version` to resolve the effective latest, or pass `draft`,
|
|
54
|
-
* `latest`, or a tag.
|
|
55
|
-
*/
|
|
56
|
-
resolve(version?: CharacterVersionSelector | null, options?: ResolveCharacterVersionOptions): Promise<ResolvedCharacterVersion>;
|
|
57
|
-
/**
|
|
58
|
-
* Give a character that predates versioning an editable draft. Safe to call
|
|
59
|
-
* repeatedly — `created` is false when a draft already existed.
|
|
60
|
-
*/
|
|
61
|
-
bootstrap(): Promise<CharacterDraftBootstrapResult>;
|
|
62
|
-
/**
|
|
63
|
-
* Compare two references. Each side is `draft`, `latest`, or a tag.
|
|
64
|
-
* The raw view lists JSON paths; the semantic view groups them into
|
|
65
|
-
* labelled changes that {@link revert} can undo one at a time.
|
|
66
|
-
*/
|
|
67
|
-
diff(from: string, to: string, options?: {
|
|
68
|
-
view?: "raw";
|
|
69
|
-
}): Promise<CharacterVersionRawDiff>;
|
|
70
|
-
diff(from: string, to: string, options: {
|
|
71
|
-
view: "semantic";
|
|
72
|
-
}): Promise<CharacterVersionSemanticDiff>;
|
|
73
|
-
/**
|
|
74
|
-
* Release the current draft as an immutable tagged version.
|
|
75
|
-
* @param version - New tag, `major.minor` or `major.minor.patch`
|
|
76
|
-
*/
|
|
77
|
-
create(version: string, options?: CreateCharacterVersionOptions): Promise<CharacterVersionInfo>;
|
|
78
|
-
/** Point `latest` at an already released tag — the way to roll back. */
|
|
79
|
-
promote(version: string): Promise<CharacterVersionInfo>;
|
|
80
|
-
/**
|
|
81
|
-
* Discard every saved draft change and restore the draft from its released
|
|
82
|
-
* parent. Pass the draft revision you last saw so a concurrent edit is
|
|
83
|
-
* refused instead of silently thrown away.
|
|
84
|
-
*/
|
|
85
|
-
discardDraft(expectedDraftRevisionId: string): Promise<DiscardCharacterDraftResult>;
|
|
86
|
-
/** Undo one semantic change in the draft, identified by a semantic diff's `change_id`. */
|
|
87
|
-
revert(options: RevertCharacterChangeOptions): Promise<RevertCharacterChangeResult>;
|
|
88
|
-
/** Mark a tag deprecated, or restore it with `deprecated: false`. Deprecated tags stay connectable. */
|
|
89
|
-
deprecate(version: string, deprecated?: boolean): Promise<CharacterVersionInfo>;
|
|
90
|
-
/**
|
|
91
|
-
* Replace the draft with the contents of a released tag, to branch new work
|
|
92
|
-
* from an older version. `expectedDraftRevisionId` guards against clobbering
|
|
93
|
-
* a draft someone else just changed.
|
|
94
|
-
*/
|
|
95
|
-
fork(version: string, expectedDraftRevisionId?: string): Promise<ForkCharacterVersionResult>;
|
|
96
|
-
private assertSelector;
|
|
97
|
-
private assertTag;
|
|
98
|
-
private request;
|
|
99
|
-
}
|
|
100
|
-
//# sourceMappingURL=CharacterVersionManager.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CharacterVersionManager.d.ts","sourceRoot":"","sources":["../../src/core/CharacterVersionManager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,6BAA6B,EAG7B,oBAAoB,EACpB,oBAAoB,EACpB,8BAA8B,EAC9B,uBAAuB,EACvB,4BAA4B,EAC5B,6BAA6B,EAC7B,2BAA2B,EAC3B,0BAA0B,EAC1B,8BAA8B,EAC9B,wBAAwB,EACxB,4BAA4B,EAC5B,2BAA2B,EAC5B,MAAM,SAAS,CAAC;AACjB,OAAO,EAGL,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,yBAAyB,4BAA4B,CAAC;AAEnE;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO;CAM7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IACvC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAgB;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAgB;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;gBAEjB,OAAO,EAAE,8BAA8B;IAgBnD,sEAAsE;IAChE,IAAI,IAAI,OAAO,CAAC,oBAAoB,CAAC;IAI3C;;;;OAIG;IACG,OAAO,CACX,OAAO,CAAC,EAAE,wBAAwB,GAAG,IAAI,EACzC,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,wBAAwB,CAAC;IAUpC;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,6BAA6B,CAAC;IAIzD;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,KAAK,CAAA;KAAE,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAC5F,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,GAAG,OAAO,CAAC,4BAA4B,CAAC;IAWpG;;;OAGG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,6BAAkC,GAAG,OAAO,CAAC,oBAAoB,CAAC;IASzG,wEAAwE;IAClE,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAM7D;;;;OAIG;IACG,YAAY,CAAC,uBAAuB,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,CAAC;IASzF,0FAA0F;IACpF,MAAM,CAAC,OAAO,EAAE,4BAA4B,GAAG,OAAO,CAAC,2BAA2B,CAAC;IAczF,uGAAuG;IACjG,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAMlF;;;;OAIG;IACG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,uBAAuB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC;IASlG,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,SAAS;YASH,OAAO;CA2CtB"}
|