@silverfish-app/sdk 1.0.0

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/index.cjs ADDED
@@ -0,0 +1,1130 @@
1
+ 'use strict';
2
+
3
+ // src/core/bodySerializer.gen.ts
4
+ var serializeFormDataPair = (data, key, value) => {
5
+ if (typeof value === "string" || value instanceof Blob) {
6
+ data.append(key, value);
7
+ } else if (value instanceof Date) {
8
+ data.append(key, value.toISOString());
9
+ } else {
10
+ data.append(key, JSON.stringify(value));
11
+ }
12
+ };
13
+ var formDataBodySerializer = {
14
+ bodySerializer: (body) => {
15
+ const data = new FormData();
16
+ Object.entries(body).forEach(([key, value]) => {
17
+ if (value === void 0 || value === null) {
18
+ return;
19
+ }
20
+ if (Array.isArray(value)) {
21
+ value.forEach((v) => serializeFormDataPair(data, key, v));
22
+ } else {
23
+ serializeFormDataPair(data, key, value);
24
+ }
25
+ });
26
+ return data;
27
+ }
28
+ };
29
+ var jsonBodySerializer = {
30
+ bodySerializer: (body) => JSON.stringify(body, (_key, value) => typeof value === "bigint" ? value.toString() : value)
31
+ };
32
+
33
+ // src/core/serverSentEvents.gen.ts
34
+ function createSseClient({
35
+ onRequest,
36
+ onSseError,
37
+ onSseEvent,
38
+ responseTransformer,
39
+ responseValidator,
40
+ sseDefaultRetryDelay,
41
+ sseMaxRetryAttempts,
42
+ sseMaxRetryDelay,
43
+ sseSleepFn,
44
+ url,
45
+ ...options
46
+ }) {
47
+ let lastEventId;
48
+ const sleep = sseSleepFn ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
49
+ const createStream = async function* () {
50
+ let retryDelay = sseDefaultRetryDelay ?? 3e3;
51
+ let attempt = 0;
52
+ const signal = options.signal ?? new AbortController().signal;
53
+ while (true) {
54
+ if (signal.aborted) break;
55
+ attempt++;
56
+ const headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers);
57
+ if (lastEventId !== void 0) {
58
+ headers.set("Last-Event-ID", lastEventId);
59
+ }
60
+ try {
61
+ const requestInit = {
62
+ redirect: "follow",
63
+ ...options,
64
+ body: options.serializedBody,
65
+ headers,
66
+ signal
67
+ };
68
+ let request = new Request(url, requestInit);
69
+ if (onRequest) {
70
+ request = await onRequest(url, requestInit);
71
+ }
72
+ const _fetch = options.fetch ?? globalThis.fetch;
73
+ const response = await _fetch(request);
74
+ if (!response.ok) throw new Error(`SSE failed: ${response.status} ${response.statusText}`);
75
+ if (!response.body) throw new Error("No body in SSE response");
76
+ const reader = response.body.pipeThrough(new TextDecoderStream()).getReader();
77
+ let buffer = "";
78
+ const abortHandler = () => {
79
+ try {
80
+ reader.cancel();
81
+ } catch {
82
+ }
83
+ };
84
+ signal.addEventListener("abort", abortHandler);
85
+ try {
86
+ while (true) {
87
+ const { done, value } = await reader.read();
88
+ if (done) break;
89
+ buffer += value;
90
+ buffer = buffer.replace(/\r\n?/g, "\n");
91
+ const chunks = buffer.split("\n\n");
92
+ buffer = chunks.pop() ?? "";
93
+ for (const chunk of chunks) {
94
+ const lines = chunk.split("\n");
95
+ const dataLines = [];
96
+ let eventName;
97
+ for (const line of lines) {
98
+ if (line.startsWith("data:")) {
99
+ dataLines.push(line.replace(/^data:\s*/, ""));
100
+ } else if (line.startsWith("event:")) {
101
+ eventName = line.replace(/^event:\s*/, "");
102
+ } else if (line.startsWith("id:")) {
103
+ lastEventId = line.replace(/^id:\s*/, "");
104
+ } else if (line.startsWith("retry:")) {
105
+ const parsed = Number.parseInt(line.replace(/^retry:\s*/, ""), 10);
106
+ if (!Number.isNaN(parsed)) {
107
+ retryDelay = parsed;
108
+ }
109
+ }
110
+ }
111
+ let data;
112
+ let parsedJson = false;
113
+ if (dataLines.length) {
114
+ const rawData = dataLines.join("\n");
115
+ try {
116
+ data = JSON.parse(rawData);
117
+ parsedJson = true;
118
+ } catch {
119
+ data = rawData;
120
+ }
121
+ }
122
+ if (parsedJson) {
123
+ if (responseValidator) {
124
+ await responseValidator(data);
125
+ }
126
+ if (responseTransformer) {
127
+ data = await responseTransformer(data);
128
+ }
129
+ }
130
+ onSseEvent?.({
131
+ data,
132
+ event: eventName,
133
+ id: lastEventId,
134
+ retry: retryDelay
135
+ });
136
+ if (dataLines.length) {
137
+ yield data;
138
+ }
139
+ }
140
+ }
141
+ } finally {
142
+ signal.removeEventListener("abort", abortHandler);
143
+ reader.releaseLock();
144
+ }
145
+ break;
146
+ } catch (error) {
147
+ onSseError?.(error);
148
+ if (sseMaxRetryAttempts !== void 0 && attempt >= sseMaxRetryAttempts) {
149
+ break;
150
+ }
151
+ const backoff = Math.min(retryDelay * 2 ** (attempt - 1), sseMaxRetryDelay ?? 3e4);
152
+ await sleep(backoff);
153
+ }
154
+ }
155
+ };
156
+ const stream = createStream();
157
+ return { stream };
158
+ }
159
+
160
+ // src/core/pathSerializer.gen.ts
161
+ var separatorArrayExplode = (style) => {
162
+ switch (style) {
163
+ case "label":
164
+ return ".";
165
+ case "matrix":
166
+ return ";";
167
+ case "simple":
168
+ return ",";
169
+ default:
170
+ return "&";
171
+ }
172
+ };
173
+ var separatorArrayNoExplode = (style) => {
174
+ switch (style) {
175
+ case "form":
176
+ return ",";
177
+ case "pipeDelimited":
178
+ return "|";
179
+ case "spaceDelimited":
180
+ return "%20";
181
+ default:
182
+ return ",";
183
+ }
184
+ };
185
+ var separatorObjectExplode = (style) => {
186
+ switch (style) {
187
+ case "label":
188
+ return ".";
189
+ case "matrix":
190
+ return ";";
191
+ case "simple":
192
+ return ",";
193
+ default:
194
+ return "&";
195
+ }
196
+ };
197
+ var serializeArrayParam = ({
198
+ allowReserved,
199
+ explode,
200
+ name,
201
+ style,
202
+ value
203
+ }) => {
204
+ if (!explode) {
205
+ const joinedValues2 = (allowReserved ? value : value.map((v) => encodeURIComponent(v))).join(separatorArrayNoExplode(style));
206
+ switch (style) {
207
+ case "label":
208
+ return `.${joinedValues2}`;
209
+ case "matrix":
210
+ return `;${name}=${joinedValues2}`;
211
+ case "simple":
212
+ return joinedValues2;
213
+ default:
214
+ return `${name}=${joinedValues2}`;
215
+ }
216
+ }
217
+ const separator = separatorArrayExplode(style);
218
+ const joinedValues = value.map((v) => {
219
+ if (style === "label" || style === "simple") {
220
+ return allowReserved ? v : encodeURIComponent(v);
221
+ }
222
+ return serializePrimitiveParam({
223
+ allowReserved,
224
+ name,
225
+ value: v
226
+ });
227
+ }).join(separator);
228
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
229
+ };
230
+ var serializePrimitiveParam = ({
231
+ allowReserved,
232
+ name,
233
+ value
234
+ }) => {
235
+ if (value === void 0 || value === null) {
236
+ return "";
237
+ }
238
+ if (typeof value === "object") {
239
+ throw new Error(
240
+ "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
241
+ );
242
+ }
243
+ return `${name}=${allowReserved ? value : encodeURIComponent(value)}`;
244
+ };
245
+ var serializeObjectParam = ({
246
+ allowReserved,
247
+ explode,
248
+ name,
249
+ style,
250
+ value,
251
+ valueOnly
252
+ }) => {
253
+ if (value instanceof Date) {
254
+ return valueOnly ? value.toISOString() : `${name}=${value.toISOString()}`;
255
+ }
256
+ if (style !== "deepObject" && !explode) {
257
+ let values = [];
258
+ Object.entries(value).forEach(([key, v]) => {
259
+ values = [...values, key, allowReserved ? v : encodeURIComponent(v)];
260
+ });
261
+ const joinedValues2 = values.join(",");
262
+ switch (style) {
263
+ case "form":
264
+ return `${name}=${joinedValues2}`;
265
+ case "label":
266
+ return `.${joinedValues2}`;
267
+ case "matrix":
268
+ return `;${name}=${joinedValues2}`;
269
+ default:
270
+ return joinedValues2;
271
+ }
272
+ }
273
+ const separator = separatorObjectExplode(style);
274
+ const joinedValues = Object.entries(value).map(
275
+ ([key, v]) => serializePrimitiveParam({
276
+ allowReserved,
277
+ name: style === "deepObject" ? `${name}[${key}]` : key,
278
+ value: v
279
+ })
280
+ ).join(separator);
281
+ return style === "label" || style === "matrix" ? separator + joinedValues : joinedValues;
282
+ };
283
+
284
+ // src/core/utils.gen.ts
285
+ var PATH_PARAM_RE = /\{[^{}]+\}/g;
286
+ var defaultPathSerializer = ({ path, url: _url }) => {
287
+ let url = _url;
288
+ const matches = _url.match(PATH_PARAM_RE);
289
+ if (matches) {
290
+ for (const match of matches) {
291
+ let explode = false;
292
+ let name = match.substring(1, match.length - 1);
293
+ let style = "simple";
294
+ if (name.endsWith("*")) {
295
+ explode = true;
296
+ name = name.substring(0, name.length - 1);
297
+ }
298
+ if (name.startsWith(".")) {
299
+ name = name.substring(1);
300
+ style = "label";
301
+ } else if (name.startsWith(";")) {
302
+ name = name.substring(1);
303
+ style = "matrix";
304
+ }
305
+ const value = path[name];
306
+ if (value === void 0 || value === null) {
307
+ continue;
308
+ }
309
+ if (Array.isArray(value)) {
310
+ url = url.replace(match, serializeArrayParam({ explode, name, style, value }));
311
+ continue;
312
+ }
313
+ if (typeof value === "object") {
314
+ url = url.replace(
315
+ match,
316
+ serializeObjectParam({
317
+ explode,
318
+ name,
319
+ style,
320
+ value,
321
+ valueOnly: true
322
+ })
323
+ );
324
+ continue;
325
+ }
326
+ if (style === "matrix") {
327
+ url = url.replace(
328
+ match,
329
+ `;${serializePrimitiveParam({
330
+ name,
331
+ value
332
+ })}`
333
+ );
334
+ continue;
335
+ }
336
+ const replaceValue = encodeURIComponent(
337
+ style === "label" ? `.${value}` : value
338
+ );
339
+ url = url.replace(match, replaceValue);
340
+ }
341
+ }
342
+ return url;
343
+ };
344
+ var getUrl = ({
345
+ baseUrl,
346
+ path,
347
+ query,
348
+ querySerializer,
349
+ url: _url
350
+ }) => {
351
+ const pathUrl = _url.startsWith("/") ? _url : `/${_url}`;
352
+ let url = (baseUrl ?? "") + pathUrl;
353
+ if (path) {
354
+ url = defaultPathSerializer({ path, url });
355
+ }
356
+ let search = query ? querySerializer(query) : "";
357
+ if (search.startsWith("?")) {
358
+ search = search.substring(1);
359
+ }
360
+ if (search) {
361
+ url += `?${search}`;
362
+ }
363
+ return url;
364
+ };
365
+ function getValidRequestBody(options) {
366
+ const hasBody = options.body !== void 0;
367
+ const isSerializedBody = hasBody && options.bodySerializer;
368
+ if (isSerializedBody) {
369
+ if ("serializedBody" in options) {
370
+ const hasSerializedBody = options.serializedBody !== void 0 && options.serializedBody !== "";
371
+ return hasSerializedBody ? options.serializedBody : null;
372
+ }
373
+ return options.body !== "" ? options.body : null;
374
+ }
375
+ if (hasBody) {
376
+ return options.body;
377
+ }
378
+ return void 0;
379
+ }
380
+
381
+ // src/core/auth.gen.ts
382
+ var getAuthToken = async (auth, callback) => {
383
+ const token = typeof callback === "function" ? await callback(auth) : callback;
384
+ if (!token) {
385
+ return;
386
+ }
387
+ if (auth.scheme === "bearer") {
388
+ return `Bearer ${token}`;
389
+ }
390
+ if (auth.scheme === "basic") {
391
+ return `Basic ${btoa(token)}`;
392
+ }
393
+ return token;
394
+ };
395
+
396
+ // src/client/utils.gen.ts
397
+ var createQuerySerializer = ({
398
+ parameters = {},
399
+ ...args
400
+ } = {}) => {
401
+ const querySerializer = (queryParams) => {
402
+ const search = [];
403
+ if (queryParams && typeof queryParams === "object") {
404
+ for (const name in queryParams) {
405
+ const value = queryParams[name];
406
+ if (value === void 0 || value === null) {
407
+ continue;
408
+ }
409
+ const options = parameters[name] || args;
410
+ if (Array.isArray(value)) {
411
+ const serializedArray = serializeArrayParam({
412
+ allowReserved: options.allowReserved,
413
+ explode: true,
414
+ name,
415
+ style: "form",
416
+ value,
417
+ ...options.array
418
+ });
419
+ if (serializedArray) search.push(serializedArray);
420
+ } else if (typeof value === "object") {
421
+ const serializedObject = serializeObjectParam({
422
+ allowReserved: options.allowReserved,
423
+ explode: true,
424
+ name,
425
+ style: "deepObject",
426
+ value,
427
+ ...options.object
428
+ });
429
+ if (serializedObject) search.push(serializedObject);
430
+ } else {
431
+ const serializedPrimitive = serializePrimitiveParam({
432
+ allowReserved: options.allowReserved,
433
+ name,
434
+ value
435
+ });
436
+ if (serializedPrimitive) search.push(serializedPrimitive);
437
+ }
438
+ }
439
+ }
440
+ return search.join("&");
441
+ };
442
+ return querySerializer;
443
+ };
444
+ var getParseAs = (contentType) => {
445
+ if (!contentType) {
446
+ return "stream";
447
+ }
448
+ const cleanContent = contentType.split(";")[0]?.trim();
449
+ if (!cleanContent) {
450
+ return;
451
+ }
452
+ if (cleanContent.startsWith("application/json") || cleanContent.endsWith("+json")) {
453
+ return "json";
454
+ }
455
+ if (cleanContent === "multipart/form-data") {
456
+ return "formData";
457
+ }
458
+ if (["application/", "audio/", "image/", "video/"].some((type) => cleanContent.startsWith(type))) {
459
+ return "blob";
460
+ }
461
+ if (cleanContent.startsWith("text/")) {
462
+ return "text";
463
+ }
464
+ return;
465
+ };
466
+ var checkForExistence = (options, name) => {
467
+ if (!name) {
468
+ return false;
469
+ }
470
+ if (options.headers.has(name) || options.query?.[name] || options.headers.get("Cookie")?.includes(`${name}=`)) {
471
+ return true;
472
+ }
473
+ return false;
474
+ };
475
+ async function setAuthParams(options) {
476
+ for (const auth of options.security ?? []) {
477
+ if (checkForExistence(options, auth.name)) {
478
+ continue;
479
+ }
480
+ const token = await getAuthToken(auth, options.auth);
481
+ if (!token) {
482
+ continue;
483
+ }
484
+ const name = auth.name ?? "Authorization";
485
+ switch (auth.in) {
486
+ case "query":
487
+ if (!options.query) {
488
+ options.query = {};
489
+ }
490
+ options.query[name] = token;
491
+ break;
492
+ case "cookie":
493
+ options.headers.append("Cookie", `${name}=${token}`);
494
+ break;
495
+ case "header":
496
+ default:
497
+ options.headers.set(name, token);
498
+ break;
499
+ }
500
+ }
501
+ }
502
+ var buildUrl = (options) => getUrl({
503
+ baseUrl: options.baseUrl,
504
+ path: options.path,
505
+ query: options.query,
506
+ querySerializer: typeof options.querySerializer === "function" ? options.querySerializer : createQuerySerializer(options.querySerializer),
507
+ url: options.url
508
+ });
509
+ var mergeConfigs = (a, b) => {
510
+ const config = { ...a, ...b };
511
+ if (config.baseUrl?.endsWith("/")) {
512
+ config.baseUrl = config.baseUrl.substring(0, config.baseUrl.length - 1);
513
+ }
514
+ config.headers = mergeHeaders(a.headers, b.headers);
515
+ return config;
516
+ };
517
+ var headersEntries = (headers) => {
518
+ const entries = [];
519
+ headers.forEach((value, key) => {
520
+ entries.push([key, value]);
521
+ });
522
+ return entries;
523
+ };
524
+ var mergeHeaders = (...headers) => {
525
+ const mergedHeaders = new Headers();
526
+ for (const header of headers) {
527
+ if (!header) {
528
+ continue;
529
+ }
530
+ const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
531
+ for (const [key, value] of iterator) {
532
+ if (value === null) {
533
+ mergedHeaders.delete(key);
534
+ } else if (Array.isArray(value)) {
535
+ for (const v of value) {
536
+ mergedHeaders.append(key, v);
537
+ }
538
+ } else if (value !== void 0) {
539
+ mergedHeaders.set(
540
+ key,
541
+ typeof value === "object" ? JSON.stringify(value) : value
542
+ );
543
+ }
544
+ }
545
+ }
546
+ return mergedHeaders;
547
+ };
548
+ var Interceptors = class {
549
+ fns = [];
550
+ clear() {
551
+ this.fns = [];
552
+ }
553
+ eject(id) {
554
+ const index = this.getInterceptorIndex(id);
555
+ if (this.fns[index]) {
556
+ this.fns[index] = null;
557
+ }
558
+ }
559
+ exists(id) {
560
+ const index = this.getInterceptorIndex(id);
561
+ return Boolean(this.fns[index]);
562
+ }
563
+ getInterceptorIndex(id) {
564
+ if (typeof id === "number") {
565
+ return this.fns[id] ? id : -1;
566
+ }
567
+ return this.fns.indexOf(id);
568
+ }
569
+ update(id, fn) {
570
+ const index = this.getInterceptorIndex(id);
571
+ if (this.fns[index]) {
572
+ this.fns[index] = fn;
573
+ return id;
574
+ }
575
+ return false;
576
+ }
577
+ use(fn) {
578
+ this.fns.push(fn);
579
+ return this.fns.length - 1;
580
+ }
581
+ };
582
+ var createInterceptors = () => ({
583
+ error: new Interceptors(),
584
+ request: new Interceptors(),
585
+ response: new Interceptors()
586
+ });
587
+ var defaultQuerySerializer = createQuerySerializer({
588
+ allowReserved: false,
589
+ array: {
590
+ explode: true,
591
+ style: "form"
592
+ },
593
+ object: {
594
+ explode: true,
595
+ style: "deepObject"
596
+ }
597
+ });
598
+ var defaultHeaders = {
599
+ "Content-Type": "application/json"
600
+ };
601
+ var createConfig = (override = {}) => ({
602
+ ...jsonBodySerializer,
603
+ headers: defaultHeaders,
604
+ parseAs: "auto",
605
+ querySerializer: defaultQuerySerializer,
606
+ ...override
607
+ });
608
+
609
+ // src/client/client.gen.ts
610
+ var createClient = (config = {}) => {
611
+ let _config = mergeConfigs(createConfig(), config);
612
+ const getConfig = () => ({ ..._config });
613
+ const setConfig = (config2) => {
614
+ _config = mergeConfigs(_config, config2);
615
+ return getConfig();
616
+ };
617
+ const interceptors = createInterceptors();
618
+ const beforeRequest = async (options) => {
619
+ const opts = {
620
+ ..._config,
621
+ ...options,
622
+ fetch: options.fetch ?? _config.fetch ?? globalThis.fetch,
623
+ headers: mergeHeaders(_config.headers, options.headers),
624
+ serializedBody: void 0
625
+ };
626
+ if (opts.security) {
627
+ await setAuthParams(opts);
628
+ }
629
+ if (opts.requestValidator) {
630
+ await opts.requestValidator(opts);
631
+ }
632
+ if (opts.body !== void 0 && opts.bodySerializer) {
633
+ opts.serializedBody = opts.bodySerializer(opts.body);
634
+ }
635
+ if (opts.body === void 0 || opts.serializedBody === "") {
636
+ opts.headers.delete("Content-Type");
637
+ }
638
+ const resolvedOpts = opts;
639
+ const url = buildUrl(resolvedOpts);
640
+ return { opts: resolvedOpts, url };
641
+ };
642
+ const request = async (options) => {
643
+ const throwOnError = options.throwOnError ?? _config.throwOnError;
644
+ const responseStyle = options.responseStyle ?? _config.responseStyle;
645
+ let request2;
646
+ let response;
647
+ try {
648
+ const { opts, url } = await beforeRequest(options);
649
+ const requestInit = {
650
+ redirect: "follow",
651
+ ...opts,
652
+ body: getValidRequestBody(opts)
653
+ };
654
+ request2 = new Request(url, requestInit);
655
+ for (const fn of interceptors.request.fns) {
656
+ if (fn) {
657
+ request2 = await fn(request2, opts);
658
+ }
659
+ }
660
+ const _fetch = opts.fetch;
661
+ response = await _fetch(request2);
662
+ for (const fn of interceptors.response.fns) {
663
+ if (fn) {
664
+ response = await fn(response, request2, opts);
665
+ }
666
+ }
667
+ const result = {
668
+ request: request2,
669
+ response
670
+ };
671
+ if (response.ok) {
672
+ const parseAs = (opts.parseAs === "auto" ? getParseAs(response.headers.get("Content-Type")) : opts.parseAs) ?? "json";
673
+ if (response.status === 204 || response.headers.get("Content-Length") === "0") {
674
+ let emptyData;
675
+ switch (parseAs) {
676
+ case "arrayBuffer":
677
+ case "blob":
678
+ case "text":
679
+ emptyData = await response[parseAs]();
680
+ break;
681
+ case "formData":
682
+ emptyData = new FormData();
683
+ break;
684
+ case "stream":
685
+ emptyData = response.body;
686
+ break;
687
+ case "json":
688
+ default:
689
+ emptyData = {};
690
+ break;
691
+ }
692
+ return opts.responseStyle === "data" ? emptyData : {
693
+ data: emptyData,
694
+ ...result
695
+ };
696
+ }
697
+ let data;
698
+ switch (parseAs) {
699
+ case "arrayBuffer":
700
+ case "blob":
701
+ case "formData":
702
+ case "text":
703
+ data = await response[parseAs]();
704
+ break;
705
+ case "json": {
706
+ const text = await response.text();
707
+ data = text ? JSON.parse(text) : {};
708
+ break;
709
+ }
710
+ case "stream":
711
+ return opts.responseStyle === "data" ? response.body : {
712
+ data: response.body,
713
+ ...result
714
+ };
715
+ }
716
+ if (parseAs === "json") {
717
+ if (opts.responseValidator) {
718
+ await opts.responseValidator(data);
719
+ }
720
+ if (opts.responseTransformer) {
721
+ data = await opts.responseTransformer(data);
722
+ }
723
+ }
724
+ return opts.responseStyle === "data" ? data : {
725
+ data,
726
+ ...result
727
+ };
728
+ }
729
+ const textError = await response.text();
730
+ let jsonError;
731
+ try {
732
+ jsonError = JSON.parse(textError);
733
+ } catch {
734
+ }
735
+ throw jsonError ?? textError;
736
+ } catch (error) {
737
+ let finalError = error;
738
+ for (const fn of interceptors.error.fns) {
739
+ if (fn) {
740
+ finalError = await fn(finalError, response, request2, options);
741
+ }
742
+ }
743
+ finalError = finalError || {};
744
+ if (throwOnError) {
745
+ throw finalError;
746
+ }
747
+ return responseStyle === "data" ? void 0 : {
748
+ error: finalError,
749
+ request: request2,
750
+ response
751
+ };
752
+ }
753
+ };
754
+ const makeMethodFn = (method) => (options) => request({ ...options, method });
755
+ const makeSseFn = (method) => async (options) => {
756
+ const { opts, url } = await beforeRequest(options);
757
+ return createSseClient({
758
+ ...opts,
759
+ body: opts.body,
760
+ method,
761
+ onRequest: async (url2, init) => {
762
+ let request2 = new Request(url2, init);
763
+ for (const fn of interceptors.request.fns) {
764
+ if (fn) {
765
+ request2 = await fn(request2, opts);
766
+ }
767
+ }
768
+ return request2;
769
+ },
770
+ serializedBody: getValidRequestBody(opts),
771
+ url
772
+ });
773
+ };
774
+ const _buildUrl = (options) => buildUrl({ ..._config, ...options });
775
+ return {
776
+ buildUrl: _buildUrl,
777
+ connect: makeMethodFn("CONNECT"),
778
+ delete: makeMethodFn("DELETE"),
779
+ get: makeMethodFn("GET"),
780
+ getConfig,
781
+ head: makeMethodFn("HEAD"),
782
+ interceptors,
783
+ options: makeMethodFn("OPTIONS"),
784
+ patch: makeMethodFn("PATCH"),
785
+ post: makeMethodFn("POST"),
786
+ put: makeMethodFn("PUT"),
787
+ request,
788
+ setConfig,
789
+ sse: {
790
+ connect: makeSseFn("CONNECT"),
791
+ delete: makeSseFn("DELETE"),
792
+ get: makeSseFn("GET"),
793
+ head: makeSseFn("HEAD"),
794
+ options: makeSseFn("OPTIONS"),
795
+ patch: makeSseFn("PATCH"),
796
+ post: makeSseFn("POST"),
797
+ put: makeSseFn("PUT"),
798
+ trace: makeSseFn("TRACE")
799
+ },
800
+ trace: makeMethodFn("TRACE")
801
+ };
802
+ };
803
+
804
+ // src/client.gen.ts
805
+ var client = createClient(createConfig());
806
+
807
+ // src/sdk.gen.ts
808
+ var HeyApiClient = class {
809
+ client;
810
+ constructor(args) {
811
+ this.client = args?.client ?? client;
812
+ }
813
+ };
814
+ var HeyApiRegistry = class {
815
+ defaultKey = "default";
816
+ instances = /* @__PURE__ */ new Map();
817
+ get(key) {
818
+ const instance = this.instances.get(key ?? this.defaultKey);
819
+ if (!instance) {
820
+ throw new Error(`No SDK client found. Create one with "new Sdk()" to fix this error.`);
821
+ }
822
+ return instance;
823
+ }
824
+ set(value, key) {
825
+ this.instances.set(key ?? this.defaultKey, value);
826
+ }
827
+ };
828
+ var Sdk = class _Sdk extends HeyApiClient {
829
+ static __registry = new HeyApiRegistry();
830
+ constructor(args) {
831
+ super(args);
832
+ _Sdk.__registry.set(this, args?.key);
833
+ }
834
+ /**
835
+ * List Books
836
+ *
837
+ * List books, paginated and sorted.
838
+ *
839
+ * Returns a page of books controlled by `page` and `page_size`, ordered by
840
+ * `sort` field in the given `direction`. Out-of-range pagination values are
841
+ * rejected with `422`.
842
+ */
843
+ listBooks(options) {
844
+ return (options?.client ?? this.client).get({ url: "/books", ...options });
845
+ }
846
+ /**
847
+ * Upload Book
848
+ *
849
+ * Upload a book file and create a new book.
850
+ *
851
+ * Accepts a multipart `file` whose extension must be one of the allowed
852
+ * upload formats; metadata is extracted from the file on import. Returns the
853
+ * created book with `201`, `400` if the file is rejected (unsupported
854
+ * extension or unreadable content), or `413` if it exceeds the upload size
855
+ * limit.
856
+ */
857
+ uploadBook(options) {
858
+ return (options.client ?? this.client).post({
859
+ ...formDataBodySerializer,
860
+ url: "/books",
861
+ ...options,
862
+ headers: {
863
+ "Content-Type": null,
864
+ ...options.headers
865
+ }
866
+ });
867
+ }
868
+ /**
869
+ * Delete Book
870
+ *
871
+ * Delete a book and all of its files.
872
+ *
873
+ * Removes the book identified by `book_id` along with its stored formats and
874
+ * cover, returning `204` with no body on success. Responds with `404` when the
875
+ * book does not exist.
876
+ */
877
+ deleteBook(options) {
878
+ return (options.client ?? this.client).delete({ url: "/books/{book_id}", ...options });
879
+ }
880
+ /**
881
+ * Get Book
882
+ *
883
+ * Get a single book by its public id.
884
+ *
885
+ * Looks up the book identified by `book_id` (the book's public id) and returns
886
+ * its full metadata. Responds with `404` when no such book exists.
887
+ */
888
+ getBook(options) {
889
+ return (options.client ?? this.client).get({ url: "/books/{book_id}", ...options });
890
+ }
891
+ /**
892
+ * Update Book
893
+ *
894
+ * Partially update a book's metadata.
895
+ *
896
+ * Applies only the fields explicitly set in the request body, leaving omitted
897
+ * fields untouched, and returns the updated book. Responds with `400` when the
898
+ * patch is empty or violates a domain rule (e.g. an out-of-range `rating`),
899
+ * and `404` when the book does not exist.
900
+ */
901
+ updateBook(options) {
902
+ return (options.client ?? this.client).patch({
903
+ url: "/books/{book_id}",
904
+ ...options,
905
+ headers: {
906
+ "Content-Type": "application/json",
907
+ ...options.headers
908
+ }
909
+ });
910
+ }
911
+ /**
912
+ * Convert Book
913
+ *
914
+ * Convert a book to another format.
915
+ *
916
+ * Enqueues a background conversion to `target_format`, optionally from an
917
+ * explicit `source_format` (otherwise the best available source is chosen), and
918
+ * returns `202` with a job to poll at `/jobs/{id}`. Responds with `404` if the
919
+ * book is missing, `503` if `ebook-convert` is unavailable, `409` if the target
920
+ * format already exists or an identical conversion is already in progress, and
921
+ * `400` if no suitable source format is available.
922
+ */
923
+ convertBook(options) {
924
+ return (options.client ?? this.client).post({
925
+ url: "/books/{book_id}/convert",
926
+ ...options,
927
+ headers: {
928
+ "Content-Type": "application/json",
929
+ ...options.headers
930
+ }
931
+ });
932
+ }
933
+ /**
934
+ * Get Book Cover
935
+ *
936
+ * Download a book's cover image.
937
+ *
938
+ * Returns the cover bytes as `image/jpeg` for the book identified by
939
+ * `book_id`. Responds with `404` when the book has no recorded cover or the
940
+ * cover file is missing from storage.
941
+ */
942
+ getBookCover(options) {
943
+ return (options.client ?? this.client).get({ url: "/books/{book_id}/cover", ...options });
944
+ }
945
+ /**
946
+ * Delete Book Format
947
+ *
948
+ * Delete one format of a book.
949
+ *
950
+ * Removes the file for the given `book_format` of the book identified by
951
+ * `book_id`, returning `204` with no body on success. Responds with `404` when
952
+ * the book does not exist or it has no such format.
953
+ */
954
+ deleteBookFormat(options) {
955
+ return (options.client ?? this.client).delete({ url: "/books/{book_id}/formats/{book_format}", ...options });
956
+ }
957
+ /**
958
+ * Download Book Format
959
+ *
960
+ * Download one format of a book.
961
+ *
962
+ * Returns the file for the given `book_format` of the book identified by
963
+ * `book_id` as an `application/octet-stream` attachment, with the stored
964
+ * filename in the `Content-Disposition` header. Responds with `404` when the
965
+ * book lacks that format or the file is missing from storage.
966
+ */
967
+ downloadBookFormat(options) {
968
+ return (options.client ?? this.client).get({ url: "/books/{book_id}/formats/{book_format}", ...options });
969
+ }
970
+ /**
971
+ * Refresh Metadata
972
+ *
973
+ * Re-extract metadata from a book file and return the updated book.
974
+ *
975
+ * Reads metadata afresh from the book's `source_format` file and merges it in:
976
+ * fields the extraction produced replace the current ones, fields it could not
977
+ * read are kept. Responds with `404` when the book or requested format is not
978
+ * found, and `400` for any other refresh failure.
979
+ */
980
+ refreshMetadata(options) {
981
+ return (options.client ?? this.client).post({
982
+ url: "/books/{book_id}/refresh-metadata",
983
+ ...options,
984
+ headers: {
985
+ "Content-Type": "application/json",
986
+ ...options.headers
987
+ }
988
+ });
989
+ }
990
+ /**
991
+ * Send Book
992
+ *
993
+ * Email a book to a recipient.
994
+ *
995
+ * Enqueues a background job to send the book to `to_email` in the requested
996
+ * `format` (or the best available sendable format if unspecified), and returns
997
+ * `202` with a job to poll at `/jobs/{id}`. Responds with `404` if the book is
998
+ * missing, `503` if SMTP is not configured, and `400` if the book has no
999
+ * matching or sendable format.
1000
+ */
1001
+ sendBook(options) {
1002
+ return (options.client ?? this.client).post({
1003
+ url: "/books/{book_id}/send",
1004
+ ...options,
1005
+ headers: {
1006
+ "Content-Type": "application/json",
1007
+ ...options.headers
1008
+ }
1009
+ });
1010
+ }
1011
+ /**
1012
+ * Get Email Config
1013
+ *
1014
+ * Return the non-secret SMTP settings for display.
1015
+ *
1016
+ * Reports whether SMTP is `configured` along with `host`, `port`,
1017
+ * `from_address` (falling back to the username when no explicit from is set)
1018
+ * and `security`. The password is never read or returned.
1019
+ */
1020
+ getEmailConfig(options) {
1021
+ return (options?.client ?? this.client).get({ url: "/config/email", ...options });
1022
+ }
1023
+ /**
1024
+ * Test Email Config
1025
+ *
1026
+ * Send a test email to verify SMTP connectivity.
1027
+ *
1028
+ * Sends a test message to `to_email` and returns 204 on success. Responds 503
1029
+ * if SMTP is not configured, or 502 if the connection, authentication or send
1030
+ * fails.
1031
+ */
1032
+ testEmailConfig(options) {
1033
+ return (options.client ?? this.client).post({
1034
+ url: "/config/email/test",
1035
+ ...options,
1036
+ headers: {
1037
+ "Content-Type": "application/json",
1038
+ ...options.headers
1039
+ }
1040
+ });
1041
+ }
1042
+ /**
1043
+ * Start Export
1044
+ *
1045
+ * Start an async Calibre export; the download link is emailed when ready.
1046
+ *
1047
+ * Enqueues a background job that snapshots the requested books (or the whole
1048
+ * library when `book_ids` is omitted) to a zip and emails a time-limited link
1049
+ * to `to_email`, returning 202 with the new job. Responds 503 when export is
1050
+ * unavailable (the calibredb binary is missing, SMTP is not configured, or no
1051
+ * public base URL is set for an absolute link), and 400 for a malformed book id.
1052
+ */
1053
+ startExport(options) {
1054
+ return (options.client ?? this.client).post({
1055
+ url: "/export/calibre",
1056
+ ...options,
1057
+ headers: {
1058
+ "Content-Type": "application/json",
1059
+ ...options.headers
1060
+ }
1061
+ });
1062
+ }
1063
+ /**
1064
+ * Download Export
1065
+ *
1066
+ * Stream a finished export zip for a valid, unexpired token.
1067
+ *
1068
+ * Served via ``FileResponse``, which streams the file and honours HTTP Range
1069
+ * requests, so a large download is memory-light and resumable.
1070
+ */
1071
+ downloadExport(options) {
1072
+ return (options.client ?? this.client).get({ url: "/export/download/{token}", ...options });
1073
+ }
1074
+ /**
1075
+ * Health
1076
+ *
1077
+ * Report liveness and the availability of optional dependencies.
1078
+ *
1079
+ * Always returns `status` ``"ok"`` and the API `version`, plus the
1080
+ * Calibre binary availability (`convert_available`, `metadata_available`)
1081
+ * and whether send-to-ereader is usable (`send_available`, true when SMTP
1082
+ * is configured).
1083
+ */
1084
+ health(options) {
1085
+ return (options?.client ?? this.client).get({ url: "/health", ...options });
1086
+ }
1087
+ /**
1088
+ * Get Job
1089
+ *
1090
+ * Return the current status and progress of a single job.
1091
+ *
1092
+ * Looks up the job by `job_id` and returns its latest state for one-shot
1093
+ * polling. Responds 404 if no job with that id exists; use `/jobs/{job_id}/stream`
1094
+ * instead to follow progress live.
1095
+ */
1096
+ getJob(options) {
1097
+ return (options.client ?? this.client).get({ url: "/jobs/{job_id}", ...options });
1098
+ }
1099
+ /**
1100
+ * Stream Job
1101
+ *
1102
+ * Stream a job's status/progress as Server-Sent Events until it finishes.
1103
+ *
1104
+ * One open connection replaces repeated polling. Updates are event-driven: the
1105
+ * stream blocks (in a threadpool, so the event loop stays free) until the job
1106
+ * actually changes, then emits — so it reflects each new binary output, not a
1107
+ * fixed tick.
1108
+ */
1109
+ streamJob(options) {
1110
+ return (options.client ?? this.client).get({ url: "/jobs/{job_id}/stream", ...options });
1111
+ }
1112
+ /**
1113
+ * Search Books
1114
+ *
1115
+ * Search books by a text query and filters.
1116
+ *
1117
+ * Returns a paginated page of books whose title, author, series or tags match
1118
+ * the query `q` (case-insensitive substring match), narrowed by the optional
1119
+ * `include_tags`, `exclude_tags`, `languages`, `formats`, and
1120
+ * `rating_min`/`rating_max` filters. Out-of-range pagination or rating values
1121
+ * are rejected with `422`.
1122
+ */
1123
+ searchBooks(options) {
1124
+ return (options?.client ?? this.client).get({ url: "/search", ...options });
1125
+ }
1126
+ };
1127
+
1128
+ exports.Sdk = Sdk;
1129
+ //# sourceMappingURL=index.cjs.map
1130
+ //# sourceMappingURL=index.cjs.map