@richie-rpc/client 1.2.7 → 1.2.9
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/dist/cjs/index.cjs +79 -39
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/websocket.cjs +9 -6
- package/dist/cjs/websocket.cjs.map +3 -3
- package/dist/mjs/index.mjs +79 -39
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/websocket.mjs +9 -6
- package/dist/mjs/websocket.mjs.map +3 -3
- package/dist/types/index.d.ts +4 -4
- package/dist/types/websocket.d.ts +3 -2
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../websocket.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type {\n ExtractClientMessagePayload,\n ExtractServerMessage,\n ExtractServerMessagePayload,\n ExtractWSHeaders,\n ExtractWSParams,\n ExtractWSQuery,\n WebSocketContract,\n WebSocketContractDefinition,\n} from '@richie-rpc/core';\nimport { buildUrl, interpolatePath } from '@richie-rpc/core';\n\n/**\n * Validation error for WebSocket messages\n */\nexport class WebSocketClientValidationError extends Error {\n constructor(\n public messageType: string,\n public
|
|
5
|
+
"/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type {\n ExtractClientMessagePayload,\n ExtractServerMessage,\n ExtractServerMessagePayload,\n ExtractWSHeaders,\n ExtractWSParams,\n ExtractWSQuery,\n WebSocketContract,\n WebSocketContractDefinition,\n} from '@richie-rpc/core';\nimport { buildUrl, interpolatePath } from '@richie-rpc/core';\nimport { z } from 'zod';\n\n/**\n * Validation error for WebSocket messages\n */\nexport class WebSocketClientValidationError extends Error {\n constructor(\n public messageType: string,\n public zodError: z.ZodError<unknown>,\n ) {\n const pretty = z.prettifyError(zodError);\n super(`Validation failed for WebSocket message type: ${messageType}:\\n${pretty}`);\n this.name = 'WebSocketClientValidationError';\n }\n}\n\n/**\n * Options for creating a WebSocket connection\n */\nexport type WebSocketConnectionOptions<T extends WebSocketContractDefinition> = {\n params?: ExtractWSParams<T> extends never ? never : ExtractWSParams<T>;\n query?: ExtractWSQuery<T> extends never ? never : ExtractWSQuery<T>;\n headers?: ExtractWSHeaders<T> extends never ? never : ExtractWSHeaders<T>;\n};\n\n/**\n * Typed WebSocket connection interface\n */\nexport interface TypedWebSocket<T extends WebSocketContractDefinition> {\n /** Connect to WebSocket server, returns disconnect function */\n connect(): () => void;\n\n /** Send a typed message (validates before sending) */\n send<K extends keyof T['clientMessages']>(\n type: K,\n payload: ExtractClientMessagePayload<T, K>,\n ): void;\n\n /** Subscribe to specific message type, returns unsubscribe function */\n on<K extends keyof T['serverMessages']>(\n type: K,\n handler: (payload: ExtractServerMessagePayload<T, K>) => void,\n ): () => void;\n\n /** Subscribe to all messages, returns unsubscribe function */\n onMessage(handler: (message: ExtractServerMessage<T>) => void): () => void;\n\n /** Subscribe to connection state changes */\n onStateChange(handler: (connected: boolean) => void): () => void;\n\n /** Subscribe to connection errors (network failures, etc.) */\n onError(handler: (error: Error) => void): () => void;\n\n /** Current connection state */\n readonly connected: boolean;\n}\n\n/**\n * WebSocket client type for a contract\n */\nexport type WebSocketClient<T extends WebSocketContract> = {\n [K in keyof T]: (options?: WebSocketConnectionOptions<T[K]>) => TypedWebSocket<T[K]>;\n};\n\n/**\n * WebSocket client configuration\n */\nexport interface WebSocketClientConfig {\n /** Base URL for WebSocket connections (ws:// or wss://) */\n baseUrl: string;\n}\n\n/**\n * Create a typed WebSocket connection for a specific endpoint\n */\nfunction createTypedWebSocket<T extends WebSocketContractDefinition>(\n endpoint: T,\n url: string,\n): TypedWebSocket<T> {\n let ws: WebSocket | null = null;\n let isConnected = false;\n\n type MessageHandler = (message: ExtractServerMessage<T>) => void;\n type TypedHandler<K extends keyof T['serverMessages']> = (\n payload: ExtractServerMessagePayload<T, K>,\n ) => void;\n type StateHandler = (connected: boolean) => void;\n type ErrorHandler = (error: Error) => void;\n\n const messageListeners = new Set<MessageHandler>();\n const typedListeners: Record<string, Set<TypedHandler<any>>> = {};\n const stateListeners = new Set<StateHandler>();\n const errorListeners = new Set<ErrorHandler>();\n\n // Initialize typed listener sets for each server message type\n for (const type of Object.keys(endpoint.serverMessages)) {\n typedListeners[type] = new Set();\n }\n\n function notifyStateChange(connected: boolean) {\n isConnected = connected;\n stateListeners.forEach((h) => h(connected));\n }\n\n function notifyError(error: Error) {\n errorListeners.forEach((h) => h(error));\n }\n\n function handleMessage(event: MessageEvent) {\n try {\n const message = JSON.parse(event.data) as ExtractServerMessage<T>;\n\n // Notify all-message listeners\n messageListeners.forEach((h) => h(message));\n\n // Notify type-specific listeners\n const { type, payload } = message as { type: string; payload: unknown };\n if (typedListeners[type]) {\n typedListeners[type].forEach((h) => h(payload as any));\n }\n } catch (err) {\n notifyError(new Error(`Failed to parse WebSocket message: ${(err as Error).message}`));\n }\n }\n\n return {\n connect() {\n if (ws) {\n // Already connected or connecting\n return () => {\n ws?.close();\n ws = null;\n };\n }\n\n ws = new WebSocket(url);\n\n ws.onopen = () => {\n notifyStateChange(true);\n };\n\n ws.onclose = () => {\n notifyStateChange(false);\n ws = null;\n };\n\n ws.onerror = () => {\n notifyError(new Error('WebSocket connection error'));\n };\n\n ws.onmessage = handleMessage;\n\n // Return disconnect function\n return () => {\n ws?.close();\n ws = null;\n };\n },\n\n send(type, payload) {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error('WebSocket is not connected');\n }\n\n // Validate payload against schema\n const messageDef = endpoint.clientMessages[type as string];\n if (messageDef && messageDef.payload) {\n const result = messageDef.payload.safeParse(payload);\n if (!result.success) {\n throw new WebSocketClientValidationError(type as string, result.error);\n }\n }\n\n // Send message\n ws.send(JSON.stringify({ type, payload }));\n },\n\n on(type, handler) {\n const typeStr = type as string;\n if (!typedListeners[typeStr]) {\n typedListeners[typeStr] = new Set();\n }\n typedListeners[typeStr].add(handler);\n return () => typedListeners[typeStr]?.delete(handler);\n },\n\n onMessage(handler) {\n messageListeners.add(handler);\n return () => messageListeners.delete(handler);\n },\n\n onStateChange(handler) {\n stateListeners.add(handler);\n return () => stateListeners.delete(handler);\n },\n\n onError(handler) {\n errorListeners.add(handler);\n return () => errorListeners.delete(handler);\n },\n\n get connected() {\n return isConnected;\n },\n };\n}\n\n/**\n * Resolve HTTP URL to WebSocket URL\n */\nfunction resolveWebSocketUrl(baseUrl: string): string {\n // If already a WebSocket URL, return as-is\n if (baseUrl.startsWith('ws://') || baseUrl.startsWith('wss://')) {\n return baseUrl;\n }\n\n // Convert http:// to ws:// and https:// to wss://\n if (baseUrl.startsWith('http://')) {\n return `ws://${baseUrl.slice(7)}`;\n }\n if (baseUrl.startsWith('https://')) {\n return `wss://${baseUrl.slice(8)}`;\n }\n\n // If relative URL, resolve using window.location\n if (baseUrl.startsWith('/')) {\n const g = globalThis as unknown as { location?: { protocol?: string; host?: string } };\n if (g?.location) {\n const protocol = g.location.protocol === 'https:' ? 'wss:' : 'ws:';\n return `${protocol}//${g.location.host}${baseUrl}`;\n }\n return `ws://localhost${baseUrl}`;\n }\n\n // Assume ws:// by default\n return `ws://${baseUrl}`;\n}\n\n/**\n * Create a typed WebSocket client for a contract\n *\n * @param contract - The WebSocket contract definition\n * @param config - Client configuration with baseUrl\n * @returns Client object with methods for each endpoint\n *\n * @example\n * ```typescript\n * const wsContract = defineWebSocketContract({\n * chat: {\n * path: '/ws/chat/:roomId',\n * params: z.object({ roomId: z.string() }),\n * clientMessages: {\n * sendMessage: { payload: z.object({ text: z.string() }) },\n * },\n * serverMessages: {\n * message: { payload: z.object({ userId: z.string(), text: z.string() }) },\n * },\n * },\n * });\n *\n * const wsClient = createWebSocketClient(wsContract, { baseUrl: 'ws://localhost:3000' });\n *\n * // Create connection instance\n * const chat = wsClient.chat({ params: { roomId: 'room1' } });\n *\n * // Connect and get disconnect function\n * const disconnect = chat.connect();\n *\n * // Subscribe to state changes\n * chat.onStateChange((connected) => {\n * console.log('Connected:', connected);\n * });\n *\n * // Subscribe to specific message types\n * chat.on('message', (payload) => {\n * console.log(`${payload.userId}: ${payload.text}`);\n * });\n *\n * // Send messages\n * chat.send('sendMessage', { text: 'Hello!' });\n *\n * // Disconnect when done\n * disconnect();\n * ```\n */\nexport function createWebSocketClient<T extends WebSocketContract>(\n contract: T,\n config: WebSocketClientConfig,\n): WebSocketClient<T> {\n const resolvedBaseUrl = resolveWebSocketUrl(config.baseUrl);\n\n const client: Record<string, unknown> = {};\n\n for (const [name, endpoint] of Object.entries(contract)) {\n client[name] = (options: WebSocketConnectionOptions<WebSocketContractDefinition> = {}) => {\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n resolvedBaseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n return createTypedWebSocket(endpoint, url);\n };\n }\n\n return client as WebSocketClient<T>;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAW0C,IAA1C;AAAA;AAKO,MAAM,uCAAuC,MAAM;AAAA,EAE/C;AAAA,EACA;AAAA,EAFT,WAAW,CACF,aACA,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "019A19CE0CB61DD964756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/index.mjs
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/client/index.ts
|
|
3
3
|
import { buildUrl, interpolatePath, objectToFormData } from "@richie-rpc/core";
|
|
4
|
+
import { z } from "zod";
|
|
4
5
|
|
|
5
6
|
export * from "./websocket.mjs";
|
|
6
7
|
|
|
7
8
|
class ClientValidationError extends Error {
|
|
8
9
|
field;
|
|
9
|
-
|
|
10
|
-
constructor(field,
|
|
11
|
-
|
|
10
|
+
zodError;
|
|
11
|
+
constructor(field, zodError) {
|
|
12
|
+
const pretty = z.prettifyError(zodError);
|
|
13
|
+
super(`Validation failed for ${field}:
|
|
14
|
+
${pretty}`);
|
|
12
15
|
this.field = field;
|
|
13
|
-
this.
|
|
16
|
+
this.zodError = zodError;
|
|
14
17
|
this.name = "ClientValidationError";
|
|
15
18
|
}
|
|
16
19
|
}
|
|
@@ -31,36 +34,38 @@ function validateRequest(endpoint, options) {
|
|
|
31
34
|
if (endpoint.params && options.params) {
|
|
32
35
|
const result = endpoint.params.safeParse(options.params);
|
|
33
36
|
if (!result.success) {
|
|
34
|
-
throw new ClientValidationError("params", result.error
|
|
37
|
+
throw new ClientValidationError("params", result.error);
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
if (endpoint.query && options.query) {
|
|
38
41
|
const result = endpoint.query.safeParse(options.query);
|
|
39
42
|
if (!result.success) {
|
|
40
|
-
throw new ClientValidationError("query", result.error
|
|
43
|
+
throw new ClientValidationError("query", result.error);
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
if (endpoint.headers && options.headers) {
|
|
44
47
|
const result = endpoint.headers.safeParse(options.headers);
|
|
45
48
|
if (!result.success) {
|
|
46
|
-
throw new ClientValidationError("headers", result.error
|
|
49
|
+
throw new ClientValidationError("headers", result.error);
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
if (endpoint.body && options.body) {
|
|
50
53
|
const result = endpoint.body.safeParse(options.body);
|
|
51
54
|
if (!result.success) {
|
|
52
|
-
throw new ClientValidationError("body", result.error
|
|
55
|
+
throw new ClientValidationError("body", result.error);
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
}
|
|
56
|
-
function
|
|
59
|
+
function parseResponse(endpoint, status, data) {
|
|
57
60
|
const responseSchema = endpoint.responses[status];
|
|
58
61
|
if (responseSchema) {
|
|
59
62
|
const result = responseSchema.safeParse(data);
|
|
60
63
|
if (!result.success) {
|
|
61
|
-
throw new ClientValidationError(`response[${status}]`, result.error
|
|
64
|
+
throw new ClientValidationError(`response[${status}]`, result.error);
|
|
62
65
|
}
|
|
66
|
+
return result.data;
|
|
63
67
|
}
|
|
68
|
+
return data;
|
|
64
69
|
}
|
|
65
70
|
function extractFilename(contentDisposition) {
|
|
66
71
|
if (!contentDisposition)
|
|
@@ -79,32 +84,34 @@ function validateDownloadRequest(endpoint, options) {
|
|
|
79
84
|
if (endpoint.params && options.params) {
|
|
80
85
|
const result = endpoint.params.safeParse(options.params);
|
|
81
86
|
if (!result.success) {
|
|
82
|
-
throw new ClientValidationError("params", result.error
|
|
87
|
+
throw new ClientValidationError("params", result.error);
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
if (endpoint.query && options.query) {
|
|
86
91
|
const result = endpoint.query.safeParse(options.query);
|
|
87
92
|
if (!result.success) {
|
|
88
|
-
throw new ClientValidationError("query", result.error
|
|
93
|
+
throw new ClientValidationError("query", result.error);
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
if (endpoint.headers && options.headers) {
|
|
92
97
|
const result = endpoint.headers.safeParse(options.headers);
|
|
93
98
|
if (!result.success) {
|
|
94
|
-
throw new ClientValidationError("headers", result.error
|
|
99
|
+
throw new ClientValidationError("headers", result.error);
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
|
-
function
|
|
103
|
+
function parseDownloadErrorResponse(endpoint, status, data) {
|
|
99
104
|
if (endpoint.errorResponses) {
|
|
100
105
|
const responseSchema = endpoint.errorResponses[status];
|
|
101
106
|
if (responseSchema) {
|
|
102
107
|
const result = responseSchema.safeParse(data);
|
|
103
108
|
if (!result.success) {
|
|
104
|
-
throw new ClientValidationError(`response[${status}]`, result.error
|
|
109
|
+
throw new ClientValidationError(`response[${status}]`, result.error);
|
|
105
110
|
}
|
|
111
|
+
return result.data;
|
|
106
112
|
}
|
|
107
113
|
}
|
|
114
|
+
return data;
|
|
108
115
|
}
|
|
109
116
|
async function makeDownloadRequest(config, endpoint, options = {}) {
|
|
110
117
|
if (config.validateRequest !== false) {
|
|
@@ -172,12 +179,10 @@ async function makeDownloadRequest(config, endpoint, options = {}) {
|
|
|
172
179
|
if (endpoint.errorResponses && !(response.status in endpoint.errorResponses)) {
|
|
173
180
|
throw new HTTPError(response.status, response.statusText, data);
|
|
174
181
|
}
|
|
175
|
-
|
|
176
|
-
validateDownloadErrorResponse(endpoint, response.status, data);
|
|
177
|
-
}
|
|
182
|
+
const parsedData = config.parseResponse !== false ? parseDownloadErrorResponse(endpoint, response.status, data) : data;
|
|
178
183
|
return {
|
|
179
184
|
status: response.status,
|
|
180
|
-
data
|
|
185
|
+
data: parsedData
|
|
181
186
|
};
|
|
182
187
|
}
|
|
183
188
|
function makeRequestWithXHR(config, endpoint, options, url) {
|
|
@@ -235,9 +240,10 @@ function makeRequestWithXHR(config, endpoint, options, url) {
|
|
|
235
240
|
reject(new HTTPError(xhr.status, xhr.statusText, data));
|
|
236
241
|
return;
|
|
237
242
|
}
|
|
238
|
-
|
|
243
|
+
let parsedData = data;
|
|
244
|
+
if (config.parseResponse !== false) {
|
|
239
245
|
try {
|
|
240
|
-
|
|
246
|
+
parsedData = parseResponse(endpoint, xhr.status, data);
|
|
241
247
|
} catch (err) {
|
|
242
248
|
reject(err);
|
|
243
249
|
return;
|
|
@@ -245,7 +251,7 @@ function makeRequestWithXHR(config, endpoint, options, url) {
|
|
|
245
251
|
}
|
|
246
252
|
resolve({
|
|
247
253
|
status: xhr.status,
|
|
248
|
-
data
|
|
254
|
+
data: parsedData
|
|
249
255
|
});
|
|
250
256
|
};
|
|
251
257
|
xhr.onerror = () => reject(new Error("Network error"));
|
|
@@ -319,20 +325,38 @@ async function makeRequest(config, endpoint, options) {
|
|
|
319
325
|
if (!response.ok && !(response.status in endpoint.responses)) {
|
|
320
326
|
throw new HTTPError(response.status, response.statusText, data);
|
|
321
327
|
}
|
|
322
|
-
|
|
323
|
-
validateResponse(endpoint, response.status, data);
|
|
324
|
-
}
|
|
328
|
+
const parsedData = config.parseResponse !== false ? parseResponse(endpoint, response.status, data) : data;
|
|
325
329
|
return {
|
|
326
330
|
status: response.status,
|
|
327
|
-
data
|
|
331
|
+
data: parsedData
|
|
328
332
|
};
|
|
329
333
|
}
|
|
330
|
-
function createStreamingResult(response, controller) {
|
|
334
|
+
function createStreamingResult(response, controller, endpoint, config) {
|
|
331
335
|
const listeners = {
|
|
332
336
|
chunk: new Set,
|
|
333
337
|
close: new Set,
|
|
334
338
|
error: new Set
|
|
335
339
|
};
|
|
340
|
+
const parseChunk = (data) => {
|
|
341
|
+
if (config.parseResponse !== false && endpoint.chunk) {
|
|
342
|
+
const result = endpoint.chunk.safeParse(data);
|
|
343
|
+
if (!result.success) {
|
|
344
|
+
throw new ClientValidationError("chunk", result.error);
|
|
345
|
+
}
|
|
346
|
+
return result.data;
|
|
347
|
+
}
|
|
348
|
+
return data;
|
|
349
|
+
};
|
|
350
|
+
const parseFinalResponse = (data) => {
|
|
351
|
+
if (config.parseResponse !== false && endpoint.finalResponse) {
|
|
352
|
+
const result = endpoint.finalResponse.safeParse(data);
|
|
353
|
+
if (!result.success) {
|
|
354
|
+
throw new ClientValidationError("finalResponse", result.error);
|
|
355
|
+
}
|
|
356
|
+
return result.data;
|
|
357
|
+
}
|
|
358
|
+
return data;
|
|
359
|
+
};
|
|
336
360
|
(async () => {
|
|
337
361
|
const reader = response.body.getReader();
|
|
338
362
|
const decoder = new TextDecoder;
|
|
@@ -352,9 +376,11 @@ function createStreamingResult(response, controller) {
|
|
|
352
376
|
try {
|
|
353
377
|
const parsed = JSON.parse(line);
|
|
354
378
|
if (parsed.__final__) {
|
|
355
|
-
|
|
379
|
+
const finalData = parseFinalResponse(parsed.data);
|
|
380
|
+
listeners.close.forEach((h) => h(finalData));
|
|
356
381
|
} else {
|
|
357
|
-
|
|
382
|
+
const chunkData = parseChunk(parsed);
|
|
383
|
+
listeners.chunk.forEach((h) => h(chunkData));
|
|
358
384
|
}
|
|
359
385
|
} catch (parseErr) {
|
|
360
386
|
listeners.error.forEach((h) => h(parseErr));
|
|
@@ -365,9 +391,11 @@ function createStreamingResult(response, controller) {
|
|
|
365
391
|
try {
|
|
366
392
|
const parsed = JSON.parse(buffer);
|
|
367
393
|
if (parsed.__final__) {
|
|
368
|
-
|
|
394
|
+
const finalData = parseFinalResponse(parsed.data);
|
|
395
|
+
listeners.close.forEach((h) => h(finalData));
|
|
369
396
|
} else {
|
|
370
|
-
|
|
397
|
+
const chunkData = parseChunk(parsed);
|
|
398
|
+
listeners.chunk.forEach((h) => h(chunkData));
|
|
371
399
|
}
|
|
372
400
|
} catch {}
|
|
373
401
|
}
|
|
@@ -395,25 +423,25 @@ function validateStreamingRequest(endpoint, options) {
|
|
|
395
423
|
if (endpoint.params && options.params) {
|
|
396
424
|
const result = endpoint.params.safeParse(options.params);
|
|
397
425
|
if (!result.success) {
|
|
398
|
-
throw new ClientValidationError("params", result.error
|
|
426
|
+
throw new ClientValidationError("params", result.error);
|
|
399
427
|
}
|
|
400
428
|
}
|
|
401
429
|
if (endpoint.query && options.query) {
|
|
402
430
|
const result = endpoint.query.safeParse(options.query);
|
|
403
431
|
if (!result.success) {
|
|
404
|
-
throw new ClientValidationError("query", result.error
|
|
432
|
+
throw new ClientValidationError("query", result.error);
|
|
405
433
|
}
|
|
406
434
|
}
|
|
407
435
|
if (endpoint.headers && options.headers) {
|
|
408
436
|
const result = endpoint.headers.safeParse(options.headers);
|
|
409
437
|
if (!result.success) {
|
|
410
|
-
throw new ClientValidationError("headers", result.error
|
|
438
|
+
throw new ClientValidationError("headers", result.error);
|
|
411
439
|
}
|
|
412
440
|
}
|
|
413
441
|
if (endpoint.body && options.body) {
|
|
414
442
|
const result = endpoint.body.safeParse(options.body);
|
|
415
443
|
if (!result.success) {
|
|
416
|
-
throw new ClientValidationError("body", result.error
|
|
444
|
+
throw new ClientValidationError("body", result.error);
|
|
417
445
|
}
|
|
418
446
|
}
|
|
419
447
|
}
|
|
@@ -465,7 +493,7 @@ async function makeStreamingRequest(config, endpoint, options) {
|
|
|
465
493
|
}
|
|
466
494
|
throw new HTTPError(response.status, response.statusText, data);
|
|
467
495
|
}
|
|
468
|
-
return createStreamingResult(response, controller);
|
|
496
|
+
return createStreamingResult(response, controller, endpoint, config);
|
|
469
497
|
}
|
|
470
498
|
function createSSEConnection(config, endpoint, options = {}) {
|
|
471
499
|
let path = endpoint.path;
|
|
@@ -483,8 +511,20 @@ function createSSEConnection(config, endpoint, options = {}) {
|
|
|
483
511
|
eventSource.addEventListener(eventName, (e) => {
|
|
484
512
|
const messageEvent = e;
|
|
485
513
|
try {
|
|
486
|
-
const
|
|
487
|
-
|
|
514
|
+
const rawData = JSON.parse(messageEvent.data);
|
|
515
|
+
let parsedData = rawData;
|
|
516
|
+
if (config.parseResponse !== false) {
|
|
517
|
+
const eventSchema = endpoint.events[eventName];
|
|
518
|
+
if (eventSchema) {
|
|
519
|
+
const result = eventSchema.safeParse(rawData);
|
|
520
|
+
if (!result.success) {
|
|
521
|
+
listeners.error.forEach((h) => h(new ClientValidationError(`event[${eventName}]`, result.error)));
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
parsedData = result.data;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
listeners[eventName].forEach((h) => h(parsedData, messageEvent.lastEventId || undefined));
|
|
488
528
|
} catch (err) {
|
|
489
529
|
listeners.error.forEach((h) => h(new Error(`Failed to parse SSE data: ${err.message}`)));
|
|
490
530
|
}
|
|
@@ -566,4 +606,4 @@ export {
|
|
|
566
606
|
ClientValidationError
|
|
567
607
|
};
|
|
568
608
|
|
|
569
|
-
//# debugId=
|
|
609
|
+
//# debugId=CA9C42DCB1FC53CB64756E2164756E21
|
package/dist/mjs/index.mjs.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type {\n Contract,\n DownloadEndpointDefinition,\n DownloadProgressEvent,\n EndpointDefinition,\n ExtractBody,\n ExtractChunk,\n ExtractFinalResponse,\n ExtractHeaders,\n ExtractParams,\n ExtractQuery,\n ExtractSSEEventData,\n SSEEndpointDefinition,\n StandardEndpointDefinition,\n StreamingEndpointDefinition,\n UploadProgressEvent,\n} from '@richie-rpc/core';\nimport { buildUrl, interpolatePath, objectToFormData } from '@richie-rpc/core';\n\n// Re-export for convenience\nexport type { UploadProgressEvent, DownloadProgressEvent };\nimport type { z } from 'zod';\n\n// Client configuration\nexport interface ClientConfig {\n baseUrl: string;\n headers?: Record<string, string>;\n validateRequest?: boolean;\n validateResponse?: boolean;\n}\n\n// Request options for an endpoint\nexport type EndpointRequestOptions<T extends EndpointDefinition> = {\n params?: ExtractParams<T> extends never ? never : ExtractParams<T>;\n query?: ExtractQuery<T> extends never ? never : ExtractQuery<T>;\n headers?: ExtractHeaders<T> extends never ? never : ExtractHeaders<T>;\n body?: ExtractBody<T> extends never ? never : ExtractBody<T>;\n abortSignal?: AbortSignal;\n /** Upload progress callback (uses XHR for progress tracking) */\n onUploadProgress?: (event: UploadProgressEvent) => void;\n};\n\n// Response type for a standard endpoint (union of all possible responses)\nexport type EndpointResponse<T extends StandardEndpointDefinition> = {\n [Status in keyof T['responses']]: {\n status: Status;\n data: T['responses'][Status] extends z.ZodTypeAny ? z.infer<T['responses'][Status]> : never;\n };\n}[keyof T['responses']];\n\n// Client method type for a standard endpoint\nexport type ClientMethod<T extends StandardEndpointDefinition> = (\n options: EndpointRequestOptions<T>,\n) => Promise<EndpointResponse<T>>;\n\n// ============================================\n// Streaming Endpoint Client Types\n// ============================================\n\n/**\n * Result object for streaming endpoints - event-based API\n */\nexport interface StreamingResult<T extends StreamingEndpointDefinition> {\n /** Subscribe to chunks */\n on(event: 'chunk', handler: (chunk: ExtractChunk<T>) => void): () => void;\n /** Subscribe to stream close (with optional final response) */\n on(event: 'close', handler: (final?: ExtractFinalResponse<T>) => void): () => void;\n /** Subscribe to errors */\n on(event: 'error', handler: (error: Error) => void): () => void;\n /** Abort the stream */\n abort(): void;\n /** Check if aborted */\n readonly aborted: boolean;\n}\n\n/**\n * Client method type for streaming endpoints\n */\nexport type StreamingClientMethod<T extends StreamingEndpointDefinition> = (\n options: EndpointRequestOptions<T>,\n) => Promise<StreamingResult<T>>;\n\n// ============================================\n// SSE Endpoint Client Types\n// ============================================\n\n/**\n * Connection object for SSE endpoints - event-based API\n */\nexport interface SSEConnection<T extends SSEEndpointDefinition> {\n /** Subscribe to a specific event type */\n on<K extends keyof T['events']>(\n event: K,\n handler: (data: ExtractSSEEventData<T, K>, id?: string) => void,\n ): () => void;\n /** Subscribe to errors */\n on(event: 'error', handler: (error: Error) => void): () => void;\n /** Close the connection */\n close(): void;\n /** Current connection state */\n readonly state: 'connecting' | 'open' | 'closed';\n}\n\n/**\n * Client method type for SSE endpoints\n */\nexport type SSEClientMethod<T extends SSEEndpointDefinition> = (\n options?: Omit<EndpointRequestOptions<T>, 'body' | 'onUploadProgress'>,\n) => SSEConnection<T>;\n\n// ============================================\n// Download Endpoint Client Types\n// ============================================\n\n/**\n * Request options for download endpoints\n */\nexport type DownloadRequestOptions<T extends DownloadEndpointDefinition> = {\n params?: ExtractParams<T> extends never ? never : ExtractParams<T>;\n query?: ExtractQuery<T> extends never ? never : ExtractQuery<T>;\n headers?: ExtractHeaders<T> extends never ? never : ExtractHeaders<T>;\n abortSignal?: AbortSignal;\n /** Download progress callback */\n onDownloadProgress?: (event: DownloadProgressEvent) => void;\n};\n\n/**\n * Response type for download endpoints\n * Success (200) returns File, errors return typed error response\n */\nexport type DownloadResponse<T extends DownloadEndpointDefinition> =\n | { status: 200; data: File }\n | (T['errorResponses'] extends Record<number, z.ZodTypeAny>\n ? {\n [S in keyof T['errorResponses']]: {\n status: S;\n data: T['errorResponses'][S] extends z.ZodTypeAny\n ? z.infer<T['errorResponses'][S]>\n : never;\n };\n }[keyof T['errorResponses']]\n : never);\n\n/**\n * Client method type for download endpoints\n */\nexport type DownloadClientMethod<T extends DownloadEndpointDefinition> = (\n options?: DownloadRequestOptions<T>,\n) => Promise<DownloadResponse<T>>;\n\n// Client type for a contract (supports all endpoint types)\nexport type Client<T extends Contract> = {\n [K in keyof T]: T[K] extends StandardEndpointDefinition\n ? ClientMethod<T[K]>\n : T[K] extends StreamingEndpointDefinition\n ? StreamingClientMethod<T[K]>\n : T[K] extends SSEEndpointDefinition\n ? SSEClientMethod<T[K]>\n : T[K] extends DownloadEndpointDefinition\n ? DownloadClientMethod<T[K]>\n : never;\n};\n\n// Validation error\nexport class ClientValidationError extends Error {\n constructor(\n public field: string,\n public issues: z.ZodIssue[],\n ) {\n super(`Validation failed for ${field}`);\n this.name = 'ClientValidationError';\n }\n}\n\n// HTTP error\nexport class HTTPError extends Error {\n constructor(\n public status: number,\n public statusText: string,\n public body: unknown,\n ) {\n super(`HTTP Error ${status}: ${statusText}`);\n this.name = 'HTTPError';\n }\n}\n\n/**\n * Validate request data before sending\n */\nfunction validateRequest<T extends StandardEndpointDefinition>(\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): void {\n // Validate params\n if (endpoint.params && options.params) {\n const result = endpoint.params.safeParse(options.params);\n if (!result.success) {\n throw new ClientValidationError('params', result.error.issues);\n }\n }\n\n // Validate query\n if (endpoint.query && options.query) {\n const result = endpoint.query.safeParse(options.query);\n if (!result.success) {\n throw new ClientValidationError('query', result.error.issues);\n }\n }\n\n // Validate headers\n if (endpoint.headers && options.headers) {\n const result = endpoint.headers.safeParse(options.headers);\n if (!result.success) {\n throw new ClientValidationError('headers', result.error.issues);\n }\n }\n\n // Validate body\n if (endpoint.body && options.body) {\n const result = endpoint.body.safeParse(options.body);\n if (!result.success) {\n throw new ClientValidationError('body', result.error.issues);\n }\n }\n}\n\n/**\n * Validate response data after receiving\n */\nfunction validateResponse<T extends StandardEndpointDefinition>(\n endpoint: T,\n status: number,\n data: unknown,\n): void {\n const responseSchema = endpoint.responses[status];\n if (responseSchema) {\n const result = responseSchema.safeParse(data);\n if (!result.success) {\n throw new ClientValidationError(`response[${status}]`, result.error.issues);\n }\n }\n}\n\n/**\n * Extract filename from Content-Disposition header\n */\nfunction extractFilename(contentDisposition: string | null): string | null {\n if (!contentDisposition) return null;\n // Try filename*= (RFC 5987) first\n const filenameStarMatch = contentDisposition.match(/filename\\*=(?:UTF-8'')?([^;\\s]+)/i);\n if (filenameStarMatch && filenameStarMatch[1]) {\n return decodeURIComponent(filenameStarMatch[1]);\n }\n // Try filename= (standard)\n const filenameMatch = contentDisposition.match(/filename=[\"']?([^\"';\\s]+)[\"']?/i);\n if (filenameMatch && filenameMatch[1]) {\n return filenameMatch[1];\n }\n return null;\n}\n\n/**\n * Validate download request data before sending\n */\nfunction validateDownloadRequest<T extends DownloadEndpointDefinition>(\n endpoint: T,\n options: DownloadRequestOptions<T>,\n): void {\n // Validate params\n if (endpoint.params && options.params) {\n const result = endpoint.params.safeParse(options.params);\n if (!result.success) {\n throw new ClientValidationError('params', result.error.issues);\n }\n }\n\n // Validate query\n if (endpoint.query && options.query) {\n const result = endpoint.query.safeParse(options.query);\n if (!result.success) {\n throw new ClientValidationError('query', result.error.issues);\n }\n }\n\n // Validate headers\n if (endpoint.headers && options.headers) {\n const result = endpoint.headers.safeParse(options.headers);\n if (!result.success) {\n throw new ClientValidationError('headers', result.error.issues);\n }\n }\n}\n\n/**\n * Validate download error response data\n */\nfunction validateDownloadErrorResponse<T extends DownloadEndpointDefinition>(\n endpoint: T,\n status: number,\n data: unknown,\n): void {\n if (endpoint.errorResponses) {\n const responseSchema = endpoint.errorResponses[status];\n if (responseSchema) {\n const result = responseSchema.safeParse(data);\n if (!result.success) {\n throw new ClientValidationError(`response[${status}]`, result.error.issues);\n }\n }\n }\n}\n\n/**\n * Make a download request using fetch with progress support\n */\nasync function makeDownloadRequest<T extends DownloadEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: DownloadRequestOptions<T> = {},\n): Promise<DownloadResponse<T>> {\n // Validate request if enabled\n if (config.validateRequest !== false) {\n validateDownloadRequest(endpoint, options);\n }\n\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // Build headers\n const headers = new Headers(config.headers);\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.set(key, String(value));\n }\n }\n\n // Build request init\n const init: RequestInit = {\n method: 'GET',\n headers,\n };\n\n // Add abort signal if present\n if (options.abortSignal) {\n init.signal = options.abortSignal;\n }\n\n // Make request\n const response = await fetch(url, init);\n\n // Handle success (200) - return File\n if (response.status === 200) {\n const contentLength = response.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n\n let blob: Blob;\n\n if (options.onDownloadProgress && response.body) {\n // Stream the response to track progress\n const reader = response.body.getReader();\n const chunks: BlobPart[] = [];\n let loaded = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunks.push(value);\n loaded += value.length;\n\n options.onDownloadProgress({\n loaded,\n total,\n progress: total > 0 ? loaded / total : NaN,\n });\n }\n\n blob = new Blob(chunks);\n } else {\n blob = await response.blob();\n }\n\n const contentDisposition = response.headers.get('content-disposition');\n const filename = extractFilename(contentDisposition) || 'download';\n const contentType = response.headers.get('content-type') || 'application/octet-stream';\n\n const file = new File([blob], filename, { type: contentType });\n\n return {\n status: 200,\n data: file,\n } as DownloadResponse<T>;\n }\n\n // Handle error responses\n let data: unknown;\n const contentType = response.headers.get('content-type') || '';\n\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n // Check for HTTP errors not in errorResponses\n if (endpoint.errorResponses && !(response.status in endpoint.errorResponses)) {\n throw new HTTPError(response.status, response.statusText, data);\n }\n\n // Validate error response if enabled\n if (config.validateResponse !== false) {\n validateDownloadErrorResponse(endpoint, response.status, data);\n }\n\n return {\n status: response.status,\n data,\n } as DownloadResponse<T>;\n}\n\n/**\n * Make a request using XMLHttpRequest for upload progress support\n */\nfunction makeRequestWithXHR<T extends StandardEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: EndpointRequestOptions<T>,\n url: string,\n): Promise<EndpointResponse<T>> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.open(endpoint.method, url);\n\n // Set base headers from config\n if (config.headers) {\n for (const [key, value] of Object.entries(config.headers)) {\n xhr.setRequestHeader(key, value);\n }\n }\n\n // Set request-specific headers\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n xhr.setRequestHeader(key, String(value));\n }\n }\n\n // Upload progress callback\n if (options.onUploadProgress) {\n xhr.upload.onprogress = (e) => {\n if (e.lengthComputable && options.onUploadProgress) {\n options.onUploadProgress({\n loaded: e.loaded,\n total: e.total,\n progress: e.loaded / e.total,\n });\n }\n };\n }\n\n // Handle abort signal\n if (options.abortSignal) {\n if (options.abortSignal.aborted) {\n xhr.abort();\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n options.abortSignal.addEventListener('abort', () => {\n xhr.abort();\n });\n }\n\n xhr.onload = () => {\n let data: unknown;\n const responseContentType = xhr.getResponseHeader('content-type') || '';\n\n if (xhr.status === 204) {\n data = {};\n } else if (responseContentType.includes('application/json')) {\n try {\n data = JSON.parse(xhr.responseText);\n } catch {\n data = xhr.responseText || {};\n }\n } else if (responseContentType.includes('text/')) {\n data = xhr.responseText;\n } else {\n data = xhr.responseText || {};\n }\n\n // Check for HTTP errors\n if (xhr.status >= 400 && !(xhr.status in endpoint.responses)) {\n reject(new HTTPError(xhr.status, xhr.statusText, data));\n return;\n }\n\n // Validate response if enabled\n if (config.validateResponse !== false) {\n try {\n validateResponse(endpoint, xhr.status, data);\n } catch (err) {\n reject(err);\n return;\n }\n }\n\n resolve({\n status: xhr.status,\n data,\n } as EndpointResponse<T>);\n };\n\n xhr.onerror = () => reject(new Error('Network error'));\n xhr.onabort = () => reject(new DOMException('Aborted', 'AbortError'));\n\n // Prepare and send body\n const contentType = endpoint.contentType ?? 'application/json';\n if (options.body !== undefined) {\n if (contentType === 'multipart/form-data') {\n // Don't set Content-Type header - browser sets boundary automatically\n xhr.send(objectToFormData(options.body as Record<string, unknown>));\n } else {\n xhr.setRequestHeader('content-type', 'application/json');\n xhr.send(JSON.stringify(options.body));\n }\n } else {\n xhr.send();\n }\n });\n}\n\n/**\n * Make a request to a standard endpoint\n */\nasync function makeRequest<T extends StandardEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): Promise<EndpointResponse<T>> {\n // Validate request if enabled\n if (config.validateRequest !== false) {\n validateRequest(endpoint, options);\n }\n\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // Use XHR for upload progress support\n if (options.onUploadProgress && options.body !== undefined) {\n return makeRequestWithXHR(config, endpoint, options, url);\n }\n\n // Build headers\n const headers = new Headers(config.headers);\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.set(key, String(value));\n }\n }\n\n // Build request init\n const init: RequestInit = {\n method: endpoint.method,\n headers,\n };\n\n // Add abort signal if present\n if (options.abortSignal) {\n init.signal = options.abortSignal;\n }\n\n // Add body if present\n if (options.body !== undefined) {\n const contentType = endpoint.contentType ?? 'application/json';\n\n if (contentType === 'multipart/form-data') {\n // Don't set Content-Type header - browser sets boundary automatically\n init.body = objectToFormData(options.body as Record<string, unknown>);\n } else {\n headers.set('content-type', 'application/json');\n init.body = JSON.stringify(options.body);\n }\n }\n\n // Make request\n const response = await fetch(url, init);\n\n // Parse response\n let data: unknown;\n\n // Handle 204 No Content\n if (response.status === 204) {\n data = {};\n } else {\n const contentType = response.headers.get('content-type') || '';\n\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else if (contentType.includes('text/')) {\n data = await response.text();\n } else {\n // Check if there's any content\n const text = await response.text();\n if (text) {\n data = text;\n } else {\n data = {};\n }\n }\n }\n\n // Check for HTTP errors\n if (!response.ok && !(response.status in endpoint.responses)) {\n throw new HTTPError(response.status, response.statusText, data);\n }\n\n // Validate response if enabled\n if (config.validateResponse !== false) {\n validateResponse(endpoint, response.status, data);\n }\n\n return {\n status: response.status,\n data,\n } as EndpointResponse<T>;\n}\n\n/**\n * Create a streaming result from an NDJSON response\n */\nfunction createStreamingResult<T extends StreamingEndpointDefinition>(\n response: Response,\n controller: AbortController,\n): StreamingResult<T> {\n type ChunkHandler = (chunk: ExtractChunk<T>) => void;\n type CloseHandler = (final?: ExtractFinalResponse<T>) => void;\n type ErrorHandler = (error: Error) => void;\n\n const listeners = {\n chunk: new Set<ChunkHandler>(),\n close: new Set<CloseHandler>(),\n error: new Set<ErrorHandler>(),\n };\n\n // Start reading in background\n (async () => {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line);\n if (parsed.__final__) {\n listeners.close.forEach((h) => h(parsed.data));\n } else {\n listeners.chunk.forEach((h) => h(parsed as ExtractChunk<T>));\n }\n } catch (parseErr) {\n listeners.error.forEach((h) => h(parseErr as Error));\n }\n }\n }\n\n // Process any remaining buffer content\n if (buffer.trim()) {\n try {\n const parsed = JSON.parse(buffer);\n if (parsed.__final__) {\n listeners.close.forEach((h) => h(parsed.data));\n } else {\n listeners.chunk.forEach((h) => h(parsed as ExtractChunk<T>));\n }\n } catch {\n // Ignore incomplete JSON at end\n }\n }\n\n // Stream ended without final message\n listeners.close.forEach((h) => h());\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n listeners.error.forEach((h) => h(err as Error));\n }\n }\n })();\n\n return {\n on(event: 'chunk' | 'close' | 'error', handler: ChunkHandler | CloseHandler | ErrorHandler) {\n (listeners[event] as Set<typeof handler>).add(handler);\n return () => (listeners[event] as Set<typeof handler>).delete(handler);\n },\n abort() {\n controller.abort();\n },\n get aborted() {\n return controller.signal.aborted;\n },\n } as StreamingResult<T>;\n}\n\n/**\n * Validate streaming request data before sending\n */\nfunction validateStreamingRequest<T extends StreamingEndpointDefinition>(\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): void {\n // Validate params\n if (endpoint.params && options.params) {\n const result = endpoint.params.safeParse(options.params);\n if (!result.success) {\n throw new ClientValidationError('params', result.error.issues);\n }\n }\n\n // Validate query\n if (endpoint.query && options.query) {\n const result = endpoint.query.safeParse(options.query);\n if (!result.success) {\n throw new ClientValidationError('query', result.error.issues);\n }\n }\n\n // Validate headers\n if (endpoint.headers && options.headers) {\n const result = endpoint.headers.safeParse(options.headers);\n if (!result.success) {\n throw new ClientValidationError('headers', result.error.issues);\n }\n }\n\n // Validate body\n if (endpoint.body && options.body) {\n const result = endpoint.body.safeParse(options.body);\n if (!result.success) {\n throw new ClientValidationError('body', result.error.issues);\n }\n }\n}\n\n/**\n * Make a streaming request to an endpoint\n */\nasync function makeStreamingRequest<T extends StreamingEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): Promise<StreamingResult<T>> {\n // Validate request if enabled\n if (config.validateRequest !== false) {\n validateStreamingRequest(endpoint, options);\n }\n\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // Build headers\n const headers = new Headers(config.headers);\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.set(key, String(value));\n }\n }\n\n // Build request init - create our own controller for abort() method\n const controller = new AbortController();\n\n // Link to external abort signal if provided\n if (options.abortSignal) {\n if (options.abortSignal.aborted) {\n controller.abort();\n } else {\n options.abortSignal.addEventListener('abort', () => controller.abort());\n }\n }\n\n const init: RequestInit = {\n method: endpoint.method,\n headers,\n signal: controller.signal,\n };\n\n // Add body if present\n if (options.body !== undefined) {\n const contentType = endpoint.contentType ?? 'application/json';\n\n if (contentType === 'multipart/form-data') {\n init.body = objectToFormData(options.body as Record<string, unknown>);\n } else {\n headers.set('content-type', 'application/json');\n init.body = JSON.stringify(options.body);\n }\n }\n\n // Make request\n const response = await fetch(url, init);\n\n // Check for error responses before streaming\n if (!response.ok) {\n const contentType = response.headers.get('content-type') || '';\n let data: unknown;\n\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n throw new HTTPError(response.status, response.statusText, data);\n }\n\n // Return streaming result\n return createStreamingResult<T>(response, controller);\n}\n\n/**\n * Create an SSE connection\n */\nfunction createSSEConnection<T extends SSEEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: Omit<EndpointRequestOptions<T>, 'body' | 'onUploadProgress'> = {},\n): SSEConnection<T> {\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // EventSource doesn't support custom headers, but we can include query params\n // Note: If auth headers are needed, consider using fetch-based SSE or passing auth in query\n const eventSource = new EventSource(url);\n\n type EventHandler = (data: unknown, id?: string) => void;\n type ErrorHandler = (error: Error) => void;\n\n const listeners: Record<string, Set<EventHandler | ErrorHandler>> = {\n error: new Set<ErrorHandler>(),\n };\n\n // Get event names from the endpoint\n const eventNames = Object.keys(endpoint.events);\n\n // Register listeners for each event type\n for (const eventName of eventNames) {\n listeners[eventName] = new Set<EventHandler>();\n eventSource.addEventListener(eventName, (e) => {\n const messageEvent = e as MessageEvent;\n try {\n const data = JSON.parse(messageEvent.data);\n (listeners[eventName] as Set<EventHandler>).forEach((h) =>\n h(data, messageEvent.lastEventId || undefined),\n );\n } catch (err) {\n (listeners.error as Set<ErrorHandler>).forEach((h) =>\n h(new Error(`Failed to parse SSE data: ${(err as Error).message}`)),\n );\n }\n });\n }\n\n // Handle errors\n eventSource.onerror = () => {\n (listeners.error as Set<ErrorHandler>).forEach((h) => h(new Error('SSE connection error')));\n };\n\n return {\n on(event: string, handler: EventHandler | ErrorHandler) {\n if (!listeners[event]) {\n listeners[event] = new Set();\n }\n (listeners[event] as Set<typeof handler>).add(handler);\n return () => (listeners[event] as Set<typeof handler>).delete(handler);\n },\n close() {\n eventSource.close();\n },\n get state() {\n const states = ['connecting', 'open', 'closed'] as const;\n return states[eventSource.readyState];\n },\n } as SSEConnection<T>;\n}\n\n/**\n * Resolve relative baseUrl to absolute URL in browser contexts\n */\nfunction resolveBaseUrl(baseUrl: string): string {\n // If baseUrl is already absolute, return as-is\n if (baseUrl.startsWith('http://') || baseUrl.startsWith('https://')) {\n return baseUrl;\n }\n\n // If baseUrl is relative (starts with /), resolve it using window.location in browser\n if (baseUrl.startsWith('/')) {\n const g = globalThis as unknown as { location?: { origin?: string } };\n const origin = g?.location?.origin || 'http://localhost';\n return origin + baseUrl;\n }\n\n // Otherwise, assume it's a full URL\n return baseUrl;\n}\n\n/**\n * Create a typesafe client for a contract\n */\nexport function createClient<T extends Contract>(contract: T, config: ClientConfig): Client<T> {\n // Resolve relative baseUrl to absolute URL\n const resolvedConfig = {\n ...config,\n baseUrl: resolveBaseUrl(config.baseUrl),\n };\n\n const client: Record<string, unknown> = {};\n\n for (const [name, endpoint] of Object.entries(contract)) {\n if (endpoint.type === 'standard') {\n client[name] = (options: EndpointRequestOptions<StandardEndpointDefinition> = {}) => {\n return makeRequest(resolvedConfig, endpoint, options);\n };\n } else if (endpoint.type === 'streaming') {\n client[name] = (options: EndpointRequestOptions<StreamingEndpointDefinition> = {}) => {\n return makeStreamingRequest(resolvedConfig, endpoint, options);\n };\n } else if (endpoint.type === 'sse') {\n client[name] = (\n options: Omit<\n EndpointRequestOptions<SSEEndpointDefinition>,\n 'body' | 'onUploadProgress'\n > = {},\n ) => {\n return createSSEConnection(resolvedConfig, endpoint, options);\n };\n } else if (endpoint.type === 'download') {\n client[name] = (options: DownloadRequestOptions<DownloadEndpointDefinition> = {}) => {\n return makeDownloadRequest(resolvedConfig, endpoint, options);\n };\n } else {\n throw new Error(`Endpoint \"${name}\" has unknown type \"${(endpoint as any).type}\".`);\n }\n }\n\n return client as Client<T>;\n}\n\n/**\n * Create a client without providing the contract at runtime\n * Useful when you only need types and want a lighter bundle\n */\nexport function createTypedClient<T extends Contract>(_config: ClientConfig): Client<T> {\n return new Proxy({} as Client<T>, {\n get(_target, _prop: string) {\n return async (_options: EndpointRequestOptions<EndpointDefinition> = {}) => {\n // Without the contract, we can't validate or infer the endpoint\n // This is just a basic fetch wrapper with typing\n throw new Error(\n 'createTypedClient requires contract at runtime for validation. Use createClient instead.',\n );\n };\n },\n });\n}\n\nexport * from './websocket.mjs';\n"
|
|
5
|
+
"/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport type {\n Contract,\n DownloadEndpointDefinition,\n DownloadProgressEvent,\n EndpointDefinition,\n ExtractBody,\n ExtractChunk,\n ExtractFinalResponse,\n ExtractHeaders,\n ExtractParams,\n ExtractQuery,\n ExtractSSEEventData,\n SSEEndpointDefinition,\n StandardEndpointDefinition,\n StreamingEndpointDefinition,\n UploadProgressEvent,\n} from '@richie-rpc/core';\nimport { buildUrl, interpolatePath, objectToFormData } from '@richie-rpc/core';\n\n// Re-export for convenience\nexport type { UploadProgressEvent, DownloadProgressEvent };\nimport { z } from 'zod';\n\n// Client configuration\nexport interface ClientConfig {\n baseUrl: string;\n headers?: Record<string, string>;\n validateRequest?: boolean;\n parseResponse?: boolean;\n}\n\n// Request options for an endpoint\nexport type EndpointRequestOptions<T extends EndpointDefinition> = {\n params?: ExtractParams<T> extends never ? never : ExtractParams<T>;\n query?: ExtractQuery<T> extends never ? never : ExtractQuery<T>;\n headers?: ExtractHeaders<T> extends never ? never : ExtractHeaders<T>;\n body?: ExtractBody<T> extends never ? never : ExtractBody<T>;\n abortSignal?: AbortSignal;\n /** Upload progress callback (uses XHR for progress tracking) */\n onUploadProgress?: (event: UploadProgressEvent) => void;\n};\n\n// Response type for a standard endpoint (union of all possible responses)\nexport type EndpointResponse<T extends StandardEndpointDefinition> = {\n [Status in keyof T['responses']]: {\n status: Status;\n data: T['responses'][Status] extends z.ZodTypeAny ? z.infer<T['responses'][Status]> : never;\n };\n}[keyof T['responses']];\n\n// Client method type for a standard endpoint\nexport type ClientMethod<T extends StandardEndpointDefinition> = (\n options: EndpointRequestOptions<T>,\n) => Promise<EndpointResponse<T>>;\n\n// ============================================\n// Streaming Endpoint Client Types\n// ============================================\n\n/**\n * Result object for streaming endpoints - event-based API\n */\nexport interface StreamingResult<T extends StreamingEndpointDefinition> {\n /** Subscribe to chunks */\n on(event: 'chunk', handler: (chunk: ExtractChunk<T>) => void): () => void;\n /** Subscribe to stream close (with optional final response) */\n on(event: 'close', handler: (final?: ExtractFinalResponse<T>) => void): () => void;\n /** Subscribe to errors */\n on(event: 'error', handler: (error: Error) => void): () => void;\n /** Abort the stream */\n abort(): void;\n /** Check if aborted */\n readonly aborted: boolean;\n}\n\n/**\n * Client method type for streaming endpoints\n */\nexport type StreamingClientMethod<T extends StreamingEndpointDefinition> = (\n options: EndpointRequestOptions<T>,\n) => Promise<StreamingResult<T>>;\n\n// ============================================\n// SSE Endpoint Client Types\n// ============================================\n\n/**\n * Connection object for SSE endpoints - event-based API\n */\nexport interface SSEConnection<T extends SSEEndpointDefinition> {\n /** Subscribe to a specific event type */\n on<K extends keyof T['events']>(\n event: K,\n handler: (data: ExtractSSEEventData<T, K>, id?: string) => void,\n ): () => void;\n /** Subscribe to errors */\n on(event: 'error', handler: (error: Error) => void): () => void;\n /** Close the connection */\n close(): void;\n /** Current connection state */\n readonly state: 'connecting' | 'open' | 'closed';\n}\n\n/**\n * Client method type for SSE endpoints\n */\nexport type SSEClientMethod<T extends SSEEndpointDefinition> = (\n options?: Omit<EndpointRequestOptions<T>, 'body' | 'onUploadProgress'>,\n) => SSEConnection<T>;\n\n// ============================================\n// Download Endpoint Client Types\n// ============================================\n\n/**\n * Request options for download endpoints\n */\nexport type DownloadRequestOptions<T extends DownloadEndpointDefinition> = {\n params?: ExtractParams<T> extends never ? never : ExtractParams<T>;\n query?: ExtractQuery<T> extends never ? never : ExtractQuery<T>;\n headers?: ExtractHeaders<T> extends never ? never : ExtractHeaders<T>;\n abortSignal?: AbortSignal;\n /** Download progress callback */\n onDownloadProgress?: (event: DownloadProgressEvent) => void;\n};\n\n/**\n * Response type for download endpoints\n * Success (200) returns File, errors return typed error response\n */\nexport type DownloadResponse<T extends DownloadEndpointDefinition> =\n | { status: 200; data: File }\n | (T['errorResponses'] extends Record<number, z.ZodTypeAny>\n ? {\n [S in keyof T['errorResponses']]: {\n status: S;\n data: T['errorResponses'][S] extends z.ZodTypeAny\n ? z.infer<T['errorResponses'][S]>\n : never;\n };\n }[keyof T['errorResponses']]\n : never);\n\n/**\n * Client method type for download endpoints\n */\nexport type DownloadClientMethod<T extends DownloadEndpointDefinition> = (\n options?: DownloadRequestOptions<T>,\n) => Promise<DownloadResponse<T>>;\n\n// Client type for a contract (supports all endpoint types)\nexport type Client<T extends Contract> = {\n [K in keyof T]: T[K] extends StandardEndpointDefinition\n ? ClientMethod<T[K]>\n : T[K] extends StreamingEndpointDefinition\n ? StreamingClientMethod<T[K]>\n : T[K] extends SSEEndpointDefinition\n ? SSEClientMethod<T[K]>\n : T[K] extends DownloadEndpointDefinition\n ? DownloadClientMethod<T[K]>\n : never;\n};\n\n// Validation error\nexport class ClientValidationError extends Error {\n constructor(\n public field: string,\n public zodError: z.ZodError<unknown>,\n ) {\n const pretty = z.prettifyError(zodError);\n super(`Validation failed for ${field}:\\n${pretty}`);\n this.name = 'ClientValidationError';\n }\n}\n\n// HTTP error\nexport class HTTPError extends Error {\n constructor(\n public status: number,\n public statusText: string,\n public body: unknown,\n ) {\n super(`HTTP Error ${status}: ${statusText}`);\n this.name = 'HTTPError';\n }\n}\n\n/**\n * Validate request data before sending\n */\nfunction validateRequest<T extends StandardEndpointDefinition>(\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): void {\n // Validate params\n if (endpoint.params && options.params) {\n const result = endpoint.params.safeParse(options.params);\n if (!result.success) {\n throw new ClientValidationError('params', result.error);\n }\n }\n\n // Validate query\n if (endpoint.query && options.query) {\n const result = endpoint.query.safeParse(options.query);\n if (!result.success) {\n throw new ClientValidationError('query', result.error);\n }\n }\n\n // Validate headers\n if (endpoint.headers && options.headers) {\n const result = endpoint.headers.safeParse(options.headers);\n if (!result.success) {\n throw new ClientValidationError('headers', result.error);\n }\n }\n\n // Validate body\n if (endpoint.body && options.body) {\n const result = endpoint.body.safeParse(options.body);\n if (!result.success) {\n throw new ClientValidationError('body', result.error);\n }\n }\n}\n\n/**\n * Parse and transform response data using Zod schema\n */\nfunction parseResponse<T extends StandardEndpointDefinition>(\n endpoint: T,\n status: number,\n data: unknown,\n): unknown {\n const responseSchema = endpoint.responses[status];\n if (responseSchema) {\n const result = responseSchema.safeParse(data);\n if (!result.success) {\n throw new ClientValidationError(`response[${status}]`, result.error);\n }\n return result.data;\n }\n return data;\n}\n\n/**\n * Extract filename from Content-Disposition header\n */\nfunction extractFilename(contentDisposition: string | null): string | null {\n if (!contentDisposition) return null;\n // Try filename*= (RFC 5987) first\n const filenameStarMatch = contentDisposition.match(/filename\\*=(?:UTF-8'')?([^;\\s]+)/i);\n if (filenameStarMatch && filenameStarMatch[1]) {\n return decodeURIComponent(filenameStarMatch[1]);\n }\n // Try filename= (standard)\n const filenameMatch = contentDisposition.match(/filename=[\"']?([^\"';\\s]+)[\"']?/i);\n if (filenameMatch && filenameMatch[1]) {\n return filenameMatch[1];\n }\n return null;\n}\n\n/**\n * Validate download request data before sending\n */\nfunction validateDownloadRequest<T extends DownloadEndpointDefinition>(\n endpoint: T,\n options: DownloadRequestOptions<T>,\n): void {\n // Validate params\n if (endpoint.params && options.params) {\n const result = endpoint.params.safeParse(options.params);\n if (!result.success) {\n throw new ClientValidationError('params', result.error);\n }\n }\n\n // Validate query\n if (endpoint.query && options.query) {\n const result = endpoint.query.safeParse(options.query);\n if (!result.success) {\n throw new ClientValidationError('query', result.error);\n }\n }\n\n // Validate headers\n if (endpoint.headers && options.headers) {\n const result = endpoint.headers.safeParse(options.headers);\n if (!result.success) {\n throw new ClientValidationError('headers', result.error);\n }\n }\n}\n\n/**\n * Parse and transform download error response data using Zod schema\n */\nfunction parseDownloadErrorResponse<T extends DownloadEndpointDefinition>(\n endpoint: T,\n status: number,\n data: unknown,\n): unknown {\n if (endpoint.errorResponses) {\n const responseSchema = endpoint.errorResponses[status];\n if (responseSchema) {\n const result = responseSchema.safeParse(data);\n if (!result.success) {\n throw new ClientValidationError(`response[${status}]`, result.error);\n }\n return result.data;\n }\n }\n return data;\n}\n\n/**\n * Make a download request using fetch with progress support\n */\nasync function makeDownloadRequest<T extends DownloadEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: DownloadRequestOptions<T> = {},\n): Promise<DownloadResponse<T>> {\n // Validate request if enabled\n if (config.validateRequest !== false) {\n validateDownloadRequest(endpoint, options);\n }\n\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // Build headers\n const headers = new Headers(config.headers);\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.set(key, String(value));\n }\n }\n\n // Build request init\n const init: RequestInit = {\n method: 'GET',\n headers,\n };\n\n // Add abort signal if present\n if (options.abortSignal) {\n init.signal = options.abortSignal;\n }\n\n // Make request\n const response = await fetch(url, init);\n\n // Handle success (200) - return File\n if (response.status === 200) {\n const contentLength = response.headers.get('content-length');\n const total = contentLength ? parseInt(contentLength, 10) : 0;\n\n let blob: Blob;\n\n if (options.onDownloadProgress && response.body) {\n // Stream the response to track progress\n const reader = response.body.getReader();\n const chunks: BlobPart[] = [];\n let loaded = 0;\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n chunks.push(value);\n loaded += value.length;\n\n options.onDownloadProgress({\n loaded,\n total,\n progress: total > 0 ? loaded / total : NaN,\n });\n }\n\n blob = new Blob(chunks);\n } else {\n blob = await response.blob();\n }\n\n const contentDisposition = response.headers.get('content-disposition');\n const filename = extractFilename(contentDisposition) || 'download';\n const contentType = response.headers.get('content-type') || 'application/octet-stream';\n\n const file = new File([blob], filename, { type: contentType });\n\n return {\n status: 200,\n data: file,\n } as DownloadResponse<T>;\n }\n\n // Handle error responses\n let data: unknown;\n const contentType = response.headers.get('content-type') || '';\n\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n // Check for HTTP errors not in errorResponses\n if (endpoint.errorResponses && !(response.status in endpoint.errorResponses)) {\n throw new HTTPError(response.status, response.statusText, data);\n }\n\n // Parse error response if enabled\n const parsedData =\n config.parseResponse !== false\n ? parseDownloadErrorResponse(endpoint, response.status, data)\n : data;\n\n return {\n status: response.status,\n data: parsedData,\n } as DownloadResponse<T>;\n}\n\n/**\n * Make a request using XMLHttpRequest for upload progress support\n */\nfunction makeRequestWithXHR<T extends StandardEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: EndpointRequestOptions<T>,\n url: string,\n): Promise<EndpointResponse<T>> {\n return new Promise((resolve, reject) => {\n const xhr = new XMLHttpRequest();\n\n xhr.open(endpoint.method, url);\n\n // Set base headers from config\n if (config.headers) {\n for (const [key, value] of Object.entries(config.headers)) {\n xhr.setRequestHeader(key, value);\n }\n }\n\n // Set request-specific headers\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n xhr.setRequestHeader(key, String(value));\n }\n }\n\n // Upload progress callback\n if (options.onUploadProgress) {\n xhr.upload.onprogress = (e) => {\n if (e.lengthComputable && options.onUploadProgress) {\n options.onUploadProgress({\n loaded: e.loaded,\n total: e.total,\n progress: e.loaded / e.total,\n });\n }\n };\n }\n\n // Handle abort signal\n if (options.abortSignal) {\n if (options.abortSignal.aborted) {\n xhr.abort();\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n options.abortSignal.addEventListener('abort', () => {\n xhr.abort();\n });\n }\n\n xhr.onload = () => {\n let data: unknown;\n const responseContentType = xhr.getResponseHeader('content-type') || '';\n\n if (xhr.status === 204) {\n data = {};\n } else if (responseContentType.includes('application/json')) {\n try {\n data = JSON.parse(xhr.responseText);\n } catch {\n data = xhr.responseText || {};\n }\n } else if (responseContentType.includes('text/')) {\n data = xhr.responseText;\n } else {\n data = xhr.responseText || {};\n }\n\n // Check for HTTP errors\n if (xhr.status >= 400 && !(xhr.status in endpoint.responses)) {\n reject(new HTTPError(xhr.status, xhr.statusText, data));\n return;\n }\n\n // Parse response if enabled\n let parsedData = data;\n if (config.parseResponse !== false) {\n try {\n parsedData = parseResponse(endpoint, xhr.status, data);\n } catch (err) {\n reject(err);\n return;\n }\n }\n\n resolve({\n status: xhr.status,\n data: parsedData,\n } as EndpointResponse<T>);\n };\n\n xhr.onerror = () => reject(new Error('Network error'));\n xhr.onabort = () => reject(new DOMException('Aborted', 'AbortError'));\n\n // Prepare and send body\n const contentType = endpoint.contentType ?? 'application/json';\n if (options.body !== undefined) {\n if (contentType === 'multipart/form-data') {\n // Don't set Content-Type header - browser sets boundary automatically\n xhr.send(objectToFormData(options.body as Record<string, unknown>));\n } else {\n xhr.setRequestHeader('content-type', 'application/json');\n xhr.send(JSON.stringify(options.body));\n }\n } else {\n xhr.send();\n }\n });\n}\n\n/**\n * Make a request to a standard endpoint\n */\nasync function makeRequest<T extends StandardEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): Promise<EndpointResponse<T>> {\n // Validate request if enabled\n if (config.validateRequest !== false) {\n validateRequest(endpoint, options);\n }\n\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // Use XHR for upload progress support\n if (options.onUploadProgress && options.body !== undefined) {\n return makeRequestWithXHR(config, endpoint, options, url);\n }\n\n // Build headers\n const headers = new Headers(config.headers);\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.set(key, String(value));\n }\n }\n\n // Build request init\n const init: RequestInit = {\n method: endpoint.method,\n headers,\n };\n\n // Add abort signal if present\n if (options.abortSignal) {\n init.signal = options.abortSignal;\n }\n\n // Add body if present\n if (options.body !== undefined) {\n const contentType = endpoint.contentType ?? 'application/json';\n\n if (contentType === 'multipart/form-data') {\n // Don't set Content-Type header - browser sets boundary automatically\n init.body = objectToFormData(options.body as Record<string, unknown>);\n } else {\n headers.set('content-type', 'application/json');\n init.body = JSON.stringify(options.body);\n }\n }\n\n // Make request\n const response = await fetch(url, init);\n\n // Parse response\n let data: unknown;\n\n // Handle 204 No Content\n if (response.status === 204) {\n data = {};\n } else {\n const contentType = response.headers.get('content-type') || '';\n\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else if (contentType.includes('text/')) {\n data = await response.text();\n } else {\n // Check if there's any content\n const text = await response.text();\n if (text) {\n data = text;\n } else {\n data = {};\n }\n }\n }\n\n // Check for HTTP errors\n if (!response.ok && !(response.status in endpoint.responses)) {\n throw new HTTPError(response.status, response.statusText, data);\n }\n\n // Parse response if enabled\n const parsedData =\n config.parseResponse !== false ? parseResponse(endpoint, response.status, data) : data;\n\n return {\n status: response.status,\n data: parsedData,\n } as EndpointResponse<T>;\n}\n\n/**\n * Create a streaming result from an NDJSON response\n */\nfunction createStreamingResult<T extends StreamingEndpointDefinition>(\n response: Response,\n controller: AbortController,\n endpoint: T,\n config: ClientConfig,\n): StreamingResult<T> {\n type ChunkHandler = (chunk: ExtractChunk<T>) => void;\n type CloseHandler = (final?: ExtractFinalResponse<T>) => void;\n type ErrorHandler = (error: Error) => void;\n\n const listeners = {\n chunk: new Set<ChunkHandler>(),\n close: new Set<CloseHandler>(),\n error: new Set<ErrorHandler>(),\n };\n\n // Helper to parse chunk data\n const parseChunk = (data: unknown): unknown => {\n if (config.parseResponse !== false && endpoint.chunk) {\n const result = endpoint.chunk.safeParse(data);\n if (!result.success) {\n throw new ClientValidationError('chunk', result.error);\n }\n return result.data;\n }\n return data;\n };\n\n // Helper to parse final response data\n const parseFinalResponse = (data: unknown): unknown => {\n if (config.parseResponse !== false && endpoint.finalResponse) {\n const result = endpoint.finalResponse.safeParse(data);\n if (!result.success) {\n throw new ClientValidationError('finalResponse', result.error);\n }\n return result.data;\n }\n return data;\n };\n\n // Start reading in background\n (async () => {\n const reader = response.body!.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const parsed = JSON.parse(line);\n if (parsed.__final__) {\n const finalData = parseFinalResponse(parsed.data);\n listeners.close.forEach((h) => h(finalData as ExtractFinalResponse<T>));\n } else {\n const chunkData = parseChunk(parsed);\n listeners.chunk.forEach((h) => h(chunkData as ExtractChunk<T>));\n }\n } catch (parseErr) {\n listeners.error.forEach((h) => h(parseErr as Error));\n }\n }\n }\n\n // Process any remaining buffer content\n if (buffer.trim()) {\n try {\n const parsed = JSON.parse(buffer);\n if (parsed.__final__) {\n const finalData = parseFinalResponse(parsed.data);\n listeners.close.forEach((h) => h(finalData as ExtractFinalResponse<T>));\n } else {\n const chunkData = parseChunk(parsed);\n listeners.chunk.forEach((h) => h(chunkData as ExtractChunk<T>));\n }\n } catch {\n // Ignore incomplete JSON at end\n }\n }\n\n // Stream ended without final message\n listeners.close.forEach((h) => h());\n } catch (err) {\n if ((err as Error).name !== 'AbortError') {\n listeners.error.forEach((h) => h(err as Error));\n }\n }\n })();\n\n return {\n on(event: 'chunk' | 'close' | 'error', handler: ChunkHandler | CloseHandler | ErrorHandler) {\n (listeners[event] as Set<typeof handler>).add(handler);\n return () => (listeners[event] as Set<typeof handler>).delete(handler);\n },\n abort() {\n controller.abort();\n },\n get aborted() {\n return controller.signal.aborted;\n },\n } as StreamingResult<T>;\n}\n\n/**\n * Validate streaming request data before sending\n */\nfunction validateStreamingRequest<T extends StreamingEndpointDefinition>(\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): void {\n // Validate params\n if (endpoint.params && options.params) {\n const result = endpoint.params.safeParse(options.params);\n if (!result.success) {\n throw new ClientValidationError('params', result.error);\n }\n }\n\n // Validate query\n if (endpoint.query && options.query) {\n const result = endpoint.query.safeParse(options.query);\n if (!result.success) {\n throw new ClientValidationError('query', result.error);\n }\n }\n\n // Validate headers\n if (endpoint.headers && options.headers) {\n const result = endpoint.headers.safeParse(options.headers);\n if (!result.success) {\n throw new ClientValidationError('headers', result.error);\n }\n }\n\n // Validate body\n if (endpoint.body && options.body) {\n const result = endpoint.body.safeParse(options.body);\n if (!result.success) {\n throw new ClientValidationError('body', result.error);\n }\n }\n}\n\n/**\n * Make a streaming request to an endpoint\n */\nasync function makeStreamingRequest<T extends StreamingEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: EndpointRequestOptions<T>,\n): Promise<StreamingResult<T>> {\n // Validate request if enabled\n if (config.validateRequest !== false) {\n validateStreamingRequest(endpoint, options);\n }\n\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // Build headers\n const headers = new Headers(config.headers);\n if (options.headers) {\n for (const [key, value] of Object.entries(options.headers)) {\n headers.set(key, String(value));\n }\n }\n\n // Build request init - create our own controller for abort() method\n const controller = new AbortController();\n\n // Link to external abort signal if provided\n if (options.abortSignal) {\n if (options.abortSignal.aborted) {\n controller.abort();\n } else {\n options.abortSignal.addEventListener('abort', () => controller.abort());\n }\n }\n\n const init: RequestInit = {\n method: endpoint.method,\n headers,\n signal: controller.signal,\n };\n\n // Add body if present\n if (options.body !== undefined) {\n const contentType = endpoint.contentType ?? 'application/json';\n\n if (contentType === 'multipart/form-data') {\n init.body = objectToFormData(options.body as Record<string, unknown>);\n } else {\n headers.set('content-type', 'application/json');\n init.body = JSON.stringify(options.body);\n }\n }\n\n // Make request\n const response = await fetch(url, init);\n\n // Check for error responses before streaming\n if (!response.ok) {\n const contentType = response.headers.get('content-type') || '';\n let data: unknown;\n\n if (contentType.includes('application/json')) {\n data = await response.json();\n } else {\n data = await response.text();\n }\n\n throw new HTTPError(response.status, response.statusText, data);\n }\n\n // Return streaming result\n return createStreamingResult<T>(response, controller, endpoint, config);\n}\n\n/**\n * Create an SSE connection\n */\nfunction createSSEConnection<T extends SSEEndpointDefinition>(\n config: ClientConfig,\n endpoint: T,\n options: Omit<EndpointRequestOptions<T>, 'body' | 'onUploadProgress'> = {},\n): SSEConnection<T> {\n // Build URL\n let path = endpoint.path;\n if (options.params) {\n path = interpolatePath(path, options.params as Record<string, string | number>);\n }\n\n const url = buildUrl(\n config.baseUrl,\n path,\n options.query as Record<string, string | number | boolean | string[]> | undefined,\n );\n\n // EventSource doesn't support custom headers, but we can include query params\n // Note: If auth headers are needed, consider using fetch-based SSE or passing auth in query\n const eventSource = new EventSource(url);\n\n type EventHandler = (data: unknown, id?: string) => void;\n type ErrorHandler = (error: Error) => void;\n\n const listeners: Record<string, Set<EventHandler | ErrorHandler>> = {\n error: new Set<ErrorHandler>(),\n };\n\n // Get event names from the endpoint\n const eventNames = Object.keys(endpoint.events);\n\n // Register listeners for each event type\n for (const eventName of eventNames) {\n listeners[eventName] = new Set<EventHandler>();\n eventSource.addEventListener(eventName, (e) => {\n const messageEvent = e as MessageEvent;\n try {\n const rawData = JSON.parse(messageEvent.data);\n\n // Parse event data using Zod schema if enabled\n let parsedData = rawData;\n if (config.parseResponse !== false) {\n const eventSchema = endpoint.events[eventName];\n if (eventSchema) {\n const result = eventSchema.safeParse(rawData);\n if (!result.success) {\n (listeners.error as Set<ErrorHandler>).forEach((h) =>\n h(new ClientValidationError(`event[${eventName}]`, result.error)),\n );\n return;\n }\n parsedData = result.data;\n }\n }\n\n (listeners[eventName] as Set<EventHandler>).forEach((h) =>\n h(parsedData, messageEvent.lastEventId || undefined),\n );\n } catch (err) {\n (listeners.error as Set<ErrorHandler>).forEach((h) =>\n h(new Error(`Failed to parse SSE data: ${(err as Error).message}`)),\n );\n }\n });\n }\n\n // Handle errors\n eventSource.onerror = () => {\n (listeners.error as Set<ErrorHandler>).forEach((h) => h(new Error('SSE connection error')));\n };\n\n return {\n on(event: string, handler: EventHandler | ErrorHandler) {\n if (!listeners[event]) {\n listeners[event] = new Set();\n }\n (listeners[event] as Set<typeof handler>).add(handler);\n return () => (listeners[event] as Set<typeof handler>).delete(handler);\n },\n close() {\n eventSource.close();\n },\n get state() {\n const states = ['connecting', 'open', 'closed'] as const;\n return states[eventSource.readyState];\n },\n } as SSEConnection<T>;\n}\n\n/**\n * Resolve relative baseUrl to absolute URL in browser contexts\n */\nfunction resolveBaseUrl(baseUrl: string): string {\n // If baseUrl is already absolute, return as-is\n if (baseUrl.startsWith('http://') || baseUrl.startsWith('https://')) {\n return baseUrl;\n }\n\n // If baseUrl is relative (starts with /), resolve it using window.location in browser\n if (baseUrl.startsWith('/')) {\n const g = globalThis as unknown as { location?: { origin?: string } };\n const origin = g?.location?.origin || 'http://localhost';\n return origin + baseUrl;\n }\n\n // Otherwise, assume it's a full URL\n return baseUrl;\n}\n\n/**\n * Create a typesafe client for a contract\n */\nexport function createClient<T extends Contract>(contract: T, config: ClientConfig): Client<T> {\n // Resolve relative baseUrl to absolute URL\n const resolvedConfig = {\n ...config,\n baseUrl: resolveBaseUrl(config.baseUrl),\n };\n\n const client: Record<string, unknown> = {};\n\n for (const [name, endpoint] of Object.entries(contract)) {\n if (endpoint.type === 'standard') {\n client[name] = (options: EndpointRequestOptions<StandardEndpointDefinition> = {}) => {\n return makeRequest(resolvedConfig, endpoint, options);\n };\n } else if (endpoint.type === 'streaming') {\n client[name] = (options: EndpointRequestOptions<StreamingEndpointDefinition> = {}) => {\n return makeStreamingRequest(resolvedConfig, endpoint, options);\n };\n } else if (endpoint.type === 'sse') {\n client[name] = (\n options: Omit<\n EndpointRequestOptions<SSEEndpointDefinition>,\n 'body' | 'onUploadProgress'\n > = {},\n ) => {\n return createSSEConnection(resolvedConfig, endpoint, options);\n };\n } else if (endpoint.type === 'download') {\n client[name] = (options: DownloadRequestOptions<DownloadEndpointDefinition> = {}) => {\n return makeDownloadRequest(resolvedConfig, endpoint, options);\n };\n } else {\n throw new Error(`Endpoint \"${name}\" has unknown type \"${(endpoint as any).type}\".`);\n }\n }\n\n return client as Client<T>;\n}\n\n/**\n * Create a client without providing the contract at runtime\n * Useful when you only need types and want a lighter bundle\n */\nexport function createTypedClient<T extends Contract>(_config: ClientConfig): Client<T> {\n return new Proxy({} as Client<T>, {\n get(_target, _prop: string) {\n return async (_options: EndpointRequestOptions<EndpointDefinition> = {}) => {\n // Without the contract, we can't validate or infer the endpoint\n // This is just a basic fetch wrapper with typing\n throw new Error(\n 'createTypedClient requires contract at runtime for validation. Use createClient instead.',\n );\n };\n },\n });\n}\n\nexport * from './websocket.mjs';\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;AAmBA;AAAA;AAg+BA;AAAA;AA70BO,MAAM,8BAA8B,MAAM;AAAA,EAEtC;AAAA,EACA;AAAA,EAFT,WAAW,CACF,OACA,QACP;AAAA,IACA,MAAM,yBAAyB,OAAO;AAAA,IAH/B;AAAA,IACA;AAAA,IAGP,KAAK,OAAO;AAAA;AAEhB;AAAA;AAGO,MAAM,kBAAkB,MAAM;AAAA,EAE1B;AAAA,EACA;AAAA,EACA;AAAA,EAHT,WAAW,CACF,QACA,YACA,MACP;AAAA,IACA,MAAM,cAAc,WAAW,YAAY;AAAA,IAJpC;AAAA,IACA;AAAA,IACA;AAAA,IAGP,KAAK,OAAO;AAAA;AAEhB;AAKA,SAAS,eAAqD,CAC5D,UACA,SACM;AAAA,EAEN,IAAI,SAAS,UAAU,QAAQ,QAAQ;AAAA,IACrC,MAAM,SAAS,SAAS,OAAO,UAAU,QAAQ,MAAM;AAAA,IACvD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,UAAU,OAAO,MAAM,MAAM;AAAA,IAC/D;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,SAAS,QAAQ,OAAO;AAAA,IACnC,MAAM,SAAS,SAAS,MAAM,UAAU,QAAQ,KAAK;AAAA,IACrD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,SAAS,OAAO,MAAM,MAAM;AAAA,IAC9D;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,WAAW,QAAQ,SAAS;AAAA,IACvC,MAAM,SAAS,SAAS,QAAQ,UAAU,QAAQ,OAAO;AAAA,IACzD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,WAAW,OAAO,MAAM,MAAM;AAAA,IAChE;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,QAAQ,QAAQ,MAAM;AAAA,IACjC,MAAM,SAAS,SAAS,KAAK,UAAU,QAAQ,IAAI;AAAA,IACnD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,QAAQ,OAAO,MAAM,MAAM;AAAA,IAC7D;AAAA,EACF;AAAA;AAMF,SAAS,gBAAsD,CAC7D,UACA,QACA,MACM;AAAA,EACN,MAAM,iBAAiB,SAAS,UAAU;AAAA,EAC1C,IAAI,gBAAgB;AAAA,IAClB,MAAM,SAAS,eAAe,UAAU,IAAI;AAAA,IAC5C,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,YAAY,WAAW,OAAO,MAAM,MAAM;AAAA,IAC5E;AAAA,EACF;AAAA;AAMF,SAAS,eAAe,CAAC,oBAAkD;AAAA,EACzE,IAAI,CAAC;AAAA,IAAoB,OAAO;AAAA,EAEhC,MAAM,oBAAoB,mBAAmB,MAAM,mCAAmC;AAAA,EACtF,IAAI,qBAAqB,kBAAkB,IAAI;AAAA,IAC7C,OAAO,mBAAmB,kBAAkB,EAAE;AAAA,EAChD;AAAA,EAEA,MAAM,gBAAgB,mBAAmB,MAAM,iCAAiC;AAAA,EAChF,IAAI,iBAAiB,cAAc,IAAI;AAAA,IACrC,OAAO,cAAc;AAAA,EACvB;AAAA,EACA,OAAO;AAAA;AAMT,SAAS,uBAA6D,CACpE,UACA,SACM;AAAA,EAEN,IAAI,SAAS,UAAU,QAAQ,QAAQ;AAAA,IACrC,MAAM,SAAS,SAAS,OAAO,UAAU,QAAQ,MAAM;AAAA,IACvD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,UAAU,OAAO,MAAM,MAAM;AAAA,IAC/D;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,SAAS,QAAQ,OAAO;AAAA,IACnC,MAAM,SAAS,SAAS,MAAM,UAAU,QAAQ,KAAK;AAAA,IACrD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,SAAS,OAAO,MAAM,MAAM;AAAA,IAC9D;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,WAAW,QAAQ,SAAS;AAAA,IACvC,MAAM,SAAS,SAAS,QAAQ,UAAU,QAAQ,OAAO;AAAA,IACzD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,WAAW,OAAO,MAAM,MAAM;AAAA,IAChE;AAAA,EACF;AAAA;AAMF,SAAS,6BAAmE,CAC1E,UACA,QACA,MACM;AAAA,EACN,IAAI,SAAS,gBAAgB;AAAA,IAC3B,MAAM,iBAAiB,SAAS,eAAe;AAAA,IAC/C,IAAI,gBAAgB;AAAA,MAClB,MAAM,SAAS,eAAe,UAAU,IAAI;AAAA,MAC5C,IAAI,CAAC,OAAO,SAAS;AAAA,QACnB,MAAM,IAAI,sBAAsB,YAAY,WAAW,OAAO,MAAM,MAAM;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AAAA;AAMF,eAAe,mBAAyD,CACtE,QACA,UACA,UAAqC,CAAC,GACR;AAAA,EAE9B,IAAI,OAAO,oBAAoB,OAAO;AAAA,IACpC,wBAAwB,UAAU,OAAO;AAAA,EAC3C;AAAA,EAGA,IAAI,OAAO,SAAS;AAAA,EACpB,IAAI,QAAQ,QAAQ;AAAA,IAClB,OAAO,gBAAgB,MAAM,QAAQ,MAAyC;AAAA,EAChF;AAAA,EAEA,MAAM,MAAM,SACV,OAAO,SACP,MACA,QAAQ,KACV;AAAA,EAGA,MAAM,UAAU,IAAI,QAAQ,OAAO,OAAO;AAAA,EAC1C,IAAI,QAAQ,SAAS;AAAA,IACnB,YAAY,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAAA,MAC1D,QAAQ,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IAChC;AAAA,EACF;AAAA,EAGA,MAAM,OAAoB;AAAA,IACxB,QAAQ;AAAA,IACR;AAAA,EACF;AAAA,EAGA,IAAI,QAAQ,aAAa;AAAA,IACvB,KAAK,SAAS,QAAQ;AAAA,EACxB;AAAA,EAGA,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AAAA,EAGtC,IAAI,SAAS,WAAW,KAAK;AAAA,IAC3B,MAAM,gBAAgB,SAAS,QAAQ,IAAI,gBAAgB;AAAA,IAC3D,MAAM,QAAQ,gBAAgB,SAAS,eAAe,EAAE,IAAI;AAAA,IAE5D,IAAI;AAAA,IAEJ,IAAI,QAAQ,sBAAsB,SAAS,MAAM;AAAA,MAE/C,MAAM,SAAS,SAAS,KAAK,UAAU;AAAA,MACvC,MAAM,SAAqB,CAAC;AAAA,MAC5B,IAAI,SAAS;AAAA,MAEb,OAAO,MAAM;AAAA,QACX,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,QAC1C,IAAI;AAAA,UAAM;AAAA,QAEV,OAAO,KAAK,KAAK;AAAA,QACjB,UAAU,MAAM;AAAA,QAEhB,QAAQ,mBAAmB;AAAA,UACzB;AAAA,UACA;AAAA,UACA,UAAU,QAAQ,IAAI,SAAS,QAAQ;AAAA,QACzC,CAAC;AAAA,MACH;AAAA,MAEA,OAAO,IAAI,KAAK,MAAM;AAAA,IACxB,EAAO;AAAA,MACL,OAAO,MAAM,SAAS,KAAK;AAAA;AAAA,IAG7B,MAAM,qBAAqB,SAAS,QAAQ,IAAI,qBAAqB;AAAA,IACrE,MAAM,WAAW,gBAAgB,kBAAkB,KAAK;AAAA,IACxD,MAAM,eAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAAA,IAE5D,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,UAAU,EAAE,MAAM,aAAY,CAAC;AAAA,IAE7D,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAGA,IAAI;AAAA,EACJ,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAAA,EAE5D,IAAI,YAAY,SAAS,kBAAkB,GAAG;AAAA,IAC5C,OAAO,MAAM,SAAS,KAAK;AAAA,EAC7B,EAAO;AAAA,IACL,OAAO,MAAM,SAAS,KAAK;AAAA;AAAA,EAI7B,IAAI,SAAS,kBAAkB,EAAE,SAAS,UAAU,SAAS,iBAAiB;AAAA,IAC5E,MAAM,IAAI,UAAU,SAAS,QAAQ,SAAS,YAAY,IAAI;AAAA,EAChE;AAAA,EAGA,IAAI,OAAO,qBAAqB,OAAO;AAAA,IACrC,8BAA8B,UAAU,SAAS,QAAQ,IAAI;AAAA,EAC/D;AAAA,EAEA,OAAO;AAAA,IACL,QAAQ,SAAS;AAAA,IACjB;AAAA,EACF;AAAA;AAMF,SAAS,kBAAwD,CAC/D,QACA,UACA,SACA,KAC8B;AAAA,EAC9B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,IACtC,MAAM,MAAM,IAAI;AAAA,IAEhB,IAAI,KAAK,SAAS,QAAQ,GAAG;AAAA,IAG7B,IAAI,OAAO,SAAS;AAAA,MAClB,YAAY,KAAK,UAAU,OAAO,QAAQ,OAAO,OAAO,GAAG;AAAA,QACzD,IAAI,iBAAiB,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,IAGA,IAAI,QAAQ,SAAS;AAAA,MACnB,YAAY,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAAA,QAC1D,IAAI,iBAAiB,KAAK,OAAO,KAAK,CAAC;AAAA,MACzC;AAAA,IACF;AAAA,IAGA,IAAI,QAAQ,kBAAkB;AAAA,MAC5B,IAAI,OAAO,aAAa,CAAC,MAAM;AAAA,QAC7B,IAAI,EAAE,oBAAoB,QAAQ,kBAAkB;AAAA,UAClD,QAAQ,iBAAiB;AAAA,YACvB,QAAQ,EAAE;AAAA,YACV,OAAO,EAAE;AAAA,YACT,UAAU,EAAE,SAAS,EAAE;AAAA,UACzB,CAAC;AAAA,QACH;AAAA;AAAA,IAEJ;AAAA,IAGA,IAAI,QAAQ,aAAa;AAAA,MACvB,IAAI,QAAQ,YAAY,SAAS;AAAA,QAC/B,IAAI,MAAM;AAAA,QACV,OAAO,IAAI,aAAa,WAAW,YAAY,CAAC;AAAA,QAChD;AAAA,MACF;AAAA,MACA,QAAQ,YAAY,iBAAiB,SAAS,MAAM;AAAA,QAClD,IAAI,MAAM;AAAA,OACX;AAAA,IACH;AAAA,IAEA,IAAI,SAAS,MAAM;AAAA,MACjB,IAAI;AAAA,MACJ,MAAM,sBAAsB,IAAI,kBAAkB,cAAc,KAAK;AAAA,MAErE,IAAI,IAAI,WAAW,KAAK;AAAA,QACtB,OAAO,CAAC;AAAA,MACV,EAAO,SAAI,oBAAoB,SAAS,kBAAkB,GAAG;AAAA,QAC3D,IAAI;AAAA,UACF,OAAO,KAAK,MAAM,IAAI,YAAY;AAAA,UAClC,MAAM;AAAA,UACN,OAAO,IAAI,gBAAgB,CAAC;AAAA;AAAA,MAEhC,EAAO,SAAI,oBAAoB,SAAS,OAAO,GAAG;AAAA,QAChD,OAAO,IAAI;AAAA,MACb,EAAO;AAAA,QACL,OAAO,IAAI,gBAAgB,CAAC;AAAA;AAAA,MAI9B,IAAI,IAAI,UAAU,OAAO,EAAE,IAAI,UAAU,SAAS,YAAY;AAAA,QAC5D,OAAO,IAAI,UAAU,IAAI,QAAQ,IAAI,YAAY,IAAI,CAAC;AAAA,QACtD;AAAA,MACF;AAAA,MAGA,IAAI,OAAO,qBAAqB,OAAO;AAAA,QACrC,IAAI;AAAA,UACF,iBAAiB,UAAU,IAAI,QAAQ,IAAI;AAAA,UAC3C,OAAO,KAAK;AAAA,UACZ,OAAO,GAAG;AAAA,UACV;AAAA;AAAA,MAEJ;AAAA,MAEA,QAAQ;AAAA,QACN,QAAQ,IAAI;AAAA,QACZ;AAAA,MACF,CAAwB;AAAA;AAAA,IAG1B,IAAI,UAAU,MAAM,OAAO,IAAI,MAAM,eAAe,CAAC;AAAA,IACrD,IAAI,UAAU,MAAM,OAAO,IAAI,aAAa,WAAW,YAAY,CAAC;AAAA,IAGpE,MAAM,cAAc,SAAS,eAAe;AAAA,IAC5C,IAAI,QAAQ,SAAS,WAAW;AAAA,MAC9B,IAAI,gBAAgB,uBAAuB;AAAA,QAEzC,IAAI,KAAK,iBAAiB,QAAQ,IAA+B,CAAC;AAAA,MACpE,EAAO;AAAA,QACL,IAAI,iBAAiB,gBAAgB,kBAAkB;AAAA,QACvD,IAAI,KAAK,KAAK,UAAU,QAAQ,IAAI,CAAC;AAAA;AAAA,IAEzC,EAAO;AAAA,MACL,IAAI,KAAK;AAAA;AAAA,GAEZ;AAAA;AAMH,eAAe,WAAiD,CAC9D,QACA,UACA,SAC8B;AAAA,EAE9B,IAAI,OAAO,oBAAoB,OAAO;AAAA,IACpC,gBAAgB,UAAU,OAAO;AAAA,EACnC;AAAA,EAGA,IAAI,OAAO,SAAS;AAAA,EACpB,IAAI,QAAQ,QAAQ;AAAA,IAClB,OAAO,gBAAgB,MAAM,QAAQ,MAAyC;AAAA,EAChF;AAAA,EAEA,MAAM,MAAM,SACV,OAAO,SACP,MACA,QAAQ,KACV;AAAA,EAGA,IAAI,QAAQ,oBAAoB,QAAQ,SAAS,WAAW;AAAA,IAC1D,OAAO,mBAAmB,QAAQ,UAAU,SAAS,GAAG;AAAA,EAC1D;AAAA,EAGA,MAAM,UAAU,IAAI,QAAQ,OAAO,OAAO;AAAA,EAC1C,IAAI,QAAQ,SAAS;AAAA,IACnB,YAAY,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAAA,MAC1D,QAAQ,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IAChC;AAAA,EACF;AAAA,EAGA,MAAM,OAAoB;AAAA,IACxB,QAAQ,SAAS;AAAA,IACjB;AAAA,EACF;AAAA,EAGA,IAAI,QAAQ,aAAa;AAAA,IACvB,KAAK,SAAS,QAAQ;AAAA,EACxB;AAAA,EAGA,IAAI,QAAQ,SAAS,WAAW;AAAA,IAC9B,MAAM,cAAc,SAAS,eAAe;AAAA,IAE5C,IAAI,gBAAgB,uBAAuB;AAAA,MAEzC,KAAK,OAAO,iBAAiB,QAAQ,IAA+B;AAAA,IACtE,EAAO;AAAA,MACL,QAAQ,IAAI,gBAAgB,kBAAkB;AAAA,MAC9C,KAAK,OAAO,KAAK,UAAU,QAAQ,IAAI;AAAA;AAAA,EAE3C;AAAA,EAGA,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AAAA,EAGtC,IAAI;AAAA,EAGJ,IAAI,SAAS,WAAW,KAAK;AAAA,IAC3B,OAAO,CAAC;AAAA,EACV,EAAO;AAAA,IACL,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAAA,IAE5D,IAAI,YAAY,SAAS,kBAAkB,GAAG;AAAA,MAC5C,OAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,EAAO,SAAI,YAAY,SAAS,OAAO,GAAG;AAAA,MACxC,OAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,EAAO;AAAA,MAEL,MAAM,OAAO,MAAM,SAAS,KAAK;AAAA,MACjC,IAAI,MAAM;AAAA,QACR,OAAO;AAAA,MACT,EAAO;AAAA,QACL,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA,EAMd,IAAI,CAAC,SAAS,MAAM,EAAE,SAAS,UAAU,SAAS,YAAY;AAAA,IAC5D,MAAM,IAAI,UAAU,SAAS,QAAQ,SAAS,YAAY,IAAI;AAAA,EAChE;AAAA,EAGA,IAAI,OAAO,qBAAqB,OAAO;AAAA,IACrC,iBAAiB,UAAU,SAAS,QAAQ,IAAI;AAAA,EAClD;AAAA,EAEA,OAAO;AAAA,IACL,QAAQ,SAAS;AAAA,IACjB;AAAA,EACF;AAAA;AAMF,SAAS,qBAA4D,CACnE,UACA,YACoB;AAAA,EAKpB,MAAM,YAAY;AAAA,IAChB,OAAO,IAAI;AAAA,IACX,OAAO,IAAI;AAAA,IACX,OAAO,IAAI;AAAA,EACb;AAAA,GAGC,YAAY;AAAA,IACX,MAAM,SAAS,SAAS,KAAM,UAAU;AAAA,IACxC,MAAM,UAAU,IAAI;AAAA,IACpB,IAAI,SAAS;AAAA,IAEb,IAAI;AAAA,MACF,OAAO,MAAM;AAAA,QACX,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,QAC1C,IAAI;AAAA,UAAM;AAAA,QAEV,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,QAChD,MAAM,QAAQ,OAAO,MAAM;AAAA,CAAI;AAAA,QAC/B,SAAS,MAAM,IAAI,KAAK;AAAA,QAExB,WAAW,QAAQ,OAAO;AAAA,UACxB,IAAI,CAAC,KAAK,KAAK;AAAA,YAAG;AAAA,UAClB,IAAI;AAAA,YACF,MAAM,SAAS,KAAK,MAAM,IAAI;AAAA,YAC9B,IAAI,OAAO,WAAW;AAAA,cACpB,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC;AAAA,YAC/C,EAAO;AAAA,cACL,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAyB,CAAC;AAAA;AAAA,YAE7D,OAAO,UAAU;AAAA,YACjB,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,QAAiB,CAAC;AAAA;AAAA,QAEvD;AAAA,MACF;AAAA,MAGA,IAAI,OAAO,KAAK,GAAG;AAAA,QACjB,IAAI;AAAA,UACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAAA,UAChC,IAAI,OAAO,WAAW;AAAA,YACpB,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,OAAO,IAAI,CAAC;AAAA,UAC/C,EAAO;AAAA,YACL,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,MAAyB,CAAC;AAAA;AAAA,UAE7D,MAAM;AAAA,MAGV;AAAA,MAGA,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,MAClC,OAAO,KAAK;AAAA,MACZ,IAAK,IAAc,SAAS,cAAc;AAAA,QACxC,UAAU,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAY,CAAC;AAAA,MAChD;AAAA;AAAA,KAED;AAAA,EAEH,OAAO;AAAA,IACL,EAAE,CAAC,OAAoC,SAAqD;AAAA,MACzF,UAAU,OAA+B,IAAI,OAAO;AAAA,MACrD,OAAO,MAAO,UAAU,OAA+B,OAAO,OAAO;AAAA;AAAA,IAEvE,KAAK,GAAG;AAAA,MACN,WAAW,MAAM;AAAA;AAAA,QAEf,OAAO,GAAG;AAAA,MACZ,OAAO,WAAW,OAAO;AAAA;AAAA,EAE7B;AAAA;AAMF,SAAS,wBAA+D,CACtE,UACA,SACM;AAAA,EAEN,IAAI,SAAS,UAAU,QAAQ,QAAQ;AAAA,IACrC,MAAM,SAAS,SAAS,OAAO,UAAU,QAAQ,MAAM;AAAA,IACvD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,UAAU,OAAO,MAAM,MAAM;AAAA,IAC/D;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,SAAS,QAAQ,OAAO;AAAA,IACnC,MAAM,SAAS,SAAS,MAAM,UAAU,QAAQ,KAAK;AAAA,IACrD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,SAAS,OAAO,MAAM,MAAM;AAAA,IAC9D;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,WAAW,QAAQ,SAAS;AAAA,IACvC,MAAM,SAAS,SAAS,QAAQ,UAAU,QAAQ,OAAO;AAAA,IACzD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,WAAW,OAAO,MAAM,MAAM;AAAA,IAChE;AAAA,EACF;AAAA,EAGA,IAAI,SAAS,QAAQ,QAAQ,MAAM;AAAA,IACjC,MAAM,SAAS,SAAS,KAAK,UAAU,QAAQ,IAAI;AAAA,IACnD,IAAI,CAAC,OAAO,SAAS;AAAA,MACnB,MAAM,IAAI,sBAAsB,QAAQ,OAAO,MAAM,MAAM;AAAA,IAC7D;AAAA,EACF;AAAA;AAMF,eAAe,oBAA2D,CACxE,QACA,UACA,SAC6B;AAAA,EAE7B,IAAI,OAAO,oBAAoB,OAAO;AAAA,IACpC,yBAAyB,UAAU,OAAO;AAAA,EAC5C;AAAA,EAGA,IAAI,OAAO,SAAS;AAAA,EACpB,IAAI,QAAQ,QAAQ;AAAA,IAClB,OAAO,gBAAgB,MAAM,QAAQ,MAAyC;AAAA,EAChF;AAAA,EAEA,MAAM,MAAM,SACV,OAAO,SACP,MACA,QAAQ,KACV;AAAA,EAGA,MAAM,UAAU,IAAI,QAAQ,OAAO,OAAO;AAAA,EAC1C,IAAI,QAAQ,SAAS;AAAA,IACnB,YAAY,KAAK,UAAU,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAAA,MAC1D,QAAQ,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,IAChC;AAAA,EACF;AAAA,EAGA,MAAM,aAAa,IAAI;AAAA,EAGvB,IAAI,QAAQ,aAAa;AAAA,IACvB,IAAI,QAAQ,YAAY,SAAS;AAAA,MAC/B,WAAW,MAAM;AAAA,IACnB,EAAO;AAAA,MACL,QAAQ,YAAY,iBAAiB,SAAS,MAAM,WAAW,MAAM,CAAC;AAAA;AAAA,EAE1E;AAAA,EAEA,MAAM,OAAoB;AAAA,IACxB,QAAQ,SAAS;AAAA,IACjB;AAAA,IACA,QAAQ,WAAW;AAAA,EACrB;AAAA,EAGA,IAAI,QAAQ,SAAS,WAAW;AAAA,IAC9B,MAAM,cAAc,SAAS,eAAe;AAAA,IAE5C,IAAI,gBAAgB,uBAAuB;AAAA,MACzC,KAAK,OAAO,iBAAiB,QAAQ,IAA+B;AAAA,IACtE,EAAO;AAAA,MACL,QAAQ,IAAI,gBAAgB,kBAAkB;AAAA,MAC9C,KAAK,OAAO,KAAK,UAAU,QAAQ,IAAI;AAAA;AAAA,EAE3C;AAAA,EAGA,MAAM,WAAW,MAAM,MAAM,KAAK,IAAI;AAAA,EAGtC,IAAI,CAAC,SAAS,IAAI;AAAA,IAChB,MAAM,cAAc,SAAS,QAAQ,IAAI,cAAc,KAAK;AAAA,IAC5D,IAAI;AAAA,IAEJ,IAAI,YAAY,SAAS,kBAAkB,GAAG;AAAA,MAC5C,OAAO,MAAM,SAAS,KAAK;AAAA,IAC7B,EAAO;AAAA,MACL,OAAO,MAAM,SAAS,KAAK;AAAA;AAAA,IAG7B,MAAM,IAAI,UAAU,SAAS,QAAQ,SAAS,YAAY,IAAI;AAAA,EAChE;AAAA,EAGA,OAAO,sBAAyB,UAAU,UAAU;AAAA;AAMtD,SAAS,mBAAoD,CAC3D,QACA,UACA,UAAwE,CAAC,GACvD;AAAA,EAElB,IAAI,OAAO,SAAS;AAAA,EACpB,IAAI,QAAQ,QAAQ;AAAA,IAClB,OAAO,gBAAgB,MAAM,QAAQ,MAAyC;AAAA,EAChF;AAAA,EAEA,MAAM,MAAM,SACV,OAAO,SACP,MACA,QAAQ,KACV;AAAA,EAIA,MAAM,cAAc,IAAI,YAAY,GAAG;AAAA,EAKvC,MAAM,YAA8D;AAAA,IAClE,OAAO,IAAI;AAAA,EACb;AAAA,EAGA,MAAM,aAAa,OAAO,KAAK,SAAS,MAAM;AAAA,EAG9C,WAAW,aAAa,YAAY;AAAA,IAClC,UAAU,aAAa,IAAI;AAAA,IAC3B,YAAY,iBAAiB,WAAW,CAAC,MAAM;AAAA,MAC7C,MAAM,eAAe;AAAA,MACrB,IAAI;AAAA,QACF,MAAM,OAAO,KAAK,MAAM,aAAa,IAAI;AAAA,QACxC,UAAU,WAAiC,QAAQ,CAAC,MACnD,EAAE,MAAM,aAAa,eAAe,SAAS,CAC/C;AAAA,QACA,OAAO,KAAK;AAAA,QACX,UAAU,MAA4B,QAAQ,CAAC,MAC9C,EAAE,IAAI,MAAM,6BAA8B,IAAc,SAAS,CAAC,CACpE;AAAA;AAAA,KAEH;AAAA,EACH;AAAA,EAGA,YAAY,UAAU,MAAM;AAAA,IACzB,UAAU,MAA4B,QAAQ,CAAC,MAAM,EAAE,IAAI,MAAM,sBAAsB,CAAC,CAAC;AAAA;AAAA,EAG5F,OAAO;AAAA,IACL,EAAE,CAAC,OAAe,SAAsC;AAAA,MACtD,IAAI,CAAC,UAAU,QAAQ;AAAA,QACrB,UAAU,SAAS,IAAI;AAAA,MACzB;AAAA,MACC,UAAU,OAA+B,IAAI,OAAO;AAAA,MACrD,OAAO,MAAO,UAAU,OAA+B,OAAO,OAAO;AAAA;AAAA,IAEvE,KAAK,GAAG;AAAA,MACN,YAAY,MAAM;AAAA;AAAA,QAEhB,KAAK,GAAG;AAAA,MACV,MAAM,SAAS,CAAC,cAAc,QAAQ,QAAQ;AAAA,MAC9C,OAAO,OAAO,YAAY;AAAA;AAAA,EAE9B;AAAA;AAMF,SAAS,cAAc,CAAC,SAAyB;AAAA,EAE/C,IAAI,QAAQ,WAAW,SAAS,KAAK,QAAQ,WAAW,UAAU,GAAG;AAAA,IACnE,OAAO;AAAA,EACT;AAAA,EAGA,IAAI,QAAQ,WAAW,GAAG,GAAG;AAAA,IAC3B,MAAM,IAAI;AAAA,IACV,MAAM,SAAS,GAAG,UAAU,UAAU;AAAA,IACtC,OAAO,SAAS;AAAA,EAClB;AAAA,EAGA,OAAO;AAAA;AAMF,SAAS,YAAgC,CAAC,UAAa,QAAiC;AAAA,EAE7F,MAAM,iBAAiB;AAAA,OAClB;AAAA,IACH,SAAS,eAAe,OAAO,OAAO;AAAA,EACxC;AAAA,EAEA,MAAM,SAAkC,CAAC;AAAA,EAEzC,YAAY,MAAM,aAAa,OAAO,QAAQ,QAAQ,GAAG;AAAA,IACvD,IAAI,SAAS,SAAS,YAAY;AAAA,MAChC,OAAO,QAAQ,CAAC,UAA8D,CAAC,MAAM;AAAA,QACnF,OAAO,YAAY,gBAAgB,UAAU,OAAO;AAAA;AAAA,IAExD,EAAO,SAAI,SAAS,SAAS,aAAa;AAAA,MACxC,OAAO,QAAQ,CAAC,UAA+D,CAAC,MAAM;AAAA,QACpF,OAAO,qBAAqB,gBAAgB,UAAU,OAAO;AAAA;AAAA,IAEjE,EAAO,SAAI,SAAS,SAAS,OAAO;AAAA,MAClC,OAAO,QAAQ,CACb,UAGI,CAAC,MACF;AAAA,QACH,OAAO,oBAAoB,gBAAgB,UAAU,OAAO;AAAA;AAAA,IAEhE,EAAO,SAAI,SAAS,SAAS,YAAY;AAAA,MACvC,OAAO,QAAQ,CAAC,UAA8D,CAAC,MAAM;AAAA,QACnF,OAAO,oBAAoB,gBAAgB,UAAU,OAAO;AAAA;AAAA,IAEhE,EAAO;AAAA,MACL,MAAM,IAAI,MAAM,aAAa,2BAA4B,SAAiB,QAAQ;AAAA;AAAA,EAEtF;AAAA,EAEA,OAAO;AAAA;AAOF,SAAS,iBAAqC,CAAC,SAAkC;AAAA,EACtF,OAAO,IAAI,MAAM,CAAC,GAAgB;AAAA,IAChC,GAAG,CAAC,SAAS,OAAe;AAAA,MAC1B,OAAO,OAAO,WAAuD,CAAC,MAAM;AAAA,QAG1E,MAAM,IAAI,MACR,0FACF;AAAA;AAAA;AAAA,EAGN,CAAC;AAAA;",
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "CA9C42DCB1FC53CB64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
package/dist/mjs/package.json
CHANGED