@richie-rpc/client 1.2.3 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +266 -40
- package/dist/cjs/index.cjs +407 -4
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/cjs/package.json +1 -1
- package/dist/cjs/websocket.cjs +178 -0
- package/dist/cjs/websocket.cjs.map +10 -0
- package/dist/mjs/index.mjs +407 -4
- package/dist/mjs/index.mjs.map +3 -3
- package/dist/mjs/package.json +1 -1
- package/dist/mjs/websocket.mjs +147 -0
- package/dist/mjs/websocket.mjs.map +10 -0
- package/dist/types/index.d.ts +71 -4
- package/dist/types/websocket.d.ts +97 -0
- package/package.json +2 -2
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// @bun @bun-cjs
|
|
2
|
+
(function(exports, require, module, __filename, __dirname) {var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
7
|
+
var __toCommonJS = (from) => {
|
|
8
|
+
var entry = __moduleCache.get(from), desc;
|
|
9
|
+
if (entry)
|
|
10
|
+
return entry;
|
|
11
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
13
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
14
|
+
get: () => from[key],
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
}));
|
|
17
|
+
__moduleCache.set(from, entry);
|
|
18
|
+
return entry;
|
|
19
|
+
};
|
|
20
|
+
var __export = (target, all) => {
|
|
21
|
+
for (var name in all)
|
|
22
|
+
__defProp(target, name, {
|
|
23
|
+
get: all[name],
|
|
24
|
+
enumerable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// packages/client/websocket.ts
|
|
31
|
+
var exports_websocket = {};
|
|
32
|
+
__export(exports_websocket, {
|
|
33
|
+
createWebSocketClient: () => createWebSocketClient,
|
|
34
|
+
WebSocketClientValidationError: () => WebSocketClientValidationError
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(exports_websocket);
|
|
37
|
+
var import_core = require("@richie-rpc/core");
|
|
38
|
+
|
|
39
|
+
class WebSocketClientValidationError extends Error {
|
|
40
|
+
messageType;
|
|
41
|
+
issues;
|
|
42
|
+
constructor(messageType, issues) {
|
|
43
|
+
super(`Validation failed for WebSocket message type: ${messageType}`);
|
|
44
|
+
this.messageType = messageType;
|
|
45
|
+
this.issues = issues;
|
|
46
|
+
this.name = "WebSocketClientValidationError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createTypedWebSocket(endpoint, url) {
|
|
50
|
+
let ws = null;
|
|
51
|
+
let isConnected = false;
|
|
52
|
+
const messageListeners = new Set;
|
|
53
|
+
const typedListeners = {};
|
|
54
|
+
const stateListeners = new Set;
|
|
55
|
+
const errorListeners = new Set;
|
|
56
|
+
for (const type of Object.keys(endpoint.serverMessages)) {
|
|
57
|
+
typedListeners[type] = new Set;
|
|
58
|
+
}
|
|
59
|
+
function notifyStateChange(connected) {
|
|
60
|
+
isConnected = connected;
|
|
61
|
+
stateListeners.forEach((h) => h(connected));
|
|
62
|
+
}
|
|
63
|
+
function notifyError(error) {
|
|
64
|
+
errorListeners.forEach((h) => h(error));
|
|
65
|
+
}
|
|
66
|
+
function handleMessage(event) {
|
|
67
|
+
try {
|
|
68
|
+
const message = JSON.parse(event.data);
|
|
69
|
+
messageListeners.forEach((h) => h(message));
|
|
70
|
+
const { type, payload } = message;
|
|
71
|
+
if (typedListeners[type]) {
|
|
72
|
+
typedListeners[type].forEach((h) => h(payload));
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
notifyError(new Error(`Failed to parse WebSocket message: ${err.message}`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
connect() {
|
|
80
|
+
if (ws) {
|
|
81
|
+
return () => {
|
|
82
|
+
ws?.close();
|
|
83
|
+
ws = null;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
ws = new WebSocket(url);
|
|
87
|
+
ws.onopen = () => {
|
|
88
|
+
notifyStateChange(true);
|
|
89
|
+
};
|
|
90
|
+
ws.onclose = () => {
|
|
91
|
+
notifyStateChange(false);
|
|
92
|
+
ws = null;
|
|
93
|
+
};
|
|
94
|
+
ws.onerror = () => {
|
|
95
|
+
notifyError(new Error("WebSocket connection error"));
|
|
96
|
+
};
|
|
97
|
+
ws.onmessage = handleMessage;
|
|
98
|
+
return () => {
|
|
99
|
+
ws?.close();
|
|
100
|
+
ws = null;
|
|
101
|
+
};
|
|
102
|
+
},
|
|
103
|
+
send(type, payload) {
|
|
104
|
+
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
105
|
+
throw new Error("WebSocket is not connected");
|
|
106
|
+
}
|
|
107
|
+
const messageDef = endpoint.clientMessages[type];
|
|
108
|
+
if (messageDef && messageDef.payload) {
|
|
109
|
+
const result = messageDef.payload.safeParse(payload);
|
|
110
|
+
if (!result.success) {
|
|
111
|
+
throw new WebSocketClientValidationError(type, result.error.issues);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
ws.send(JSON.stringify({ type, payload }));
|
|
115
|
+
},
|
|
116
|
+
on(type, handler) {
|
|
117
|
+
const typeStr = type;
|
|
118
|
+
if (!typedListeners[typeStr]) {
|
|
119
|
+
typedListeners[typeStr] = new Set;
|
|
120
|
+
}
|
|
121
|
+
typedListeners[typeStr].add(handler);
|
|
122
|
+
return () => typedListeners[typeStr]?.delete(handler);
|
|
123
|
+
},
|
|
124
|
+
onMessage(handler) {
|
|
125
|
+
messageListeners.add(handler);
|
|
126
|
+
return () => messageListeners.delete(handler);
|
|
127
|
+
},
|
|
128
|
+
onStateChange(handler) {
|
|
129
|
+
stateListeners.add(handler);
|
|
130
|
+
return () => stateListeners.delete(handler);
|
|
131
|
+
},
|
|
132
|
+
onError(handler) {
|
|
133
|
+
errorListeners.add(handler);
|
|
134
|
+
return () => errorListeners.delete(handler);
|
|
135
|
+
},
|
|
136
|
+
get connected() {
|
|
137
|
+
return isConnected;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function resolveWebSocketUrl(baseUrl) {
|
|
142
|
+
if (baseUrl.startsWith("ws://") || baseUrl.startsWith("wss://")) {
|
|
143
|
+
return baseUrl;
|
|
144
|
+
}
|
|
145
|
+
if (baseUrl.startsWith("http://")) {
|
|
146
|
+
return `ws://${baseUrl.slice(7)}`;
|
|
147
|
+
}
|
|
148
|
+
if (baseUrl.startsWith("https://")) {
|
|
149
|
+
return `wss://${baseUrl.slice(8)}`;
|
|
150
|
+
}
|
|
151
|
+
if (baseUrl.startsWith("/")) {
|
|
152
|
+
const g = globalThis;
|
|
153
|
+
if (g?.location) {
|
|
154
|
+
const protocol = g.location.protocol === "https:" ? "wss:" : "ws:";
|
|
155
|
+
return `${protocol}//${g.location.host}${baseUrl}`;
|
|
156
|
+
}
|
|
157
|
+
return `ws://localhost${baseUrl}`;
|
|
158
|
+
}
|
|
159
|
+
return `ws://${baseUrl}`;
|
|
160
|
+
}
|
|
161
|
+
function createWebSocketClient(contract, config) {
|
|
162
|
+
const resolvedBaseUrl = resolveWebSocketUrl(config.baseUrl);
|
|
163
|
+
const client = {};
|
|
164
|
+
for (const [name, endpoint] of Object.entries(contract)) {
|
|
165
|
+
client[name] = (options = {}) => {
|
|
166
|
+
let path = endpoint.path;
|
|
167
|
+
if (options.params) {
|
|
168
|
+
path = import_core.interpolatePath(path, options.params);
|
|
169
|
+
}
|
|
170
|
+
const url = import_core.buildUrl(resolvedBaseUrl, path, options.query);
|
|
171
|
+
return createTypedWebSocket(endpoint, url);
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return client;
|
|
175
|
+
}
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
//# debugId=15DE3AD0993419A564756E2164756E21
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../websocket.ts"],
|
|
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"
|
|
6
|
+
],
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "15DE3AD0993419A564756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/dist/mjs/index.mjs
CHANGED
|
@@ -60,6 +60,207 @@ function validateResponse(endpoint, status, data) {
|
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
+
function extractFilename(contentDisposition) {
|
|
64
|
+
if (!contentDisposition)
|
|
65
|
+
return null;
|
|
66
|
+
const filenameStarMatch = contentDisposition.match(/filename\*=(?:UTF-8'')?([^;\s]+)/i);
|
|
67
|
+
if (filenameStarMatch && filenameStarMatch[1]) {
|
|
68
|
+
return decodeURIComponent(filenameStarMatch[1]);
|
|
69
|
+
}
|
|
70
|
+
const filenameMatch = contentDisposition.match(/filename=["']?([^"';\s]+)["']?/i);
|
|
71
|
+
if (filenameMatch && filenameMatch[1]) {
|
|
72
|
+
return filenameMatch[1];
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
function validateDownloadRequest(endpoint, options) {
|
|
77
|
+
if (endpoint.params && options.params) {
|
|
78
|
+
const result = endpoint.params.safeParse(options.params);
|
|
79
|
+
if (!result.success) {
|
|
80
|
+
throw new ClientValidationError("params", result.error.issues);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (endpoint.query && options.query) {
|
|
84
|
+
const result = endpoint.query.safeParse(options.query);
|
|
85
|
+
if (!result.success) {
|
|
86
|
+
throw new ClientValidationError("query", result.error.issues);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (endpoint.headers && options.headers) {
|
|
90
|
+
const result = endpoint.headers.safeParse(options.headers);
|
|
91
|
+
if (!result.success) {
|
|
92
|
+
throw new ClientValidationError("headers", result.error.issues);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function validateDownloadErrorResponse(endpoint, status, data) {
|
|
97
|
+
if (endpoint.errorResponses) {
|
|
98
|
+
const responseSchema = endpoint.errorResponses[status];
|
|
99
|
+
if (responseSchema) {
|
|
100
|
+
const result = responseSchema.safeParse(data);
|
|
101
|
+
if (!result.success) {
|
|
102
|
+
throw new ClientValidationError(`response[${status}]`, result.error.issues);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function makeDownloadRequest(config, endpoint, options = {}) {
|
|
108
|
+
if (config.validateRequest !== false) {
|
|
109
|
+
validateDownloadRequest(endpoint, options);
|
|
110
|
+
}
|
|
111
|
+
let path = endpoint.path;
|
|
112
|
+
if (options.params) {
|
|
113
|
+
path = interpolatePath(path, options.params);
|
|
114
|
+
}
|
|
115
|
+
const url = buildUrl(config.baseUrl, path, options.query);
|
|
116
|
+
const headers = new Headers(config.headers);
|
|
117
|
+
if (options.headers) {
|
|
118
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
119
|
+
headers.set(key, String(value));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const init = {
|
|
123
|
+
method: "GET",
|
|
124
|
+
headers
|
|
125
|
+
};
|
|
126
|
+
if (options.abortSignal) {
|
|
127
|
+
init.signal = options.abortSignal;
|
|
128
|
+
}
|
|
129
|
+
const response = await fetch(url, init);
|
|
130
|
+
if (response.status === 200) {
|
|
131
|
+
const contentLength = response.headers.get("content-length");
|
|
132
|
+
const total = contentLength ? parseInt(contentLength, 10) : 0;
|
|
133
|
+
let blob;
|
|
134
|
+
if (options.onDownloadProgress && response.body) {
|
|
135
|
+
const reader = response.body.getReader();
|
|
136
|
+
const chunks = [];
|
|
137
|
+
let loaded = 0;
|
|
138
|
+
while (true) {
|
|
139
|
+
const { done, value } = await reader.read();
|
|
140
|
+
if (done)
|
|
141
|
+
break;
|
|
142
|
+
chunks.push(value);
|
|
143
|
+
loaded += value.length;
|
|
144
|
+
options.onDownloadProgress({
|
|
145
|
+
loaded,
|
|
146
|
+
total,
|
|
147
|
+
progress: total > 0 ? loaded / total : NaN
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
blob = new Blob(chunks);
|
|
151
|
+
} else {
|
|
152
|
+
blob = await response.blob();
|
|
153
|
+
}
|
|
154
|
+
const contentDisposition = response.headers.get("content-disposition");
|
|
155
|
+
const filename = extractFilename(contentDisposition) || "download";
|
|
156
|
+
const contentType2 = response.headers.get("content-type") || "application/octet-stream";
|
|
157
|
+
const file = new File([blob], filename, { type: contentType2 });
|
|
158
|
+
return {
|
|
159
|
+
status: 200,
|
|
160
|
+
data: file
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
let data;
|
|
164
|
+
const contentType = response.headers.get("content-type") || "";
|
|
165
|
+
if (contentType.includes("application/json")) {
|
|
166
|
+
data = await response.json();
|
|
167
|
+
} else {
|
|
168
|
+
data = await response.text();
|
|
169
|
+
}
|
|
170
|
+
if (endpoint.errorResponses && !(response.status in endpoint.errorResponses)) {
|
|
171
|
+
throw new HTTPError(response.status, response.statusText, data);
|
|
172
|
+
}
|
|
173
|
+
if (config.validateResponse !== false) {
|
|
174
|
+
validateDownloadErrorResponse(endpoint, response.status, data);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
status: response.status,
|
|
178
|
+
data
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
function makeRequestWithXHR(config, endpoint, options, url) {
|
|
182
|
+
return new Promise((resolve, reject) => {
|
|
183
|
+
const xhr = new XMLHttpRequest;
|
|
184
|
+
xhr.open(endpoint.method, url);
|
|
185
|
+
if (config.headers) {
|
|
186
|
+
for (const [key, value] of Object.entries(config.headers)) {
|
|
187
|
+
xhr.setRequestHeader(key, value);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
if (options.headers) {
|
|
191
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
192
|
+
xhr.setRequestHeader(key, String(value));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (options.onUploadProgress) {
|
|
196
|
+
xhr.upload.onprogress = (e) => {
|
|
197
|
+
if (e.lengthComputable && options.onUploadProgress) {
|
|
198
|
+
options.onUploadProgress({
|
|
199
|
+
loaded: e.loaded,
|
|
200
|
+
total: e.total,
|
|
201
|
+
progress: e.loaded / e.total
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
if (options.abortSignal) {
|
|
207
|
+
if (options.abortSignal.aborted) {
|
|
208
|
+
xhr.abort();
|
|
209
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
options.abortSignal.addEventListener("abort", () => {
|
|
213
|
+
xhr.abort();
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
xhr.onload = () => {
|
|
217
|
+
let data;
|
|
218
|
+
const responseContentType = xhr.getResponseHeader("content-type") || "";
|
|
219
|
+
if (xhr.status === 204) {
|
|
220
|
+
data = {};
|
|
221
|
+
} else if (responseContentType.includes("application/json")) {
|
|
222
|
+
try {
|
|
223
|
+
data = JSON.parse(xhr.responseText);
|
|
224
|
+
} catch {
|
|
225
|
+
data = xhr.responseText || {};
|
|
226
|
+
}
|
|
227
|
+
} else if (responseContentType.includes("text/")) {
|
|
228
|
+
data = xhr.responseText;
|
|
229
|
+
} else {
|
|
230
|
+
data = xhr.responseText || {};
|
|
231
|
+
}
|
|
232
|
+
if (xhr.status >= 400 && !(xhr.status in endpoint.responses)) {
|
|
233
|
+
reject(new HTTPError(xhr.status, xhr.statusText, data));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (config.validateResponse !== false) {
|
|
237
|
+
try {
|
|
238
|
+
validateResponse(endpoint, xhr.status, data);
|
|
239
|
+
} catch (err) {
|
|
240
|
+
reject(err);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
resolve({
|
|
245
|
+
status: xhr.status,
|
|
246
|
+
data
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
xhr.onerror = () => reject(new Error("Network error"));
|
|
250
|
+
xhr.onabort = () => reject(new DOMException("Aborted", "AbortError"));
|
|
251
|
+
const contentType = endpoint.contentType ?? "application/json";
|
|
252
|
+
if (options.body !== undefined) {
|
|
253
|
+
if (contentType === "multipart/form-data") {
|
|
254
|
+
xhr.send(objectToFormData(options.body));
|
|
255
|
+
} else {
|
|
256
|
+
xhr.setRequestHeader("content-type", "application/json");
|
|
257
|
+
xhr.send(JSON.stringify(options.body));
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
xhr.send();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
}
|
|
63
264
|
async function makeRequest(config, endpoint, options) {
|
|
64
265
|
if (config.validateRequest !== false) {
|
|
65
266
|
validateRequest(endpoint, options);
|
|
@@ -69,6 +270,9 @@ async function makeRequest(config, endpoint, options) {
|
|
|
69
270
|
path = interpolatePath(path, options.params);
|
|
70
271
|
}
|
|
71
272
|
const url = buildUrl(config.baseUrl, path, options.query);
|
|
273
|
+
if (options.onUploadProgress && options.body !== undefined) {
|
|
274
|
+
return makeRequestWithXHR(config, endpoint, options, url);
|
|
275
|
+
}
|
|
72
276
|
const headers = new Headers(config.headers);
|
|
73
277
|
if (options.headers) {
|
|
74
278
|
for (const [key, value] of Object.entries(options.headers)) {
|
|
@@ -121,6 +325,189 @@ async function makeRequest(config, endpoint, options) {
|
|
|
121
325
|
data
|
|
122
326
|
};
|
|
123
327
|
}
|
|
328
|
+
function createStreamingResult(response, controller) {
|
|
329
|
+
const listeners = {
|
|
330
|
+
chunk: new Set,
|
|
331
|
+
close: new Set,
|
|
332
|
+
error: new Set
|
|
333
|
+
};
|
|
334
|
+
(async () => {
|
|
335
|
+
const reader = response.body.getReader();
|
|
336
|
+
const decoder = new TextDecoder;
|
|
337
|
+
let buffer = "";
|
|
338
|
+
try {
|
|
339
|
+
while (true) {
|
|
340
|
+
const { done, value } = await reader.read();
|
|
341
|
+
if (done)
|
|
342
|
+
break;
|
|
343
|
+
buffer += decoder.decode(value, { stream: true });
|
|
344
|
+
const lines = buffer.split(`
|
|
345
|
+
`);
|
|
346
|
+
buffer = lines.pop() || "";
|
|
347
|
+
for (const line of lines) {
|
|
348
|
+
if (!line.trim())
|
|
349
|
+
continue;
|
|
350
|
+
try {
|
|
351
|
+
const parsed = JSON.parse(line);
|
|
352
|
+
if (parsed.__final__) {
|
|
353
|
+
listeners.close.forEach((h) => h(parsed.data));
|
|
354
|
+
} else {
|
|
355
|
+
listeners.chunk.forEach((h) => h(parsed));
|
|
356
|
+
}
|
|
357
|
+
} catch (parseErr) {
|
|
358
|
+
listeners.error.forEach((h) => h(parseErr));
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
if (buffer.trim()) {
|
|
363
|
+
try {
|
|
364
|
+
const parsed = JSON.parse(buffer);
|
|
365
|
+
if (parsed.__final__) {
|
|
366
|
+
listeners.close.forEach((h) => h(parsed.data));
|
|
367
|
+
} else {
|
|
368
|
+
listeners.chunk.forEach((h) => h(parsed));
|
|
369
|
+
}
|
|
370
|
+
} catch {}
|
|
371
|
+
}
|
|
372
|
+
listeners.close.forEach((h) => h());
|
|
373
|
+
} catch (err) {
|
|
374
|
+
if (err.name !== "AbortError") {
|
|
375
|
+
listeners.error.forEach((h) => h(err));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
})();
|
|
379
|
+
return {
|
|
380
|
+
on(event, handler) {
|
|
381
|
+
listeners[event].add(handler);
|
|
382
|
+
return () => listeners[event].delete(handler);
|
|
383
|
+
},
|
|
384
|
+
abort() {
|
|
385
|
+
controller.abort();
|
|
386
|
+
},
|
|
387
|
+
get aborted() {
|
|
388
|
+
return controller.signal.aborted;
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function validateStreamingRequest(endpoint, options) {
|
|
393
|
+
if (endpoint.params && options.params) {
|
|
394
|
+
const result = endpoint.params.safeParse(options.params);
|
|
395
|
+
if (!result.success) {
|
|
396
|
+
throw new ClientValidationError("params", result.error.issues);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (endpoint.query && options.query) {
|
|
400
|
+
const result = endpoint.query.safeParse(options.query);
|
|
401
|
+
if (!result.success) {
|
|
402
|
+
throw new ClientValidationError("query", result.error.issues);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
if (endpoint.headers && options.headers) {
|
|
406
|
+
const result = endpoint.headers.safeParse(options.headers);
|
|
407
|
+
if (!result.success) {
|
|
408
|
+
throw new ClientValidationError("headers", result.error.issues);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (endpoint.body && options.body) {
|
|
412
|
+
const result = endpoint.body.safeParse(options.body);
|
|
413
|
+
if (!result.success) {
|
|
414
|
+
throw new ClientValidationError("body", result.error.issues);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async function makeStreamingRequest(config, endpoint, options) {
|
|
419
|
+
if (config.validateRequest !== false) {
|
|
420
|
+
validateStreamingRequest(endpoint, options);
|
|
421
|
+
}
|
|
422
|
+
let path = endpoint.path;
|
|
423
|
+
if (options.params) {
|
|
424
|
+
path = interpolatePath(path, options.params);
|
|
425
|
+
}
|
|
426
|
+
const url = buildUrl(config.baseUrl, path, options.query);
|
|
427
|
+
const headers = new Headers(config.headers);
|
|
428
|
+
if (options.headers) {
|
|
429
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
430
|
+
headers.set(key, String(value));
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
const controller = new AbortController;
|
|
434
|
+
if (options.abortSignal) {
|
|
435
|
+
if (options.abortSignal.aborted) {
|
|
436
|
+
controller.abort();
|
|
437
|
+
} else {
|
|
438
|
+
options.abortSignal.addEventListener("abort", () => controller.abort());
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const init = {
|
|
442
|
+
method: endpoint.method,
|
|
443
|
+
headers,
|
|
444
|
+
signal: controller.signal
|
|
445
|
+
};
|
|
446
|
+
if (options.body !== undefined) {
|
|
447
|
+
const contentType = endpoint.contentType ?? "application/json";
|
|
448
|
+
if (contentType === "multipart/form-data") {
|
|
449
|
+
init.body = objectToFormData(options.body);
|
|
450
|
+
} else {
|
|
451
|
+
headers.set("content-type", "application/json");
|
|
452
|
+
init.body = JSON.stringify(options.body);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
const response = await fetch(url, init);
|
|
456
|
+
if (!response.ok) {
|
|
457
|
+
const contentType = response.headers.get("content-type") || "";
|
|
458
|
+
let data;
|
|
459
|
+
if (contentType.includes("application/json")) {
|
|
460
|
+
data = await response.json();
|
|
461
|
+
} else {
|
|
462
|
+
data = await response.text();
|
|
463
|
+
}
|
|
464
|
+
throw new HTTPError(response.status, response.statusText, data);
|
|
465
|
+
}
|
|
466
|
+
return createStreamingResult(response, controller);
|
|
467
|
+
}
|
|
468
|
+
function createSSEConnection(config, endpoint, options = {}) {
|
|
469
|
+
let path = endpoint.path;
|
|
470
|
+
if (options.params) {
|
|
471
|
+
path = interpolatePath(path, options.params);
|
|
472
|
+
}
|
|
473
|
+
const url = buildUrl(config.baseUrl, path, options.query);
|
|
474
|
+
const eventSource = new EventSource(url);
|
|
475
|
+
const listeners = {
|
|
476
|
+
error: new Set
|
|
477
|
+
};
|
|
478
|
+
const eventNames = Object.keys(endpoint.events);
|
|
479
|
+
for (const eventName of eventNames) {
|
|
480
|
+
listeners[eventName] = new Set;
|
|
481
|
+
eventSource.addEventListener(eventName, (e) => {
|
|
482
|
+
const messageEvent = e;
|
|
483
|
+
try {
|
|
484
|
+
const data = JSON.parse(messageEvent.data);
|
|
485
|
+
listeners[eventName].forEach((h) => h(data, messageEvent.lastEventId || undefined));
|
|
486
|
+
} catch (err) {
|
|
487
|
+
listeners.error.forEach((h) => h(new Error(`Failed to parse SSE data: ${err.message}`)));
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
eventSource.onerror = () => {
|
|
492
|
+
listeners.error.forEach((h) => h(new Error("SSE connection error")));
|
|
493
|
+
};
|
|
494
|
+
return {
|
|
495
|
+
on(event, handler) {
|
|
496
|
+
if (!listeners[event]) {
|
|
497
|
+
listeners[event] = new Set;
|
|
498
|
+
}
|
|
499
|
+
listeners[event].add(handler);
|
|
500
|
+
return () => listeners[event].delete(handler);
|
|
501
|
+
},
|
|
502
|
+
close() {
|
|
503
|
+
eventSource.close();
|
|
504
|
+
},
|
|
505
|
+
get state() {
|
|
506
|
+
const states = ["connecting", "open", "closed"];
|
|
507
|
+
return states[eventSource.readyState];
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
}
|
|
124
511
|
function resolveBaseUrl(baseUrl) {
|
|
125
512
|
if (baseUrl.startsWith("http://") || baseUrl.startsWith("https://")) {
|
|
126
513
|
return baseUrl;
|
|
@@ -139,9 +526,25 @@ function createClient(contract, config) {
|
|
|
139
526
|
};
|
|
140
527
|
const client = {};
|
|
141
528
|
for (const [name, endpoint] of Object.entries(contract)) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
529
|
+
if (endpoint.type === "standard") {
|
|
530
|
+
client[name] = (options = {}) => {
|
|
531
|
+
return makeRequest(resolvedConfig, endpoint, options);
|
|
532
|
+
};
|
|
533
|
+
} else if (endpoint.type === "streaming") {
|
|
534
|
+
client[name] = (options = {}) => {
|
|
535
|
+
return makeStreamingRequest(resolvedConfig, endpoint, options);
|
|
536
|
+
};
|
|
537
|
+
} else if (endpoint.type === "sse") {
|
|
538
|
+
client[name] = (options = {}) => {
|
|
539
|
+
return createSSEConnection(resolvedConfig, endpoint, options);
|
|
540
|
+
};
|
|
541
|
+
} else if (endpoint.type === "download") {
|
|
542
|
+
client[name] = (options = {}) => {
|
|
543
|
+
return makeDownloadRequest(resolvedConfig, endpoint, options);
|
|
544
|
+
};
|
|
545
|
+
} else {
|
|
546
|
+
throw new Error(`Endpoint "${name}" has unknown type "${endpoint.type}".`);
|
|
547
|
+
}
|
|
145
548
|
}
|
|
146
549
|
return client;
|
|
147
550
|
}
|
|
@@ -161,4 +564,4 @@ export {
|
|
|
161
564
|
ClientValidationError
|
|
162
565
|
};
|
|
163
566
|
|
|
164
|
-
//# debugId=
|
|
567
|
+
//# debugId=50D6CA4EBD15A65664756E2164756E21
|