@tinycloud/sdk-services 2.3.0-beta.5 → 2.3.0-beta.7

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,4 +1,4 @@
1
- import { e as Result, c as IService, B as BaseService } from '../BaseService-C_iXlTeN.cjs';
1
+ import { e as Result, c as IService, B as BaseService } from '../BaseService-DZ2hBJeD.cjs';
2
2
 
3
3
  /**
4
4
  * KV Service Types
@@ -76,6 +76,57 @@ interface KVPutOptions {
76
76
  */
77
77
  signal?: AbortSignal;
78
78
  }
79
+ /**
80
+ * One entry in a KV batch put request.
81
+ */
82
+ interface KVBatchPutItem {
83
+ /**
84
+ * The key to store under.
85
+ */
86
+ key: string;
87
+ /**
88
+ * The value to store.
89
+ *
90
+ * Objects are JSON stringified. Strings are stored as text. Binary values
91
+ * should be supplied as Blob, ArrayBuffer, or Uint8Array.
92
+ */
93
+ value: unknown;
94
+ /**
95
+ * Content type for this item. Defaults to application/json for objects and
96
+ * application/octet-stream for binary values.
97
+ */
98
+ contentType?: string;
99
+ }
100
+ /**
101
+ * Options for KV batch put operations.
102
+ */
103
+ interface KVBatchPutOptions {
104
+ /**
105
+ * Override the default prefix for all entries in this batch.
106
+ */
107
+ prefix?: string;
108
+ /**
109
+ * Custom timeout for this operation in milliseconds.
110
+ */
111
+ timeout?: number;
112
+ /**
113
+ * Custom abort signal for this operation.
114
+ */
115
+ signal?: AbortSignal;
116
+ }
117
+ /**
118
+ * Response from KV batch put operations.
119
+ */
120
+ interface KVBatchPutResponse {
121
+ /**
122
+ * Keys successfully written by the batch.
123
+ */
124
+ written: string[];
125
+ /**
126
+ * Number of written keys.
127
+ */
128
+ count: number;
129
+ }
79
130
  /**
80
131
  * Options for KV list operations.
81
132
  */
@@ -343,6 +394,10 @@ interface IPrefixedKVService {
343
394
  * ```
344
395
  */
345
396
  put(key: string, value: unknown, options?: Omit<KVPutOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
397
+ /**
398
+ * Store multiple values within this prefix in one TinyCloud KV invocation.
399
+ */
400
+ batchPut(items: KVBatchPutItem[], options?: Omit<KVBatchPutOptions, 'prefix'>): Promise<Result<KVBatchPutResponse>>;
346
401
  /**
347
402
  * List keys within this prefix.
348
403
  *
@@ -431,6 +486,7 @@ interface IPrefixedKVService {
431
486
  interface IKVServiceLike {
432
487
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
433
488
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
489
+ batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
434
490
  list(options?: KVListOptions): Promise<Result<KVListResponse>>;
435
491
  delete(key: string, options?: KVDeleteOptions): Promise<Result<void>>;
436
492
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
@@ -503,6 +559,10 @@ declare class PrefixedKVService implements IPrefixedKVService {
503
559
  * Store a value at a key.
504
560
  */
505
561
  put(key: string, value: unknown, options?: Omit<KVPutOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
562
+ /**
563
+ * Store multiple values within this prefix in one TinyCloud KV invocation.
564
+ */
565
+ batchPut(items: KVBatchPutItem[], options?: Omit<KVBatchPutOptions, 'prefix'>): Promise<Result<KVBatchPutResponse>>;
506
566
  /**
507
567
  * List keys within this prefix.
508
568
  */
@@ -590,6 +650,17 @@ interface IKVService extends IService {
590
650
  * ```
591
651
  */
592
652
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
653
+ /**
654
+ * Store multiple values in one TinyCloud KV invocation.
655
+ *
656
+ * The batch is authorized as one invocation containing one `tinycloud.kv/put`
657
+ * capability per key. The node commits the whole batch or rejects it.
658
+ *
659
+ * @param items - Entries to write
660
+ * @param options - Optional batch configuration
661
+ * @returns Result with the written keys and count
662
+ */
663
+ batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
593
664
  /**
594
665
  * List keys with optional prefix filtering.
595
666
  *
@@ -757,6 +828,8 @@ declare class KVService extends BaseService implements IKVService {
757
828
  * @returns Fetch response
758
829
  */
759
830
  private invokeOperation;
831
+ private serializeBatchPutValue;
832
+ private normalizeBatchPutResponse;
760
833
  /**
761
834
  * Create KVResponseHeaders from fetch response headers.
762
835
  *
@@ -782,6 +855,10 @@ declare class KVService extends BaseService implements IKVService {
782
855
  * Store a value at a key.
783
856
  */
784
857
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
858
+ /**
859
+ * Store multiple values in one TinyCloud KV invocation.
860
+ */
861
+ batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
785
862
  /**
786
863
  * List keys with optional prefix filtering.
787
864
  */
@@ -843,4 +920,4 @@ declare class KVService extends BaseService implements IKVService {
843
920
  withPrefix(prefix: string): IPrefixedKVService;
844
921
  }
845
922
 
846
- export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, type IKVService, type IPrefixedKVService, KVAction, type KVActionType, type KVCreateSignedReadUrlOptions, type KVDeleteOptions, type KVGetOptions, type KVHeadOptions, type KVListOptions, type KVListResponse, type KVPutOptions, type KVResponse, type KVResponseHeaders, KVService, type KVServiceConfig, type KVSignedReadUrlResponse, PrefixedKVService };
923
+ 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 };
@@ -1,4 +1,4 @@
1
- import { e as Result, c as IService, B as BaseService } from '../BaseService-C_iXlTeN.js';
1
+ import { e as Result, c as IService, B as BaseService } from '../BaseService-DZ2hBJeD.js';
2
2
 
3
3
  /**
4
4
  * KV Service Types
@@ -76,6 +76,57 @@ interface KVPutOptions {
76
76
  */
77
77
  signal?: AbortSignal;
78
78
  }
79
+ /**
80
+ * One entry in a KV batch put request.
81
+ */
82
+ interface KVBatchPutItem {
83
+ /**
84
+ * The key to store under.
85
+ */
86
+ key: string;
87
+ /**
88
+ * The value to store.
89
+ *
90
+ * Objects are JSON stringified. Strings are stored as text. Binary values
91
+ * should be supplied as Blob, ArrayBuffer, or Uint8Array.
92
+ */
93
+ value: unknown;
94
+ /**
95
+ * Content type for this item. Defaults to application/json for objects and
96
+ * application/octet-stream for binary values.
97
+ */
98
+ contentType?: string;
99
+ }
100
+ /**
101
+ * Options for KV batch put operations.
102
+ */
103
+ interface KVBatchPutOptions {
104
+ /**
105
+ * Override the default prefix for all entries in this batch.
106
+ */
107
+ prefix?: string;
108
+ /**
109
+ * Custom timeout for this operation in milliseconds.
110
+ */
111
+ timeout?: number;
112
+ /**
113
+ * Custom abort signal for this operation.
114
+ */
115
+ signal?: AbortSignal;
116
+ }
117
+ /**
118
+ * Response from KV batch put operations.
119
+ */
120
+ interface KVBatchPutResponse {
121
+ /**
122
+ * Keys successfully written by the batch.
123
+ */
124
+ written: string[];
125
+ /**
126
+ * Number of written keys.
127
+ */
128
+ count: number;
129
+ }
79
130
  /**
80
131
  * Options for KV list operations.
81
132
  */
@@ -343,6 +394,10 @@ interface IPrefixedKVService {
343
394
  * ```
344
395
  */
345
396
  put(key: string, value: unknown, options?: Omit<KVPutOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
397
+ /**
398
+ * Store multiple values within this prefix in one TinyCloud KV invocation.
399
+ */
400
+ batchPut(items: KVBatchPutItem[], options?: Omit<KVBatchPutOptions, 'prefix'>): Promise<Result<KVBatchPutResponse>>;
346
401
  /**
347
402
  * List keys within this prefix.
348
403
  *
@@ -431,6 +486,7 @@ interface IPrefixedKVService {
431
486
  interface IKVServiceLike {
432
487
  get<T = unknown>(key: string, options?: KVGetOptions): Promise<Result<KVResponse<T>>>;
433
488
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
489
+ batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
434
490
  list(options?: KVListOptions): Promise<Result<KVListResponse>>;
435
491
  delete(key: string, options?: KVDeleteOptions): Promise<Result<void>>;
436
492
  head(key: string, options?: KVHeadOptions): Promise<Result<KVResponse<void>>>;
@@ -503,6 +559,10 @@ declare class PrefixedKVService implements IPrefixedKVService {
503
559
  * Store a value at a key.
504
560
  */
505
561
  put(key: string, value: unknown, options?: Omit<KVPutOptions, 'prefix'>): Promise<Result<KVResponse<void>>>;
562
+ /**
563
+ * Store multiple values within this prefix in one TinyCloud KV invocation.
564
+ */
565
+ batchPut(items: KVBatchPutItem[], options?: Omit<KVBatchPutOptions, 'prefix'>): Promise<Result<KVBatchPutResponse>>;
506
566
  /**
507
567
  * List keys within this prefix.
508
568
  */
@@ -590,6 +650,17 @@ interface IKVService extends IService {
590
650
  * ```
591
651
  */
592
652
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
653
+ /**
654
+ * Store multiple values in one TinyCloud KV invocation.
655
+ *
656
+ * The batch is authorized as one invocation containing one `tinycloud.kv/put`
657
+ * capability per key. The node commits the whole batch or rejects it.
658
+ *
659
+ * @param items - Entries to write
660
+ * @param options - Optional batch configuration
661
+ * @returns Result with the written keys and count
662
+ */
663
+ batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
593
664
  /**
594
665
  * List keys with optional prefix filtering.
595
666
  *
@@ -757,6 +828,8 @@ declare class KVService extends BaseService implements IKVService {
757
828
  * @returns Fetch response
758
829
  */
759
830
  private invokeOperation;
831
+ private serializeBatchPutValue;
832
+ private normalizeBatchPutResponse;
760
833
  /**
761
834
  * Create KVResponseHeaders from fetch response headers.
762
835
  *
@@ -782,6 +855,10 @@ declare class KVService extends BaseService implements IKVService {
782
855
  * Store a value at a key.
783
856
  */
784
857
  put(key: string, value: unknown, options?: KVPutOptions): Promise<Result<KVResponse<void>>>;
858
+ /**
859
+ * Store multiple values in one TinyCloud KV invocation.
860
+ */
861
+ batchPut(items: KVBatchPutItem[], options?: KVBatchPutOptions): Promise<Result<KVBatchPutResponse>>;
785
862
  /**
786
863
  * List keys with optional prefix filtering.
787
864
  */
@@ -843,4 +920,4 @@ declare class KVService extends BaseService implements IKVService {
843
920
  withPrefix(prefix: string): IPrefixedKVService;
844
921
  }
845
922
 
846
- export { DEFAULT_SIGNED_READ_URL_EXPIRY_MS, type IKVService, type IPrefixedKVService, KVAction, type KVActionType, type KVCreateSignedReadUrlOptions, type KVDeleteOptions, type KVGetOptions, type KVHeadOptions, type KVListOptions, type KVListResponse, type KVPutOptions, type KVResponse, type KVResponseHeaders, KVService, type KVServiceConfig, type KVSignedReadUrlResponse, PrefixedKVService };
923
+ 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 };
package/dist/kv/index.js CHANGED
@@ -361,6 +361,18 @@ var PrefixedKVService = class _PrefixedKVService {
361
361
  const fullKey = this.getFullKey(key);
362
362
  return this._kv.put(fullKey, value, { ...options, prefix: "" });
363
363
  }
364
+ /**
365
+ * Store multiple values within this prefix in one TinyCloud KV invocation.
366
+ */
367
+ async batchPut(items, options) {
368
+ return this._kv.batchPut(
369
+ items.map((item) => ({
370
+ ...item,
371
+ key: this.getFullKey(item.key)
372
+ })),
373
+ { ...options, prefix: "" }
374
+ );
375
+ }
364
376
  /**
365
377
  * List keys within this prefix.
366
378
  */
@@ -414,6 +426,12 @@ var KVAction = {
414
426
  };
415
427
 
416
428
  // src/kv/KVService.ts
429
+ function encodeKvBatchPartName(path) {
430
+ return encodeURIComponent(path).replace(
431
+ /[!'()*]/g,
432
+ (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`
433
+ );
434
+ }
417
435
  var KVService = class extends BaseService {
418
436
  /**
419
437
  * Create a new KVService instance.
@@ -522,6 +540,53 @@ var KVService = class extends BaseService {
522
540
  signal: this.combineSignals(signal)
523
541
  });
524
542
  }
543
+ serializeBatchPutValue(item) {
544
+ const contentType = item.contentType;
545
+ if (item.value instanceof Blob) {
546
+ if (!contentType || item.value.type === contentType) {
547
+ return item.value;
548
+ }
549
+ return new Blob([item.value], { type: contentType });
550
+ }
551
+ if (item.value instanceof ArrayBuffer) {
552
+ return new Blob([item.value], {
553
+ type: contentType ?? "application/octet-stream"
554
+ });
555
+ }
556
+ if (ArrayBuffer.isView(item.value)) {
557
+ const value = item.value;
558
+ const bytes = new Uint8Array(value.byteLength);
559
+ bytes.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
560
+ return new Blob([bytes], {
561
+ type: contentType ?? "application/octet-stream"
562
+ });
563
+ }
564
+ if (typeof item.value === "string") {
565
+ return new Blob([item.value], {
566
+ type: contentType ?? "text/plain;charset=UTF-8"
567
+ });
568
+ }
569
+ const json = JSON.stringify(item.value);
570
+ if (json === void 0) {
571
+ throw new Error(`Cannot JSON serialize KV batch value for key "${item.key}"`);
572
+ }
573
+ return new Blob([json], {
574
+ type: contentType ?? "application/json"
575
+ });
576
+ }
577
+ normalizeBatchPutResponse(data) {
578
+ if (!data || typeof data !== "object") {
579
+ return void 0;
580
+ }
581
+ const response = data;
582
+ if (!Array.isArray(response.written) || !response.written.every((key) => typeof key === "string") || typeof response.count !== "number") {
583
+ return void 0;
584
+ }
585
+ return {
586
+ written: response.written,
587
+ count: response.count
588
+ };
589
+ }
525
590
  /**
526
591
  * Create KVResponseHeaders from fetch response headers.
527
592
  *
@@ -723,6 +788,107 @@ var KVService = class extends BaseService {
723
788
  }
724
789
  });
725
790
  }
791
+ /**
792
+ * Store multiple values in one TinyCloud KV invocation.
793
+ */
794
+ async batchPut(items, options) {
795
+ return this.withTelemetry("batchPut", String(items.length), async () => {
796
+ if (!this.requireAuth()) {
797
+ return err(authRequiredError("kv"));
798
+ }
799
+ if (items.length === 0) {
800
+ return ok({ written: [], count: 0 });
801
+ }
802
+ if (!this.context.invokeAny) {
803
+ return err(
804
+ serviceError(
805
+ ErrorCodes.INVALID_INPUT,
806
+ "KV batchPut requires SDK runtime support for multi-resource invocations",
807
+ "kv"
808
+ )
809
+ );
810
+ }
811
+ const session = this.context.session;
812
+ const paths = items.map((item) => this.getFullPath(item.key, options?.prefix));
813
+ const seen = /* @__PURE__ */ new Set();
814
+ for (const path of paths) {
815
+ if (seen.has(path)) {
816
+ return err(
817
+ serviceError(
818
+ ErrorCodes.INVALID_INPUT,
819
+ `KV batchPut received duplicate key after prefix resolution: ${path}`,
820
+ "kv"
821
+ )
822
+ );
823
+ }
824
+ seen.add(path);
825
+ }
826
+ try {
827
+ const body = new FormData();
828
+ for (let index = 0; index < items.length; index++) {
829
+ body.append(
830
+ encodeKvBatchPartName(paths[index]),
831
+ this.serializeBatchPutValue(items[index])
832
+ );
833
+ }
834
+ const headers = this.context.invokeAny(
835
+ session,
836
+ paths.map((path) => ({
837
+ spaceId: session.spaceId,
838
+ service: "kv",
839
+ path,
840
+ action: KVAction.PUT
841
+ }))
842
+ );
843
+ const response = await this.context.fetch(`${this.host}/invoke`, {
844
+ method: "POST",
845
+ headers,
846
+ body,
847
+ signal: this.combineSignals(options?.signal)
848
+ });
849
+ if (!response.ok) {
850
+ const errorText = await response.text();
851
+ if (response.status === 401 || response.status === 403) {
852
+ const { resource, action } = parseAuthError(errorText);
853
+ return err(authUnauthorizedError("kv", errorText, {
854
+ status: response.status,
855
+ ...action && { requiredAction: action },
856
+ ...resource && { resource }
857
+ }));
858
+ }
859
+ const quotaError = this.handleQuotaErrorResponse(
860
+ response,
861
+ errorText,
862
+ "batch"
863
+ );
864
+ if (quotaError) {
865
+ return quotaError;
866
+ }
867
+ return err(
868
+ serviceError(
869
+ ErrorCodes.KV_WRITE_FAILED,
870
+ `Failed to batch put ${items.length} key(s): ${response.status} - ${errorText}`,
871
+ "kv",
872
+ { meta: { status: response.status, statusText: response.statusText } }
873
+ )
874
+ );
875
+ }
876
+ const batchResponse = this.normalizeBatchPutResponse(await response.json());
877
+ if (!batchResponse || batchResponse.count !== batchResponse.written.length) {
878
+ return err(
879
+ serviceError(
880
+ ErrorCodes.NETWORK_ERROR,
881
+ "KV batchPut response did not include matching written keys and count",
882
+ "kv"
883
+ )
884
+ );
885
+ }
886
+ return ok(batchResponse);
887
+ } catch (error) {
888
+ return err(wrapError("kv", error));
889
+ }
890
+ });
891
+ }
726
892
  /**
727
893
  * List keys with optional prefix filtering.
728
894
  */