@appstrata/protocol 0.1.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 +106 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +5 -0
- package/dist/client/proxy.d.ts +72 -0
- package/dist/client/proxy.d.ts.map +1 -0
- package/dist/client/proxy.js +446 -0
- package/dist/client/rpc.d.ts +62 -0
- package/dist/client/rpc.d.ts.map +1 -0
- package/dist/client/rpc.js +138 -0
- package/dist/host/index.d.ts +5 -0
- package/dist/host/index.d.ts.map +1 -0
- package/dist/host/index.js +4 -0
- package/dist/host/message-bridge.d.ts +146 -0
- package/dist/host/message-bridge.d.ts.map +1 -0
- package/dist/host/message-bridge.js +360 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/messages.d.ts +197 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +141 -0
- package/dist/transport/http/client-polling.d.ts +32 -0
- package/dist/transport/http/client-polling.d.ts.map +1 -0
- package/dist/transport/http/client-polling.js +181 -0
- package/dist/transport/http/client-sse.d.ts +30 -0
- package/dist/transport/http/client-sse.d.ts.map +1 -0
- package/dist/transport/http/client-sse.js +155 -0
- package/dist/transport/http/host-manager.d.ts +63 -0
- package/dist/transport/http/host-manager.d.ts.map +1 -0
- package/dist/transport/http/host-manager.js +74 -0
- package/dist/transport/http/host-polling.d.ts +65 -0
- package/dist/transport/http/host-polling.d.ts.map +1 -0
- package/dist/transport/http/host-polling.js +143 -0
- package/dist/transport/http/host-sse.d.ts +56 -0
- package/dist/transport/http/host-sse.d.ts.map +1 -0
- package/dist/transport/http/host-sse.js +149 -0
- package/dist/transport/http/index.d.ts +13 -0
- package/dist/transport/http/index.d.ts.map +1 -0
- package/dist/transport/http/index.js +12 -0
- package/dist/transport/http/types.d.ts +73 -0
- package/dist/transport/http/types.d.ts.map +1 -0
- package/dist/transport/http/types.js +8 -0
- package/dist/transport/index.d.ts +33 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +37 -0
- package/dist/transport/postMessage.d.ts +70 -0
- package/dist/transport/postMessage.d.ts.map +1 -0
- package/dist/transport/postMessage.js +94 -0
- package/dist/transport/relay.d.ts +118 -0
- package/dist/transport/relay.d.ts.map +1 -0
- package/dist/transport/relay.js +216 -0
- package/dist/transport/types.d.ts +30 -0
- package/dist/transport/types.d.ts.map +1 -0
- package/dist/transport/types.js +6 -0
- package/package.json +60 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC (Request/Response) layer for capability operations.
|
|
3
|
+
*
|
|
4
|
+
* Handles sending requests and matching responses.
|
|
5
|
+
*/
|
|
6
|
+
import type { Transport } from "../transport/index.js";
|
|
7
|
+
/**
|
|
8
|
+
* RPC client for sending requests to the host.
|
|
9
|
+
*
|
|
10
|
+
* Manages request/response correlation and timeouts.
|
|
11
|
+
*/
|
|
12
|
+
export declare class RpcClient {
|
|
13
|
+
private transport;
|
|
14
|
+
private pending;
|
|
15
|
+
private defaultTimeout;
|
|
16
|
+
private readyPromise;
|
|
17
|
+
private unsubscribe?;
|
|
18
|
+
/**
|
|
19
|
+
* Create an RPC client.
|
|
20
|
+
*
|
|
21
|
+
* @param transport - Transport for sending/receiving messages
|
|
22
|
+
* @param readyPromise - Promise that resolves when the handshake is complete.
|
|
23
|
+
* Per spec §2.2, REQUESTs must not be sent before READY/READY_ACK.
|
|
24
|
+
* @param options - RPC options
|
|
25
|
+
*/
|
|
26
|
+
constructor(transport: Transport, readyPromise: Promise<void>, options?: {
|
|
27
|
+
defaultTimeout?: number;
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Send a notification (fire-and-forget request, no response expected).
|
|
31
|
+
*
|
|
32
|
+
* The REQUEST is sent without a `requestId`, signalling to the Host
|
|
33
|
+
* that no RESPONSE should be sent (spec §4.4).
|
|
34
|
+
*
|
|
35
|
+
* @param op - Operation name
|
|
36
|
+
* @param payload - Operation payload
|
|
37
|
+
*/
|
|
38
|
+
notify(op: string, payload?: unknown): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Send a request and wait for response.
|
|
41
|
+
*
|
|
42
|
+
* @param op - Operation name
|
|
43
|
+
* @param payload - Operation payload
|
|
44
|
+
* @param timeout - Request timeout in milliseconds (default: 30000)
|
|
45
|
+
* @returns Promise that resolves with the result
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const result = await rpc.call("storage.get", { key: "myKey" });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
call(op: string, payload?: unknown, timeout?: number): Promise<unknown>;
|
|
53
|
+
/**
|
|
54
|
+
* Handle response message.
|
|
55
|
+
*/
|
|
56
|
+
private handleResponse;
|
|
57
|
+
/**
|
|
58
|
+
* Close the RPC client and cancel all pending requests.
|
|
59
|
+
*/
|
|
60
|
+
close(): void;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=rpc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc.d.ts","sourceRoot":"","sources":["../../src/client/rpc.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAavD;;;;GAIG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,WAAW,CAAC,CAAa;IAEjC;;;;;;;OAOG;gBAED,SAAS,EAAE,SAAS,EACpB,YAAY,EAAE,OAAO,CAAC,IAAI,CAAC,EAC3B,OAAO,GAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAO;IAc3C;;;;;;;;OAQG;IACG,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAe1D;;;;;;;;;;;;OAYG;IACG,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgC7E;;OAEG;IACH,OAAO,CAAC,cAAc;IA2BtB;;OAEG;IACH,KAAK,IAAI,IAAI;CAiBd"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RPC (Request/Response) layer for capability operations.
|
|
3
|
+
*
|
|
4
|
+
* Handles sending requests and matching responses.
|
|
5
|
+
*/
|
|
6
|
+
import { generateRequestId, isResponseMessage } from "../messages.js";
|
|
7
|
+
/**
|
|
8
|
+
* RPC client for sending requests to the host.
|
|
9
|
+
*
|
|
10
|
+
* Manages request/response correlation and timeouts.
|
|
11
|
+
*/
|
|
12
|
+
export class RpcClient {
|
|
13
|
+
/**
|
|
14
|
+
* Create an RPC client.
|
|
15
|
+
*
|
|
16
|
+
* @param transport - Transport for sending/receiving messages
|
|
17
|
+
* @param readyPromise - Promise that resolves when the handshake is complete.
|
|
18
|
+
* Per spec §2.2, REQUESTs must not be sent before READY/READY_ACK.
|
|
19
|
+
* @param options - RPC options
|
|
20
|
+
*/
|
|
21
|
+
constructor(transport, readyPromise, options = {}) {
|
|
22
|
+
this.pending = new Map();
|
|
23
|
+
this.transport = transport;
|
|
24
|
+
this.readyPromise = readyPromise;
|
|
25
|
+
this.defaultTimeout = options.defaultTimeout ?? 30000; // 30 seconds default
|
|
26
|
+
// Listen for responses
|
|
27
|
+
this.unsubscribe = transport.onMessage((msg) => {
|
|
28
|
+
if (isResponseMessage(msg)) {
|
|
29
|
+
this.handleResponse(msg);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Send a notification (fire-and-forget request, no response expected).
|
|
35
|
+
*
|
|
36
|
+
* The REQUEST is sent without a `requestId`, signalling to the Host
|
|
37
|
+
* that no RESPONSE should be sent (spec §4.4).
|
|
38
|
+
*
|
|
39
|
+
* @param op - Operation name
|
|
40
|
+
* @param payload - Operation payload
|
|
41
|
+
*/
|
|
42
|
+
async notify(op, payload) {
|
|
43
|
+
await this.readyPromise;
|
|
44
|
+
const request = {
|
|
45
|
+
protocol: "appstrata-protocol",
|
|
46
|
+
version: "1.0",
|
|
47
|
+
type: "REQUEST",
|
|
48
|
+
timestamp: Date.now(),
|
|
49
|
+
op,
|
|
50
|
+
payload
|
|
51
|
+
};
|
|
52
|
+
this.transport.send(request);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Send a request and wait for response.
|
|
56
|
+
*
|
|
57
|
+
* @param op - Operation name
|
|
58
|
+
* @param payload - Operation payload
|
|
59
|
+
* @param timeout - Request timeout in milliseconds (default: 30000)
|
|
60
|
+
* @returns Promise that resolves with the result
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* const result = await rpc.call("storage.get", { key: "myKey" });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
async call(op, payload, timeout) {
|
|
68
|
+
// Spec §2.2: Apps MUST NOT send REQUEST messages until handshake is complete
|
|
69
|
+
await this.readyPromise;
|
|
70
|
+
const requestId = generateRequestId();
|
|
71
|
+
const timeoutMs = timeout ?? this.defaultTimeout;
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
// Set up timeout
|
|
74
|
+
const timeoutId = setTimeout(() => {
|
|
75
|
+
this.pending.delete(requestId);
|
|
76
|
+
reject(new Error(`RPC timeout after ${timeoutMs}ms for operation: ${op}`));
|
|
77
|
+
}, timeoutMs);
|
|
78
|
+
// Store pending request
|
|
79
|
+
this.pending.set(requestId, { resolve, reject, timeoutId });
|
|
80
|
+
// Send request
|
|
81
|
+
const request = {
|
|
82
|
+
protocol: "appstrata-protocol",
|
|
83
|
+
version: "1.0",
|
|
84
|
+
type: "REQUEST",
|
|
85
|
+
timestamp: Date.now(),
|
|
86
|
+
requestId,
|
|
87
|
+
op,
|
|
88
|
+
payload
|
|
89
|
+
};
|
|
90
|
+
this.transport.send(request);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Handle response message.
|
|
95
|
+
*/
|
|
96
|
+
handleResponse(msg) {
|
|
97
|
+
const pending = this.pending.get(msg.requestId);
|
|
98
|
+
if (!pending) {
|
|
99
|
+
// No pending request for this response (maybe already timed out)
|
|
100
|
+
console.warn("[AppStrata] Received response for unknown request:", msg.requestId);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
// Clear timeout
|
|
104
|
+
if (pending.timeoutId) {
|
|
105
|
+
clearTimeout(pending.timeoutId);
|
|
106
|
+
}
|
|
107
|
+
// Remove from pending
|
|
108
|
+
this.pending.delete(msg.requestId);
|
|
109
|
+
// Resolve or reject
|
|
110
|
+
if (msg.ok) {
|
|
111
|
+
pending.resolve(msg.result);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
const error = new Error(msg.error?.message || "RPC call failed");
|
|
115
|
+
error.code = msg.error?.code;
|
|
116
|
+
error.details = msg.error?.details;
|
|
117
|
+
pending.reject(error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Close the RPC client and cancel all pending requests.
|
|
122
|
+
*/
|
|
123
|
+
close() {
|
|
124
|
+
// Unsubscribe from transport
|
|
125
|
+
if (this.unsubscribe) {
|
|
126
|
+
this.unsubscribe();
|
|
127
|
+
this.unsubscribe = undefined;
|
|
128
|
+
}
|
|
129
|
+
// Cancel all pending requests
|
|
130
|
+
for (const [, pending] of this.pending) {
|
|
131
|
+
if (pending.timeoutId) {
|
|
132
|
+
clearTimeout(pending.timeoutId);
|
|
133
|
+
}
|
|
134
|
+
pending.reject(new Error("RPC client closed"));
|
|
135
|
+
}
|
|
136
|
+
this.pending.clear();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/host/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MessageBridge - Host-side message protocol bridge.
|
|
3
|
+
*
|
|
4
|
+
* Bridges communication between the player and app via the message protocol.
|
|
5
|
+
* Handles the HELLO/READY/READY_ACK handshake and subsequent RPC/event communication.
|
|
6
|
+
*
|
|
7
|
+
* Key responsibilities:
|
|
8
|
+
* - Listen for HELLO messages from apps
|
|
9
|
+
* - Send READY messages with AppContext
|
|
10
|
+
* - Retry READY until READY_ACK received (if HELLO not received)
|
|
11
|
+
* - Handle REQUEST messages and send RESPONSE
|
|
12
|
+
* - Fire lifecycle EVENT messages
|
|
13
|
+
*/
|
|
14
|
+
import { type AppContext, type SignagePlayer } from "@appstrata/core";
|
|
15
|
+
import type { Transport } from "../transport/index.js";
|
|
16
|
+
export interface MessageBridgeConfig {
|
|
17
|
+
/**
|
|
18
|
+
* Transport for sending/receiving messages.
|
|
19
|
+
*/
|
|
20
|
+
transport: Transport;
|
|
21
|
+
/**
|
|
22
|
+
* SignagePlayer instance to delegate RPC calls to.
|
|
23
|
+
* RPC requests will be routed to the player's API methods.
|
|
24
|
+
*/
|
|
25
|
+
player: SignagePlayer;
|
|
26
|
+
/**
|
|
27
|
+
* Must return the current AppContext.
|
|
28
|
+
* Called when READY needs to be sent.
|
|
29
|
+
*/
|
|
30
|
+
getContext: () => Promise<AppContext>;
|
|
31
|
+
/**
|
|
32
|
+
* READY retry interval in milliseconds.
|
|
33
|
+
* @default 1000 (1 second)
|
|
34
|
+
*/
|
|
35
|
+
retryInterval?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Maximum number of READY retries.
|
|
38
|
+
* @default 10
|
|
39
|
+
*/
|
|
40
|
+
maxRetries?: number;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* MessageBridge - Host-side protocol bridge.
|
|
44
|
+
*
|
|
45
|
+
* **Single-session:** one `MessageBridge` instance covers one App page load.
|
|
46
|
+
* Once the handshake completes (`receivedReadyAck = true`), the bridge enters
|
|
47
|
+
* the ACTIVE state and does not reset. When the App reloads, the old bridge
|
|
48
|
+
* must be destroyed and a new one created.
|
|
49
|
+
*
|
|
50
|
+
* Bridges the player to apps via the message protocol.
|
|
51
|
+
*
|
|
52
|
+
* Usage:
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const bridge = new MessageBridge({
|
|
55
|
+
* transport: createPostMessageTransport({ targetWindow: iframe.contentWindow!, targetOrigin: "*" }),
|
|
56
|
+
* player: myPlayer,
|
|
57
|
+
* getContext: async () => buildAppContext(),
|
|
58
|
+
* });
|
|
59
|
+
*
|
|
60
|
+
* // Start the handshake (sends READY)
|
|
61
|
+
* bridge.start();
|
|
62
|
+
*
|
|
63
|
+
* // Send lifecycle events
|
|
64
|
+
* bridge.fireShow();
|
|
65
|
+
* bridge.fireStart();
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare class MessageBridge {
|
|
69
|
+
private config;
|
|
70
|
+
private transport;
|
|
71
|
+
private receivedHello;
|
|
72
|
+
private receivedReadyAck;
|
|
73
|
+
private helloRequestId?;
|
|
74
|
+
private retryTimer?;
|
|
75
|
+
private retryCount;
|
|
76
|
+
private started;
|
|
77
|
+
private unsubscribeFromTransport?;
|
|
78
|
+
private pendingEvents;
|
|
79
|
+
constructor(config: MessageBridgeConfig);
|
|
80
|
+
/**
|
|
81
|
+
* Start the bridge (send initial READY message).
|
|
82
|
+
*/
|
|
83
|
+
start(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Handle HELLO message from app.
|
|
86
|
+
*/
|
|
87
|
+
private handleHello;
|
|
88
|
+
/**
|
|
89
|
+
* Handle READY_ACK message from app.
|
|
90
|
+
*/
|
|
91
|
+
private handleReadyAck;
|
|
92
|
+
/**
|
|
93
|
+
* Flush pending events that were queued before READY_ACK.
|
|
94
|
+
*/
|
|
95
|
+
private flushPendingEvents;
|
|
96
|
+
/**
|
|
97
|
+
* Handle REQUEST message from app.
|
|
98
|
+
*/
|
|
99
|
+
private handleRequest;
|
|
100
|
+
/**
|
|
101
|
+
* Handle request by routing to player API.
|
|
102
|
+
*/
|
|
103
|
+
private handlePlayerRequest;
|
|
104
|
+
/**
|
|
105
|
+
* Helper to check capability availability.
|
|
106
|
+
*/
|
|
107
|
+
private requireCapability;
|
|
108
|
+
/**
|
|
109
|
+
* Send latest AppContext as READY message to app.
|
|
110
|
+
*
|
|
111
|
+
* Awaits the AppContext to be available.
|
|
112
|
+
* If proactive is true, and HELLO arrives by the time the context is available,
|
|
113
|
+
* no READY is sent.
|
|
114
|
+
*
|
|
115
|
+
* @param reason - The phase at which the READY message is being sent. Only used for logging.
|
|
116
|
+
*/
|
|
117
|
+
private sendReady;
|
|
118
|
+
/**
|
|
119
|
+
* Schedule next retry for READY messages.
|
|
120
|
+
*/
|
|
121
|
+
private scheduleNextRetry;
|
|
122
|
+
/**
|
|
123
|
+
* Cancel the next retry for READY messages.
|
|
124
|
+
*/
|
|
125
|
+
private cancelNextRetry;
|
|
126
|
+
/**
|
|
127
|
+
* Send an EVENT message through the transport.
|
|
128
|
+
* If the handshake is not yet complete (READY_ACK not received), the event
|
|
129
|
+
* is queued and will be flushed when READY_ACK arrives.
|
|
130
|
+
*/
|
|
131
|
+
private sendEventMessage;
|
|
132
|
+
fireShow(): void;
|
|
133
|
+
fireStart(): void;
|
|
134
|
+
fireHide(): void;
|
|
135
|
+
fireStop(): void;
|
|
136
|
+
fireContextChange(context: AppContext): void;
|
|
137
|
+
/**
|
|
138
|
+
* Cleanup.
|
|
139
|
+
*
|
|
140
|
+
* Unsubscribes from the transport but does NOT close it.
|
|
141
|
+
* The transport lifecycle is owned by whoever created it
|
|
142
|
+
* (e.g., the session manager), not by the bridge.
|
|
143
|
+
*/
|
|
144
|
+
destroy(): void;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=message-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-bridge.d.ts","sourceRoot":"","sources":["../../src/host/message-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAmC,KAAK,UAAU,EAAE,KAAK,aAAa,EAA0B,MAAM,iBAAiB,CAAC;AAG/H,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAkBvD,MAAM,WAAW,mBAAmB;IAElC;;OAEG;IACH,SAAS,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,MAAM,EAAE,aAAa,CAAC;IAEtB;;;OAGG;IACH,UAAU,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IAEtC;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CAErB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA4E;IAC1F,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,UAAU,CAAC,CAAgC;IACnD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,wBAAwB,CAAC,CAAa;IAC9C,OAAO,CAAC,aAAa,CAAsB;gBAE/B,MAAM,EAAE,mBAAmB;IAqBvC;;OAEG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACH,OAAO,CAAC,WAAW;IAoBnB;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAQ1B;;OAEG;YACW,aAAa;IAsD3B;;OAEG;YACW,mBAAmB;IAoEjC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAMzB;;;;;;;;OAQG;YACW,SAAS;IAyBvB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAqBzB;;OAEG;IACH,OAAO,CAAC,eAAe;IAOvB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAoBxB,QAAQ,IAAI,IAAI;IAIhB,SAAS,IAAI,IAAI;IAIjB,QAAQ,IAAI,IAAI;IAIhB,QAAQ,IAAI,IAAI;IAIhB,iBAAiB,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;IAK5C;;;;;;OAMG;IACH,OAAO,IAAI,IAAI;CAUhB"}
|