@donkeylabs/adapter-sveltekit 2.0.14 → 2.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/index.d.ts +231 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +501 -0
- package/dist/generator/index.d.ts +17 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +330 -0
- package/dist/hooks/index.d.ts +53 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +96 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +51 -120
- package/dist/vite.d.ts +71 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +611 -0
- package/package.json +16 -14
- package/src/client/index.ts +0 -659
- package/src/generator/index.ts +0 -401
- package/src/hooks/index.ts +0 -124
- package/src/vite.ts +0 -729
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified API client for @donkeylabs/adapter-sveltekit
|
|
3
|
+
*
|
|
4
|
+
* Auto-detects environment:
|
|
5
|
+
* - SSR: Direct service calls through locals (no HTTP)
|
|
6
|
+
* - Browser: HTTP calls to API routes
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Type-safe SSE connection wrapper.
|
|
10
|
+
* Provides typed event handlers with automatic JSON parsing.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* // With auto-reconnect (default)
|
|
15
|
+
* const connection = api.notifications.subscribe({ userId: "123" });
|
|
16
|
+
*
|
|
17
|
+
* // Disable auto-reconnect for manual control
|
|
18
|
+
* const connection = api.notifications.subscribe({ userId: "123" }, {
|
|
19
|
+
* autoReconnect: false
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Custom reconnect delay
|
|
23
|
+
* const connection = api.notifications.subscribe({ userId: "123" }, {
|
|
24
|
+
* reconnectDelay: 5000 // 5 seconds
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* // Typed event handler - returns unsubscribe function
|
|
28
|
+
* const unsubscribe = connection.on("notification", (data) => {
|
|
29
|
+
* console.log(data.message); // Fully typed!
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Later: unsubscribe from this specific handler
|
|
33
|
+
* unsubscribe();
|
|
34
|
+
*
|
|
35
|
+
* // Close entire connection
|
|
36
|
+
* connection.close();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class SSEConnection {
|
|
40
|
+
eventSource;
|
|
41
|
+
handlers = new Map();
|
|
42
|
+
url;
|
|
43
|
+
options;
|
|
44
|
+
reconnectTimeout = null;
|
|
45
|
+
closed = false;
|
|
46
|
+
constructor(url, options = {}) {
|
|
47
|
+
this.url = url;
|
|
48
|
+
this.options = {
|
|
49
|
+
autoReconnect: true,
|
|
50
|
+
reconnectDelay: 3000,
|
|
51
|
+
...options,
|
|
52
|
+
};
|
|
53
|
+
this.eventSource = this.createEventSource();
|
|
54
|
+
}
|
|
55
|
+
createEventSource() {
|
|
56
|
+
const es = new EventSource(this.url);
|
|
57
|
+
es.onopen = () => {
|
|
58
|
+
this.options.onConnect?.();
|
|
59
|
+
};
|
|
60
|
+
es.onerror = () => {
|
|
61
|
+
// Native EventSource auto-reconnects, but we want control
|
|
62
|
+
// Close it and handle reconnection ourselves
|
|
63
|
+
if (this.options.autoReconnect && !this.closed) {
|
|
64
|
+
this.options.onDisconnect?.();
|
|
65
|
+
es.close();
|
|
66
|
+
this.scheduleReconnect();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
// Re-attach existing handlers to new EventSource
|
|
70
|
+
for (const [event] of this.handlers) {
|
|
71
|
+
es.addEventListener(event, (e) => {
|
|
72
|
+
this.dispatchEvent(event, e.data);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return es;
|
|
76
|
+
}
|
|
77
|
+
scheduleReconnect() {
|
|
78
|
+
if (this.reconnectTimeout || this.closed)
|
|
79
|
+
return;
|
|
80
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
81
|
+
this.reconnectTimeout = null;
|
|
82
|
+
if (!this.closed) {
|
|
83
|
+
this.eventSource = this.createEventSource();
|
|
84
|
+
}
|
|
85
|
+
}, this.options.reconnectDelay);
|
|
86
|
+
}
|
|
87
|
+
dispatchEvent(event, rawData) {
|
|
88
|
+
const handlers = this.handlers.get(event);
|
|
89
|
+
if (!handlers)
|
|
90
|
+
return;
|
|
91
|
+
let data;
|
|
92
|
+
try {
|
|
93
|
+
data = JSON.parse(rawData);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
data = rawData;
|
|
97
|
+
}
|
|
98
|
+
for (const h of handlers) {
|
|
99
|
+
h(data);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Register a typed event handler.
|
|
104
|
+
* @returns Unsubscribe function to remove this specific handler
|
|
105
|
+
*/
|
|
106
|
+
on(event, handler) {
|
|
107
|
+
const isNewEvent = !this.handlers.has(event);
|
|
108
|
+
if (isNewEvent) {
|
|
109
|
+
this.handlers.set(event, new Set());
|
|
110
|
+
// Add EventSource listener for this event type
|
|
111
|
+
this.eventSource?.addEventListener(event, (e) => {
|
|
112
|
+
this.dispatchEvent(event, e.data);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
this.handlers.get(event).add(handler);
|
|
116
|
+
// Return unsubscribe function
|
|
117
|
+
return () => {
|
|
118
|
+
const handlers = this.handlers.get(event);
|
|
119
|
+
if (handlers) {
|
|
120
|
+
handlers.delete(handler);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Register a typed event handler that fires only once.
|
|
126
|
+
* @returns Unsubscribe function to remove this specific handler
|
|
127
|
+
*/
|
|
128
|
+
once(event, handler) {
|
|
129
|
+
const wrappedHandler = (data) => {
|
|
130
|
+
unsubscribe();
|
|
131
|
+
handler(data);
|
|
132
|
+
};
|
|
133
|
+
const unsubscribe = this.on(event, wrappedHandler);
|
|
134
|
+
return unsubscribe;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Remove all handlers for an event.
|
|
138
|
+
*/
|
|
139
|
+
off(event) {
|
|
140
|
+
this.handlers.delete(event);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Register error handler.
|
|
144
|
+
* Note: With autoReconnect enabled, errors trigger automatic reconnection.
|
|
145
|
+
*/
|
|
146
|
+
onError(handler) {
|
|
147
|
+
const wrappedHandler = (e) => {
|
|
148
|
+
handler(e);
|
|
149
|
+
};
|
|
150
|
+
if (this.eventSource) {
|
|
151
|
+
const existingHandler = this.eventSource.onerror;
|
|
152
|
+
this.eventSource.onerror = (e) => {
|
|
153
|
+
// Call existing handler (for reconnection logic)
|
|
154
|
+
if (existingHandler)
|
|
155
|
+
existingHandler(e);
|
|
156
|
+
wrappedHandler(e);
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return () => {
|
|
160
|
+
// Can't easily remove, but handler will be replaced on reconnect
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Register open handler (connection established)
|
|
165
|
+
*/
|
|
166
|
+
onOpen(handler) {
|
|
167
|
+
if (this.eventSource) {
|
|
168
|
+
const existingHandler = this.eventSource.onopen;
|
|
169
|
+
this.eventSource.onopen = (e) => {
|
|
170
|
+
if (existingHandler)
|
|
171
|
+
existingHandler(e);
|
|
172
|
+
handler(e);
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return () => {
|
|
176
|
+
if (this.eventSource)
|
|
177
|
+
this.eventSource.onopen = null;
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Get connection state
|
|
182
|
+
*/
|
|
183
|
+
get readyState() {
|
|
184
|
+
return this.eventSource?.readyState ?? EventSource.CLOSED;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Check if connected
|
|
188
|
+
*/
|
|
189
|
+
get connected() {
|
|
190
|
+
return this.eventSource?.readyState === EventSource.OPEN;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if reconnecting
|
|
194
|
+
*/
|
|
195
|
+
get reconnecting() {
|
|
196
|
+
return this.reconnectTimeout !== null;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Close the SSE connection and stop reconnection attempts
|
|
200
|
+
*/
|
|
201
|
+
close() {
|
|
202
|
+
this.closed = true;
|
|
203
|
+
if (this.reconnectTimeout) {
|
|
204
|
+
clearTimeout(this.reconnectTimeout);
|
|
205
|
+
this.reconnectTimeout = null;
|
|
206
|
+
}
|
|
207
|
+
this.eventSource?.close();
|
|
208
|
+
this.eventSource = null;
|
|
209
|
+
this.handlers.clear();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Base class for unified API clients.
|
|
214
|
+
* Extend this class with your generated route methods.
|
|
215
|
+
*/
|
|
216
|
+
export class UnifiedApiClientBase {
|
|
217
|
+
baseUrl;
|
|
218
|
+
locals;
|
|
219
|
+
isSSR;
|
|
220
|
+
customFetch;
|
|
221
|
+
constructor(options) {
|
|
222
|
+
this.baseUrl = options?.baseUrl ?? "";
|
|
223
|
+
this.locals = options?.locals;
|
|
224
|
+
this.isSSR = typeof window === "undefined";
|
|
225
|
+
this.customFetch = options?.fetch;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Make a request to an API route.
|
|
229
|
+
* Automatically uses direct calls in SSR (when locals.handleRoute is available), HTTP otherwise.
|
|
230
|
+
*/
|
|
231
|
+
async request(route, input, options) {
|
|
232
|
+
// Use direct route handler if available (SSR with locals)
|
|
233
|
+
if (this.locals?.handleRoute) {
|
|
234
|
+
return this.locals.handleRoute(route, input);
|
|
235
|
+
}
|
|
236
|
+
// Fall back to HTTP (browser or SSR without locals)
|
|
237
|
+
return this.httpCall(route, input, options);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* HTTP call to API endpoint (browser or SSR with event.fetch).
|
|
241
|
+
*/
|
|
242
|
+
async httpCall(route, input, options) {
|
|
243
|
+
const url = `${this.baseUrl}/${route}`;
|
|
244
|
+
const fetchFn = this.customFetch ?? fetch;
|
|
245
|
+
const response = await fetchFn(url, {
|
|
246
|
+
method: "POST",
|
|
247
|
+
headers: {
|
|
248
|
+
"Content-Type": "application/json",
|
|
249
|
+
...options?.headers,
|
|
250
|
+
},
|
|
251
|
+
body: JSON.stringify(input),
|
|
252
|
+
signal: options?.signal,
|
|
253
|
+
});
|
|
254
|
+
if (!response.ok) {
|
|
255
|
+
const error = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
256
|
+
throw new Error(error.message || error.error || `HTTP ${response.status}`);
|
|
257
|
+
}
|
|
258
|
+
return response.json();
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Make a raw request (for non-JSON endpoints like streaming).
|
|
262
|
+
* Returns the raw Response object without processing.
|
|
263
|
+
*/
|
|
264
|
+
async rawRequest(route, init) {
|
|
265
|
+
const url = `${this.baseUrl}/${route}`;
|
|
266
|
+
const fetchFn = this.customFetch ?? fetch;
|
|
267
|
+
return fetchFn(url, {
|
|
268
|
+
method: "POST",
|
|
269
|
+
...init,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Make a stream request (validated input, Response output).
|
|
274
|
+
* For streaming, binary data, or custom content-type responses.
|
|
275
|
+
*
|
|
276
|
+
* By default uses POST with JSON body. For browser compatibility
|
|
277
|
+
* (video src, image src, download links), use streamUrl() instead.
|
|
278
|
+
*/
|
|
279
|
+
async streamRequest(route, input, options) {
|
|
280
|
+
const url = `${this.baseUrl}/${route}`;
|
|
281
|
+
const fetchFn = this.customFetch ?? fetch;
|
|
282
|
+
const response = await fetchFn(url, {
|
|
283
|
+
method: "POST",
|
|
284
|
+
headers: {
|
|
285
|
+
"Content-Type": "application/json",
|
|
286
|
+
...options?.headers,
|
|
287
|
+
},
|
|
288
|
+
body: JSON.stringify(input),
|
|
289
|
+
signal: options?.signal,
|
|
290
|
+
});
|
|
291
|
+
// Unlike typed requests, we return the raw Response
|
|
292
|
+
// Error handling is left to the caller
|
|
293
|
+
return response;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Get the URL for a stream endpoint (for browser src attributes).
|
|
297
|
+
* Returns a URL with query params that can be used in:
|
|
298
|
+
* - <video src={url}>
|
|
299
|
+
* - <img src={url}>
|
|
300
|
+
* - <a href={url} download>
|
|
301
|
+
* - window.open(url)
|
|
302
|
+
*/
|
|
303
|
+
streamUrl(route, input) {
|
|
304
|
+
let url = `${this.baseUrl}/${route}`;
|
|
305
|
+
if (input && typeof input === "object") {
|
|
306
|
+
const params = new URLSearchParams();
|
|
307
|
+
for (const [key, value] of Object.entries(input)) {
|
|
308
|
+
params.set(key, typeof value === "string" ? value : JSON.stringify(value));
|
|
309
|
+
}
|
|
310
|
+
url += `?${params.toString()}`;
|
|
311
|
+
}
|
|
312
|
+
return url;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Fetch a stream via GET with query params.
|
|
316
|
+
* Alternative to streamRequest() for cases where GET is preferred.
|
|
317
|
+
*/
|
|
318
|
+
async streamGet(route, input, options) {
|
|
319
|
+
const url = this.streamUrl(route, input);
|
|
320
|
+
const fetchFn = this.customFetch ?? fetch;
|
|
321
|
+
return fetchFn(url, {
|
|
322
|
+
method: "GET",
|
|
323
|
+
headers: options?.headers,
|
|
324
|
+
signal: options?.signal,
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Connect to an SSE endpoint.
|
|
329
|
+
* Returns a typed SSEConnection for handling server-sent events.
|
|
330
|
+
*/
|
|
331
|
+
sseConnect(route, input, options) {
|
|
332
|
+
let url = `${this.baseUrl}/${route}`;
|
|
333
|
+
// Add input as query params for GET request
|
|
334
|
+
if (input && typeof input === "object") {
|
|
335
|
+
const params = new URLSearchParams();
|
|
336
|
+
for (const [key, value] of Object.entries(input)) {
|
|
337
|
+
params.set(key, typeof value === "string" ? value : JSON.stringify(value));
|
|
338
|
+
}
|
|
339
|
+
url += `?${params.toString()}`;
|
|
340
|
+
}
|
|
341
|
+
return new SSEConnection(url, options);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Connect to a specific SSE route endpoint.
|
|
345
|
+
* Alias for sseConnect() - provides compatibility with @donkeylabs/server generated clients.
|
|
346
|
+
* @returns SSE connection with typed event handlers
|
|
347
|
+
*/
|
|
348
|
+
connectToSSERoute(route, input = {}, options) {
|
|
349
|
+
// Map SSEOptions to SSEConnectionOptions
|
|
350
|
+
const connectionOptions = options ? {
|
|
351
|
+
autoReconnect: options.autoReconnect,
|
|
352
|
+
reconnectDelay: options.reconnectDelay,
|
|
353
|
+
onConnect: options.onConnect,
|
|
354
|
+
onDisconnect: options.onDisconnect,
|
|
355
|
+
} : undefined;
|
|
356
|
+
return this.sseConnect(route, input, connectionOptions);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Make a formData request (file uploads with validated fields).
|
|
360
|
+
*/
|
|
361
|
+
async formDataRequest(route, fields, files, options) {
|
|
362
|
+
const url = `${this.baseUrl}/${route}`;
|
|
363
|
+
const fetchFn = this.customFetch ?? fetch;
|
|
364
|
+
const formData = new FormData();
|
|
365
|
+
// Add fields
|
|
366
|
+
if (fields && typeof fields === "object") {
|
|
367
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
368
|
+
formData.append(key, typeof value === "string" ? value : JSON.stringify(value));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// Add files
|
|
372
|
+
for (const file of files) {
|
|
373
|
+
formData.append("file", file);
|
|
374
|
+
}
|
|
375
|
+
const response = await fetchFn(url, {
|
|
376
|
+
method: "POST",
|
|
377
|
+
headers: options?.headers,
|
|
378
|
+
body: formData,
|
|
379
|
+
signal: options?.signal,
|
|
380
|
+
});
|
|
381
|
+
if (!response.ok) {
|
|
382
|
+
const error = await response.json().catch(() => ({ error: "Unknown error" }));
|
|
383
|
+
throw new Error(error.message || error.error || `HTTP ${response.status}`);
|
|
384
|
+
}
|
|
385
|
+
return response.json();
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Make an HTML request (returns HTML string).
|
|
389
|
+
*/
|
|
390
|
+
async htmlRequest(route, input, options) {
|
|
391
|
+
let url = `${this.baseUrl}/${route}`;
|
|
392
|
+
const fetchFn = this.customFetch ?? fetch;
|
|
393
|
+
// Add input as query params for GET request
|
|
394
|
+
if (input && typeof input === "object") {
|
|
395
|
+
const params = new URLSearchParams();
|
|
396
|
+
for (const [key, value] of Object.entries(input)) {
|
|
397
|
+
params.set(key, typeof value === "string" ? value : JSON.stringify(value));
|
|
398
|
+
}
|
|
399
|
+
url += `?${params.toString()}`;
|
|
400
|
+
}
|
|
401
|
+
const response = await fetchFn(url, {
|
|
402
|
+
method: "GET",
|
|
403
|
+
headers: {
|
|
404
|
+
Accept: "text/html",
|
|
405
|
+
...options?.headers,
|
|
406
|
+
},
|
|
407
|
+
signal: options?.signal,
|
|
408
|
+
});
|
|
409
|
+
if (!response.ok) {
|
|
410
|
+
throw new Error(`HTTP ${response.status}`);
|
|
411
|
+
}
|
|
412
|
+
return response.text();
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* SSE (Server-Sent Events) subscription.
|
|
416
|
+
* Only works in the browser.
|
|
417
|
+
*/
|
|
418
|
+
sse = {
|
|
419
|
+
/**
|
|
420
|
+
* Subscribe to SSE channels.
|
|
421
|
+
* Returns a function to unsubscribe.
|
|
422
|
+
*
|
|
423
|
+
* @example
|
|
424
|
+
* const unsub = api.sse.subscribe(["notifications"], (event, data) => {
|
|
425
|
+
* console.log(event, data);
|
|
426
|
+
* });
|
|
427
|
+
* // Later: unsub();
|
|
428
|
+
*/
|
|
429
|
+
subscribe: (channels, callback, options) => {
|
|
430
|
+
if (typeof window === "undefined") {
|
|
431
|
+
// SSR - return no-op
|
|
432
|
+
return () => { };
|
|
433
|
+
}
|
|
434
|
+
const url = `${this.baseUrl}/sse?channels=${channels.join(",")}`;
|
|
435
|
+
let eventSource = new EventSource(url);
|
|
436
|
+
let reconnectTimeout = null;
|
|
437
|
+
// Known event types from the server
|
|
438
|
+
const eventTypes = [
|
|
439
|
+
'cron-event', 'job-completed', 'internal-event', 'manual', 'message',
|
|
440
|
+
// Workflow events
|
|
441
|
+
'workflow.started', 'workflow.progress', 'workflow.completed',
|
|
442
|
+
'workflow.failed', 'workflow.cancelled',
|
|
443
|
+
'workflow.step.started', 'workflow.step.completed', 'workflow.step.failed',
|
|
444
|
+
];
|
|
445
|
+
const handleMessage = (e) => {
|
|
446
|
+
try {
|
|
447
|
+
const data = JSON.parse(e.data);
|
|
448
|
+
callback(e.type || "message", data);
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
callback(e.type || "message", e.data);
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
const handleError = () => {
|
|
455
|
+
if (options?.reconnect !== false && eventSource) {
|
|
456
|
+
eventSource.close();
|
|
457
|
+
reconnectTimeout = setTimeout(() => {
|
|
458
|
+
eventSource = new EventSource(url);
|
|
459
|
+
// Re-attach all listeners on reconnect
|
|
460
|
+
eventSource.onmessage = handleMessage;
|
|
461
|
+
eventSource.onerror = handleError;
|
|
462
|
+
for (const type of eventTypes) {
|
|
463
|
+
eventSource.addEventListener(type, handleMessage);
|
|
464
|
+
}
|
|
465
|
+
}, 1000);
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
// Listen for unnamed messages
|
|
469
|
+
eventSource.onmessage = handleMessage;
|
|
470
|
+
eventSource.onerror = handleError;
|
|
471
|
+
// Listen for named event types (SSE sends "event: type-name")
|
|
472
|
+
for (const type of eventTypes) {
|
|
473
|
+
eventSource.addEventListener(type, handleMessage);
|
|
474
|
+
}
|
|
475
|
+
// Return unsubscribe function
|
|
476
|
+
return () => {
|
|
477
|
+
if (reconnectTimeout) {
|
|
478
|
+
clearTimeout(reconnectTimeout);
|
|
479
|
+
}
|
|
480
|
+
if (eventSource) {
|
|
481
|
+
eventSource.close();
|
|
482
|
+
eventSource = null;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Create an API client instance.
|
|
490
|
+
* Call with locals and fetch in SSR, without in browser.
|
|
491
|
+
*
|
|
492
|
+
* @example
|
|
493
|
+
* // +page.server.ts (SSR)
|
|
494
|
+
* const api = createApiClient({ locals, fetch });
|
|
495
|
+
*
|
|
496
|
+
* // +page.svelte (browser)
|
|
497
|
+
* const api = createApiClient();
|
|
498
|
+
*/
|
|
499
|
+
export function createApiClient(ClientClass, options) {
|
|
500
|
+
return new ClientClass(options);
|
|
501
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SvelteKit-specific client generator
|
|
3
|
+
*
|
|
4
|
+
* This generator extends the core @donkeylabs/server generator
|
|
5
|
+
* to produce clients that work with both SSR (direct calls) and browser (HTTP).
|
|
6
|
+
*/
|
|
7
|
+
import { type RouteInfo, type ExtractedRoute, type ClientGeneratorOptions } from "@donkeylabs/server/generator";
|
|
8
|
+
/** SvelteKit-specific generator options */
|
|
9
|
+
export declare const svelteKitGeneratorOptions: ClientGeneratorOptions;
|
|
10
|
+
/**
|
|
11
|
+
* Generate a SvelteKit-compatible API client
|
|
12
|
+
*
|
|
13
|
+
* This is called by the donkeylabs CLI when adapter is set to "@donkeylabs/adapter-sveltekit"
|
|
14
|
+
*/
|
|
15
|
+
export declare function generateClient(_config: Record<string, unknown>, routes: RouteInfo[] | ExtractedRoute[], outputPath: string): Promise<void>;
|
|
16
|
+
export { generateClientCode, zodToTypeScript, toPascalCase, toCamelCase, type RouteInfo, type ExtractedRoute, type ClientGeneratorOptions, } from "@donkeylabs/server/generator";
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generator/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,8BAA8B,CAAC;AAetC,2CAA2C;AAC3C,eAAO,MAAM,yBAAyB,EAAE,sBAoCvC,CAAC;AAuRF;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,EAAE,SAAS,EAAE,GAAG,cAAc,EAAE,EACtC,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAgCf;AAGD,OAAO,EACL,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,WAAW,EACX,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,KAAK,sBAAsB,GAC5B,MAAM,8BAA8B,CAAC"}
|