@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.cjs CHANGED
@@ -543,6 +543,31 @@ var KVService = class extends BaseService {
543
543
  }
544
544
  return void 0;
545
545
  }
546
+ /**
547
+ * Classify a KV 404 by reading the response body once.
548
+ *
549
+ * The server returns 404 both for a genuinely missing key AND for an
550
+ * un-hosted space (body "Space not found"). Previously get/head/delete
551
+ * collapsed every 404 to KV_NOT_FOUND before reading the body, so an
552
+ * un-hosted-space read was indistinguishable from a missing key. We now
553
+ * preserve status + the "Space not found" body for the un-hosted case (so the
554
+ * CLI/SDK can normalize it to SPACE_NOT_HOSTED, matching put/list/sql), and
555
+ * fall through to KV_NOT_FOUND for a real missing key.
556
+ */
557
+ async classifyNotFound(response, key) {
558
+ const errorText = await response.text();
559
+ if (/space not found/i.test(errorText)) {
560
+ return err(
561
+ serviceError(
562
+ ErrorCodes.KV_NOT_FOUND,
563
+ `KV ${response.status} - ${errorText}`,
564
+ "kv",
565
+ { meta: { status: response.status, statusText: response.statusText } }
566
+ )
567
+ );
568
+ }
569
+ return err(serviceError(ErrorCodes.KV_NOT_FOUND, `Key not found: ${key}`, "kv"));
570
+ }
546
571
  /**
547
572
  * Get the full path with optional prefix.
548
573
  *
@@ -593,6 +618,38 @@ var KVService = class extends BaseService {
593
618
  signal: this.combineSignals(signal)
594
619
  });
595
620
  }
621
+ /**
622
+ * Serialize a single put value into a fetch body.
623
+ *
624
+ * Binary values (Blob/ArrayBuffer/typed-array, incl. Node Buffer) are sent as
625
+ * raw bytes (as a Blob) so they round-trip byte-identically — without this a
626
+ * Buffer would be JSON.stringify'd into `{"type":"Buffer","data":[...]}`.
627
+ * Strings are returned unchanged (preserving prior behavior); other values are
628
+ * JSON-encoded. `contentType` overrides the inferred type for binary values.
629
+ */
630
+ serializePutValue(value, contentType) {
631
+ if (value instanceof Blob) {
632
+ if (!contentType || value.type === contentType) {
633
+ return value;
634
+ }
635
+ return new Blob([value], { type: contentType });
636
+ }
637
+ if (value instanceof ArrayBuffer) {
638
+ return new Blob([value], {
639
+ type: contentType ?? "application/octet-stream"
640
+ });
641
+ }
642
+ if (ArrayBuffer.isView(value)) {
643
+ const view = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
644
+ return new Blob([view], {
645
+ type: contentType ?? "application/octet-stream"
646
+ });
647
+ }
648
+ if (typeof value === "string") {
649
+ return contentType ? new Blob([value], { type: contentType }) : value;
650
+ }
651
+ return JSON.stringify(value);
652
+ }
596
653
  serializeBatchPutValue(item) {
597
654
  const contentType = item.contentType;
598
655
  if (item.value instanceof Blob) {
@@ -662,10 +719,13 @@ var KVService = class extends BaseService {
662
719
  * @param raw - Whether to return raw text
663
720
  * @returns Parsed data
664
721
  */
665
- async parseResponse(response, raw = false) {
722
+ async parseResponse(response, raw = false, binary = false) {
666
723
  if (!response.ok) {
667
724
  return void 0;
668
725
  }
726
+ if (binary) {
727
+ return new Uint8Array(await response.arrayBuffer());
728
+ }
669
729
  if (raw) {
670
730
  return await response.text();
671
731
  }
@@ -754,13 +814,7 @@ var KVService = class extends BaseService {
754
814
  }));
755
815
  }
756
816
  if (response.status === 404) {
757
- return err(
758
- serviceError(
759
- ErrorCodes.KV_NOT_FOUND,
760
- `Key not found: ${key}`,
761
- "kv"
762
- )
763
- );
817
+ return this.classifyNotFound(response, key);
764
818
  }
765
819
  const errorText = await response.text();
766
820
  return err(
@@ -772,7 +826,11 @@ var KVService = class extends BaseService {
772
826
  )
773
827
  );
774
828
  }
775
- const data = await this.parseResponse(response, options?.raw);
829
+ const data = await this.parseResponse(
830
+ response,
831
+ options?.raw,
832
+ options?.binary
833
+ );
776
834
  return ok({
777
835
  data,
778
836
  headers: this.createResponseHeaders(response.headers)
@@ -791,12 +849,7 @@ var KVService = class extends BaseService {
791
849
  return err(authRequiredError("kv"));
792
850
  }
793
851
  const path = this.getFullPath(key, options?.prefix);
794
- let body;
795
- if (typeof value === "string") {
796
- body = value;
797
- } else {
798
- body = JSON.stringify(value);
799
- }
852
+ const body = this.serializePutValue(value, options?.contentType);
800
853
  try {
801
854
  const response = await this.invokeOperation(
802
855
  path,
@@ -1022,13 +1075,7 @@ var KVService = class extends BaseService {
1022
1075
  }));
1023
1076
  }
1024
1077
  if (response.status === 404) {
1025
- return err(
1026
- serviceError(
1027
- ErrorCodes.KV_NOT_FOUND,
1028
- `Key not found: ${key}`,
1029
- "kv"
1030
- )
1031
- );
1078
+ return this.classifyNotFound(response, key);
1032
1079
  }
1033
1080
  const errorText = await response.text();
1034
1081
  return err(
@@ -1073,13 +1120,7 @@ var KVService = class extends BaseService {
1073
1120
  }));
1074
1121
  }
1075
1122
  if (response.status === 404) {
1076
- return err(
1077
- serviceError(
1078
- ErrorCodes.KV_NOT_FOUND,
1079
- `Key not found: ${key}`,
1080
- "kv"
1081
- )
1082
- );
1123
+ return this.classifyNotFound(response, key);
1083
1124
  }
1084
1125
  const errorText = await response.text();
1085
1126
  return err(