jiren 3.1.0 → 3.2.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.
Files changed (33) hide show
  1. package/components/client-node-native.ts +150 -292
  2. package/components/client.ts +385 -286
  3. package/components/index.ts +0 -2
  4. package/components/native-cache-node.ts +0 -3
  5. package/components/native-cache.ts +0 -8
  6. package/components/native-node.ts +137 -4
  7. package/components/native.ts +29 -65
  8. package/components/types.ts +25 -41
  9. package/dist/components/client-node-native.d.ts +0 -1
  10. package/dist/components/client-node-native.d.ts.map +1 -1
  11. package/dist/components/client-node-native.js +84 -202
  12. package/dist/components/client-node-native.js.map +1 -1
  13. package/dist/components/native-cache-node.d.ts.map +1 -1
  14. package/dist/components/native-cache-node.js +0 -1
  15. package/dist/components/native-cache-node.js.map +1 -1
  16. package/dist/components/native-node.d.ts +78 -0
  17. package/dist/components/native-node.d.ts.map +1 -1
  18. package/dist/components/native-node.js +122 -2
  19. package/dist/components/native-node.js.map +1 -1
  20. package/dist/components/types.d.ts +5 -13
  21. package/dist/components/types.d.ts.map +1 -1
  22. package/lib/libhttpclient.dylib +0 -0
  23. package/package.json +1 -1
  24. package/components/cache.ts +0 -451
  25. package/components/native-json.ts +0 -195
  26. package/components/persistent-worker.ts +0 -67
  27. package/components/subprocess-worker.ts +0 -60
  28. package/components/worker-pool.ts +0 -153
  29. package/components/worker.ts +0 -154
  30. package/dist/components/cache.d.ts +0 -32
  31. package/dist/components/cache.d.ts.map +0 -1
  32. package/dist/components/cache.js +0 -374
  33. package/dist/components/cache.js.map +0 -1
@@ -43,7 +43,7 @@ const STATUS_TEXT: Record<number, string> = {
43
43
  };
44
44
 
45
45
  export function defineUrls<const T extends readonly TargetUrlConfig[]>(
46
- urls: T
46
+ urls: T,
47
47
  ): T {
48
48
  return urls;
49
49
  }
@@ -59,9 +59,8 @@ const clientRegistry = new FinalizationRegistry<any>((ptr) => {
59
59
  export class JirenClient<
60
60
  T extends readonly TargetUrlConfig[] | Record<string, UrlConfig> =
61
61
  | readonly TargetUrlConfig[]
62
- | Record<string, UrlConfig>
63
- > implements Disposable
64
- {
62
+ | Record<string, UrlConfig>,
63
+ > implements Disposable {
65
64
  private ptr: any = null; // Koffi pointer
66
65
  private urlMap: Map<string, string> = new Map();
67
66
  private cacheConfig: Map<string, { enabled: boolean; ttl: number }> =
@@ -101,7 +100,6 @@ export class JirenClient<
101
100
  /** Type-safe URL accessor for warmed-up URLs */
102
101
  public readonly url: UrlAccessor<T>;
103
102
  /** Alias for url property */
104
- public readonly targets: UrlAccessor<T>;
105
103
 
106
104
  private metricsCollector: MetricsCollector;
107
105
  public readonly metrics: MetricsAPI;
@@ -150,7 +148,7 @@ export class JirenClient<
150
148
  }
151
149
 
152
150
  // Process target URLs
153
- const targets = options?.urls ?? (options as any)?.targets;
151
+ const targets = options?.urls;
154
152
  if (targets) {
155
153
  const urls: string[] = [];
156
154
 
@@ -179,7 +177,7 @@ export class JirenClient<
179
177
  } else {
180
178
  for (const [key, urlConfig] of Object.entries(targets) as [
181
179
  string,
182
- UrlConfig
180
+ UrlConfig,
183
181
  ][]) {
184
182
  if (typeof urlConfig === "string") {
185
183
  urls.push(urlConfig);
@@ -203,7 +201,7 @@ export class JirenClient<
203
201
  }
204
202
  }
205
203
 
206
- if (urls.length > 0 && (options as any)?.preconnect !== false) {
204
+ if (urls.length > 0 && options?.preconnect !== false) {
207
205
  this.targetsPromise = this.preconnect(urls).then(() => {
208
206
  urls.forEach((url) => this.targetsComplete.add(url));
209
207
  this.targetsPromise = null;
@@ -223,8 +221,6 @@ export class JirenClient<
223
221
 
224
222
  // Create proxy for type-safe URL access
225
223
  this.url = this.createUrlAccessor();
226
- // Alias for targets
227
- this.targets = this.url;
228
224
 
229
225
  // Store global retry config
230
226
  if (options?.retry) {
@@ -263,8 +259,8 @@ export class JirenClient<
263
259
  if (!baseUrl) {
264
260
  throw new Error(
265
261
  `URL key "${prop}" not found. Available keys: ${Array.from(
266
- self.urlMap.keys()
267
- ).join(", ")}`
262
+ self.urlMap.keys(),
263
+ ).join(", ")}`,
268
264
  );
269
265
  }
270
266
 
@@ -275,7 +271,7 @@ export class JirenClient<
275
271
 
276
272
  return {
277
273
  get: async <R = any>(
278
- options?: UrlRequestOptions
274
+ options?: UrlRequestOptions,
279
275
  ): Promise<JirenResponse<R> | R | string | ArrayBuffer | Blob> => {
280
276
  if (self.targetsPromise) {
281
277
  await self.targetsPromise;
@@ -330,7 +326,7 @@ export class JirenClient<
330
326
 
331
327
  // Deduplication
332
328
  const dedupKey = `GET:${buildUrl(options?.path)}:${JSON.stringify(
333
- options?.headers || {}
329
+ options?.headers || {},
334
330
  )}`;
335
331
 
336
332
  if (self.inflightRequests.has(dedupKey)) {
@@ -369,7 +365,7 @@ export class JirenClient<
369
365
  responseType: options?.responseType,
370
366
  antibot: useAntibot,
371
367
  timeout: options?.timeout,
372
- }
368
+ },
373
369
  );
374
370
 
375
371
  if (
@@ -382,7 +378,7 @@ export class JirenClient<
382
378
  response as JirenResponse,
383
379
  cacheConfig.ttl,
384
380
  options?.path,
385
- options
381
+ options,
386
382
  );
387
383
  }
388
384
 
@@ -440,7 +436,7 @@ export class JirenClient<
440
436
 
441
437
  post: async <R = any>(
442
438
  body?: any,
443
- options?: UrlRequestOptions & { responseType?: "json" }
439
+ options?: UrlRequestOptions & { responseType?: "json" },
444
440
  ): Promise<JirenResponse<R> | R | string | ArrayBuffer | Blob> => {
445
441
  const { headers: preparedHeaders, serializedBody } =
446
442
  self.prepareBody(body, options?.headers);
@@ -454,13 +450,13 @@ export class JirenClient<
454
450
  responseType: options?.responseType,
455
451
  antibot: options?.antibot,
456
452
  timeout: options?.timeout,
457
- }
453
+ },
458
454
  );
459
455
  },
460
456
 
461
457
  put: async <R = any>(
462
458
  body?: any,
463
- options?: UrlRequestOptions & { responseType?: "json" }
459
+ options?: UrlRequestOptions & { responseType?: "json" },
464
460
  ): Promise<JirenResponse<R> | R | string | ArrayBuffer | Blob> => {
465
461
  const { headers: preparedHeaders, serializedBody } =
466
462
  self.prepareBody(body, options?.headers);
@@ -474,13 +470,13 @@ export class JirenClient<
474
470
  responseType: options?.responseType,
475
471
  antibot: options?.antibot,
476
472
  timeout: options?.timeout,
477
- }
473
+ },
478
474
  );
479
475
  },
480
476
 
481
477
  patch: async <R = any>(
482
478
  body?: any,
483
- options?: UrlRequestOptions & { responseType?: "json" }
479
+ options?: UrlRequestOptions & { responseType?: "json" },
484
480
  ): Promise<JirenResponse<R> | R | string | ArrayBuffer | Blob> => {
485
481
  const { headers: preparedHeaders, serializedBody } =
486
482
  self.prepareBody(body, options?.headers);
@@ -494,12 +490,12 @@ export class JirenClient<
494
490
  responseType: options?.responseType,
495
491
  antibot: options?.antibot,
496
492
  timeout: options?.timeout,
497
- }
493
+ },
498
494
  );
499
495
  },
500
496
 
501
497
  delete: async <R = any>(
502
- options?: UrlRequestOptions & { responseType?: "json" }
498
+ options?: UrlRequestOptions & { responseType?: "json" },
503
499
  ): Promise<JirenResponse<R> | R | string | ArrayBuffer | Blob> => {
504
500
  const { headers: preparedHeaders, serializedBody } =
505
501
  self.prepareBody(options?.body, options?.headers);
@@ -513,12 +509,12 @@ export class JirenClient<
513
509
  responseType: options?.responseType,
514
510
  antibot: options?.antibot,
515
511
  timeout: options?.timeout,
516
- }
512
+ },
517
513
  );
518
514
  },
519
515
 
520
516
  head: async (
521
- options?: UrlRequestOptions
517
+ options?: UrlRequestOptions,
522
518
  ): Promise<JirenResponse<any>> => {
523
519
  return self._request("HEAD", buildUrl(options?.path), null, {
524
520
  headers: options?.headers,
@@ -529,7 +525,7 @@ export class JirenClient<
529
525
  },
530
526
 
531
527
  options: async (
532
- options?: UrlRequestOptions
528
+ options?: UrlRequestOptions,
533
529
  ): Promise<JirenResponse<any>> => {
534
530
  return self._request("OPTIONS", buildUrl(options?.path), null, {
535
531
  headers: options?.headers,
@@ -540,7 +536,7 @@ export class JirenClient<
540
536
  },
541
537
 
542
538
  trace: async <R = any>(
543
- options?: UrlRequestOptions
539
+ options?: UrlRequestOptions,
544
540
  ): Promise<JirenResponse<R> | R | string | ArrayBuffer | Blob> => {
545
541
  // Trace method
546
542
  return self._request<R>("TRACE", buildUrl(options?.path), null, {
@@ -565,31 +561,6 @@ export class JirenClient<
565
561
  }
566
562
  },
567
563
 
568
- getJsonFields: async <T extends Record<string, any>>(
569
- fields: (keyof T)[],
570
- options?: UrlRequestOptions
571
- ): Promise<Partial<T>> => {
572
- const { headers: preparedHeaders } = self.prepareBody(
573
- options?.body,
574
- options?.headers
575
- );
576
-
577
- const response = (await self._request<any>(
578
- "GET",
579
- buildUrl(options?.path),
580
- null,
581
- {
582
- headers: preparedHeaders,
583
- maxRedirects: options?.maxRedirects,
584
- antibot: options?.antibot,
585
- timeout: options?.timeout,
586
- retry: options?.retry ?? self.globalRetry,
587
- }
588
- )) as JirenResponse<any>;
589
-
590
- return response.body.jsonFields(fields);
591
- },
592
-
593
564
  /**
594
565
  * Download with progress tracking
595
566
  * Note: For Node.js, HTTPS uses fetch-based streaming. HTTP uses native streaming.
@@ -602,7 +573,7 @@ export class JirenClient<
602
573
  * });
603
574
  */
604
575
  download: async <R = any>(
605
- options?: ProgressRequestOptions
576
+ options?: ProgressRequestOptions,
606
577
  ): Promise<JirenResponse<R>> => {
607
578
  const url = buildUrl(options?.path);
608
579
 
@@ -617,132 +588,34 @@ export class JirenClient<
617
588
  const isHttps = url.startsWith("https://");
618
589
 
619
590
  if (isHttps) {
620
- // Use Node.js fetch with streaming
621
- const fetchOptions: RequestInit = {
622
- method: "GET",
591
+ // HTTPS: Fall back to buffered request with simulated progress
592
+ // (Native streaming for HTTPS requires more work on HTTP/2 layer)
593
+ const response = await self._request<R>("GET", url, null, {
623
594
  headers: options?.headers,
624
- };
625
-
626
- const response = await fetch(url, fetchOptions);
627
- const contentLength = parseInt(
628
- response.headers.get("content-length") || "0",
629
- 10
630
- );
631
- const reader = response.body?.getReader();
632
-
633
- if (!reader) {
634
- throw new Error("Failed to get response reader");
635
- }
636
-
637
- const chunks: Uint8Array[] = [];
638
- let loaded = 0;
639
- const startTime = performance.now();
640
- let lastLoaded = 0;
641
- let lastTime = startTime;
642
-
643
- while (true) {
644
- const { done, value } = await reader.read();
645
- if (done) break;
646
-
647
- chunks.push(value);
648
- loaded += value.length;
649
-
650
- // Calculate progress
651
- const now = performance.now();
652
- const elapsed = now - lastTime;
653
- const bytesThisInterval = loaded - lastLoaded;
654
- const speed =
655
- elapsed > 0 ? (bytesThisInterval / elapsed) * 1000 : 0;
656
- const remaining =
657
- contentLength > 0 ? contentLength - loaded : 0;
658
- const eta = speed > 0 ? (remaining / speed) * 1000 : 0;
659
-
660
- options.onDownloadProgress({
661
- loaded,
662
- total: contentLength,
663
- percent:
664
- contentLength > 0
665
- ? Math.round((loaded / contentLength) * 100)
666
- : 0,
667
- speed: Math.round(speed),
668
- eta: Math.round(eta),
669
- });
670
-
671
- lastLoaded = loaded;
672
- lastTime = now;
673
- }
595
+ });
674
596
 
675
- // Final progress
597
+ // Fire final progress event
598
+ const bodyText = await response.body.text();
599
+ const bodySize = Buffer.byteLength(bodyText);
676
600
  options.onDownloadProgress({
677
- loaded,
678
- total: contentLength || loaded,
601
+ loaded: bodySize,
602
+ total: bodySize,
679
603
  percent: 100,
680
604
  speed: 0,
681
605
  eta: 0,
682
606
  });
683
607
 
684
- // Combine chunks
685
- const totalLength = chunks.reduce(
686
- (acc, chunk) => acc + chunk.length,
687
- 0
688
- );
689
- const buffer = new Uint8Array(totalLength);
690
- let offset = 0;
691
- for (const chunk of chunks) {
692
- buffer.set(chunk, offset);
693
- offset += chunk.length;
694
- }
695
-
696
- // Parse headers
697
- const headersObj: Record<string, string> = {};
698
- response.headers.forEach((value, key) => {
699
- headersObj[key.toLowerCase()] = value;
700
- });
701
-
702
- // Build response
703
- const decoder = new TextDecoder();
704
- let bodyUsed = false;
705
-
706
- const bodyObj: JirenResponseBody<R> = {
707
- bodyUsed: false,
708
- arrayBuffer: async () => buffer.buffer as ArrayBuffer,
709
- blob: async () => new Blob([buffer]),
710
- text: async () => {
711
- bodyUsed = true;
712
- return decoder.decode(buffer);
713
- },
714
- json: async <T = R>(): Promise<T> => {
715
- bodyUsed = true;
716
- return JSON.parse(decoder.decode(buffer));
717
- },
718
- jsonFields: async <T extends Record<string, any> = any>(
719
- fields: (keyof T)[]
720
- ): Promise<Partial<T>> => {
721
- bodyUsed = true;
722
- const fullObj = JSON.parse(decoder.decode(buffer));
723
- const result: Partial<T> = {};
724
- for (const field of fields) {
725
- if (field in fullObj) {
726
- result[field] = fullObj[field];
727
- }
728
- }
729
- return result;
730
- },
731
- };
732
-
733
- Object.defineProperty(bodyObj, "bodyUsed", {
734
- get: () => bodyUsed,
735
- });
736
-
608
+ // Recreate response with body
737
609
  return {
738
- url,
739
- status: response.status,
740
- statusText: response.statusText,
741
- headers: headersObj,
742
- ok: response.ok,
743
- redirected: response.redirected,
744
- type: "basic",
745
- body: bodyObj,
610
+ ...response,
611
+ body: {
612
+ ...response.body,
613
+ text: async () => bodyText,
614
+ json: async () => JSON.parse(bodyText),
615
+ arrayBuffer: async () => Buffer.from(bodyText).buffer,
616
+ blob: async () => new Blob([bodyText]),
617
+ bodyUsed: true,
618
+ },
746
619
  } as JirenResponse<R>;
747
620
  }
748
621
 
@@ -770,40 +643,14 @@ export class JirenClient<
770
643
  arrayBuffer: async () => Buffer.from(bodyText).buffer,
771
644
  blob: async () => new Blob([bodyText]),
772
645
  bodyUsed: true,
773
- jsonFields: async <T extends Record<string, any> = any>(
774
- fields: (keyof T)[]
775
- ): Promise<Partial<T>> => {
776
- const fullObj = JSON.parse(bodyText);
777
- const result: Partial<T> = {};
778
- for (const field of fields) {
779
- if (field in fullObj) {
780
- result[field] = fullObj[field];
781
- }
782
- }
783
- return result;
784
- },
785
646
  },
786
647
  } as JirenResponse<R>;
787
648
  },
788
-
789
- /**
790
- * Upload with progress tracking
791
- * @param options - Request options with onUploadProgress callback
792
- * @example
793
- * await client.url.api.upload({
794
- * method: 'POST',
795
- * path: '/upload',
796
- * body: largeData,
797
- * onUploadProgress: (progress) => {
798
- * console.log(`${progress.percent}%`);
799
- * }
800
- * });
801
- */
802
649
  upload: async <R = any>(
803
650
  options?: ProgressRequestOptions & {
804
651
  method?: "POST" | "PUT" | "PATCH";
805
652
  body?: string | object | null;
806
- }
653
+ },
807
654
  ): Promise<JirenResponse<R>> => {
808
655
  const url = buildUrl(options?.path);
809
656
  const method = options?.method || "POST";
@@ -841,86 +688,110 @@ export class JirenClient<
841
688
  });
842
689
 
843
690
  // Prepare headers
844
- const { headers: preparedHeaders } = self.prepareBody(
845
- options.body,
846
- options.headers
847
- );
691
+ // HTTPS: Use fast path with simulated progress
692
+ // (Native layer handles the upload in one call)
693
+ const { headers: preparedHeaders, serializedBody } =
694
+ self.prepareBody(options.body, options.headers);
848
695
 
849
- // For Node.js, use fetch with manual progress tracking
850
- // Since fetch doesn't support upload progress natively, we simulate it
851
- const response = await fetch(url, {
696
+ const response = await self._request<R>(
852
697
  method,
853
- headers: preparedHeaders,
854
- body: bodyStr,
855
- });
698
+ url,
699
+ serializedBody,
700
+ {
701
+ headers: preparedHeaders,
702
+ },
703
+ );
856
704
 
857
- // Fire final progress (100%)
858
- const elapsed = performance.now() - startTime;
859
- const speed = elapsed > 0 ? (bodyLength / elapsed) * 1000 : 0;
705
+ // Fire final progress event (100%)
860
706
  options.onUploadProgress({
861
707
  loaded: bodyLength,
862
708
  total: bodyLength,
863
709
  percent: 100,
864
- speed: Math.round(speed),
710
+ speed: 0,
865
711
  eta: 0,
866
712
  });
867
713
 
868
- // Parse response
869
- const headersObj: Record<string, string> = {};
870
- response.headers.forEach((value, key) => {
871
- headersObj[key.toLowerCase()] = value;
872
- });
714
+ return response;
715
+ },
716
+ getJsonFields: async <R = any>(
717
+ fields: string[],
718
+ options?: UrlRequestOptions,
719
+ ): Promise<R> => {
720
+ if (fields.length > 8) {
721
+ throw new Error("Maximum 8 fields supported per call");
722
+ }
873
723
 
874
- const responseBody = await response.text();
875
- let bodyUsed = false;
724
+ const url = buildUrl(options?.path);
876
725
 
877
- const bodyObj: JirenResponseBody<R> = {
878
- bodyUsed: false,
879
- text: async () => {
880
- bodyUsed = true;
881
- return responseBody;
882
- },
883
- json: async <T = R>(): Promise<T> => {
884
- bodyUsed = true;
885
- return JSON.parse(responseBody);
886
- },
887
- jsonFields: async <T extends Record<string, any> = any>(
888
- fields: (keyof T)[]
889
- ): Promise<Partial<T>> => {
890
- bodyUsed = true;
891
- const fullObj = JSON.parse(responseBody);
892
- const result: Partial<T> = {};
893
- for (const field of fields) {
894
- if (field in fullObj) {
895
- result[field] = fullObj[field];
896
- }
897
- }
898
- return result;
899
- },
900
- arrayBuffer: async () => {
901
- bodyUsed = true;
902
- return Buffer.from(responseBody).buffer as ArrayBuffer;
903
- },
904
- blob: async () => {
905
- bodyUsed = true;
906
- return new Blob([responseBody]);
907
- },
908
- };
726
+ let resultPtr: any = null;
909
727
 
910
- Object.defineProperty(bodyObj, "bodyUsed", {
911
- get: () => bodyUsed,
912
- });
728
+ if (options?.headers || options?.body) {
729
+ const { headers, serializedBody } = self.prepareBody(
730
+ options.body,
731
+ options.headers,
732
+ );
733
+ const headersStr = Object.entries({
734
+ ...self.defaultHeaders,
735
+ ...headers,
736
+ })
737
+ .map(([k, v]) => `${k.toLowerCase()}: ${v}`)
738
+ .join("\r\n");
739
+
740
+ resultPtr = lib.symbols.zclient_request_json_fields(
741
+ self.ptr,
742
+ "GET", // Default to GET
743
+ url,
744
+ headersStr,
745
+ serializedBody,
746
+ fields,
747
+ fields.length,
748
+ );
749
+ } else {
750
+ resultPtr = lib.symbols.zclient_get_json_fields(
751
+ self.ptr,
752
+ url,
753
+ fields,
754
+ fields.length,
755
+ );
756
+ }
913
757
 
914
- return {
915
- url,
916
- status: response.status,
917
- statusText: response.statusText,
918
- headers: headersObj,
919
- ok: response.ok,
920
- redirected: response.redirected,
921
- type: "basic",
922
- body: bodyObj,
923
- } as JirenResponse<R>;
758
+ if (!resultPtr) {
759
+ throw new Error("Native getJsonFields failed");
760
+ }
761
+
762
+ try {
763
+ const result: any = {};
764
+ const decoder = new TextDecoder();
765
+
766
+ for (let i = 0; i < fields.length; i++) {
767
+ const key = fields[i]!;
768
+ const type = lib.symbols.zjson_field_type(resultPtr, i);
769
+
770
+ if (type === 0) {
771
+ result[key] = null;
772
+ } else if (type === 1) {
773
+ const len = Number(lib.symbols.zjson_field_len(resultPtr, i));
774
+ result[key] = len === 1;
775
+ } else if (type === 2) {
776
+ const len = Number(lib.symbols.zjson_field_len(resultPtr, i));
777
+ result[key] = len;
778
+ } else if (type === 3) {
779
+ const ptrVal = lib.symbols.zjson_field_str(resultPtr, i);
780
+ const lenVal = Number(
781
+ lib.symbols.zjson_field_len(resultPtr, i),
782
+ );
783
+ if (ptrVal && lenVal > 0) {
784
+ const bytes = koffi.decode(ptrVal, "uint8_t", lenVal);
785
+ result[key] = decoder.decode(bytes);
786
+ } else {
787
+ result[key] = "";
788
+ }
789
+ }
790
+ }
791
+ return result as R;
792
+ } finally {
793
+ lib.symbols.zclient_json_fields_free(resultPtr);
794
+ }
924
795
  },
925
796
  } as UrlEndpoint;
926
797
  },
@@ -960,8 +831,8 @@ export class JirenClient<
960
831
  new Promise<void>((resolve) => {
961
832
  lib.symbols.zclient_prefetch(this.ptr, url);
962
833
  resolve();
963
- })
964
- )
834
+ }),
835
+ ),
965
836
  );
966
837
  }
967
838
 
@@ -977,37 +848,37 @@ export class JirenClient<
977
848
  method: string,
978
849
  url: string,
979
850
  body?: string | null,
980
- options?: RequestOptions & { responseType: "json" }
851
+ options?: RequestOptions & { responseType: "json" },
981
852
  ): Promise<T>;
982
853
  protected async _request<T = any>(
983
854
  method: string,
984
855
  url: string,
985
856
  body?: string | null,
986
- options?: RequestOptions & { responseType: "text" }
857
+ options?: RequestOptions & { responseType: "text" },
987
858
  ): Promise<string>;
988
859
  protected async _request<T = any>(
989
860
  method: string,
990
861
  url: string,
991
862
  body?: string | null,
992
- options?: RequestOptions & { responseType: "arraybuffer" }
863
+ options?: RequestOptions & { responseType: "arraybuffer" },
993
864
  ): Promise<ArrayBuffer>;
994
865
  protected async _request<T = any>(
995
866
  method: string,
996
867
  url: string,
997
868
  body?: string | null,
998
- options?: RequestOptions & { responseType: "blob" }
869
+ options?: RequestOptions & { responseType: "blob" },
999
870
  ): Promise<Blob>;
1000
871
  protected async _request<T = any>(
1001
872
  method: string,
1002
873
  url: string,
1003
874
  body?: string | null,
1004
- options?: RequestOptions
875
+ options?: RequestOptions,
1005
876
  ): Promise<JirenResponse<T>>;
1006
877
  protected async _request<T = any>(
1007
878
  method: string,
1008
879
  url: string,
1009
880
  body?: string | null,
1010
- options?: RequestOptions | Record<string, string> | null
881
+ options?: RequestOptions | Record<string, string> | null,
1011
882
  ): Promise<JirenResponse<T> | T | string | ArrayBuffer | Blob> {
1012
883
  if (!this.ptr) throw new Error("Client is closed");
1013
884
 
@@ -1095,7 +966,7 @@ export class JirenClient<
1095
966
  // Retry logic
1096
967
  let retryConfig = this.globalRetry;
1097
968
  if (options && typeof options === "object" && "retry" in options) {
1098
- const userRetry = (options as any).retry;
969
+ const userRetry = options?.retry;
1099
970
  if (typeof userRetry === "number") {
1100
971
  retryConfig = { count: userRetry, delay: 100, backoff: 2 };
1101
972
  } else if (typeof userRetry === "object") {
@@ -1123,7 +994,7 @@ export class JirenClient<
1123
994
  headerStr.length > 0 ? headerStr : null,
1124
995
  body || null,
1125
996
  maxRedirects,
1126
- antibot
997
+ antibot,
1127
998
  );
1128
999
 
1129
1000
  if (!respPtr) {
@@ -1203,7 +1074,7 @@ export class JirenClient<
1203
1074
  const bodyPtr = lib.symbols.zclient_response_body(respPtr);
1204
1075
 
1205
1076
  const headersLen = Number(
1206
- lib.symbols.zclient_response_headers_len(respPtr)
1077
+ lib.symbols.zclient_response_headers_len(respPtr),
1207
1078
  );
1208
1079
  let headersObj: Record<string, string> | NativeHeaders = {};
1209
1080
 
@@ -1211,7 +1082,7 @@ export class JirenClient<
1211
1082
  const rawHeadersPtr = lib.symbols.zclient_response_headers(respPtr);
1212
1083
  if (rawHeadersPtr) {
1213
1084
  const raw = Buffer.from(
1214
- koffi.decode(rawHeadersPtr, "uint8_t", headersLen)
1085
+ koffi.decode(rawHeadersPtr, "uint8_t", headersLen),
1215
1086
  );
1216
1087
  headersObj = new NativeHeaders(raw);
1217
1088
  }
@@ -1228,7 +1099,7 @@ export class JirenClient<
1228
1099
  }
1229
1100
  return Reflect.get(target, prop);
1230
1101
  },
1231
- }
1102
+ },
1232
1103
  ) as unknown as Record<string, string>;
1233
1104
 
1234
1105
  let buffer: Buffer = Buffer.alloc(0);
@@ -1267,7 +1138,7 @@ export class JirenClient<
1267
1138
  consumeBody();
1268
1139
  return buffer.buffer.slice(
1269
1140
  buffer.byteOffset,
1270
- buffer.byteOffset + buffer.byteLength
1141
+ buffer.byteOffset + buffer.byteLength,
1271
1142
  ) as ArrayBuffer;
1272
1143
  },
1273
1144
  blob: async () => {
@@ -1282,19 +1153,6 @@ export class JirenClient<
1282
1153
  consumeBody();
1283
1154
  return JSON.parse(buffer.toString("utf-8"));
1284
1155
  },
1285
- jsonFields: async <T extends Record<string, any> = any>(
1286
- fields: (keyof T)[]
1287
- ): Promise<Partial<T>> => {
1288
- consumeBody();
1289
- const fullObj = JSON.parse(buffer.toString("utf-8"));
1290
- const result: Partial<T> = {};
1291
- for (const field of fields) {
1292
- if (field in fullObj) {
1293
- result[field] = fullObj[field];
1294
- }
1295
- }
1296
- return result;
1297
- },
1298
1156
  };
1299
1157
 
1300
1158
  Object.defineProperty(bodyObj, "bodyUsed", {
@@ -1321,7 +1179,7 @@ export class JirenClient<
1321
1179
  */
1322
1180
  private prepareBody(
1323
1181
  body: string | object | null | undefined,
1324
- userHeaders?: Record<string, string>
1182
+ userHeaders?: Record<string, string>,
1325
1183
  ): { headers: Record<string, string>; serializedBody: string | null } {
1326
1184
  let serializedBody: string | null = null;
1327
1185
  const headers = { ...userHeaders };
@@ -1330,7 +1188,7 @@ export class JirenClient<
1330
1188
  if (typeof body === "object") {
1331
1189
  serializedBody = JSON.stringify(body);
1332
1190
  const hasContentType = Object.keys(headers).some(
1333
- (k) => k.toLowerCase() === "content-type"
1191
+ (k) => k.toLowerCase() === "content-type",
1334
1192
  );
1335
1193
  if (!hasContentType) {
1336
1194
  headers["Content-Type"] = "application/json";