@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/index.cjs CHANGED
@@ -1113,6 +1113,31 @@ var KVService = class extends BaseService {
1113
1113
  }
1114
1114
  return void 0;
1115
1115
  }
1116
+ /**
1117
+ * Classify a KV 404 by reading the response body once.
1118
+ *
1119
+ * The server returns 404 both for a genuinely missing key AND for an
1120
+ * un-hosted space (body "Space not found"). Previously get/head/delete
1121
+ * collapsed every 404 to KV_NOT_FOUND before reading the body, so an
1122
+ * un-hosted-space read was indistinguishable from a missing key. We now
1123
+ * preserve status + the "Space not found" body for the un-hosted case (so the
1124
+ * CLI/SDK can normalize it to SPACE_NOT_HOSTED, matching put/list/sql), and
1125
+ * fall through to KV_NOT_FOUND for a real missing key.
1126
+ */
1127
+ async classifyNotFound(response, key) {
1128
+ const errorText = await response.text();
1129
+ if (/space not found/i.test(errorText)) {
1130
+ return err(
1131
+ serviceError(
1132
+ ErrorCodes.KV_NOT_FOUND,
1133
+ `KV ${response.status} - ${errorText}`,
1134
+ "kv",
1135
+ { meta: { status: response.status, statusText: response.statusText } }
1136
+ )
1137
+ );
1138
+ }
1139
+ return err(serviceError(ErrorCodes.KV_NOT_FOUND, `Key not found: ${key}`, "kv"));
1140
+ }
1116
1141
  /**
1117
1142
  * Get the full path with optional prefix.
1118
1143
  *
@@ -1163,6 +1188,38 @@ var KVService = class extends BaseService {
1163
1188
  signal: this.combineSignals(signal)
1164
1189
  });
1165
1190
  }
1191
+ /**
1192
+ * Serialize a single put value into a fetch body.
1193
+ *
1194
+ * Binary values (Blob/ArrayBuffer/typed-array, incl. Node Buffer) are sent as
1195
+ * raw bytes (as a Blob) so they round-trip byte-identically — without this a
1196
+ * Buffer would be JSON.stringify'd into `{"type":"Buffer","data":[...]}`.
1197
+ * Strings are returned unchanged (preserving prior behavior); other values are
1198
+ * JSON-encoded. `contentType` overrides the inferred type for binary values.
1199
+ */
1200
+ serializePutValue(value, contentType) {
1201
+ if (value instanceof Blob) {
1202
+ if (!contentType || value.type === contentType) {
1203
+ return value;
1204
+ }
1205
+ return new Blob([value], { type: contentType });
1206
+ }
1207
+ if (value instanceof ArrayBuffer) {
1208
+ return new Blob([value], {
1209
+ type: contentType ?? "application/octet-stream"
1210
+ });
1211
+ }
1212
+ if (ArrayBuffer.isView(value)) {
1213
+ const view = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
1214
+ return new Blob([view], {
1215
+ type: contentType ?? "application/octet-stream"
1216
+ });
1217
+ }
1218
+ if (typeof value === "string") {
1219
+ return contentType ? new Blob([value], { type: contentType }) : value;
1220
+ }
1221
+ return JSON.stringify(value);
1222
+ }
1166
1223
  serializeBatchPutValue(item) {
1167
1224
  const contentType = item.contentType;
1168
1225
  if (item.value instanceof Blob) {
@@ -1232,10 +1289,13 @@ var KVService = class extends BaseService {
1232
1289
  * @param raw - Whether to return raw text
1233
1290
  * @returns Parsed data
1234
1291
  */
1235
- async parseResponse(response, raw = false) {
1292
+ async parseResponse(response, raw = false, binary = false) {
1236
1293
  if (!response.ok) {
1237
1294
  return void 0;
1238
1295
  }
1296
+ if (binary) {
1297
+ return new Uint8Array(await response.arrayBuffer());
1298
+ }
1239
1299
  if (raw) {
1240
1300
  return await response.text();
1241
1301
  }
@@ -1324,13 +1384,7 @@ var KVService = class extends BaseService {
1324
1384
  }));
1325
1385
  }
1326
1386
  if (response.status === 404) {
1327
- return err(
1328
- serviceError(
1329
- ErrorCodes.KV_NOT_FOUND,
1330
- `Key not found: ${key}`,
1331
- "kv"
1332
- )
1333
- );
1387
+ return this.classifyNotFound(response, key);
1334
1388
  }
1335
1389
  const errorText = await response.text();
1336
1390
  return err(
@@ -1342,7 +1396,11 @@ var KVService = class extends BaseService {
1342
1396
  )
1343
1397
  );
1344
1398
  }
1345
- const data = await this.parseResponse(response, options?.raw);
1399
+ const data = await this.parseResponse(
1400
+ response,
1401
+ options?.raw,
1402
+ options?.binary
1403
+ );
1346
1404
  return ok({
1347
1405
  data,
1348
1406
  headers: this.createResponseHeaders(response.headers)
@@ -1361,12 +1419,7 @@ var KVService = class extends BaseService {
1361
1419
  return err(authRequiredError("kv"));
1362
1420
  }
1363
1421
  const path = this.getFullPath(key, options?.prefix);
1364
- let body;
1365
- if (typeof value === "string") {
1366
- body = value;
1367
- } else {
1368
- body = JSON.stringify(value);
1369
- }
1422
+ const body = this.serializePutValue(value, options?.contentType);
1370
1423
  try {
1371
1424
  const response = await this.invokeOperation(
1372
1425
  path,
@@ -1592,13 +1645,7 @@ var KVService = class extends BaseService {
1592
1645
  }));
1593
1646
  }
1594
1647
  if (response.status === 404) {
1595
- return err(
1596
- serviceError(
1597
- ErrorCodes.KV_NOT_FOUND,
1598
- `Key not found: ${key}`,
1599
- "kv"
1600
- )
1601
- );
1648
+ return this.classifyNotFound(response, key);
1602
1649
  }
1603
1650
  const errorText = await response.text();
1604
1651
  return err(
@@ -1643,13 +1690,7 @@ var KVService = class extends BaseService {
1643
1690
  }));
1644
1691
  }
1645
1692
  if (response.status === 404) {
1646
- return err(
1647
- serviceError(
1648
- ErrorCodes.KV_NOT_FOUND,
1649
- `Key not found: ${key}`,
1650
- "kv"
1651
- )
1652
- );
1693
+ return this.classifyNotFound(response, key);
1653
1694
  }
1654
1695
  const errorText = await response.text();
1655
1696
  return err(