ai-functions 0.4.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +9 -0
- package/dist/rpc/auth.d.ts +69 -0
- package/dist/rpc/auth.d.ts.map +1 -0
- package/dist/rpc/auth.js +136 -0
- package/dist/rpc/auth.js.map +1 -0
- package/dist/rpc/client.d.ts +62 -0
- package/dist/rpc/client.d.ts.map +1 -0
- package/dist/rpc/client.js +103 -0
- package/dist/rpc/client.js.map +1 -0
- package/dist/rpc/deferred.d.ts +60 -0
- package/dist/rpc/deferred.d.ts.map +1 -0
- package/dist/rpc/deferred.js +96 -0
- package/dist/rpc/deferred.js.map +1 -0
- package/dist/rpc/index.d.ts +22 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +38 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/rpc/local.d.ts +42 -0
- package/dist/rpc/local.d.ts.map +1 -0
- package/dist/rpc/local.js +50 -0
- package/dist/rpc/local.js.map +1 -0
- package/dist/rpc/server.d.ts +165 -0
- package/dist/rpc/server.d.ts.map +1 -0
- package/dist/rpc/server.js +405 -0
- package/dist/rpc/server.js.map +1 -0
- package/dist/rpc/session.d.ts +32 -0
- package/dist/rpc/session.d.ts.map +1 -0
- package/dist/rpc/session.js +43 -0
- package/dist/rpc/session.js.map +1 -0
- package/dist/rpc/transport.d.ts +306 -0
- package/dist/rpc/transport.d.ts.map +1 -0
- package/dist/rpc/transport.js +731 -0
- package/dist/rpc/transport.js.map +1 -0
- package/package.json +1 -1
- package/.turbo/turbo-test.log +0 -105
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local RPC target for in-memory implementations
|
|
3
|
+
*
|
|
4
|
+
* Allows using the same RPC semantics (including promise pipelining)
|
|
5
|
+
* for local in-memory implementations, useful for:
|
|
6
|
+
* - Testing
|
|
7
|
+
* - Client-side caching
|
|
8
|
+
* - Offline support
|
|
9
|
+
* - Development without a server
|
|
10
|
+
*/
|
|
11
|
+
import { RpcTarget } from 'capnweb';
|
|
12
|
+
/**
|
|
13
|
+
* Create a local RPC target that can be used with the same API
|
|
14
|
+
* as remote targets, but executes locally.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* class MyLocalAPI extends RpcTarget {
|
|
19
|
+
* async getData(id: string) {
|
|
20
|
+
* return this.localStore.get(id)
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* const api = createLocalTarget(new MyLocalAPI())
|
|
25
|
+
* const data = await api.getData('123') // Executes locally
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function createLocalTarget<T extends RpcTarget>(target: T): T;
|
|
29
|
+
/**
|
|
30
|
+
* Base class for local implementations that mirror remote APIs
|
|
31
|
+
*/
|
|
32
|
+
export declare abstract class LocalTarget extends RpcTarget {
|
|
33
|
+
/**
|
|
34
|
+
* Override to provide initialization logic
|
|
35
|
+
*/
|
|
36
|
+
initialize(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Override to provide cleanup logic
|
|
39
|
+
*/
|
|
40
|
+
dispose(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../src/rpc/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnC;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,SAAS,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAInE;AAED;;GAEG;AACH,8BAAsB,WAAY,SAAQ,SAAS;IACjD;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local RPC target for in-memory implementations
|
|
3
|
+
*
|
|
4
|
+
* Allows using the same RPC semantics (including promise pipelining)
|
|
5
|
+
* for local in-memory implementations, useful for:
|
|
6
|
+
* - Testing
|
|
7
|
+
* - Client-side caching
|
|
8
|
+
* - Offline support
|
|
9
|
+
* - Development without a server
|
|
10
|
+
*/
|
|
11
|
+
import { RpcTarget } from 'capnweb';
|
|
12
|
+
/**
|
|
13
|
+
* Create a local RPC target that can be used with the same API
|
|
14
|
+
* as remote targets, but executes locally.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* class MyLocalAPI extends RpcTarget {
|
|
19
|
+
* async getData(id: string) {
|
|
20
|
+
* return this.localStore.get(id)
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* const api = createLocalTarget(new MyLocalAPI())
|
|
25
|
+
* const data = await api.getData('123') // Executes locally
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function createLocalTarget(target) {
|
|
29
|
+
// For local targets, we can return the target directly
|
|
30
|
+
// since capnweb's RpcTarget already handles method calls properly
|
|
31
|
+
return target;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Base class for local implementations that mirror remote APIs
|
|
35
|
+
*/
|
|
36
|
+
export class LocalTarget extends RpcTarget {
|
|
37
|
+
/**
|
|
38
|
+
* Override to provide initialization logic
|
|
39
|
+
*/
|
|
40
|
+
async initialize() {
|
|
41
|
+
// Default: no initialization needed
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Override to provide cleanup logic
|
|
45
|
+
*/
|
|
46
|
+
async dispose() {
|
|
47
|
+
// Default: no cleanup needed
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/rpc/local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAEnC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,iBAAiB,CAAsB,MAAS;IAC9D,uDAAuD;IACvD,kEAAkE;IAClE,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;GAEG;AACH,MAAM,OAAgB,WAAY,SAAQ,SAAS;IACjD;;OAEG;IACH,KAAK,CAAC,UAAU;QACd,oCAAoC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACX,6BAA6B;IAC/B,CAAC;CACF"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono RPC Server Handlers
|
|
3
|
+
*
|
|
4
|
+
* Provides RPC endpoints for:
|
|
5
|
+
* - HTTP batch requests (POST /rpc)
|
|
6
|
+
* - WebSocket persistent connections (GET /rpc/ws)
|
|
7
|
+
* - postMessage bridge for iframe communication (GET /rpc/bridge)
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import type { Context, Hono, MiddlewareHandler } from 'hono';
|
|
12
|
+
import type { WSContext } from 'hono/ws';
|
|
13
|
+
/**
|
|
14
|
+
* RPC method handler function
|
|
15
|
+
*/
|
|
16
|
+
export type RPCMethod<TContext = unknown> = (ctx: TContext, ...args: unknown[]) => unknown | Promise<unknown>;
|
|
17
|
+
/**
|
|
18
|
+
* Collection of RPC methods
|
|
19
|
+
*/
|
|
20
|
+
export type RPCMethods<TContext = unknown> = Record<string, RPCMethod<TContext>>;
|
|
21
|
+
/**
|
|
22
|
+
* Options for creating an RPC handler
|
|
23
|
+
*/
|
|
24
|
+
export interface RPCHandlerOptions<TContext = unknown> {
|
|
25
|
+
/** Available RPC methods */
|
|
26
|
+
methods: RPCMethods<TContext>;
|
|
27
|
+
/** Create context from request (for auth, etc) */
|
|
28
|
+
createContext?: (c: Context) => TContext | Promise<TContext>;
|
|
29
|
+
/** Called before each method invocation */
|
|
30
|
+
onCall?: (method: string, params: unknown[], ctx: TContext) => void | Promise<void>;
|
|
31
|
+
/** Called after each method invocation */
|
|
32
|
+
onResult?: (method: string, result: unknown, ctx: TContext) => void | Promise<void>;
|
|
33
|
+
/** Called on errors */
|
|
34
|
+
onError?: (method: string, error: Error, ctx: TContext) => void | Promise<void>;
|
|
35
|
+
/** Allowed origins for CORS (default: '*') */
|
|
36
|
+
allowedOrigins?: string[] | '*';
|
|
37
|
+
/** Allowed origins for postMessage bridge */
|
|
38
|
+
bridgeOrigins?: string[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create HTTP batch RPC handler
|
|
42
|
+
*/
|
|
43
|
+
export declare function createHTTPHandler<TContext>(options: RPCHandlerOptions<TContext>): MiddlewareHandler;
|
|
44
|
+
/**
|
|
45
|
+
* Create WebSocket RPC handler for Hono
|
|
46
|
+
*
|
|
47
|
+
* Usage with hono/ws:
|
|
48
|
+
* ```ts
|
|
49
|
+
* import { upgradeWebSocket } from 'hono/cloudflare-workers' // or hono/bun, etc
|
|
50
|
+
*
|
|
51
|
+
* app.get('/rpc/ws', upgradeWebSocket(createWSHandler({ methods })))
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare function createWSHandler<TContext>(options: RPCHandlerOptions<TContext>): (c: Context) => {
|
|
55
|
+
onOpen(_evt: Event, ws: WSContext): Promise<void>;
|
|
56
|
+
onMessage(evt: MessageEvent, ws: WSContext): Promise<void>;
|
|
57
|
+
onClose(_evt: CloseEvent, _ws: WSContext): void;
|
|
58
|
+
onError(evt: Event, _ws: WSContext): void;
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Generate the postMessage bridge HTML/JS
|
|
62
|
+
*
|
|
63
|
+
* This creates a lightweight page that:
|
|
64
|
+
* 1. Listens for postMessage from parent window
|
|
65
|
+
* 2. Makes authenticated fetch/WS calls to the RPC endpoint
|
|
66
|
+
* 3. Posts results back to parent
|
|
67
|
+
*/
|
|
68
|
+
export declare function createBridgeHandler<TContext>(options: RPCHandlerOptions<TContext> & {
|
|
69
|
+
/** RPC endpoint URL (default: '/rpc') */
|
|
70
|
+
rpcUrl?: string;
|
|
71
|
+
/** WebSocket URL (default: derived from rpcUrl) */
|
|
72
|
+
wsUrl?: string;
|
|
73
|
+
}): MiddlewareHandler;
|
|
74
|
+
/**
|
|
75
|
+
* Create a complete RPC middleware that handles all transports
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { Hono } from 'hono'
|
|
80
|
+
* import { upgradeWebSocket } from 'hono/cloudflare-workers'
|
|
81
|
+
* import { createRPCMiddleware } from 'ai-functions/rpc'
|
|
82
|
+
*
|
|
83
|
+
* const app = new Hono()
|
|
84
|
+
*
|
|
85
|
+
* const rpc = createRPCMiddleware({
|
|
86
|
+
* methods: {
|
|
87
|
+
* greet: (ctx, name) => `Hello, ${name}!`,
|
|
88
|
+
* getUser: async (ctx, id) => db.users.get(id),
|
|
89
|
+
* },
|
|
90
|
+
* createContext: (c) => ({
|
|
91
|
+
* user: c.get('user'),
|
|
92
|
+
* db: c.get('db'),
|
|
93
|
+
* }),
|
|
94
|
+
* bridgeOrigins: ['https://myapp.com', 'https://app.myapp.com'],
|
|
95
|
+
* })
|
|
96
|
+
*
|
|
97
|
+
* // Single /rpc endpoint for both HTTP POST and WebSocket GET
|
|
98
|
+
* app.post('/rpc', rpc.http)
|
|
99
|
+
* app.get('/rpc', upgradeWebSocket(rpc.ws))
|
|
100
|
+
*
|
|
101
|
+
* // postMessage bridge HTML (embed in iframe for cross-origin auth)
|
|
102
|
+
* app.get('/rpc.html', rpc.bridge)
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function createRPCMiddleware<TContext>(options: RPCHandlerOptions<TContext> & {
|
|
106
|
+
rpcUrl?: string;
|
|
107
|
+
wsUrl?: string;
|
|
108
|
+
}): {
|
|
109
|
+
/** HTTP batch handler */
|
|
110
|
+
http: MiddlewareHandler;
|
|
111
|
+
/** WebSocket handler (use with upgradeWebSocket) */
|
|
112
|
+
ws: (c: Context) => {
|
|
113
|
+
onOpen(_evt: Event, ws: WSContext): Promise<void>;
|
|
114
|
+
onMessage(evt: MessageEvent, ws: WSContext): Promise<void>;
|
|
115
|
+
onClose(_evt: CloseEvent, _ws: WSContext): void;
|
|
116
|
+
onError(evt: Event, _ws: WSContext): void;
|
|
117
|
+
};
|
|
118
|
+
/** postMessage bridge handler */
|
|
119
|
+
bridge: MiddlewareHandler;
|
|
120
|
+
/** The methods for direct access */
|
|
121
|
+
methods: RPCMethods<TContext>;
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Mount all RPC routes on a Hono app
|
|
125
|
+
*
|
|
126
|
+
* Single endpoint handles both HTTP POST and WebSocket upgrade:
|
|
127
|
+
* - POST /rpc → HTTP batch requests
|
|
128
|
+
* - GET /rpc (with Upgrade header) → WebSocket connection
|
|
129
|
+
* - GET /rpc.html → postMessage bridge for iframe embedding
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```ts
|
|
133
|
+
* import { Hono } from 'hono'
|
|
134
|
+
* import { upgradeWebSocket } from 'hono/cloudflare-workers'
|
|
135
|
+
* import { mountRPC } from 'ai-functions/rpc'
|
|
136
|
+
*
|
|
137
|
+
* const app = new Hono()
|
|
138
|
+
*
|
|
139
|
+
* mountRPC(app, '/rpc', {
|
|
140
|
+
* methods: { ... },
|
|
141
|
+
* upgradeWebSocket,
|
|
142
|
+
* })
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
export declare function mountRPC<TContext>(app: Hono, basePath: string, options: RPCHandlerOptions<TContext> & {
|
|
146
|
+
rpcUrl?: string;
|
|
147
|
+
wsUrl?: string;
|
|
148
|
+
/** WebSocket upgrade function from hono adapter */
|
|
149
|
+
upgradeWebSocket?: (handler: ReturnType<typeof createWSHandler>) => MiddlewareHandler;
|
|
150
|
+
}): {
|
|
151
|
+
/** HTTP batch handler */
|
|
152
|
+
http: MiddlewareHandler;
|
|
153
|
+
/** WebSocket handler (use with upgradeWebSocket) */
|
|
154
|
+
ws: (c: Context) => {
|
|
155
|
+
onOpen(_evt: Event, ws: WSContext): Promise<void>;
|
|
156
|
+
onMessage(evt: MessageEvent, ws: WSContext): Promise<void>;
|
|
157
|
+
onClose(_evt: CloseEvent, _ws: WSContext): void;
|
|
158
|
+
onError(evt: Event, _ws: WSContext): void;
|
|
159
|
+
};
|
|
160
|
+
/** postMessage bridge handler */
|
|
161
|
+
bridge: MiddlewareHandler;
|
|
162
|
+
/** The methods for direct access */
|
|
163
|
+
methods: RPCMethods<TContext>;
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/rpc/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono RPC Server Handlers
|
|
3
|
+
*
|
|
4
|
+
* Provides RPC endpoints for:
|
|
5
|
+
* - HTTP batch requests (POST /rpc)
|
|
6
|
+
* - WebSocket persistent connections (GET /rpc/ws)
|
|
7
|
+
* - postMessage bridge for iframe communication (GET /rpc/bridge)
|
|
8
|
+
*
|
|
9
|
+
* @packageDocumentation
|
|
10
|
+
*/
|
|
11
|
+
import { applyChain } from './deferred.js';
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// HTTP Batch Handler
|
|
14
|
+
// =============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Process a single RPC call
|
|
17
|
+
*/
|
|
18
|
+
async function processCall(call, methods, ctx, options) {
|
|
19
|
+
const { method, params = [], chain, id } = call;
|
|
20
|
+
if (!method) {
|
|
21
|
+
return {
|
|
22
|
+
id,
|
|
23
|
+
type: 'error',
|
|
24
|
+
error: { message: 'Method name required', code: 'INVALID_REQUEST' },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const handler = methods[method];
|
|
28
|
+
if (!handler) {
|
|
29
|
+
return {
|
|
30
|
+
id,
|
|
31
|
+
type: 'error',
|
|
32
|
+
error: { message: `Unknown method: ${method}`, code: 'METHOD_NOT_FOUND' },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
try {
|
|
36
|
+
// Pre-call hook
|
|
37
|
+
await options.onCall?.(method, params, ctx);
|
|
38
|
+
// Execute the method
|
|
39
|
+
let result = await handler(ctx, ...params);
|
|
40
|
+
// Apply chain operations (promise pipelining)
|
|
41
|
+
if (chain && chain.length > 0) {
|
|
42
|
+
result = applyChain(result, chain);
|
|
43
|
+
}
|
|
44
|
+
// Post-call hook
|
|
45
|
+
await options.onResult?.(method, result, ctx);
|
|
46
|
+
return { id, type: 'result', result };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
50
|
+
await options.onError?.(method, err, ctx);
|
|
51
|
+
return {
|
|
52
|
+
id,
|
|
53
|
+
type: 'error',
|
|
54
|
+
error: {
|
|
55
|
+
message: err.message,
|
|
56
|
+
code: 'INTERNAL_ERROR',
|
|
57
|
+
stack: process.env.NODE_ENV === 'development' ? err.stack : undefined,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create HTTP batch RPC handler
|
|
64
|
+
*/
|
|
65
|
+
export function createHTTPHandler(options) {
|
|
66
|
+
const { methods, createContext, allowedOrigins = '*' } = options;
|
|
67
|
+
return async (c) => {
|
|
68
|
+
// Handle CORS
|
|
69
|
+
const origin = c.req.header('origin');
|
|
70
|
+
if (allowedOrigins === '*') {
|
|
71
|
+
c.header('Access-Control-Allow-Origin', '*');
|
|
72
|
+
}
|
|
73
|
+
else if (origin && allowedOrigins.includes(origin)) {
|
|
74
|
+
c.header('Access-Control-Allow-Origin', origin);
|
|
75
|
+
}
|
|
76
|
+
c.header('Access-Control-Allow-Methods', 'POST, OPTIONS');
|
|
77
|
+
c.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
78
|
+
if (c.req.method === 'OPTIONS') {
|
|
79
|
+
return new Response(null, { status: 204 });
|
|
80
|
+
}
|
|
81
|
+
// Parse request body
|
|
82
|
+
let calls;
|
|
83
|
+
try {
|
|
84
|
+
const body = await c.req.json();
|
|
85
|
+
calls = Array.isArray(body) ? body : [body];
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return c.json({ error: { message: 'Invalid JSON', code: 'PARSE_ERROR' } }, 400);
|
|
89
|
+
}
|
|
90
|
+
// Create context
|
|
91
|
+
const ctx = createContext ? await createContext(c) : {};
|
|
92
|
+
// Process all calls
|
|
93
|
+
const results = await Promise.all(calls.map((call) => processCall(call, methods, ctx, options)));
|
|
94
|
+
return c.json(results);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
// =============================================================================
|
|
98
|
+
// WebSocket Handler
|
|
99
|
+
// =============================================================================
|
|
100
|
+
/**
|
|
101
|
+
* Create WebSocket RPC handler for Hono
|
|
102
|
+
*
|
|
103
|
+
* Usage with hono/ws:
|
|
104
|
+
* ```ts
|
|
105
|
+
* import { upgradeWebSocket } from 'hono/cloudflare-workers' // or hono/bun, etc
|
|
106
|
+
*
|
|
107
|
+
* app.get('/rpc/ws', upgradeWebSocket(createWSHandler({ methods })))
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export function createWSHandler(options) {
|
|
111
|
+
const { methods, createContext } = options;
|
|
112
|
+
return (c) => {
|
|
113
|
+
let ctx;
|
|
114
|
+
// Server-side callback registry for this connection
|
|
115
|
+
const callbackRegistry = {
|
|
116
|
+
callbacks: new Map(),
|
|
117
|
+
invoke: async (id, args) => {
|
|
118
|
+
const fn = callbackRegistry.callbacks.get(id);
|
|
119
|
+
if (!fn)
|
|
120
|
+
throw new Error(`Callback not found: ${id}`);
|
|
121
|
+
return fn(...args);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
return {
|
|
125
|
+
async onOpen(_evt, ws) {
|
|
126
|
+
ctx = createContext ? await createContext(c) : {};
|
|
127
|
+
},
|
|
128
|
+
async onMessage(evt, ws) {
|
|
129
|
+
let message;
|
|
130
|
+
try {
|
|
131
|
+
message = JSON.parse(evt.data);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
ws.send(JSON.stringify({
|
|
135
|
+
type: 'error',
|
|
136
|
+
error: { message: 'Invalid JSON', code: 'PARSE_ERROR' },
|
|
137
|
+
}));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Handle ping
|
|
141
|
+
if (message.type === 'ping') {
|
|
142
|
+
ws.send(JSON.stringify({ type: 'pong' }));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
// Handle callback response
|
|
146
|
+
if (message.type === 'result' && message.callbackId) {
|
|
147
|
+
// Client is responding to a callback we invoked
|
|
148
|
+
// This would be handled by pending callback promises
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Handle RPC call
|
|
152
|
+
if (message.type === 'call') {
|
|
153
|
+
const result = await processCall(message, methods, ctx, options);
|
|
154
|
+
ws.send(JSON.stringify(result));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
// Handle cancel (for streaming)
|
|
158
|
+
if (message.type === 'cancel') {
|
|
159
|
+
// Could implement stream cancellation here
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
onClose(_evt, _ws) {
|
|
164
|
+
// Cleanup callback registry
|
|
165
|
+
callbackRegistry.callbacks.clear();
|
|
166
|
+
},
|
|
167
|
+
onError(evt, _ws) {
|
|
168
|
+
console.error('WebSocket error:', evt);
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
// =============================================================================
|
|
174
|
+
// postMessage Bridge
|
|
175
|
+
// =============================================================================
|
|
176
|
+
/**
|
|
177
|
+
* Generate the postMessage bridge HTML/JS
|
|
178
|
+
*
|
|
179
|
+
* This creates a lightweight page that:
|
|
180
|
+
* 1. Listens for postMessage from parent window
|
|
181
|
+
* 2. Makes authenticated fetch/WS calls to the RPC endpoint
|
|
182
|
+
* 3. Posts results back to parent
|
|
183
|
+
*/
|
|
184
|
+
export function createBridgeHandler(options) {
|
|
185
|
+
const { bridgeOrigins = [], rpcUrl = '/rpc', wsUrl } = options;
|
|
186
|
+
// Generate allowed origins check
|
|
187
|
+
const originsCheck = bridgeOrigins.length === 0
|
|
188
|
+
? 'true' // Allow all in dev
|
|
189
|
+
: `[${bridgeOrigins.map((o) => `'${o}'`).join(',')}].includes(event.origin)`;
|
|
190
|
+
const bridgeScript = `
|
|
191
|
+
<!DOCTYPE html>
|
|
192
|
+
<html>
|
|
193
|
+
<head>
|
|
194
|
+
<title>RPC Bridge</title>
|
|
195
|
+
<script>
|
|
196
|
+
(function() {
|
|
197
|
+
const RPC_URL = '${rpcUrl}';
|
|
198
|
+
const WS_URL = ${wsUrl ? `'${wsUrl}'` : 'null'};
|
|
199
|
+
const pendingRequests = new Map();
|
|
200
|
+
let ws = null;
|
|
201
|
+
let wsReady = false;
|
|
202
|
+
let wsQueue = [];
|
|
203
|
+
|
|
204
|
+
// Connect WebSocket if available
|
|
205
|
+
function connectWS() {
|
|
206
|
+
if (!WS_URL) return;
|
|
207
|
+
|
|
208
|
+
ws = new WebSocket(WS_URL);
|
|
209
|
+
|
|
210
|
+
ws.onopen = () => {
|
|
211
|
+
wsReady = true;
|
|
212
|
+
// Flush queued messages
|
|
213
|
+
wsQueue.forEach(msg => ws.send(JSON.stringify(msg)));
|
|
214
|
+
wsQueue = [];
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
ws.onmessage = (event) => {
|
|
218
|
+
const msg = JSON.parse(event.data);
|
|
219
|
+
const pending = pendingRequests.get(msg.id);
|
|
220
|
+
if (pending) {
|
|
221
|
+
pendingRequests.delete(msg.id);
|
|
222
|
+
pending.source.postMessage({
|
|
223
|
+
type: 'rpc-response',
|
|
224
|
+
id: msg.id,
|
|
225
|
+
result: msg.result,
|
|
226
|
+
error: msg.error
|
|
227
|
+
}, pending.origin);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
ws.onclose = () => {
|
|
232
|
+
wsReady = false;
|
|
233
|
+
// Reconnect after delay
|
|
234
|
+
setTimeout(connectWS, 1000);
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Make HTTP request
|
|
239
|
+
async function httpRequest(calls, source, origin) {
|
|
240
|
+
try {
|
|
241
|
+
const response = await fetch(RPC_URL, {
|
|
242
|
+
method: 'POST',
|
|
243
|
+
headers: { 'Content-Type': 'application/json' },
|
|
244
|
+
credentials: 'include', // Include cookies!
|
|
245
|
+
body: JSON.stringify(calls)
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const results = await response.json();
|
|
249
|
+
|
|
250
|
+
results.forEach(result => {
|
|
251
|
+
source.postMessage({
|
|
252
|
+
type: 'rpc-response',
|
|
253
|
+
id: result.id,
|
|
254
|
+
result: result.result,
|
|
255
|
+
error: result.error
|
|
256
|
+
}, origin);
|
|
257
|
+
});
|
|
258
|
+
} catch (error) {
|
|
259
|
+
calls.forEach(call => {
|
|
260
|
+
source.postMessage({
|
|
261
|
+
type: 'rpc-response',
|
|
262
|
+
id: call.id,
|
|
263
|
+
error: { message: error.message }
|
|
264
|
+
}, origin);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Handle incoming messages
|
|
270
|
+
window.addEventListener('message', (event) => {
|
|
271
|
+
// Validate origin
|
|
272
|
+
if (!(${originsCheck})) {
|
|
273
|
+
console.warn('RPC Bridge: Rejected message from', event.origin);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const { type, calls, useWebSocket } = event.data;
|
|
278
|
+
|
|
279
|
+
if (type !== 'rpc-request') return;
|
|
280
|
+
|
|
281
|
+
// Store pending requests for response routing
|
|
282
|
+
calls.forEach(call => {
|
|
283
|
+
pendingRequests.set(call.id, {
|
|
284
|
+
source: event.source,
|
|
285
|
+
origin: event.origin
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Route to WebSocket or HTTP
|
|
290
|
+
if (useWebSocket && ws && wsReady) {
|
|
291
|
+
calls.forEach(call => ws.send(JSON.stringify(call)));
|
|
292
|
+
} else if (useWebSocket && ws) {
|
|
293
|
+
// Queue for when WS is ready
|
|
294
|
+
calls.forEach(call => wsQueue.push(call));
|
|
295
|
+
} else {
|
|
296
|
+
httpRequest(calls, event.source, event.origin);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
// Initialize
|
|
301
|
+
connectWS();
|
|
302
|
+
|
|
303
|
+
// Signal ready
|
|
304
|
+
if (window.parent !== window) {
|
|
305
|
+
window.parent.postMessage({ type: 'rpc-bridge-ready' }, '*');
|
|
306
|
+
}
|
|
307
|
+
})();
|
|
308
|
+
</script>
|
|
309
|
+
</head>
|
|
310
|
+
<body></body>
|
|
311
|
+
</html>
|
|
312
|
+
`;
|
|
313
|
+
return async (c) => {
|
|
314
|
+
c.header('Content-Type', 'text/html');
|
|
315
|
+
// Security headers for iframe
|
|
316
|
+
c.header('X-Frame-Options', 'ALLOWALL'); // Allow embedding
|
|
317
|
+
c.header('Content-Security-Policy', "default-src 'self'; script-src 'unsafe-inline'; connect-src 'self' wss://*.apis.do https://*.apis.do");
|
|
318
|
+
return c.html(bridgeScript);
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
// =============================================================================
|
|
322
|
+
// Unified Middleware
|
|
323
|
+
// =============================================================================
|
|
324
|
+
/**
|
|
325
|
+
* Create a complete RPC middleware that handles all transports
|
|
326
|
+
*
|
|
327
|
+
* @example
|
|
328
|
+
* ```ts
|
|
329
|
+
* import { Hono } from 'hono'
|
|
330
|
+
* import { upgradeWebSocket } from 'hono/cloudflare-workers'
|
|
331
|
+
* import { createRPCMiddleware } from 'ai-functions/rpc'
|
|
332
|
+
*
|
|
333
|
+
* const app = new Hono()
|
|
334
|
+
*
|
|
335
|
+
* const rpc = createRPCMiddleware({
|
|
336
|
+
* methods: {
|
|
337
|
+
* greet: (ctx, name) => `Hello, ${name}!`,
|
|
338
|
+
* getUser: async (ctx, id) => db.users.get(id),
|
|
339
|
+
* },
|
|
340
|
+
* createContext: (c) => ({
|
|
341
|
+
* user: c.get('user'),
|
|
342
|
+
* db: c.get('db'),
|
|
343
|
+
* }),
|
|
344
|
+
* bridgeOrigins: ['https://myapp.com', 'https://app.myapp.com'],
|
|
345
|
+
* })
|
|
346
|
+
*
|
|
347
|
+
* // Single /rpc endpoint for both HTTP POST and WebSocket GET
|
|
348
|
+
* app.post('/rpc', rpc.http)
|
|
349
|
+
* app.get('/rpc', upgradeWebSocket(rpc.ws))
|
|
350
|
+
*
|
|
351
|
+
* // postMessage bridge HTML (embed in iframe for cross-origin auth)
|
|
352
|
+
* app.get('/rpc.html', rpc.bridge)
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
export function createRPCMiddleware(options) {
|
|
356
|
+
return {
|
|
357
|
+
/** HTTP batch handler */
|
|
358
|
+
http: createHTTPHandler(options),
|
|
359
|
+
/** WebSocket handler (use with upgradeWebSocket) */
|
|
360
|
+
ws: createWSHandler(options),
|
|
361
|
+
/** postMessage bridge handler */
|
|
362
|
+
bridge: createBridgeHandler(options),
|
|
363
|
+
/** The methods for direct access */
|
|
364
|
+
methods: options.methods,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Mount all RPC routes on a Hono app
|
|
369
|
+
*
|
|
370
|
+
* Single endpoint handles both HTTP POST and WebSocket upgrade:
|
|
371
|
+
* - POST /rpc → HTTP batch requests
|
|
372
|
+
* - GET /rpc (with Upgrade header) → WebSocket connection
|
|
373
|
+
* - GET /rpc.html → postMessage bridge for iframe embedding
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```ts
|
|
377
|
+
* import { Hono } from 'hono'
|
|
378
|
+
* import { upgradeWebSocket } from 'hono/cloudflare-workers'
|
|
379
|
+
* import { mountRPC } from 'ai-functions/rpc'
|
|
380
|
+
*
|
|
381
|
+
* const app = new Hono()
|
|
382
|
+
*
|
|
383
|
+
* mountRPC(app, '/rpc', {
|
|
384
|
+
* methods: { ... },
|
|
385
|
+
* upgradeWebSocket,
|
|
386
|
+
* })
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
export function mountRPC(app, basePath, options) {
|
|
390
|
+
const rpc = createRPCMiddleware({
|
|
391
|
+
...options,
|
|
392
|
+
rpcUrl: options.rpcUrl ?? basePath,
|
|
393
|
+
wsUrl: options.wsUrl ?? basePath.replace(/^http/, 'ws'),
|
|
394
|
+
});
|
|
395
|
+
// HTTP batch (POST)
|
|
396
|
+
app.post(basePath, rpc.http);
|
|
397
|
+
// WebSocket upgrade (GET with Upgrade header)
|
|
398
|
+
if (options.upgradeWebSocket) {
|
|
399
|
+
app.get(basePath, options.upgradeWebSocket(rpc.ws));
|
|
400
|
+
}
|
|
401
|
+
// Bridge HTML page (for iframe embedding)
|
|
402
|
+
app.get(`${basePath}.html`, rpc.bridge);
|
|
403
|
+
return rpc;
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/rpc/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,EAAE,UAAU,EAAkB,MAAM,eAAe,CAAA;AAgD1D,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;GAEG;AACH,KAAK,UAAU,WAAW,CACxB,IAAgB,EAChB,OAA6B,EAC7B,GAAa,EACb,OAAoC;IAEpC,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,IAAI,CAAA;IAE/C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,EAAE;YACF,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,IAAI,EAAE,iBAAiB,EAAE;SACpE,CAAA;IACH,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,EAAE;YACF,IAAI,EAAE,OAAO;YACb,KAAK,EAAE,EAAE,OAAO,EAAE,mBAAmB,MAAM,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE;SAC1E,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,gBAAgB;QAChB,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;QAE3C,qBAAqB;QACrB,IAAI,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,CAAA;QAE1C,8CAA8C;QAC9C,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,KAAoB,CAAC,CAAA;QACnD,CAAC;QAED,iBAAiB;QACjB,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAA;QAE7C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;IACvC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QACrE,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;QAEzC,OAAO;YACL,EAAE;YACF,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACL,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,IAAI,EAAE,gBAAgB;gBACtB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aACtE;SACF,CAAA;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAoC;IAEpC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,cAAc,GAAG,GAAG,EAAE,GAAG,OAAO,CAAA;IAEhE,OAAO,KAAK,EAAE,CAAU,EAAE,EAAE;QAC1B,cAAc;QACd,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA;QACrC,IAAI,cAAc,KAAK,GAAG,EAAE,CAAC;YAC3B,CAAC,CAAC,MAAM,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAA;QAC9C,CAAC;aAAM,IAAI,MAAM,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACrD,CAAC,CAAC,MAAM,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAA;QACjD,CAAC;QACD,CAAC,CAAC,MAAM,CAAC,8BAA8B,EAAE,eAAe,CAAC,CAAA;QACzD,CAAC,CAAC,MAAM,CAAC,8BAA8B,EAAE,6BAA6B,CAAC,CAAA;QAEvE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC/B,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAA;QAC5C,CAAC;QAED,qBAAqB;QACrB,IAAI,KAAmB,CAAA;QACvB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;YAC/B,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC7C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,EAC3D,GAAG,CACJ,CAAA;QACH,CAAC;QAED,iBAAiB;QACjB,MAAM,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,EAAe,CAAA;QAErE,oBAAoB;QACpB,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAC9D,CAAA;QAED,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACxB,CAAC,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,oBAAoB;AACpB,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAW,OAAoC;IAC5E,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,OAAO,CAAA;IAE1C,OAAO,CAAC,CAAU,EAAE,EAAE;QACpB,IAAI,GAAa,CAAA;QAEjB,oDAAoD;QACpD,MAAM,gBAAgB,GAA2B;YAC/C,SAAS,EAAE,IAAI,GAAG,EAAE;YACpB,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;gBACzB,MAAM,EAAE,GAAG,gBAAgB,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;gBAC7C,IAAI,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAA;gBACrD,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;YACpB,CAAC;SACF,CAAA;QAED,OAAO;YACL,KAAK,CAAC,MAAM,CAAC,IAAW,EAAE,EAAa;gBACrC,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,EAAe,CAAA;YACjE,CAAC;YAED,KAAK,CAAC,SAAS,CAAC,GAAiB,EAAE,EAAa;gBAC9C,IAAI,OAAmB,CAAA;gBACvB,IAAI,CAAC;oBACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAc,CAAC,CAAA;gBAC1C,CAAC;gBAAC,MAAM,CAAC;oBACP,EAAE,CAAC,IAAI,CACL,IAAI,CAAC,SAAS,CAAC;wBACb,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE;qBACxD,CAAC,CACH,CAAA;oBACD,OAAM;gBACR,CAAC;gBAED,cAAc;gBACd,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC5B,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;oBACzC,OAAM;gBACR,CAAC;gBAED,2BAA2B;gBAC3B,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;oBACpD,gDAAgD;oBAChD,qDAAqD;oBACrD,OAAM;gBACR,CAAC;gBAED,kBAAkB;gBAClB,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC5B,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAA;oBAChE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;oBAC/B,OAAM;gBACR,CAAC;gBAED,gCAAgC;gBAChC,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC9B,2CAA2C;oBAC3C,OAAM;gBACR,CAAC;YACH,CAAC;YAED,OAAO,CAAC,IAAgB,EAAE,GAAc;gBACtC,4BAA4B;gBAC5B,gBAAgB,CAAC,SAAS,CAAC,KAAK,EAAE,CAAA;YACpC,CAAC;YAED,OAAO,CAAC,GAAU,EAAE,GAAc;gBAChC,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAA;YACxC,CAAC;SACF,CAAA;IACH,CAAC,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAKC;IAED,MAAM,EAAE,aAAa,GAAG,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IAE9D,iCAAiC;IACjC,MAAM,YAAY,GAChB,aAAa,CAAC,MAAM,KAAK,CAAC;QACxB,CAAC,CAAC,MAAM,CAAC,mBAAmB;QAC5B,CAAC,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,0BAA0B,CAAA;IAEhF,MAAM,YAAY,GAAG;;;;;;;yBAOE,MAAM;uBACR,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBA0EpC,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwC3B,CAAA;IAEC,OAAO,KAAK,EAAE,CAAU,EAAE,EAAE;QAC1B,CAAC,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;QACrC,8BAA8B;QAC9B,CAAC,CAAC,MAAM,CAAC,iBAAiB,EAAE,UAAU,CAAC,CAAA,CAAC,kBAAkB;QAC1D,CAAC,CAAC,MAAM,CACN,yBAAyB,EACzB,sGAAsG,CACvG,CAAA;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;IAC7B,CAAC,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,qBAAqB;AACrB,gFAAgF;AAEhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAGC;IAED,OAAO;QACL,yBAAyB;QACzB,IAAI,EAAE,iBAAiB,CAAC,OAAO,CAAC;QAChC,oDAAoD;QACpD,EAAE,EAAE,eAAe,CAAC,OAAO,CAAC;QAC5B,iCAAiC;QACjC,MAAM,EAAE,mBAAmB,CAAC,OAAO,CAAC;QACpC,oCAAoC;QACpC,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAA;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,QAAQ,CACtB,GAAS,EACT,QAAgB,EAChB,OAKC;IAED,MAAM,GAAG,GAAG,mBAAmB,CAAC;QAC9B,GAAG,OAAO;QACV,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,QAAQ;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;KACxD,CAAC,CAAA;IAEF,oBAAoB;IACpB,GAAG,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAA;IAE5B,8CAA8C;IAC9C,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;QAC7B,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;IACrD,CAAC;IAED,0CAA0C;IAC1C,GAAG,CAAC,GAAG,CAAC,GAAG,QAAQ,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAEvC,OAAO,GAAG,CAAA;AACZ,CAAC"}
|