@tinycloud/sdk-services 2.10.0-beta.0 → 2.11.0-beta.5

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,5 +1,5 @@
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
@@ -179,6 +179,8 @@ interface KVListOptions {
179
179
  raw?: boolean;
180
180
  /** Maximum number of keys the node may return. */
181
181
  limit?: number;
182
+ /** Opaque scope-bound cursor returned by a previous bounded list. */
183
+ cursor?: string;
182
184
  /**
183
185
  * Custom timeout for this operation in milliseconds.
184
186
  */
@@ -318,6 +320,8 @@ interface KVListResponse {
318
320
  keys: string[];
319
321
  /** True when more matching keys exist than the requested limit. */
320
322
  truncated?: boolean;
323
+ /** Opaque cursor for the next page, when the node returned one. */
324
+ nextCursor?: string;
321
325
  }
322
326
  /**
323
327
  * Response from signed KV read URL creation.
@@ -1,5 +1,5 @@
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
@@ -179,6 +179,8 @@ interface KVListOptions {
179
179
  raw?: boolean;
180
180
  /** Maximum number of keys the node may return. */
181
181
  limit?: number;
182
+ /** Opaque scope-bound cursor returned by a previous bounded list. */
183
+ cursor?: string;
182
184
  /**
183
185
  * Custom timeout for this operation in milliseconds.
184
186
  */
@@ -318,6 +320,8 @@ interface KVListResponse {
318
320
  keys: string[];
319
321
  /** True when more matching keys exist than the requested limit. */
320
322
  truncated?: boolean;
323
+ /** Opaque cursor for the next page, when the node returned one. */
324
+ nextCursor?: string;
321
325
  }
322
326
  /**
323
327
  * Response from signed KV read URL creation.
package/dist/kv/index.js CHANGED
@@ -1192,6 +1192,7 @@ var KVService = class extends BaseService {
1192
1192
  }
1193
1193
  seen.add(path);
1194
1194
  }
1195
+ let requestMayHaveDispatched = false;
1195
1196
  try {
1196
1197
  const body = new FormData();
1197
1198
  for (let index = 0; index < items.length; index++) {
@@ -1209,14 +1210,31 @@ var KVService = class extends BaseService {
1209
1210
  action: KVAction.PUT
1210
1211
  }))
1211
1212
  );
1212
- const response = await this.context.fetch(`${this.host}/invoke`, {
1213
+ const url = `${this.host}/invoke`;
1214
+ const init = {
1213
1215
  method: "POST",
1214
1216
  headers,
1215
1217
  body,
1216
1218
  signal: this.combineSignals(options?.signal)
1217
- });
1219
+ };
1220
+ const fetchFn = this.context.fetch;
1221
+ requestMayHaveDispatched = true;
1222
+ const response = await fetchFn(url, init);
1218
1223
  if (!response.ok) {
1219
- const errorText = await response.text();
1224
+ let errorText;
1225
+ try {
1226
+ errorText = await response.text();
1227
+ } catch (textError) {
1228
+ const cause = textError instanceof Error ? textError : new Error(String(textError));
1229
+ return err(
1230
+ serviceError(
1231
+ ErrorCodes.KV_WRITE_FAILED,
1232
+ `Failed to batch put ${items.length} key(s): ${response.status} - <response body could not be read: ${cause.message}>`,
1233
+ "kv",
1234
+ { cause, meta: { status: response.status, statusText: response.statusText } }
1235
+ )
1236
+ );
1237
+ }
1220
1238
  if (response.status === 401 || response.status === 403) {
1221
1239
  const { resource, action } = parseAuthError(errorText);
1222
1240
  return err(authUnauthorizedError("kv", errorText, {
@@ -1242,19 +1260,73 @@ var KVService = class extends BaseService {
1242
1260
  )
1243
1261
  );
1244
1262
  }
1245
- const batchResponse = this.normalizeBatchPutResponse(await response.json());
1246
- if (!batchResponse || batchResponse.count !== batchResponse.written.length) {
1263
+ let rawBody;
1264
+ try {
1265
+ rawBody = await response.json();
1266
+ } catch (jsonError) {
1267
+ const cause = jsonError instanceof Error ? jsonError : new Error(String(jsonError));
1268
+ return err(
1269
+ serviceError(
1270
+ ErrorCodes.NETWORK_ERROR,
1271
+ `KV batchPut response was not valid JSON: ${cause.message}`,
1272
+ "kv",
1273
+ {
1274
+ cause,
1275
+ meta: {
1276
+ requestMayHaveDispatched: true,
1277
+ responseReceived: true,
1278
+ status: response.status,
1279
+ outcome: "batch-unconfirmed"
1280
+ }
1281
+ }
1282
+ )
1283
+ );
1284
+ }
1285
+ const batchResponse = this.normalizeBatchPutResponse(rawBody);
1286
+ if (!batchResponse) {
1247
1287
  return err(
1248
1288
  serviceError(
1249
1289
  ErrorCodes.NETWORK_ERROR,
1250
1290
  "KV batchPut response did not include matching written keys and count",
1251
- "kv"
1291
+ "kv",
1292
+ {
1293
+ meta: {
1294
+ requestMayHaveDispatched: true,
1295
+ responseReceived: true,
1296
+ status: response.status,
1297
+ outcome: "batch-unconfirmed"
1298
+ }
1299
+ }
1300
+ )
1301
+ );
1302
+ }
1303
+ const requestedPaths = new Set(paths);
1304
+ const writtenPaths = new Set(batchResponse.written);
1305
+ const matchesRequest = batchResponse.count === paths.length && batchResponse.written.length === paths.length && writtenPaths.size === paths.length && batchResponse.written.every((key) => requestedPaths.has(key));
1306
+ if (!matchesRequest) {
1307
+ return err(
1308
+ serviceError(
1309
+ ErrorCodes.NETWORK_ERROR,
1310
+ `KV batchPut response did not confirm all ${paths.length} requested key(s) were written`,
1311
+ "kv",
1312
+ {
1313
+ meta: {
1314
+ requestMayHaveDispatched: true,
1315
+ responseReceived: true,
1316
+ status: response.status,
1317
+ outcome: "batch-unconfirmed"
1318
+ }
1319
+ }
1252
1320
  )
1253
1321
  );
1254
1322
  }
1255
1323
  return ok(batchResponse);
1256
1324
  } catch (error) {
1257
- return err(wrapError("kv", error));
1325
+ const wrapped = wrapError("kv", error);
1326
+ return err({
1327
+ ...wrapped,
1328
+ meta: { ...wrapped.meta, requestMayHaveDispatched }
1329
+ });
1258
1330
  }
1259
1331
  });
1260
1332
  }
@@ -1283,7 +1355,10 @@ var KVService = class extends BaseService {
1283
1355
  KVAction.LIST,
1284
1356
  void 0,
1285
1357
  options?.signal,
1286
- options?.limit === void 0 ? void 0 : { "x-tinycloud-limit": String(options.limit) }
1358
+ options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
1359
+ ...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
1360
+ ...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
1361
+ }
1287
1362
  );
1288
1363
  if (!response.ok) {
1289
1364
  if (response.status === 401) {
@@ -1315,7 +1390,8 @@ var KVService = class extends BaseService {
1315
1390
  }
1316
1391
  return ok({
1317
1392
  keys,
1318
- ...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" }
1393
+ ...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" },
1394
+ ...response.headers.get("x-tinycloud-next-cursor") === null ? {} : { nextCursor: response.headers.get("x-tinycloud-next-cursor") ?? void 0 }
1319
1395
  });
1320
1396
  } catch (error) {
1321
1397
  return err(wrapError("kv", error));