@aomi-labs/client 0.1.2 → 0.1.6
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 +3 -1
- package/dist/cli.js +240 -103
- package/dist/index.cjs +76 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -10
- package/dist/index.d.ts +16 -10
- package/dist/index.js +76 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/aomi-transact/SKILL.md +13 -6
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
AomiClient: () => AomiClient,
|
|
24
|
-
Session: () =>
|
|
24
|
+
Session: () => ClientSession,
|
|
25
25
|
TypedEventEmitter: () => TypedEventEmitter,
|
|
26
26
|
isAsyncCallback: () => isAsyncCallback,
|
|
27
27
|
isInlineCall: () => isInlineCall,
|
|
@@ -275,9 +275,9 @@ var AomiClient = class {
|
|
|
275
275
|
*/
|
|
276
276
|
async sendMessage(sessionId, message, options) {
|
|
277
277
|
var _a, _b;
|
|
278
|
-
const
|
|
278
|
+
const app = (_a = options == null ? void 0 : options.app) != null ? _a : "default";
|
|
279
279
|
const apiKey = (_b = options == null ? void 0 : options.apiKey) != null ? _b : this.apiKey;
|
|
280
|
-
const payload = { message,
|
|
280
|
+
const payload = { message, app };
|
|
281
281
|
if (options == null ? void 0 : options.publicKey) {
|
|
282
282
|
payload.public_key = options.publicKey;
|
|
283
283
|
}
|
|
@@ -450,11 +450,11 @@ var AomiClient = class {
|
|
|
450
450
|
// Control API
|
|
451
451
|
// ===========================================================================
|
|
452
452
|
/**
|
|
453
|
-
* Get available
|
|
453
|
+
* Get available apps.
|
|
454
454
|
*/
|
|
455
|
-
async
|
|
455
|
+
async getApps(sessionId, options) {
|
|
456
456
|
var _a;
|
|
457
|
-
const url = new URL("/api/control/
|
|
457
|
+
const url = new URL("/api/control/apps", this.baseUrl);
|
|
458
458
|
if (options == null ? void 0 : options.publicKey) {
|
|
459
459
|
url.searchParams.set("public_key", options.publicKey);
|
|
460
460
|
}
|
|
@@ -465,7 +465,7 @@ var AomiClient = class {
|
|
|
465
465
|
}
|
|
466
466
|
const response = await fetch(url.toString(), { headers });
|
|
467
467
|
if (!response.ok) {
|
|
468
|
-
throw new Error(`Failed to get
|
|
468
|
+
throw new Error(`Failed to get apps: HTTP ${response.status}`);
|
|
469
469
|
}
|
|
470
470
|
return await response.json();
|
|
471
471
|
}
|
|
@@ -495,8 +495,8 @@ var AomiClient = class {
|
|
|
495
495
|
var _a;
|
|
496
496
|
const apiKey = (_a = options == null ? void 0 : options.apiKey) != null ? _a : this.apiKey;
|
|
497
497
|
const payload = { rig };
|
|
498
|
-
if (options == null ? void 0 : options.
|
|
499
|
-
payload.
|
|
498
|
+
if (options == null ? void 0 : options.app) {
|
|
499
|
+
payload.app = options.app;
|
|
500
500
|
}
|
|
501
501
|
return postState(this.baseUrl, "/api/control/model", payload, sessionId, apiKey);
|
|
502
502
|
}
|
|
@@ -677,7 +677,38 @@ function normalizeEip712Payload(payload) {
|
|
|
677
677
|
}
|
|
678
678
|
|
|
679
679
|
// src/session.ts
|
|
680
|
-
|
|
680
|
+
function sortJson(value) {
|
|
681
|
+
if (Array.isArray(value)) {
|
|
682
|
+
return value.map((entry) => sortJson(entry));
|
|
683
|
+
}
|
|
684
|
+
if (value && typeof value === "object") {
|
|
685
|
+
return Object.keys(value).sort().reduce((acc, key) => {
|
|
686
|
+
acc[key] = sortJson(value[key]);
|
|
687
|
+
return acc;
|
|
688
|
+
}, {});
|
|
689
|
+
}
|
|
690
|
+
return value;
|
|
691
|
+
}
|
|
692
|
+
function isSubsetMatch(expected, actual) {
|
|
693
|
+
if (Array.isArray(expected)) {
|
|
694
|
+
if (!Array.isArray(actual) || expected.length !== actual.length) {
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
return expected.every(
|
|
698
|
+
(entry, index) => isSubsetMatch(entry, actual[index])
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
if (expected && typeof expected === "object") {
|
|
702
|
+
if (!actual || typeof actual !== "object" || Array.isArray(actual)) {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
return Object.entries(expected).every(
|
|
706
|
+
([key, value]) => isSubsetMatch(value, actual[key])
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
return expected === actual;
|
|
710
|
+
}
|
|
711
|
+
var ClientSession = class extends TypedEventEmitter {
|
|
681
712
|
constructor(clientOrOptions, sessionOptions) {
|
|
682
713
|
var _a, _b, _c;
|
|
683
714
|
super();
|
|
@@ -693,7 +724,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
693
724
|
this.pendingResolve = null;
|
|
694
725
|
this.client = clientOrOptions instanceof AomiClient ? clientOrOptions : new AomiClient(clientOrOptions);
|
|
695
726
|
this.sessionId = (_a = sessionOptions == null ? void 0 : sessionOptions.sessionId) != null ? _a : crypto.randomUUID();
|
|
696
|
-
this.
|
|
727
|
+
this.app = (_b = sessionOptions == null ? void 0 : sessionOptions.app) != null ? _b : "default";
|
|
697
728
|
this.publicKey = sessionOptions == null ? void 0 : sessionOptions.publicKey;
|
|
698
729
|
this.apiKey = sessionOptions == null ? void 0 : sessionOptions.apiKey;
|
|
699
730
|
this.userState = sessionOptions == null ? void 0 : sessionOptions.userState;
|
|
@@ -719,11 +750,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
719
750
|
async send(message) {
|
|
720
751
|
this.assertOpen();
|
|
721
752
|
const response = await this.client.sendMessage(this.sessionId, message, {
|
|
722
|
-
|
|
753
|
+
app: this.app,
|
|
723
754
|
publicKey: this.publicKey,
|
|
724
755
|
apiKey: this.apiKey,
|
|
725
756
|
userState: this.userState
|
|
726
757
|
});
|
|
758
|
+
this.assertUserStateAligned(response.user_state);
|
|
727
759
|
this.applyState(response);
|
|
728
760
|
if (!response.is_processing && this.walletRequests.length === 0) {
|
|
729
761
|
return { messages: this._messages, title: this._title };
|
|
@@ -742,11 +774,12 @@ var Session = class extends TypedEventEmitter {
|
|
|
742
774
|
async sendAsync(message) {
|
|
743
775
|
this.assertOpen();
|
|
744
776
|
const response = await this.client.sendMessage(this.sessionId, message, {
|
|
745
|
-
|
|
777
|
+
app: this.app,
|
|
746
778
|
publicKey: this.publicKey,
|
|
747
779
|
apiKey: this.apiKey,
|
|
748
780
|
userState: this.userState
|
|
749
781
|
});
|
|
782
|
+
this.assertUserStateAligned(response.user_state);
|
|
750
783
|
this.applyState(response);
|
|
751
784
|
if (response.is_processing) {
|
|
752
785
|
this._isProcessing = true;
|
|
@@ -859,6 +892,23 @@ var Session = class extends TypedEventEmitter {
|
|
|
859
892
|
getIsProcessing() {
|
|
860
893
|
return this._isProcessing;
|
|
861
894
|
}
|
|
895
|
+
resolveUserState(userState) {
|
|
896
|
+
this.userState = userState;
|
|
897
|
+
const address = userState["address"];
|
|
898
|
+
if (typeof address === "string" && address.length > 0) {
|
|
899
|
+
this.publicKey = address;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
resolveWallet(address, chainId) {
|
|
903
|
+
this.resolveUserState({ address, chainId: chainId != null ? chainId : 1, isConnected: true });
|
|
904
|
+
}
|
|
905
|
+
async syncUserState() {
|
|
906
|
+
this.assertOpen();
|
|
907
|
+
const state = await this.client.fetchState(this.sessionId, this.userState);
|
|
908
|
+
this.assertUserStateAligned(state.user_state);
|
|
909
|
+
this.applyState(state);
|
|
910
|
+
return state;
|
|
911
|
+
}
|
|
862
912
|
// ===========================================================================
|
|
863
913
|
// Internal — Polling (ported from PollingController)
|
|
864
914
|
// ===========================================================================
|
|
@@ -887,6 +937,7 @@ var Session = class extends TypedEventEmitter {
|
|
|
887
937
|
this.userState
|
|
888
938
|
);
|
|
889
939
|
if (!this.pollTimer) return;
|
|
940
|
+
this.assertUserStateAligned(state.user_state);
|
|
890
941
|
this.applyState(state);
|
|
891
942
|
if (!state.is_processing && this.walletRequests.length === 0) {
|
|
892
943
|
this.stopPolling();
|
|
@@ -988,6 +1039,18 @@ var Session = class extends TypedEventEmitter {
|
|
|
988
1039
|
throw new Error("Session is closed");
|
|
989
1040
|
}
|
|
990
1041
|
}
|
|
1042
|
+
assertUserStateAligned(actualUserState) {
|
|
1043
|
+
if (!this.userState || !actualUserState) {
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
if (!isSubsetMatch(this.userState, actualUserState)) {
|
|
1047
|
+
const expected = JSON.stringify(sortJson(this.userState));
|
|
1048
|
+
const actual = JSON.stringify(sortJson(actualUserState));
|
|
1049
|
+
throw new Error(
|
|
1050
|
+
`Backend user_state mismatch. expected subset=${expected} actual=${actual}`
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
991
1054
|
};
|
|
992
1055
|
// Annotate the CommonJS export names for ESM import in node:
|
|
993
1056
|
0 && (module.exports = {
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/sse.ts","../src/client.ts","../src/types.ts","../src/event-emitter.ts","../src/event-unwrap.ts","../src/wallet-utils.ts","../src/session.ts"],"sourcesContent":["// =============================================================================\n// Client\n// =============================================================================\n\nexport { AomiClient } from \"./client\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiCreateThreadResponse,\n AomiInterruptResponse,\n AomiSSEEvent,\n AomiSSEEventType,\n AomiStateResponse,\n AomiSystemEvent,\n AomiSystemResponse,\n AomiThread,\n Logger,\n UserState,\n} from \"./types\";\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport {\n isAsyncCallback,\n isInlineCall,\n isSystemError,\n isSystemNotice,\n} from \"./types\";\n\n// =============================================================================\n// Session (high-level orchestrated client)\n// =============================================================================\n\nexport { Session } from \"./session\";\n\nexport type {\n SessionOptions,\n SessionEventMap,\n SendResult,\n WalletRequest,\n WalletRequestKind,\n WalletRequestResult,\n} from \"./session\";\n\n// =============================================================================\n// Event Utilities\n// =============================================================================\n\nexport { TypedEventEmitter } from \"./event-emitter\";\nexport { unwrapSystemEvent, type UnwrappedEvent } from \"./event-unwrap\";\n\n// =============================================================================\n// Wallet Utilities\n// =============================================================================\n\nexport {\n normalizeTxPayload,\n normalizeEip712Payload,\n} from \"./wallet-utils\";\n\nexport type {\n WalletTxPayload,\n WalletEip712Payload,\n} from \"./wallet-utils\";\n","import type { AomiSSEEvent, Logger } from \"./types\";\n\nexport type SseSubscriber = {\n subscribe: (\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ) => () => void;\n};\n\nexport type SseSubscriberOptions = {\n backendUrl: string;\n getHeaders: (sessionId: string) => HeadersInit;\n logger?: Logger;\n};\n\ntype SseSubscription = {\n abortController: AbortController | null;\n retries: number;\n retryTimer: ReturnType<typeof setTimeout> | null;\n stopped: boolean;\n listeners: Set<SseListener>;\n stop: (reason?: string) => void;\n};\n\ntype SseListener = {\n onUpdate: (event: AomiSSEEvent) => void;\n onError?: (error: unknown) => void;\n};\n\nfunction extractSseData(rawEvent: string): string | null {\n const dataLines = rawEvent\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart());\n if (!dataLines.length) return null;\n return dataLines.join(\"\\n\");\n}\n\nasync function readSseStream(\n stream: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n onMessage: (data: string) => void,\n): Promise<void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (!signal.aborted) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n buffer = buffer.replace(/\\r/g, \"\");\n\n let separatorIndex = buffer.indexOf(\"\\n\\n\");\n while (separatorIndex >= 0) {\n const rawEvent = buffer.slice(0, separatorIndex);\n buffer = buffer.slice(separatorIndex + 2);\n const data = extractSseData(rawEvent);\n if (data) {\n onMessage(data);\n }\n separatorIndex = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function createSseSubscriber({\n backendUrl,\n getHeaders,\n logger,\n}: SseSubscriberOptions): SseSubscriber {\n const subscriptions = new Map<string, SseSubscription>();\n\n const subscribe: SseSubscriber[\"subscribe\"] = (\n sessionId,\n onUpdate,\n onError,\n ) => {\n const existing = subscriptions.get(sessionId);\n const listener: SseListener = { onUpdate, onError };\n if (existing) {\n existing.listeners.add(listener);\n logger?.debug(\"[aomi][sse] listener added\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n return () => {\n existing.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n if (existing.listeners.size === 0) {\n existing.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === existing) {\n subscriptions.delete(sessionId);\n }\n }\n };\n }\n\n const subscription: SseSubscription = {\n abortController: null,\n retries: 0,\n retryTimer: null,\n stopped: false,\n listeners: new Set([listener]),\n stop: (reason?: string) => {\n subscription.stopped = true;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n subscription.abortController?.abort();\n subscription.abortController = null;\n logger?.debug(\"[aomi][sse] stop\", {\n sessionId,\n reason,\n retries: subscription.retries,\n });\n },\n };\n\n const scheduleRetry = () => {\n if (subscription.stopped) return;\n subscription.retries += 1;\n const delayMs = Math.min(500 * 2 ** (subscription.retries - 1), 10000);\n logger?.debug(\"[aomi][sse] retry scheduled\", {\n sessionId,\n delayMs,\n retries: subscription.retries,\n });\n subscription.retryTimer = setTimeout(() => {\n void open();\n }, delayMs);\n };\n\n const open = async () => {\n if (subscription.stopped) return;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n\n const controller = new AbortController();\n subscription.abortController = controller;\n const openedAt = Date.now();\n\n try {\n const response = await fetch(`${backendUrl}/api/updates`, {\n headers: getHeaders(sessionId),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(\n `SSE HTTP ${response.status}: ${response.statusText}`,\n );\n }\n\n if (!response.body) {\n throw new Error(\"SSE response missing body\");\n }\n\n subscription.retries = 0;\n\n await readSseStream(response.body, controller.signal, (data) => {\n let parsed: AomiSSEEvent;\n try {\n parsed = JSON.parse(data) as AomiSSEEvent;\n } catch (error) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n return;\n }\n\n for (const item of subscription.listeners) {\n try {\n item.onUpdate(parsed);\n } catch (error) {\n item.onError?.(error);\n }\n }\n });\n logger?.debug(\"[aomi][sse] stream ended\", {\n sessionId,\n aborted: controller.signal.aborted,\n stopped: subscription.stopped,\n durationMs: Date.now() - openedAt,\n });\n } catch (error) {\n if (!controller.signal.aborted && !subscription.stopped) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n }\n }\n\n if (!subscription.stopped) {\n scheduleRetry();\n }\n };\n\n subscriptions.set(sessionId, subscription);\n void open();\n\n return () => {\n subscription.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: subscription.listeners.size,\n });\n if (subscription.listeners.size === 0) {\n subscription.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === subscription) {\n subscriptions.delete(sessionId);\n }\n }\n };\n };\n\n return { subscribe };\n}\n","import type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiCreateThreadResponse,\n AomiInterruptResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n AomiSystemResponse,\n AomiThread,\n Logger,\n UserState,\n} from \"./types\";\nimport { createSseSubscriber, type SseSubscriber } from \"./sse\";\n\n// =============================================================================\n// Internal helpers\n// =============================================================================\n\nconst SESSION_ID_HEADER = \"X-Session-Id\";\nconst API_KEY_HEADER = \"X-API-Key\";\n\nfunction toQueryString(payload: Record<string, unknown>): string {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined || value === null) continue;\n params.set(key, String(value));\n }\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nfunction withSessionHeader(\n sessionId: string,\n init?: HeadersInit,\n): HeadersInit {\n const headers = new Headers(init);\n headers.set(SESSION_ID_HEADER, sessionId);\n return headers;\n}\n\nasync function postState<T>(\n baseUrl: string,\n path: string,\n payload: Record<string, unknown>,\n sessionId: string,\n apiKey?: string,\n): Promise<T> {\n const query = toQueryString(payload);\n const url = `${baseUrl}${path}${query}`;\n\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as T;\n}\n\n// =============================================================================\n// AomiClient\n// =============================================================================\n\nexport class AomiClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly logger?: Logger;\n private readonly sseSubscriber: SseSubscriber;\n\n constructor(options: AomiClientOptions) {\n // Strip trailing slash\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.logger = options.logger;\n\n this.sseSubscriber = createSseSubscriber({\n backendUrl: this.baseUrl,\n getHeaders: (sessionId) =>\n withSessionHeader(sessionId, { Accept: \"text/event-stream\" }),\n logger: this.logger,\n });\n }\n\n // ===========================================================================\n // Chat & State\n // ===========================================================================\n\n /**\n * Fetch current session state (messages, processing status, title).\n */\n async fetchState(\n sessionId: string,\n userState?: UserState,\n ): Promise<AomiStateResponse> {\n const url = new URL(\"/api/state\", this.baseUrl);\n if (userState) {\n url.searchParams.set(\"user_state\", JSON.stringify(userState));\n }\n\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiStateResponse;\n }\n\n /**\n * Send a chat message and return updated session state.\n */\n async sendMessage(\n sessionId: string,\n message: string,\n options?: {\n namespace?: string;\n publicKey?: string;\n apiKey?: string;\n userState?: UserState;\n },\n ): Promise<AomiChatResponse> {\n const namespace = options?.namespace ?? \"default\";\n const apiKey = options?.apiKey ?? this.apiKey;\n\n const payload: Record<string, unknown> = { message, namespace };\n if (options?.publicKey) {\n payload.public_key = options.publicKey;\n }\n if (options?.userState) {\n payload.user_state = JSON.stringify(options.userState);\n }\n\n return postState<AomiChatResponse>(\n this.baseUrl,\n \"/api/chat\",\n payload,\n sessionId,\n apiKey,\n );\n }\n\n /**\n * Send a system-level message (e.g. wallet state changes, context switches).\n */\n async sendSystemMessage(\n sessionId: string,\n message: string,\n ): Promise<AomiSystemResponse> {\n return postState<AomiSystemResponse>(\n this.baseUrl,\n \"/api/system\",\n { message },\n sessionId,\n );\n }\n\n /**\n * Interrupt the AI's current response.\n */\n async interrupt(sessionId: string): Promise<AomiInterruptResponse> {\n return postState<AomiInterruptResponse>(\n this.baseUrl,\n \"/api/interrupt\",\n {},\n sessionId,\n );\n }\n\n // ===========================================================================\n // SSE (Real-time Updates)\n // ===========================================================================\n\n /**\n * Subscribe to real-time SSE updates for a session.\n * Automatically reconnects with exponential backoff on disconnects.\n * Returns an unsubscribe function.\n */\n subscribeSSE(\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ): () => void {\n return this.sseSubscriber.subscribe(sessionId, onUpdate, onError);\n }\n\n // ===========================================================================\n // Thread / Session Management\n // ===========================================================================\n\n /**\n * List all threads for a wallet address.\n */\n async listThreads(publicKey: string): Promise<AomiThread[]> {\n const url = `${this.baseUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch threads: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiThread[];\n }\n\n /**\n * Get a single thread by ID.\n */\n async getThread(sessionId: string): Promise<AomiThread> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiThread;\n }\n\n /**\n * Create a new thread. The client generates the session ID.\n */\n async createThread(\n threadId: string,\n publicKey?: string,\n ): Promise<AomiCreateThreadResponse> {\n const body: Record<string, string> = {};\n if (publicKey) body.public_key = publicKey;\n\n const url = `${this.baseUrl}/api/sessions`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(threadId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create thread: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiCreateThreadResponse;\n }\n\n /**\n * Delete a thread by ID.\n */\n async deleteThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to delete thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Rename a thread.\n */\n async renameThread(sessionId: string, newTitle: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: withSessionHeader(sessionId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify({ title: newTitle }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to rename thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Archive a thread.\n */\n async archiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to archive thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Unarchive a thread.\n */\n async unarchiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to unarchive thread: HTTP ${response.status}`);\n }\n }\n\n // ===========================================================================\n // System Events\n // ===========================================================================\n\n /**\n * Get system events for a session.\n */\n async getSystemEvents(\n sessionId: string,\n count?: number,\n ): Promise<AomiSystemEvent[]> {\n const url = new URL(\"/api/events\", this.baseUrl);\n if (count !== undefined) {\n url.searchParams.set(\"count\", String(count));\n }\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n if (response.status === 404) return [];\n throw new Error(`Failed to get system events: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiSystemEvent[];\n }\n\n // ===========================================================================\n // Control API\n // ===========================================================================\n\n /**\n * Get available namespaces.\n */\n async getNamespaces(\n sessionId: string,\n options?: { publicKey?: string; apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/namespaces\", this.baseUrl);\n if (options?.publicKey) {\n url.searchParams.set(\"public_key\", options.publicKey);\n }\n\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to get namespaces: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Get available models.\n */\n async getModels(\n sessionId: string,\n options?: { apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/models\", this.baseUrl);\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), {\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get models: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Set the model for a session.\n */\n async setModel(\n sessionId: string,\n rig: string,\n options?: { namespace?: string; apiKey?: string },\n ): Promise<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }> {\n const apiKey = options?.apiKey ?? this.apiKey;\n const payload: Record<string, unknown> = { rig };\n if (options?.namespace) {\n payload.namespace = options.namespace;\n }\n\n return postState<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }>(this.baseUrl, \"/api/control/model\", payload, sessionId, apiKey);\n }\n}\n","// =============================================================================\n// User State\n// =============================================================================\n\n/**\n * Client-side user state synced with the backend.\n * Typically wallet connection info, but can be any key-value data.\n */\nexport type UserState = Record<string, unknown>;\n\n// =============================================================================\n// Logger\n// =============================================================================\n\n/**\n * Optional logger for debug output. Pass `console` or any compatible object.\n */\nexport type Logger = {\n debug: (...args: unknown[]) => void;\n};\n\n// =============================================================================\n// Client Options\n// =============================================================================\n\nexport type AomiClientOptions = {\n /** Base URL of the Aomi backend (e.g. \"https://aomi.dev\") */\n baseUrl: string;\n /** Default API key for non-default namespaces */\n apiKey?: string;\n /** Optional logger for debug output (default: silent) */\n logger?: Logger;\n};\n\n// =============================================================================\n// Base Types\n// =============================================================================\n\nexport interface AomiMessage {\n sender?: \"user\" | \"agent\" | \"system\" | string;\n content?: string;\n timestamp?: string;\n is_streaming?: boolean;\n tool_result?: [string, string] | null;\n}\n\n// =============================================================================\n// API Response Types\n// =============================================================================\n\n/**\n * GET /api/state\n * Fetches current session state including messages and processing status\n */\nexport interface AomiStateResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n}\n\n/**\n * POST /api/chat\n * Sends a chat message and returns updated session state\n */\nexport interface AomiChatResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n}\n\n/**\n * POST /api/system\n * Sends a system message and returns the response message\n */\nexport interface AomiSystemResponse {\n res?: AomiMessage | null;\n}\n\n/**\n * POST /api/interrupt\n * Interrupts current processing and returns updated session state\n */\nexport type AomiInterruptResponse = AomiChatResponse;\n\n/**\n * GET /api/sessions\n * Returns array of AomiThread\n */\nexport interface AomiThread {\n session_id: string;\n title: string;\n is_archived?: boolean;\n}\n\n/**\n * POST /api/sessions\n * Creates a new thread/session\n */\nexport interface AomiCreateThreadResponse {\n session_id: string;\n title?: string;\n}\n\n// =============================================================================\n// SSE Event Types (/api/updates)\n// =============================================================================\n\n/**\n * Base SSE event - all events have session_id and type\n */\nexport type AomiSSEEvent = {\n type:\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\"\n | string;\n session_id: string;\n new_title?: string;\n [key: string]: unknown;\n};\n\nexport type AomiSSEEventType =\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\";\n\n// =============================================================================\n// System Events (/api/events)\n// =============================================================================\n\n/**\n * Backend SystemEvent enum serializes as tagged JSON:\n * - InlineCall: {\"InlineCall\": {\"type\": \"wallet_tx_request\", \"payload\": {...}}}\n * - SystemNotice: {\"SystemNotice\": \"message\"}\n * - SystemError: {\"SystemError\": \"message\"}\n * - AsyncCallback: {\"AsyncCallback\": {...}} (not sent over HTTP)\n */\nexport type AomiSystemEvent =\n | { InlineCall: { type: string; payload?: unknown; [key: string]: unknown } }\n | { SystemNotice: string }\n | { SystemError: string }\n | { AsyncCallback: Record<string, unknown> };\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isInlineCall(\n event: AomiSystemEvent,\n): event is { InlineCall: { type: string; payload?: unknown } } {\n return \"InlineCall\" in event;\n}\n\nexport function isSystemNotice(\n event: AomiSystemEvent,\n): event is { SystemNotice: string } {\n return \"SystemNotice\" in event;\n}\n\nexport function isSystemError(\n event: AomiSystemEvent,\n): event is { SystemError: string } {\n return \"SystemError\" in event;\n}\n\nexport function isAsyncCallback(\n event: AomiSystemEvent,\n): event is { AsyncCallback: Record<string, unknown> } {\n return \"AsyncCallback\" in event;\n}\n","// =============================================================================\n// Typed EventEmitter (browser-safe, no Node.js deps)\n// =============================================================================\n\ntype Listener<T = unknown> = (payload: T) => void;\n\n/**\n * Minimal typed event emitter with wildcard support.\n *\n * ```ts\n * type Events = { message: string; error: { code: number } };\n * const ee = new TypedEventEmitter<Events>();\n * ee.on(\"message\", (msg) => console.log(msg));\n * ee.emit(\"message\", \"hello\");\n * ```\n */\nexport class TypedEventEmitter<\n EventMap extends Record<string, unknown> = Record<string, unknown>,\n> {\n private listeners = new Map<string, Set<Listener<never>>>();\n\n /**\n * Subscribe to an event type. Returns an unsubscribe function.\n */\n on<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(handler as Listener<never>);\n\n return () => {\n set!.delete(handler as Listener<never>);\n if (set!.size === 0) {\n this.listeners.delete(type);\n }\n };\n }\n\n /**\n * Subscribe to an event type for a single emission, then auto-unsubscribe.\n */\n once<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n const wrapper = ((payload: EventMap[K]) => {\n unsub();\n handler(payload);\n }) as Listener<EventMap[K]>;\n\n const unsub = this.on(type, wrapper);\n return unsub;\n }\n\n /**\n * Emit an event to all listeners of `type` and wildcard `\"*\"` listeners.\n */\n emit<K extends keyof EventMap & string>(\n type: K,\n payload: EventMap[K],\n ): void {\n // Type-specific listeners\n const typeSet = this.listeners.get(type);\n if (typeSet) {\n for (const handler of typeSet) {\n (handler as Listener<EventMap[K]>)(payload);\n }\n }\n\n // Wildcard listeners\n if (type !== \"*\") {\n const wildcardSet = this.listeners.get(\"*\");\n if (wildcardSet) {\n for (const handler of wildcardSet) {\n (handler as Listener<unknown>)({ type, payload });\n }\n }\n }\n }\n\n /**\n * Remove a specific handler from an event type.\n */\n off<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): void {\n const set = this.listeners.get(type);\n if (set) {\n set.delete(handler as Listener<never>);\n if (set.size === 0) {\n this.listeners.delete(type);\n }\n }\n }\n\n /**\n * Remove all listeners for all event types.\n */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","// =============================================================================\n// System Event Unwrap\n// =============================================================================\n//\n// Converts tagged-enum AomiSystemEvent into a flat { type, payload } object.\n// Ported from packages/react/src/contexts/event-context.tsx dispatchSystemEvents.\n\nimport type { AomiSystemEvent } from \"./types\";\nimport {\n isInlineCall,\n isSystemNotice,\n isSystemError,\n isAsyncCallback,\n} from \"./types\";\n\nexport type UnwrappedEvent = {\n type: string;\n payload: unknown;\n};\n\n/**\n * Unwrap a tagged-enum AomiSystemEvent from the backend into a flat event.\n *\n * ```ts\n * const event: AomiSystemEvent = { InlineCall: { type: \"wallet_tx_request\", payload: { to: \"0x...\" } } };\n * const unwrapped = unwrapSystemEvent(event);\n * // => { type: \"wallet_tx_request\", payload: { to: \"0x...\" } }\n * ```\n */\nexport function unwrapSystemEvent(\n event: AomiSystemEvent,\n): UnwrappedEvent | null {\n if (isInlineCall(event)) {\n return {\n type: event.InlineCall.type,\n payload: event.InlineCall.payload ?? event.InlineCall,\n };\n }\n\n if (isSystemNotice(event)) {\n return {\n type: \"system_notice\",\n payload: { message: event.SystemNotice },\n };\n }\n\n if (isSystemError(event)) {\n return {\n type: \"system_error\",\n payload: { message: event.SystemError },\n };\n }\n\n if (isAsyncCallback(event)) {\n return {\n type: \"async_callback\",\n payload: event.AsyncCallback,\n };\n }\n\n return null;\n}\n","// =============================================================================\n// Wallet Payload Normalization\n// =============================================================================\n//\n// Pure functions extracted from packages/react/src/handlers/wallet-handler.ts.\n// Normalizes the various payload shapes the backend can send for wallet\n// transaction and EIP-712 signing requests.\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletTxPayload = {\n to: string;\n value?: string;\n data?: string;\n chainId?: number;\n};\n\nexport type WalletEip712Payload = {\n typed_data?: {\n domain?: { chainId?: number | string };\n types?: Record<string, Array<{ name: string; type: string }>>;\n primaryType?: string;\n message?: Record<string, unknown>;\n };\n description?: string;\n};\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\ntype UnknownRecord = Record<string, unknown>;\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UnknownRecord;\n}\n\nfunction getToolArgs(payload: unknown): UnknownRecord {\n const root = asRecord(payload);\n const nestedArgs = asRecord(root?.args);\n return nestedArgs ?? root ?? {};\n}\n\nfunction parseChainId(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"string\") return undefined;\n\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n if (trimmed.startsWith(\"0x\")) {\n const parsedHex = Number.parseInt(trimmed.slice(2), 16);\n return Number.isFinite(parsedHex) ? parsedHex : undefined;\n }\n\n const parsed = Number.parseInt(trimmed, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\n// =============================================================================\n// Normalization\n// =============================================================================\n\n/**\n * Normalize a wallet_tx_request payload into a consistent shape.\n * Returns `null` if the payload is missing the required `to` field.\n */\nexport function normalizeTxPayload(payload: unknown): WalletTxPayload | null {\n const root = asRecord(payload);\n const args = getToolArgs(payload);\n const ctx = asRecord(root?.ctx);\n\n const to = typeof args.to === \"string\" ? args.to : undefined;\n if (!to) return null;\n\n const valueRaw = args.value;\n const value =\n typeof valueRaw === \"string\"\n ? valueRaw\n : typeof valueRaw === \"number\" && Number.isFinite(valueRaw)\n ? String(Math.trunc(valueRaw))\n : undefined;\n\n const data = typeof args.data === \"string\" ? args.data : undefined;\n const chainId =\n parseChainId(args.chainId) ??\n parseChainId(args.chain_id) ??\n parseChainId(ctx?.user_chain_id) ??\n parseChainId(ctx?.userChainId);\n\n return { to, value, data, chainId };\n}\n\n/**\n * Normalize an EIP-712 signing request payload.\n */\nexport function normalizeEip712Payload(\n payload: unknown,\n): WalletEip712Payload {\n const args = getToolArgs(payload);\n const typedDataRaw = args.typed_data ?? args.typedData;\n let typedData: WalletEip712Payload[\"typed_data\"] | undefined;\n\n if (typeof typedDataRaw === \"string\") {\n try {\n const parsed = JSON.parse(typedDataRaw) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n typedData = parsed as WalletEip712Payload[\"typed_data\"];\n }\n } catch {\n typedData = undefined;\n }\n } else if (\n typedDataRaw &&\n typeof typedDataRaw === \"object\" &&\n !Array.isArray(typedDataRaw)\n ) {\n typedData = typedDataRaw as WalletEip712Payload[\"typed_data\"];\n }\n\n const description =\n typeof args.description === \"string\" ? args.description : undefined;\n\n return { typed_data: typedData, description };\n}\n","// =============================================================================\n// Session — High-level orchestrated client\n// =============================================================================\n//\n// Wraps AomiClient with polling, event dispatch, and wallet request management.\n// Ported from the React runtime (polling-controller, event-context, wallet-handler).\n//\n// Usage:\n// const session = new Session({ baseUrl: \"https://api.aomi.dev\" });\n// session.on(\"wallet_tx_request\", async (req) => {\n// const signed = await signer.signTransaction(req.payload);\n// await session.resolve(req.id, { txHash: signed.hash });\n// });\n// const result = await session.send(\"swap 1 ETH for USDC\");\n// session.close();\n\nimport { AomiClient } from \"./client\";\nimport type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n UserState,\n} from \"./types\";\nimport { TypedEventEmitter } from \"./event-emitter\";\nimport { unwrapSystemEvent } from \"./event-unwrap\";\nimport {\n normalizeTxPayload,\n normalizeEip712Payload,\n type WalletTxPayload,\n type WalletEip712Payload,\n} from \"./wallet-utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletRequestKind = \"transaction\" | \"eip712_sign\";\n\nexport type WalletRequest = {\n id: string;\n kind: WalletRequestKind;\n payload: WalletTxPayload | WalletEip712Payload;\n timestamp: number;\n};\n\nexport type WalletRequestResult = {\n txHash?: string;\n signature?: string;\n amount?: string;\n};\n\nexport type SendResult = {\n messages: AomiMessage[];\n title?: string;\n};\n\nexport type SessionOptions = {\n /** Session ID. Auto-generated (crypto.randomUUID) if omitted. */\n sessionId?: string;\n /** Namespace for chat messages. Default: \"default\" */\n namespace?: string;\n /** User public key (wallet address). */\n publicKey?: string;\n /** API key override. */\n apiKey?: string;\n /** User state to send with requests (wallet connection info, etc). */\n userState?: UserState;\n /** Polling interval in ms. Default: 500 */\n pollIntervalMs?: number;\n /** Logger for debug output. Pass `console` for verbose logging. */\n logger?: { debug: (...args: unknown[]) => void };\n};\n\n/** Events emitted by Session. */\nexport type SessionEventMap = {\n /** A transaction signing request arrived from the backend. */\n wallet_tx_request: WalletRequest;\n /** An EIP-712 signing request arrived from the backend. */\n wallet_eip712_request: WalletRequest;\n /** A system notice from the backend. */\n system_notice: { message: string };\n /** A system error from the backend. */\n system_error: { message: string };\n /** An async callback event. */\n async_callback: Record<string, unknown>;\n /** SSE: tool execution in progress. */\n tool_update: AomiSSEEvent;\n /** SSE: tool execution completed. */\n tool_complete: AomiSSEEvent;\n /** Session title changed. */\n title_changed: { title: string };\n /** Messages updated (new messages from poll or send response). */\n messages: AomiMessage[];\n /** AI started processing. */\n processing_start: undefined;\n /** AI finished processing. */\n processing_end: undefined;\n /** An error occurred during polling or SSE. */\n error: { error: unknown };\n /** Wildcard: receives all events as { type, payload }. */\n \"*\": { type: string; payload: unknown };\n};\n\n// =============================================================================\n// Session Class\n// =============================================================================\n\nexport class Session extends TypedEventEmitter<SessionEventMap> {\n /** The underlying low-level client. */\n readonly client: AomiClient;\n /** The session (thread) ID. */\n readonly sessionId: string;\n\n private namespace: string;\n private publicKey?: string;\n private apiKey?: string;\n private userState?: UserState;\n private pollIntervalMs: number;\n private logger?: { debug: (...args: unknown[]) => void };\n\n // Internal state\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private unsubscribeSSE: (() => void) | null = null;\n private _isProcessing = false;\n private walletRequests: WalletRequest[] = [];\n private walletRequestNextId = 1;\n private _messages: AomiMessage[] = [];\n private _title?: string;\n private closed = false;\n\n // For send() blocking behavior\n private pendingResolve: ((result: SendResult) => void) | null = null;\n\n constructor(\n clientOrOptions: AomiClient | AomiClientOptions,\n sessionOptions?: SessionOptions,\n ) {\n super();\n\n this.client =\n clientOrOptions instanceof AomiClient\n ? clientOrOptions\n : new AomiClient(clientOrOptions);\n\n this.sessionId = sessionOptions?.sessionId ?? crypto.randomUUID();\n this.namespace = sessionOptions?.namespace ?? \"default\";\n this.publicKey = sessionOptions?.publicKey;\n this.apiKey = sessionOptions?.apiKey;\n this.userState = sessionOptions?.userState;\n this.pollIntervalMs = sessionOptions?.pollIntervalMs ?? 500;\n this.logger = sessionOptions?.logger;\n\n // Start SSE subscription\n this.unsubscribeSSE = this.client.subscribeSSE(\n this.sessionId,\n (event) => this.handleSSEEvent(event),\n (error) => this.emit(\"error\", { error }),\n );\n }\n\n // ===========================================================================\n // Public API — Chat\n // ===========================================================================\n\n /**\n * Send a message and wait for the AI to finish processing.\n *\n * The returned promise resolves when `is_processing` becomes `false` AND\n * there are no pending wallet requests. If a wallet request arrives\n * mid-processing, polling continues but the promise pauses until the\n * request is resolved or rejected via `resolve()` / `reject()`.\n */\n async send(message: string): Promise<SendResult> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n namespace: this.namespace,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.applyState(response);\n\n if (!response.is_processing && this.walletRequests.length === 0) {\n return { messages: this._messages, title: this._title };\n }\n\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n\n return new Promise<SendResult>((resolve) => {\n this.pendingResolve = resolve;\n this.startPolling();\n });\n }\n\n /**\n * Send a message without waiting for completion.\n * Polling starts in the background; listen to events for updates.\n */\n async sendAsync(message: string): Promise<AomiChatResponse> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n namespace: this.namespace,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.applyState(response);\n\n if (response.is_processing) {\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n this.startPolling();\n }\n\n return response;\n }\n\n // ===========================================================================\n // Public API — Wallet Request Resolution\n // ===========================================================================\n\n /**\n * Resolve a pending wallet request (transaction or EIP-712 signing).\n * Sends the result to the backend and resumes polling.\n */\n async resolve(requestId: string, result: WalletRequestResult): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: result.txHash ?? \"\",\n status: \"success\",\n amount: result.amount,\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"success\",\n signature: result.signature,\n description: eip712Payload.description,\n });\n }\n\n // Resume polling if still processing\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n /**\n * Reject a pending wallet request.\n * Sends an error to the backend and resumes polling.\n */\n async reject(requestId: string, reason?: string): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: \"\",\n status: \"failed\",\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"failed\",\n error: reason ?? \"Request rejected\",\n description: eip712Payload.description,\n });\n }\n\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n // ===========================================================================\n // Public API — Control\n // ===========================================================================\n\n /**\n * Cancel the AI's current response.\n */\n async interrupt(): Promise<void> {\n this.stopPolling();\n const response = await this.client.interrupt(this.sessionId);\n this.applyState(response);\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n\n /**\n * Close the session. Stops polling, unsubscribes SSE, removes all listeners.\n * The session cannot be used after closing.\n */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopPolling();\n this.unsubscribeSSE?.();\n this.unsubscribeSSE = null;\n this.resolvePending();\n this.removeAllListeners();\n }\n\n // ===========================================================================\n // Public API — Accessors\n // ===========================================================================\n\n /** Current messages in the session. */\n getMessages(): AomiMessage[] {\n return this._messages;\n }\n\n /** Current session title. */\n getTitle(): string | undefined {\n return this._title;\n }\n\n /** Pending wallet requests waiting for resolve/reject. */\n getPendingRequests(): WalletRequest[] {\n return [...this.walletRequests];\n }\n\n /** Whether the AI is currently processing. */\n getIsProcessing(): boolean {\n return this._isProcessing;\n }\n\n // ===========================================================================\n // Internal — Polling (ported from PollingController)\n // ===========================================================================\n\n private startPolling(): void {\n if (this.pollTimer || this.closed) return;\n\n this.logger?.debug(\"[session] polling started\", this.sessionId);\n this.pollTimer = setInterval(() => {\n void this.pollTick();\n }, this.pollIntervalMs);\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n this.logger?.debug(\"[session] polling stopped\", this.sessionId);\n }\n }\n\n private async pollTick(): Promise<void> {\n if (!this.pollTimer) return;\n\n try {\n const state = await this.client.fetchState(\n this.sessionId,\n this.userState,\n );\n\n // Guard: polling may have been stopped while awaiting fetch\n if (!this.pollTimer) return;\n\n this.applyState(state);\n\n if (!state.is_processing && this.walletRequests.length === 0) {\n this.stopPolling();\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n } catch (error) {\n this.logger?.debug(\"[session] poll error\", error);\n this.emit(\"error\", { error });\n }\n }\n\n // ===========================================================================\n // Internal — State Application\n // ===========================================================================\n\n private applyState(\n state: Pick<\n AomiStateResponse,\n \"messages\" | \"system_events\" | \"title\" | \"is_processing\"\n >,\n ): void {\n if (state.messages) {\n this._messages = state.messages;\n this.emit(\"messages\", this._messages);\n }\n\n if (state.title) {\n this._title = state.title;\n }\n\n if (state.system_events?.length) {\n this.dispatchSystemEvents(state.system_events);\n }\n }\n\n private dispatchSystemEvents(events: AomiSystemEvent[]): void {\n for (const event of events) {\n const unwrapped = unwrapSystemEvent(event);\n if (!unwrapped) continue;\n\n if (unwrapped.type === \"wallet_tx_request\") {\n const payload = normalizeTxPayload(unwrapped.payload);\n if (payload) {\n const req = this.enqueueWalletRequest(\"transaction\", payload);\n this.emit(\"wallet_tx_request\", req);\n }\n } else if (unwrapped.type === \"wallet_eip712_request\") {\n const payload = normalizeEip712Payload(unwrapped.payload ?? {});\n const req = this.enqueueWalletRequest(\"eip712_sign\", payload);\n this.emit(\"wallet_eip712_request\", req);\n } else if (\n unwrapped.type === \"system_notice\" ||\n unwrapped.type === \"system_error\" ||\n unwrapped.type === \"async_callback\"\n ) {\n // These match known event map keys — emit directly\n this.emit(\n unwrapped.type as keyof SessionEventMap,\n unwrapped.payload as never,\n );\n }\n }\n }\n\n // ===========================================================================\n // Internal — SSE Handling\n // ===========================================================================\n\n private handleSSEEvent(event: AomiSSEEvent): void {\n if (event.type === \"title_changed\" && event.new_title) {\n this._title = event.new_title;\n this.emit(\"title_changed\", { title: event.new_title });\n } else if (event.type === \"tool_update\") {\n this.emit(\"tool_update\", event);\n } else if (event.type === \"tool_complete\") {\n this.emit(\"tool_complete\", event);\n }\n }\n\n // ===========================================================================\n // Internal — Wallet Request Queue\n // ===========================================================================\n\n private enqueueWalletRequest(\n kind: WalletRequestKind,\n payload: WalletTxPayload | WalletEip712Payload,\n ): WalletRequest {\n const req: WalletRequest = {\n id: `wreq-${this.walletRequestNextId++}`,\n kind,\n payload,\n timestamp: Date.now(),\n };\n this.walletRequests.push(req);\n return req;\n }\n\n private removeWalletRequest(id: string): WalletRequest | null {\n const idx = this.walletRequests.findIndex((r) => r.id === id);\n if (idx === -1) return null;\n return this.walletRequests.splice(idx, 1)[0];\n }\n\n // ===========================================================================\n // Internal — Helpers\n // ===========================================================================\n\n private async sendSystemEvent(\n type: string,\n payload: unknown,\n ): Promise<void> {\n const message = JSON.stringify({ type, payload });\n await this.client.sendSystemMessage(this.sessionId, message);\n }\n\n private resolvePending(): void {\n if (this.pendingResolve) {\n const resolve = this.pendingResolve;\n this.pendingResolve = null;\n resolve({ messages: this._messages, title: this._title });\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"Session is closed\");\n }\n }\n}\n"],"mappings":"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","names":["_a"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/sse.ts","../src/client.ts","../src/types.ts","../src/event-emitter.ts","../src/event-unwrap.ts","../src/wallet-utils.ts","../src/session.ts"],"sourcesContent":["// =============================================================================\n// Client\n// =============================================================================\n\nexport { AomiClient } from \"./client\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiCreateThreadResponse,\n AomiInterruptResponse,\n AomiSSEEvent,\n AomiSSEEventType,\n AomiStateResponse,\n AomiSystemEvent,\n AomiSystemResponse,\n AomiThread,\n Logger,\n UserState,\n} from \"./types\";\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport {\n isAsyncCallback,\n isInlineCall,\n isSystemError,\n isSystemNotice,\n} from \"./types\";\n\n// =============================================================================\n// Session (high-level orchestrated client)\n// =============================================================================\n\nexport { ClientSession as Session } from \"./session\";\n\nexport type {\n SessionOptions,\n SessionEventMap,\n SendResult,\n WalletRequest,\n WalletRequestKind,\n WalletRequestResult,\n} from \"./session\";\n\n// =============================================================================\n// Event Utilities\n// =============================================================================\n\nexport { TypedEventEmitter } from \"./event-emitter\";\nexport { unwrapSystemEvent, type UnwrappedEvent } from \"./event-unwrap\";\n\n// =============================================================================\n// Wallet Utilities\n// =============================================================================\n\nexport {\n normalizeTxPayload,\n normalizeEip712Payload,\n} from \"./wallet-utils\";\n\nexport type {\n WalletTxPayload,\n WalletEip712Payload,\n} from \"./wallet-utils\";\n","import type { AomiSSEEvent, Logger } from \"./types\";\n\nexport type SseSubscriber = {\n subscribe: (\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ) => () => void;\n};\n\nexport type SseSubscriberOptions = {\n backendUrl: string;\n getHeaders: (sessionId: string) => HeadersInit;\n logger?: Logger;\n};\n\ntype SseSubscription = {\n abortController: AbortController | null;\n retries: number;\n retryTimer: ReturnType<typeof setTimeout> | null;\n stopped: boolean;\n listeners: Set<SseListener>;\n stop: (reason?: string) => void;\n};\n\ntype SseListener = {\n onUpdate: (event: AomiSSEEvent) => void;\n onError?: (error: unknown) => void;\n};\n\nfunction extractSseData(rawEvent: string): string | null {\n const dataLines = rawEvent\n .split(\"\\n\")\n .filter((line) => line.startsWith(\"data:\"))\n .map((line) => line.slice(5).trimStart());\n if (!dataLines.length) return null;\n return dataLines.join(\"\\n\");\n}\n\nasync function readSseStream(\n stream: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n onMessage: (data: string) => void,\n): Promise<void> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (!signal.aborted) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n buffer = buffer.replace(/\\r/g, \"\");\n\n let separatorIndex = buffer.indexOf(\"\\n\\n\");\n while (separatorIndex >= 0) {\n const rawEvent = buffer.slice(0, separatorIndex);\n buffer = buffer.slice(separatorIndex + 2);\n const data = extractSseData(rawEvent);\n if (data) {\n onMessage(data);\n }\n separatorIndex = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function createSseSubscriber({\n backendUrl,\n getHeaders,\n logger,\n}: SseSubscriberOptions): SseSubscriber {\n const subscriptions = new Map<string, SseSubscription>();\n\n const subscribe: SseSubscriber[\"subscribe\"] = (\n sessionId,\n onUpdate,\n onError,\n ) => {\n const existing = subscriptions.get(sessionId);\n const listener: SseListener = { onUpdate, onError };\n if (existing) {\n existing.listeners.add(listener);\n logger?.debug(\"[aomi][sse] listener added\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n return () => {\n existing.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: existing.listeners.size,\n });\n if (existing.listeners.size === 0) {\n existing.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === existing) {\n subscriptions.delete(sessionId);\n }\n }\n };\n }\n\n const subscription: SseSubscription = {\n abortController: null,\n retries: 0,\n retryTimer: null,\n stopped: false,\n listeners: new Set([listener]),\n stop: (reason?: string) => {\n subscription.stopped = true;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n subscription.abortController?.abort();\n subscription.abortController = null;\n logger?.debug(\"[aomi][sse] stop\", {\n sessionId,\n reason,\n retries: subscription.retries,\n });\n },\n };\n\n const scheduleRetry = () => {\n if (subscription.stopped) return;\n subscription.retries += 1;\n const delayMs = Math.min(500 * 2 ** (subscription.retries - 1), 10000);\n logger?.debug(\"[aomi][sse] retry scheduled\", {\n sessionId,\n delayMs,\n retries: subscription.retries,\n });\n subscription.retryTimer = setTimeout(() => {\n void open();\n }, delayMs);\n };\n\n const open = async () => {\n if (subscription.stopped) return;\n if (subscription.retryTimer) {\n clearTimeout(subscription.retryTimer);\n subscription.retryTimer = null;\n }\n\n const controller = new AbortController();\n subscription.abortController = controller;\n const openedAt = Date.now();\n\n try {\n const response = await fetch(`${backendUrl}/api/updates`, {\n headers: getHeaders(sessionId),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(\n `SSE HTTP ${response.status}: ${response.statusText}`,\n );\n }\n\n if (!response.body) {\n throw new Error(\"SSE response missing body\");\n }\n\n subscription.retries = 0;\n\n await readSseStream(response.body, controller.signal, (data) => {\n let parsed: AomiSSEEvent;\n try {\n parsed = JSON.parse(data) as AomiSSEEvent;\n } catch (error) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n return;\n }\n\n for (const item of subscription.listeners) {\n try {\n item.onUpdate(parsed);\n } catch (error) {\n item.onError?.(error);\n }\n }\n });\n logger?.debug(\"[aomi][sse] stream ended\", {\n sessionId,\n aborted: controller.signal.aborted,\n stopped: subscription.stopped,\n durationMs: Date.now() - openedAt,\n });\n } catch (error) {\n if (!controller.signal.aborted && !subscription.stopped) {\n for (const item of subscription.listeners) {\n item.onError?.(error);\n }\n }\n }\n\n if (!subscription.stopped) {\n scheduleRetry();\n }\n };\n\n subscriptions.set(sessionId, subscription);\n void open();\n\n return () => {\n subscription.listeners.delete(listener);\n logger?.debug(\"[aomi][sse] listener removed\", {\n sessionId,\n listeners: subscription.listeners.size,\n });\n if (subscription.listeners.size === 0) {\n subscription.stop(\"unsubscribe\");\n if (subscriptions.get(sessionId) === subscription) {\n subscriptions.delete(sessionId);\n }\n }\n };\n };\n\n return { subscribe };\n}\n","import type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiCreateThreadResponse,\n AomiInterruptResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n AomiSystemResponse,\n AomiThread,\n Logger,\n UserState,\n} from \"./types\";\nimport { createSseSubscriber, type SseSubscriber } from \"./sse\";\n\n// =============================================================================\n// Internal helpers\n// =============================================================================\n\nconst SESSION_ID_HEADER = \"X-Session-Id\";\nconst API_KEY_HEADER = \"X-API-Key\";\n\nfunction toQueryString(payload: Record<string, unknown>): string {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(payload)) {\n if (value === undefined || value === null) continue;\n params.set(key, String(value));\n }\n const qs = params.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nfunction withSessionHeader(\n sessionId: string,\n init?: HeadersInit,\n): HeadersInit {\n const headers = new Headers(init);\n headers.set(SESSION_ID_HEADER, sessionId);\n return headers;\n}\n\nasync function postState<T>(\n baseUrl: string,\n path: string,\n payload: Record<string, unknown>,\n sessionId: string,\n apiKey?: string,\n): Promise<T> {\n const query = toQueryString(payload);\n const url = `${baseUrl}${path}${query}`;\n\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as T;\n}\n\n// =============================================================================\n// AomiClient\n// =============================================================================\n\nexport class AomiClient {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly logger?: Logger;\n private readonly sseSubscriber: SseSubscriber;\n\n constructor(options: AomiClientOptions) {\n // Strip trailing slash\n this.baseUrl = options.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = options.apiKey;\n this.logger = options.logger;\n\n this.sseSubscriber = createSseSubscriber({\n backendUrl: this.baseUrl,\n getHeaders: (sessionId) =>\n withSessionHeader(sessionId, { Accept: \"text/event-stream\" }),\n logger: this.logger,\n });\n }\n\n // ===========================================================================\n // Chat & State\n // ===========================================================================\n\n /**\n * Fetch current session state (messages, processing status, title).\n */\n async fetchState(\n sessionId: string,\n userState?: UserState,\n ): Promise<AomiStateResponse> {\n const url = new URL(\"/api/state\", this.baseUrl);\n if (userState) {\n url.searchParams.set(\"user_state\", JSON.stringify(userState));\n }\n\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiStateResponse;\n }\n\n /**\n * Send a chat message and return updated session state.\n */\n async sendMessage(\n sessionId: string,\n message: string,\n options?: {\n app?: string;\n publicKey?: string;\n apiKey?: string;\n userState?: UserState;\n },\n ): Promise<AomiChatResponse> {\n const app = options?.app ?? \"default\";\n const apiKey = options?.apiKey ?? this.apiKey;\n\n const payload: Record<string, unknown> = { message, app };\n if (options?.publicKey) {\n payload.public_key = options.publicKey;\n }\n if (options?.userState) {\n payload.user_state = JSON.stringify(options.userState);\n }\n\n return postState<AomiChatResponse>(\n this.baseUrl,\n \"/api/chat\",\n payload,\n sessionId,\n apiKey,\n );\n }\n\n /**\n * Send a system-level message (e.g. wallet state changes, context switches).\n */\n async sendSystemMessage(\n sessionId: string,\n message: string,\n ): Promise<AomiSystemResponse> {\n return postState<AomiSystemResponse>(\n this.baseUrl,\n \"/api/system\",\n { message },\n sessionId,\n );\n }\n\n /**\n * Interrupt the AI's current response.\n */\n async interrupt(sessionId: string): Promise<AomiInterruptResponse> {\n return postState<AomiInterruptResponse>(\n this.baseUrl,\n \"/api/interrupt\",\n {},\n sessionId,\n );\n }\n\n // ===========================================================================\n // SSE (Real-time Updates)\n // ===========================================================================\n\n /**\n * Subscribe to real-time SSE updates for a session.\n * Automatically reconnects with exponential backoff on disconnects.\n * Returns an unsubscribe function.\n */\n subscribeSSE(\n sessionId: string,\n onUpdate: (event: AomiSSEEvent) => void,\n onError?: (error: unknown) => void,\n ): () => void {\n return this.sseSubscriber.subscribe(sessionId, onUpdate, onError);\n }\n\n // ===========================================================================\n // Thread / Session Management\n // ===========================================================================\n\n /**\n * List all threads for a wallet address.\n */\n async listThreads(publicKey: string): Promise<AomiThread[]> {\n const url = `${this.baseUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch threads: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiThread[];\n }\n\n /**\n * Get a single thread by ID.\n */\n async getThread(sessionId: string): Promise<AomiThread> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as AomiThread;\n }\n\n /**\n * Create a new thread. The client generates the session ID.\n */\n async createThread(\n threadId: string,\n publicKey?: string,\n ): Promise<AomiCreateThreadResponse> {\n const body: Record<string, string> = {};\n if (publicKey) body.public_key = publicKey;\n\n const url = `${this.baseUrl}/api/sessions`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(threadId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to create thread: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiCreateThreadResponse;\n }\n\n /**\n * Delete a thread by ID.\n */\n async deleteThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to delete thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Rename a thread.\n */\n async renameThread(sessionId: string, newTitle: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}`;\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: withSessionHeader(sessionId, {\n \"Content-Type\": \"application/json\",\n }),\n body: JSON.stringify({ title: newTitle }),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to rename thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Archive a thread.\n */\n async archiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to archive thread: HTTP ${response.status}`);\n }\n }\n\n /**\n * Unarchive a thread.\n */\n async unarchiveThread(sessionId: string): Promise<void> {\n const url = `${this.baseUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;\n const response = await fetch(url, {\n method: \"POST\",\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n throw new Error(`Failed to unarchive thread: HTTP ${response.status}`);\n }\n }\n\n // ===========================================================================\n // System Events\n // ===========================================================================\n\n /**\n * Get system events for a session.\n */\n async getSystemEvents(\n sessionId: string,\n count?: number,\n ): Promise<AomiSystemEvent[]> {\n const url = new URL(\"/api/events\", this.baseUrl);\n if (count !== undefined) {\n url.searchParams.set(\"count\", String(count));\n }\n const response = await fetch(url.toString(), {\n headers: withSessionHeader(sessionId),\n });\n\n if (!response.ok) {\n if (response.status === 404) return [];\n throw new Error(`Failed to get system events: HTTP ${response.status}`);\n }\n\n return (await response.json()) as AomiSystemEvent[];\n }\n\n // ===========================================================================\n // Control API\n // ===========================================================================\n\n /**\n * Get available apps.\n */\n async getApps(\n sessionId: string,\n options?: { publicKey?: string; apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/apps\", this.baseUrl);\n if (options?.publicKey) {\n url.searchParams.set(\"public_key\", options.publicKey);\n }\n\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), { headers });\n\n if (!response.ok) {\n throw new Error(`Failed to get apps: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Get available models.\n */\n async getModels(\n sessionId: string,\n options?: { apiKey?: string },\n ): Promise<string[]> {\n const url = new URL(\"/api/control/models\", this.baseUrl);\n const apiKey = options?.apiKey ?? this.apiKey;\n const headers = new Headers(withSessionHeader(sessionId));\n if (apiKey) {\n headers.set(API_KEY_HEADER, apiKey);\n }\n\n const response = await fetch(url.toString(), {\n headers,\n });\n\n if (!response.ok) {\n throw new Error(`Failed to get models: HTTP ${response.status}`);\n }\n\n return (await response.json()) as string[];\n }\n\n /**\n * Set the model for a session.\n */\n async setModel(\n sessionId: string,\n rig: string,\n options?: { app?: string; apiKey?: string },\n ): Promise<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }> {\n const apiKey = options?.apiKey ?? this.apiKey;\n const payload: Record<string, unknown> = { rig };\n if (options?.app) {\n payload.app = options.app;\n }\n\n return postState<{\n success: boolean;\n rig: string;\n baml: string;\n created: boolean;\n }>(this.baseUrl, \"/api/control/model\", payload, sessionId, apiKey);\n }\n}\n","// =============================================================================\n// User State\n// =============================================================================\n\n/**\n * Client-side user state synced with the backend.\n * Typically wallet connection info, but can be any key-value data.\n */\nexport type UserState = Record<string, unknown>;\n\n// =============================================================================\n// Logger\n// =============================================================================\n\n/**\n * Optional logger for debug output. Pass `console` or any compatible object.\n */\nexport type Logger = {\n debug: (...args: unknown[]) => void;\n};\n\n// =============================================================================\n// Client Options\n// =============================================================================\n\nexport type AomiClientOptions = {\n /** Base URL of the Aomi backend (e.g. \"https://aomi.dev\") */\n baseUrl: string;\n /** Default API key for non-default apps */\n apiKey?: string;\n /** Optional logger for debug output (default: silent) */\n logger?: Logger;\n};\n\n// =============================================================================\n// Base Types\n// =============================================================================\n\nexport interface AomiMessage {\n sender?: \"user\" | \"agent\" | \"system\" | string;\n content?: string;\n timestamp?: string;\n is_streaming?: boolean;\n tool_result?: [string, string] | null;\n}\n\n// =============================================================================\n// API Response Types\n// =============================================================================\n\n/**\n * GET /api/state\n * Fetches current session state including messages and processing status\n */\nexport interface AomiStateResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n user_state?: UserState | null;\n}\n\n/**\n * POST /api/chat\n * Sends a chat message and returns updated session state\n */\nexport interface AomiChatResponse {\n messages?: AomiMessage[] | null;\n system_events?: AomiSystemEvent[] | null;\n title?: string | null;\n is_processing?: boolean;\n user_state?: UserState | null;\n}\n\n/**\n * POST /api/system\n * Sends a system message and returns the response message\n */\nexport interface AomiSystemResponse {\n res?: AomiMessage | null;\n}\n\n/**\n * POST /api/interrupt\n * Interrupts current processing and returns updated session state\n */\nexport type AomiInterruptResponse = AomiChatResponse;\n\n/**\n * GET /api/sessions\n * Returns array of AomiThread\n */\nexport interface AomiThread {\n session_id: string;\n title: string;\n is_archived?: boolean;\n}\n\n/**\n * POST /api/sessions\n * Creates a new thread/session\n */\nexport interface AomiCreateThreadResponse {\n session_id: string;\n title?: string;\n}\n\n// =============================================================================\n// SSE Event Types (/api/updates)\n// =============================================================================\n\n/**\n * Base SSE event - all events have session_id and type\n */\nexport type AomiSSEEvent = {\n type:\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\"\n | string;\n session_id: string;\n new_title?: string;\n [key: string]: unknown;\n};\n\nexport type AomiSSEEventType =\n | \"title_changed\"\n | \"tool_update\"\n | \"tool_complete\"\n | \"system_notice\";\n\n// =============================================================================\n// System Events (/api/events)\n// =============================================================================\n\n/**\n * Backend SystemEvent enum serializes as tagged JSON:\n * - InlineCall: {\"InlineCall\": {\"type\": \"wallet_tx_request\", \"payload\": {...}}}\n * - SystemNotice: {\"SystemNotice\": \"message\"}\n * - SystemError: {\"SystemError\": \"message\"}\n * - AsyncCallback: {\"AsyncCallback\": {...}} (not sent over HTTP)\n */\nexport type AomiSystemEvent =\n | { InlineCall: { type: string; payload?: unknown; [key: string]: unknown } }\n | { SystemNotice: string }\n | { SystemError: string }\n | { AsyncCallback: Record<string, unknown> };\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\nexport function isInlineCall(\n event: AomiSystemEvent,\n): event is { InlineCall: { type: string; payload?: unknown } } {\n return \"InlineCall\" in event;\n}\n\nexport function isSystemNotice(\n event: AomiSystemEvent,\n): event is { SystemNotice: string } {\n return \"SystemNotice\" in event;\n}\n\nexport function isSystemError(\n event: AomiSystemEvent,\n): event is { SystemError: string } {\n return \"SystemError\" in event;\n}\n\nexport function isAsyncCallback(\n event: AomiSystemEvent,\n): event is { AsyncCallback: Record<string, unknown> } {\n return \"AsyncCallback\" in event;\n}\n","// =============================================================================\n// Typed EventEmitter (browser-safe, no Node.js deps)\n// =============================================================================\n\ntype Listener<T = unknown> = (payload: T) => void;\n\n/**\n * Minimal typed event emitter with wildcard support.\n *\n * ```ts\n * type Events = { message: string; error: { code: number } };\n * const ee = new TypedEventEmitter<Events>();\n * ee.on(\"message\", (msg) => console.log(msg));\n * ee.emit(\"message\", \"hello\");\n * ```\n */\nexport class TypedEventEmitter<\n EventMap extends Record<string, unknown> = Record<string, unknown>,\n> {\n private listeners = new Map<string, Set<Listener<never>>>();\n\n /**\n * Subscribe to an event type. Returns an unsubscribe function.\n */\n on<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n let set = this.listeners.get(type);\n if (!set) {\n set = new Set();\n this.listeners.set(type, set);\n }\n set.add(handler as Listener<never>);\n\n return () => {\n set!.delete(handler as Listener<never>);\n if (set!.size === 0) {\n this.listeners.delete(type);\n }\n };\n }\n\n /**\n * Subscribe to an event type for a single emission, then auto-unsubscribe.\n */\n once<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): () => void {\n const wrapper = ((payload: EventMap[K]) => {\n unsub();\n handler(payload);\n }) as Listener<EventMap[K]>;\n\n const unsub = this.on(type, wrapper);\n return unsub;\n }\n\n /**\n * Emit an event to all listeners of `type` and wildcard `\"*\"` listeners.\n */\n emit<K extends keyof EventMap & string>(\n type: K,\n payload: EventMap[K],\n ): void {\n // Type-specific listeners\n const typeSet = this.listeners.get(type);\n if (typeSet) {\n for (const handler of typeSet) {\n (handler as Listener<EventMap[K]>)(payload);\n }\n }\n\n // Wildcard listeners\n if (type !== \"*\") {\n const wildcardSet = this.listeners.get(\"*\");\n if (wildcardSet) {\n for (const handler of wildcardSet) {\n (handler as Listener<unknown>)({ type, payload });\n }\n }\n }\n }\n\n /**\n * Remove a specific handler from an event type.\n */\n off<K extends keyof EventMap & string>(\n type: K,\n handler: Listener<EventMap[K]>,\n ): void {\n const set = this.listeners.get(type);\n if (set) {\n set.delete(handler as Listener<never>);\n if (set.size === 0) {\n this.listeners.delete(type);\n }\n }\n }\n\n /**\n * Remove all listeners for all event types.\n */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","// =============================================================================\n// System Event Unwrap\n// =============================================================================\n//\n// Converts tagged-enum AomiSystemEvent into a flat { type, payload } object.\n// Ported from packages/react/src/contexts/event-context.tsx dispatchSystemEvents.\n\nimport type { AomiSystemEvent } from \"./types\";\nimport {\n isInlineCall,\n isSystemNotice,\n isSystemError,\n isAsyncCallback,\n} from \"./types\";\n\nexport type UnwrappedEvent = {\n type: string;\n payload: unknown;\n};\n\n/**\n * Unwrap a tagged-enum AomiSystemEvent from the backend into a flat event.\n *\n * ```ts\n * const event: AomiSystemEvent = { InlineCall: { type: \"wallet_tx_request\", payload: { to: \"0x...\" } } };\n * const unwrapped = unwrapSystemEvent(event);\n * // => { type: \"wallet_tx_request\", payload: { to: \"0x...\" } }\n * ```\n */\nexport function unwrapSystemEvent(\n event: AomiSystemEvent,\n): UnwrappedEvent | null {\n if (isInlineCall(event)) {\n return {\n type: event.InlineCall.type,\n payload: event.InlineCall.payload ?? event.InlineCall,\n };\n }\n\n if (isSystemNotice(event)) {\n return {\n type: \"system_notice\",\n payload: { message: event.SystemNotice },\n };\n }\n\n if (isSystemError(event)) {\n return {\n type: \"system_error\",\n payload: { message: event.SystemError },\n };\n }\n\n if (isAsyncCallback(event)) {\n return {\n type: \"async_callback\",\n payload: event.AsyncCallback,\n };\n }\n\n return null;\n}\n","// =============================================================================\n// Wallet Payload Normalization\n// =============================================================================\n//\n// Pure functions extracted from packages/react/src/handlers/wallet-handler.ts.\n// Normalizes the various payload shapes the backend can send for wallet\n// transaction and EIP-712 signing requests.\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletTxPayload = {\n to: string;\n value?: string;\n data?: string;\n chainId?: number;\n};\n\nexport type WalletEip712Payload = {\n typed_data?: {\n domain?: { chainId?: number | string };\n types?: Record<string, Array<{ name: string; type: string }>>;\n primaryType?: string;\n message?: Record<string, unknown>;\n };\n description?: string;\n};\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\ntype UnknownRecord = Record<string, unknown>;\n\nfunction asRecord(value: unknown): UnknownRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UnknownRecord;\n}\n\nfunction getToolArgs(payload: unknown): UnknownRecord {\n const root = asRecord(payload);\n const nestedArgs = asRecord(root?.args);\n return nestedArgs ?? root ?? {};\n}\n\nfunction parseChainId(value: unknown): number | undefined {\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n if (typeof value !== \"string\") return undefined;\n\n const trimmed = value.trim();\n if (!trimmed) return undefined;\n\n if (trimmed.startsWith(\"0x\")) {\n const parsedHex = Number.parseInt(trimmed.slice(2), 16);\n return Number.isFinite(parsedHex) ? parsedHex : undefined;\n }\n\n const parsed = Number.parseInt(trimmed, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\n// =============================================================================\n// Normalization\n// =============================================================================\n\n/**\n * Normalize a wallet_tx_request payload into a consistent shape.\n * Returns `null` if the payload is missing the required `to` field.\n */\nexport function normalizeTxPayload(payload: unknown): WalletTxPayload | null {\n const root = asRecord(payload);\n const args = getToolArgs(payload);\n const ctx = asRecord(root?.ctx);\n\n const to = typeof args.to === \"string\" ? args.to : undefined;\n if (!to) return null;\n\n const valueRaw = args.value;\n const value =\n typeof valueRaw === \"string\"\n ? valueRaw\n : typeof valueRaw === \"number\" && Number.isFinite(valueRaw)\n ? String(Math.trunc(valueRaw))\n : undefined;\n\n const data = typeof args.data === \"string\" ? args.data : undefined;\n const chainId =\n parseChainId(args.chainId) ??\n parseChainId(args.chain_id) ??\n parseChainId(ctx?.user_chain_id) ??\n parseChainId(ctx?.userChainId);\n\n return { to, value, data, chainId };\n}\n\n/**\n * Normalize an EIP-712 signing request payload.\n */\nexport function normalizeEip712Payload(\n payload: unknown,\n): WalletEip712Payload {\n const args = getToolArgs(payload);\n const typedDataRaw = args.typed_data ?? args.typedData;\n let typedData: WalletEip712Payload[\"typed_data\"] | undefined;\n\n if (typeof typedDataRaw === \"string\") {\n try {\n const parsed = JSON.parse(typedDataRaw) as unknown;\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n typedData = parsed as WalletEip712Payload[\"typed_data\"];\n }\n } catch {\n typedData = undefined;\n }\n } else if (\n typedDataRaw &&\n typeof typedDataRaw === \"object\" &&\n !Array.isArray(typedDataRaw)\n ) {\n typedData = typedDataRaw as WalletEip712Payload[\"typed_data\"];\n }\n\n const description =\n typeof args.description === \"string\" ? args.description : undefined;\n\n return { typed_data: typedData, description };\n}\n","// =============================================================================\n// Session — High-level orchestrated client\n// =============================================================================\n//\n// Wraps AomiClient with polling, event dispatch, and wallet request management.\n// Ported from the React runtime (polling-controller, event-context, wallet-handler).\n//\n// Usage:\n// const session = new Session({ baseUrl: \"https://api.aomi.dev\" });\n// session.on(\"wallet_tx_request\", async (req) => {\n// const signed = await signer.signTransaction(req.payload);\n// await session.resolve(req.id, { txHash: signed.hash });\n// });\n// const result = await session.send(\"swap 1 ETH for USDC\");\n// session.close();\n\nimport { AomiClient } from \"./client\";\nimport type {\n AomiClientOptions,\n AomiMessage,\n AomiChatResponse,\n AomiSSEEvent,\n AomiStateResponse,\n AomiSystemEvent,\n UserState,\n} from \"./types\";\nimport { TypedEventEmitter } from \"./event-emitter\";\nimport { unwrapSystemEvent } from \"./event-unwrap\";\nimport {\n normalizeTxPayload,\n normalizeEip712Payload,\n type WalletTxPayload,\n type WalletEip712Payload,\n} from \"./wallet-utils\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport type WalletRequestKind = \"transaction\" | \"eip712_sign\";\n\nexport type WalletRequest = {\n id: string;\n kind: WalletRequestKind;\n payload: WalletTxPayload | WalletEip712Payload;\n timestamp: number;\n};\n\nexport type WalletRequestResult = {\n txHash?: string;\n signature?: string;\n amount?: string;\n};\n\nexport type SendResult = {\n messages: AomiMessage[];\n title?: string;\n};\n\nfunction sortJson(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map((entry) => sortJson(entry));\n }\n if (value && typeof value === \"object\") {\n return Object.keys(value as Record<string, unknown>)\n .sort()\n .reduce<Record<string, unknown>>((acc, key) => {\n acc[key] = sortJson((value as Record<string, unknown>)[key]);\n return acc;\n }, {});\n }\n return value;\n}\n\nfunction isSubsetMatch(expected: unknown, actual: unknown): boolean {\n if (Array.isArray(expected)) {\n if (!Array.isArray(actual) || expected.length !== actual.length) {\n return false;\n }\n return expected.every((entry, index) =>\n isSubsetMatch(entry, actual[index]),\n );\n }\n\n if (expected && typeof expected === \"object\") {\n if (!actual || typeof actual !== \"object\" || Array.isArray(actual)) {\n return false;\n }\n\n return Object.entries(expected as Record<string, unknown>).every(\n ([key, value]) =>\n isSubsetMatch(value, (actual as Record<string, unknown>)[key]),\n );\n }\n\n return expected === actual;\n}\n\nexport type SessionOptions = {\n /** Session ID. Auto-generated (crypto.randomUUID) if omitted. */\n sessionId?: string;\n /** App for chat messages. Default: \"default\" */\n app?: string;\n /** User public key (wallet address). */\n publicKey?: string;\n /** API key override. */\n apiKey?: string;\n /** User state to send with requests (wallet connection info, etc). */\n userState?: UserState;\n /** Polling interval in ms. Default: 500 */\n pollIntervalMs?: number;\n /** Logger for debug output. Pass `console` for verbose logging. */\n logger?: { debug: (...args: unknown[]) => void };\n};\n\n/** Events emitted by Session. */\nexport type SessionEventMap = {\n /** A transaction signing request arrived from the backend. */\n wallet_tx_request: WalletRequest;\n /** An EIP-712 signing request arrived from the backend. */\n wallet_eip712_request: WalletRequest;\n /** A system notice from the backend. */\n system_notice: { message: string };\n /** A system error from the backend. */\n system_error: { message: string };\n /** An async callback event. */\n async_callback: Record<string, unknown>;\n /** SSE: tool execution in progress. */\n tool_update: AomiSSEEvent;\n /** SSE: tool execution completed. */\n tool_complete: AomiSSEEvent;\n /** Session title changed. */\n title_changed: { title: string };\n /** Messages updated (new messages from poll or send response). */\n messages: AomiMessage[];\n /** AI started processing. */\n processing_start: undefined;\n /** AI finished processing. */\n processing_end: undefined;\n /** An error occurred during polling or SSE. */\n error: { error: unknown };\n /** Wildcard: receives all events as { type, payload }. */\n \"*\": { type: string; payload: unknown };\n};\n\n// =============================================================================\n// Session Class\n// =============================================================================\n\nexport class ClientSession extends TypedEventEmitter<SessionEventMap> {\n /** The underlying low-level client. */\n readonly client: AomiClient;\n /** The session (thread) ID. */\n readonly sessionId: string;\n\n private app: string;\n private publicKey?: string;\n private apiKey?: string;\n private userState?: UserState;\n private pollIntervalMs: number;\n private logger?: { debug: (...args: unknown[]) => void };\n\n // Internal state\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n private unsubscribeSSE: (() => void) | null = null;\n private _isProcessing = false;\n private walletRequests: WalletRequest[] = [];\n private walletRequestNextId = 1;\n private _messages: AomiMessage[] = [];\n private _title?: string;\n private closed = false;\n\n // For send() blocking behavior\n private pendingResolve: ((result: SendResult) => void) | null = null;\n\n constructor(\n clientOrOptions: AomiClient | AomiClientOptions,\n sessionOptions?: SessionOptions,\n ) {\n super();\n\n this.client =\n clientOrOptions instanceof AomiClient\n ? clientOrOptions\n : new AomiClient(clientOrOptions);\n\n this.sessionId = sessionOptions?.sessionId ?? crypto.randomUUID();\n this.app = sessionOptions?.app ?? \"default\";\n this.publicKey = sessionOptions?.publicKey;\n this.apiKey = sessionOptions?.apiKey;\n this.userState = sessionOptions?.userState;\n this.pollIntervalMs = sessionOptions?.pollIntervalMs ?? 500;\n this.logger = sessionOptions?.logger;\n\n // Start SSE subscription\n this.unsubscribeSSE = this.client.subscribeSSE(\n this.sessionId,\n (event) => this.handleSSEEvent(event),\n (error) => this.emit(\"error\", { error }),\n );\n }\n\n // ===========================================================================\n // Public API — Chat\n // ===========================================================================\n\n /**\n * Send a message and wait for the AI to finish processing.\n *\n * The returned promise resolves when `is_processing` becomes `false` AND\n * there are no pending wallet requests. If a wallet request arrives\n * mid-processing, polling continues but the promise pauses until the\n * request is resolved or rejected via `resolve()` / `reject()`.\n */\n async send(message: string): Promise<SendResult> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n app: this.app,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.assertUserStateAligned(response.user_state);\n this.applyState(response);\n\n if (!response.is_processing && this.walletRequests.length === 0) {\n return { messages: this._messages, title: this._title };\n }\n\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n\n return new Promise<SendResult>((resolve) => {\n this.pendingResolve = resolve;\n this.startPolling();\n });\n }\n\n /**\n * Send a message without waiting for completion.\n * Polling starts in the background; listen to events for updates.\n */\n async sendAsync(message: string): Promise<AomiChatResponse> {\n this.assertOpen();\n\n const response = await this.client.sendMessage(this.sessionId, message, {\n app: this.app,\n publicKey: this.publicKey,\n apiKey: this.apiKey,\n userState: this.userState,\n });\n\n this.assertUserStateAligned(response.user_state);\n this.applyState(response);\n\n if (response.is_processing) {\n this._isProcessing = true;\n this.emit(\"processing_start\", undefined);\n this.startPolling();\n }\n\n return response;\n }\n\n // ===========================================================================\n // Public API — Wallet Request Resolution\n // ===========================================================================\n\n /**\n * Resolve a pending wallet request (transaction or EIP-712 signing).\n * Sends the result to the backend and resumes polling.\n */\n async resolve(requestId: string, result: WalletRequestResult): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: result.txHash ?? \"\",\n status: \"success\",\n amount: result.amount,\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"success\",\n signature: result.signature,\n description: eip712Payload.description,\n });\n }\n\n // Resume polling if still processing\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n /**\n * Reject a pending wallet request.\n * Sends an error to the backend and resumes polling.\n */\n async reject(requestId: string, reason?: string): Promise<void> {\n const req = this.removeWalletRequest(requestId);\n if (!req) {\n throw new Error(`No pending wallet request with id \"${requestId}\"`);\n }\n\n if (req.kind === \"transaction\") {\n await this.sendSystemEvent(\"wallet:tx_complete\", {\n txHash: \"\",\n status: \"failed\",\n });\n } else {\n const eip712Payload = req.payload as WalletEip712Payload;\n await this.sendSystemEvent(\"wallet_eip712_response\", {\n status: \"failed\",\n error: reason ?? \"Request rejected\",\n description: eip712Payload.description,\n });\n }\n\n if (this._isProcessing) {\n this.startPolling();\n }\n }\n\n // ===========================================================================\n // Public API — Control\n // ===========================================================================\n\n /**\n * Cancel the AI's current response.\n */\n async interrupt(): Promise<void> {\n this.stopPolling();\n const response = await this.client.interrupt(this.sessionId);\n this.applyState(response);\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n\n /**\n * Close the session. Stops polling, unsubscribes SSE, removes all listeners.\n * The session cannot be used after closing.\n */\n close(): void {\n if (this.closed) return;\n this.closed = true;\n this.stopPolling();\n this.unsubscribeSSE?.();\n this.unsubscribeSSE = null;\n this.resolvePending();\n this.removeAllListeners();\n }\n\n // ===========================================================================\n // Public API — Accessors\n // ===========================================================================\n\n /** Current messages in the session. */\n getMessages(): AomiMessage[] {\n return this._messages;\n }\n\n /** Current session title. */\n getTitle(): string | undefined {\n return this._title;\n }\n\n /** Pending wallet requests waiting for resolve/reject. */\n getPendingRequests(): WalletRequest[] {\n return [...this.walletRequests];\n }\n\n /** Whether the AI is currently processing. */\n getIsProcessing(): boolean {\n return this._isProcessing;\n }\n\n resolveUserState(userState: UserState): void {\n this.userState = userState;\n\n const address = userState[\"address\"];\n if (typeof address === \"string\" && address.length > 0) {\n this.publicKey = address;\n }\n }\n\n resolveWallet(address: string, chainId?: number): void {\n this.resolveUserState({ address, chainId: chainId ?? 1, isConnected: true });\n }\n\n async syncUserState(): Promise<AomiStateResponse> {\n this.assertOpen();\n\n const state = await this.client.fetchState(this.sessionId, this.userState);\n this.assertUserStateAligned(state.user_state);\n this.applyState(state);\n return state;\n }\n\n // ===========================================================================\n // Internal — Polling (ported from PollingController)\n // ===========================================================================\n\n private startPolling(): void {\n if (this.pollTimer || this.closed) return;\n\n this.logger?.debug(\"[session] polling started\", this.sessionId);\n this.pollTimer = setInterval(() => {\n void this.pollTick();\n }, this.pollIntervalMs);\n }\n\n private stopPolling(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n this.logger?.debug(\"[session] polling stopped\", this.sessionId);\n }\n }\n\n private async pollTick(): Promise<void> {\n if (!this.pollTimer) return;\n\n try {\n const state = await this.client.fetchState(\n this.sessionId,\n this.userState,\n );\n\n // Guard: polling may have been stopped while awaiting fetch\n if (!this.pollTimer) return;\n\n this.assertUserStateAligned(state.user_state);\n this.applyState(state);\n\n if (!state.is_processing && this.walletRequests.length === 0) {\n this.stopPolling();\n this._isProcessing = false;\n this.emit(\"processing_end\", undefined);\n this.resolvePending();\n }\n } catch (error) {\n this.logger?.debug(\"[session] poll error\", error);\n this.emit(\"error\", { error });\n }\n }\n\n // ===========================================================================\n // Internal — State Application\n // ===========================================================================\n\n private applyState(\n state: Pick<\n AomiStateResponse,\n \"messages\" | \"system_events\" | \"title\" | \"is_processing\"\n >,\n ): void {\n if (state.messages) {\n this._messages = state.messages;\n this.emit(\"messages\", this._messages);\n }\n\n if (state.title) {\n this._title = state.title;\n }\n\n if (state.system_events?.length) {\n this.dispatchSystemEvents(state.system_events);\n }\n }\n\n private dispatchSystemEvents(events: AomiSystemEvent[]): void {\n for (const event of events) {\n const unwrapped = unwrapSystemEvent(event);\n if (!unwrapped) continue;\n\n if (unwrapped.type === \"wallet_tx_request\") {\n const payload = normalizeTxPayload(unwrapped.payload);\n if (payload) {\n const req = this.enqueueWalletRequest(\"transaction\", payload);\n this.emit(\"wallet_tx_request\", req);\n }\n } else if (unwrapped.type === \"wallet_eip712_request\") {\n const payload = normalizeEip712Payload(unwrapped.payload ?? {});\n const req = this.enqueueWalletRequest(\"eip712_sign\", payload);\n this.emit(\"wallet_eip712_request\", req);\n } else if (\n unwrapped.type === \"system_notice\" ||\n unwrapped.type === \"system_error\" ||\n unwrapped.type === \"async_callback\"\n ) {\n // These match known event map keys — emit directly\n this.emit(\n unwrapped.type as keyof SessionEventMap,\n unwrapped.payload as never,\n );\n }\n }\n }\n\n // ===========================================================================\n // Internal — SSE Handling\n // ===========================================================================\n\n private handleSSEEvent(event: AomiSSEEvent): void {\n if (event.type === \"title_changed\" && event.new_title) {\n this._title = event.new_title;\n this.emit(\"title_changed\", { title: event.new_title });\n } else if (event.type === \"tool_update\") {\n this.emit(\"tool_update\", event);\n } else if (event.type === \"tool_complete\") {\n this.emit(\"tool_complete\", event);\n }\n }\n\n // ===========================================================================\n // Internal — Wallet Request Queue\n // ===========================================================================\n\n private enqueueWalletRequest(\n kind: WalletRequestKind,\n payload: WalletTxPayload | WalletEip712Payload,\n ): WalletRequest {\n const req: WalletRequest = {\n id: `wreq-${this.walletRequestNextId++}`,\n kind,\n payload,\n timestamp: Date.now(),\n };\n this.walletRequests.push(req);\n return req;\n }\n\n private removeWalletRequest(id: string): WalletRequest | null {\n const idx = this.walletRequests.findIndex((r) => r.id === id);\n if (idx === -1) return null;\n return this.walletRequests.splice(idx, 1)[0];\n }\n\n // ===========================================================================\n // Internal — Helpers\n // ===========================================================================\n\n private async sendSystemEvent(\n type: string,\n payload: unknown,\n ): Promise<void> {\n const message = JSON.stringify({ type, payload });\n await this.client.sendSystemMessage(this.sessionId, message);\n }\n\n private resolvePending(): void {\n if (this.pendingResolve) {\n const resolve = this.pendingResolve;\n this.pendingResolve = null;\n resolve({ messages: this._messages, title: this._title });\n }\n }\n\n private assertOpen(): void {\n if (this.closed) {\n throw new Error(\"Session is closed\");\n }\n }\n\n private assertUserStateAligned(actualUserState?: UserState | null): void {\n if (!this.userState || !actualUserState) {\n return;\n }\n\n if (!isSubsetMatch(this.userState, actualUserState)) {\n const expected = JSON.stringify(sortJson(this.userState));\n const actual = JSON.stringify(sortJson(actualUserState));\n throw new Error(\n `Backend user_state mismatch. expected subset=${expected} actual=${actual}`,\n );\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC8BA,SAAS,eAAe,UAAiC;AACvD,QAAM,YAAY,SACf,MAAM,IAAI,EACV,OAAO,CAAC,SAAS,KAAK,WAAW,OAAO,CAAC,EACzC,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC,EAAE,UAAU,CAAC;AAC1C,MAAI,CAAC,UAAU,OAAQ,QAAO;AAC9B,SAAO,UAAU,KAAK,IAAI;AAC5B;AAEA,eAAe,cACb,QACA,QACA,WACe;AACf,QAAM,SAAS,OAAO,UAAU;AAChC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,SAAS;AAEb,MAAI;AACF,WAAO,CAAC,OAAO,SAAS;AACtB,YAAM,EAAE,OAAO,KAAK,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,KAAM;AAEV,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,eAAS,OAAO,QAAQ,OAAO,EAAE;AAEjC,UAAI,iBAAiB,OAAO,QAAQ,MAAM;AAC1C,aAAO,kBAAkB,GAAG;AAC1B,cAAM,WAAW,OAAO,MAAM,GAAG,cAAc;AAC/C,iBAAS,OAAO,MAAM,iBAAiB,CAAC;AACxC,cAAM,OAAO,eAAe,QAAQ;AACpC,YAAI,MAAM;AACR,oBAAU,IAAI;AAAA,QAChB;AACA,yBAAiB,OAAO,QAAQ,MAAM;AAAA,MACxC;AAAA,IACF;AAAA,EACF,UAAE;AACA,WAAO,YAAY;AAAA,EACrB;AACF;AAEO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AACF,GAAwC;AACtC,QAAM,gBAAgB,oBAAI,IAA6B;AAEvD,QAAM,YAAwC,CAC5C,WACA,UACA,YACG;AACH,UAAM,WAAW,cAAc,IAAI,SAAS;AAC5C,UAAM,WAAwB,EAAE,UAAU,QAAQ;AAClD,QAAI,UAAU;AACZ,eAAS,UAAU,IAAI,QAAQ;AAC/B,uCAAQ,MAAM,8BAA8B;AAAA,QAC1C;AAAA,QACA,WAAW,SAAS,UAAU;AAAA,MAChC;AACA,aAAO,MAAM;AACX,iBAAS,UAAU,OAAO,QAAQ;AAClC,yCAAQ,MAAM,gCAAgC;AAAA,UAC5C;AAAA,UACA,WAAW,SAAS,UAAU;AAAA,QAChC;AACA,YAAI,SAAS,UAAU,SAAS,GAAG;AACjC,mBAAS,KAAK,aAAa;AAC3B,cAAI,cAAc,IAAI,SAAS,MAAM,UAAU;AAC7C,0BAAc,OAAO,SAAS;AAAA,UAChC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAAgC;AAAA,MACpC,iBAAiB;AAAA,MACjB,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,WAAW,oBAAI,IAAI,CAAC,QAAQ,CAAC;AAAA,MAC7B,MAAM,CAAC,WAAoB;AAjHjC;AAkHQ,qBAAa,UAAU;AACvB,YAAI,aAAa,YAAY;AAC3B,uBAAa,aAAa,UAAU;AACpC,uBAAa,aAAa;AAAA,QAC5B;AACA,2BAAa,oBAAb,mBAA8B;AAC9B,qBAAa,kBAAkB;AAC/B,yCAAQ,MAAM,oBAAoB;AAAA,UAChC;AAAA,UACA;AAAA,UACA,SAAS,aAAa;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAEA,UAAM,gBAAgB,MAAM;AAC1B,UAAI,aAAa,QAAS;AAC1B,mBAAa,WAAW;AACxB,YAAM,UAAU,KAAK,IAAI,MAAM,MAAM,aAAa,UAAU,IAAI,GAAK;AACrE,uCAAQ,MAAM,+BAA+B;AAAA,QAC3C;AAAA,QACA;AAAA,QACA,SAAS,aAAa;AAAA,MACxB;AACA,mBAAa,aAAa,WAAW,MAAM;AACzC,aAAK,KAAK;AAAA,MACZ,GAAG,OAAO;AAAA,IACZ;AAEA,UAAM,OAAO,YAAY;AA/I7B;AAgJM,UAAI,aAAa,QAAS;AAC1B,UAAI,aAAa,YAAY;AAC3B,qBAAa,aAAa,UAAU;AACpC,qBAAa,aAAa;AAAA,MAC5B;AAEA,YAAM,aAAa,IAAI,gBAAgB;AACvC,mBAAa,kBAAkB;AAC/B,YAAM,WAAW,KAAK,IAAI;AAE1B,UAAI;AACF,cAAM,WAAW,MAAM,MAAM,GAAG,UAAU,gBAAgB;AAAA,UACxD,SAAS,WAAW,SAAS;AAAA,UAC7B,QAAQ,WAAW;AAAA,QACrB,CAAC;AAED,YAAI,CAAC,SAAS,IAAI;AAChB,gBAAM,IAAI;AAAA,YACR,YAAY,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,UACrD;AAAA,QACF;AAEA,YAAI,CAAC,SAAS,MAAM;AAClB,gBAAM,IAAI,MAAM,2BAA2B;AAAA,QAC7C;AAEA,qBAAa,UAAU;AAEvB,cAAM,cAAc,SAAS,MAAM,WAAW,QAAQ,CAAC,SAAS;AA5KxE,cAAAA,KAAA;AA6KU,cAAI;AACJ,cAAI;AACF,qBAAS,KAAK,MAAM,IAAI;AAAA,UAC1B,SAAS,OAAO;AACd,uBAAW,QAAQ,aAAa,WAAW;AACzC,eAAAA,MAAA,KAAK,YAAL,gBAAAA,IAAA,WAAe;AAAA,YACjB;AACA;AAAA,UACF;AAEA,qBAAW,QAAQ,aAAa,WAAW;AACzC,gBAAI;AACF,mBAAK,SAAS,MAAM;AAAA,YACtB,SAAS,OAAO;AACd,yBAAK,YAAL,8BAAe;AAAA,YACjB;AAAA,UACF;AAAA,QACF,CAAC;AACD,yCAAQ,MAAM,4BAA4B;AAAA,UACxC;AAAA,UACA,SAAS,WAAW,OAAO;AAAA,UAC3B,SAAS,aAAa;AAAA,UACtB,YAAY,KAAK,IAAI,IAAI;AAAA,QAC3B;AAAA,MACF,SAAS,OAAO;AACd,YAAI,CAAC,WAAW,OAAO,WAAW,CAAC,aAAa,SAAS;AACvD,qBAAW,QAAQ,aAAa,WAAW;AACzC,uBAAK,YAAL,8BAAe;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,aAAa,SAAS;AACzB,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,kBAAc,IAAI,WAAW,YAAY;AACzC,SAAK,KAAK;AAEV,WAAO,MAAM;AACX,mBAAa,UAAU,OAAO,QAAQ;AACtC,uCAAQ,MAAM,gCAAgC;AAAA,QAC5C;AAAA,QACA,WAAW,aAAa,UAAU;AAAA,MACpC;AACA,UAAI,aAAa,UAAU,SAAS,GAAG;AACrC,qBAAa,KAAK,aAAa;AAC/B,YAAI,cAAc,IAAI,SAAS,MAAM,cAAc;AACjD,wBAAc,OAAO,SAAS;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,UAAU;AACrB;;;ACjNA,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB;AAEvB,SAAS,cAAc,SAA0C;AAC/D,QAAM,SAAS,IAAI,gBAAgB;AACnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,WAAO,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,EAC/B;AACA,QAAM,KAAK,OAAO,SAAS;AAC3B,SAAO,KAAK,IAAI,EAAE,KAAK;AACzB;AAEA,SAAS,kBACP,WACA,MACa;AACb,QAAM,UAAU,IAAI,QAAQ,IAAI;AAChC,UAAQ,IAAI,mBAAmB,SAAS;AACxC,SAAO;AACT;AAEA,eAAe,UACb,SACA,MACA,SACA,WACA,QACY;AACZ,QAAM,QAAQ,cAAc,OAAO;AACnC,QAAM,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,KAAK;AAErC,QAAM,UAAU,IAAI,QAAQ,kBAAkB,SAAS,CAAC;AACxD,MAAI,QAAQ;AACV,YAAQ,IAAI,gBAAgB,MAAM;AAAA,EACpC;AAEA,QAAM,WAAW,MAAM,MAAM,KAAK;AAAA,IAChC,QAAQ;AAAA,IACR;AAAA,EACF,CAAC;AAED,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,EACnE;AAEA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAMO,IAAM,aAAN,MAAiB;AAAA,EAMtB,YAAY,SAA4B;AAEtC,SAAK,UAAU,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACjD,SAAK,SAAS,QAAQ;AACtB,SAAK,SAAS,QAAQ;AAEtB,SAAK,gBAAgB,oBAAoB;AAAA,MACvC,YAAY,KAAK;AAAA,MACjB,YAAY,CAAC,cACX,kBAAkB,WAAW,EAAE,QAAQ,oBAAoB,CAAC;AAAA,MAC9D,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,WACJ,WACA,WAC4B;AAC5B,UAAM,MAAM,IAAI,IAAI,cAAc,KAAK,OAAO;AAC9C,QAAI,WAAW;AACb,UAAI,aAAa,IAAI,cAAc,KAAK,UAAU,SAAS,CAAC;AAAA,IAC9D;AAEA,UAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,MAC3C,SAAS,kBAAkB,SAAS;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,IACnE;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YACJ,WACA,SACA,SAM2B;AApI/B;AAqII,UAAM,OAAM,wCAAS,QAAT,YAAgB;AAC5B,UAAM,UAAS,wCAAS,WAAT,YAAmB,KAAK;AAEvC,UAAM,UAAmC,EAAE,SAAS,IAAI;AACxD,QAAI,mCAAS,WAAW;AACtB,cAAQ,aAAa,QAAQ;AAAA,IAC/B;AACA,QAAI,mCAAS,WAAW;AACtB,cAAQ,aAAa,KAAK,UAAU,QAAQ,SAAS;AAAA,IACvD;AAEA,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,WACA,SAC6B;AAC7B,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,EAAE,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,WAAmD;AACjE,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,CAAC;AAAA,MACD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,aACE,WACA,UACA,SACY;AACZ,WAAO,KAAK,cAAc,UAAU,WAAW,UAAU,OAAO;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,YAAY,WAA0C;AAC1D,UAAM,MAAM,GAAG,KAAK,OAAO,4BAA4B,mBAAmB,SAAS,CAAC;AACpF,UAAM,WAAW,MAAM,MAAM,GAAG;AAEhC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,EAAE;AAAA,IACpE;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,WAAwC;AACtD,UAAM,MAAM,GAAG,KAAK,OAAO,iBAAiB,mBAAmB,SAAS,CAAC;AACzE,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,SAAS,kBAAkB,SAAS;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,IACnE;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,UACA,WACmC;AACnC,UAAM,OAA+B,CAAC;AACtC,QAAI,UAAW,MAAK,aAAa;AAEjC,UAAM,MAAM,GAAG,KAAK,OAAO;AAC3B,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,kBAAkB,UAAU;AAAA,QACnC,gBAAgB;AAAA,MAClB,CAAC;AAAA,MACD,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,EAAE;AAAA,IACpE;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,WAAkC;AACnD,UAAM,MAAM,GAAG,KAAK,OAAO,iBAAiB,mBAAmB,SAAS,CAAC;AACzE,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,kBAAkB,SAAS;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,EAAE;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aAAa,WAAmB,UAAiC;AACrE,UAAM,MAAM,GAAG,KAAK,OAAO,iBAAiB,mBAAmB,SAAS,CAAC;AACzE,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,kBAAkB,WAAW;AAAA,QACpC,gBAAgB;AAAA,MAClB,CAAC;AAAA,MACD,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,CAAC;AAAA,IAC1C,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,iCAAiC,SAAS,MAAM,EAAE;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,cAAc,WAAkC;AACpD,UAAM,MAAM,GAAG,KAAK,OAAO,iBAAiB,mBAAmB,SAAS,CAAC;AACzE,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,kBAAkB,SAAS;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,kCAAkC,SAAS,MAAM,EAAE;AAAA,IACrE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBAAgB,WAAkC;AACtD,UAAM,MAAM,GAAG,KAAK,OAAO,iBAAiB,mBAAmB,SAAS,CAAC;AACzE,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR,SAAS,kBAAkB,SAAS;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,oCAAoC,SAAS,MAAM,EAAE;AAAA,IACvE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,gBACJ,WACA,OAC4B;AAC5B,UAAM,MAAM,IAAI,IAAI,eAAe,KAAK,OAAO;AAC/C,QAAI,UAAU,QAAW;AACvB,UAAI,aAAa,IAAI,SAAS,OAAO,KAAK,CAAC;AAAA,IAC7C;AACA,UAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,MAC3C,SAAS,kBAAkB,SAAS;AAAA,IACtC,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,UAAI,SAAS,WAAW,IAAK,QAAO,CAAC;AACrC,YAAM,IAAI,MAAM,qCAAqC,SAAS,MAAM,EAAE;AAAA,IACxE;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,QACJ,WACA,SACmB;AArWvB;AAsWI,UAAM,MAAM,IAAI,IAAI,qBAAqB,KAAK,OAAO;AACrD,QAAI,mCAAS,WAAW;AACtB,UAAI,aAAa,IAAI,cAAc,QAAQ,SAAS;AAAA,IACtD;AAEA,UAAM,UAAS,wCAAS,WAAT,YAAmB,KAAK;AACvC,UAAM,UAAU,IAAI,QAAQ,kBAAkB,SAAS,CAAC;AACxD,QAAI,QAAQ;AACV,cAAQ,IAAI,gBAAgB,MAAM;AAAA,IACpC;AAEA,UAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG,EAAE,QAAQ,CAAC;AAExD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,4BAA4B,SAAS,MAAM,EAAE;AAAA,IAC/D;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UACJ,WACA,SACmB;AAhYvB;AAiYI,UAAM,MAAM,IAAI,IAAI,uBAAuB,KAAK,OAAO;AACvD,UAAM,UAAS,wCAAS,WAAT,YAAmB,KAAK;AACvC,UAAM,UAAU,IAAI,QAAQ,kBAAkB,SAAS,CAAC;AACxD,QAAI,QAAQ;AACV,cAAQ,IAAI,gBAAgB,MAAM;AAAA,IACpC;AAEA,UAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,MAC3C;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,8BAA8B,SAAS,MAAM,EAAE;AAAA,IACjE;AAEA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SACJ,WACA,KACA,SAMC;AA/ZL;AAgaI,UAAM,UAAS,wCAAS,WAAT,YAAmB,KAAK;AACvC,UAAM,UAAmC,EAAE,IAAI;AAC/C,QAAI,mCAAS,KAAK;AAChB,cAAQ,MAAM,QAAQ;AAAA,IACxB;AAEA,WAAO,UAKJ,KAAK,SAAS,sBAAsB,SAAS,WAAW,MAAM;AAAA,EACnE;AACF;;;ACpRO,SAAS,aACd,OAC8D;AAC9D,SAAO,gBAAgB;AACzB;AAEO,SAAS,eACd,OACmC;AACnC,SAAO,kBAAkB;AAC3B;AAEO,SAAS,cACd,OACkC;AAClC,SAAO,iBAAiB;AAC1B;AAEO,SAAS,gBACd,OACqD;AACrD,SAAO,mBAAmB;AAC5B;;;AC/JO,IAAM,oBAAN,MAEL;AAAA,EAFK;AAGL,SAAQ,YAAY,oBAAI,IAAkC;AAAA;AAAA;AAAA;AAAA;AAAA,EAK1D,GACE,MACA,SACY;AACZ,QAAI,MAAM,KAAK,UAAU,IAAI,IAAI;AACjC,QAAI,CAAC,KAAK;AACR,YAAM,oBAAI,IAAI;AACd,WAAK,UAAU,IAAI,MAAM,GAAG;AAAA,IAC9B;AACA,QAAI,IAAI,OAA0B;AAElC,WAAO,MAAM;AACX,UAAK,OAAO,OAA0B;AACtC,UAAI,IAAK,SAAS,GAAG;AACnB,aAAK,UAAU,OAAO,IAAI;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,KACE,MACA,SACY;AACZ,UAAM,WAAW,CAAC,YAAyB;AACzC,YAAM;AACN,cAAQ,OAAO;AAAA,IACjB;AAEA,UAAM,QAAQ,KAAK,GAAG,MAAM,OAAO;AACnC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,KACE,MACA,SACM;AAEN,UAAM,UAAU,KAAK,UAAU,IAAI,IAAI;AACvC,QAAI,SAAS;AACX,iBAAW,WAAW,SAAS;AAC7B,QAAC,QAAkC,OAAO;AAAA,MAC5C;AAAA,IACF;AAGA,QAAI,SAAS,KAAK;AAChB,YAAM,cAAc,KAAK,UAAU,IAAI,GAAG;AAC1C,UAAI,aAAa;AACf,mBAAW,WAAW,aAAa;AACjC,UAAC,QAA8B,EAAE,MAAM,QAAQ,CAAC;AAAA,QAClD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IACE,MACA,SACM;AACN,UAAM,MAAM,KAAK,UAAU,IAAI,IAAI;AACnC,QAAI,KAAK;AACP,UAAI,OAAO,OAA0B;AACrC,UAAI,IAAI,SAAS,GAAG;AAClB,aAAK,UAAU,OAAO,IAAI;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,qBAA2B;AACzB,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;;;AC9EO,SAAS,kBACd,OACuB;AA/BzB;AAgCE,MAAI,aAAa,KAAK,GAAG;AACvB,WAAO;AAAA,MACL,MAAM,MAAM,WAAW;AAAA,MACvB,UAAS,WAAM,WAAW,YAAjB,YAA4B,MAAM;AAAA,IAC7C;AAAA,EACF;AAEA,MAAI,eAAe,KAAK,GAAG;AACzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,EAAE,SAAS,MAAM,aAAa;AAAA,IACzC;AAAA,EACF;AAEA,MAAI,cAAc,KAAK,GAAG;AACxB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,EAAE,SAAS,MAAM,YAAY;AAAA,IACxC;AAAA,EACF;AAEA,MAAI,gBAAgB,KAAK,GAAG;AAC1B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,SAAS,MAAM;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AACT;;;AC1BA,SAAS,SAAS,OAA2C;AAC3D,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK;AAC5D,WAAO;AACT,SAAO;AACT;AAEA,SAAS,YAAY,SAAiC;AAzCtD;AA0CE,QAAM,OAAO,SAAS,OAAO;AAC7B,QAAM,aAAa,SAAS,6BAAM,IAAI;AACtC,UAAO,uCAAc,SAAd,YAAsB,CAAC;AAChC;AAEA,SAAS,aAAa,OAAoC;AACxD,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAM,UAAU,MAAM,KAAK;AAC3B,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,QAAQ,WAAW,IAAI,GAAG;AAC5B,UAAM,YAAY,OAAO,SAAS,QAAQ,MAAM,CAAC,GAAG,EAAE;AACtD,WAAO,OAAO,SAAS,SAAS,IAAI,YAAY;AAAA,EAClD;AAEA,QAAM,SAAS,OAAO,SAAS,SAAS,EAAE;AAC1C,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAUO,SAAS,mBAAmB,SAA0C;AAvE7E;AAwEE,QAAM,OAAO,SAAS,OAAO;AAC7B,QAAM,OAAO,YAAY,OAAO;AAChC,QAAM,MAAM,SAAS,6BAAM,GAAG;AAE9B,QAAM,KAAK,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AACnD,MAAI,CAAC,GAAI,QAAO;AAEhB,QAAM,WAAW,KAAK;AACtB,QAAM,QACJ,OAAO,aAAa,WAChB,WACA,OAAO,aAAa,YAAY,OAAO,SAAS,QAAQ,IACtD,OAAO,KAAK,MAAM,QAAQ,CAAC,IAC3B;AAER,QAAM,OAAO,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AACzD,QAAM,WACJ,8BAAa,KAAK,OAAO,MAAzB,YACA,aAAa,KAAK,QAAQ,MAD1B,YAEA,aAAa,2BAAK,aAAa,MAF/B,YAGA,aAAa,2BAAK,WAAW;AAE/B,SAAO,EAAE,IAAI,OAAO,MAAM,QAAQ;AACpC;AAKO,SAAS,uBACd,SACqB;AAtGvB;AAuGE,QAAM,OAAO,YAAY,OAAO;AAChC,QAAM,gBAAe,UAAK,eAAL,YAAmB,KAAK;AAC7C,MAAI;AAEJ,MAAI,OAAO,iBAAiB,UAAU;AACpC,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,YAAY;AACtC,UAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,oBAAY;AAAA,MACd;AAAA,IACF,SAAQ;AACN,kBAAY;AAAA,IACd;AAAA,EACF,WACE,gBACA,OAAO,iBAAiB,YACxB,CAAC,MAAM,QAAQ,YAAY,GAC3B;AACA,gBAAY;AAAA,EACd;AAEA,QAAM,cACJ,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAE5D,SAAO,EAAE,YAAY,WAAW,YAAY;AAC9C;;;ACrEA,SAAS,SAAS,OAAyB;AACzC,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,UAAU,SAAS,KAAK,CAAC;AAAA,EAC7C;AACA,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,WAAO,OAAO,KAAK,KAAgC,EAChD,KAAK,EACL,OAAgC,CAAC,KAAK,QAAQ;AAC7C,UAAI,GAAG,IAAI,SAAU,MAAkC,GAAG,CAAC;AAC3D,aAAO;AAAA,IACT,GAAG,CAAC,CAAC;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,cAAc,UAAmB,QAA0B;AAClE,MAAI,MAAM,QAAQ,QAAQ,GAAG;AAC3B,QAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,SAAS,WAAW,OAAO,QAAQ;AAC/D,aAAO;AAAA,IACT;AACA,WAAO,SAAS;AAAA,MAAM,CAAC,OAAO,UAC5B,cAAc,OAAO,OAAO,KAAK,CAAC;AAAA,IACpC;AAAA,EACF;AAEA,MAAI,YAAY,OAAO,aAAa,UAAU;AAC5C,QAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAEA,WAAO,OAAO,QAAQ,QAAmC,EAAE;AAAA,MACzD,CAAC,CAAC,KAAK,KAAK,MACV,cAAc,OAAQ,OAAmC,GAAG,CAAC;AAAA,IACjE;AAAA,EACF;AAEA,SAAO,aAAa;AACtB;AAqDO,IAAM,gBAAN,cAA4B,kBAAmC;AAAA,EA0BpE,YACE,iBACA,gBACA;AAlLJ;AAmLI,UAAM;AAhBR;AAAA,SAAQ,YAAmD;AAC3D,SAAQ,iBAAsC;AAC9C,SAAQ,gBAAgB;AACxB,SAAQ,iBAAkC,CAAC;AAC3C,SAAQ,sBAAsB;AAC9B,SAAQ,YAA2B,CAAC;AAEpC,SAAQ,SAAS;AAGjB;AAAA,SAAQ,iBAAwD;AAQ9D,SAAK,SACH,2BAA2B,aACvB,kBACA,IAAI,WAAW,eAAe;AAEpC,SAAK,aAAY,sDAAgB,cAAhB,YAA6B,OAAO,WAAW;AAChE,SAAK,OAAM,sDAAgB,QAAhB,YAAuB;AAClC,SAAK,YAAY,iDAAgB;AACjC,SAAK,SAAS,iDAAgB;AAC9B,SAAK,YAAY,iDAAgB;AACjC,SAAK,kBAAiB,sDAAgB,mBAAhB,YAAkC;AACxD,SAAK,SAAS,iDAAgB;AAG9B,SAAK,iBAAiB,KAAK,OAAO;AAAA,MAChC,KAAK;AAAA,MACL,CAAC,UAAU,KAAK,eAAe,KAAK;AAAA,MACpC,CAAC,UAAU,KAAK,KAAK,SAAS,EAAE,MAAM,CAAC;AAAA,IACzC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,MAAM,KAAK,SAAsC;AAC/C,SAAK,WAAW;AAEhB,UAAM,WAAW,MAAM,KAAK,OAAO,YAAY,KAAK,WAAW,SAAS;AAAA,MACtE,KAAK,KAAK;AAAA,MACV,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,IAClB,CAAC;AAED,SAAK,uBAAuB,SAAS,UAAU;AAC/C,SAAK,WAAW,QAAQ;AAExB,QAAI,CAAC,SAAS,iBAAiB,KAAK,eAAe,WAAW,GAAG;AAC/D,aAAO,EAAE,UAAU,KAAK,WAAW,OAAO,KAAK,OAAO;AAAA,IACxD;AAEA,SAAK,gBAAgB;AACrB,SAAK,KAAK,oBAAoB,MAAS;AAEvC,WAAO,IAAI,QAAoB,CAAC,YAAY;AAC1C,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAU,SAA4C;AAC1D,SAAK,WAAW;AAEhB,UAAM,WAAW,MAAM,KAAK,OAAO,YAAY,KAAK,WAAW,SAAS;AAAA,MACtE,KAAK,KAAK;AAAA,MACV,WAAW,KAAK;AAAA,MAChB,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,IAClB,CAAC;AAED,SAAK,uBAAuB,SAAS,UAAU;AAC/C,SAAK,WAAW,QAAQ;AAExB,QAAI,SAAS,eAAe;AAC1B,WAAK,gBAAgB;AACrB,WAAK,KAAK,oBAAoB,MAAS;AACvC,WAAK,aAAa;AAAA,IACpB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,QAAQ,WAAmB,QAA4C;AAlR/E;AAmRI,UAAM,MAAM,KAAK,oBAAoB,SAAS;AAC9C,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sCAAsC,SAAS,GAAG;AAAA,IACpE;AAEA,QAAI,IAAI,SAAS,eAAe;AAC9B,YAAM,KAAK,gBAAgB,sBAAsB;AAAA,QAC/C,SAAQ,YAAO,WAAP,YAAiB;AAAA,QACzB,QAAQ;AAAA,QACR,QAAQ,OAAO;AAAA,MACjB,CAAC;AAAA,IACH,OAAO;AACL,YAAM,gBAAgB,IAAI;AAC1B,YAAM,KAAK,gBAAgB,0BAA0B;AAAA,QACnD,QAAQ;AAAA,QACR,WAAW,OAAO;AAAA,QAClB,aAAa,cAAc;AAAA,MAC7B,CAAC;AAAA,IACH;AAGA,QAAI,KAAK,eAAe;AACtB,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,WAAmB,QAAgC;AAC9D,UAAM,MAAM,KAAK,oBAAoB,SAAS;AAC9C,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,sCAAsC,SAAS,GAAG;AAAA,IACpE;AAEA,QAAI,IAAI,SAAS,eAAe;AAC9B,YAAM,KAAK,gBAAgB,sBAAsB;AAAA,QAC/C,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,OAAO;AACL,YAAM,gBAAgB,IAAI;AAC1B,YAAM,KAAK,gBAAgB,0BAA0B;AAAA,QACnD,QAAQ;AAAA,QACR,OAAO,0BAAU;AAAA,QACjB,aAAa,cAAc;AAAA,MAC7B,CAAC;AAAA,IACH;AAEA,QAAI,KAAK,eAAe;AACtB,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,YAA2B;AAC/B,SAAK,YAAY;AACjB,UAAM,WAAW,MAAM,KAAK,OAAO,UAAU,KAAK,SAAS;AAC3D,SAAK,WAAW,QAAQ;AACxB,SAAK,gBAAgB;AACrB,SAAK,KAAK,kBAAkB,MAAS;AACrC,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AA9VhB;AA+VI,QAAI,KAAK,OAAQ;AACjB,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,eAAK,mBAAL;AACA,SAAK,iBAAiB;AACtB,SAAK,eAAe;AACpB,SAAK,mBAAmB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAA6B;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,WAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,qBAAsC;AACpC,WAAO,CAAC,GAAG,KAAK,cAAc;AAAA,EAChC;AAAA;AAAA,EAGA,kBAA2B;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAiB,WAA4B;AAC3C,SAAK,YAAY;AAEjB,UAAM,UAAU,UAAU,SAAS;AACnC,QAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,GAAG;AACrD,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,cAAc,SAAiB,SAAwB;AACrD,SAAK,iBAAiB,EAAE,SAAS,SAAS,4BAAW,GAAG,aAAa,KAAK,CAAC;AAAA,EAC7E;AAAA,EAEA,MAAM,gBAA4C;AAChD,SAAK,WAAW;AAEhB,UAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,KAAK,WAAW,KAAK,SAAS;AACzE,SAAK,uBAAuB,MAAM,UAAU;AAC5C,SAAK,WAAW,KAAK;AACrB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAqB;AA1Z/B;AA2ZI,QAAI,KAAK,aAAa,KAAK,OAAQ;AAEnC,eAAK,WAAL,mBAAa,MAAM,6BAA6B,KAAK;AACrD,SAAK,YAAY,YAAY,MAAM;AACjC,WAAK,KAAK,SAAS;AAAA,IACrB,GAAG,KAAK,cAAc;AAAA,EACxB;AAAA,EAEQ,cAAoB;AAna9B;AAoaI,QAAI,KAAK,WAAW;AAClB,oBAAc,KAAK,SAAS;AAC5B,WAAK,YAAY;AACjB,iBAAK,WAAL,mBAAa,MAAM,6BAA6B,KAAK;AAAA,IACvD;AAAA,EACF;AAAA,EAEA,MAAc,WAA0B;AA3a1C;AA4aI,QAAI,CAAC,KAAK,UAAW;AAErB,QAAI;AACF,YAAM,QAAQ,MAAM,KAAK,OAAO;AAAA,QAC9B,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAGA,UAAI,CAAC,KAAK,UAAW;AAErB,WAAK,uBAAuB,MAAM,UAAU;AAC5C,WAAK,WAAW,KAAK;AAErB,UAAI,CAAC,MAAM,iBAAiB,KAAK,eAAe,WAAW,GAAG;AAC5D,aAAK,YAAY;AACjB,aAAK,gBAAgB;AACrB,aAAK,KAAK,kBAAkB,MAAS;AACrC,aAAK,eAAe;AAAA,MACtB;AAAA,IACF,SAAS,OAAO;AACd,iBAAK,WAAL,mBAAa,MAAM,wBAAwB;AAC3C,WAAK,KAAK,SAAS,EAAE,MAAM,CAAC;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,WACN,OAIM;AA/cV;AAgdI,QAAI,MAAM,UAAU;AAClB,WAAK,YAAY,MAAM;AACvB,WAAK,KAAK,YAAY,KAAK,SAAS;AAAA,IACtC;AAEA,QAAI,MAAM,OAAO;AACf,WAAK,SAAS,MAAM;AAAA,IACtB;AAEA,SAAI,WAAM,kBAAN,mBAAqB,QAAQ;AAC/B,WAAK,qBAAqB,MAAM,aAAa;AAAA,IAC/C;AAAA,EACF;AAAA,EAEQ,qBAAqB,QAAiC;AA9dhE;AA+dI,eAAW,SAAS,QAAQ;AAC1B,YAAM,YAAY,kBAAkB,KAAK;AACzC,UAAI,CAAC,UAAW;AAEhB,UAAI,UAAU,SAAS,qBAAqB;AAC1C,cAAM,UAAU,mBAAmB,UAAU,OAAO;AACpD,YAAI,SAAS;AACX,gBAAM,MAAM,KAAK,qBAAqB,eAAe,OAAO;AAC5D,eAAK,KAAK,qBAAqB,GAAG;AAAA,QACpC;AAAA,MACF,WAAW,UAAU,SAAS,yBAAyB;AACrD,cAAM,UAAU,wBAAuB,eAAU,YAAV,YAAqB,CAAC,CAAC;AAC9D,cAAM,MAAM,KAAK,qBAAqB,eAAe,OAAO;AAC5D,aAAK,KAAK,yBAAyB,GAAG;AAAA,MACxC,WACE,UAAU,SAAS,mBACnB,UAAU,SAAS,kBACnB,UAAU,SAAS,kBACnB;AAEA,aAAK;AAAA,UACH,UAAU;AAAA,UACV,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,eAAe,OAA2B;AAChD,QAAI,MAAM,SAAS,mBAAmB,MAAM,WAAW;AACrD,WAAK,SAAS,MAAM;AACpB,WAAK,KAAK,iBAAiB,EAAE,OAAO,MAAM,UAAU,CAAC;AAAA,IACvD,WAAW,MAAM,SAAS,eAAe;AACvC,WAAK,KAAK,eAAe,KAAK;AAAA,IAChC,WAAW,MAAM,SAAS,iBAAiB;AACzC,WAAK,KAAK,iBAAiB,KAAK;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,qBACN,MACA,SACe;AACf,UAAM,MAAqB;AAAA,MACzB,IAAI,QAAQ,KAAK,qBAAqB;AAAA,MACtC;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AACA,SAAK,eAAe,KAAK,GAAG;AAC5B,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,IAAkC;AAC5D,UAAM,MAAM,KAAK,eAAe,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AAC5D,QAAI,QAAQ,GAAI,QAAO;AACvB,WAAO,KAAK,eAAe,OAAO,KAAK,CAAC,EAAE,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBACZ,MACA,SACe;AACf,UAAM,UAAU,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAChD,UAAM,KAAK,OAAO,kBAAkB,KAAK,WAAW,OAAO;AAAA,EAC7D;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,KAAK,gBAAgB;AACvB,YAAM,UAAU,KAAK;AACrB,WAAK,iBAAiB;AACtB,cAAQ,EAAE,UAAU,KAAK,WAAW,OAAO,KAAK,OAAO,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,aAAmB;AACzB,QAAI,KAAK,QAAQ;AACf,YAAM,IAAI,MAAM,mBAAmB;AAAA,IACrC;AAAA,EACF;AAAA,EAEQ,uBAAuB,iBAA0C;AACvE,QAAI,CAAC,KAAK,aAAa,CAAC,iBAAiB;AACvC;AAAA,IACF;AAEA,QAAI,CAAC,cAAc,KAAK,WAAW,eAAe,GAAG;AACnD,YAAM,WAAW,KAAK,UAAU,SAAS,KAAK,SAAS,CAAC;AACxD,YAAM,SAAS,KAAK,UAAU,SAAS,eAAe,CAAC;AACvD,YAAM,IAAI;AAAA,QACR,gDAAgD,QAAQ,WAAW,MAAM;AAAA,MAC3E;AAAA,IACF;AAAA,EACF;AACF;","names":["_a"]}
|