@tinycloud/sdk-services 3.2.6-beta.4 → 3.3.0-beta.11

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.
Files changed (45) hide show
  1. package/dist/{BaseService-1Ug6y7DC.d.cts → BaseService-Cc6Ueicm.d.cts} +1 -1
  2. package/dist/{BaseService-Bn07Vudy.d.ts → BaseService-DOdXd7sr.d.ts} +1 -1
  3. package/dist/encryption/index.cjs +8 -0
  4. package/dist/encryption/index.cjs.map +1 -1
  5. package/dist/encryption/index.d.cts +2 -2
  6. package/dist/encryption/index.d.ts +2 -2
  7. package/dist/encryption/index.js +8 -0
  8. package/dist/encryption/index.js.map +1 -1
  9. package/dist/index.cjs +345 -203
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +107 -7
  12. package/dist/index.d.ts +107 -7
  13. package/dist/index.js +344 -203
  14. package/dist/index.js.map +1 -1
  15. package/dist/internal/decrypt-transport-response-error.d.cts +1 -1
  16. package/dist/internal/decrypt-transport-response-error.d.ts +1 -1
  17. package/dist/kv/index.cjs +66 -21
  18. package/dist/kv/index.cjs.map +1 -1
  19. package/dist/kv/index.d.cts +4 -4
  20. package/dist/kv/index.d.ts +4 -4
  21. package/dist/kv/index.js +66 -21
  22. package/dist/kv/index.js.map +1 -1
  23. package/dist/kv/replication/grantPolicy.cjs +82 -0
  24. package/dist/kv/replication/grantPolicy.cjs.map +1 -0
  25. package/dist/kv/replication/grantPolicy.d.cts +19 -0
  26. package/dist/kv/replication/grantPolicy.d.ts +19 -0
  27. package/dist/kv/replication/grantPolicy.js +50 -0
  28. package/dist/kv/replication/grantPolicy.js.map +1 -0
  29. package/dist/kv/replication/index.cjs +571 -128
  30. package/dist/kv/replication/index.cjs.map +1 -1
  31. package/dist/kv/replication/index.d.cts +3 -3
  32. package/dist/kv/replication/index.d.ts +3 -3
  33. package/dist/kv/replication/index.js +571 -128
  34. package/dist/kv/replication/index.js.map +1 -1
  35. package/dist/{scope-BnyVPZ5E.d.ts → scope-B-m6cKH-.d.ts} +310 -7
  36. package/dist/{scope-CQ5kmHlt.d.cts → scope-B7oeKdLM.d.cts} +310 -7
  37. package/dist/sql/index.cjs +70 -36
  38. package/dist/sql/index.cjs.map +1 -1
  39. package/dist/sql/index.d.cts +2 -2
  40. package/dist/sql/index.d.ts +2 -2
  41. package/dist/sql/index.js +70 -36
  42. package/dist/sql/index.js.map +1 -1
  43. package/dist/{types-gmdUiorz.d.cts → types-BjH0ZtGy.d.cts} +6 -0
  44. package/dist/{types-gmdUiorz.d.ts → types-BjH0ZtGy.d.ts} +6 -0
  45. package/package.json +16 -2
package/dist/index.cjs CHANGED
@@ -84,8 +84,8 @@ __export(src_exports, {
84
84
  authRequiredError: () => authRequiredError,
85
85
  authUnauthorizedError: () => authUnauthorizedError,
86
86
  authorizationVerdictOf: () => authorizationVerdictOf,
87
- base64Decode: () => base64Decode2,
88
- base64Encode: () => base64Encode2,
87
+ base64Decode: () => base64Decode,
88
+ base64Encode: () => base64Encode,
89
89
  buildCanonicalDecryptRequest: () => buildCanonicalDecryptRequest,
90
90
  buildDecryptAttenuation: () => buildDecryptAttenuation,
91
91
  buildDecryptFacts: () => buildDecryptFacts,
@@ -115,13 +115,14 @@ __export(src_exports, {
115
115
  generateRandomReceiverKey: () => generateRandomReceiverKey,
116
116
  getTinyCloudDebugLogs: () => getTinyCloudDebugLogs,
117
117
  hexDecode: () => hexDecode,
118
- hexEncode: () => hexEncode2,
118
+ hexEncode: () => hexEncode,
119
119
  installTinyCloudDebugGlobals: () => installTinyCloudDebugGlobals,
120
120
  isNetworkId: () => isNetworkId,
121
121
  isStorageFullError: () => isStorageFullError,
122
122
  kvPrefixCovers: () => kvPrefixCovers,
123
123
  networkDiscoveryKey: () => networkDiscoveryKey,
124
124
  networkError: () => networkError,
125
+ nodeRetryError: () => nodeRetryError,
125
126
  notFoundError: () => notFoundError,
126
127
  ok: () => ok,
127
128
  openWrappedKey: () => openWrappedKey,
@@ -179,6 +180,14 @@ var ErrorCodes = {
179
180
  ABORTED: "ABORTED",
180
181
  INVALID_INPUT: "INVALID_INPUT",
181
182
  PERMISSION_DENIED: "PERMISSION_DENIED",
183
+ // Node retry signals (tinycloud-node #347). `meta.retryable` says whether a
184
+ // retry is safe; `meta.retryAfterMs` carries the node's Retry-After.
185
+ /** HTTP 503 `sql_busy:<stage>` / `unavailable_retryable`: nothing was applied; retry after `meta.retryAfterMs`. */
186
+ NODE_BUSY: "NODE_BUSY",
187
+ /** HTTP 503 `request_timeout`: the node's deadline passed before any write began; nothing was applied. */
188
+ REQUEST_TIMEOUT: "REQUEST_TIMEOUT",
189
+ /** HTTP 500 `outcome_unknown`: a write may have been applied; read back before retrying a non-idempotent operation. */
190
+ OUTCOME_UNKNOWN: "OUTCOME_UNKNOWN",
182
191
  // KV-specific errors
183
192
  KV_NOT_FOUND: "KV_NOT_FOUND",
184
193
  KV_WRITE_FAILED: "KV_WRITE_FAILED",
@@ -1123,6 +1132,42 @@ var ServiceContext = class {
1123
1132
  }
1124
1133
  };
1125
1134
 
1135
+ // src/responseErrors.ts
1136
+ function parseServiceErrorBody(errorText) {
1137
+ try {
1138
+ return JSON.parse(errorText);
1139
+ } catch {
1140
+ return {};
1141
+ }
1142
+ }
1143
+ function formatServiceResponseError(serviceLabel, operation, status, errorText, parsed) {
1144
+ if (parsed.message) {
1145
+ return compactMessage(parsed.message);
1146
+ }
1147
+ if (looksLikeHtml(errorText)) {
1148
+ if (status === 524 || /524\s*[:-]/i.test(errorText) || /a timeout occurred/i.test(errorText)) {
1149
+ return `${serviceLabel} ${operation} failed: upstream request timed out. Please retry.`;
1150
+ }
1151
+ return `${serviceLabel} ${operation} failed: upstream service returned an HTML error page (${status}).`;
1152
+ }
1153
+ return `${serviceLabel} ${operation} failed: ${status} - ${compactMessage(errorText)}`;
1154
+ }
1155
+ function responseErrorMeta(status, statusText, errorText) {
1156
+ const meta = { status, statusText };
1157
+ const snippet = compactMessage(errorText);
1158
+ if (snippet) {
1159
+ meta.responseSnippet = snippet.slice(0, 300);
1160
+ }
1161
+ return meta;
1162
+ }
1163
+ function looksLikeHtml(text) {
1164
+ return /<!doctype html/i.test(text) || /<html[\s>]/i.test(text);
1165
+ }
1166
+ function compactMessage(message) {
1167
+ const compact = message.replace(/\s+/g, " ").trim();
1168
+ return compact.length > 500 ? `${compact.slice(0, 500)}...` : compact;
1169
+ }
1170
+
1126
1171
  // src/errors.ts
1127
1172
  var import_bootstrap = require("@tinycloud/bootstrap");
1128
1173
 
@@ -1282,6 +1327,30 @@ function networkError(service, message, cause) {
1282
1327
  cause
1283
1328
  };
1284
1329
  }
1330
+ function nodeRetryError(service, message, response, errorText) {
1331
+ const body = errorText.trim();
1332
+ const [, token, stage] = /^([a-z_]+)(?::\s*([a-z_]+):)?/.exec(body) ?? [];
1333
+ let code;
1334
+ if (response.status === 503 && (token === "sql_busy" || token === "unavailable_retryable")) {
1335
+ code = ErrorCodes.NODE_BUSY;
1336
+ } else if (response.status === 503 && token === "request_timeout") {
1337
+ code = ErrorCodes.REQUEST_TIMEOUT;
1338
+ } else if (response.status === 500 && token === "outcome_unknown") {
1339
+ code = ErrorCodes.OUTCOME_UNKNOWN;
1340
+ } else {
1341
+ return void 0;
1342
+ }
1343
+ const retryable = code !== ErrorCodes.OUTCOME_UNKNOWN;
1344
+ const retryAfter = response.headers.get("retry-after")?.trim();
1345
+ return serviceError(code, message, service, {
1346
+ meta: {
1347
+ ...responseErrorMeta(response.status, response.statusText, errorText),
1348
+ retryable,
1349
+ ...token === "sql_busy" && stage ? { stage } : {},
1350
+ ...retryable && retryAfter && /^\d{1,9}$/.test(retryAfter) ? { retryAfterMs: Number(retryAfter) * 1e3 } : {}
1351
+ }
1352
+ });
1353
+ }
1285
1354
  var RequestTimeoutError = class extends Error {
1286
1355
  constructor(timeoutMs) {
1287
1356
  super(`Request timed out after ${timeoutMs}ms.`);
@@ -2620,9 +2689,12 @@ var KVService = class extends BaseService {
2620
2689
  { meta: { status: response.status, statusText: response.statusText } }
2621
2690
  ));
2622
2691
  }
2692
+ const message = `Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
2693
+ const retryError = nodeRetryError("kv", message, response, errorText);
2694
+ if (retryError) return err(retryError);
2623
2695
  return err(serviceError(
2624
2696
  ErrorCodes.NETWORK_ERROR,
2625
- `Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2697
+ message,
2626
2698
  "kv",
2627
2699
  { meta: { status: response.status, statusText: response.statusText } }
2628
2700
  ));
@@ -2704,19 +2776,14 @@ var KVService = class extends BaseService {
2704
2776
  { meta: { status: response.status, statusText: response.statusText } }
2705
2777
  ));
2706
2778
  }
2707
- if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
2708
- return err(serviceError(
2709
- ErrorCodes.KV_CONFLICT,
2710
- `Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
2711
- "kv",
2712
- { meta: { status: response.status, statusText: response.statusText } }
2713
- ));
2714
- }
2779
+ const message = `Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
2780
+ const retryError = nodeRetryError("kv", message, response, errorText);
2781
+ if (retryError) return err(retryError);
2715
2782
  const quotaError = this.handleQuotaErrorResponse(response, errorText, key);
2716
2783
  if (quotaError) return quotaError;
2717
2784
  return err(serviceError(
2718
2785
  ErrorCodes.KV_WRITE_FAILED,
2719
- `Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2786
+ message,
2720
2787
  "kv",
2721
2788
  { meta: { status: response.status, statusText: response.statusText } }
2722
2789
  ));
@@ -3016,9 +3083,12 @@ var KVService = class extends BaseService {
3016
3083
  );
3017
3084
  }
3018
3085
  const errorText = await response.text();
3086
+ const message = `Failed to list keys: ${response.status} - ${errorText}`;
3087
+ const retryError = nodeRetryError("kv", message, response, errorText);
3088
+ if (retryError) return err(retryError);
3019
3089
  return err(serviceError(
3020
3090
  ErrorCodes.NETWORK_ERROR,
3021
- `Failed to list keys: ${response.status} - ${errorText}`,
3091
+ message,
3022
3092
  "kv",
3023
3093
  { meta: { status: response.status, statusText: response.statusText } }
3024
3094
  ));
@@ -3269,17 +3339,12 @@ var KVService = class extends BaseService {
3269
3339
  { meta: { status: response.status, statusText: response.statusText } }
3270
3340
  ));
3271
3341
  }
3272
- if (response.status === 503 && options?.ifMatch !== void 0) {
3273
- return err(serviceError(
3274
- ErrorCodes.KV_CONFLICT,
3275
- `Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
3276
- "kv",
3277
- { meta: { status: response.status, statusText: response.statusText } }
3278
- ));
3279
- }
3342
+ const message = `Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
3343
+ const retryError = nodeRetryError("kv", message, response, errorText);
3344
+ if (retryError) return err(retryError);
3280
3345
  return err(serviceError(
3281
3346
  ErrorCodes.NETWORK_ERROR,
3282
- `Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
3347
+ message,
3283
3348
  "kv",
3284
3349
  { meta: { status: response.status, statusText: response.statusText } }
3285
3350
  ));
@@ -3320,10 +3385,13 @@ var KVService = class extends BaseService {
3320
3385
  return await this.classifyNotFound(response, key);
3321
3386
  }
3322
3387
  const errorText = await response.text();
3388
+ const message = `Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
3389
+ const retryError = nodeRetryError("kv", message, response, errorText);
3390
+ if (retryError) return err(retryError);
3323
3391
  return err(
3324
3392
  serviceError(
3325
3393
  ErrorCodes.NETWORK_ERROR,
3326
- `Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
3394
+ message,
3327
3395
  "kv",
3328
3396
  { meta: { status: response.status, statusText: response.statusText } }
3329
3397
  )
@@ -3515,42 +3583,6 @@ function requiresSecretsOptIn(space, prefix) {
3515
3583
  return prefix.split("/", 1)[0] === "vault";
3516
3584
  }
3517
3585
 
3518
- // src/responseErrors.ts
3519
- function parseServiceErrorBody(errorText) {
3520
- try {
3521
- return JSON.parse(errorText);
3522
- } catch {
3523
- return {};
3524
- }
3525
- }
3526
- function formatServiceResponseError(serviceLabel, operation, status, errorText, parsed) {
3527
- if (parsed.message) {
3528
- return compactMessage(parsed.message);
3529
- }
3530
- if (looksLikeHtml(errorText)) {
3531
- if (status === 524 || /524\s*[:-]/i.test(errorText) || /a timeout occurred/i.test(errorText)) {
3532
- return `${serviceLabel} ${operation} failed: upstream request timed out. Please retry.`;
3533
- }
3534
- return `${serviceLabel} ${operation} failed: upstream service returned an HTML error page (${status}).`;
3535
- }
3536
- return `${serviceLabel} ${operation} failed: ${status} - ${compactMessage(errorText)}`;
3537
- }
3538
- function responseErrorMeta(status, statusText, errorText) {
3539
- const meta = { status, statusText };
3540
- const snippet = compactMessage(errorText);
3541
- if (snippet) {
3542
- meta.responseSnippet = snippet.slice(0, 300);
3543
- }
3544
- return meta;
3545
- }
3546
- function looksLikeHtml(text) {
3547
- return /<!doctype html/i.test(text) || /<html[\s>]/i.test(text);
3548
- }
3549
- function compactMessage(message) {
3550
- const compact = message.replace(/\s+/g, " ").trim();
3551
- return compact.length > 500 ? `${compact.slice(0, 500)}...` : compact;
3552
- }
3553
-
3554
3586
  // src/sql/SQLMigrations.ts
3555
3587
  var SQLMigrations = class {
3556
3588
  constructor(service, dbName) {
@@ -3966,6 +3998,8 @@ var SQLService = class extends BaseService {
3966
3998
  if (response.status === 413 && parseStorageRejection(errorText)) {
3967
3999
  return err(storageRejectionError("sql", 413, meta, errorText));
3968
4000
  }
4001
+ const retryError = nodeRetryError("sql", `SQL ${operation} failed: ${response.status} - ${errorText}`, response, errorText);
4002
+ if (retryError) return err(retryError);
3969
4003
  const errorBody = parseServiceErrorBody(errorText);
3970
4004
  const errorCode = this.mapHttpStatusToErrorCode(
3971
4005
  response.status,
@@ -4435,6 +4469,8 @@ var DuckDbService = class extends BaseService {
4435
4469
  if (response.status === 413 && parseStorageRejection(errorText)) {
4436
4470
  return err(storageRejectionError("duckdb", 413, meta, errorText));
4437
4471
  }
4472
+ const retryError = nodeRetryError("duckdb", `DuckDB ${operation} failed: ${response.status} - ${errorText}`, response, errorText);
4473
+ if (retryError) return err(retryError);
4438
4474
  const errorBody = parseServiceErrorBody(errorText);
4439
4475
  const errorCode = this.mapHttpStatusToErrorCode(
4440
4476
  response.status,
@@ -5642,6 +5678,116 @@ var TinyCloudQuota = class {
5642
5678
  }
5643
5679
  };
5644
5680
 
5681
+ // src/encryption/canonical.ts
5682
+ function canonicalize(value) {
5683
+ if (value === void 0) {
5684
+ return "";
5685
+ }
5686
+ return stringify(value);
5687
+ }
5688
+ function stringify(value) {
5689
+ if (value === null) return "null";
5690
+ switch (typeof value) {
5691
+ case "boolean":
5692
+ case "number":
5693
+ return JSON.stringify(value);
5694
+ case "string":
5695
+ return JSON.stringify(value);
5696
+ case "object": {
5697
+ if (Array.isArray(value)) {
5698
+ return `[${value.map(stringify).join(",")}]`;
5699
+ }
5700
+ const keys = Object.keys(value).sort();
5701
+ const parts = [];
5702
+ for (const k of keys) {
5703
+ const v = value[k];
5704
+ if (v === void 0) continue;
5705
+ parts.push(`${JSON.stringify(k)}:${stringify(v)}`);
5706
+ }
5707
+ return `{${parts.join(",")}}`;
5708
+ }
5709
+ default:
5710
+ throw new TypeError(
5711
+ `canonicalize: unsupported value type ${typeof value}`
5712
+ );
5713
+ }
5714
+ }
5715
+ var HEX = "0123456789abcdef";
5716
+ function hexEncode(bytes) {
5717
+ let out = "";
5718
+ for (let i = 0; i < bytes.length; i++) {
5719
+ const b = bytes[i];
5720
+ out += HEX[b >> 4 & 15] + HEX[b & 15];
5721
+ }
5722
+ return out;
5723
+ }
5724
+ function hexDecode(hex) {
5725
+ if (hex.length % 2 !== 0) {
5726
+ throw new Error("hex string must have even length");
5727
+ }
5728
+ const out = new Uint8Array(hex.length / 2);
5729
+ for (let i = 0; i < out.length; i++) {
5730
+ const hi = parseInt(hex[i * 2], 16);
5731
+ const lo = parseInt(hex[i * 2 + 1], 16);
5732
+ if (Number.isNaN(hi) || Number.isNaN(lo)) {
5733
+ throw new Error("invalid hex character");
5734
+ }
5735
+ out[i] = hi << 4 | lo;
5736
+ }
5737
+ return out;
5738
+ }
5739
+ function base64Encode(bytes) {
5740
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5741
+ let out = "";
5742
+ for (let i = 0; i < bytes.length; i += 3) {
5743
+ const b0 = bytes[i];
5744
+ const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
5745
+ const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
5746
+ out += chars[b0 >> 2 & 63];
5747
+ out += chars[(b0 << 4 | b1 >> 4) & 63];
5748
+ out += i + 1 < bytes.length ? chars[(b1 << 2 | b2 >> 6) & 63] : "=";
5749
+ out += i + 2 < bytes.length ? chars[b2 & 63] : "=";
5750
+ }
5751
+ return out;
5752
+ }
5753
+ function base64Decode(s) {
5754
+ const clean = s.replace(/[^A-Za-z0-9+/=]/g, "");
5755
+ const len = clean.length;
5756
+ if (len % 4 !== 0) {
5757
+ throw new Error("invalid base64 input");
5758
+ }
5759
+ const padding = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
5760
+ const outLen = len / 4 * 3 - padding;
5761
+ const out = new Uint8Array(outLen);
5762
+ const lookup = {};
5763
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5764
+ for (let i = 0; i < chars.length; i++) lookup[chars[i]] = i;
5765
+ let outIdx = 0;
5766
+ for (let i = 0; i < len; i += 4) {
5767
+ const v0 = lookup[clean[i]] ?? 0;
5768
+ const v1 = lookup[clean[i + 1]] ?? 0;
5769
+ const v2 = clean[i + 2] === "=" ? 0 : lookup[clean[i + 2]] ?? 0;
5770
+ const v3 = clean[i + 3] === "=" ? 0 : lookup[clean[i + 3]] ?? 0;
5771
+ const b0 = v0 << 2 | v1 >> 4;
5772
+ const b1 = (v1 & 15) << 4 | v2 >> 2;
5773
+ const b2 = (v2 & 3) << 6 | v3;
5774
+ if (outIdx < outLen) out[outIdx++] = b0;
5775
+ if (outIdx < outLen) out[outIdx++] = b1;
5776
+ if (outIdx < outLen) out[outIdx++] = b2;
5777
+ }
5778
+ return out;
5779
+ }
5780
+ function utf8Encode(s) {
5781
+ return new TextEncoder().encode(s);
5782
+ }
5783
+ function utf8Decode(b) {
5784
+ return new TextDecoder().decode(b);
5785
+ }
5786
+ function canonicalHashHex(sha256, value) {
5787
+ const canonical = canonicalize(value);
5788
+ return hexEncode(sha256(utf8Encode(canonical)));
5789
+ }
5790
+
5645
5791
  // src/vault/types.ts
5646
5792
  var VaultPublicSpaceKVActions = [
5647
5793
  "tinycloud.kv/get",
@@ -5811,7 +5957,7 @@ function toBytes(str) {
5811
5957
  function fromBytes(bytes) {
5812
5958
  return new TextDecoder().decode(bytes);
5813
5959
  }
5814
- function hexEncode(bytes) {
5960
+ function hexEncode2(bytes) {
5815
5961
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
5816
5962
  }
5817
5963
  function concatBytes(...arrays) {
@@ -5824,14 +5970,14 @@ function concatBytes(...arrays) {
5824
5970
  }
5825
5971
  return result;
5826
5972
  }
5827
- function base64Encode(bytes) {
5973
+ function base64Encode2(bytes) {
5828
5974
  let binary = "";
5829
5975
  for (let i = 0; i < bytes.length; i++) {
5830
5976
  binary += String.fromCharCode(bytes[i]);
5831
5977
  }
5832
5978
  return btoa(binary);
5833
5979
  }
5834
- function base64Decode(str) {
5980
+ function base64Decode2(str) {
5835
5981
  const binary = atob(str);
5836
5982
  const bytes = new Uint8Array(binary.length);
5837
5983
  for (let i = 0; i < binary.length; i++) {
@@ -5873,6 +6019,11 @@ function defaultVaultMessage(input) {
5873
6019
  return input.message;
5874
6020
  case "PERMISSION_DENIED":
5875
6021
  return input.message;
6022
+ case "AAD_MISMATCH":
6023
+ case "ETAG_MISMATCH":
6024
+ case "INVALID_ETAG":
6025
+ case "OUTCOME_UNKNOWN":
6026
+ case "NODE_BUSY":
5876
6027
  case "STORAGE_QUOTA_EXCEEDED":
5877
6028
  case "STORAGE_LIMIT_REACHED":
5878
6029
  return input.message;
@@ -5895,6 +6046,37 @@ function typedKvCause(error) {
5895
6046
  ...error.cause !== void 0 ? { cause: error.cause } : {}
5896
6047
  });
5897
6048
  }
6049
+ function canonicalAadSpaceId(spaceId) {
6050
+ return spaceId.replace(/0x[0-9a-fA-F]{40}/g, (address) => address.toLowerCase());
6051
+ }
6052
+ function checkEnvelopeAad(value, spaceId, key) {
6053
+ const e = value;
6054
+ if (typeof e !== "object" || e === null || Array.isArray(e) || !["networkId", "alg", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext"].every(
6055
+ (field) => typeof e[field] === "string" && e[field] !== ""
6056
+ ) || !Number.isInteger(e.keyVersion) || e.aad !== void 0 && typeof e.aad !== "string") {
6057
+ return "corrupt";
6058
+ }
6059
+ let aad = "";
6060
+ try {
6061
+ if (typeof e.aad === "string") aad = fromBytes(base64Decode(e.aad));
6062
+ } catch {
6063
+ }
6064
+ const suffix = `:${key}`;
6065
+ return aad.endsWith(suffix) && canonicalAadSpaceId(aad.slice(0, -suffix.length)) === canonicalAadSpaceId(`tinycloud.vault:${spaceId}`) ? "ok" : "mismatch";
6066
+ }
6067
+ var AMBIGUOUS_WRITE_STATUSES = [500, 502, 503, 504, 520, 522, 524];
6068
+ function ifMatchWriteError(key, error) {
6069
+ const status = error.meta?.status;
6070
+ const code = error.code === ErrorCodes.KV_PRECONDITION_FAILED ? "ETAG_MISMATCH" : error.code === ErrorCodes.KV_WRITE_FAILED && status === 400 ? "INVALID_ETAG" : error.code === ErrorCodes.OUTCOME_UNKNOWN || error.code === ErrorCodes.KV_WRITE_FAILED && typeof status === "number" && AMBIGUOUS_WRITE_STATUSES.includes(status) || (error.code === ErrorCodes.NETWORK_ERROR || error.code === ErrorCodes.TIMEOUT) && status === void 0 && error.meta?.requestMayHaveDispatched !== false ? "OUTCOME_UNKNOWN" : error.code === ErrorCodes.NODE_BUSY || error.code === ErrorCodes.REQUEST_TIMEOUT ? "NODE_BUSY" : void 0;
6071
+ if (code === void 0) return void 0;
6072
+ return vaultError({
6073
+ code,
6074
+ key,
6075
+ message: error.message,
6076
+ ...error.meta !== void 0 ? { meta: error.meta } : {},
6077
+ cause: typedKvCause(error)
6078
+ });
6079
+ }
5898
6080
  function kvWriteError(context, error) {
5899
6081
  if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
5900
6082
  return vaultError({ code: error.code, message: error.message, meta: error.meta });
@@ -6081,7 +6263,7 @@ var DataVaultService = class extends BaseService {
6081
6263
  }
6082
6264
  if (existingPubKey) {
6083
6265
  this.encryptionIdentity = {
6084
- publicKey: base64Decode(existingPubKey),
6266
+ publicKey: base64Decode2(existingPubKey),
6085
6267
  privateKey: new Uint8Array(0)
6086
6268
  // private key not available without signing
6087
6269
  };
@@ -6106,7 +6288,7 @@ var DataVaultService = class extends BaseService {
6106
6288
  );
6107
6289
  this.encryptionIdentity = this.crypto.x25519FromSeed(seed);
6108
6290
  try {
6109
- const pubKeyB64 = base64Encode(this.encryptionIdentity.publicKey);
6291
+ const pubKeyB64 = base64Encode2(this.encryptionIdentity.publicKey);
6110
6292
  await this.tc.ensurePublicSpace();
6111
6293
  await this.tc.publicKV.put(".well-known/vault-pubkey", pubKeyB64);
6112
6294
  await this.tc.publicKV.put(".well-known/vault-version", CURRENT_VAULT_VERSION);
@@ -6172,6 +6354,21 @@ var DataVaultService = class extends BaseService {
6172
6354
  message: "Authentication required"
6173
6355
  });
6174
6356
  }
6357
+ if (options?.ifMatch !== void 0) {
6358
+ if (options.ifNoneMatch !== void 0) {
6359
+ return vaultError({
6360
+ code: "STORAGE_ERROR",
6361
+ cause: new Error("ifMatch cannot be combined with ifNoneMatch")
6362
+ });
6363
+ }
6364
+ if (!/^"[^"\s]+"$/.test(options.ifMatch)) {
6365
+ return vaultError({
6366
+ code: "INVALID_ETAG",
6367
+ key,
6368
+ message: options.ifMatch.startsWith("W/") ? 'ifMatch is a weak etag (W/"..."): the node only issues strong etags, so the etag was weakened in transit (a proxy or CDN rewrote it). Read it from a connection that preserves strong ETags' : "ifMatch must be the strong, quoted ETag returned by a network read (VaultEntry.etag), passed exactly as returned"
6369
+ });
6370
+ }
6371
+ }
6175
6372
  try {
6176
6373
  const { plaintext, contentType } = this.serializeValue(value, options);
6177
6374
  const metadata = {
@@ -6194,7 +6391,8 @@ var DataVaultService = class extends BaseService {
6194
6391
  }
6195
6392
  const valuePath = `vault/${key}`;
6196
6393
  const valueBody = JSON.stringify(envelopeResult.data);
6197
- const valuePutResult = options?.ifNoneMatch !== void 0 ? await this.tc.kv.put(valuePath, valueBody, { ifNoneMatch: options.ifNoneMatch }) : await this.tc.kv.put(valuePath, valueBody);
6394
+ const putOptions = options?.ifMatch !== void 0 ? { ifMatch: options.ifMatch } : options?.ifNoneMatch !== void 0 ? { ifNoneMatch: options.ifNoneMatch } : void 0;
6395
+ const valuePutResult = putOptions !== void 0 ? await this.tc.kv.put(valuePath, valueBody, putOptions) : await this.tc.kv.put(valuePath, valueBody);
6198
6396
  if (!valuePutResult.ok) {
6199
6397
  if (options?.ifNoneMatch !== void 0 && valuePutResult.error.code === ErrorCodes.KV_PRECONDITION_FAILED) {
6200
6398
  return vaultError({
@@ -6204,6 +6402,10 @@ var DataVaultService = class extends BaseService {
6204
6402
  cause: typedKvCause(valuePutResult.error)
6205
6403
  });
6206
6404
  }
6405
+ if (options?.ifMatch !== void 0) {
6406
+ const classified = ifMatchWriteError(key, valuePutResult.error);
6407
+ if (classified !== void 0) return classified;
6408
+ }
6207
6409
  return kvWriteError("Failed to store encrypted value", valuePutResult.error);
6208
6410
  }
6209
6411
  return { ok: true, data: void 0 };
@@ -6238,6 +6440,19 @@ var DataVaultService = class extends BaseService {
6238
6440
  }
6239
6441
  const rawEnvelope = unwrapKVData(valueResult.data);
6240
6442
  const envelope = typeof rawEnvelope === "string" ? JSON.parse(rawEnvelope) : rawEnvelope;
6443
+ if (options?.expectAad === true) {
6444
+ const verdict = checkEnvelopeAad(envelope, this.vaultConfig.spaceId, key);
6445
+ if (verdict === "corrupt") {
6446
+ return vaultError({ code: "DECRYPTION_FAILED", message: "envelope is malformed" });
6447
+ }
6448
+ if (verdict === "mismatch") {
6449
+ return vaultError({
6450
+ code: "AAD_MISMATCH",
6451
+ key,
6452
+ message: `Envelope at ${key} is not bound to this space and key`
6453
+ });
6454
+ }
6455
+ }
6241
6456
  const proof = await this.decryptCapabilityProof();
6242
6457
  const plaintextResult = await config.service.decryptEnvelope(envelope, proof);
6243
6458
  if (!plaintextResult.ok) {
@@ -6254,7 +6469,11 @@ var DataVaultService = class extends BaseService {
6254
6469
  contentType,
6255
6470
  options
6256
6471
  );
6257
- return { ok: true, data: { value, metadata, keyId } };
6472
+ const etag = options?.source === "network" ? valueResult.data.headers?.etag : void 0;
6473
+ return {
6474
+ ok: true,
6475
+ data: { value, metadata, keyId, ...etag === void 0 ? {} : { etag } }
6476
+ };
6258
6477
  } catch (error) {
6259
6478
  return vaultError({
6260
6479
  code: "STORAGE_ERROR",
@@ -6300,6 +6519,12 @@ var DataVaultService = class extends BaseService {
6300
6519
  } catch {
6301
6520
  return { status: "corrupt_envelope" };
6302
6521
  }
6522
+ if (options?.expectAad === true) {
6523
+ const verdict = checkEnvelopeAad(envelope, this.vaultConfig.spaceId, key);
6524
+ if (verdict !== "ok") {
6525
+ return { status: verdict === "corrupt" ? "corrupt_envelope" : "aad_mismatch" };
6526
+ }
6527
+ }
6303
6528
  let plaintextResult;
6304
6529
  try {
6305
6530
  const proof = await this.decryptCapabilityProof();
@@ -6331,7 +6556,11 @@ var DataVaultService = class extends BaseService {
6331
6556
  contentType,
6332
6557
  options
6333
6558
  );
6334
- return { status: "ok", entry: { value, metadata, keyId } };
6559
+ const etag = valueResult.data.headers?.etag;
6560
+ return {
6561
+ status: "ok",
6562
+ entry: { value, metadata, keyId, ...etag === void 0 ? {} : { etag } }
6563
+ };
6335
6564
  } catch {
6336
6565
  return { status: "invalid_payload" };
6337
6566
  }
@@ -6381,6 +6610,14 @@ var DataVaultService = class extends BaseService {
6381
6610
  )
6382
6611
  });
6383
6612
  }
6613
+ if (options?.ifMatch !== void 0) {
6614
+ return vaultError({
6615
+ code: "STORAGE_ERROR",
6616
+ cause: new Error(
6617
+ "ifMatch is only supported by network-encrypted vaults"
6618
+ )
6619
+ });
6620
+ }
6384
6621
  if (!this._isUnlocked || !this.masterKey) {
6385
6622
  return vaultError({
6386
6623
  code: "VAULT_LOCKED",
@@ -6406,7 +6643,7 @@ var DataVaultService = class extends BaseService {
6406
6643
  }
6407
6644
  const contentType = options?.contentType ?? (value instanceof Uint8Array ? "application/octet-stream" : "application/json");
6408
6645
  const entryKey = this.crypto.randomBytes(32);
6409
- const keyId = hexEncode(this.crypto.sha256(entryKey)).slice(0, 16);
6646
+ const keyId = hexEncode2(this.crypto.sha256(entryKey)).slice(0, 16);
6410
6647
  const encrypted = this.crypto.encrypt(entryKey, plaintext);
6411
6648
  const keyBlob = this.crypto.encrypt(this.masterKey, entryKey);
6412
6649
  const metadata = {
@@ -6424,7 +6661,7 @@ var DataVaultService = class extends BaseService {
6424
6661
  ...metadata
6425
6662
  });
6426
6663
  const keyPayload = JSON.stringify({
6427
- key: base64Encode(keyBlob),
6664
+ key: base64Encode2(keyBlob),
6428
6665
  metadata: keyMetadata
6429
6666
  });
6430
6667
  const keyPutResult = await this.tc.kv.put(
@@ -6435,7 +6672,7 @@ var DataVaultService = class extends BaseService {
6435
6672
  return kvWriteError("Failed to store key blob", keyPutResult.error);
6436
6673
  }
6437
6674
  const valuePayload = JSON.stringify({
6438
- data: base64Encode(encrypted),
6675
+ data: base64Encode2(encrypted),
6439
6676
  metadata
6440
6677
  });
6441
6678
  const valuePutResult = await this.tc.kv.put(
@@ -6466,6 +6703,12 @@ var DataVaultService = class extends BaseService {
6466
6703
  if (this.usesNetworkEncryption) {
6467
6704
  return this.getNetworkEncrypted(key, options);
6468
6705
  }
6706
+ if (options?.expectAad === true) {
6707
+ return vaultError({
6708
+ code: "STORAGE_ERROR",
6709
+ cause: new Error("expectAad is only supported by network-encrypted vaults")
6710
+ });
6711
+ }
6469
6712
  if (!this._isUnlocked || !this.masterKey) {
6470
6713
  return vaultError({
6471
6714
  code: "VAULT_LOCKED",
@@ -6487,7 +6730,7 @@ var DataVaultService = class extends BaseService {
6487
6730
  return vaultError({ code: "KEY_NOT_FOUND", key });
6488
6731
  }
6489
6732
  const keyEnvelope = JSON.parse(keyResult.data.data);
6490
- const keyBlobBytes = base64Decode(keyEnvelope.key);
6733
+ const keyBlobBytes = base64Decode2(keyEnvelope.key);
6491
6734
  const entryKey = this.crypto.decrypt(this.masterKey, keyBlobBytes);
6492
6735
  const valueResult = await this.tc.kv.get(`vault/${key}`, {
6493
6736
  raw: true,
@@ -6497,7 +6740,7 @@ var DataVaultService = class extends BaseService {
6497
6740
  return vaultError({ code: "KEY_NOT_FOUND", key });
6498
6741
  }
6499
6742
  const valueEnvelope = JSON.parse(valueResult.data.data);
6500
- const encryptedBytes = base64Decode(valueEnvelope.data);
6743
+ const encryptedBytes = base64Decode2(valueEnvelope.data);
6501
6744
  const plaintext = this.crypto.decrypt(entryKey, encryptedBytes);
6502
6745
  const metadata = valueEnvelope.metadata ?? {};
6503
6746
  const contentType = metadata[VaultHeaders.CONTENT_TYPE] ?? "application/json";
@@ -6745,7 +6988,7 @@ var DataVaultService = class extends BaseService {
6745
6988
  return vaultError({ code: "KEY_NOT_FOUND", key });
6746
6989
  }
6747
6990
  const keyEnvelope = JSON.parse(keyResult.data.data);
6748
- const keyBlobBytes = base64Decode(keyEnvelope.key);
6991
+ const keyBlobBytes = base64Decode2(keyEnvelope.key);
6749
6992
  const entryKey = this.crypto.decrypt(this.masterKey, keyBlobBytes);
6750
6993
  const ephemeralSeed = this.crypto.randomBytes(32);
6751
6994
  const ephemeralKeyPair = this.crypto.x25519FromSeed(ephemeralSeed);
@@ -6764,7 +7007,7 @@ var DataVaultService = class extends BaseService {
6764
7007
  encryptedGrant
6765
7008
  );
6766
7009
  const grantPayload = JSON.stringify({
6767
- grant: base64Encode(grantBlob),
7010
+ grant: base64Encode2(grantBlob),
6768
7011
  spaceId: this.vaultConfig.spaceId,
6769
7012
  metadata: {
6770
7013
  [VaultHeaders.GRANT_VERSION]: "1",
@@ -6804,6 +7047,14 @@ var DataVaultService = class extends BaseService {
6804
7047
  */
6805
7048
  async getShared(grantorDID, key, options) {
6806
7049
  return this.withTelemetry("getShared", key, async () => {
7050
+ if (options?.expectAad === true) {
7051
+ return vaultError({
7052
+ code: "STORAGE_ERROR",
7053
+ cause: new Error(
7054
+ "expectAad is not supported by getShared: the AAD binds the grantor's space, which this vault does not know"
7055
+ )
7056
+ });
7057
+ }
6807
7058
  if (this.usesNetworkEncryption) {
6808
7059
  const grantorKV = options?.kv;
6809
7060
  if (!grantorKV) {
@@ -6898,7 +7149,7 @@ var DataVaultService = class extends BaseService {
6898
7149
  });
6899
7150
  }
6900
7151
  const grantEnvelope = typeof grantResult.data?.data === "string" ? JSON.parse(grantResult.data.data) : grantResult.data?.data;
6901
- const grantBlobBytes = base64Decode(grantEnvelope.grant);
7152
+ const grantBlobBytes = base64Decode2(grantEnvelope.grant);
6902
7153
  const ephemeralPubKey = grantBlobBytes.slice(0, 32);
6903
7154
  const encryptedGrant = grantBlobBytes.slice(32);
6904
7155
  const sharedSecret = this.crypto.x25519Dh(
@@ -6921,7 +7172,7 @@ var DataVaultService = class extends BaseService {
6921
7172
  });
6922
7173
  }
6923
7174
  const valueEnvelope = typeof valueResult.data?.data === "string" ? JSON.parse(valueResult.data.data) : valueResult.data?.data;
6924
- const encryptedBytes = base64Decode(valueEnvelope.data);
7175
+ const encryptedBytes = base64Decode2(valueEnvelope.data);
6925
7176
  const plaintext = this.crypto.decrypt(entryKey, encryptedBytes);
6926
7177
  const metadata = valueEnvelope.metadata ?? {};
6927
7178
  const contentType = metadata[VaultHeaders.CONTENT_TYPE] ?? "application/json";
@@ -6975,7 +7226,7 @@ var DataVaultService = class extends BaseService {
6975
7226
  if (!result.ok) {
6976
7227
  return vaultError({ code: "PUBLIC_KEY_NOT_FOUND", did });
6977
7228
  }
6978
- const pubKeyBytes = base64Decode(result.data);
7229
+ const pubKeyBytes = base64Decode2(result.data);
6979
7230
  return { ok: true, data: pubKeyBytes };
6980
7231
  } catch (error) {
6981
7232
  return vaultError({ code: "PUBLIC_KEY_NOT_FOUND", did });
@@ -7094,7 +7345,7 @@ var DataVaultService = class extends BaseService {
7094
7345
  }
7095
7346
  const currentEntry = getResult.data;
7096
7347
  const newEntryKey = this.crypto.randomBytes(32);
7097
- const newKeyId = hexEncode(this.crypto.sha256(newEntryKey)).slice(
7348
+ const newKeyId = hexEncode2(this.crypto.sha256(newEntryKey)).slice(
7098
7349
  0,
7099
7350
  16
7100
7351
  );
@@ -7111,7 +7362,7 @@ var DataVaultService = class extends BaseService {
7111
7362
  [VaultHeaders.KEY_ID]: newKeyId
7112
7363
  };
7113
7364
  const keyPayload = JSON.stringify({
7114
- key: base64Encode(newKeyBlob),
7365
+ key: base64Encode2(newKeyBlob),
7115
7366
  metadata: JSON.stringify({
7116
7367
  keyId: newKeyId,
7117
7368
  ...metadata
@@ -7125,7 +7376,7 @@ var DataVaultService = class extends BaseService {
7125
7376
  return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
7126
7377
  }
7127
7378
  const valuePayload = JSON.stringify({
7128
- data: base64Encode(encrypted),
7379
+ data: base64Encode2(encrypted),
7129
7380
  metadata
7130
7381
  });
7131
7382
  const valuePutResult = await this.tc.kv.put(
@@ -7417,116 +7668,6 @@ var SecretsService = class {
7417
7668
  }
7418
7669
  };
7419
7670
 
7420
- // src/encryption/canonical.ts
7421
- function canonicalize(value) {
7422
- if (value === void 0) {
7423
- return "";
7424
- }
7425
- return stringify(value);
7426
- }
7427
- function stringify(value) {
7428
- if (value === null) return "null";
7429
- switch (typeof value) {
7430
- case "boolean":
7431
- case "number":
7432
- return JSON.stringify(value);
7433
- case "string":
7434
- return JSON.stringify(value);
7435
- case "object": {
7436
- if (Array.isArray(value)) {
7437
- return `[${value.map(stringify).join(",")}]`;
7438
- }
7439
- const keys = Object.keys(value).sort();
7440
- const parts = [];
7441
- for (const k of keys) {
7442
- const v = value[k];
7443
- if (v === void 0) continue;
7444
- parts.push(`${JSON.stringify(k)}:${stringify(v)}`);
7445
- }
7446
- return `{${parts.join(",")}}`;
7447
- }
7448
- default:
7449
- throw new TypeError(
7450
- `canonicalize: unsupported value type ${typeof value}`
7451
- );
7452
- }
7453
- }
7454
- var HEX = "0123456789abcdef";
7455
- function hexEncode2(bytes) {
7456
- let out = "";
7457
- for (let i = 0; i < bytes.length; i++) {
7458
- const b = bytes[i];
7459
- out += HEX[b >> 4 & 15] + HEX[b & 15];
7460
- }
7461
- return out;
7462
- }
7463
- function hexDecode(hex) {
7464
- if (hex.length % 2 !== 0) {
7465
- throw new Error("hex string must have even length");
7466
- }
7467
- const out = new Uint8Array(hex.length / 2);
7468
- for (let i = 0; i < out.length; i++) {
7469
- const hi = parseInt(hex[i * 2], 16);
7470
- const lo = parseInt(hex[i * 2 + 1], 16);
7471
- if (Number.isNaN(hi) || Number.isNaN(lo)) {
7472
- throw new Error("invalid hex character");
7473
- }
7474
- out[i] = hi << 4 | lo;
7475
- }
7476
- return out;
7477
- }
7478
- function base64Encode2(bytes) {
7479
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7480
- let out = "";
7481
- for (let i = 0; i < bytes.length; i += 3) {
7482
- const b0 = bytes[i];
7483
- const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
7484
- const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
7485
- out += chars[b0 >> 2 & 63];
7486
- out += chars[(b0 << 4 | b1 >> 4) & 63];
7487
- out += i + 1 < bytes.length ? chars[(b1 << 2 | b2 >> 6) & 63] : "=";
7488
- out += i + 2 < bytes.length ? chars[b2 & 63] : "=";
7489
- }
7490
- return out;
7491
- }
7492
- function base64Decode2(s) {
7493
- const clean = s.replace(/[^A-Za-z0-9+/=]/g, "");
7494
- const len = clean.length;
7495
- if (len % 4 !== 0) {
7496
- throw new Error("invalid base64 input");
7497
- }
7498
- const padding = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
7499
- const outLen = len / 4 * 3 - padding;
7500
- const out = new Uint8Array(outLen);
7501
- const lookup = {};
7502
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7503
- for (let i = 0; i < chars.length; i++) lookup[chars[i]] = i;
7504
- let outIdx = 0;
7505
- for (let i = 0; i < len; i += 4) {
7506
- const v0 = lookup[clean[i]] ?? 0;
7507
- const v1 = lookup[clean[i + 1]] ?? 0;
7508
- const v2 = clean[i + 2] === "=" ? 0 : lookup[clean[i + 2]] ?? 0;
7509
- const v3 = clean[i + 3] === "=" ? 0 : lookup[clean[i + 3]] ?? 0;
7510
- const b0 = v0 << 2 | v1 >> 4;
7511
- const b1 = (v1 & 15) << 4 | v2 >> 2;
7512
- const b2 = (v2 & 3) << 6 | v3;
7513
- if (outIdx < outLen) out[outIdx++] = b0;
7514
- if (outIdx < outLen) out[outIdx++] = b1;
7515
- if (outIdx < outLen) out[outIdx++] = b2;
7516
- }
7517
- return out;
7518
- }
7519
- function utf8Encode(s) {
7520
- return new TextEncoder().encode(s);
7521
- }
7522
- function utf8Decode(b) {
7523
- return new TextDecoder().decode(b);
7524
- }
7525
- function canonicalHashHex(sha256, value) {
7526
- const canonical = canonicalize(value);
7527
- return hexEncode2(sha256(utf8Encode(canonical)));
7528
- }
7529
-
7530
7671
  // src/encryption/types.ts
7531
7672
  var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
7532
7673
  var ENVELOPE_VERSION = 1;
@@ -7736,7 +7877,7 @@ function encryptToNetwork(crypto2, input) {
7736
7877
  const symmetricKey = crypto2.randomBytes(32);
7737
7878
  const ciphertext = crypto2.authEncrypt(symmetricKey, input.plaintext, input.aad);
7738
7879
  const wrapped = crypto2.sealToNetworkKey(input.networkPublicKey, symmetricKey);
7739
- const encryptedSymmetricKey = base64Encode2(wrapped);
7880
+ const encryptedSymmetricKey = base64Encode(wrapped);
7740
7881
  const encryptedSymmetricKeyHash = canonicalHashHex(
7741
7882
  crypto2.sha256,
7742
7883
  encryptedSymmetricKey
@@ -7748,8 +7889,8 @@ function encryptToNetwork(crypto2, input) {
7748
7889
  keyVersion,
7749
7890
  encryptedSymmetricKey,
7750
7891
  encryptedSymmetricKeyHash,
7751
- ciphertext: base64Encode2(ciphertext),
7752
- ...input.aad !== void 0 ? { aad: base64Encode2(input.aad) } : {},
7892
+ ciphertext: base64Encode(ciphertext),
7893
+ ...input.aad !== void 0 ? { aad: base64Encode(input.aad) } : {},
7753
7894
  ...input.metadata !== void 0 ? { metadata: input.metadata } : {}
7754
7895
  };
7755
7896
  return { envelope, symmetricKey };
@@ -7823,8 +7964,8 @@ function validateEnvelope(crypto2, envelope) {
7823
7964
  return { ok: true, data: e };
7824
7965
  }
7825
7966
  function decryptEnvelopeWithKey(crypto2, envelope, symmetricKey) {
7826
- const ciphertext = base64Decode2(envelope.ciphertext);
7827
- const aad = envelope.aad !== void 0 ? base64Decode2(envelope.aad) : void 0;
7967
+ const ciphertext = base64Decode(envelope.ciphertext);
7968
+ const aad = envelope.aad !== void 0 ? base64Decode(envelope.aad) : void 0;
7828
7969
  return crypto2.authDecrypt(symmetricKey, ciphertext, aad);
7829
7970
  }
7830
7971
 
@@ -7842,7 +7983,7 @@ function buildCanonicalDecryptRequest(input) {
7842
7983
  return { canonicalBody, bodyHash, receiverPublicKeyHash };
7843
7984
  }
7844
7985
  function buildDecryptFacts(input) {
7845
- const bodyHash = input.canonicalBody !== void 0 ? hexEncode2(input.crypto.sha256(utf8Encode(input.canonicalBody))) : canonicalHashHex(
7986
+ const bodyHash = input.canonicalBody !== void 0 ? hexEncode(input.crypto.sha256(utf8Encode(input.canonicalBody))) : canonicalHashHex(
7846
7987
  input.crypto.sha256,
7847
7988
  input.body
7848
7989
  );
@@ -8125,7 +8266,7 @@ function verifyDecryptResponse(input) {
8125
8266
  })
8126
8267
  };
8127
8268
  }
8128
- const expectedRequestHash = hexEncode2(
8269
+ const expectedRequestHash = hexEncode(
8129
8270
  crypto2.sha256(utf8Encode(`${invocationCid}${requestBodyHash}`))
8130
8271
  );
8131
8272
  if (response.requestHash !== expectedRequestHash) {
@@ -8149,7 +8290,7 @@ function verifyDecryptResponse(input) {
8149
8290
  const signedBytes = new TextEncoder().encode(
8150
8291
  canonicalSignedResponse(response)
8151
8292
  );
8152
- const signatureBytes = base64Decode2(response.nodeSignature);
8293
+ const signatureBytes = base64Decode(response.nodeSignature);
8153
8294
  if (!crypto2.verifyNodeSignature(response.nodeId, signedBytes, signatureBytes)) {
8154
8295
  return {
8155
8296
  ok: false,
@@ -8161,7 +8302,7 @@ function verifyDecryptResponse(input) {
8161
8302
  return { ok: true, data: response };
8162
8303
  }
8163
8304
  function openWrappedKey(crypto2, receiverPrivateKey, response) {
8164
- const wrapped = base64Decode2(response.wrappedKey);
8305
+ const wrapped = base64Decode(response.wrappedKey);
8165
8306
  return crypto2.openWithReceiverKey(receiverPrivateKey, wrapped);
8166
8307
  }
8167
8308
 
@@ -8205,7 +8346,7 @@ var EncryptionService = class extends BaseService {
8205
8346
  const usable = ensureNetworkUsableForDecrypt(discovered.data);
8206
8347
  if (!usable.ok) return usable;
8207
8348
  const descriptor = usable.data;
8208
- const networkPublicKey = base64Decode2(descriptor.publicEncryptionKey);
8349
+ const networkPublicKey = base64Decode(descriptor.publicEncryptionKey);
8209
8350
  const result = encryptToNetwork(this.crypto, {
8210
8351
  // Discovery returns the node's canonical network identifier. Persist
8211
8352
  // that spelling in the envelope so a later response can be compared
@@ -8233,7 +8374,7 @@ var EncryptionService = class extends BaseService {
8233
8374
  this.assertActive();
8234
8375
  const validated = validateEnvelope(this.crypto, envelope);
8235
8376
  if (!validated.ok) return validated;
8236
- if (options?.aad !== void 0 && validated.data.aad !== base64Encode2(options.aad)) {
8377
+ if (options?.aad !== void 0 && validated.data.aad !== base64Encode(options.aad)) {
8237
8378
  return encErr(
8238
8379
  encryptionError({
8239
8380
  code: "INVALID_INPUT",
@@ -8261,7 +8402,7 @@ var EncryptionService = class extends BaseService {
8261
8402
  );
8262
8403
  }
8263
8404
  const receiverKey = generateRandomReceiverKey({ crypto: this.crypto });
8264
- const receiverPublicKey = base64Encode2(receiverKey.publicKey);
8405
+ const receiverPublicKey = base64Encode(receiverKey.publicKey);
8265
8406
  const receiverPublicKeyHash = canonicalHashHex(
8266
8407
  this.crypto.sha256,
8267
8408
  receiverPublicKey
@@ -8476,6 +8617,7 @@ var import_decrypt_transport_response_error3 = require("@tinycloud/sdk-services/
8476
8617
  kvPrefixCovers,
8477
8618
  networkDiscoveryKey,
8478
8619
  networkError,
8620
+ nodeRetryError,
8479
8621
  notFoundError,
8480
8622
  ok,
8481
8623
  openWrappedKey,