@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.js CHANGED
@@ -14,6 +14,14 @@ var ErrorCodes = {
14
14
  ABORTED: "ABORTED",
15
15
  INVALID_INPUT: "INVALID_INPUT",
16
16
  PERMISSION_DENIED: "PERMISSION_DENIED",
17
+ // Node retry signals (tinycloud-node #347). `meta.retryable` says whether a
18
+ // retry is safe; `meta.retryAfterMs` carries the node's Retry-After.
19
+ /** HTTP 503 `sql_busy:<stage>` / `unavailable_retryable`: nothing was applied; retry after `meta.retryAfterMs`. */
20
+ NODE_BUSY: "NODE_BUSY",
21
+ /** HTTP 503 `request_timeout`: the node's deadline passed before any write began; nothing was applied. */
22
+ REQUEST_TIMEOUT: "REQUEST_TIMEOUT",
23
+ /** HTTP 500 `outcome_unknown`: a write may have been applied; read back before retrying a non-idempotent operation. */
24
+ OUTCOME_UNKNOWN: "OUTCOME_UNKNOWN",
17
25
  // KV-specific errors
18
26
  KV_NOT_FOUND: "KV_NOT_FOUND",
19
27
  KV_WRITE_FAILED: "KV_WRITE_FAILED",
@@ -958,6 +966,42 @@ var ServiceContext = class {
958
966
  }
959
967
  };
960
968
 
969
+ // src/responseErrors.ts
970
+ function parseServiceErrorBody(errorText) {
971
+ try {
972
+ return JSON.parse(errorText);
973
+ } catch {
974
+ return {};
975
+ }
976
+ }
977
+ function formatServiceResponseError(serviceLabel, operation, status, errorText, parsed) {
978
+ if (parsed.message) {
979
+ return compactMessage(parsed.message);
980
+ }
981
+ if (looksLikeHtml(errorText)) {
982
+ if (status === 524 || /524\s*[:-]/i.test(errorText) || /a timeout occurred/i.test(errorText)) {
983
+ return `${serviceLabel} ${operation} failed: upstream request timed out. Please retry.`;
984
+ }
985
+ return `${serviceLabel} ${operation} failed: upstream service returned an HTML error page (${status}).`;
986
+ }
987
+ return `${serviceLabel} ${operation} failed: ${status} - ${compactMessage(errorText)}`;
988
+ }
989
+ function responseErrorMeta(status, statusText, errorText) {
990
+ const meta = { status, statusText };
991
+ const snippet = compactMessage(errorText);
992
+ if (snippet) {
993
+ meta.responseSnippet = snippet.slice(0, 300);
994
+ }
995
+ return meta;
996
+ }
997
+ function looksLikeHtml(text) {
998
+ return /<!doctype html/i.test(text) || /<html[\s>]/i.test(text);
999
+ }
1000
+ function compactMessage(message) {
1001
+ const compact = message.replace(/\s+/g, " ").trim();
1002
+ return compact.length > 500 ? `${compact.slice(0, 500)}...` : compact;
1003
+ }
1004
+
961
1005
  // src/errors.ts
962
1006
  import { CAPABILITY_REGISTRY } from "@tinycloud/bootstrap";
963
1007
 
@@ -1117,6 +1161,30 @@ function networkError(service, message, cause) {
1117
1161
  cause
1118
1162
  };
1119
1163
  }
1164
+ function nodeRetryError(service, message, response, errorText) {
1165
+ const body = errorText.trim();
1166
+ const [, token, stage] = /^([a-z_]+)(?::\s*([a-z_]+):)?/.exec(body) ?? [];
1167
+ let code;
1168
+ if (response.status === 503 && (token === "sql_busy" || token === "unavailable_retryable")) {
1169
+ code = ErrorCodes.NODE_BUSY;
1170
+ } else if (response.status === 503 && token === "request_timeout") {
1171
+ code = ErrorCodes.REQUEST_TIMEOUT;
1172
+ } else if (response.status === 500 && token === "outcome_unknown") {
1173
+ code = ErrorCodes.OUTCOME_UNKNOWN;
1174
+ } else {
1175
+ return void 0;
1176
+ }
1177
+ const retryable = code !== ErrorCodes.OUTCOME_UNKNOWN;
1178
+ const retryAfter = response.headers.get("retry-after")?.trim();
1179
+ return serviceError(code, message, service, {
1180
+ meta: {
1181
+ ...responseErrorMeta(response.status, response.statusText, errorText),
1182
+ retryable,
1183
+ ...token === "sql_busy" && stage ? { stage } : {},
1184
+ ...retryable && retryAfter && /^\d{1,9}$/.test(retryAfter) ? { retryAfterMs: Number(retryAfter) * 1e3 } : {}
1185
+ }
1186
+ });
1187
+ }
1120
1188
  var RequestTimeoutError = class extends Error {
1121
1189
  constructor(timeoutMs) {
1122
1190
  super(`Request timed out after ${timeoutMs}ms.`);
@@ -2455,9 +2523,12 @@ var KVService = class extends BaseService {
2455
2523
  { meta: { status: response.status, statusText: response.statusText } }
2456
2524
  ));
2457
2525
  }
2526
+ const message = `Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
2527
+ const retryError = nodeRetryError("kv", message, response, errorText);
2528
+ if (retryError) return err(retryError);
2458
2529
  return err(serviceError(
2459
2530
  ErrorCodes.NETWORK_ERROR,
2460
- `Failed to get key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2531
+ message,
2461
2532
  "kv",
2462
2533
  { meta: { status: response.status, statusText: response.statusText } }
2463
2534
  ));
@@ -2539,19 +2610,14 @@ var KVService = class extends BaseService {
2539
2610
  { meta: { status: response.status, statusText: response.statusText } }
2540
2611
  ));
2541
2612
  }
2542
- if (response.status === 503 && (options?.ifMatch !== void 0 || options?.ifNoneMatch !== void 0)) {
2543
- return err(serviceError(
2544
- ErrorCodes.KV_CONFLICT,
2545
- `Concurrent KV update conflicted for key ${JSON.stringify(key)}`,
2546
- "kv",
2547
- { meta: { status: response.status, statusText: response.statusText } }
2548
- ));
2549
- }
2613
+ const message = `Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
2614
+ const retryError = nodeRetryError("kv", message, response, errorText);
2615
+ if (retryError) return err(retryError);
2550
2616
  const quotaError = this.handleQuotaErrorResponse(response, errorText, key);
2551
2617
  if (quotaError) return quotaError;
2552
2618
  return err(serviceError(
2553
2619
  ErrorCodes.KV_WRITE_FAILED,
2554
- `Failed to put key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
2620
+ message,
2555
2621
  "kv",
2556
2622
  { meta: { status: response.status, statusText: response.statusText } }
2557
2623
  ));
@@ -2851,9 +2917,12 @@ var KVService = class extends BaseService {
2851
2917
  );
2852
2918
  }
2853
2919
  const errorText = await response.text();
2920
+ const message = `Failed to list keys: ${response.status} - ${errorText}`;
2921
+ const retryError = nodeRetryError("kv", message, response, errorText);
2922
+ if (retryError) return err(retryError);
2854
2923
  return err(serviceError(
2855
2924
  ErrorCodes.NETWORK_ERROR,
2856
- `Failed to list keys: ${response.status} - ${errorText}`,
2925
+ message,
2857
2926
  "kv",
2858
2927
  { meta: { status: response.status, statusText: response.statusText } }
2859
2928
  ));
@@ -3104,17 +3173,12 @@ var KVService = class extends BaseService {
3104
3173
  { meta: { status: response.status, statusText: response.statusText } }
3105
3174
  ));
3106
3175
  }
3107
- if (response.status === 503 && options?.ifMatch !== void 0) {
3108
- return err(serviceError(
3109
- ErrorCodes.KV_CONFLICT,
3110
- `Concurrent KV delete conflicted for key ${JSON.stringify(key)}`,
3111
- "kv",
3112
- { meta: { status: response.status, statusText: response.statusText } }
3113
- ));
3114
- }
3176
+ const message = `Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
3177
+ const retryError = nodeRetryError("kv", message, response, errorText);
3178
+ if (retryError) return err(retryError);
3115
3179
  return err(serviceError(
3116
3180
  ErrorCodes.NETWORK_ERROR,
3117
- `Failed to delete key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
3181
+ message,
3118
3182
  "kv",
3119
3183
  { meta: { status: response.status, statusText: response.statusText } }
3120
3184
  ));
@@ -3155,10 +3219,13 @@ var KVService = class extends BaseService {
3155
3219
  return await this.classifyNotFound(response, key);
3156
3220
  }
3157
3221
  const errorText = await response.text();
3222
+ const message = `Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`;
3223
+ const retryError = nodeRetryError("kv", message, response, errorText);
3224
+ if (retryError) return err(retryError);
3158
3225
  return err(
3159
3226
  serviceError(
3160
3227
  ErrorCodes.NETWORK_ERROR,
3161
- `Failed to get metadata for key ${JSON.stringify(key)}: ${response.status} - ${errorText}`,
3228
+ message,
3162
3229
  "kv",
3163
3230
  { meta: { status: response.status, statusText: response.statusText } }
3164
3231
  )
@@ -3350,42 +3417,6 @@ function requiresSecretsOptIn(space, prefix) {
3350
3417
  return prefix.split("/", 1)[0] === "vault";
3351
3418
  }
3352
3419
 
3353
- // src/responseErrors.ts
3354
- function parseServiceErrorBody(errorText) {
3355
- try {
3356
- return JSON.parse(errorText);
3357
- } catch {
3358
- return {};
3359
- }
3360
- }
3361
- function formatServiceResponseError(serviceLabel, operation, status, errorText, parsed) {
3362
- if (parsed.message) {
3363
- return compactMessage(parsed.message);
3364
- }
3365
- if (looksLikeHtml(errorText)) {
3366
- if (status === 524 || /524\s*[:-]/i.test(errorText) || /a timeout occurred/i.test(errorText)) {
3367
- return `${serviceLabel} ${operation} failed: upstream request timed out. Please retry.`;
3368
- }
3369
- return `${serviceLabel} ${operation} failed: upstream service returned an HTML error page (${status}).`;
3370
- }
3371
- return `${serviceLabel} ${operation} failed: ${status} - ${compactMessage(errorText)}`;
3372
- }
3373
- function responseErrorMeta(status, statusText, errorText) {
3374
- const meta = { status, statusText };
3375
- const snippet = compactMessage(errorText);
3376
- if (snippet) {
3377
- meta.responseSnippet = snippet.slice(0, 300);
3378
- }
3379
- return meta;
3380
- }
3381
- function looksLikeHtml(text) {
3382
- return /<!doctype html/i.test(text) || /<html[\s>]/i.test(text);
3383
- }
3384
- function compactMessage(message) {
3385
- const compact = message.replace(/\s+/g, " ").trim();
3386
- return compact.length > 500 ? `${compact.slice(0, 500)}...` : compact;
3387
- }
3388
-
3389
3420
  // src/sql/SQLMigrations.ts
3390
3421
  var SQLMigrations = class {
3391
3422
  constructor(service, dbName) {
@@ -3801,6 +3832,8 @@ var SQLService = class extends BaseService {
3801
3832
  if (response.status === 413 && parseStorageRejection(errorText)) {
3802
3833
  return err(storageRejectionError("sql", 413, meta, errorText));
3803
3834
  }
3835
+ const retryError = nodeRetryError("sql", `SQL ${operation} failed: ${response.status} - ${errorText}`, response, errorText);
3836
+ if (retryError) return err(retryError);
3804
3837
  const errorBody = parseServiceErrorBody(errorText);
3805
3838
  const errorCode = this.mapHttpStatusToErrorCode(
3806
3839
  response.status,
@@ -4270,6 +4303,8 @@ var DuckDbService = class extends BaseService {
4270
4303
  if (response.status === 413 && parseStorageRejection(errorText)) {
4271
4304
  return err(storageRejectionError("duckdb", 413, meta, errorText));
4272
4305
  }
4306
+ const retryError = nodeRetryError("duckdb", `DuckDB ${operation} failed: ${response.status} - ${errorText}`, response, errorText);
4307
+ if (retryError) return err(retryError);
4273
4308
  const errorBody = parseServiceErrorBody(errorText);
4274
4309
  const errorCode = this.mapHttpStatusToErrorCode(
4275
4310
  response.status,
@@ -5477,6 +5512,116 @@ var TinyCloudQuota = class {
5477
5512
  }
5478
5513
  };
5479
5514
 
5515
+ // src/encryption/canonical.ts
5516
+ function canonicalize(value) {
5517
+ if (value === void 0) {
5518
+ return "";
5519
+ }
5520
+ return stringify(value);
5521
+ }
5522
+ function stringify(value) {
5523
+ if (value === null) return "null";
5524
+ switch (typeof value) {
5525
+ case "boolean":
5526
+ case "number":
5527
+ return JSON.stringify(value);
5528
+ case "string":
5529
+ return JSON.stringify(value);
5530
+ case "object": {
5531
+ if (Array.isArray(value)) {
5532
+ return `[${value.map(stringify).join(",")}]`;
5533
+ }
5534
+ const keys = Object.keys(value).sort();
5535
+ const parts = [];
5536
+ for (const k of keys) {
5537
+ const v = value[k];
5538
+ if (v === void 0) continue;
5539
+ parts.push(`${JSON.stringify(k)}:${stringify(v)}`);
5540
+ }
5541
+ return `{${parts.join(",")}}`;
5542
+ }
5543
+ default:
5544
+ throw new TypeError(
5545
+ `canonicalize: unsupported value type ${typeof value}`
5546
+ );
5547
+ }
5548
+ }
5549
+ var HEX = "0123456789abcdef";
5550
+ function hexEncode(bytes) {
5551
+ let out = "";
5552
+ for (let i = 0; i < bytes.length; i++) {
5553
+ const b = bytes[i];
5554
+ out += HEX[b >> 4 & 15] + HEX[b & 15];
5555
+ }
5556
+ return out;
5557
+ }
5558
+ function hexDecode(hex) {
5559
+ if (hex.length % 2 !== 0) {
5560
+ throw new Error("hex string must have even length");
5561
+ }
5562
+ const out = new Uint8Array(hex.length / 2);
5563
+ for (let i = 0; i < out.length; i++) {
5564
+ const hi = parseInt(hex[i * 2], 16);
5565
+ const lo = parseInt(hex[i * 2 + 1], 16);
5566
+ if (Number.isNaN(hi) || Number.isNaN(lo)) {
5567
+ throw new Error("invalid hex character");
5568
+ }
5569
+ out[i] = hi << 4 | lo;
5570
+ }
5571
+ return out;
5572
+ }
5573
+ function base64Encode(bytes) {
5574
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5575
+ let out = "";
5576
+ for (let i = 0; i < bytes.length; i += 3) {
5577
+ const b0 = bytes[i];
5578
+ const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
5579
+ const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
5580
+ out += chars[b0 >> 2 & 63];
5581
+ out += chars[(b0 << 4 | b1 >> 4) & 63];
5582
+ out += i + 1 < bytes.length ? chars[(b1 << 2 | b2 >> 6) & 63] : "=";
5583
+ out += i + 2 < bytes.length ? chars[b2 & 63] : "=";
5584
+ }
5585
+ return out;
5586
+ }
5587
+ function base64Decode(s) {
5588
+ const clean = s.replace(/[^A-Za-z0-9+/=]/g, "");
5589
+ const len = clean.length;
5590
+ if (len % 4 !== 0) {
5591
+ throw new Error("invalid base64 input");
5592
+ }
5593
+ const padding = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
5594
+ const outLen = len / 4 * 3 - padding;
5595
+ const out = new Uint8Array(outLen);
5596
+ const lookup = {};
5597
+ const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
5598
+ for (let i = 0; i < chars.length; i++) lookup[chars[i]] = i;
5599
+ let outIdx = 0;
5600
+ for (let i = 0; i < len; i += 4) {
5601
+ const v0 = lookup[clean[i]] ?? 0;
5602
+ const v1 = lookup[clean[i + 1]] ?? 0;
5603
+ const v2 = clean[i + 2] === "=" ? 0 : lookup[clean[i + 2]] ?? 0;
5604
+ const v3 = clean[i + 3] === "=" ? 0 : lookup[clean[i + 3]] ?? 0;
5605
+ const b0 = v0 << 2 | v1 >> 4;
5606
+ const b1 = (v1 & 15) << 4 | v2 >> 2;
5607
+ const b2 = (v2 & 3) << 6 | v3;
5608
+ if (outIdx < outLen) out[outIdx++] = b0;
5609
+ if (outIdx < outLen) out[outIdx++] = b1;
5610
+ if (outIdx < outLen) out[outIdx++] = b2;
5611
+ }
5612
+ return out;
5613
+ }
5614
+ function utf8Encode(s) {
5615
+ return new TextEncoder().encode(s);
5616
+ }
5617
+ function utf8Decode(b) {
5618
+ return new TextDecoder().decode(b);
5619
+ }
5620
+ function canonicalHashHex(sha256, value) {
5621
+ const canonical = canonicalize(value);
5622
+ return hexEncode(sha256(utf8Encode(canonical)));
5623
+ }
5624
+
5480
5625
  // src/vault/types.ts
5481
5626
  var VaultPublicSpaceKVActions = [
5482
5627
  "tinycloud.kv/get",
@@ -5646,7 +5791,7 @@ function toBytes(str) {
5646
5791
  function fromBytes(bytes) {
5647
5792
  return new TextDecoder().decode(bytes);
5648
5793
  }
5649
- function hexEncode(bytes) {
5794
+ function hexEncode2(bytes) {
5650
5795
  return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
5651
5796
  }
5652
5797
  function concatBytes(...arrays) {
@@ -5659,14 +5804,14 @@ function concatBytes(...arrays) {
5659
5804
  }
5660
5805
  return result;
5661
5806
  }
5662
- function base64Encode(bytes) {
5807
+ function base64Encode2(bytes) {
5663
5808
  let binary = "";
5664
5809
  for (let i = 0; i < bytes.length; i++) {
5665
5810
  binary += String.fromCharCode(bytes[i]);
5666
5811
  }
5667
5812
  return btoa(binary);
5668
5813
  }
5669
- function base64Decode(str) {
5814
+ function base64Decode2(str) {
5670
5815
  const binary = atob(str);
5671
5816
  const bytes = new Uint8Array(binary.length);
5672
5817
  for (let i = 0; i < binary.length; i++) {
@@ -5708,6 +5853,11 @@ function defaultVaultMessage(input) {
5708
5853
  return input.message;
5709
5854
  case "PERMISSION_DENIED":
5710
5855
  return input.message;
5856
+ case "AAD_MISMATCH":
5857
+ case "ETAG_MISMATCH":
5858
+ case "INVALID_ETAG":
5859
+ case "OUTCOME_UNKNOWN":
5860
+ case "NODE_BUSY":
5711
5861
  case "STORAGE_QUOTA_EXCEEDED":
5712
5862
  case "STORAGE_LIMIT_REACHED":
5713
5863
  return input.message;
@@ -5730,6 +5880,37 @@ function typedKvCause(error) {
5730
5880
  ...error.cause !== void 0 ? { cause: error.cause } : {}
5731
5881
  });
5732
5882
  }
5883
+ function canonicalAadSpaceId(spaceId) {
5884
+ return spaceId.replace(/0x[0-9a-fA-F]{40}/g, (address) => address.toLowerCase());
5885
+ }
5886
+ function checkEnvelopeAad(value, spaceId, key) {
5887
+ const e = value;
5888
+ if (typeof e !== "object" || e === null || Array.isArray(e) || !["networkId", "alg", "encryptedSymmetricKey", "encryptedSymmetricKeyHash", "ciphertext"].every(
5889
+ (field) => typeof e[field] === "string" && e[field] !== ""
5890
+ ) || !Number.isInteger(e.keyVersion) || e.aad !== void 0 && typeof e.aad !== "string") {
5891
+ return "corrupt";
5892
+ }
5893
+ let aad = "";
5894
+ try {
5895
+ if (typeof e.aad === "string") aad = fromBytes(base64Decode(e.aad));
5896
+ } catch {
5897
+ }
5898
+ const suffix = `:${key}`;
5899
+ return aad.endsWith(suffix) && canonicalAadSpaceId(aad.slice(0, -suffix.length)) === canonicalAadSpaceId(`tinycloud.vault:${spaceId}`) ? "ok" : "mismatch";
5900
+ }
5901
+ var AMBIGUOUS_WRITE_STATUSES = [500, 502, 503, 504, 520, 522, 524];
5902
+ function ifMatchWriteError(key, error) {
5903
+ const status = error.meta?.status;
5904
+ 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;
5905
+ if (code === void 0) return void 0;
5906
+ return vaultError({
5907
+ code,
5908
+ key,
5909
+ message: error.message,
5910
+ ...error.meta !== void 0 ? { meta: error.meta } : {},
5911
+ cause: typedKvCause(error)
5912
+ });
5913
+ }
5733
5914
  function kvWriteError(context, error) {
5734
5915
  if (error.code === ErrorCodes.STORAGE_QUOTA_EXCEEDED || error.code === ErrorCodes.STORAGE_LIMIT_REACHED) {
5735
5916
  return vaultError({ code: error.code, message: error.message, meta: error.meta });
@@ -5916,7 +6097,7 @@ var DataVaultService = class extends BaseService {
5916
6097
  }
5917
6098
  if (existingPubKey) {
5918
6099
  this.encryptionIdentity = {
5919
- publicKey: base64Decode(existingPubKey),
6100
+ publicKey: base64Decode2(existingPubKey),
5920
6101
  privateKey: new Uint8Array(0)
5921
6102
  // private key not available without signing
5922
6103
  };
@@ -5941,7 +6122,7 @@ var DataVaultService = class extends BaseService {
5941
6122
  );
5942
6123
  this.encryptionIdentity = this.crypto.x25519FromSeed(seed);
5943
6124
  try {
5944
- const pubKeyB64 = base64Encode(this.encryptionIdentity.publicKey);
6125
+ const pubKeyB64 = base64Encode2(this.encryptionIdentity.publicKey);
5945
6126
  await this.tc.ensurePublicSpace();
5946
6127
  await this.tc.publicKV.put(".well-known/vault-pubkey", pubKeyB64);
5947
6128
  await this.tc.publicKV.put(".well-known/vault-version", CURRENT_VAULT_VERSION);
@@ -6007,6 +6188,21 @@ var DataVaultService = class extends BaseService {
6007
6188
  message: "Authentication required"
6008
6189
  });
6009
6190
  }
6191
+ if (options?.ifMatch !== void 0) {
6192
+ if (options.ifNoneMatch !== void 0) {
6193
+ return vaultError({
6194
+ code: "STORAGE_ERROR",
6195
+ cause: new Error("ifMatch cannot be combined with ifNoneMatch")
6196
+ });
6197
+ }
6198
+ if (!/^"[^"\s]+"$/.test(options.ifMatch)) {
6199
+ return vaultError({
6200
+ code: "INVALID_ETAG",
6201
+ key,
6202
+ 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"
6203
+ });
6204
+ }
6205
+ }
6010
6206
  try {
6011
6207
  const { plaintext, contentType } = this.serializeValue(value, options);
6012
6208
  const metadata = {
@@ -6029,7 +6225,8 @@ var DataVaultService = class extends BaseService {
6029
6225
  }
6030
6226
  const valuePath = `vault/${key}`;
6031
6227
  const valueBody = JSON.stringify(envelopeResult.data);
6032
- const valuePutResult = options?.ifNoneMatch !== void 0 ? await this.tc.kv.put(valuePath, valueBody, { ifNoneMatch: options.ifNoneMatch }) : await this.tc.kv.put(valuePath, valueBody);
6228
+ const putOptions = options?.ifMatch !== void 0 ? { ifMatch: options.ifMatch } : options?.ifNoneMatch !== void 0 ? { ifNoneMatch: options.ifNoneMatch } : void 0;
6229
+ const valuePutResult = putOptions !== void 0 ? await this.tc.kv.put(valuePath, valueBody, putOptions) : await this.tc.kv.put(valuePath, valueBody);
6033
6230
  if (!valuePutResult.ok) {
6034
6231
  if (options?.ifNoneMatch !== void 0 && valuePutResult.error.code === ErrorCodes.KV_PRECONDITION_FAILED) {
6035
6232
  return vaultError({
@@ -6039,6 +6236,10 @@ var DataVaultService = class extends BaseService {
6039
6236
  cause: typedKvCause(valuePutResult.error)
6040
6237
  });
6041
6238
  }
6239
+ if (options?.ifMatch !== void 0) {
6240
+ const classified = ifMatchWriteError(key, valuePutResult.error);
6241
+ if (classified !== void 0) return classified;
6242
+ }
6042
6243
  return kvWriteError("Failed to store encrypted value", valuePutResult.error);
6043
6244
  }
6044
6245
  return { ok: true, data: void 0 };
@@ -6073,6 +6274,19 @@ var DataVaultService = class extends BaseService {
6073
6274
  }
6074
6275
  const rawEnvelope = unwrapKVData(valueResult.data);
6075
6276
  const envelope = typeof rawEnvelope === "string" ? JSON.parse(rawEnvelope) : rawEnvelope;
6277
+ if (options?.expectAad === true) {
6278
+ const verdict = checkEnvelopeAad(envelope, this.vaultConfig.spaceId, key);
6279
+ if (verdict === "corrupt") {
6280
+ return vaultError({ code: "DECRYPTION_FAILED", message: "envelope is malformed" });
6281
+ }
6282
+ if (verdict === "mismatch") {
6283
+ return vaultError({
6284
+ code: "AAD_MISMATCH",
6285
+ key,
6286
+ message: `Envelope at ${key} is not bound to this space and key`
6287
+ });
6288
+ }
6289
+ }
6076
6290
  const proof = await this.decryptCapabilityProof();
6077
6291
  const plaintextResult = await config.service.decryptEnvelope(envelope, proof);
6078
6292
  if (!plaintextResult.ok) {
@@ -6089,7 +6303,11 @@ var DataVaultService = class extends BaseService {
6089
6303
  contentType,
6090
6304
  options
6091
6305
  );
6092
- return { ok: true, data: { value, metadata, keyId } };
6306
+ const etag = options?.source === "network" ? valueResult.data.headers?.etag : void 0;
6307
+ return {
6308
+ ok: true,
6309
+ data: { value, metadata, keyId, ...etag === void 0 ? {} : { etag } }
6310
+ };
6093
6311
  } catch (error) {
6094
6312
  return vaultError({
6095
6313
  code: "STORAGE_ERROR",
@@ -6135,6 +6353,12 @@ var DataVaultService = class extends BaseService {
6135
6353
  } catch {
6136
6354
  return { status: "corrupt_envelope" };
6137
6355
  }
6356
+ if (options?.expectAad === true) {
6357
+ const verdict = checkEnvelopeAad(envelope, this.vaultConfig.spaceId, key);
6358
+ if (verdict !== "ok") {
6359
+ return { status: verdict === "corrupt" ? "corrupt_envelope" : "aad_mismatch" };
6360
+ }
6361
+ }
6138
6362
  let plaintextResult;
6139
6363
  try {
6140
6364
  const proof = await this.decryptCapabilityProof();
@@ -6166,7 +6390,11 @@ var DataVaultService = class extends BaseService {
6166
6390
  contentType,
6167
6391
  options
6168
6392
  );
6169
- return { status: "ok", entry: { value, metadata, keyId } };
6393
+ const etag = valueResult.data.headers?.etag;
6394
+ return {
6395
+ status: "ok",
6396
+ entry: { value, metadata, keyId, ...etag === void 0 ? {} : { etag } }
6397
+ };
6170
6398
  } catch {
6171
6399
  return { status: "invalid_payload" };
6172
6400
  }
@@ -6216,6 +6444,14 @@ var DataVaultService = class extends BaseService {
6216
6444
  )
6217
6445
  });
6218
6446
  }
6447
+ if (options?.ifMatch !== void 0) {
6448
+ return vaultError({
6449
+ code: "STORAGE_ERROR",
6450
+ cause: new Error(
6451
+ "ifMatch is only supported by network-encrypted vaults"
6452
+ )
6453
+ });
6454
+ }
6219
6455
  if (!this._isUnlocked || !this.masterKey) {
6220
6456
  return vaultError({
6221
6457
  code: "VAULT_LOCKED",
@@ -6241,7 +6477,7 @@ var DataVaultService = class extends BaseService {
6241
6477
  }
6242
6478
  const contentType = options?.contentType ?? (value instanceof Uint8Array ? "application/octet-stream" : "application/json");
6243
6479
  const entryKey = this.crypto.randomBytes(32);
6244
- const keyId = hexEncode(this.crypto.sha256(entryKey)).slice(0, 16);
6480
+ const keyId = hexEncode2(this.crypto.sha256(entryKey)).slice(0, 16);
6245
6481
  const encrypted = this.crypto.encrypt(entryKey, plaintext);
6246
6482
  const keyBlob = this.crypto.encrypt(this.masterKey, entryKey);
6247
6483
  const metadata = {
@@ -6259,7 +6495,7 @@ var DataVaultService = class extends BaseService {
6259
6495
  ...metadata
6260
6496
  });
6261
6497
  const keyPayload = JSON.stringify({
6262
- key: base64Encode(keyBlob),
6498
+ key: base64Encode2(keyBlob),
6263
6499
  metadata: keyMetadata
6264
6500
  });
6265
6501
  const keyPutResult = await this.tc.kv.put(
@@ -6270,7 +6506,7 @@ var DataVaultService = class extends BaseService {
6270
6506
  return kvWriteError("Failed to store key blob", keyPutResult.error);
6271
6507
  }
6272
6508
  const valuePayload = JSON.stringify({
6273
- data: base64Encode(encrypted),
6509
+ data: base64Encode2(encrypted),
6274
6510
  metadata
6275
6511
  });
6276
6512
  const valuePutResult = await this.tc.kv.put(
@@ -6301,6 +6537,12 @@ var DataVaultService = class extends BaseService {
6301
6537
  if (this.usesNetworkEncryption) {
6302
6538
  return this.getNetworkEncrypted(key, options);
6303
6539
  }
6540
+ if (options?.expectAad === true) {
6541
+ return vaultError({
6542
+ code: "STORAGE_ERROR",
6543
+ cause: new Error("expectAad is only supported by network-encrypted vaults")
6544
+ });
6545
+ }
6304
6546
  if (!this._isUnlocked || !this.masterKey) {
6305
6547
  return vaultError({
6306
6548
  code: "VAULT_LOCKED",
@@ -6322,7 +6564,7 @@ var DataVaultService = class extends BaseService {
6322
6564
  return vaultError({ code: "KEY_NOT_FOUND", key });
6323
6565
  }
6324
6566
  const keyEnvelope = JSON.parse(keyResult.data.data);
6325
- const keyBlobBytes = base64Decode(keyEnvelope.key);
6567
+ const keyBlobBytes = base64Decode2(keyEnvelope.key);
6326
6568
  const entryKey = this.crypto.decrypt(this.masterKey, keyBlobBytes);
6327
6569
  const valueResult = await this.tc.kv.get(`vault/${key}`, {
6328
6570
  raw: true,
@@ -6332,7 +6574,7 @@ var DataVaultService = class extends BaseService {
6332
6574
  return vaultError({ code: "KEY_NOT_FOUND", key });
6333
6575
  }
6334
6576
  const valueEnvelope = JSON.parse(valueResult.data.data);
6335
- const encryptedBytes = base64Decode(valueEnvelope.data);
6577
+ const encryptedBytes = base64Decode2(valueEnvelope.data);
6336
6578
  const plaintext = this.crypto.decrypt(entryKey, encryptedBytes);
6337
6579
  const metadata = valueEnvelope.metadata ?? {};
6338
6580
  const contentType = metadata[VaultHeaders.CONTENT_TYPE] ?? "application/json";
@@ -6580,7 +6822,7 @@ var DataVaultService = class extends BaseService {
6580
6822
  return vaultError({ code: "KEY_NOT_FOUND", key });
6581
6823
  }
6582
6824
  const keyEnvelope = JSON.parse(keyResult.data.data);
6583
- const keyBlobBytes = base64Decode(keyEnvelope.key);
6825
+ const keyBlobBytes = base64Decode2(keyEnvelope.key);
6584
6826
  const entryKey = this.crypto.decrypt(this.masterKey, keyBlobBytes);
6585
6827
  const ephemeralSeed = this.crypto.randomBytes(32);
6586
6828
  const ephemeralKeyPair = this.crypto.x25519FromSeed(ephemeralSeed);
@@ -6599,7 +6841,7 @@ var DataVaultService = class extends BaseService {
6599
6841
  encryptedGrant
6600
6842
  );
6601
6843
  const grantPayload = JSON.stringify({
6602
- grant: base64Encode(grantBlob),
6844
+ grant: base64Encode2(grantBlob),
6603
6845
  spaceId: this.vaultConfig.spaceId,
6604
6846
  metadata: {
6605
6847
  [VaultHeaders.GRANT_VERSION]: "1",
@@ -6639,6 +6881,14 @@ var DataVaultService = class extends BaseService {
6639
6881
  */
6640
6882
  async getShared(grantorDID, key, options) {
6641
6883
  return this.withTelemetry("getShared", key, async () => {
6884
+ if (options?.expectAad === true) {
6885
+ return vaultError({
6886
+ code: "STORAGE_ERROR",
6887
+ cause: new Error(
6888
+ "expectAad is not supported by getShared: the AAD binds the grantor's space, which this vault does not know"
6889
+ )
6890
+ });
6891
+ }
6642
6892
  if (this.usesNetworkEncryption) {
6643
6893
  const grantorKV = options?.kv;
6644
6894
  if (!grantorKV) {
@@ -6733,7 +6983,7 @@ var DataVaultService = class extends BaseService {
6733
6983
  });
6734
6984
  }
6735
6985
  const grantEnvelope = typeof grantResult.data?.data === "string" ? JSON.parse(grantResult.data.data) : grantResult.data?.data;
6736
- const grantBlobBytes = base64Decode(grantEnvelope.grant);
6986
+ const grantBlobBytes = base64Decode2(grantEnvelope.grant);
6737
6987
  const ephemeralPubKey = grantBlobBytes.slice(0, 32);
6738
6988
  const encryptedGrant = grantBlobBytes.slice(32);
6739
6989
  const sharedSecret = this.crypto.x25519Dh(
@@ -6756,7 +7006,7 @@ var DataVaultService = class extends BaseService {
6756
7006
  });
6757
7007
  }
6758
7008
  const valueEnvelope = typeof valueResult.data?.data === "string" ? JSON.parse(valueResult.data.data) : valueResult.data?.data;
6759
- const encryptedBytes = base64Decode(valueEnvelope.data);
7009
+ const encryptedBytes = base64Decode2(valueEnvelope.data);
6760
7010
  const plaintext = this.crypto.decrypt(entryKey, encryptedBytes);
6761
7011
  const metadata = valueEnvelope.metadata ?? {};
6762
7012
  const contentType = metadata[VaultHeaders.CONTENT_TYPE] ?? "application/json";
@@ -6810,7 +7060,7 @@ var DataVaultService = class extends BaseService {
6810
7060
  if (!result.ok) {
6811
7061
  return vaultError({ code: "PUBLIC_KEY_NOT_FOUND", did });
6812
7062
  }
6813
- const pubKeyBytes = base64Decode(result.data);
7063
+ const pubKeyBytes = base64Decode2(result.data);
6814
7064
  return { ok: true, data: pubKeyBytes };
6815
7065
  } catch (error) {
6816
7066
  return vaultError({ code: "PUBLIC_KEY_NOT_FOUND", did });
@@ -6929,7 +7179,7 @@ var DataVaultService = class extends BaseService {
6929
7179
  }
6930
7180
  const currentEntry = getResult.data;
6931
7181
  const newEntryKey = this.crypto.randomBytes(32);
6932
- const newKeyId = hexEncode(this.crypto.sha256(newEntryKey)).slice(
7182
+ const newKeyId = hexEncode2(this.crypto.sha256(newEntryKey)).slice(
6933
7183
  0,
6934
7184
  16
6935
7185
  );
@@ -6946,7 +7196,7 @@ var DataVaultService = class extends BaseService {
6946
7196
  [VaultHeaders.KEY_ID]: newKeyId
6947
7197
  };
6948
7198
  const keyPayload = JSON.stringify({
6949
- key: base64Encode(newKeyBlob),
7199
+ key: base64Encode2(newKeyBlob),
6950
7200
  metadata: JSON.stringify({
6951
7201
  keyId: newKeyId,
6952
7202
  ...metadata
@@ -6960,7 +7210,7 @@ var DataVaultService = class extends BaseService {
6960
7210
  return kvWriteError("Failed to store rotated key blob", keyPutResult.error);
6961
7211
  }
6962
7212
  const valuePayload = JSON.stringify({
6963
- data: base64Encode(encrypted),
7213
+ data: base64Encode2(encrypted),
6964
7214
  metadata
6965
7215
  });
6966
7216
  const valuePutResult = await this.tc.kv.put(
@@ -7252,116 +7502,6 @@ var SecretsService = class {
7252
7502
  }
7253
7503
  };
7254
7504
 
7255
- // src/encryption/canonical.ts
7256
- function canonicalize(value) {
7257
- if (value === void 0) {
7258
- return "";
7259
- }
7260
- return stringify(value);
7261
- }
7262
- function stringify(value) {
7263
- if (value === null) return "null";
7264
- switch (typeof value) {
7265
- case "boolean":
7266
- case "number":
7267
- return JSON.stringify(value);
7268
- case "string":
7269
- return JSON.stringify(value);
7270
- case "object": {
7271
- if (Array.isArray(value)) {
7272
- return `[${value.map(stringify).join(",")}]`;
7273
- }
7274
- const keys = Object.keys(value).sort();
7275
- const parts = [];
7276
- for (const k of keys) {
7277
- const v = value[k];
7278
- if (v === void 0) continue;
7279
- parts.push(`${JSON.stringify(k)}:${stringify(v)}`);
7280
- }
7281
- return `{${parts.join(",")}}`;
7282
- }
7283
- default:
7284
- throw new TypeError(
7285
- `canonicalize: unsupported value type ${typeof value}`
7286
- );
7287
- }
7288
- }
7289
- var HEX = "0123456789abcdef";
7290
- function hexEncode2(bytes) {
7291
- let out = "";
7292
- for (let i = 0; i < bytes.length; i++) {
7293
- const b = bytes[i];
7294
- out += HEX[b >> 4 & 15] + HEX[b & 15];
7295
- }
7296
- return out;
7297
- }
7298
- function hexDecode(hex) {
7299
- if (hex.length % 2 !== 0) {
7300
- throw new Error("hex string must have even length");
7301
- }
7302
- const out = new Uint8Array(hex.length / 2);
7303
- for (let i = 0; i < out.length; i++) {
7304
- const hi = parseInt(hex[i * 2], 16);
7305
- const lo = parseInt(hex[i * 2 + 1], 16);
7306
- if (Number.isNaN(hi) || Number.isNaN(lo)) {
7307
- throw new Error("invalid hex character");
7308
- }
7309
- out[i] = hi << 4 | lo;
7310
- }
7311
- return out;
7312
- }
7313
- function base64Encode2(bytes) {
7314
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7315
- let out = "";
7316
- for (let i = 0; i < bytes.length; i += 3) {
7317
- const b0 = bytes[i];
7318
- const b1 = i + 1 < bytes.length ? bytes[i + 1] : 0;
7319
- const b2 = i + 2 < bytes.length ? bytes[i + 2] : 0;
7320
- out += chars[b0 >> 2 & 63];
7321
- out += chars[(b0 << 4 | b1 >> 4) & 63];
7322
- out += i + 1 < bytes.length ? chars[(b1 << 2 | b2 >> 6) & 63] : "=";
7323
- out += i + 2 < bytes.length ? chars[b2 & 63] : "=";
7324
- }
7325
- return out;
7326
- }
7327
- function base64Decode2(s) {
7328
- const clean = s.replace(/[^A-Za-z0-9+/=]/g, "");
7329
- const len = clean.length;
7330
- if (len % 4 !== 0) {
7331
- throw new Error("invalid base64 input");
7332
- }
7333
- const padding = clean.endsWith("==") ? 2 : clean.endsWith("=") ? 1 : 0;
7334
- const outLen = len / 4 * 3 - padding;
7335
- const out = new Uint8Array(outLen);
7336
- const lookup = {};
7337
- const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7338
- for (let i = 0; i < chars.length; i++) lookup[chars[i]] = i;
7339
- let outIdx = 0;
7340
- for (let i = 0; i < len; i += 4) {
7341
- const v0 = lookup[clean[i]] ?? 0;
7342
- const v1 = lookup[clean[i + 1]] ?? 0;
7343
- const v2 = clean[i + 2] === "=" ? 0 : lookup[clean[i + 2]] ?? 0;
7344
- const v3 = clean[i + 3] === "=" ? 0 : lookup[clean[i + 3]] ?? 0;
7345
- const b0 = v0 << 2 | v1 >> 4;
7346
- const b1 = (v1 & 15) << 4 | v2 >> 2;
7347
- const b2 = (v2 & 3) << 6 | v3;
7348
- if (outIdx < outLen) out[outIdx++] = b0;
7349
- if (outIdx < outLen) out[outIdx++] = b1;
7350
- if (outIdx < outLen) out[outIdx++] = b2;
7351
- }
7352
- return out;
7353
- }
7354
- function utf8Encode(s) {
7355
- return new TextEncoder().encode(s);
7356
- }
7357
- function utf8Decode(b) {
7358
- return new TextDecoder().decode(b);
7359
- }
7360
- function canonicalHashHex(sha256, value) {
7361
- const canonical = canonicalize(value);
7362
- return hexEncode2(sha256(utf8Encode(canonical)));
7363
- }
7364
-
7365
7505
  // src/encryption/types.ts
7366
7506
  var DEFAULT_ENCRYPTION_ALG = "x25519-aes256gcm/v1";
7367
7507
  var ENVELOPE_VERSION = 1;
@@ -7571,7 +7711,7 @@ function encryptToNetwork(crypto2, input) {
7571
7711
  const symmetricKey = crypto2.randomBytes(32);
7572
7712
  const ciphertext = crypto2.authEncrypt(symmetricKey, input.plaintext, input.aad);
7573
7713
  const wrapped = crypto2.sealToNetworkKey(input.networkPublicKey, symmetricKey);
7574
- const encryptedSymmetricKey = base64Encode2(wrapped);
7714
+ const encryptedSymmetricKey = base64Encode(wrapped);
7575
7715
  const encryptedSymmetricKeyHash = canonicalHashHex(
7576
7716
  crypto2.sha256,
7577
7717
  encryptedSymmetricKey
@@ -7583,8 +7723,8 @@ function encryptToNetwork(crypto2, input) {
7583
7723
  keyVersion,
7584
7724
  encryptedSymmetricKey,
7585
7725
  encryptedSymmetricKeyHash,
7586
- ciphertext: base64Encode2(ciphertext),
7587
- ...input.aad !== void 0 ? { aad: base64Encode2(input.aad) } : {},
7726
+ ciphertext: base64Encode(ciphertext),
7727
+ ...input.aad !== void 0 ? { aad: base64Encode(input.aad) } : {},
7588
7728
  ...input.metadata !== void 0 ? { metadata: input.metadata } : {}
7589
7729
  };
7590
7730
  return { envelope, symmetricKey };
@@ -7658,8 +7798,8 @@ function validateEnvelope(crypto2, envelope) {
7658
7798
  return { ok: true, data: e };
7659
7799
  }
7660
7800
  function decryptEnvelopeWithKey(crypto2, envelope, symmetricKey) {
7661
- const ciphertext = base64Decode2(envelope.ciphertext);
7662
- const aad = envelope.aad !== void 0 ? base64Decode2(envelope.aad) : void 0;
7801
+ const ciphertext = base64Decode(envelope.ciphertext);
7802
+ const aad = envelope.aad !== void 0 ? base64Decode(envelope.aad) : void 0;
7663
7803
  return crypto2.authDecrypt(symmetricKey, ciphertext, aad);
7664
7804
  }
7665
7805
 
@@ -7677,7 +7817,7 @@ function buildCanonicalDecryptRequest(input) {
7677
7817
  return { canonicalBody, bodyHash, receiverPublicKeyHash };
7678
7818
  }
7679
7819
  function buildDecryptFacts(input) {
7680
- const bodyHash = input.canonicalBody !== void 0 ? hexEncode2(input.crypto.sha256(utf8Encode(input.canonicalBody))) : canonicalHashHex(
7820
+ const bodyHash = input.canonicalBody !== void 0 ? hexEncode(input.crypto.sha256(utf8Encode(input.canonicalBody))) : canonicalHashHex(
7681
7821
  input.crypto.sha256,
7682
7822
  input.body
7683
7823
  );
@@ -7960,7 +8100,7 @@ function verifyDecryptResponse(input) {
7960
8100
  })
7961
8101
  };
7962
8102
  }
7963
- const expectedRequestHash = hexEncode2(
8103
+ const expectedRequestHash = hexEncode(
7964
8104
  crypto2.sha256(utf8Encode(`${invocationCid}${requestBodyHash}`))
7965
8105
  );
7966
8106
  if (response.requestHash !== expectedRequestHash) {
@@ -7984,7 +8124,7 @@ function verifyDecryptResponse(input) {
7984
8124
  const signedBytes = new TextEncoder().encode(
7985
8125
  canonicalSignedResponse(response)
7986
8126
  );
7987
- const signatureBytes = base64Decode2(response.nodeSignature);
8127
+ const signatureBytes = base64Decode(response.nodeSignature);
7988
8128
  if (!crypto2.verifyNodeSignature(response.nodeId, signedBytes, signatureBytes)) {
7989
8129
  return {
7990
8130
  ok: false,
@@ -7996,7 +8136,7 @@ function verifyDecryptResponse(input) {
7996
8136
  return { ok: true, data: response };
7997
8137
  }
7998
8138
  function openWrappedKey(crypto2, receiverPrivateKey, response) {
7999
- const wrapped = base64Decode2(response.wrappedKey);
8139
+ const wrapped = base64Decode(response.wrappedKey);
8000
8140
  return crypto2.openWithReceiverKey(receiverPrivateKey, wrapped);
8001
8141
  }
8002
8142
 
@@ -8040,7 +8180,7 @@ var EncryptionService = class extends BaseService {
8040
8180
  const usable = ensureNetworkUsableForDecrypt(discovered.data);
8041
8181
  if (!usable.ok) return usable;
8042
8182
  const descriptor = usable.data;
8043
- const networkPublicKey = base64Decode2(descriptor.publicEncryptionKey);
8183
+ const networkPublicKey = base64Decode(descriptor.publicEncryptionKey);
8044
8184
  const result = encryptToNetwork(this.crypto, {
8045
8185
  // Discovery returns the node's canonical network identifier. Persist
8046
8186
  // that spelling in the envelope so a later response can be compared
@@ -8068,7 +8208,7 @@ var EncryptionService = class extends BaseService {
8068
8208
  this.assertActive();
8069
8209
  const validated = validateEnvelope(this.crypto, envelope);
8070
8210
  if (!validated.ok) return validated;
8071
- if (options?.aad !== void 0 && validated.data.aad !== base64Encode2(options.aad)) {
8211
+ if (options?.aad !== void 0 && validated.data.aad !== base64Encode(options.aad)) {
8072
8212
  return encErr(
8073
8213
  encryptionError({
8074
8214
  code: "INVALID_INPUT",
@@ -8096,7 +8236,7 @@ var EncryptionService = class extends BaseService {
8096
8236
  );
8097
8237
  }
8098
8238
  const receiverKey = generateRandomReceiverKey({ crypto: this.crypto });
8099
- const receiverPublicKey = base64Encode2(receiverKey.publicKey);
8239
+ const receiverPublicKey = base64Encode(receiverKey.publicKey);
8100
8240
  const receiverPublicKeyHash = canonicalHashHex(
8101
8241
  this.crypto.sha256,
8102
8242
  receiverPublicKey
@@ -8272,8 +8412,8 @@ export {
8272
8412
  authRequiredError,
8273
8413
  authUnauthorizedError,
8274
8414
  authorizationVerdictOf,
8275
- base64Decode2 as base64Decode,
8276
- base64Encode2 as base64Encode,
8415
+ base64Decode,
8416
+ base64Encode,
8277
8417
  buildCanonicalDecryptRequest,
8278
8418
  buildDecryptAttenuation,
8279
8419
  buildDecryptFacts,
@@ -8303,13 +8443,14 @@ export {
8303
8443
  generateRandomReceiverKey,
8304
8444
  getTinyCloudDebugLogs,
8305
8445
  hexDecode,
8306
- hexEncode2 as hexEncode,
8446
+ hexEncode,
8307
8447
  installTinyCloudDebugGlobals,
8308
8448
  isNetworkId,
8309
8449
  isStorageFullError,
8310
8450
  kvPrefixCovers,
8311
8451
  networkDiscoveryKey,
8312
8452
  networkError,
8453
+ nodeRetryError,
8313
8454
  notFoundError,
8314
8455
  ok,
8315
8456
  openWrappedKey,