@tinycloud/sdk-services 2.3.0 → 2.4.0-beta.2

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/kv/index.js CHANGED
@@ -514,6 +514,31 @@ var KVService = class extends BaseService {
514
514
  }
515
515
  return void 0;
516
516
  }
517
+ /**
518
+ * Classify a KV 404 by reading the response body once.
519
+ *
520
+ * The server returns 404 both for a genuinely missing key AND for an
521
+ * un-hosted space (body "Space not found"). Previously get/head/delete
522
+ * collapsed every 404 to KV_NOT_FOUND before reading the body, so an
523
+ * un-hosted-space read was indistinguishable from a missing key. We now
524
+ * preserve status + the "Space not found" body for the un-hosted case (so the
525
+ * CLI/SDK can normalize it to SPACE_NOT_HOSTED, matching put/list/sql), and
526
+ * fall through to KV_NOT_FOUND for a real missing key.
527
+ */
528
+ async classifyNotFound(response, key) {
529
+ const errorText = await response.text();
530
+ if (/space not found/i.test(errorText)) {
531
+ return err(
532
+ serviceError(
533
+ ErrorCodes.KV_NOT_FOUND,
534
+ `KV ${response.status} - ${errorText}`,
535
+ "kv",
536
+ { meta: { status: response.status, statusText: response.statusText } }
537
+ )
538
+ );
539
+ }
540
+ return err(serviceError(ErrorCodes.KV_NOT_FOUND, `Key not found: ${key}`, "kv"));
541
+ }
517
542
  /**
518
543
  * Get the full path with optional prefix.
519
544
  *
@@ -564,6 +589,38 @@ var KVService = class extends BaseService {
564
589
  signal: this.combineSignals(signal)
565
590
  });
566
591
  }
592
+ /**
593
+ * Serialize a single put value into a fetch body.
594
+ *
595
+ * Binary values (Blob/ArrayBuffer/typed-array, incl. Node Buffer) are sent as
596
+ * raw bytes (as a Blob) so they round-trip byte-identically — without this a
597
+ * Buffer would be JSON.stringify'd into `{"type":"Buffer","data":[...]}`.
598
+ * Strings are returned unchanged (preserving prior behavior); other values are
599
+ * JSON-encoded. `contentType` overrides the inferred type for binary values.
600
+ */
601
+ serializePutValue(value, contentType) {
602
+ if (value instanceof Blob) {
603
+ if (!contentType || value.type === contentType) {
604
+ return value;
605
+ }
606
+ return new Blob([value], { type: contentType });
607
+ }
608
+ if (value instanceof ArrayBuffer) {
609
+ return new Blob([value], {
610
+ type: contentType ?? "application/octet-stream"
611
+ });
612
+ }
613
+ if (ArrayBuffer.isView(value)) {
614
+ const view = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
615
+ return new Blob([view], {
616
+ type: contentType ?? "application/octet-stream"
617
+ });
618
+ }
619
+ if (typeof value === "string") {
620
+ return contentType ? new Blob([value], { type: contentType }) : value;
621
+ }
622
+ return JSON.stringify(value);
623
+ }
567
624
  serializeBatchPutValue(item) {
568
625
  const contentType = item.contentType;
569
626
  if (item.value instanceof Blob) {
@@ -633,10 +690,13 @@ var KVService = class extends BaseService {
633
690
  * @param raw - Whether to return raw text
634
691
  * @returns Parsed data
635
692
  */
636
- async parseResponse(response, raw = false) {
693
+ async parseResponse(response, raw = false, binary = false) {
637
694
  if (!response.ok) {
638
695
  return void 0;
639
696
  }
697
+ if (binary) {
698
+ return new Uint8Array(await response.arrayBuffer());
699
+ }
640
700
  if (raw) {
641
701
  return await response.text();
642
702
  }
@@ -725,13 +785,7 @@ var KVService = class extends BaseService {
725
785
  }));
726
786
  }
727
787
  if (response.status === 404) {
728
- return err(
729
- serviceError(
730
- ErrorCodes.KV_NOT_FOUND,
731
- `Key not found: ${key}`,
732
- "kv"
733
- )
734
- );
788
+ return this.classifyNotFound(response, key);
735
789
  }
736
790
  const errorText = await response.text();
737
791
  return err(
@@ -743,7 +797,11 @@ var KVService = class extends BaseService {
743
797
  )
744
798
  );
745
799
  }
746
- const data = await this.parseResponse(response, options?.raw);
800
+ const data = await this.parseResponse(
801
+ response,
802
+ options?.raw,
803
+ options?.binary
804
+ );
747
805
  return ok({
748
806
  data,
749
807
  headers: this.createResponseHeaders(response.headers)
@@ -762,12 +820,7 @@ var KVService = class extends BaseService {
762
820
  return err(authRequiredError("kv"));
763
821
  }
764
822
  const path = this.getFullPath(key, options?.prefix);
765
- let body;
766
- if (typeof value === "string") {
767
- body = value;
768
- } else {
769
- body = JSON.stringify(value);
770
- }
823
+ const body = this.serializePutValue(value, options?.contentType);
771
824
  try {
772
825
  const response = await this.invokeOperation(
773
826
  path,
@@ -993,13 +1046,7 @@ var KVService = class extends BaseService {
993
1046
  }));
994
1047
  }
995
1048
  if (response.status === 404) {
996
- return err(
997
- serviceError(
998
- ErrorCodes.KV_NOT_FOUND,
999
- `Key not found: ${key}`,
1000
- "kv"
1001
- )
1002
- );
1049
+ return this.classifyNotFound(response, key);
1003
1050
  }
1004
1051
  const errorText = await response.text();
1005
1052
  return err(
@@ -1044,13 +1091,7 @@ var KVService = class extends BaseService {
1044
1091
  }));
1045
1092
  }
1046
1093
  if (response.status === 404) {
1047
- return err(
1048
- serviceError(
1049
- ErrorCodes.KV_NOT_FOUND,
1050
- `Key not found: ${key}`,
1051
- "kv"
1052
- )
1053
- );
1094
+ return this.classifyNotFound(response, key);
1054
1095
  }
1055
1096
  const errorText = await response.text();
1056
1097
  return err(