@tinycloud/sdk-services 2.8.0 → 2.10.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.
@@ -1,11 +1,12 @@
1
- import { B as BaseService } from '../BaseService-DxSU4U-v.cjs';
2
- import { R as Result, I as IService } from '../types-KCcgZiab.cjs';
1
+ import { B as BaseService } from '../BaseService-BhpVpA9b.cjs';
2
+ import { R as Result, I as IService } from '../types-qwMmB7qB.cjs';
3
3
 
4
4
  /**
5
5
  * KV Service Types
6
6
  *
7
7
  * Type definitions for the KV (Key-Value) service operations.
8
8
  */
9
+
9
10
  /**
10
11
  * Configuration for KVService.
11
12
  */
@@ -143,6 +144,18 @@ interface KVBatchPutResponse {
143
144
  */
144
145
  count: number;
145
146
  }
147
+ /**
148
+ * Response from a KV batch read. Transport or authorization failures are
149
+ * returned by the outer Result; each requested key has its own Result so a
150
+ * missing key does not discard successful siblings.
151
+ */
152
+ interface KVBatchReadResponse<T = unknown> {
153
+ results: Array<{
154
+ key: string;
155
+ result: Result<KVResponse<T>>;
156
+ }>;
157
+ count: number;
158
+ }
146
159
  /**
147
160
  * Options for KV list operations.
148
161
  */
@@ -166,6 +179,8 @@ interface KVListOptions {
166
179
  raw?: boolean;
167
180
  /** Maximum number of keys the node may return. */
168
181
  limit?: number;
182
+ /** Opaque scope-bound cursor returned by a previous bounded list. */
183
+ cursor?: string;
169
184
  /**
170
185
  * Custom timeout for this operation in milliseconds.
171
186
  */
@@ -305,6 +320,8 @@ interface KVListResponse {
305
320
  keys: string[];
306
321
  /** True when more matching keys exist than the requested limit. */
307
322
  truncated?: boolean;
323
+ /** Opaque cursor for the next page, when the node returned one. */
324
+ nextCursor?: string;
308
325
  }
309
326
  /**
310
327
  * Response from signed KV read URL creation.
@@ -398,6 +415,7 @@ interface IPrefixedKVService {
398
415
  * ```
399
416
  */
400
417
  get<T = unknown>(key: string, options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVResponse<T>>>;
418
+ batchGet<T = unknown>(keys: string[], options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<T>>>;
401
419
  /**
402
420
  * Store a value at a key.
403
421
  *
@@ -472,6 +490,7 @@ interface IPrefixedKVService {
472
490
  * ```
473
491
  */
474
492
  head(key: string, options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
493
+ batchHead(keys: string[], options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<void>>>;
475
494
  /**
476
495
  * Create a short-lived signed URL for reading a KV object.
477
496
  *
@@ -507,11 +526,13 @@ interface IPrefixedKVService {
507
526
  */
508
527
  interface IKVServiceLike {
509
528
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
529
+ batchGet<T = unknown>(keys: string[], options?: KVGetOptions): Promise<Result<KVBatchReadResponse<T>>>;
510
530
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
511
531
  batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
512
532
  list(options?: KVListOptions): Promise<Result<KVListResponse>>;
513
533
  delete(key: string, options?: KVDeleteOptions): Promise<Result<KVResponse<void>>>;
514
534
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
535
+ batchHead(keys: string[], options?: KVHeadOptions): Promise<Result<KVBatchReadResponse<void>>>;
515
536
  createSignedReadUrl(key: string, options?: KVCreateSignedReadUrlOptions): Promise<Result<KVSignedReadUrlResponse>>;
516
537
  }
517
538
  /**
@@ -577,6 +598,7 @@ declare class PrefixedKVService implements IPrefixedKVService {
577
598
  * Get a value by key.
578
599
  */
579
600
  get<T = unknown>(key: string, options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVResponse<T>>>;
601
+ batchGet<T = unknown>(keys: string[], options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<T>>>;
580
602
  /**
581
603
  * Store a value at a key.
582
604
  */
@@ -597,6 +619,7 @@ declare class PrefixedKVService implements IPrefixedKVService {
597
619
  * Get metadata for a key without retrieving the value.
598
620
  */
599
621
  head(key: string, options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
622
+ batchHead(keys: string[], options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<void>>>;
600
623
  /**
601
624
  * Create a short-lived signed URL for reading a KV object.
602
625
  */
@@ -651,6 +674,7 @@ interface IKVService extends IService {
651
674
  * ```
652
675
  */
653
676
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
677
+ batchGet<T = unknown>(keys: string[], options?: KVGetOptions): Promise<Result<KVBatchReadResponse<T>>>;
654
678
  /**
655
679
  * Store a value at a key.
656
680
  *
@@ -734,6 +758,7 @@ interface IKVService extends IService {
734
758
  * ```
735
759
  */
736
760
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
761
+ batchHead(keys: string[], options?: KVHeadOptions): Promise<Result<KVBatchReadResponse<void>>>;
737
762
  /**
738
763
  * Create a short-lived signed URL for reading a KV object.
739
764
  *
@@ -881,6 +906,10 @@ declare class KVService extends BaseService implements IKVService {
881
906
  * @returns KVResponseHeaders object
882
907
  */
883
908
  private createResponseHeaders;
909
+ private createBatchResponseHeaders;
910
+ private parseBatchValue;
911
+ private normalizeBatchReadResponse;
912
+ private batchRead;
884
913
  /**
885
914
  * Parse response body based on content type.
886
915
  *
@@ -895,6 +924,7 @@ declare class KVService extends BaseService implements IKVService {
895
924
  * Get a value by key.
896
925
  */
897
926
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
927
+ batchGet<T = unknown>(keys: string[], options?: KVGetOptions): Promise<Result<KVBatchReadResponse<T>>>;
898
928
  /**
899
929
  * Store a value at a key.
900
930
  */
@@ -915,6 +945,7 @@ declare class KVService extends BaseService implements IKVService {
915
945
  * Get metadata for a key without retrieving the value.
916
946
  */
917
947
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
948
+ batchHead(keys: string[], options?: KVHeadOptions): Promise<Result<KVBatchReadResponse<void>>>;
918
949
  /**
919
950
  * Create a short-lived signed URL for reading a KV object.
920
951
  */
@@ -964,4 +995,4 @@ declare class KVService extends BaseService implements IKVService {
964
995
  withPrefix(prefix: string): IPrefixedKVService;
965
996
  }
966
997
 
967
- export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, type IKVService, type IPrefixedKVService, KVAction, type KVActionType, type KVBatchPutItem, type KVBatchPutOptions, type KVBatchPutResponse, type KVCreateSignedReadUrlOptions, type KVDeleteOptions, type KVGetOptions, type KVHeadOptions, type KVListOptions, type KVListResponse, type KVPutOptions, type KVResponse, type KVResponseHeaders, KVService, type KVServiceConfig, type KVSignedReadUrlResponse, PrefixedKVService };
998
+ export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, type IKVService, type IPrefixedKVService, KVAction, type KVActionType, type KVBatchPutItem, type KVBatchPutOptions, type KVBatchPutResponse, type KVBatchReadResponse, type KVCreateSignedReadUrlOptions, type KVDeleteOptions, type KVGetOptions, type KVHeadOptions, type KVListOptions, type KVListResponse, type KVPutOptions, type KVResponse, type KVResponseHeaders, KVService, type KVServiceConfig, type KVSignedReadUrlResponse, PrefixedKVService };
@@ -1,11 +1,12 @@
1
- import { B as BaseService } from '../BaseService-BiYeqCRT.js';
2
- import { R as Result, I as IService } from '../types-KCcgZiab.js';
1
+ import { B as BaseService } from '../BaseService-CuV-ZVPs.js';
2
+ import { R as Result, I as IService } from '../types-qwMmB7qB.js';
3
3
 
4
4
  /**
5
5
  * KV Service Types
6
6
  *
7
7
  * Type definitions for the KV (Key-Value) service operations.
8
8
  */
9
+
9
10
  /**
10
11
  * Configuration for KVService.
11
12
  */
@@ -143,6 +144,18 @@ interface KVBatchPutResponse {
143
144
  */
144
145
  count: number;
145
146
  }
147
+ /**
148
+ * Response from a KV batch read. Transport or authorization failures are
149
+ * returned by the outer Result; each requested key has its own Result so a
150
+ * missing key does not discard successful siblings.
151
+ */
152
+ interface KVBatchReadResponse<T = unknown> {
153
+ results: Array<{
154
+ key: string;
155
+ result: Result<KVResponse<T>>;
156
+ }>;
157
+ count: number;
158
+ }
146
159
  /**
147
160
  * Options for KV list operations.
148
161
  */
@@ -166,6 +179,8 @@ interface KVListOptions {
166
179
  raw?: boolean;
167
180
  /** Maximum number of keys the node may return. */
168
181
  limit?: number;
182
+ /** Opaque scope-bound cursor returned by a previous bounded list. */
183
+ cursor?: string;
169
184
  /**
170
185
  * Custom timeout for this operation in milliseconds.
171
186
  */
@@ -305,6 +320,8 @@ interface KVListResponse {
305
320
  keys: string[];
306
321
  /** True when more matching keys exist than the requested limit. */
307
322
  truncated?: boolean;
323
+ /** Opaque cursor for the next page, when the node returned one. */
324
+ nextCursor?: string;
308
325
  }
309
326
  /**
310
327
  * Response from signed KV read URL creation.
@@ -398,6 +415,7 @@ interface IPrefixedKVService {
398
415
  * ```
399
416
  */
400
417
  get<T = unknown>(key: string, options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVResponse<T>>>;
418
+ batchGet<T = unknown>(keys: string[], options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<T>>>;
401
419
  /**
402
420
  * Store a value at a key.
403
421
  *
@@ -472,6 +490,7 @@ interface IPrefixedKVService {
472
490
  * ```
473
491
  */
474
492
  head(key: string, options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
493
+ batchHead(keys: string[], options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<void>>>;
475
494
  /**
476
495
  * Create a short-lived signed URL for reading a KV object.
477
496
  *
@@ -507,11 +526,13 @@ interface IPrefixedKVService {
507
526
  */
508
527
  interface IKVServiceLike {
509
528
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
529
+ batchGet<T = unknown>(keys: string[], options?: KVGetOptions): Promise<Result<KVBatchReadResponse<T>>>;
510
530
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
511
531
  batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
512
532
  list(options?: KVListOptions): Promise<Result<KVListResponse>>;
513
533
  delete(key: string, options?: KVDeleteOptions): Promise<Result<KVResponse<void>>>;
514
534
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
535
+ batchHead(keys: string[], options?: KVHeadOptions): Promise<Result<KVBatchReadResponse<void>>>;
515
536
  createSignedReadUrl(key: string, options?: KVCreateSignedReadUrlOptions): Promise<Result<KVSignedReadUrlResponse>>;
516
537
  }
517
538
  /**
@@ -577,6 +598,7 @@ declare class PrefixedKVService implements IPrefixedKVService {
577
598
  * Get a value by key.
578
599
  */
579
600
  get<T = unknown>(key: string, options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVResponse<T>>>;
601
+ batchGet<T = unknown>(keys: string[], options?: Omit<KVGetOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<T>>>;
580
602
  /**
581
603
  * Store a value at a key.
582
604
  */
@@ -597,6 +619,7 @@ declare class PrefixedKVService implements IPrefixedKVService {
597
619
  * Get metadata for a key without retrieving the value.
598
620
  */
599
621
  head(key: string, options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
622
+ batchHead(keys: string[], options?: Omit<KVHeadOptions, 'prefix'>): Promise<Result<KVBatchReadResponse<void>>>;
600
623
  /**
601
624
  * Create a short-lived signed URL for reading a KV object.
602
625
  */
@@ -651,6 +674,7 @@ interface IKVService extends IService {
651
674
  * ```
652
675
  */
653
676
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
677
+ batchGet<T = unknown>(keys: string[], options?: KVGetOptions): Promise<Result<KVBatchReadResponse<T>>>;
654
678
  /**
655
679
  * Store a value at a key.
656
680
  *
@@ -734,6 +758,7 @@ interface IKVService extends IService {
734
758
  * ```
735
759
  */
736
760
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
761
+ batchHead(keys: string[], options?: KVHeadOptions): Promise<Result<KVBatchReadResponse<void>>>;
737
762
  /**
738
763
  * Create a short-lived signed URL for reading a KV object.
739
764
  *
@@ -881,6 +906,10 @@ declare class KVService extends BaseService implements IKVService {
881
906
  * @returns KVResponseHeaders object
882
907
  */
883
908
  private createResponseHeaders;
909
+ private createBatchResponseHeaders;
910
+ private parseBatchValue;
911
+ private normalizeBatchReadResponse;
912
+ private batchRead;
884
913
  /**
885
914
  * Parse response body based on content type.
886
915
  *
@@ -895,6 +924,7 @@ declare class KVService extends BaseService implements IKVService {
895
924
  * Get a value by key.
896
925
  */
897
926
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
927
+ batchGet<T = unknown>(keys: string[], options?: KVGetOptions): Promise<Result<KVBatchReadResponse<T>>>;
898
928
  /**
899
929
  * Store a value at a key.
900
930
  */
@@ -915,6 +945,7 @@ declare class KVService extends BaseService implements IKVService {
915
945
  * Get metadata for a key without retrieving the value.
916
946
  */
917
947
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
948
+ batchHead(keys: string[], options?: KVHeadOptions): Promise<Result<KVBatchReadResponse<void>>>;
918
949
  /**
919
950
  * Create a short-lived signed URL for reading a KV object.
920
951
  */
@@ -964,4 +995,4 @@ declare class KVService extends BaseService implements IKVService {
964
995
  withPrefix(prefix: string): IPrefixedKVService;
965
996
  }
966
997
 
967
- export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, type IKVService, type IPrefixedKVService, KVAction, type KVActionType, type KVBatchPutItem, type KVBatchPutOptions, type KVBatchPutResponse, type KVCreateSignedReadUrlOptions, type KVDeleteOptions, type KVGetOptions, type KVHeadOptions, type KVListOptions, type KVListResponse, type KVPutOptions, type KVResponse, type KVResponseHeaders, KVService, type KVServiceConfig, type KVSignedReadUrlResponse, PrefixedKVService };
998
+ export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, type IKVService, type IPrefixedKVService, KVAction, type KVActionType, type KVBatchPutItem, type KVBatchPutOptions, type KVBatchPutResponse, type KVBatchReadResponse, type KVCreateSignedReadUrlOptions, type KVDeleteOptions, type KVGetOptions, type KVHeadOptions, type KVListOptions, type KVListResponse, type KVPutOptions, type KVResponse, type KVResponseHeaders, KVService, type KVServiceConfig, type KVSignedReadUrlResponse, PrefixedKVService };
package/dist/kv/index.js CHANGED
@@ -421,6 +421,20 @@ var PrefixedKVService = class _PrefixedKVService {
421
421
  const fullKey = this.getFullKey(key);
422
422
  return this._kv.get(fullKey, { ...options, prefix: "" });
423
423
  }
424
+ async batchGet(keys, options) {
425
+ const response = await this._kv.batchGet(
426
+ keys.map((key) => this.getFullKey(key)),
427
+ { ...options, prefix: "" }
428
+ );
429
+ if (!response.ok) return response;
430
+ return ok({
431
+ ...response.data,
432
+ results: response.data.results.map((item, index) => ({
433
+ ...item,
434
+ key: keys[index]
435
+ }))
436
+ });
437
+ }
424
438
  /**
425
439
  * Store a value at a key.
426
440
  */
@@ -465,6 +479,20 @@ var PrefixedKVService = class _PrefixedKVService {
465
479
  const fullKey = this.getFullKey(key);
466
480
  return this._kv.head(fullKey, { ...options, prefix: "" });
467
481
  }
482
+ async batchHead(keys, options) {
483
+ const response = await this._kv.batchHead(
484
+ keys.map((key) => this.getFullKey(key)),
485
+ { ...options, prefix: "" }
486
+ );
487
+ if (!response.ok) return response;
488
+ return ok({
489
+ ...response.data,
490
+ results: response.data.results.map((item, index) => ({
491
+ ...item,
492
+ key: keys[index]
493
+ }))
494
+ });
495
+ }
468
496
  /**
469
497
  * Create a short-lived signed URL for reading a KV object.
470
498
  */
@@ -493,6 +521,7 @@ var KVAction = {
493
521
  };
494
522
 
495
523
  // src/kv/KVService.ts
524
+ var MAX_KV_BATCH_READ_ITEMS = 100;
496
525
  function encodeKvBatchPartName(path) {
497
526
  return encodeURIComponent(path).replace(
498
527
  /[!'()*]/g,
@@ -727,6 +756,173 @@ var KVService = class extends BaseService {
727
756
  get: (name) => headers.get(name)
728
757
  };
729
758
  }
759
+ createBatchResponseHeaders(values) {
760
+ const normalized = new Map(
761
+ Object.entries(values).map(([name, value]) => [name.toLowerCase(), value])
762
+ );
763
+ return this.createResponseHeaders({
764
+ get: (name) => normalized.get(name.toLowerCase()) ?? null
765
+ });
766
+ }
767
+ parseBatchValue(dataBase64, headers, raw = false, binary = false) {
768
+ const encoded = globalThis.atob(dataBase64);
769
+ const bytes = Uint8Array.from(encoded, (character) => character.charCodeAt(0));
770
+ if (binary) return bytes;
771
+ const text = new TextDecoder().decode(bytes);
772
+ if (raw) return text;
773
+ const contentType = Object.entries(headers).find(
774
+ ([name]) => name.toLowerCase() === "content-type"
775
+ )?.[1];
776
+ return contentType?.includes("application/json") ? JSON.parse(text) : text;
777
+ }
778
+ normalizeBatchReadResponse(data, paths, requireData) {
779
+ if (!data || typeof data !== "object") return void 0;
780
+ const response = data;
781
+ if (!Array.isArray(response.results) || response.results.length !== paths.length) {
782
+ return void 0;
783
+ }
784
+ for (let index = 0; index < response.results.length; index++) {
785
+ const item = response.results[index];
786
+ if (!item || typeof item !== "object" || item.key !== paths[index] || typeof item.ok !== "boolean") {
787
+ return void 0;
788
+ }
789
+ if (item.ok && (!item.headers || typeof item.headers !== "object" || Object.values(item.headers).some((value) => typeof value !== "string") || requireData && typeof item.dataBase64 !== "string")) {
790
+ return void 0;
791
+ }
792
+ if (!item.ok && (!item.error || typeof item.error.code !== "string" || typeof item.error.message !== "string")) {
793
+ return void 0;
794
+ }
795
+ }
796
+ return response;
797
+ }
798
+ async batchRead(keys, action, options) {
799
+ if (!this.requireAuth()) return err(authRequiredError("kv"));
800
+ if (keys.length === 0) return ok({ results: [], count: 0 });
801
+ if (keys.length > MAX_KV_BATCH_READ_ITEMS) {
802
+ return err(serviceError(
803
+ ErrorCodes.INVALID_INPUT,
804
+ `KV batch reads accept at most ${MAX_KV_BATCH_READ_ITEMS} keys`,
805
+ "kv"
806
+ ));
807
+ }
808
+ if (keys.length === 1) {
809
+ const key = keys[0];
810
+ const result = action === KVAction.GET ? await this.get(key, options) : await this.head(key, options);
811
+ return ok({
812
+ results: [{ key, result }],
813
+ count: 1
814
+ });
815
+ }
816
+ if (!this.context.invokeAny) {
817
+ return err(serviceError(
818
+ ErrorCodes.INVALID_INPUT,
819
+ "KV batch reads require SDK runtime support for multi-resource invocations",
820
+ "kv"
821
+ ));
822
+ }
823
+ const getOptions = action === KVAction.GET ? options : void 0;
824
+ if (getOptions?.maxResponseBytes !== void 0 && (!Number.isSafeInteger(getOptions.maxResponseBytes) || getOptions.maxResponseBytes <= 0)) {
825
+ return err(serviceError(
826
+ ErrorCodes.INVALID_INPUT,
827
+ "KV maxResponseBytes must be a positive safe integer",
828
+ "kv"
829
+ ));
830
+ }
831
+ const paths = keys.map((key) => this.getFullPath(key, options?.prefix));
832
+ if (new Set(paths).size !== paths.length) {
833
+ return err(serviceError(
834
+ ErrorCodes.INVALID_INPUT,
835
+ "KV batch read received duplicate keys after prefix resolution",
836
+ "kv"
837
+ ));
838
+ }
839
+ try {
840
+ const session = this.context.session;
841
+ const invocationHeaders = this.context.invokeAny(
842
+ session,
843
+ paths.map((path) => ({
844
+ spaceId: session.spaceId,
845
+ service: "kv",
846
+ path,
847
+ action
848
+ }))
849
+ );
850
+ const limitHeaders = {};
851
+ if (getOptions?.maxResponseBytes !== void 0) {
852
+ limitHeaders["x-tinycloud-max-response-bytes"] = String(
853
+ getOptions.maxResponseBytes
854
+ );
855
+ }
856
+ const headers = Array.isArray(invocationHeaders) ? [...invocationHeaders, ...Object.entries(limitHeaders)] : { ...invocationHeaders, ...limitHeaders };
857
+ const response = await this.context.fetch(`${this.host}/invoke`, {
858
+ method: "POST",
859
+ headers,
860
+ signal: this.combineSignals(options?.signal)
861
+ });
862
+ if (!response.ok) {
863
+ const errorText = await response.text();
864
+ if (response.status === 401 || response.status === 403) {
865
+ const { resource, action: requiredAction } = parseAuthError(errorText);
866
+ return err(authUnauthorizedError("kv", errorText, {
867
+ status: response.status,
868
+ ...requiredAction && { requiredAction },
869
+ ...resource && { resource }
870
+ }));
871
+ }
872
+ if (response.status === 413) {
873
+ return err(serviceError(
874
+ ErrorCodes.KV_RESPONSE_TOO_LARGE,
875
+ "A KV batch value exceeds the requested response limit",
876
+ "kv",
877
+ { meta: { status: response.status, statusText: response.statusText } }
878
+ ));
879
+ }
880
+ return err(serviceError(
881
+ ErrorCodes.NETWORK_ERROR,
882
+ `Failed to batch read ${keys.length} key(s): ${response.status} - ${errorText}`,
883
+ "kv",
884
+ { meta: { status: response.status, statusText: response.statusText } }
885
+ ));
886
+ }
887
+ const payload = this.normalizeBatchReadResponse(
888
+ await response.json(),
889
+ paths,
890
+ action === KVAction.GET
891
+ );
892
+ if (!payload) {
893
+ return err(serviceError(
894
+ ErrorCodes.NETWORK_ERROR,
895
+ "KV batch read response did not match the requested keys",
896
+ "kv"
897
+ ));
898
+ }
899
+ const results = payload.results.map((item, index) => {
900
+ if (!item.ok) {
901
+ return {
902
+ key: keys[index],
903
+ result: err(serviceError(item.error.code, item.error.message, "kv"))
904
+ };
905
+ }
906
+ const headers2 = item.headers;
907
+ const data = action === KVAction.HEAD ? void 0 : this.parseBatchValue(
908
+ item.dataBase64,
909
+ headers2,
910
+ getOptions?.raw,
911
+ getOptions?.binary
912
+ );
913
+ return {
914
+ key: keys[index],
915
+ result: ok({
916
+ data,
917
+ headers: this.createBatchResponseHeaders(headers2)
918
+ })
919
+ };
920
+ });
921
+ return ok({ results, count: results.length });
922
+ } catch (error) {
923
+ return err(wrapError("kv", error));
924
+ }
925
+ }
730
926
  /**
731
927
  * Parse response body based on content type.
732
928
  *
@@ -873,6 +1069,13 @@ var KVService = class extends BaseService {
873
1069
  }
874
1070
  });
875
1071
  }
1072
+ async batchGet(keys, options) {
1073
+ return this.withTelemetry(
1074
+ "batchGet",
1075
+ String(keys.length),
1076
+ () => this.batchRead(keys, KVAction.GET, options)
1077
+ );
1078
+ }
876
1079
  /**
877
1080
  * Store a value at a key.
878
1081
  */
@@ -1080,7 +1283,10 @@ var KVService = class extends BaseService {
1080
1283
  KVAction.LIST,
1081
1284
  void 0,
1082
1285
  options?.signal,
1083
- options?.limit === void 0 ? void 0 : { "x-tinycloud-limit": String(options.limit) }
1286
+ options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
1287
+ ...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
1288
+ ...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
1289
+ }
1084
1290
  );
1085
1291
  if (!response.ok) {
1086
1292
  if (response.status === 401) {
@@ -1112,7 +1318,8 @@ var KVService = class extends BaseService {
1112
1318
  }
1113
1319
  return ok({
1114
1320
  keys,
1115
- ...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" }
1321
+ ...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" },
1322
+ ...response.headers.get("x-tinycloud-next-cursor") === null ? {} : { nextCursor: response.headers.get("x-tinycloud-next-cursor") ?? void 0 }
1116
1323
  });
1117
1324
  } catch (error) {
1118
1325
  return err(wrapError("kv", error));
@@ -1232,6 +1439,13 @@ var KVService = class extends BaseService {
1232
1439
  }
1233
1440
  });
1234
1441
  }
1442
+ async batchHead(keys, options) {
1443
+ return this.withTelemetry(
1444
+ "batchHead",
1445
+ String(keys.length),
1446
+ () => this.batchRead(keys, KVAction.HEAD, options)
1447
+ );
1448
+ }
1235
1449
  /**
1236
1450
  * Create a short-lived signed URL for reading a KV object.
1237
1451
  */