@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.
@@ -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 issues: unknown[],\n ) {\n super(`Validation failed for WebSocket message type: ${messageType}`);\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.issues);\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"
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": "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",
8
- "debugId": "15DE3AD0993419A564756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "019A19CE0CB61DD964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -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
- issues;
10
- constructor(field, issues) {
11
- super(`Validation failed for ${field}`);
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.issues = issues;
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.issues);
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.issues);
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.issues);
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.issues);
55
+ throw new ClientValidationError("body", result.error);
53
56
  }
54
57
  }
55
58
  }
56
- function validateResponse(endpoint, status, data) {
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.issues);
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.issues);
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.issues);
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.issues);
99
+ throw new ClientValidationError("headers", result.error);
95
100
  }
96
101
  }
97
102
  }
98
- function validateDownloadErrorResponse(endpoint, status, data) {
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.issues);
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
- if (config.validateResponse !== false) {
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
- if (config.validateResponse !== false) {
243
+ let parsedData = data;
244
+ if (config.parseResponse !== false) {
239
245
  try {
240
- validateResponse(endpoint, xhr.status, data);
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
- if (config.validateResponse !== false) {
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
- listeners.close.forEach((h) => h(parsed.data));
379
+ const finalData = parseFinalResponse(parsed.data);
380
+ listeners.close.forEach((h) => h(finalData));
356
381
  } else {
357
- listeners.chunk.forEach((h) => h(parsed));
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
- listeners.close.forEach((h) => h(parsed.data));
394
+ const finalData = parseFinalResponse(parsed.data);
395
+ listeners.close.forEach((h) => h(finalData));
369
396
  } else {
370
- listeners.chunk.forEach((h) => h(parsed));
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.issues);
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.issues);
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.issues);
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.issues);
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 data = JSON.parse(messageEvent.data);
487
- listeners[eventName].forEach((h) => h(data, messageEvent.lastEventId || undefined));
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=6F543E32A246010C64756E2164756E21
609
+ //# debugId=CA9C42DCB1FC53CB64756E2164756E21
@@ -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": "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",
8
- "debugId": "6F543E32A246010C64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "CA9C42DCB1FC53CB64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@richie-rpc/client",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "type": "module"
5
5
  }