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

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
@@ -514,7 +514,9 @@ function createKVResponseSchema(dataSchema) {
514
514
  var GenericKVResponseSchema = createKVResponseSchema(import_zod.z.unknown());
515
515
  var KVListResponseSchema = import_zod.z.object({
516
516
  /** Array of keys matching the list criteria */
517
- keys: import_zod.z.array(import_zod.z.string())
517
+ keys: import_zod.z.array(import_zod.z.string()),
518
+ truncated: import_zod.z.boolean().optional(),
519
+ nextCursor: import_zod.z.string().optional()
518
520
  });
519
521
  var KVListResultSchema = createResultSchema(KVListResponseSchema);
520
522
  var ServiceRequestEventSchema = import_zod.z.object({
@@ -2189,6 +2191,7 @@ var KVService = class extends BaseService {
2189
2191
  }
2190
2192
  seen.add(path);
2191
2193
  }
2194
+ let requestMayHaveDispatched = false;
2192
2195
  try {
2193
2196
  const body = new FormData();
2194
2197
  for (let index = 0; index < items.length; index++) {
@@ -2206,14 +2209,31 @@ var KVService = class extends BaseService {
2206
2209
  action: KVAction.PUT
2207
2210
  }))
2208
2211
  );
2209
- const response = await this.context.fetch(`${this.host}/invoke`, {
2212
+ const url = `${this.host}/invoke`;
2213
+ const init = {
2210
2214
  method: "POST",
2211
2215
  headers,
2212
2216
  body,
2213
2217
  signal: this.combineSignals(options?.signal)
2214
- });
2218
+ };
2219
+ const fetchFn = this.context.fetch;
2220
+ requestMayHaveDispatched = true;
2221
+ const response = await fetchFn(url, init);
2215
2222
  if (!response.ok) {
2216
- const errorText = await response.text();
2223
+ let errorText;
2224
+ try {
2225
+ errorText = await response.text();
2226
+ } catch (textError) {
2227
+ const cause = textError instanceof Error ? textError : new Error(String(textError));
2228
+ return err(
2229
+ serviceError(
2230
+ ErrorCodes.KV_WRITE_FAILED,
2231
+ `Failed to batch put ${items.length} key(s): ${response.status} - <response body could not be read: ${cause.message}>`,
2232
+ "kv",
2233
+ { cause, meta: { status: response.status, statusText: response.statusText } }
2234
+ )
2235
+ );
2236
+ }
2217
2237
  if (response.status === 401 || response.status === 403) {
2218
2238
  const { resource, action } = parseAuthError(errorText);
2219
2239
  return err(authUnauthorizedError("kv", errorText, {
@@ -2239,19 +2259,73 @@ var KVService = class extends BaseService {
2239
2259
  )
2240
2260
  );
2241
2261
  }
2242
- const batchResponse = this.normalizeBatchPutResponse(await response.json());
2243
- if (!batchResponse || batchResponse.count !== batchResponse.written.length) {
2262
+ let rawBody;
2263
+ try {
2264
+ rawBody = await response.json();
2265
+ } catch (jsonError) {
2266
+ const cause = jsonError instanceof Error ? jsonError : new Error(String(jsonError));
2267
+ return err(
2268
+ serviceError(
2269
+ ErrorCodes.NETWORK_ERROR,
2270
+ `KV batchPut response was not valid JSON: ${cause.message}`,
2271
+ "kv",
2272
+ {
2273
+ cause,
2274
+ meta: {
2275
+ requestMayHaveDispatched: true,
2276
+ responseReceived: true,
2277
+ status: response.status,
2278
+ outcome: "batch-unconfirmed"
2279
+ }
2280
+ }
2281
+ )
2282
+ );
2283
+ }
2284
+ const batchResponse = this.normalizeBatchPutResponse(rawBody);
2285
+ if (!batchResponse) {
2244
2286
  return err(
2245
2287
  serviceError(
2246
2288
  ErrorCodes.NETWORK_ERROR,
2247
2289
  "KV batchPut response did not include matching written keys and count",
2248
- "kv"
2290
+ "kv",
2291
+ {
2292
+ meta: {
2293
+ requestMayHaveDispatched: true,
2294
+ responseReceived: true,
2295
+ status: response.status,
2296
+ outcome: "batch-unconfirmed"
2297
+ }
2298
+ }
2299
+ )
2300
+ );
2301
+ }
2302
+ const requestedPaths = new Set(paths);
2303
+ const writtenPaths = new Set(batchResponse.written);
2304
+ const matchesRequest = batchResponse.count === paths.length && batchResponse.written.length === paths.length && writtenPaths.size === paths.length && batchResponse.written.every((key) => requestedPaths.has(key));
2305
+ if (!matchesRequest) {
2306
+ return err(
2307
+ serviceError(
2308
+ ErrorCodes.NETWORK_ERROR,
2309
+ `KV batchPut response did not confirm all ${paths.length} requested key(s) were written`,
2310
+ "kv",
2311
+ {
2312
+ meta: {
2313
+ requestMayHaveDispatched: true,
2314
+ responseReceived: true,
2315
+ status: response.status,
2316
+ outcome: "batch-unconfirmed"
2317
+ }
2318
+ }
2249
2319
  )
2250
2320
  );
2251
2321
  }
2252
2322
  return ok(batchResponse);
2253
2323
  } catch (error) {
2254
- return err(wrapError("kv", error));
2324
+ const wrapped = wrapError("kv", error);
2325
+ return err({
2326
+ ...wrapped,
2327
+ meta: { ...wrapped.meta, requestMayHaveDispatched }
2328
+ });
2255
2329
  }
2256
2330
  });
2257
2331
  }
@@ -2280,7 +2354,10 @@ var KVService = class extends BaseService {
2280
2354
  KVAction.LIST,
2281
2355
  void 0,
2282
2356
  options?.signal,
2283
- options?.limit === void 0 ? void 0 : { "x-tinycloud-limit": String(options.limit) }
2357
+ options?.limit === void 0 && options?.cursor === void 0 ? void 0 : {
2358
+ ...options?.limit === void 0 ? {} : { "x-tinycloud-limit": String(options.limit) },
2359
+ ...options?.cursor === void 0 ? {} : { "x-tinycloud-cursor": options.cursor }
2360
+ }
2284
2361
  );
2285
2362
  if (!response.ok) {
2286
2363
  if (response.status === 401) {
@@ -2312,7 +2389,8 @@ var KVService = class extends BaseService {
2312
2389
  }
2313
2390
  return ok({
2314
2391
  keys,
2315
- ...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" }
2392
+ ...response.headers.get("x-tinycloud-truncated") === null ? {} : { truncated: response.headers.get("x-tinycloud-truncated") === "true" },
2393
+ ...response.headers.get("x-tinycloud-next-cursor") === null ? {} : { nextCursor: response.headers.get("x-tinycloud-next-cursor") ?? void 0 }
2316
2394
  });
2317
2395
  } catch (error) {
2318
2396
  return err(wrapError("kv", error));
@@ -5037,6 +5115,10 @@ var DataVaultService = class extends BaseService {
5037
5115
  * @returns Result with array of key names (vault/ prefix stripped)
5038
5116
  */
5039
5117
  async list(options) {
5118
+ const page = await this.listPage(options);
5119
+ return page.ok ? { ok: true, data: page.data.keys } : page;
5120
+ }
5121
+ async listPage(options) {
5040
5122
  return this.withTelemetry("list", options?.prefix, async () => {
5041
5123
  if (!this.isUnlocked) {
5042
5124
  return vaultError({
@@ -5054,7 +5136,9 @@ var DataVaultService = class extends BaseService {
5054
5136
  const listPrefix = options?.prefix ? `vault/${options.prefix}` : "vault/";
5055
5137
  const listResult = await this.tc.kv.list({
5056
5138
  prefix: listPrefix,
5057
- removePrefix: true
5139
+ removePrefix: true,
5140
+ ...options?.limit === void 0 ? {} : { limit: options.limit },
5141
+ ...options?.cursor === void 0 ? {} : { cursor: options.cursor }
5058
5142
  });
5059
5143
  if (!listResult.ok) {
5060
5144
  return vaultError({
@@ -5071,7 +5155,11 @@ var DataVaultService = class extends BaseService {
5071
5155
  (k) => k.startsWith(userPrefix) ? k.slice(userPrefix.length) : k
5072
5156
  );
5073
5157
  }
5074
- return ok(keys);
5158
+ return ok({
5159
+ keys,
5160
+ truncated: listResult.data.truncated === true,
5161
+ ...listResult.data.nextCursor === void 0 ? {} : { nextCursor: listResult.data.nextCursor }
5162
+ });
5075
5163
  } catch (error) {
5076
5164
  return vaultError({
5077
5165
  code: "STORAGE_ERROR",