@polymorfa/browser 0.1.0-dev.20260922094209
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/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/calls/api.d.ts +22 -0
- package/dist/calls/api.d.ts.map +1 -0
- package/dist/calls/api.js +104 -0
- package/dist/calls/api.js.map +1 -0
- package/dist/calls/backend.d.ts +85 -0
- package/dist/calls/backend.d.ts.map +1 -0
- package/dist/calls/backend.js +141 -0
- package/dist/calls/backend.js.map +1 -0
- package/dist/calls/client.d.ts +56 -0
- package/dist/calls/client.d.ts.map +1 -0
- package/dist/calls/client.js +260 -0
- package/dist/calls/client.js.map +1 -0
- package/dist/calls/controller.d.ts +329 -0
- package/dist/calls/controller.d.ts.map +1 -0
- package/dist/calls/controller.js +1328 -0
- package/dist/calls/controller.js.map +1 -0
- package/dist/calls/diagnostics.d.ts +52 -0
- package/dist/calls/diagnostics.d.ts.map +1 -0
- package/dist/calls/diagnostics.js +188 -0
- package/dist/calls/diagnostics.js.map +1 -0
- package/dist/calls/index.d.ts +3 -0
- package/dist/calls/index.d.ts.map +1 -0
- package/dist/calls/index.js +5 -0
- package/dist/calls/index.js.map +1 -0
- package/dist/calls/internal.d.ts +8 -0
- package/dist/calls/internal.d.ts.map +1 -0
- package/dist/calls/internal.js +8 -0
- package/dist/calls/internal.js.map +1 -0
- package/dist/calls/media.d.ts +144 -0
- package/dist/calls/media.d.ts.map +1 -0
- package/dist/calls/media.js +512 -0
- package/dist/calls/media.js.map +1 -0
- package/dist/calls/signaling.d.ts +74 -0
- package/dist/calls/signaling.d.ts.map +1 -0
- package/dist/calls/signaling.js +169 -0
- package/dist/calls/signaling.js.map +1 -0
- package/dist/calls/socket.d.ts +95 -0
- package/dist/calls/socket.d.ts.map +1 -0
- package/dist/calls/socket.js +267 -0
- package/dist/calls/socket.js.map +1 -0
- package/dist/chat/composer.d.ts +59 -0
- package/dist/chat/composer.d.ts.map +1 -0
- package/dist/chat/composer.js +217 -0
- package/dist/chat/composer.js.map +1 -0
- package/dist/chat/conversation.d.ts +71 -0
- package/dist/chat/conversation.d.ts.map +1 -0
- package/dist/chat/conversation.js +204 -0
- package/dist/chat/conversation.js.map +1 -0
- package/dist/chat/index.d.ts +4 -0
- package/dist/chat/index.d.ts.map +1 -0
- package/dist/chat/index.js +4 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/voice-recorder.d.ts +75 -0
- package/dist/chat/voice-recorder.d.ts.map +1 -0
- package/dist/chat/voice-recorder.js +346 -0
- package/dist/chat/voice-recorder.js.map +1 -0
- package/dist/controller.d.ts +16 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +50 -0
- package/dist/controller.js.map +1 -0
- package/dist/diagnostics.d.ts +27 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +2 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/dropin/client.d.ts +82 -0
- package/dist/dropin/client.d.ts.map +1 -0
- package/dist/dropin/client.js +314 -0
- package/dist/dropin/client.js.map +1 -0
- package/dist/dropin/connect.d.ts +23 -0
- package/dist/dropin/connect.d.ts.map +1 -0
- package/dist/dropin/connect.js +54 -0
- package/dist/dropin/connect.js.map +1 -0
- package/dist/dropin/inbox.d.ts +131 -0
- package/dist/dropin/inbox.d.ts.map +1 -0
- package/dist/dropin/inbox.js +406 -0
- package/dist/dropin/inbox.js.map +1 -0
- package/dist/dropin/index.d.ts +5 -0
- package/dist/dropin/index.d.ts.map +1 -0
- package/dist/dropin/index.js +5 -0
- package/dist/dropin/index.js.map +1 -0
- package/dist/dropin/permissions.d.ts +29 -0
- package/dist/dropin/permissions.d.ts.map +1 -0
- package/dist/dropin/permissions.js +53 -0
- package/dist/dropin/permissions.js.map +1 -0
- package/dist/errors.d.ts +39 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +41 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/internal.d.ts +12 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +13 -0
- package/dist/internal.js.map +1 -0
- package/dist/messaging/client.d.ts +54 -0
- package/dist/messaging/client.d.ts.map +1 -0
- package/dist/messaging/client.js +153 -0
- package/dist/messaging/client.js.map +1 -0
- package/dist/messaging/composer.d.ts +12 -0
- package/dist/messaging/composer.d.ts.map +1 -0
- package/dist/messaging/composer.js +36 -0
- package/dist/messaging/composer.js.map +1 -0
- package/dist/messaging/index.d.ts +4 -0
- package/dist/messaging/index.d.ts.map +1 -0
- package/dist/messaging/index.js +3 -0
- package/dist/messaging/index.js.map +1 -0
- package/dist/messaging/types.d.ts +209 -0
- package/dist/messaging/types.d.ts.map +1 -0
- package/dist/messaging/types.js +2 -0
- package/dist/messaging/types.js.map +1 -0
- package/dist/templates/controller.d.ts +45 -0
- package/dist/templates/controller.d.ts.map +1 -0
- package/dist/templates/controller.js +298 -0
- package/dist/templates/controller.js.map +1 -0
- package/dist/templates/index.d.ts +4 -0
- package/dist/templates/index.d.ts.map +1 -0
- package/dist/templates/index.js +3 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/transport.d.ts +7 -0
- package/dist/templates/transport.d.ts.map +1 -0
- package/dist/templates/transport.js +124 -0
- package/dist/templates/transport.js.map +1 -0
- package/dist/templates/types.d.ts +141 -0
- package/dist/templates/types.d.ts.map +1 -0
- package/dist/templates/types.js +2 -0
- package/dist/templates/types.js.map +1 -0
- package/dist/token.d.ts +37 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +152 -0
- package/dist/token.js.map +1 -0
- package/dist/transport.d.ts +53 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +328 -0
- package/dist/transport.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { CallClaimedError, CallsDisabledError, } from "@polymorfa/sdk/calls/internal";
|
|
2
|
+
import { BrowserTransport } from "../transport.js";
|
|
3
|
+
/** Client-token signaling over the Messaging REST routes. */
|
|
4
|
+
export class CallsSignalingClient {
|
|
5
|
+
#transport;
|
|
6
|
+
#prefix;
|
|
7
|
+
constructor(transport, apiPrefix = "/messaging") {
|
|
8
|
+
this.#transport = transport;
|
|
9
|
+
this.#prefix = apiPrefix.replace(/\/$/, "");
|
|
10
|
+
}
|
|
11
|
+
async offer(callId, request, signal) {
|
|
12
|
+
const response = await this.#transport
|
|
13
|
+
.request({
|
|
14
|
+
method: "POST",
|
|
15
|
+
path: this.#path(callId, "/offer"),
|
|
16
|
+
body: { sdp: request.sdp, connectionId: request.connectionId },
|
|
17
|
+
...(signal === undefined ? {} : { signal }),
|
|
18
|
+
idempotencyKey: `voip-offer:${callId}:${request.connectionId}:${nonce()}`,
|
|
19
|
+
})
|
|
20
|
+
.catch((cause) => {
|
|
21
|
+
throw claimedError(cause);
|
|
22
|
+
});
|
|
23
|
+
return response.data.data;
|
|
24
|
+
}
|
|
25
|
+
async renegotiate(callId, request, signal) {
|
|
26
|
+
const response = await this.#transport.request({
|
|
27
|
+
method: "POST",
|
|
28
|
+
path: this.#path(callId, "/renegotiate"),
|
|
29
|
+
body: { sdp: request.sdp, connectionId: request.connectionId },
|
|
30
|
+
...(signal === undefined ? {} : { signal }),
|
|
31
|
+
});
|
|
32
|
+
return response.data.data;
|
|
33
|
+
}
|
|
34
|
+
async candidate(callId, candidate, connectionId, signal) {
|
|
35
|
+
await this.#transport.request({
|
|
36
|
+
method: "POST",
|
|
37
|
+
path: this.#path(callId, "/candidate"),
|
|
38
|
+
body: { ...candidate, connectionId },
|
|
39
|
+
...(signal === undefined ? {} : { signal }),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async candidates(callId, signal) {
|
|
43
|
+
const response = await this.#transport.request({
|
|
44
|
+
method: "GET",
|
|
45
|
+
path: this.#path(callId, "/candidates"),
|
|
46
|
+
...(signal === undefined ? {} : { signal }),
|
|
47
|
+
});
|
|
48
|
+
return response.data.data.candidates;
|
|
49
|
+
}
|
|
50
|
+
async accept(callId, options, signal) {
|
|
51
|
+
const response = await this.#transport
|
|
52
|
+
.request({
|
|
53
|
+
method: "POST",
|
|
54
|
+
path: this.#path(callId, "/accept"),
|
|
55
|
+
body: {
|
|
56
|
+
exclusive: options.exclusive === true,
|
|
57
|
+
...(options.video === undefined ? {} : { video: options.video }),
|
|
58
|
+
},
|
|
59
|
+
...(signal === undefined ? {} : { signal }),
|
|
60
|
+
})
|
|
61
|
+
.catch((cause) => {
|
|
62
|
+
throw claimedError(cause);
|
|
63
|
+
});
|
|
64
|
+
const data = response.data?.data;
|
|
65
|
+
return {
|
|
66
|
+
answered: data?.answered === true,
|
|
67
|
+
answeredBy: typeof data?.answeredBy === "string" ? data.answeredBy : "",
|
|
68
|
+
exclusive: data?.exclusive === true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async reject(callId, signal) {
|
|
72
|
+
await this.#transport.request({
|
|
73
|
+
method: "POST",
|
|
74
|
+
path: this.#path(callId, "/reject"),
|
|
75
|
+
...(signal === undefined ? {} : { signal }),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async leave(callId, connectionId, signal) {
|
|
79
|
+
await this.#transport.request({
|
|
80
|
+
method: "POST",
|
|
81
|
+
path: this.#path(callId, "/leave"),
|
|
82
|
+
body: { connectionId },
|
|
83
|
+
...(signal === undefined ? {} : { signal }),
|
|
84
|
+
idempotencyKey: `voip-leave:${callId}:${connectionId}`,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
async end(callId, signal) {
|
|
88
|
+
await this.#transport.request({
|
|
89
|
+
method: "DELETE",
|
|
90
|
+
path: this.#path(callId),
|
|
91
|
+
...(signal === undefined ? {} : { signal }),
|
|
92
|
+
idempotencyKey: `voip-end:${callId}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Best-effort: one attempt, no retries. A client token acts as its own
|
|
97
|
+
* participant, so the report names none.
|
|
98
|
+
*/
|
|
99
|
+
async report(callId, report, signal) {
|
|
100
|
+
const body = { ...report };
|
|
101
|
+
delete body["participant"];
|
|
102
|
+
await this.#transport.request({
|
|
103
|
+
method: "POST",
|
|
104
|
+
path: this.#path(callId, "/reports"),
|
|
105
|
+
body,
|
|
106
|
+
maxNetworkRetries: 0,
|
|
107
|
+
...(signal === undefined ? {} : { signal }),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
token(request = {}) {
|
|
111
|
+
return this.#transport.token(request.refresh === undefined ? {} : { refresh: request.refresh });
|
|
112
|
+
}
|
|
113
|
+
socketUrl(path) {
|
|
114
|
+
const url = new URL(path, `${this.#transport.baseUrl}/`);
|
|
115
|
+
url.protocol =
|
|
116
|
+
url.protocol === "https:"
|
|
117
|
+
? "wss:"
|
|
118
|
+
: url.protocol === "http:"
|
|
119
|
+
? "ws:"
|
|
120
|
+
: url.protocol;
|
|
121
|
+
return url.toString();
|
|
122
|
+
}
|
|
123
|
+
#path(callId, suffix = "") {
|
|
124
|
+
return `${this.#prefix}/voip/calls/${encodeURIComponent(callId)}${suffix}`;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Turn a `409 call_claimed` HTTP failure into {@link CallClaimedError} and a
|
|
129
|
+
* `403 calls_disabled` one into {@link CallsDisabledError}.
|
|
130
|
+
*/
|
|
131
|
+
export function claimedError(cause) {
|
|
132
|
+
const message = cause instanceof Error ? cause.message : undefined;
|
|
133
|
+
if (isCallClaimed(cause))
|
|
134
|
+
return new CallClaimedError(message);
|
|
135
|
+
if (hasFailureCode(cause, 403, "calls_disabled")) {
|
|
136
|
+
return cause instanceof CallsDisabledError
|
|
137
|
+
? cause
|
|
138
|
+
: new CallsDisabledError(message);
|
|
139
|
+
}
|
|
140
|
+
return cause;
|
|
141
|
+
}
|
|
142
|
+
function hasFailureCode(cause, status, code) {
|
|
143
|
+
const failure = cause;
|
|
144
|
+
if (failure?.status !== status)
|
|
145
|
+
return false;
|
|
146
|
+
if (failure.code === code)
|
|
147
|
+
return true;
|
|
148
|
+
const details = failure.details;
|
|
149
|
+
const error = details?.["error"];
|
|
150
|
+
return error?.["code"] === code || details?.["code"] === code;
|
|
151
|
+
}
|
|
152
|
+
/** True for a `409` failure whose code (or response body code) is `call_claimed`. */
|
|
153
|
+
export function isCallClaimed(cause) {
|
|
154
|
+
if (cause instanceof CallClaimedError)
|
|
155
|
+
return true;
|
|
156
|
+
const failure = cause;
|
|
157
|
+
if (failure?.status !== 409)
|
|
158
|
+
return false;
|
|
159
|
+
if (failure.code === "call_claimed")
|
|
160
|
+
return true;
|
|
161
|
+
const details = failure.details;
|
|
162
|
+
const error = details?.["error"];
|
|
163
|
+
return (error?.["code"] === "call_claimed" || details?.["code"] === "call_claimed");
|
|
164
|
+
}
|
|
165
|
+
function nonce() {
|
|
166
|
+
const bytes = globalThis.crypto.getRandomValues(new Uint8Array(6));
|
|
167
|
+
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=signaling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"signaling.js","sourceRoot":"","sources":["../../src/calls/signaling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { type LifecycleFrame } from "@polymorfa/sdk/calls/internal";
|
|
2
|
+
import type { CallLifecycleEvent } from "./controller.js";
|
|
3
|
+
import type { CallsSignaling, TrickleCandidate } from "./signaling.js";
|
|
4
|
+
/** Server → browser frames on the calls WebSocket. */
|
|
5
|
+
export type CallsSocketServerMessage = LifecycleFrame;
|
|
6
|
+
/**
|
|
7
|
+
* A failure delivered to {@link CallsSocket.onError}. A `CallsAuthError`
|
|
8
|
+
* (`code: "unauthorized"`) means the platform closed the socket with 4401;
|
|
9
|
+
* the socket asks for a fresh token before reconnecting.
|
|
10
|
+
*/
|
|
11
|
+
export interface CallsSocketError {
|
|
12
|
+
readonly code: string;
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}
|
|
15
|
+
/** Browser → server frames on the calls WebSocket. */
|
|
16
|
+
export type CallsSocketClientMessage = {
|
|
17
|
+
readonly type: "auth";
|
|
18
|
+
readonly token: string;
|
|
19
|
+
} | {
|
|
20
|
+
readonly type: "candidate";
|
|
21
|
+
readonly callId: string;
|
|
22
|
+
readonly connectionId: string;
|
|
23
|
+
readonly candidate: TrickleCandidate;
|
|
24
|
+
} | {
|
|
25
|
+
readonly type: "ping";
|
|
26
|
+
};
|
|
27
|
+
export interface CallsSocketOptions {
|
|
28
|
+
/** Signaling client that supplies the client token and the socket URL. */
|
|
29
|
+
readonly signaling: Pick<CallsSignaling, "token" | "socketUrl">;
|
|
30
|
+
/** Session to follow when the credential is a server key (sent as `?session=`). */
|
|
31
|
+
readonly session?: string;
|
|
32
|
+
/** Participant name for a server key (sent as `?participant=`). */
|
|
33
|
+
readonly participant?: string;
|
|
34
|
+
/** Reconnect backoff bounds in milliseconds. Defaults 1 000 → 30 000. */
|
|
35
|
+
readonly minBackoffMs?: number;
|
|
36
|
+
readonly maxBackoffMs?: number;
|
|
37
|
+
/** Heartbeat period in milliseconds; 0 disables it. Defaults to 15 000. */
|
|
38
|
+
readonly heartbeatMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Deadline in milliseconds from opening until the platform accepts the auth
|
|
41
|
+
* frame; 0 disables it. Defaults to 10 000.
|
|
42
|
+
*/
|
|
43
|
+
readonly openTimeoutMs?: number;
|
|
44
|
+
/** Send a replacement token this long before expiry. Defaults to 60 000. */
|
|
45
|
+
readonly refreshBeforeExpiryMs?: number;
|
|
46
|
+
readonly WebSocket?: typeof globalThis.WebSocket;
|
|
47
|
+
readonly setTimeout?: typeof globalThis.setTimeout;
|
|
48
|
+
readonly clearTimeout?: typeof globalThis.clearTimeout;
|
|
49
|
+
readonly setInterval?: typeof globalThis.setInterval;
|
|
50
|
+
readonly clearInterval?: typeof globalThis.clearInterval;
|
|
51
|
+
readonly random?: () => number;
|
|
52
|
+
readonly now?: () => number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The calls WebSocket: one socket per client at `/voip/ws`. The client token
|
|
56
|
+
* travels in the first frame, never in the URL, and is replaced before it
|
|
57
|
+
* expires. It pushes the session's `call.*` lifecycle events, delivers the
|
|
58
|
+
* pod's ICE candidates, and carries the browser's candidates. It reconnects
|
|
59
|
+
* with capped exponential backoff until {@link close}. Pass it as a
|
|
60
|
+
* backend's `incoming` source and as the media factory's candidate transport.
|
|
61
|
+
*/
|
|
62
|
+
export declare class CallsSocket {
|
|
63
|
+
#private;
|
|
64
|
+
constructor(options: CallsSocketOptions);
|
|
65
|
+
/** True while an authenticated socket is open. */
|
|
66
|
+
get connected(): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Open the socket; resolves after the first attempt settles (authenticated,
|
|
69
|
+
* failed, or {@link close} called meanwhile).
|
|
70
|
+
*/
|
|
71
|
+
connect(): Promise<void>;
|
|
72
|
+
/** Close the socket and stop reconnecting. */
|
|
73
|
+
close(): void;
|
|
74
|
+
/** Lifecycle source for {@link CallsBackend.subscribe}. */
|
|
75
|
+
subscribe(listener: (event: CallLifecycleEvent) => void): () => void;
|
|
76
|
+
/** Remote ICE candidates pushed by the pod. */
|
|
77
|
+
onCandidate(listener: (callId: string, candidate: TrickleCandidate, connectionId?: string) => void): () => void;
|
|
78
|
+
/** Authenticated connection state changes (true = ready). */
|
|
79
|
+
onState(listener: (connected: boolean) => void): () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Failures worth surfacing: server `error` frames, `token_failed`,
|
|
82
|
+
* `connect_timeout`, `unauthorized` (a 4401 close), and `unsupported`.
|
|
83
|
+
* Only `unsupported` stops the socket. For a revoked credential your token
|
|
84
|
+
* provider decides: throw from it, or call {@link close}.
|
|
85
|
+
*/
|
|
86
|
+
onError(listener: (error: CallsSocketError) => void): () => void;
|
|
87
|
+
/** Send a local ICE candidate; false while the socket is not ready (use REST). */
|
|
88
|
+
sendCandidate(callId: string, candidate: TrickleCandidate, connectionId: string): boolean;
|
|
89
|
+
}
|
|
90
|
+
/** Parse one server frame; unknown or malformed frames yield `undefined`. */
|
|
91
|
+
export declare function parseCallsSocketMessage(data: unknown): CallsSocketServerMessage | undefined;
|
|
92
|
+
export declare function lifecycleEventFrom(message: Extract<CallsSocketServerMessage, {
|
|
93
|
+
type: "event";
|
|
94
|
+
}>): CallLifecycleEvent | undefined;
|
|
95
|
+
//# sourceMappingURL=socket.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/calls/socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAiB,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACzE,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,sDAAsD;AACtD,MAAM,MAAM,wBAAwB,GAAG,cAAc,CAAC;AAEtD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,sDAAsD;AACtD,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IACE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;CACtC,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,WAAW,CAAC,CAAC;IAChE,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,yEAAyE;IACzE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,4EAA4E;IAC5E,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,UAAU,CAAC,SAAS,CAAC;IACjD,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,UAAU,CAAC,UAAU,CAAC;IACnD,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,UAAU,CAAC,YAAY,CAAC;IACvD,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,UAAU,CAAC,WAAW,CAAC;IACrD,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,UAAU,CAAC,aAAa,CAAC;IACzD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED;;;;;;;GAOG;AACH,qBAAa,WAAW;;gBASV,OAAO,EAAE,kBAAkB;IAwEvC,kDAAkD;IAClD,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAY9B,8CAA8C;IAC9C,KAAK,IAAI,IAAI;IAIb,2DAA2D;IAC3D,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GAAG,MAAM,IAAI;IAKpE,+CAA+C;IAC/C,WAAW,CACT,QAAQ,EAAE,CACR,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,gBAAgB,EAC3B,YAAY,CAAC,EAAE,MAAM,KAClB,IAAI,GACR,MAAM,IAAI;IAKb,6DAA6D;IAC7D,OAAO,CAAC,QAAQ,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAK3D;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI;IAKhE,kFAAkF;IAClF,aAAa,CACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,gBAAgB,EAC3B,YAAY,EAAE,MAAM,GACnB,OAAO;CASX;AAUD,6EAA6E;AAC7E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,OAAO,GACZ,wBAAwB,GAAG,SAAS,CAEtC;AAwBD,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,OAAO,CAAC,wBAAwB,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAC5D,kBAAkB,GAAG,SAAS,CA+DhC"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { LifecycleSocket, capabilitiesFrom, isParticipant, parseLifecycleFrame, } from "@polymorfa/sdk/calls/internal";
|
|
2
|
+
/**
|
|
3
|
+
* The calls WebSocket: one socket per client at `/voip/ws`. The client token
|
|
4
|
+
* travels in the first frame, never in the URL, and is replaced before it
|
|
5
|
+
* expires. It pushes the session's `call.*` lifecycle events, delivers the
|
|
6
|
+
* pod's ICE candidates, and carries the browser's candidates. It reconnects
|
|
7
|
+
* with capped exponential backoff until {@link close}. Pass it as a
|
|
8
|
+
* backend's `incoming` source and as the media factory's candidate transport.
|
|
9
|
+
*/
|
|
10
|
+
export class CallsSocket {
|
|
11
|
+
#lifecycle = new Set();
|
|
12
|
+
#candidates = new Set();
|
|
13
|
+
#state = new Set();
|
|
14
|
+
#errors = new Set();
|
|
15
|
+
#socket;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
const signaling = options.signaling;
|
|
18
|
+
if (signaling.token === undefined || signaling.socketUrl === undefined) {
|
|
19
|
+
this.#socket = undefined;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
// Read the methods on every call so a replaced provider takes effect.
|
|
23
|
+
this.#socket = new LifecycleSocket({
|
|
24
|
+
api: {
|
|
25
|
+
token: (request) => unsupported(signaling.token).call(signaling, request),
|
|
26
|
+
socketUrl: (path) => unsupported(signaling.socketUrl).call(signaling, path),
|
|
27
|
+
},
|
|
28
|
+
...(options.session === undefined ? {} : { session: options.session }),
|
|
29
|
+
...(options.participant === undefined
|
|
30
|
+
? {}
|
|
31
|
+
: { participant: options.participant }),
|
|
32
|
+
...(options.WebSocket === undefined
|
|
33
|
+
? {}
|
|
34
|
+
: { WebSocket: options.WebSocket }),
|
|
35
|
+
...(options.setTimeout === undefined
|
|
36
|
+
? {}
|
|
37
|
+
: { setTimeout: options.setTimeout }),
|
|
38
|
+
...(options.clearTimeout === undefined
|
|
39
|
+
? {}
|
|
40
|
+
: { clearTimeout: options.clearTimeout }),
|
|
41
|
+
...(options.setInterval === undefined
|
|
42
|
+
? {}
|
|
43
|
+
: { setInterval: options.setInterval }),
|
|
44
|
+
...(options.clearInterval === undefined
|
|
45
|
+
? {}
|
|
46
|
+
: { clearInterval: options.clearInterval }),
|
|
47
|
+
...(options.random === undefined ? {} : { random: options.random }),
|
|
48
|
+
...(options.now === undefined ? {} : { now: options.now }),
|
|
49
|
+
...(options.minBackoffMs === undefined
|
|
50
|
+
? {}
|
|
51
|
+
: { minBackoffMs: options.minBackoffMs }),
|
|
52
|
+
...(options.maxBackoffMs === undefined
|
|
53
|
+
? {}
|
|
54
|
+
: { maxBackoffMs: options.maxBackoffMs }),
|
|
55
|
+
...(options.heartbeatMs === undefined
|
|
56
|
+
? {}
|
|
57
|
+
: { heartbeatMs: options.heartbeatMs }),
|
|
58
|
+
...(options.openTimeoutMs === undefined
|
|
59
|
+
? {}
|
|
60
|
+
: { connectTimeoutMs: options.openTimeoutMs }),
|
|
61
|
+
...(options.refreshBeforeExpiryMs === undefined
|
|
62
|
+
? {}
|
|
63
|
+
: { refreshBeforeExpiryMs: options.refreshBeforeExpiryMs }),
|
|
64
|
+
});
|
|
65
|
+
this.#socket.on("event", (event) => {
|
|
66
|
+
const lifecycle = lifecycleEventFrom({
|
|
67
|
+
type: "event",
|
|
68
|
+
event: event.event,
|
|
69
|
+
callId: event.callId,
|
|
70
|
+
payload: event.payload,
|
|
71
|
+
timestamp: event.timestamp,
|
|
72
|
+
});
|
|
73
|
+
if (lifecycle === undefined)
|
|
74
|
+
return;
|
|
75
|
+
for (const listener of [...this.#lifecycle])
|
|
76
|
+
listener(lifecycle);
|
|
77
|
+
});
|
|
78
|
+
this.#socket.on("candidate", ({ callId, candidate, connectionId }) => {
|
|
79
|
+
for (const listener of [...this.#candidates])
|
|
80
|
+
listener(callId, candidate, connectionId);
|
|
81
|
+
});
|
|
82
|
+
this.#socket.on("state", (connected) => {
|
|
83
|
+
for (const listener of [...this.#state])
|
|
84
|
+
listener(connected);
|
|
85
|
+
});
|
|
86
|
+
this.#socket.on("error", (error) => this.#emitError(error));
|
|
87
|
+
}
|
|
88
|
+
/** True while an authenticated socket is open. */
|
|
89
|
+
get connected() {
|
|
90
|
+
return this.#socket?.connected ?? false;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Open the socket; resolves after the first attempt settles (authenticated,
|
|
94
|
+
* failed, or {@link close} called meanwhile).
|
|
95
|
+
*/
|
|
96
|
+
async connect() {
|
|
97
|
+
if (this.#socket === undefined) {
|
|
98
|
+
// Not a failure that retrying can fix.
|
|
99
|
+
this.#emitError({
|
|
100
|
+
code: "unsupported",
|
|
101
|
+
message: "The signaling client cannot authenticate the calls socket.",
|
|
102
|
+
});
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
await this.#socket.connect();
|
|
106
|
+
}
|
|
107
|
+
/** Close the socket and stop reconnecting. */
|
|
108
|
+
close() {
|
|
109
|
+
this.#socket?.close();
|
|
110
|
+
}
|
|
111
|
+
/** Lifecycle source for {@link CallsBackend.subscribe}. */
|
|
112
|
+
subscribe(listener) {
|
|
113
|
+
this.#lifecycle.add(listener);
|
|
114
|
+
return () => this.#lifecycle.delete(listener);
|
|
115
|
+
}
|
|
116
|
+
/** Remote ICE candidates pushed by the pod. */
|
|
117
|
+
onCandidate(listener) {
|
|
118
|
+
this.#candidates.add(listener);
|
|
119
|
+
return () => this.#candidates.delete(listener);
|
|
120
|
+
}
|
|
121
|
+
/** Authenticated connection state changes (true = ready). */
|
|
122
|
+
onState(listener) {
|
|
123
|
+
this.#state.add(listener);
|
|
124
|
+
return () => this.#state.delete(listener);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Failures worth surfacing: server `error` frames, `token_failed`,
|
|
128
|
+
* `connect_timeout`, `unauthorized` (a 4401 close), and `unsupported`.
|
|
129
|
+
* Only `unsupported` stops the socket. For a revoked credential your token
|
|
130
|
+
* provider decides: throw from it, or call {@link close}.
|
|
131
|
+
*/
|
|
132
|
+
onError(listener) {
|
|
133
|
+
this.#errors.add(listener);
|
|
134
|
+
return () => this.#errors.delete(listener);
|
|
135
|
+
}
|
|
136
|
+
/** Send a local ICE candidate; false while the socket is not ready (use REST). */
|
|
137
|
+
sendCandidate(callId, candidate, connectionId) {
|
|
138
|
+
return (this.#socket?.sendCandidate(callId, connectionId, candidate) ?? false);
|
|
139
|
+
}
|
|
140
|
+
#emitError(error) {
|
|
141
|
+
for (const listener of [...this.#errors])
|
|
142
|
+
listener(error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function unsupported(method) {
|
|
146
|
+
if (method === undefined)
|
|
147
|
+
throw new Error("The signaling client cannot authenticate the calls socket.");
|
|
148
|
+
return method;
|
|
149
|
+
}
|
|
150
|
+
/** Parse one server frame; unknown or malformed frames yield `undefined`. */
|
|
151
|
+
export function parseCallsSocketMessage(data) {
|
|
152
|
+
return parseLifecycleFrame(data);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Map a pushed `call.*` event onto the controller's lifecycle vocabulary. The
|
|
156
|
+
* number wins over the public ID. Outgoing offers are the browser's own.
|
|
157
|
+
*/
|
|
158
|
+
/** The capability flags a payload actually reports, if any. */
|
|
159
|
+
function reportedCapabilities(value) {
|
|
160
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
161
|
+
return undefined;
|
|
162
|
+
const reported = value;
|
|
163
|
+
const flags = {
|
|
164
|
+
...(typeof reported["video"] === "boolean"
|
|
165
|
+
? { video: reported["video"] }
|
|
166
|
+
: {}),
|
|
167
|
+
...(typeof reported["invite"] === "boolean"
|
|
168
|
+
? { invite: reported["invite"] }
|
|
169
|
+
: {}),
|
|
170
|
+
};
|
|
171
|
+
return Object.keys(flags).length === 0 ? undefined : flags;
|
|
172
|
+
}
|
|
173
|
+
export function lifecycleEventFrom(message) {
|
|
174
|
+
const payload = (message.payload ?? {});
|
|
175
|
+
switch (message.event) {
|
|
176
|
+
case "call.received": {
|
|
177
|
+
if (payload.direction === "outgoing")
|
|
178
|
+
return undefined;
|
|
179
|
+
return {
|
|
180
|
+
type: "incomingCall",
|
|
181
|
+
call: {
|
|
182
|
+
callId: message.callId,
|
|
183
|
+
from: peerFrom(payload.from),
|
|
184
|
+
video: payload.hasVideo === true || payload.has_video === true,
|
|
185
|
+
capabilities: capabilitiesFrom(payload.capabilities),
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
case "call.accepted": {
|
|
190
|
+
const answeredBy = payload.answeredBy;
|
|
191
|
+
const capabilities = reportedCapabilities(payload.capabilities);
|
|
192
|
+
return {
|
|
193
|
+
type: "accepted",
|
|
194
|
+
callId: message.callId,
|
|
195
|
+
...(typeof answeredBy === "string" && answeredBy.length > 0
|
|
196
|
+
? { answeredBy }
|
|
197
|
+
: {}),
|
|
198
|
+
exclusive: payload.exclusive === true,
|
|
199
|
+
// Reported fields only: the controller merges them with what the
|
|
200
|
+
// call already has, so a partial report cannot flip the other flag.
|
|
201
|
+
...(capabilities === undefined ? {} : { capabilities }),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
case "call.ended": {
|
|
205
|
+
const reason = endReasonFrom(payload.reason);
|
|
206
|
+
return reason === undefined
|
|
207
|
+
? { type: "ended", callId: message.callId }
|
|
208
|
+
: { type: "ended", callId: message.callId, reason };
|
|
209
|
+
}
|
|
210
|
+
case "call.missed":
|
|
211
|
+
return { type: "ended", callId: message.callId, reason: "missed" };
|
|
212
|
+
case "call.rejected":
|
|
213
|
+
return { type: "ended", callId: message.callId, reason: "rejected" };
|
|
214
|
+
case "call.participant_joined":
|
|
215
|
+
case "call.participant_state": {
|
|
216
|
+
if (payload.callId !== message.callId)
|
|
217
|
+
return undefined;
|
|
218
|
+
const participant = payload.participant;
|
|
219
|
+
if (!isParticipant(participant))
|
|
220
|
+
return undefined;
|
|
221
|
+
return participant.state === "left"
|
|
222
|
+
? {
|
|
223
|
+
type: "participantLeft",
|
|
224
|
+
callId: message.callId,
|
|
225
|
+
participantId: participant.id,
|
|
226
|
+
}
|
|
227
|
+
: { type: "participant", callId: message.callId, participant };
|
|
228
|
+
}
|
|
229
|
+
case "call.participant_left": {
|
|
230
|
+
if (payload.callId !== message.callId)
|
|
231
|
+
return undefined;
|
|
232
|
+
const participantId = payload.participantId;
|
|
233
|
+
if (typeof participantId !== "string" || participantId.length === 0)
|
|
234
|
+
return undefined;
|
|
235
|
+
return { type: "participantLeft", callId: message.callId, participantId };
|
|
236
|
+
}
|
|
237
|
+
default:
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function peerFrom(value) {
|
|
242
|
+
if (typeof value === "string")
|
|
243
|
+
return value;
|
|
244
|
+
if (value === null || typeof value !== "object")
|
|
245
|
+
return "";
|
|
246
|
+
const ref = value;
|
|
247
|
+
for (const candidate of [ref.phoneNumber, ref.id])
|
|
248
|
+
if (typeof candidate === "string" && candidate.length > 0)
|
|
249
|
+
return candidate;
|
|
250
|
+
return "";
|
|
251
|
+
}
|
|
252
|
+
function endReasonFrom(value) {
|
|
253
|
+
if (typeof value !== "string" || value.length === 0)
|
|
254
|
+
return undefined;
|
|
255
|
+
switch (value) {
|
|
256
|
+
case "user_hangup":
|
|
257
|
+
return "remote_hangup";
|
|
258
|
+
case "setup_timeout":
|
|
259
|
+
case "media_timeout":
|
|
260
|
+
return "ice_timeout";
|
|
261
|
+
case "lost_connection":
|
|
262
|
+
return "connection_failed";
|
|
263
|
+
default:
|
|
264
|
+
return value;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=socket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket.js","sourceRoot":"","sources":["../../src/calls/socket.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ObservableController, type ControllerSnapshot } from "../controller.js";
|
|
2
|
+
import type { ConversationController, MessageAttachment } from "./conversation.js";
|
|
3
|
+
export interface LocalAttachment {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly size: number;
|
|
7
|
+
readonly contentType: string;
|
|
8
|
+
/** The picked or pasted bytes, for `ComposerActions.upload` to read. */
|
|
9
|
+
readonly file?: Blob;
|
|
10
|
+
}
|
|
11
|
+
/** Describe a picked, pasted, or dropped file as a composer attachment. */
|
|
12
|
+
export declare function localAttachmentFromFile(file: File, createId?: () => string): LocalAttachment;
|
|
13
|
+
export interface ComposerAttachment extends LocalAttachment {
|
|
14
|
+
readonly status: "uploading" | "ready" | "failed";
|
|
15
|
+
readonly progress: number;
|
|
16
|
+
readonly uploaded?: MessageAttachment;
|
|
17
|
+
readonly error?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ComposerDraft {
|
|
20
|
+
readonly text: string;
|
|
21
|
+
readonly replyTo?: string;
|
|
22
|
+
readonly attachments: readonly MessageAttachment[];
|
|
23
|
+
}
|
|
24
|
+
export interface ComposerActions {
|
|
25
|
+
upload(attachment: LocalAttachment, onProgress: (progress: number) => void, signal: AbortSignal): Promise<MessageAttachment>;
|
|
26
|
+
send(draft: ComposerDraft, signal: AbortSignal): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Composer actions that send through a conversation, so the composer and the
|
|
30
|
+
* message list share one optimistic history. `upload` stays yours: it turns
|
|
31
|
+
* the local bytes into a hosted `MessageAttachment`.
|
|
32
|
+
*/
|
|
33
|
+
export declare function createConversationComposerActions(conversation: ConversationController, upload: ComposerActions["upload"]): ComposerActions;
|
|
34
|
+
export interface MessageComposerSnapshot extends ControllerSnapshot {
|
|
35
|
+
readonly status: "ready" | "error";
|
|
36
|
+
readonly text: string;
|
|
37
|
+
readonly replyTo?: string;
|
|
38
|
+
readonly attachments: readonly ComposerAttachment[];
|
|
39
|
+
readonly sending: boolean;
|
|
40
|
+
readonly error?: string;
|
|
41
|
+
}
|
|
42
|
+
export interface MessageComposerOptions {
|
|
43
|
+
readonly maxTextLength?: number;
|
|
44
|
+
readonly maxAttachmentSize?: number;
|
|
45
|
+
readonly now?: () => number;
|
|
46
|
+
}
|
|
47
|
+
export declare class MessageComposerController extends ObservableController<MessageComposerSnapshot> {
|
|
48
|
+
#private;
|
|
49
|
+
constructor(actions: ComposerActions, options?: MessageComposerOptions);
|
|
50
|
+
setText(text: string): void;
|
|
51
|
+
setReplyTo(replyTo?: string): void;
|
|
52
|
+
addAttachment(attachment: LocalAttachment): Promise<void>;
|
|
53
|
+
cancelAttachment(id: string): void;
|
|
54
|
+
submit(): Promise<void>;
|
|
55
|
+
cancelSend(): void;
|
|
56
|
+
reset(): void;
|
|
57
|
+
protected onDispose(): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=composer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/chat/composer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC;CACtB;AAED,2EAA2E;AAC3E,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,IAAI,EACV,QAAQ,GAAE,MAAM,MAAkC,GACjD,eAAe,CAQjB;AAED,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CACJ,UAAU,EAAE,eAAe,EAC3B,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,EACtC,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChE;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,YAAY,EAAE,sBAAsB,EACpC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,GAChC,eAAe,CAejB;AAED,MAAM,WAAW,uBAAwB,SAAQ,kBAAkB;IACjE,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACpD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED,qBAAa,yBAA0B,SAAQ,oBAAoB,CAAC,uBAAuB,CAAC;;gBAO9E,OAAO,EAAE,eAAe,EAAE,OAAO,GAAE,sBAA2B;IAU1E,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI3B,UAAU,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAI5B,aAAa,CAAC,UAAU,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC/D,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAU5B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAuD7B,UAAU,IAAI,IAAI;IAOlB,KAAK,IAAI,IAAI;cAWM,SAAS,IAAI,IAAI;CAwDrC"}
|