@tinycloud/cli 1.5.0-beta.8 → 1.5.0

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.js CHANGED
@@ -932,6 +932,12 @@ function abytes(b, ...lengths) {
932
932
  if (lengths.length > 0 && !lengths.includes(b.length))
933
933
  throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
934
934
  }
935
+ function ahash(h) {
936
+ if (typeof h !== "function" || typeof h.create !== "function")
937
+ throw new Error("Hash should be wrapped by utils.createHasher");
938
+ anumber(h.outputLen);
939
+ anumber(h.blockLen);
940
+ }
935
941
  function aexists(instance, checkFinished = true) {
936
942
  if (instance.destroyed)
937
943
  throw new Error("Hash instance has been destroyed");
@@ -1100,7 +1106,7 @@ function Chi(a, b, c) {
1100
1106
  function Maj(a, b, c) {
1101
1107
  return a & b ^ a & c ^ b & c;
1102
1108
  }
1103
- var HashMD, SHA256_IV, SHA512_IV;
1109
+ var HashMD, SHA256_IV, SHA384_IV, SHA512_IV;
1104
1110
  var init_md = __esm({
1105
1111
  "../../node_modules/@noble/hashes/esm/_md.js"() {
1106
1112
  "use strict";
@@ -1205,6 +1211,24 @@ var init_md = __esm({
1205
1211
  528734635,
1206
1212
  1541459225
1207
1213
  ]);
1214
+ SHA384_IV = /* @__PURE__ */ Uint32Array.from([
1215
+ 3418070365,
1216
+ 3238371032,
1217
+ 1654270250,
1218
+ 914150663,
1219
+ 2438529370,
1220
+ 812702999,
1221
+ 355462360,
1222
+ 4144912697,
1223
+ 1731405415,
1224
+ 4290775857,
1225
+ 2394180231,
1226
+ 1750603025,
1227
+ 3675008525,
1228
+ 1694076839,
1229
+ 1203062813,
1230
+ 3204075428
1231
+ ]);
1208
1232
  SHA512_IV = /* @__PURE__ */ Uint32Array.from([
1209
1233
  1779033703,
1210
1234
  4089235720,
@@ -1227,7 +1251,7 @@ var init_md = __esm({
1227
1251
  });
1228
1252
 
1229
1253
  // ../../node_modules/@noble/hashes/esm/sha2.js
1230
- var SHA256_K, SHA256_W, SHA256, K512, SHA512_Kh, SHA512_Kl, SHA512_W_H, SHA512_W_L, SHA512, sha256, sha512;
1254
+ var SHA256_K, SHA256_W, SHA256, K512, SHA512_Kh, SHA512_Kl, SHA512_W_H, SHA512_W_L, SHA512, SHA384, sha256, sha512, sha384;
1231
1255
  var init_sha2 = __esm({
1232
1256
  "../../node_modules/@noble/hashes/esm/sha2.js"() {
1233
1257
  "use strict";
@@ -1568,8 +1592,30 @@ var init_sha2 = __esm({
1568
1592
  this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1569
1593
  }
1570
1594
  };
1595
+ SHA384 = class extends SHA512 {
1596
+ constructor() {
1597
+ super(48);
1598
+ this.Ah = SHA384_IV[0] | 0;
1599
+ this.Al = SHA384_IV[1] | 0;
1600
+ this.Bh = SHA384_IV[2] | 0;
1601
+ this.Bl = SHA384_IV[3] | 0;
1602
+ this.Ch = SHA384_IV[4] | 0;
1603
+ this.Cl = SHA384_IV[5] | 0;
1604
+ this.Dh = SHA384_IV[6] | 0;
1605
+ this.Dl = SHA384_IV[7] | 0;
1606
+ this.Eh = SHA384_IV[8] | 0;
1607
+ this.El = SHA384_IV[9] | 0;
1608
+ this.Fh = SHA384_IV[10] | 0;
1609
+ this.Fl = SHA384_IV[11] | 0;
1610
+ this.Gh = SHA384_IV[12] | 0;
1611
+ this.Gl = SHA384_IV[13] | 0;
1612
+ this.Hh = SHA384_IV[14] | 0;
1613
+ this.Hl = SHA384_IV[15] | 0;
1614
+ }
1615
+ };
1571
1616
  sha256 = /* @__PURE__ */ createHasher(() => new SHA256());
1572
1617
  sha512 = /* @__PURE__ */ createHasher(() => new SHA512());
1618
+ sha384 = /* @__PURE__ */ createHasher(() => new SHA384());
1573
1619
  }
1574
1620
  });
1575
1621
 
@@ -1583,6 +1629,81 @@ var init_sha256 = __esm({
1583
1629
  }
1584
1630
  });
1585
1631
 
1632
+ // ../../node_modules/@noble/hashes/esm/hmac.js
1633
+ var HMAC, hmac;
1634
+ var init_hmac = __esm({
1635
+ "../../node_modules/@noble/hashes/esm/hmac.js"() {
1636
+ "use strict";
1637
+ init_utils();
1638
+ HMAC = class extends Hash {
1639
+ constructor(hash, _key) {
1640
+ super();
1641
+ this.finished = false;
1642
+ this.destroyed = false;
1643
+ ahash(hash);
1644
+ const key = toBytes(_key);
1645
+ this.iHash = hash.create();
1646
+ if (typeof this.iHash.update !== "function")
1647
+ throw new Error("Expected instance of class which extends utils.Hash");
1648
+ this.blockLen = this.iHash.blockLen;
1649
+ this.outputLen = this.iHash.outputLen;
1650
+ const blockLen = this.blockLen;
1651
+ const pad = new Uint8Array(blockLen);
1652
+ pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
1653
+ for (let i = 0; i < pad.length; i++)
1654
+ pad[i] ^= 54;
1655
+ this.iHash.update(pad);
1656
+ this.oHash = hash.create();
1657
+ for (let i = 0; i < pad.length; i++)
1658
+ pad[i] ^= 54 ^ 92;
1659
+ this.oHash.update(pad);
1660
+ clean(pad);
1661
+ }
1662
+ update(buf) {
1663
+ aexists(this);
1664
+ this.iHash.update(buf);
1665
+ return this;
1666
+ }
1667
+ digestInto(out) {
1668
+ aexists(this);
1669
+ abytes(out, this.outputLen);
1670
+ this.finished = true;
1671
+ this.iHash.digestInto(out);
1672
+ this.oHash.update(out);
1673
+ this.oHash.digestInto(out);
1674
+ this.destroy();
1675
+ }
1676
+ digest() {
1677
+ const out = new Uint8Array(this.oHash.outputLen);
1678
+ this.digestInto(out);
1679
+ return out;
1680
+ }
1681
+ _cloneInto(to) {
1682
+ to || (to = Object.create(Object.getPrototypeOf(this), {}));
1683
+ const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
1684
+ to = to;
1685
+ to.finished = finished;
1686
+ to.destroyed = destroyed;
1687
+ to.blockLen = blockLen;
1688
+ to.outputLen = outputLen;
1689
+ to.oHash = oHash._cloneInto(to.oHash);
1690
+ to.iHash = iHash._cloneInto(to.iHash);
1691
+ return to;
1692
+ }
1693
+ clone() {
1694
+ return this._cloneInto();
1695
+ }
1696
+ destroy() {
1697
+ this.destroyed = true;
1698
+ this.oHash.destroy();
1699
+ this.iHash.destroy();
1700
+ }
1701
+ };
1702
+ hmac = (hash, key, message) => new HMAC(hash, key).update(message).digest();
1703
+ hmac.create = (hash, key) => new HMAC(hash, key);
1704
+ }
1705
+ });
1706
+
1586
1707
  // src/lib/raw-encryption.ts
1587
1708
  var init_raw_encryption = __esm({
1588
1709
  "src/lib/raw-encryption.ts"() {
@@ -1782,8 +1903,8 @@ function createReplicationEventSink(profileRoot, options) {
1782
1903
  `);
1783
1904
  } else if (event.type === "replication.sync") {
1784
1905
  const pending = event.pendingCleared === void 0 ? "" : ` pendingCleared:${event.pendingCleared}`;
1785
- const origin = event.origin === void 0 ? "" : ` origin:${event.origin}`;
1786
- process.stderr.write(`[replication] sync ${event.replica} ${event.outcome}${event.code ? ` ${event.code}` : ""}${pending}${origin}
1906
+ const origin2 = event.origin === void 0 ? "" : ` origin:${event.origin}`;
1907
+ process.stderr.write(`[replication] sync ${event.replica} ${event.outcome}${event.code ? ` ${event.code}` : ""}${pending}${origin2}
1787
1908
  `);
1788
1909
  } else if (event.type === "replication.grant") {
1789
1910
  process.stderr.write(`[replication] grant ${event.replicaId} ${event.action}${event.code ? ` ${event.code}` : ""}${event.effectiveExpiresAt ? ` effectiveExpiresAt:${event.effectiveExpiresAt}` : ""}
@@ -2188,6 +2309,10 @@ function _abytes2(value, length5, title = "") {
2188
2309
  }
2189
2310
  return value;
2190
2311
  }
2312
+ function numberToHexUnpadded(num) {
2313
+ const hex3 = num.toString(16);
2314
+ return hex3.length & 1 ? "0" + hex3 : hex3;
2315
+ }
2191
2316
  function hexToNumber(hex3) {
2192
2317
  if (typeof hex3 !== "string")
2193
2318
  throw new Error("hex string expected, got " + typeof hex3);
@@ -2248,6 +2373,56 @@ function bitLen(n) {
2248
2373
  ;
2249
2374
  return len;
2250
2375
  }
2376
+ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
2377
+ if (typeof hashLen !== "number" || hashLen < 2)
2378
+ throw new Error("hashLen must be a number");
2379
+ if (typeof qByteLen !== "number" || qByteLen < 2)
2380
+ throw new Error("qByteLen must be a number");
2381
+ if (typeof hmacFn !== "function")
2382
+ throw new Error("hmacFn must be a function");
2383
+ const u8n = (len) => new Uint8Array(len);
2384
+ const u8of = (byte) => Uint8Array.of(byte);
2385
+ let v = u8n(hashLen);
2386
+ let k = u8n(hashLen);
2387
+ let i = 0;
2388
+ const reset = () => {
2389
+ v.fill(1);
2390
+ k.fill(0);
2391
+ i = 0;
2392
+ };
2393
+ const h = (...b) => hmacFn(k, v, ...b);
2394
+ const reseed = (seed = u8n(0)) => {
2395
+ k = h(u8of(0), seed);
2396
+ v = h();
2397
+ if (seed.length === 0)
2398
+ return;
2399
+ k = h(u8of(1), seed);
2400
+ v = h();
2401
+ };
2402
+ const gen = () => {
2403
+ if (i++ >= 1e3)
2404
+ throw new Error("drbg: tried 1000 values");
2405
+ let len = 0;
2406
+ const out = [];
2407
+ while (len < qByteLen) {
2408
+ v = h();
2409
+ const sl = v.slice();
2410
+ out.push(sl);
2411
+ len += v.length;
2412
+ }
2413
+ return concatBytes(...out);
2414
+ };
2415
+ const genUntil = (seed, pred) => {
2416
+ reset();
2417
+ reseed(seed);
2418
+ let res = void 0;
2419
+ while (!(res = pred(gen())))
2420
+ reseed();
2421
+ reset();
2422
+ return res;
2423
+ };
2424
+ return genUntil;
2425
+ }
2251
2426
  function _validateObject(object3, fields, optFields = {}) {
2252
2427
  if (!object3 || typeof object3 !== "object")
2253
2428
  throw new Error("expected valid options object");
@@ -2584,6 +2759,26 @@ function Field(ORDER, bitLenOrOpts, isLE2 = false, opts = {}) {
2584
2759
  });
2585
2760
  return Object.freeze(f);
2586
2761
  }
2762
+ function getFieldBytesLength(fieldOrder) {
2763
+ if (typeof fieldOrder !== "bigint")
2764
+ throw new Error("field order must be bigint");
2765
+ const bitLength = fieldOrder.toString(2).length;
2766
+ return Math.ceil(bitLength / 8);
2767
+ }
2768
+ function getMinHashLength(fieldOrder) {
2769
+ const length5 = getFieldBytesLength(fieldOrder);
2770
+ return length5 + Math.ceil(length5 / 2);
2771
+ }
2772
+ function mapHashToField(key, fieldOrder, isLE2 = false) {
2773
+ const len = key.length;
2774
+ const fieldLen = getFieldBytesLength(fieldOrder);
2775
+ const minLen = getMinHashLength(fieldOrder);
2776
+ if (len < 16 || len < minLen || len > 1024)
2777
+ throw new Error("expected " + minLen + "-1024 bytes of input, got " + len);
2778
+ const num = isLE2 ? bytesToNumberLE(key) : bytesToNumberBE(key);
2779
+ const reduced = mod(num, fieldOrder - _1n2) + _1n2;
2780
+ return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
2781
+ }
2587
2782
  var _0n2, _1n2, _2n, _3n, _4n, _5n, _7n, _8n, _9n, _16n, isNegativeLE, FIELD_FIELDS;
2588
2783
  var init_modular = __esm({
2589
2784
  "../../node_modules/@noble/curves/esm/abstract/modular.js"() {
@@ -2683,6 +2878,21 @@ function assert0(n) {
2683
2878
  if (n !== _0n3)
2684
2879
  throw new Error("invalid wNAF");
2685
2880
  }
2881
+ function mulEndoUnsafe(Point, point, k1, k2) {
2882
+ let acc = point;
2883
+ let p1 = Point.ZERO;
2884
+ let p2 = Point.ZERO;
2885
+ while (k1 > _0n3 || k2 > _0n3) {
2886
+ if (k1 & _1n3)
2887
+ p1 = p1.add(acc);
2888
+ if (k2 & _1n3)
2889
+ p2 = p2.add(acc);
2890
+ acc = acc.double();
2891
+ k1 >>= _1n3;
2892
+ k2 >>= _1n3;
2893
+ }
2894
+ return { p1, p2 };
2895
+ }
2686
2896
  function pippenger(c, fieldN, points, scalars) {
2687
2897
  validateMSMPoints(points, c);
2688
2898
  validateMSMScalars(scalars, fieldN);
@@ -6592,7 +6802,7 @@ var init_profile_replicas = __esm({
6592
6802
  });
6593
6803
 
6594
6804
  // src/lib/logout-pending.ts
6595
- import { lstat as lstat4, open as open5, readFile as readFile5 } from "fs/promises";
6805
+ import { lstat as lstat4, open as open5, readFile as readFile5, rm as rm4 } from "fs/promises";
6596
6806
  import { join as join9 } from "path";
6597
6807
  import { createProfileReplicaPurge, logoutPrincipalDigest, REPLICA_LOGOUT_PENDING_FILE as REPLICA_LOGOUT_PENDING_FILE2, RESTORED_GATE_MESSAGE } from "@tinycloud/node-sdk";
6598
6808
  import { namedProfilePath, profilePath as profilePath4 } from "@tinycloud/operations/state";
@@ -6673,32 +6883,35 @@ async function assertPendingRemoteLogoutSession(name, expected) {
6673
6883
  }, { requireProfile: true });
6674
6884
  }
6675
6885
  async function clearProfileCredentials(name, syncDirectory = false, legacyCleanup = false) {
6676
- const profile = await ProfileManager.getProfile(name);
6677
- const { namedKeys: _namedKeys, ...signedOutProfile } = profile;
6678
- await ProfileManager.setProfileDurable(name, { ...signedOutProfile, authSignedOut: true, ...legacyCleanup ? { legacyReplicaCleanup: true } : {} });
6679
- let failed = false;
6680
- let error;
6681
- try {
6682
- await ProfileManager.removeKey(name);
6683
- } catch (cause) {
6684
- failed = true;
6685
- error = cause;
6686
- }
6687
- try {
6688
- await ProfileManager.clearSession(name);
6689
- } catch (cause) {
6690
- if (!failed) error = cause;
6691
- failed = true;
6692
- }
6693
- if (failed) throw error;
6694
- if (syncDirectory) {
6695
- const directory = await open5(profilePath4(name), "r");
6886
+ await ProfileManager.withLock(name, async () => {
6887
+ const profile = await ProfileManager.getProfile(name);
6888
+ const { namedKeys: _namedKeys, ...signedOutProfile } = profile;
6889
+ await rm4(join9(profilePath4(name), "approval-pending.json"), { force: true });
6890
+ await ProfileManager.setProfileDurable(name, { ...signedOutProfile, authSignedOut: true, ...legacyCleanup ? { legacyReplicaCleanup: true } : {} });
6891
+ let failed = false;
6892
+ let error;
6696
6893
  try {
6697
- await directory.sync();
6698
- } finally {
6699
- await directory.close();
6894
+ await ProfileManager.removeKey(name);
6895
+ } catch (cause) {
6896
+ failed = true;
6897
+ error = cause;
6700
6898
  }
6701
- }
6899
+ try {
6900
+ await ProfileManager.clearSession(name);
6901
+ } catch (cause) {
6902
+ if (!failed) error = cause;
6903
+ failed = true;
6904
+ }
6905
+ if (failed) throw error;
6906
+ if (syncDirectory) {
6907
+ const directory = await open5(profilePath4(name), "r");
6908
+ try {
6909
+ await directory.sync();
6910
+ } finally {
6911
+ await directory.close();
6912
+ }
6913
+ }
6914
+ }, { requireProfile: true });
6702
6915
  }
6703
6916
  async function finishSignedOutCredentialRemoval(name) {
6704
6917
  const profile = await ProfileManager.getProfile(name).catch((error) => {
@@ -7363,7 +7576,7 @@ var init_host = __esm({
7363
7576
  });
7364
7577
 
7365
7578
  // src/config/profiles.ts
7366
- import { chmod as chmod3, lstat as lstat5, readdir as readdir5, rm as rm4 } from "fs/promises";
7579
+ import { chmod as chmod3, lstat as lstat5, readdir as readdir5, rm as rm5 } from "fs/promises";
7367
7580
  import { CLI_NAME as CLI_NAME11 } from "@tinycloud/operations/cli-name";
7368
7581
  import { join as join10 } from "path";
7369
7582
  import {
@@ -7385,6 +7598,7 @@ var init_profiles = __esm({
7385
7598
  "use strict";
7386
7599
  init_constants();
7387
7600
  init_storage2();
7601
+ init_types();
7388
7602
  init_errors();
7389
7603
  ProfileManager = class _ProfileManager {
7390
7604
  // ── Initialization ──────────────────────────────────────────────────
@@ -7458,7 +7672,7 @@ var init_profiles = __esm({
7458
7672
  if (!profile) {
7459
7673
  throw new CLIError(
7460
7674
  "PROFILE_NOT_FOUND",
7461
- `Profile "${name}" does not exist. Create it with \`${CLI_NAME11} init --name ${name}\`.`
7675
+ `Profile "${name}" does not exist. Create it with \`${CLI_NAME11} init --key-only --name ${name}\`.`
7462
7676
  );
7463
7677
  }
7464
7678
  return profile;
@@ -7481,7 +7695,7 @@ var init_profiles = __esm({
7481
7695
  }
7482
7696
  /** Removes profile.json under the profile lock (rollback of a profile a failed login created). */
7483
7697
  static async removeProfileConfig(name) {
7484
- await _ProfileManager.withLock(name, () => rm4(join10(profilePath5(name), "profile.json"), { force: true }));
7698
+ await _ProfileManager.withLock(name, () => rm5(join10(profilePath5(name), "profile.json"), { force: true }));
7485
7699
  }
7486
7700
  /**
7487
7701
  * Returns true if a profile directory exists.
@@ -7532,16 +7746,16 @@ var init_profiles = __esm({
7532
7746
  });
7533
7747
  if (kind === "missing") return;
7534
7748
  if (kind === "link") {
7535
- await rm4(profileDir, { force: true });
7749
+ await rm5(profileDir, { force: true });
7536
7750
  return;
7537
7751
  }
7538
7752
  await _ProfileManager.withLock(name, async () => {
7539
7753
  const directory = profilePath5(name);
7540
- for (const file of ["session.json", "key.json"]) await rm4(join10(directory, file), { force: true });
7754
+ for (const file of ["session.json", "key.json"]) await rm5(join10(directory, file), { force: true });
7541
7755
  for (const entry of await readdir5(directory)) {
7542
- if (entry !== ".lock" && entry !== "profile.json") await rm4(join10(directory, entry), { recursive: true, force: true });
7756
+ if (entry !== ".lock" && entry !== "profile.json") await rm5(join10(directory, entry), { recursive: true, force: true });
7543
7757
  }
7544
- await rm4(join10(directory, "profile.json"), { force: true });
7758
+ await rm5(join10(directory, "profile.json"), { force: true });
7545
7759
  await recordProfileDeletion(name);
7546
7760
  });
7547
7761
  }
@@ -7571,7 +7785,7 @@ var init_profiles = __esm({
7571
7785
  }
7572
7786
  /** Removes key.json under the profile lock (rollback of a key a failed login created). */
7573
7787
  static async removeKey(name) {
7574
- await _ProfileManager.withLock(name, () => rm4(join10(profilePath5(name), "key.json"), { force: true }));
7788
+ await _ProfileManager.withLock(name, () => rm5(join10(profilePath5(name), "key.json"), { force: true }));
7575
7789
  }
7576
7790
  // ── Session management ──────────────────────────────────────────────
7577
7791
  /**
@@ -7666,6 +7880,7 @@ var init_profiles = __esm({
7666
7880
  quiet: options.quiet ?? false,
7667
7881
  replication,
7668
7882
  replicationDebug: options.replicationDebug === true || process.env.TC_REPLICATION_DEBUG === "1",
7883
+ ...profileConfig === void 0 ? {} : { posture: resolveProfilePosture(profileConfig) },
7669
7884
  ...localDiscovery === void 0 ? {} : { localDiscovery }
7670
7885
  };
7671
7886
  }
@@ -12787,6 +13002,1097 @@ var init_raw = __esm({
12787
13002
  }
12788
13003
  });
12789
13004
 
13005
+ // ../../node_modules/@noble/curves/esm/abstract/weierstrass.js
13006
+ function _splitEndoScalar(k, basis, n) {
13007
+ const [[a1, b1], [a2, b2]] = basis;
13008
+ const c1 = divNearest(b2 * k, n);
13009
+ const c2 = divNearest(-b1 * k, n);
13010
+ let k1 = k - c1 * a1 - c2 * a2;
13011
+ let k2 = -c1 * b1 - c2 * b2;
13012
+ const k1neg = k1 < _0n6;
13013
+ const k2neg = k2 < _0n6;
13014
+ if (k1neg)
13015
+ k1 = -k1;
13016
+ if (k2neg)
13017
+ k2 = -k2;
13018
+ const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n6;
13019
+ if (k1 < _0n6 || k1 >= MAX_NUM || k2 < _0n6 || k2 >= MAX_NUM) {
13020
+ throw new Error("splitScalar (endomorphism): failed, k=" + k);
13021
+ }
13022
+ return { k1neg, k1, k2neg, k2 };
13023
+ }
13024
+ function validateSigFormat(format5) {
13025
+ if (!["compact", "recovered", "der"].includes(format5))
13026
+ throw new Error('Signature format must be "compact", "recovered", or "der"');
13027
+ return format5;
13028
+ }
13029
+ function validateSigOpts(opts, def) {
13030
+ const optsn = {};
13031
+ for (let optName of Object.keys(def)) {
13032
+ optsn[optName] = opts[optName] === void 0 ? def[optName] : opts[optName];
13033
+ }
13034
+ _abool2(optsn.lowS, "lowS");
13035
+ _abool2(optsn.prehash, "prehash");
13036
+ if (optsn.format !== void 0)
13037
+ validateSigFormat(optsn.format);
13038
+ return optsn;
13039
+ }
13040
+ function _normFnElement(Fn2, key) {
13041
+ const { BYTES: expected } = Fn2;
13042
+ let num;
13043
+ if (typeof key === "bigint") {
13044
+ num = key;
13045
+ } else {
13046
+ let bytes = ensureBytes("private key", key);
13047
+ try {
13048
+ num = Fn2.fromBytes(bytes);
13049
+ } catch (error) {
13050
+ throw new Error(`invalid private key: expected ui8a of size ${expected}, got ${typeof key}`);
13051
+ }
13052
+ }
13053
+ if (!Fn2.isValidNot0(num))
13054
+ throw new Error("invalid private key: out of range [1..N-1]");
13055
+ return num;
13056
+ }
13057
+ function weierstrassN(params, extraOpts = {}) {
13058
+ const validated = _createCurveFields("weierstrass", params, extraOpts);
13059
+ const { Fp: Fp2, Fn: Fn2 } = validated;
13060
+ let CURVE = validated.CURVE;
13061
+ const { h: cofactor, n: CURVE_ORDER } = CURVE;
13062
+ _validateObject(extraOpts, {}, {
13063
+ allowInfinityPoint: "boolean",
13064
+ clearCofactor: "function",
13065
+ isTorsionFree: "function",
13066
+ fromBytes: "function",
13067
+ toBytes: "function",
13068
+ endo: "object",
13069
+ wrapPrivateKey: "boolean"
13070
+ });
13071
+ const { endo } = extraOpts;
13072
+ if (endo) {
13073
+ if (!Fp2.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
13074
+ throw new Error('invalid endo: expected "beta": bigint and "basises": array');
13075
+ }
13076
+ }
13077
+ const lengths = getWLengths(Fp2, Fn2);
13078
+ function assertCompressionIsSupported() {
13079
+ if (!Fp2.isOdd)
13080
+ throw new Error("compression is not supported: Field does not have .isOdd()");
13081
+ }
13082
+ function pointToBytes(_c, point, isCompressed) {
13083
+ const { x, y } = point.toAffine();
13084
+ const bx = Fp2.toBytes(x);
13085
+ _abool2(isCompressed, "isCompressed");
13086
+ if (isCompressed) {
13087
+ assertCompressionIsSupported();
13088
+ const hasEvenY = !Fp2.isOdd(y);
13089
+ return concatBytes(pprefix(hasEvenY), bx);
13090
+ } else {
13091
+ return concatBytes(Uint8Array.of(4), bx, Fp2.toBytes(y));
13092
+ }
13093
+ }
13094
+ function pointFromBytes(bytes) {
13095
+ _abytes2(bytes, void 0, "Point");
13096
+ const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths;
13097
+ const length5 = bytes.length;
13098
+ const head = bytes[0];
13099
+ const tail = bytes.subarray(1);
13100
+ if (length5 === comp && (head === 2 || head === 3)) {
13101
+ const x = Fp2.fromBytes(tail);
13102
+ if (!Fp2.isValid(x))
13103
+ throw new Error("bad point: is not on curve, wrong x");
13104
+ const y2 = weierstrassEquation(x);
13105
+ let y;
13106
+ try {
13107
+ y = Fp2.sqrt(y2);
13108
+ } catch (sqrtError) {
13109
+ const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
13110
+ throw new Error("bad point: is not on curve, sqrt error" + err);
13111
+ }
13112
+ assertCompressionIsSupported();
13113
+ const isYOdd = Fp2.isOdd(y);
13114
+ const isHeadOdd = (head & 1) === 1;
13115
+ if (isHeadOdd !== isYOdd)
13116
+ y = Fp2.neg(y);
13117
+ return { x, y };
13118
+ } else if (length5 === uncomp && head === 4) {
13119
+ const L = Fp2.BYTES;
13120
+ const x = Fp2.fromBytes(tail.subarray(0, L));
13121
+ const y = Fp2.fromBytes(tail.subarray(L, L * 2));
13122
+ if (!isValidXY(x, y))
13123
+ throw new Error("bad point: is not on curve");
13124
+ return { x, y };
13125
+ } else {
13126
+ throw new Error(`bad point: got length ${length5}, expected compressed=${comp} or uncompressed=${uncomp}`);
13127
+ }
13128
+ }
13129
+ const encodePoint = extraOpts.toBytes || pointToBytes;
13130
+ const decodePoint2 = extraOpts.fromBytes || pointFromBytes;
13131
+ function weierstrassEquation(x) {
13132
+ const x2 = Fp2.sqr(x);
13133
+ const x3 = Fp2.mul(x2, x);
13134
+ return Fp2.add(Fp2.add(x3, Fp2.mul(x, CURVE.a)), CURVE.b);
13135
+ }
13136
+ function isValidXY(x, y) {
13137
+ const left = Fp2.sqr(y);
13138
+ const right = weierstrassEquation(x);
13139
+ return Fp2.eql(left, right);
13140
+ }
13141
+ if (!isValidXY(CURVE.Gx, CURVE.Gy))
13142
+ throw new Error("bad curve params: generator point");
13143
+ const _4a3 = Fp2.mul(Fp2.pow(CURVE.a, _3n3), _4n2);
13144
+ const _27b2 = Fp2.mul(Fp2.sqr(CURVE.b), BigInt(27));
13145
+ if (Fp2.is0(Fp2.add(_4a3, _27b2)))
13146
+ throw new Error("bad curve params: a or b");
13147
+ function acoord(title, n, banZero = false) {
13148
+ if (!Fp2.isValid(n) || banZero && Fp2.is0(n))
13149
+ throw new Error(`bad point coordinate ${title}`);
13150
+ return n;
13151
+ }
13152
+ function aprjpoint(other) {
13153
+ if (!(other instanceof Point))
13154
+ throw new Error("ProjectivePoint expected");
13155
+ }
13156
+ function splitEndoScalarN(k) {
13157
+ if (!endo || !endo.basises)
13158
+ throw new Error("no endo");
13159
+ return _splitEndoScalar(k, endo.basises, Fn2.ORDER);
13160
+ }
13161
+ const toAffineMemo = memoized((p, iz) => {
13162
+ const { X, Y, Z } = p;
13163
+ if (Fp2.eql(Z, Fp2.ONE))
13164
+ return { x: X, y: Y };
13165
+ const is0 = p.is0();
13166
+ if (iz == null)
13167
+ iz = is0 ? Fp2.ONE : Fp2.inv(Z);
13168
+ const x = Fp2.mul(X, iz);
13169
+ const y = Fp2.mul(Y, iz);
13170
+ const zz = Fp2.mul(Z, iz);
13171
+ if (is0)
13172
+ return { x: Fp2.ZERO, y: Fp2.ZERO };
13173
+ if (!Fp2.eql(zz, Fp2.ONE))
13174
+ throw new Error("invZ was invalid");
13175
+ return { x, y };
13176
+ });
13177
+ const assertValidMemo = memoized((p) => {
13178
+ if (p.is0()) {
13179
+ if (extraOpts.allowInfinityPoint && !Fp2.is0(p.Y))
13180
+ return;
13181
+ throw new Error("bad point: ZERO");
13182
+ }
13183
+ const { x, y } = p.toAffine();
13184
+ if (!Fp2.isValid(x) || !Fp2.isValid(y))
13185
+ throw new Error("bad point: x or y not field elements");
13186
+ if (!isValidXY(x, y))
13187
+ throw new Error("bad point: equation left != right");
13188
+ if (!p.isTorsionFree())
13189
+ throw new Error("bad point: not in prime-order subgroup");
13190
+ return true;
13191
+ });
13192
+ function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
13193
+ k2p = new Point(Fp2.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
13194
+ k1p = negateCt(k1neg, k1p);
13195
+ k2p = negateCt(k2neg, k2p);
13196
+ return k1p.add(k2p);
13197
+ }
13198
+ class Point {
13199
+ /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
13200
+ constructor(X, Y, Z) {
13201
+ this.X = acoord("x", X);
13202
+ this.Y = acoord("y", Y, true);
13203
+ this.Z = acoord("z", Z);
13204
+ Object.freeze(this);
13205
+ }
13206
+ static CURVE() {
13207
+ return CURVE;
13208
+ }
13209
+ /** Does NOT validate if the point is valid. Use `.assertValidity()`. */
13210
+ static fromAffine(p) {
13211
+ const { x, y } = p || {};
13212
+ if (!p || !Fp2.isValid(x) || !Fp2.isValid(y))
13213
+ throw new Error("invalid affine point");
13214
+ if (p instanceof Point)
13215
+ throw new Error("projective point not allowed");
13216
+ if (Fp2.is0(x) && Fp2.is0(y))
13217
+ return Point.ZERO;
13218
+ return new Point(x, y, Fp2.ONE);
13219
+ }
13220
+ static fromBytes(bytes) {
13221
+ const P = Point.fromAffine(decodePoint2(_abytes2(bytes, void 0, "point")));
13222
+ P.assertValidity();
13223
+ return P;
13224
+ }
13225
+ static fromHex(hex3) {
13226
+ return Point.fromBytes(ensureBytes("pointHex", hex3));
13227
+ }
13228
+ get x() {
13229
+ return this.toAffine().x;
13230
+ }
13231
+ get y() {
13232
+ return this.toAffine().y;
13233
+ }
13234
+ /**
13235
+ *
13236
+ * @param windowSize
13237
+ * @param isLazy true will defer table computation until the first multiplication
13238
+ * @returns
13239
+ */
13240
+ precompute(windowSize = 8, isLazy = true) {
13241
+ wnaf.createCache(this, windowSize);
13242
+ if (!isLazy)
13243
+ this.multiply(_3n3);
13244
+ return this;
13245
+ }
13246
+ // TODO: return `this`
13247
+ /** A point on curve is valid if it conforms to equation. */
13248
+ assertValidity() {
13249
+ assertValidMemo(this);
13250
+ }
13251
+ hasEvenY() {
13252
+ const { y } = this.toAffine();
13253
+ if (!Fp2.isOdd)
13254
+ throw new Error("Field doesn't support isOdd");
13255
+ return !Fp2.isOdd(y);
13256
+ }
13257
+ /** Compare one point to another. */
13258
+ equals(other) {
13259
+ aprjpoint(other);
13260
+ const { X: X1, Y: Y1, Z: Z1 } = this;
13261
+ const { X: X2, Y: Y2, Z: Z2 } = other;
13262
+ const U1 = Fp2.eql(Fp2.mul(X1, Z2), Fp2.mul(X2, Z1));
13263
+ const U2 = Fp2.eql(Fp2.mul(Y1, Z2), Fp2.mul(Y2, Z1));
13264
+ return U1 && U2;
13265
+ }
13266
+ /** Flips point to one corresponding to (x, -y) in Affine coordinates. */
13267
+ negate() {
13268
+ return new Point(this.X, Fp2.neg(this.Y), this.Z);
13269
+ }
13270
+ // Renes-Costello-Batina exception-free doubling formula.
13271
+ // There is 30% faster Jacobian formula, but it is not complete.
13272
+ // https://eprint.iacr.org/2015/1060, algorithm 3
13273
+ // Cost: 8M + 3S + 3*a + 2*b3 + 15add.
13274
+ double() {
13275
+ const { a, b } = CURVE;
13276
+ const b3 = Fp2.mul(b, _3n3);
13277
+ const { X: X1, Y: Y1, Z: Z1 } = this;
13278
+ let X3 = Fp2.ZERO, Y3 = Fp2.ZERO, Z3 = Fp2.ZERO;
13279
+ let t0 = Fp2.mul(X1, X1);
13280
+ let t1 = Fp2.mul(Y1, Y1);
13281
+ let t2 = Fp2.mul(Z1, Z1);
13282
+ let t3 = Fp2.mul(X1, Y1);
13283
+ t3 = Fp2.add(t3, t3);
13284
+ Z3 = Fp2.mul(X1, Z1);
13285
+ Z3 = Fp2.add(Z3, Z3);
13286
+ X3 = Fp2.mul(a, Z3);
13287
+ Y3 = Fp2.mul(b3, t2);
13288
+ Y3 = Fp2.add(X3, Y3);
13289
+ X3 = Fp2.sub(t1, Y3);
13290
+ Y3 = Fp2.add(t1, Y3);
13291
+ Y3 = Fp2.mul(X3, Y3);
13292
+ X3 = Fp2.mul(t3, X3);
13293
+ Z3 = Fp2.mul(b3, Z3);
13294
+ t2 = Fp2.mul(a, t2);
13295
+ t3 = Fp2.sub(t0, t2);
13296
+ t3 = Fp2.mul(a, t3);
13297
+ t3 = Fp2.add(t3, Z3);
13298
+ Z3 = Fp2.add(t0, t0);
13299
+ t0 = Fp2.add(Z3, t0);
13300
+ t0 = Fp2.add(t0, t2);
13301
+ t0 = Fp2.mul(t0, t3);
13302
+ Y3 = Fp2.add(Y3, t0);
13303
+ t2 = Fp2.mul(Y1, Z1);
13304
+ t2 = Fp2.add(t2, t2);
13305
+ t0 = Fp2.mul(t2, t3);
13306
+ X3 = Fp2.sub(X3, t0);
13307
+ Z3 = Fp2.mul(t2, t1);
13308
+ Z3 = Fp2.add(Z3, Z3);
13309
+ Z3 = Fp2.add(Z3, Z3);
13310
+ return new Point(X3, Y3, Z3);
13311
+ }
13312
+ // Renes-Costello-Batina exception-free addition formula.
13313
+ // There is 30% faster Jacobian formula, but it is not complete.
13314
+ // https://eprint.iacr.org/2015/1060, algorithm 1
13315
+ // Cost: 12M + 0S + 3*a + 3*b3 + 23add.
13316
+ add(other) {
13317
+ aprjpoint(other);
13318
+ const { X: X1, Y: Y1, Z: Z1 } = this;
13319
+ const { X: X2, Y: Y2, Z: Z2 } = other;
13320
+ let X3 = Fp2.ZERO, Y3 = Fp2.ZERO, Z3 = Fp2.ZERO;
13321
+ const a = CURVE.a;
13322
+ const b3 = Fp2.mul(CURVE.b, _3n3);
13323
+ let t0 = Fp2.mul(X1, X2);
13324
+ let t1 = Fp2.mul(Y1, Y2);
13325
+ let t2 = Fp2.mul(Z1, Z2);
13326
+ let t3 = Fp2.add(X1, Y1);
13327
+ let t4 = Fp2.add(X2, Y2);
13328
+ t3 = Fp2.mul(t3, t4);
13329
+ t4 = Fp2.add(t0, t1);
13330
+ t3 = Fp2.sub(t3, t4);
13331
+ t4 = Fp2.add(X1, Z1);
13332
+ let t5 = Fp2.add(X2, Z2);
13333
+ t4 = Fp2.mul(t4, t5);
13334
+ t5 = Fp2.add(t0, t2);
13335
+ t4 = Fp2.sub(t4, t5);
13336
+ t5 = Fp2.add(Y1, Z1);
13337
+ X3 = Fp2.add(Y2, Z2);
13338
+ t5 = Fp2.mul(t5, X3);
13339
+ X3 = Fp2.add(t1, t2);
13340
+ t5 = Fp2.sub(t5, X3);
13341
+ Z3 = Fp2.mul(a, t4);
13342
+ X3 = Fp2.mul(b3, t2);
13343
+ Z3 = Fp2.add(X3, Z3);
13344
+ X3 = Fp2.sub(t1, Z3);
13345
+ Z3 = Fp2.add(t1, Z3);
13346
+ Y3 = Fp2.mul(X3, Z3);
13347
+ t1 = Fp2.add(t0, t0);
13348
+ t1 = Fp2.add(t1, t0);
13349
+ t2 = Fp2.mul(a, t2);
13350
+ t4 = Fp2.mul(b3, t4);
13351
+ t1 = Fp2.add(t1, t2);
13352
+ t2 = Fp2.sub(t0, t2);
13353
+ t2 = Fp2.mul(a, t2);
13354
+ t4 = Fp2.add(t4, t2);
13355
+ t0 = Fp2.mul(t1, t4);
13356
+ Y3 = Fp2.add(Y3, t0);
13357
+ t0 = Fp2.mul(t5, t4);
13358
+ X3 = Fp2.mul(t3, X3);
13359
+ X3 = Fp2.sub(X3, t0);
13360
+ t0 = Fp2.mul(t3, t1);
13361
+ Z3 = Fp2.mul(t5, Z3);
13362
+ Z3 = Fp2.add(Z3, t0);
13363
+ return new Point(X3, Y3, Z3);
13364
+ }
13365
+ subtract(other) {
13366
+ return this.add(other.negate());
13367
+ }
13368
+ is0() {
13369
+ return this.equals(Point.ZERO);
13370
+ }
13371
+ /**
13372
+ * Constant time multiplication.
13373
+ * Uses wNAF method. Windowed method may be 10% faster,
13374
+ * but takes 2x longer to generate and consumes 2x memory.
13375
+ * Uses precomputes when available.
13376
+ * Uses endomorphism for Koblitz curves.
13377
+ * @param scalar by which the point would be multiplied
13378
+ * @returns New point
13379
+ */
13380
+ multiply(scalar) {
13381
+ const { endo: endo2 } = extraOpts;
13382
+ if (!Fn2.isValidNot0(scalar))
13383
+ throw new Error("invalid scalar: out of range");
13384
+ let point, fake;
13385
+ const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
13386
+ if (endo2) {
13387
+ const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
13388
+ const { p: k1p, f: k1f } = mul(k1);
13389
+ const { p: k2p, f: k2f } = mul(k2);
13390
+ fake = k1f.add(k2f);
13391
+ point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg);
13392
+ } else {
13393
+ const { p, f } = mul(scalar);
13394
+ point = p;
13395
+ fake = f;
13396
+ }
13397
+ return normalizeZ(Point, [point, fake])[0];
13398
+ }
13399
+ /**
13400
+ * Non-constant-time multiplication. Uses double-and-add algorithm.
13401
+ * It's faster, but should only be used when you don't care about
13402
+ * an exposed secret key e.g. sig verification, which works over *public* keys.
13403
+ */
13404
+ multiplyUnsafe(sc) {
13405
+ const { endo: endo2 } = extraOpts;
13406
+ const p = this;
13407
+ if (!Fn2.isValid(sc))
13408
+ throw new Error("invalid scalar: out of range");
13409
+ if (sc === _0n6 || p.is0())
13410
+ return Point.ZERO;
13411
+ if (sc === _1n6)
13412
+ return p;
13413
+ if (wnaf.hasCache(this))
13414
+ return this.multiply(sc);
13415
+ if (endo2) {
13416
+ const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
13417
+ const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
13418
+ return finishEndo(endo2.beta, p1, p2, k1neg, k2neg);
13419
+ } else {
13420
+ return wnaf.unsafe(p, sc);
13421
+ }
13422
+ }
13423
+ multiplyAndAddUnsafe(Q, a, b) {
13424
+ const sum = this.multiplyUnsafe(a).add(Q.multiplyUnsafe(b));
13425
+ return sum.is0() ? void 0 : sum;
13426
+ }
13427
+ /**
13428
+ * Converts Projective point to affine (x, y) coordinates.
13429
+ * @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
13430
+ */
13431
+ toAffine(invertedZ) {
13432
+ return toAffineMemo(this, invertedZ);
13433
+ }
13434
+ /**
13435
+ * Checks whether Point is free of torsion elements (is in prime subgroup).
13436
+ * Always torsion-free for cofactor=1 curves.
13437
+ */
13438
+ isTorsionFree() {
13439
+ const { isTorsionFree } = extraOpts;
13440
+ if (cofactor === _1n6)
13441
+ return true;
13442
+ if (isTorsionFree)
13443
+ return isTorsionFree(Point, this);
13444
+ return wnaf.unsafe(this, CURVE_ORDER).is0();
13445
+ }
13446
+ clearCofactor() {
13447
+ const { clearCofactor } = extraOpts;
13448
+ if (cofactor === _1n6)
13449
+ return this;
13450
+ if (clearCofactor)
13451
+ return clearCofactor(Point, this);
13452
+ return this.multiplyUnsafe(cofactor);
13453
+ }
13454
+ isSmallOrder() {
13455
+ return this.multiplyUnsafe(cofactor).is0();
13456
+ }
13457
+ toBytes(isCompressed = true) {
13458
+ _abool2(isCompressed, "isCompressed");
13459
+ this.assertValidity();
13460
+ return encodePoint(Point, this, isCompressed);
13461
+ }
13462
+ toHex(isCompressed = true) {
13463
+ return bytesToHex(this.toBytes(isCompressed));
13464
+ }
13465
+ toString() {
13466
+ return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
13467
+ }
13468
+ // TODO: remove
13469
+ get px() {
13470
+ return this.X;
13471
+ }
13472
+ get py() {
13473
+ return this.X;
13474
+ }
13475
+ get pz() {
13476
+ return this.Z;
13477
+ }
13478
+ toRawBytes(isCompressed = true) {
13479
+ return this.toBytes(isCompressed);
13480
+ }
13481
+ _setWindowSize(windowSize) {
13482
+ this.precompute(windowSize);
13483
+ }
13484
+ static normalizeZ(points) {
13485
+ return normalizeZ(Point, points);
13486
+ }
13487
+ static msm(points, scalars) {
13488
+ return pippenger(Point, Fn2, points, scalars);
13489
+ }
13490
+ static fromPrivateKey(privateKey) {
13491
+ return Point.BASE.multiply(_normFnElement(Fn2, privateKey));
13492
+ }
13493
+ }
13494
+ Point.BASE = new Point(CURVE.Gx, CURVE.Gy, Fp2.ONE);
13495
+ Point.ZERO = new Point(Fp2.ZERO, Fp2.ONE, Fp2.ZERO);
13496
+ Point.Fp = Fp2;
13497
+ Point.Fn = Fn2;
13498
+ const bits = Fn2.BITS;
13499
+ const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
13500
+ Point.BASE.precompute(8);
13501
+ return Point;
13502
+ }
13503
+ function pprefix(hasEvenY) {
13504
+ return Uint8Array.of(hasEvenY ? 2 : 3);
13505
+ }
13506
+ function getWLengths(Fp2, Fn2) {
13507
+ return {
13508
+ secretKey: Fn2.BYTES,
13509
+ publicKey: 1 + Fp2.BYTES,
13510
+ publicKeyUncompressed: 1 + 2 * Fp2.BYTES,
13511
+ publicKeyHasPrefix: true,
13512
+ signature: 2 * Fn2.BYTES
13513
+ };
13514
+ }
13515
+ function ecdh(Point, ecdhOpts = {}) {
13516
+ const { Fn: Fn2 } = Point;
13517
+ const randomBytes_ = ecdhOpts.randomBytes || randomBytes;
13518
+ const lengths = Object.assign(getWLengths(Point.Fp, Fn2), { seed: getMinHashLength(Fn2.ORDER) });
13519
+ function isValidSecretKey(secretKey) {
13520
+ try {
13521
+ return !!_normFnElement(Fn2, secretKey);
13522
+ } catch (error) {
13523
+ return false;
13524
+ }
13525
+ }
13526
+ function isValidPublicKey(publicKey, isCompressed) {
13527
+ const { publicKey: comp, publicKeyUncompressed } = lengths;
13528
+ try {
13529
+ const l = publicKey.length;
13530
+ if (isCompressed === true && l !== comp)
13531
+ return false;
13532
+ if (isCompressed === false && l !== publicKeyUncompressed)
13533
+ return false;
13534
+ return !!Point.fromBytes(publicKey);
13535
+ } catch (error) {
13536
+ return false;
13537
+ }
13538
+ }
13539
+ function randomSecretKey(seed = randomBytes_(lengths.seed)) {
13540
+ return mapHashToField(_abytes2(seed, lengths.seed, "seed"), Fn2.ORDER);
13541
+ }
13542
+ function getPublicKey(secretKey, isCompressed = true) {
13543
+ return Point.BASE.multiply(_normFnElement(Fn2, secretKey)).toBytes(isCompressed);
13544
+ }
13545
+ function keygen(seed) {
13546
+ const secretKey = randomSecretKey(seed);
13547
+ return { secretKey, publicKey: getPublicKey(secretKey) };
13548
+ }
13549
+ function isProbPub(item) {
13550
+ if (typeof item === "bigint")
13551
+ return false;
13552
+ if (item instanceof Point)
13553
+ return true;
13554
+ const { secretKey, publicKey, publicKeyUncompressed } = lengths;
13555
+ if (Fn2.allowedLengths || secretKey === publicKey)
13556
+ return void 0;
13557
+ const l = ensureBytes("key", item).length;
13558
+ return l === publicKey || l === publicKeyUncompressed;
13559
+ }
13560
+ function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
13561
+ if (isProbPub(secretKeyA) === true)
13562
+ throw new Error("first arg must be private key");
13563
+ if (isProbPub(publicKeyB) === false)
13564
+ throw new Error("second arg must be public key");
13565
+ const s = _normFnElement(Fn2, secretKeyA);
13566
+ const b = Point.fromHex(publicKeyB);
13567
+ return b.multiply(s).toBytes(isCompressed);
13568
+ }
13569
+ const utils = {
13570
+ isValidSecretKey,
13571
+ isValidPublicKey,
13572
+ randomSecretKey,
13573
+ // TODO: remove
13574
+ isValidPrivateKey: isValidSecretKey,
13575
+ randomPrivateKey: randomSecretKey,
13576
+ normPrivateKeyToScalar: (key) => _normFnElement(Fn2, key),
13577
+ precompute(windowSize = 8, point = Point.BASE) {
13578
+ return point.precompute(windowSize, false);
13579
+ }
13580
+ };
13581
+ return Object.freeze({ getPublicKey, getSharedSecret, keygen, Point, utils, lengths });
13582
+ }
13583
+ function ecdsa(Point, hash, ecdsaOpts = {}) {
13584
+ ahash(hash);
13585
+ _validateObject(ecdsaOpts, {}, {
13586
+ hmac: "function",
13587
+ lowS: "boolean",
13588
+ randomBytes: "function",
13589
+ bits2int: "function",
13590
+ bits2int_modN: "function"
13591
+ });
13592
+ const randomBytes4 = ecdsaOpts.randomBytes || randomBytes;
13593
+ const hmac2 = ecdsaOpts.hmac || ((key, ...msgs) => hmac(hash, key, concatBytes(...msgs)));
13594
+ const { Fp: Fp2, Fn: Fn2 } = Point;
13595
+ const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn2;
13596
+ const { keygen, getPublicKey, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
13597
+ const defaultSigOpts = {
13598
+ prehash: false,
13599
+ lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : false,
13600
+ format: void 0,
13601
+ //'compact' as ECDSASigFormat,
13602
+ extraEntropy: false
13603
+ };
13604
+ const defaultSigOpts_format = "compact";
13605
+ function isBiggerThanHalfOrder(number) {
13606
+ const HALF = CURVE_ORDER >> _1n6;
13607
+ return number > HALF;
13608
+ }
13609
+ function validateRS(title, num) {
13610
+ if (!Fn2.isValidNot0(num))
13611
+ throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
13612
+ return num;
13613
+ }
13614
+ function validateSigLength(bytes, format5) {
13615
+ validateSigFormat(format5);
13616
+ const size = lengths.signature;
13617
+ const sizer = format5 === "compact" ? size : format5 === "recovered" ? size + 1 : void 0;
13618
+ return _abytes2(bytes, sizer, `${format5} signature`);
13619
+ }
13620
+ class Signature {
13621
+ constructor(r, s, recovery) {
13622
+ this.r = validateRS("r", r);
13623
+ this.s = validateRS("s", s);
13624
+ if (recovery != null)
13625
+ this.recovery = recovery;
13626
+ Object.freeze(this);
13627
+ }
13628
+ static fromBytes(bytes, format5 = defaultSigOpts_format) {
13629
+ validateSigLength(bytes, format5);
13630
+ let recid;
13631
+ if (format5 === "der") {
13632
+ const { r: r2, s: s2 } = DER.toSig(_abytes2(bytes));
13633
+ return new Signature(r2, s2);
13634
+ }
13635
+ if (format5 === "recovered") {
13636
+ recid = bytes[0];
13637
+ format5 = "compact";
13638
+ bytes = bytes.subarray(1);
13639
+ }
13640
+ const L = Fn2.BYTES;
13641
+ const r = bytes.subarray(0, L);
13642
+ const s = bytes.subarray(L, L * 2);
13643
+ return new Signature(Fn2.fromBytes(r), Fn2.fromBytes(s), recid);
13644
+ }
13645
+ static fromHex(hex3, format5) {
13646
+ return this.fromBytes(hexToBytes(hex3), format5);
13647
+ }
13648
+ addRecoveryBit(recovery) {
13649
+ return new Signature(this.r, this.s, recovery);
13650
+ }
13651
+ recoverPublicKey(messageHash) {
13652
+ const FIELD_ORDER = Fp2.ORDER;
13653
+ const { r, s, recovery: rec } = this;
13654
+ if (rec == null || ![0, 1, 2, 3].includes(rec))
13655
+ throw new Error("recovery id invalid");
13656
+ const hasCofactor = CURVE_ORDER * _2n4 < FIELD_ORDER;
13657
+ if (hasCofactor && rec > 1)
13658
+ throw new Error("recovery id is ambiguous for h>1 curve");
13659
+ const radj = rec === 2 || rec === 3 ? r + CURVE_ORDER : r;
13660
+ if (!Fp2.isValid(radj))
13661
+ throw new Error("recovery id 2 or 3 invalid");
13662
+ const x = Fp2.toBytes(radj);
13663
+ const R = Point.fromBytes(concatBytes(pprefix((rec & 1) === 0), x));
13664
+ const ir = Fn2.inv(radj);
13665
+ const h = bits2int_modN(ensureBytes("msgHash", messageHash));
13666
+ const u1 = Fn2.create(-h * ir);
13667
+ const u2 = Fn2.create(s * ir);
13668
+ const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
13669
+ if (Q.is0())
13670
+ throw new Error("point at infinify");
13671
+ Q.assertValidity();
13672
+ return Q;
13673
+ }
13674
+ // Signatures should be low-s, to prevent malleability.
13675
+ hasHighS() {
13676
+ return isBiggerThanHalfOrder(this.s);
13677
+ }
13678
+ toBytes(format5 = defaultSigOpts_format) {
13679
+ validateSigFormat(format5);
13680
+ if (format5 === "der")
13681
+ return hexToBytes(DER.hexFromSig(this));
13682
+ const r = Fn2.toBytes(this.r);
13683
+ const s = Fn2.toBytes(this.s);
13684
+ if (format5 === "recovered") {
13685
+ if (this.recovery == null)
13686
+ throw new Error("recovery bit must be present");
13687
+ return concatBytes(Uint8Array.of(this.recovery), r, s);
13688
+ }
13689
+ return concatBytes(r, s);
13690
+ }
13691
+ toHex(format5) {
13692
+ return bytesToHex(this.toBytes(format5));
13693
+ }
13694
+ // TODO: remove
13695
+ assertValidity() {
13696
+ }
13697
+ static fromCompact(hex3) {
13698
+ return Signature.fromBytes(ensureBytes("sig", hex3), "compact");
13699
+ }
13700
+ static fromDER(hex3) {
13701
+ return Signature.fromBytes(ensureBytes("sig", hex3), "der");
13702
+ }
13703
+ normalizeS() {
13704
+ return this.hasHighS() ? new Signature(this.r, Fn2.neg(this.s), this.recovery) : this;
13705
+ }
13706
+ toDERRawBytes() {
13707
+ return this.toBytes("der");
13708
+ }
13709
+ toDERHex() {
13710
+ return bytesToHex(this.toBytes("der"));
13711
+ }
13712
+ toCompactRawBytes() {
13713
+ return this.toBytes("compact");
13714
+ }
13715
+ toCompactHex() {
13716
+ return bytesToHex(this.toBytes("compact"));
13717
+ }
13718
+ }
13719
+ const bits2int = ecdsaOpts.bits2int || function bits2int_def(bytes) {
13720
+ if (bytes.length > 8192)
13721
+ throw new Error("input is too large");
13722
+ const num = bytesToNumberBE(bytes);
13723
+ const delta = bytes.length * 8 - fnBits;
13724
+ return delta > 0 ? num >> BigInt(delta) : num;
13725
+ };
13726
+ const bits2int_modN = ecdsaOpts.bits2int_modN || function bits2int_modN_def(bytes) {
13727
+ return Fn2.create(bits2int(bytes));
13728
+ };
13729
+ const ORDER_MASK = bitMask(fnBits);
13730
+ function int2octets(num) {
13731
+ aInRange("num < 2^" + fnBits, num, _0n6, ORDER_MASK);
13732
+ return Fn2.toBytes(num);
13733
+ }
13734
+ function validateMsgAndHash(message, prehash) {
13735
+ _abytes2(message, void 0, "message");
13736
+ return prehash ? _abytes2(hash(message), void 0, "prehashed message") : message;
13737
+ }
13738
+ function prepSig(message, privateKey, opts) {
13739
+ if (["recovered", "canonical"].some((k) => k in opts))
13740
+ throw new Error("sign() legacy options not supported");
13741
+ const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
13742
+ message = validateMsgAndHash(message, prehash);
13743
+ const h1int = bits2int_modN(message);
13744
+ const d = _normFnElement(Fn2, privateKey);
13745
+ const seedArgs = [int2octets(d), int2octets(h1int)];
13746
+ if (extraEntropy != null && extraEntropy !== false) {
13747
+ const e = extraEntropy === true ? randomBytes4(lengths.secretKey) : extraEntropy;
13748
+ seedArgs.push(ensureBytes("extraEntropy", e));
13749
+ }
13750
+ const seed = concatBytes(...seedArgs);
13751
+ const m = h1int;
13752
+ function k2sig(kBytes) {
13753
+ const k = bits2int(kBytes);
13754
+ if (!Fn2.isValidNot0(k))
13755
+ return;
13756
+ const ik = Fn2.inv(k);
13757
+ const q = Point.BASE.multiply(k).toAffine();
13758
+ const r = Fn2.create(q.x);
13759
+ if (r === _0n6)
13760
+ return;
13761
+ const s = Fn2.create(ik * Fn2.create(m + r * d));
13762
+ if (s === _0n6)
13763
+ return;
13764
+ let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n6);
13765
+ let normS = s;
13766
+ if (lowS && isBiggerThanHalfOrder(s)) {
13767
+ normS = Fn2.neg(s);
13768
+ recovery ^= 1;
13769
+ }
13770
+ return new Signature(r, normS, recovery);
13771
+ }
13772
+ return { seed, k2sig };
13773
+ }
13774
+ function sign(message, secretKey, opts = {}) {
13775
+ message = ensureBytes("message", message);
13776
+ const { seed, k2sig } = prepSig(message, secretKey, opts);
13777
+ const drbg = createHmacDrbg(hash.outputLen, Fn2.BYTES, hmac2);
13778
+ const sig = drbg(seed, k2sig);
13779
+ return sig;
13780
+ }
13781
+ function tryParsingSig(sg) {
13782
+ let sig = void 0;
13783
+ const isHex = typeof sg === "string" || isBytes(sg);
13784
+ const isObj = !isHex && sg !== null && typeof sg === "object" && typeof sg.r === "bigint" && typeof sg.s === "bigint";
13785
+ if (!isHex && !isObj)
13786
+ throw new Error("invalid signature, expected Uint8Array, hex string or Signature instance");
13787
+ if (isObj) {
13788
+ sig = new Signature(sg.r, sg.s);
13789
+ } else if (isHex) {
13790
+ try {
13791
+ sig = Signature.fromBytes(ensureBytes("sig", sg), "der");
13792
+ } catch (derError) {
13793
+ if (!(derError instanceof DER.Err))
13794
+ throw derError;
13795
+ }
13796
+ if (!sig) {
13797
+ try {
13798
+ sig = Signature.fromBytes(ensureBytes("sig", sg), "compact");
13799
+ } catch (error) {
13800
+ return false;
13801
+ }
13802
+ }
13803
+ }
13804
+ if (!sig)
13805
+ return false;
13806
+ return sig;
13807
+ }
13808
+ function verify(signature, message, publicKey, opts = {}) {
13809
+ const { lowS, prehash, format: format5 } = validateSigOpts(opts, defaultSigOpts);
13810
+ publicKey = ensureBytes("publicKey", publicKey);
13811
+ message = validateMsgAndHash(ensureBytes("message", message), prehash);
13812
+ if ("strict" in opts)
13813
+ throw new Error("options.strict was renamed to lowS");
13814
+ const sig = format5 === void 0 ? tryParsingSig(signature) : Signature.fromBytes(ensureBytes("sig", signature), format5);
13815
+ if (sig === false)
13816
+ return false;
13817
+ try {
13818
+ const P = Point.fromBytes(publicKey);
13819
+ if (lowS && sig.hasHighS())
13820
+ return false;
13821
+ const { r, s } = sig;
13822
+ const h = bits2int_modN(message);
13823
+ const is = Fn2.inv(s);
13824
+ const u1 = Fn2.create(h * is);
13825
+ const u2 = Fn2.create(r * is);
13826
+ const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
13827
+ if (R.is0())
13828
+ return false;
13829
+ const v = Fn2.create(R.x);
13830
+ return v === r;
13831
+ } catch (e) {
13832
+ return false;
13833
+ }
13834
+ }
13835
+ function recoverPublicKey(signature, message, opts = {}) {
13836
+ const { prehash } = validateSigOpts(opts, defaultSigOpts);
13837
+ message = validateMsgAndHash(message, prehash);
13838
+ return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes();
13839
+ }
13840
+ return Object.freeze({
13841
+ keygen,
13842
+ getPublicKey,
13843
+ getSharedSecret,
13844
+ utils,
13845
+ lengths,
13846
+ Point,
13847
+ sign,
13848
+ verify,
13849
+ recoverPublicKey,
13850
+ Signature,
13851
+ hash
13852
+ });
13853
+ }
13854
+ function _weierstrass_legacy_opts_to_new(c) {
13855
+ const CURVE = {
13856
+ a: c.a,
13857
+ b: c.b,
13858
+ p: c.Fp.ORDER,
13859
+ n: c.n,
13860
+ h: c.h,
13861
+ Gx: c.Gx,
13862
+ Gy: c.Gy
13863
+ };
13864
+ const Fp2 = c.Fp;
13865
+ let allowedLengths = c.allowedPrivateKeyLengths ? Array.from(new Set(c.allowedPrivateKeyLengths.map((l) => Math.ceil(l / 2)))) : void 0;
13866
+ const Fn2 = Field(CURVE.n, {
13867
+ BITS: c.nBitLength,
13868
+ allowedLengths,
13869
+ modFromBytes: c.wrapPrivateKey
13870
+ });
13871
+ const curveOpts = {
13872
+ Fp: Fp2,
13873
+ Fn: Fn2,
13874
+ allowInfinityPoint: c.allowInfinityPoint,
13875
+ endo: c.endo,
13876
+ isTorsionFree: c.isTorsionFree,
13877
+ clearCofactor: c.clearCofactor,
13878
+ fromBytes: c.fromBytes,
13879
+ toBytes: c.toBytes
13880
+ };
13881
+ return { CURVE, curveOpts };
13882
+ }
13883
+ function _ecdsa_legacy_opts_to_new(c) {
13884
+ const { CURVE, curveOpts } = _weierstrass_legacy_opts_to_new(c);
13885
+ const ecdsaOpts = {
13886
+ hmac: c.hmac,
13887
+ randomBytes: c.randomBytes,
13888
+ lowS: c.lowS,
13889
+ bits2int: c.bits2int,
13890
+ bits2int_modN: c.bits2int_modN
13891
+ };
13892
+ return { CURVE, curveOpts, hash: c.hash, ecdsaOpts };
13893
+ }
13894
+ function _ecdsa_new_output_to_legacy(c, _ecdsa) {
13895
+ const Point = _ecdsa.Point;
13896
+ return Object.assign({}, _ecdsa, {
13897
+ ProjectivePoint: Point,
13898
+ CURVE: Object.assign({}, c, nLength(Point.Fn.ORDER, Point.Fn.BITS))
13899
+ });
13900
+ }
13901
+ function weierstrass(c) {
13902
+ const { CURVE, curveOpts, hash, ecdsaOpts } = _ecdsa_legacy_opts_to_new(c);
13903
+ const Point = weierstrassN(CURVE, curveOpts);
13904
+ const signs = ecdsa(Point, hash, ecdsaOpts);
13905
+ return _ecdsa_new_output_to_legacy(c, signs);
13906
+ }
13907
+ var divNearest, DERErr, DER, _0n6, _1n6, _2n4, _3n3, _4n2;
13908
+ var init_weierstrass = __esm({
13909
+ "../../node_modules/@noble/curves/esm/abstract/weierstrass.js"() {
13910
+ "use strict";
13911
+ init_hmac();
13912
+ init_utils();
13913
+ init_utils2();
13914
+ init_curve();
13915
+ init_modular();
13916
+ divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n4) / den;
13917
+ DERErr = class extends Error {
13918
+ constructor(m = "") {
13919
+ super(m);
13920
+ }
13921
+ };
13922
+ DER = {
13923
+ // asn.1 DER encoding utils
13924
+ Err: DERErr,
13925
+ // Basic building block is TLV (Tag-Length-Value)
13926
+ _tlv: {
13927
+ encode: (tag, data) => {
13928
+ const { Err: E } = DER;
13929
+ if (tag < 0 || tag > 256)
13930
+ throw new E("tlv.encode: wrong tag");
13931
+ if (data.length & 1)
13932
+ throw new E("tlv.encode: unpadded data");
13933
+ const dataLen = data.length / 2;
13934
+ const len = numberToHexUnpadded(dataLen);
13935
+ if (len.length / 2 & 128)
13936
+ throw new E("tlv.encode: long form length too big");
13937
+ const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
13938
+ const t = numberToHexUnpadded(tag);
13939
+ return t + lenLen + len + data;
13940
+ },
13941
+ // v - value, l - left bytes (unparsed)
13942
+ decode(tag, data) {
13943
+ const { Err: E } = DER;
13944
+ let pos = 0;
13945
+ if (tag < 0 || tag > 256)
13946
+ throw new E("tlv.encode: wrong tag");
13947
+ if (data.length < 2 || data[pos++] !== tag)
13948
+ throw new E("tlv.decode: wrong tlv");
13949
+ const first = data[pos++];
13950
+ const isLong = !!(first & 128);
13951
+ let length5 = 0;
13952
+ if (!isLong)
13953
+ length5 = first;
13954
+ else {
13955
+ const lenLen = first & 127;
13956
+ if (!lenLen)
13957
+ throw new E("tlv.decode(long): indefinite length not supported");
13958
+ if (lenLen > 4)
13959
+ throw new E("tlv.decode(long): byte length is too big");
13960
+ const lengthBytes = data.subarray(pos, pos + lenLen);
13961
+ if (lengthBytes.length !== lenLen)
13962
+ throw new E("tlv.decode: length bytes not complete");
13963
+ if (lengthBytes[0] === 0)
13964
+ throw new E("tlv.decode(long): zero leftmost byte");
13965
+ for (const b of lengthBytes)
13966
+ length5 = length5 << 8 | b;
13967
+ pos += lenLen;
13968
+ if (length5 < 128)
13969
+ throw new E("tlv.decode(long): not minimal encoding");
13970
+ }
13971
+ const v = data.subarray(pos, pos + length5);
13972
+ if (v.length !== length5)
13973
+ throw new E("tlv.decode: wrong value length");
13974
+ return { v, l: data.subarray(pos + length5) };
13975
+ }
13976
+ },
13977
+ // https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
13978
+ // since we always use positive integers here. It must always be empty:
13979
+ // - add zero byte if exists
13980
+ // - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
13981
+ _int: {
13982
+ encode(num) {
13983
+ const { Err: E } = DER;
13984
+ if (num < _0n6)
13985
+ throw new E("integer: negative integers are not allowed");
13986
+ let hex3 = numberToHexUnpadded(num);
13987
+ if (Number.parseInt(hex3[0], 16) & 8)
13988
+ hex3 = "00" + hex3;
13989
+ if (hex3.length & 1)
13990
+ throw new E("unexpected DER parsing assertion: unpadded hex");
13991
+ return hex3;
13992
+ },
13993
+ decode(data) {
13994
+ const { Err: E } = DER;
13995
+ if (data[0] & 128)
13996
+ throw new E("invalid signature integer: negative");
13997
+ if (data[0] === 0 && !(data[1] & 128))
13998
+ throw new E("invalid signature integer: unnecessary leading zero");
13999
+ return bytesToNumberBE(data);
14000
+ }
14001
+ },
14002
+ toSig(hex3) {
14003
+ const { Err: E, _int: int, _tlv: tlv } = DER;
14004
+ const data = ensureBytes("signature", hex3);
14005
+ const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
14006
+ if (seqLeftBytes.length)
14007
+ throw new E("invalid signature: left bytes after parsing");
14008
+ const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
14009
+ const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
14010
+ if (sLeftBytes.length)
14011
+ throw new E("invalid signature: left bytes after parsing");
14012
+ return { r: int.decode(rBytes), s: int.decode(sBytes) };
14013
+ },
14014
+ hexFromSig(sig) {
14015
+ const { _tlv: tlv, _int: int } = DER;
14016
+ const rs = tlv.encode(2, int.encode(sig.r));
14017
+ const ss = tlv.encode(2, int.encode(sig.s));
14018
+ const seq = rs + ss;
14019
+ return tlv.encode(48, seq);
14020
+ }
14021
+ };
14022
+ _0n6 = BigInt(0);
14023
+ _1n6 = BigInt(1);
14024
+ _2n4 = BigInt(2);
14025
+ _3n3 = BigInt(3);
14026
+ _4n2 = BigInt(4);
14027
+ }
14028
+ });
14029
+
14030
+ // ../../node_modules/@noble/curves/esm/_shortw_utils.js
14031
+ function createCurve(curveDef, defHash) {
14032
+ const create5 = (hash) => weierstrass({ ...curveDef, hash });
14033
+ return { ...create5(defHash), create: create5 };
14034
+ }
14035
+ var init_shortw_utils = __esm({
14036
+ "../../node_modules/@noble/curves/esm/_shortw_utils.js"() {
14037
+ "use strict";
14038
+ init_weierstrass();
14039
+ }
14040
+ });
14041
+
14042
+ // ../../node_modules/@noble/curves/esm/nist.js
14043
+ var p256_CURVE, p384_CURVE, p521_CURVE, Fp256, Fp384, Fp521, p256, p384, p521;
14044
+ var init_nist = __esm({
14045
+ "../../node_modules/@noble/curves/esm/nist.js"() {
14046
+ "use strict";
14047
+ init_sha2();
14048
+ init_shortw_utils();
14049
+ init_modular();
14050
+ p256_CURVE = {
14051
+ p: BigInt("0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff"),
14052
+ n: BigInt("0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"),
14053
+ h: BigInt(1),
14054
+ a: BigInt("0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc"),
14055
+ b: BigInt("0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),
14056
+ Gx: BigInt("0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),
14057
+ Gy: BigInt("0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5")
14058
+ };
14059
+ p384_CURVE = {
14060
+ p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff"),
14061
+ n: BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973"),
14062
+ h: BigInt(1),
14063
+ a: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc"),
14064
+ b: BigInt("0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"),
14065
+ Gx: BigInt("0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7"),
14066
+ Gy: BigInt("0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
14067
+ };
14068
+ p521_CURVE = {
14069
+ p: BigInt("0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
14070
+ n: BigInt("0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409"),
14071
+ h: BigInt(1),
14072
+ a: BigInt("0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc"),
14073
+ b: BigInt("0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00"),
14074
+ Gx: BigInt("0x00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66"),
14075
+ Gy: BigInt("0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650")
14076
+ };
14077
+ Fp256 = Field(p256_CURVE.p);
14078
+ Fp384 = Field(p384_CURVE.p);
14079
+ Fp521 = Field(p521_CURVE.p);
14080
+ p256 = createCurve({ ...p256_CURVE, Fp: Fp256, lowS: false }, sha256);
14081
+ p384 = createCurve({ ...p384_CURVE, Fp: Fp384, lowS: false }, sha384);
14082
+ p521 = createCurve({ ...p521_CURVE, Fp: Fp521, lowS: false, allowedPrivateKeyLengths: [130, 131, 132] }, sha512);
14083
+ }
14084
+ });
14085
+
14086
+ // ../../node_modules/@noble/curves/esm/p256.js
14087
+ var p2562;
14088
+ var init_p256 = __esm({
14089
+ "../../node_modules/@noble/curves/esm/p256.js"() {
14090
+ "use strict";
14091
+ init_nist();
14092
+ p2562 = p256;
14093
+ }
14094
+ });
14095
+
12790
14096
  // ../share-envelope/dist/links.js
12791
14097
  var links_exports = {};
12792
14098
  __export(links_exports, {
@@ -12813,6 +14119,7 @@ __export(links_exports, {
12813
14119
  checkLinkBody: () => checkLinkBody,
12814
14120
  checkLinkHeaderLife: () => checkLinkHeaderLife,
12815
14121
  checkLinkRecord: () => checkLinkRecord,
14122
+ createApprovalRequest: () => createApprovalRequest,
12816
14123
  createLink: () => createLink,
12817
14124
  deleteLink: () => deleteLink,
12818
14125
  ed25519KeyProblem: () => ed25519KeyProblem,
@@ -12826,11 +14133,13 @@ __export(links_exports, {
12826
14133
  linkTypeSchema: () => linkTypeSchema,
12827
14134
  normalizeLinkId: () => normalizeLinkId,
12828
14135
  openLinkRecord: () => openLinkRecord,
14136
+ parseApprovalRequest: () => parseApprovalRequest,
12829
14137
  parseLink: () => parseLink,
12830
14138
  parseLinkTimestamp: () => parseLinkTimestamp,
12831
14139
  prepareLinkRecord: () => prepareLinkRecord,
12832
14140
  randomLinkNonce: () => randomLinkNonce,
12833
14141
  redactLink: () => redactLink,
14142
+ resolveApprovalRequest: () => resolveApprovalRequest,
12834
14143
  resolveLink: () => resolveLink,
12835
14144
  shortShareLinkCid: () => shortShareLinkCid,
12836
14145
  signDelete: () => signDelete,
@@ -13205,14 +14514,14 @@ function linkTypeForPathLetter(letter) {
13205
14514
  function normalizeLinkId(id) {
13206
14515
  return /^[A-Za-z2-7]{26}$/.test(id) ? id.toLowerCase() : null;
13207
14516
  }
13208
- function canonicalHttpsOrigin(origin) {
14517
+ function canonicalHttpsOrigin(origin2) {
13209
14518
  let url;
13210
14519
  try {
13211
- url = new URL(origin);
14520
+ url = new URL(origin2);
13212
14521
  } catch {
13213
14522
  return false;
13214
14523
  }
13215
- return url.protocol === "https:" && url.username === "" && url.password === "" && url.origin === origin;
14524
+ return url.protocol === "https:" && url.username === "" && url.password === "" && url.origin === origin2;
13216
14525
  }
13217
14526
  function assertKey2(key) {
13218
14527
  if (key.length !== 32) throw new LinkError("invalid_argument", "a link key is 32 bytes");
@@ -13345,9 +14654,19 @@ async function openLinkRecord(record2, key, options = {}) {
13345
14654
  await runBodyValidator(opened, options.validateBody);
13346
14655
  return opened;
13347
14656
  }
13348
- function checkApiOrigin(origin) {
13349
- if (!AUDIENCE_ORIGIN.test(origin)) throw new LinkError("invalid_argument", "the API origin is not a canonical https origin");
13350
- return origin;
14657
+ function parseApprovalRequest(value, options = {}) {
14658
+ const parsed = requestSchema.safeParse(value);
14659
+ if (!parsed.success) throw new LinkError("body_validation_failed", "invalid approval request");
14660
+ const request = parsed.data;
14661
+ const publicKey = decodeStrictBase64Url(request.targetPublicJwk.x);
14662
+ if (ed25519KeyProblem(publicKey) !== null || didKeyFromEd25519PublicKey(publicKey) !== request.targetDid || request.issuer !== request.targetDid || options.issuer !== void 0 && request.issuer !== options.issuer) {
14663
+ throw new LinkError("issuer_binding_mismatch");
14664
+ }
14665
+ return request;
14666
+ }
14667
+ function checkApiOrigin(origin2) {
14668
+ if (!AUDIENCE_ORIGIN.test(origin2)) throw new LinkError("invalid_argument", "the API origin is not a canonical https origin");
14669
+ return origin2;
13351
14670
  }
13352
14671
  function requestSignal(options) {
13353
14672
  const timeout = AbortSignal.timeout(options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
@@ -13460,6 +14779,34 @@ async function createLink(input) {
13460
14779
  const { id } = created.data;
13461
14780
  return { link: buildShortLink({ origin: input.linkOrigin, type: input.type, id, key, bodyCid }), id, expiresAt: record2.header.expiresAt, bodyCid };
13462
14781
  }
14782
+ async function createApprovalRequest(input) {
14783
+ const request = parseApprovalRequest(input.request, { issuer: input.issuerKey.did });
14784
+ const now = toEpochMs(input.now);
14785
+ const prepared = await prepareLinkRecord({
14786
+ type: "openkey-approval-request",
14787
+ issuerKey: input.issuerKey,
14788
+ apiOrigin: input.apiOrigin,
14789
+ now,
14790
+ expiresAt: input.expiresAt ?? new Date(now + LINK_TYPE_SPECS["openkey-approval-request"].defaultLifeSeconds * 1e3),
14791
+ plaintext: new TextEncoder().encode(canonicalize2(request))
14792
+ });
14793
+ const response = await send(
14794
+ `${checkApiOrigin(input.apiOrigin)}/v1/links`,
14795
+ { method: "POST", body: JSON.stringify(prepared.record) },
14796
+ input,
14797
+ "application/json"
14798
+ );
14799
+ if (response.status !== 201) throw await refusal(response);
14800
+ const created = createdSchema.safeParse(await readJson2(response));
14801
+ if (!created.success || !LINK_ID_PATTERN.test(created.data.id) || created.data.expiresAt !== prepared.record.header.expiresAt) throw new LinkError("invalid_response");
14802
+ return {
14803
+ id: created.data.id,
14804
+ expiresAt: prepared.record.header.expiresAt,
14805
+ bodyCid: prepared.bodyCid,
14806
+ record: prepared.record,
14807
+ link: buildShortLink({ origin: input.openkeyOrigin, type: "openkey-approval-request", id: created.data.id, key: prepared.key, bodyCid: prepared.bodyCid })
14808
+ };
14809
+ }
13463
14810
  async function deleteLink(input) {
13464
14811
  const apiOrigin = checkApiOrigin(input.apiOrigin);
13465
14812
  const id = normalizeLinkId(input.id);
@@ -13524,9 +14871,20 @@ async function resolveLink(link4, input) {
13524
14871
  } else if (opened.type !== "share") {
13525
14872
  throw new LinkError("full_non_share");
13526
14873
  }
14874
+ if (opened.type === "openkey-approval-request") {
14875
+ if (opened.header.audience !== input.apiOrigin) throw new LinkError("audience_mismatch");
14876
+ parseApprovalRequest(opened.value, { issuer: opened.header.issuer });
14877
+ }
13527
14878
  await runBodyValidator(opened, input.validateBody);
13528
14879
  return { ...opened, form: parsed.form, id: parsed.form === "short" ? parsed.id : void 0 };
13529
14880
  }
14881
+ async function resolveApprovalRequest(link4, input) {
14882
+ const opened = await resolveLink(link4, input);
14883
+ if (opened.type !== "openkey-approval-request") throw new LinkError("type_path_mismatch");
14884
+ if (opened.header.audience !== input.apiOrigin) throw new LinkError("audience_mismatch");
14885
+ const request = parseApprovalRequest(opened.value, { issuer: opened.header.issuer });
14886
+ return { ...opened, request };
14887
+ }
13530
14888
  function shortShareLinkCid(href, options) {
13531
14889
  try {
13532
14890
  const parsed = parseLink(href, { trustedOrigins: options.trustedOrigins });
@@ -13569,7 +14927,7 @@ function signerFromJwk(jwk) {
13569
14927
  if (signer.did !== didKeyFromEd25519PublicKey(publicKey)) throw new LinkError("invalid_argument", "the JWK public key does not match its private key");
13570
14928
  return signer;
13571
14929
  }
13572
- var SHA256_CODE2, ENVELOPE_AAD_LABEL2, SEALED_BLOB_VERSION, AAD2, KEY_LENGTH, NONCE_LENGTH, TAG_LENGTH, HEADER_LENGTH, LINK_TYPES, MAX_LINK_BODY_BYTES, MAX_LINK_REQUEST_BYTES, LINK_TYPE_SPECS, LINK_HEADER_DOMAIN, LINK_DELETE_DOMAIN, LINK_WINDOW_SECONDS, LINK_MIN_LIFE_SECONDS, LINK_MIN_BODY_BYTES, LINK_SEAL_OVERHEAD_BYTES, LINK_MAX_RECORD_HEADER_BYTES, DEFAULT_LINKS_API_ORIGIN, FULL_LINK_PATH, LINK_ID_PATTERN, LinkError, ED25519_MULTICODEC_PREFIX2, PUBLIC_KEY_LENGTH, ExtendedPoint, GROUP_ORDER, FIELD_PRIME, DID_KEY_PATTERN, SERVICE_ISSUER_PATTERN, AUDIENCE_PATTERN, TIMESTAMP_PATTERN, NONCE_PATTERN, CID_PATTERN, HEADER_KEYS, DELETE_KEYS, ed25519DidKey, linkTypeSchema, linkHeaderV1Schema, linkSignatureV1Schema, linkDeleteRequestV1Schema, LINK_FRAGMENT_VERSION, SHORT_PATH, SHORT_FRAGMENT, FULL_FRAGMENT, REMOVED_FRAGMENT, MAX_FULL_RECORD_JSON_BYTES, jsonObject, DEFAULT_TIMEOUT_MS, MAX_JSON_RESPONSE_BYTES, AUDIENCE_ORIGIN, createdSchema, errorBodySchema, KEY_PARAMETER, DEFAULT_SHARE_ORIGINS;
14930
+ var SHA256_CODE2, ENVELOPE_AAD_LABEL2, SEALED_BLOB_VERSION, AAD2, KEY_LENGTH, NONCE_LENGTH, TAG_LENGTH, HEADER_LENGTH, LINK_TYPES, MAX_LINK_BODY_BYTES, MAX_LINK_REQUEST_BYTES, LINK_TYPE_SPECS, LINK_HEADER_DOMAIN, LINK_DELETE_DOMAIN, LINK_WINDOW_SECONDS, LINK_MIN_LIFE_SECONDS, LINK_MIN_BODY_BYTES, LINK_SEAL_OVERHEAD_BYTES, LINK_MAX_RECORD_HEADER_BYTES, DEFAULT_LINKS_API_ORIGIN, FULL_LINK_PATH, LINK_ID_PATTERN, LinkError, ED25519_MULTICODEC_PREFIX2, PUBLIC_KEY_LENGTH, ExtendedPoint, GROUP_ORDER, FIELD_PRIME, DID_KEY_PATTERN, SERVICE_ISSUER_PATTERN, AUDIENCE_PATTERN, TIMESTAMP_PATTERN, NONCE_PATTERN, CID_PATTERN, HEADER_KEYS, DELETE_KEYS, ed25519DidKey, linkTypeSchema, linkHeaderV1Schema, linkSignatureV1Schema, linkDeleteRequestV1Schema, LINK_FRAGMENT_VERSION, SHORT_PATH, SHORT_FRAGMENT, FULL_FRAGMENT, REMOVED_FRAGMENT, MAX_FULL_RECORD_JSON_BYTES, jsonObject, bytes32, ed25519Jwk, p256Jwk, origin, permission, requestSchema, DEFAULT_TIMEOUT_MS, MAX_JSON_RESPONSE_BYTES, AUDIENCE_ORIGIN, createdSchema, errorBodySchema, KEY_PARAMETER, DEFAULT_SHARE_ORIGINS;
13573
14931
  var init_links = __esm({
13574
14932
  "../share-envelope/dist/links.js"() {
13575
14933
  "use strict";
@@ -13584,6 +14942,8 @@ var init_links = __esm({
13584
14942
  init_base58();
13585
14943
  init_ed25519();
13586
14944
  init_zod();
14945
+ init_p256();
14946
+ init_zod();
13587
14947
  init_ed25519();
13588
14948
  SHA256_CODE2 = 18;
13589
14949
  ENVELOPE_AAD_LABEL2 = "tinycloud-share-envelope-v1";
@@ -13593,11 +14953,12 @@ var init_links = __esm({
13593
14953
  NONCE_LENGTH = 12;
13594
14954
  TAG_LENGTH = 16;
13595
14955
  HEADER_LENGTH = 1;
13596
- LINK_TYPES = ["openkey-login", "courier", "share"];
14956
+ LINK_TYPES = ["openkey-login", "openkey-approval-request", "courier", "share"];
13597
14957
  MAX_LINK_BODY_BYTES = 65536;
13598
14958
  MAX_LINK_REQUEST_BYTES = Math.ceil(MAX_LINK_BODY_BYTES * 4 / 3) + 3072;
13599
14959
  LINK_TYPE_SPECS = {
13600
14960
  "openkey-login": { maxLifeSeconds: 600, defaultLifeSeconds: 600, pathLetter: "l", readOnce: true },
14961
+ "openkey-approval-request": { maxLifeSeconds: 86400, defaultLifeSeconds: 3600, pathLetter: "a", readOnce: false },
13601
14962
  courier: { maxLifeSeconds: 604800, defaultLifeSeconds: 86400, pathLetter: "c", readOnce: false },
13602
14963
  share: { maxLifeSeconds: 2592e3, defaultLifeSeconds: 2592e3, pathLetter: "s", readOnce: false }
13603
14964
  };
@@ -13668,12 +15029,52 @@ var init_links = __esm({
13668
15029
  nonce: external_exports2.string()
13669
15030
  }).strict();
13670
15031
  LINK_FRAGMENT_VERSION = 4;
13671
- SHORT_PATH = /^\/(s|c|l)\/([A-Za-z2-7]{26})$/;
15032
+ SHORT_PATH = /^\/(s|c|l|a)\/([A-Za-z2-7]{26})$/;
13672
15033
  SHORT_FRAGMENT = /^#v=4&k=([A-Za-z0-9_-]{43})&c=(bafkrei[a-z2-7]{52})$/;
13673
15034
  FULL_FRAGMENT = /^#v=4&k=([A-Za-z0-9_-]{43})&r=([A-Za-z0-9_-]+)$/;
13674
15035
  REMOVED_FRAGMENT = /^#v=[23](&|$)/;
13675
15036
  MAX_FULL_RECORD_JSON_BYTES = MAX_LINK_REQUEST_BYTES;
13676
15037
  jsonObject = external_exports2.record(external_exports2.unknown());
15038
+ bytes32 = external_exports2.string().refine((value) => decodeStrictBase64Url(value)?.length === 32);
15039
+ ed25519Jwk = external_exports2.object({ kty: external_exports2.literal("OKP"), crv: external_exports2.literal("Ed25519"), x: bytes32 }).strict();
15040
+ p256Jwk = external_exports2.object({ kty: external_exports2.literal("EC"), crv: external_exports2.literal("P-256"), x: bytes32, y: bytes32 }).strict().refine((key) => {
15041
+ try {
15042
+ const point = new Uint8Array(65);
15043
+ point[0] = 4;
15044
+ point.set(decodeStrictBase64Url(key.x), 1);
15045
+ point.set(decodeStrictBase64Url(key.y), 33);
15046
+ p2562.ProjectivePoint.fromHex(point).assertValidity();
15047
+ return true;
15048
+ } catch {
15049
+ return false;
15050
+ }
15051
+ });
15052
+ origin = external_exports2.string().refine((value) => {
15053
+ try {
15054
+ const url = new URL(value);
15055
+ return url.origin === value && (url.protocol === "https:" || url.protocol === "http:" && ["127.0.0.1", "localhost", "[::1]"].includes(url.hostname));
15056
+ } catch {
15057
+ return false;
15058
+ }
15059
+ });
15060
+ permission = external_exports2.object({
15061
+ service: external_exports2.string().min(1),
15062
+ space: external_exports2.string().min(1),
15063
+ path: external_exports2.string(),
15064
+ actions: external_exports2.array(external_exports2.string().min(1)).min(1),
15065
+ caveats: external_exports2.array(external_exports2.unknown()).optional()
15066
+ }).strict();
15067
+ requestSchema = external_exports2.object({
15068
+ issuer: external_exports2.string(),
15069
+ requestVersion: external_exports2.literal(1),
15070
+ targetDid: external_exports2.string(),
15071
+ targetPublicJwk: ed25519Jwk,
15072
+ nodeOrigin: origin,
15073
+ permissions: external_exports2.array(permission).min(1),
15074
+ reason: external_exports2.string().optional(),
15075
+ grantLifetimeSeconds: external_exports2.number().int().positive(),
15076
+ resultEncryptionPublicJwk: p256Jwk
15077
+ }).strict();
13677
15078
  DEFAULT_TIMEOUT_MS = 1e4;
13678
15079
  MAX_JSON_RESPONSE_BYTES = 4096;
13679
15080
  AUDIENCE_ORIGIN = /^https:\/\/[a-z0-9]([a-z0-9.-]*[a-z0-9])?(:[0-9]{1,5})?$/;
@@ -18984,6 +20385,23 @@ var unifiedEncryptionNetworkSchema = external_exports.string().refine((value) =>
18984
20385
  const network = separator < 0 ? "" : rest.slice(separator + 1);
18985
20386
  return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
18986
20387
  }, { message: "expected canonical TinyCloud encryption network" });
20388
+ var unifiedEncryptionResourceSchema = external_exports.string().refine((value) => {
20389
+ const prefix = "urn:tinycloud:encryption:";
20390
+ if (!value.startsWith(prefix)) return false;
20391
+ const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
20392
+ if (match === null) return false;
20393
+ const path = match[3];
20394
+ return path === void 0 || path.split("/").every(
20395
+ (segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
20396
+ );
20397
+ }, { message: "expected a canonical TinyCloud encryption resource" });
20398
+ var unifiedEncryptionKeyPathSchema = external_exports.string().regex(/^share\/[^/]+$/).refine(
20399
+ (value) => {
20400
+ const segment = value.slice("share/".length);
20401
+ return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
20402
+ },
20403
+ { message: "expected an exact share key path" }
20404
+ );
18987
20405
  var unifiedKvCapabilitySchema = external_exports.object({
18988
20406
  kind: external_exports.literal("kv"),
18989
20407
  resource: unifiedResourceSchema,
@@ -18997,7 +20415,7 @@ var unifiedKvCapabilitySchema = external_exports.object({
18997
20415
  }).strict();
18998
20416
  var unifiedEncryptionCapabilitySchema = external_exports.object({
18999
20417
  kind: external_exports.literal("encryption"),
19000
- resource: unifiedEncryptionNetworkSchema,
20418
+ resource: unifiedEncryptionResourceSchema,
19001
20419
  action: external_exports.literal("tinycloud.encryption/decrypt")
19002
20420
  }).strict();
19003
20421
  var unifiedCapabilitySchema = external_exports.union([unifiedKvCapabilitySchema, unifiedEncryptionCapabilitySchema]);
@@ -19006,6 +20424,7 @@ var unifiedContentSourceSchema = external_exports.object({
19006
20424
  kvResource: unifiedResourceSchema,
19007
20425
  selector: external_exports.union([external_exports.literal("exact"), external_exports.literal("prefix")]),
19008
20426
  encryptionNetwork: unifiedEncryptionNetworkSchema,
20427
+ encryptionKeyPath: unifiedEncryptionKeyPathSchema.optional(),
19009
20428
  encryptedSymmetricKeyDigestHex: external_exports.string().regex(/^[0-9a-f]{64}$/),
19010
20429
  keyVersion: external_exports.number().int().positive(),
19011
20430
  mode: external_exports.union([external_exports.literal("mutable"), external_exports.literal("immutable")]),
@@ -19123,16 +20542,21 @@ function validateV3Invariants(value, ctx) {
19123
20542
  if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
19124
20543
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
19125
20544
  }
19126
- if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
20545
+ const encryptionKeyPath = value.contentSource.encryptionKeyPath;
20546
+ if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
20547
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
20548
+ }
20549
+ if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptionKeyPath !== encryptionKeyPath || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
19127
20550
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
19128
20551
  }
19129
20552
  if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
19130
20553
  ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
19131
20554
  }
19132
20555
  const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
19133
- const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === value.encryptionNetwork && capability.action === "tinycloud.encryption/decrypt");
20556
+ const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
20557
+ const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
19134
20558
  if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
19135
- ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt network" });
20559
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
19136
20560
  }
19137
20561
  }
19138
20562
  var unsignedShareEnvelopeV3Schema = unsignedShareEnvelopeV3BaseSchema.superRefine(validateV3Invariants);
@@ -24635,6 +26059,23 @@ var unifiedEncryptionNetworkSchema2 = external_exports3.string().refine((value)
24635
26059
  const network = separator < 0 ? "" : rest.slice(separator + 1);
24636
26060
  return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
24637
26061
  }, { message: "expected canonical TinyCloud encryption network" });
26062
+ var unifiedEncryptionResourceSchema2 = external_exports3.string().refine((value) => {
26063
+ const prefix = "urn:tinycloud:encryption:";
26064
+ if (!value.startsWith(prefix)) return false;
26065
+ const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
26066
+ if (match === null) return false;
26067
+ const path = match[3];
26068
+ return path === void 0 || path.split("/").every(
26069
+ (segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
26070
+ );
26071
+ }, { message: "expected a canonical TinyCloud encryption resource" });
26072
+ var unifiedEncryptionKeyPathSchema2 = external_exports3.string().regex(/^share\/[^/]+$/).refine(
26073
+ (value) => {
26074
+ const segment = value.slice("share/".length);
26075
+ return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
26076
+ },
26077
+ { message: "expected an exact share key path" }
26078
+ );
24638
26079
  var unifiedKvCapabilitySchema2 = external_exports3.object({
24639
26080
  kind: external_exports3.literal("kv"),
24640
26081
  resource: unifiedResourceSchema2,
@@ -24648,7 +26089,7 @@ var unifiedKvCapabilitySchema2 = external_exports3.object({
24648
26089
  }).strict();
24649
26090
  var unifiedEncryptionCapabilitySchema2 = external_exports3.object({
24650
26091
  kind: external_exports3.literal("encryption"),
24651
- resource: unifiedEncryptionNetworkSchema2,
26092
+ resource: unifiedEncryptionResourceSchema2,
24652
26093
  action: external_exports3.literal("tinycloud.encryption/decrypt")
24653
26094
  }).strict();
24654
26095
  var unifiedCapabilitySchema2 = external_exports3.union([unifiedKvCapabilitySchema2, unifiedEncryptionCapabilitySchema2]);
@@ -24657,6 +26098,7 @@ var unifiedContentSourceSchema2 = external_exports3.object({
24657
26098
  kvResource: unifiedResourceSchema2,
24658
26099
  selector: external_exports3.union([external_exports3.literal("exact"), external_exports3.literal("prefix")]),
24659
26100
  encryptionNetwork: unifiedEncryptionNetworkSchema2,
26101
+ encryptionKeyPath: unifiedEncryptionKeyPathSchema2.optional(),
24660
26102
  encryptedSymmetricKeyDigestHex: external_exports3.string().regex(/^[0-9a-f]{64}$/),
24661
26103
  keyVersion: external_exports3.number().int().positive(),
24662
26104
  mode: external_exports3.union([external_exports3.literal("mutable"), external_exports3.literal("immutable")]),
@@ -24774,16 +26216,21 @@ function validateV3Invariants2(value, ctx) {
24774
26216
  if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
24775
26217
  ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
24776
26218
  }
24777
- if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
26219
+ const encryptionKeyPath = value.contentSource.encryptionKeyPath;
26220
+ if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
26221
+ ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
26222
+ }
26223
+ if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptionKeyPath !== encryptionKeyPath || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
24778
26224
  ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
24779
26225
  }
24780
26226
  if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
24781
26227
  ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
24782
26228
  }
24783
26229
  const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
24784
- const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === value.encryptionNetwork && capability.action === "tinycloud.encryption/decrypt");
26230
+ const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
26231
+ const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
24785
26232
  if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
24786
- ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt network" });
26233
+ ctx.addIssue({ code: external_exports3.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
24787
26234
  }
24788
26235
  }
24789
26236
  var unsignedShareEnvelopeV3Schema2 = unsignedShareEnvelopeV3BaseSchema2.superRefine(validateV3Invariants2);
@@ -24793,6 +26240,7 @@ var SEALED_BLOB_VERSION2 = 1;
24793
26240
  var AAD3 = utf8Bytes3(ENVELOPE_AAD_LABEL3);
24794
26241
  var KEY_LENGTH2 = 32;
24795
26242
  var NONCE_LENGTH2 = 12;
26243
+ var TAG_LENGTH2 = 16;
24796
26244
  var HEADER_LENGTH2 = 1;
24797
26245
  function assertKey3(key32) {
24798
26246
  if (key32.length !== KEY_LENGTH2) {
@@ -24820,6 +26268,17 @@ async function seal2(plaintextBytes, key32) {
24820
26268
  blob.set(ciphertext, HEADER_LENGTH2 + nonce.length);
24821
26269
  return { blob, cid: await computeCid2(blob) };
24822
26270
  }
26271
+ async function open7(blob, key32) {
26272
+ if (blob.length < HEADER_LENGTH2 + NONCE_LENGTH2 + TAG_LENGTH2) {
26273
+ throw new TypeError(`sealed blob too short: ${blob.length} bytes`);
26274
+ }
26275
+ if (blob[0] !== SEALED_BLOB_VERSION2) {
26276
+ throw new TypeError(`unknown sealed blob version: ${blob[0]}`);
26277
+ }
26278
+ const nonce = blob.subarray(HEADER_LENGTH2, HEADER_LENGTH2 + NONCE_LENGTH2);
26279
+ const ciphertext = blob.subarray(HEADER_LENGTH2 + NONCE_LENGTH2);
26280
+ return decryptEnvelope2(nonce, ciphertext, key32);
26281
+ }
24823
26282
  async function encryptEnvelope2(plaintextBytes, key32) {
24824
26283
  const key = await importAesKey2(key32, "encrypt");
24825
26284
  const nonce = globalThis.crypto.getRandomValues(new Uint8Array(NONCE_LENGTH2));
@@ -24832,6 +26291,19 @@ async function encryptEnvelope2(plaintextBytes, key32) {
24832
26291
  );
24833
26292
  return { nonce, ciphertext };
24834
26293
  }
26294
+ async function decryptEnvelope2(nonce, ciphertext, key32) {
26295
+ if (nonce.length !== NONCE_LENGTH2) {
26296
+ throw new TypeError(`nonce must be ${NONCE_LENGTH2} bytes, got ${nonce.length}`);
26297
+ }
26298
+ const key = await importAesKey2(key32, "decrypt");
26299
+ return new Uint8Array(
26300
+ await globalThis.crypto.subtle.decrypt(
26301
+ { name: "AES-GCM", iv: nonce, additionalData: AAD3 },
26302
+ key,
26303
+ ciphertext
26304
+ )
26305
+ );
26306
+ }
24835
26307
  function isPlainRecord3(value) {
24836
26308
  const proto = Object.getPrototypeOf(value);
24837
26309
  return proto === Object.prototype || proto === null;
@@ -24946,6 +26418,7 @@ function equal(left, right) {
24946
26418
  return left.length === right.length && left.every((byte, index) => byte === right[index]);
24947
26419
  }
24948
26420
  var ED25519_VERIFY_OPTS2 = { zip215: false };
26421
+ var ENVELOPE_V2_SIGNATURE_DOMAIN = "xyz.tinycloud.share/envelope/v2\0";
24949
26422
  var ENVELOPE_V3_SIGNATURE_DOMAIN = "xyz.tinycloud.share/envelope/v3\0";
24950
26423
  var POLICY_V1_SIGNATURE_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
24951
26424
  var POLICY_V2_SIGNATURE_DOMAIN = "xyz.tinycloud.policy/policy/v2\0";
@@ -24953,6 +26426,14 @@ var CONTENT_SOURCE_V1_DOMAIN = "xyz.tinycloud.policy/ContentSource/v1\0";
24953
26426
  var POLICY_CAPABILITY_V1_DOMAIN = "xyz.tinycloud.policy/PolicyCapability/v1\0";
24954
26427
  var NATIVE_PROJECTION_V1_DOMAIN = "xyz.tinycloud.policy/NativeProjection/v1\0";
24955
26428
  var ATTESTED_ENFORCER_V2_DOMAIN = "xyz.tinycloud.policy/AttestedEnforcerBinding/v2\0";
26429
+ function signingBytesV2(unsigned) {
26430
+ const domain = utf8Bytes3(ENVELOPE_V2_SIGNATURE_DOMAIN);
26431
+ const body = utf8Bytes3(canonicalize3(unsigned));
26432
+ const bytes3 = new Uint8Array(domain.length + body.length);
26433
+ bytes3.set(domain);
26434
+ bytes3.set(body, domain.length);
26435
+ return bytes3;
26436
+ }
24956
26437
  function signingBytesV3(unsigned) {
24957
26438
  const domain = utf8Bytes3(ENVELOPE_V3_SIGNATURE_DOMAIN);
24958
26439
  const body = utf8Bytes3(canonicalize3(unsigned));
@@ -24961,6 +26442,17 @@ function signingBytesV3(unsigned) {
24961
26442
  bytes3.set(body, domain.length);
24962
26443
  return bytes3;
24963
26444
  }
26445
+ function verifyEnvelopeV2SignatureOnly(envelope) {
26446
+ const parsed = shareEnvelopeV2Schema2.parse(envelope);
26447
+ const { signature, ...unsigned } = parsed;
26448
+ return ed25519.verify(fromBase64Url3(signature.value), signingBytesV2(unsigned), ed25519PublicKeyFromDidKey2(signature.signerDid), ED25519_VERIFY_OPTS2);
26449
+ }
26450
+ async function verifyEnvelopeV2(envelope, options) {
26451
+ const parsed = shareEnvelopeV2Schema2.parse(envelope);
26452
+ if (parsed.signature.signerDid !== options.expectedSignerDid || !verifyEnvelopeV2SignatureOnly(parsed)) return false;
26453
+ if (parsed.authorizationTarget.kind === "policy") return await computeCid2(fromBase64Url3(parsed.authorizationTarget.policyBytes)) === parsed.authorizationTarget.policyCid;
26454
+ return true;
26455
+ }
24964
26456
  function verifyEnvelopeV3SignatureOnly(envelope) {
24965
26457
  const parsed = shareEnvelopeV3Schema2.parse(envelope);
24966
26458
  const { signature, ...unsigned } = parsed;
@@ -25047,6 +26539,52 @@ function base32Lower(bytes3) {
25047
26539
  if (bits > 0) output += alphabet[buffer << 5 - bits & 31];
25048
26540
  return output;
25049
26541
  }
26542
+ var KEY_LENGTH22 = 32;
26543
+ function assertCanonicalCid(cidString) {
26544
+ const cid2 = CID3.parse(cidString);
26545
+ if (cid2.version !== 1 || cid2.code !== code3 || cid2.multihash.code !== 18 || // sha2-256 (0x12) only, at the link layer too
26546
+ cid2.toString() !== cidString) {
26547
+ throw new TypeError(`not a canonical CIDv1 raw sha2-256 base32 CID: ${cidString}`);
26548
+ }
26549
+ }
26550
+ function parseShareUrl(url, options = {}) {
26551
+ const parsed = new URL(url);
26552
+ if (parsed.protocol !== "https:") {
26553
+ throw new TypeError(`share URL must be https, got ${parsed.protocol}`);
26554
+ }
26555
+ if (parsed.username !== "" || parsed.password !== "") {
26556
+ throw new TypeError("share URL must not carry userinfo");
26557
+ }
26558
+ if (parsed.search !== "") {
26559
+ throw new TypeError("share URL must not have a query string");
26560
+ }
26561
+ if (options.expectedOrigin !== void 0) {
26562
+ if (!isCanonicalHttpsOrigin2(options.expectedOrigin)) {
26563
+ throw new TypeError(
26564
+ `expectedOrigin must be a canonical https origin, got ${options.expectedOrigin}`
26565
+ );
26566
+ }
26567
+ if (parsed.origin !== options.expectedOrigin) {
26568
+ throw new TypeError(
26569
+ `share URL origin ${parsed.origin} does not match expected ${options.expectedOrigin}`
26570
+ );
26571
+ }
26572
+ }
26573
+ const match = /^\/s\/([a-z2-7]+)$/.exec(parsed.pathname);
26574
+ if (!match || match[1] === void 0) {
26575
+ throw new TypeError(`not a share URL path: ${parsed.pathname}`);
26576
+ }
26577
+ const ciphertextCid = match[1];
26578
+ assertCanonicalCid(ciphertextCid);
26579
+ if (!parsed.hash.startsWith("#k=")) {
26580
+ throw new TypeError("share URL is missing the #k= key fragment");
26581
+ }
26582
+ const key32 = fromBase64Url3(parsed.hash.slice("#k=".length));
26583
+ if (key32.length !== KEY_LENGTH22) {
26584
+ throw new TypeError(`fragment key must be ${KEY_LENGTH22} bytes, got ${key32.length}`);
26585
+ }
26586
+ return { ciphertextCid, key32 };
26587
+ }
25050
26588
  var ARTIFACT_ROOT2 = "artifacts";
25051
26589
  function parseArtifactVersionPath2(path) {
25052
26590
  const match = /^artifacts\/([a-z0-9][a-z0-9_-]{2,62})\/versions\/([1-9][0-9]{0,14})\/([^/]+)$/.exec(path);
@@ -25123,6 +26661,7 @@ function verifyArtifactShare(envelope, options) {
25123
26661
  }
25124
26662
  var SHARE_RESULT_VERSION = 1;
25125
26663
  var DEFAULT_MAX_SEALED_BLOB_BYTES = 100 * 1024 * 1024 + 29;
26664
+ var DEFAULT_MAX_CONTENT_BLOB_BYTES = DEFAULT_MAX_SEALED_BLOB_BYTES;
25126
26665
  var ShareReceiveError = class extends Error {
25127
26666
  code;
25128
26667
  details;
@@ -25136,13 +26675,13 @@ var ShareReceiveError = class extends Error {
25136
26675
  return { protocol: "tinycloud-share", version: SHARE_RESULT_VERSION, error: { code: this.code } };
25137
26676
  }
25138
26677
  };
25139
- function metadataFor(envelope, origin) {
25140
- const kind = envelope.recipientMatcher.kind === "recipientDid" ? "recipientDid" : envelope.recipientMatcher.kind === "exactEmail" ? "email" : "emailDomain";
26678
+ function metadataFor(envelope, origin2) {
26679
+ const kind = envelope.recipientMatcher.kind === "recipientDid" ? "recipientDid" : envelope.recipientMatcher.kind === "exactEmail" ? "email" : envelope.recipientMatcher.kind === "emailDomain" ? "emailDomain" : "bearer";
25141
26680
  return {
25142
26681
  protocol: "tinycloud-share",
25143
26682
  version: 1,
25144
26683
  shareId: envelope.shareId,
25145
- origin,
26684
+ origin: origin2,
25146
26685
  target: { ...envelope.target, kind },
25147
26686
  resource: { ...envelope.resource },
25148
26687
  actions: [...envelope.actions],
@@ -25152,7 +26691,7 @@ function metadataFor(envelope, origin) {
25152
26691
  ...envelope.display.filename === void 0 ? {} : { filename: envelope.display.filename },
25153
26692
  ...envelope.display.mode === void 0 ? {} : { mode: envelope.display.mode }
25154
26693
  },
25155
- ...envelope.artifactPin === void 0 ? {} : { artifact: { id: envelope.artifactPin.artifactId, version: envelope.artifactPin.version } }
26694
+ ...envelope.version === 3 && envelope.artifactPin !== void 0 ? { artifact: { id: envelope.artifactPin.artifactId, version: envelope.artifactPin.version } } : {}
25156
26695
  };
25157
26696
  }
25158
26697
  function receiveErrorFor(error) {
@@ -25250,14 +26789,165 @@ async function resolvePolicyShare(link4, options) {
25250
26789
  options.onResolvedAddressedEnvelope?.(envelope, cid2);
25251
26790
  return { envelope, origin: url.origin, cid: cid2 };
25252
26791
  }
26792
+ async function resolveLegacyV2(link4, options) {
26793
+ let parsed;
26794
+ try {
26795
+ parsed = parseShareUrl(link4, { ...options.expectedOrigin === void 0 ? {} : { expectedOrigin: options.expectedOrigin } });
26796
+ } catch {
26797
+ throw new ShareReceiveError("invalid-link", "legacy share link format is invalid");
26798
+ }
26799
+ try {
26800
+ options.signal?.throwIfAborted();
26801
+ const origin2 = new URL(link4).origin;
26802
+ const limit = options.maxSealedBlobBytes ?? DEFAULT_MAX_SEALED_BLOB_BYTES;
26803
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope limit is invalid");
26804
+ let sealed;
26805
+ if (options.fetchBlob !== void 0) {
26806
+ try {
26807
+ sealed = await options.fetchBlob({ origin: origin2, cid: parsed.ciphertextCid, ...options.signal === void 0 ? {} : { signal: options.signal } });
26808
+ } catch {
26809
+ throw new ShareReceiveError("fetch-failed", "legacy registry unavailable");
26810
+ }
26811
+ } else {
26812
+ if (options.registryBaseUrl === void 0) throw new ShareReceiveError("fetch-failed", "legacy registry is required");
26813
+ const response = await (options.fetch ?? globalThis.fetch)(`${options.registryBaseUrl.replace(/\/+$/, "")}/ipfs/${parsed.ciphertextCid}?format=raw`, {
26814
+ headers: { accept: "application/vnd.ipld.raw" },
26815
+ redirect: "error",
26816
+ ...options.signal === void 0 ? {} : { signal: options.signal }
26817
+ });
26818
+ if (!response.ok) throw new ShareReceiveError("fetch-failed", "legacy registry unavailable");
26819
+ if (Number(response.headers.get("content-length")) > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
26820
+ const reader = response.body?.getReader();
26821
+ if (reader === void 0) throw new ShareReceiveError("fetch-failed", "legacy registry returned no body");
26822
+ const chunks = [];
26823
+ let length32 = 0;
26824
+ for (; ; ) {
26825
+ const part = await reader.read();
26826
+ if (part.done) break;
26827
+ length32 += part.value.length;
26828
+ if (length32 > limit) {
26829
+ await reader.cancel();
26830
+ throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
26831
+ }
26832
+ chunks.push(part.value);
26833
+ }
26834
+ sealed = new Uint8Array(length32);
26835
+ let offset = 0;
26836
+ for (const chunk of chunks) {
26837
+ sealed.set(chunk, offset);
26838
+ offset += chunk.length;
26839
+ }
26840
+ }
26841
+ options.signal?.throwIfAborted();
26842
+ if (!(sealed instanceof Uint8Array) || sealed.length > limit) throw new ShareReceiveError("max-bytes-exceeded", "sealed envelope exceeds the size limit");
26843
+ if (await computeCid2(sealed) !== parsed.ciphertextCid) throw new ShareReceiveError("cid-mismatch", "legacy envelope CID does not match");
26844
+ let plaintext;
26845
+ try {
26846
+ plaintext = await open7(sealed, parsed.key32);
26847
+ } catch {
26848
+ throw new ShareReceiveError("decrypt-failed", "legacy envelope could not be opened");
26849
+ }
26850
+ let envelope;
26851
+ try {
26852
+ const encoded = new TextDecoder("utf-8", { fatal: true }).decode(plaintext);
26853
+ const value = JSON.parse(encoded);
26854
+ if (canonicalize3(value) !== encoded) throw new Error("non-canonical envelope");
26855
+ envelope = shareEnvelopeV2Schema2.parse(value);
26856
+ } catch {
26857
+ throw new ShareReceiveError("envelope-invalid", "legacy envelope is invalid");
26858
+ }
26859
+ return { envelope, origin: origin2, cid: parsed.ciphertextCid };
26860
+ } finally {
26861
+ parsed.key32.fill(0);
26862
+ }
26863
+ }
26864
+ function evidenceMatchesV2(envelope, evidence) {
26865
+ const actions = new Set(evidence.actions.map((action) => action === "read" ? "tinycloud.kv/get" : action === "list" ? "tinycloud.kv/list" : action === "edit" ? "tinycloud.kv/put" : action));
26866
+ const resourceCovers = evidence.resource.kind === "exact" ? envelope.resource.kind === "exact" && evidence.resource.path === envelope.resource.path : envelope.resource.path === evidence.resource.path || envelope.resource.path.startsWith(evidence.resource.path.endsWith("/") ? evidence.resource.path : `${evidence.resource.path}/`);
26867
+ return envelope.authorizationTarget.kind === "policy" && evidence.policyCid === envelope.authorizationTarget.policyCid && evidence.signerDid === envelope.signature.signerDid && evidence.registrationCid.length > 0 && evidence.shareId === envelope.shareId && canonicalize3(evidence.recipientMatcher) === canonicalize3(envelope.recipientMatcher) && canonicalize3(evidence.target) === canonicalize3(envelope.target) && resourceCovers && envelope.actions.every((action) => actions.has(action === "read" ? "tinycloud.kv/get" : action === "list" ? "tinycloud.kv/list" : "tinycloud.kv/put")) && canonicalize3(evidence.contentSource) === canonicalize3(envelope.contentSource) && evidence.contentSourceDigest === envelope.contentSourceDigest && evidence.delegationCid === envelope.delegationCid && evidence.authorityMaterialHandle === envelope.authorityMaterialHandle && evidence.authorityMaterialDigest === envelope.authorityMaterialDigest && evidence.expiresAt === envelope.expiry && Number.isFinite(Date.parse(evidence.expiresAt)) && Date.parse(evidence.expiresAt) === Date.parse(envelope.expiry);
26868
+ }
26869
+ async function verifyLegacyV2(envelope, options) {
26870
+ try {
26871
+ if (!await verifyEnvelopeV2(envelope, { expectedSignerDid: envelope.signature.signerDid })) throw new Error("signature");
26872
+ } catch {
26873
+ throw new ShareReceiveError("signature-invalid", "legacy envelope signature is invalid");
26874
+ }
26875
+ const expiry = Date.parse(envelope.expiry);
26876
+ if (!Number.isFinite(expiry)) throw new ShareReceiveError("envelope-invalid", "legacy share expiry is invalid");
26877
+ if (expiry <= (options.now?.() ?? Date.now())) throw new ShareReceiveError("expired", "legacy share has expired", { expiresAt: envelope.expiry });
26878
+ if (envelope.authorizationTarget.kind === "policy") {
26879
+ if (options.trustedPolicyAuthority === void 0) throw new ShareReceiveError("envelope-invalid", "a legacy policy authority is required");
26880
+ let evidence;
26881
+ try {
26882
+ evidence = await options.trustedPolicyAuthority.resolve({ policyCid: envelope.authorizationTarget.policyCid, envelope });
26883
+ } catch {
26884
+ }
26885
+ if (evidence === void 0 || !evidenceMatchesV2(envelope, evidence)) throw new ShareReceiveError("capability-invalid", "legacy policy evidence does not match");
26886
+ if (options.trustedSignerDid !== void 0 && options.trustedSignerDid !== evidence.signerDid) throw new ShareReceiveError("signature-invalid", "legacy signer is not trusted");
26887
+ } else if (options.trustedSignerDid === void 0 || options.trustedSignerDid !== envelope.signature.signerDid || envelope.authorizationTarget.kind === "recipientDid" && envelope.recipientMatcher.kind === "recipientDid" && envelope.authorizationTarget.did !== envelope.recipientMatcher.value) {
26888
+ throw new ShareReceiveError("capability-invalid", "legacy recipient authority does not match");
26889
+ }
26890
+ }
25253
26891
  async function inspectShare(link4, options = {}) {
26892
+ if (isLegacyV2Link(link4)) {
26893
+ const legacy = await resolveLegacyV2(link4, options);
26894
+ await verifyLegacyV2(legacy.envelope, options);
26895
+ options.onResolvedAddressedEnvelope?.(legacy.envelope, legacy.cid);
26896
+ return { metadata: metadataFor(legacy.envelope, legacy.origin), link: { origin: legacy.origin, cid: legacy.cid, kind: "compact" } };
26897
+ }
25254
26898
  const resolved = await resolvePolicyShare(link4, options);
25255
26899
  return { metadata: metadataFor(resolved.envelope, resolved.origin), link: { origin: resolved.origin, cid: resolved.cid, kind: "policy" } };
25256
26900
  }
25257
26901
  async function receiveShare(link4, options = {}) {
26902
+ if (isLegacyV2Link(link4)) return receiveLegacyV2(link4, options);
25258
26903
  const resolved = await resolvePolicyShare(link4, options);
25259
26904
  return { state: "authorization-required", method: resolved.envelope.recipientMatcher.kind === "recipientDid" ? "openkey-device" : "email-claim" };
25260
26905
  }
26906
+ function isLegacyV2Link(link4) {
26907
+ try {
26908
+ const url = new URL(link4);
26909
+ return /^\/s\/bafkrei[a-z2-7]{52}$/.test(url.pathname) && url.hash.startsWith("#k=");
26910
+ } catch {
26911
+ return false;
26912
+ }
26913
+ }
26914
+ async function receiveLegacyV2(link4, options) {
26915
+ const resolved = await resolveLegacyV2(link4, options);
26916
+ const { envelope } = resolved;
26917
+ await verifyLegacyV2(envelope, options);
26918
+ options.onResolvedAddressedEnvelope?.(envelope, resolved.cid);
26919
+ const method = envelope.recipientMatcher.kind === "recipientDid" ? "openkey-device" : "email-claim";
26920
+ if (options.authorization === void 0) return { state: "authorization-required", method };
26921
+ const result = options.authorizationResumeToken === void 0 ? await options.authorization.begin({ envelope, method }) : await options.authorization.resume({
26922
+ envelope,
26923
+ method,
26924
+ resumeToken: options.authorizationResumeToken,
26925
+ ...options.authorizationProof === void 0 ? {} : { proof: options.authorizationProof }
26926
+ });
26927
+ if (result.state === "authorization-required") return result;
26928
+ if (result.state === "denied") throw new ShareReceiveError("authorization-denied", "legacy share authorization was denied");
26929
+ if (result.value === null || typeof result.value !== "object" || !(result.value.bytes instanceof Uint8Array) || result.value.proof === void 0 || options.authorization.verifyResult === void 0) {
26930
+ throw new ShareReceiveError("content-integrity-failed", "legacy content lacks a verifiable proof");
26931
+ }
26932
+ const authorized = result.value;
26933
+ try {
26934
+ if (!await options.authorization.verifyResult({ envelope, value: authorized, proof: authorized.proof })) throw new Error("proof");
26935
+ } catch {
26936
+ throw new ShareReceiveError("content-integrity-failed", "legacy content proof is invalid");
26937
+ }
26938
+ const bytes3 = authorized.bytes.slice();
26939
+ if (bytes3.length > (options.maxContentBlobBytes ?? DEFAULT_MAX_CONTENT_BLOB_BYTES)) throw new ShareReceiveError("max-bytes-exceeded", "legacy content exceeds the size limit");
26940
+ const bodyDigest = toBase64Url2(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes3)));
26941
+ if (authorized.bodyDigest !== bodyDigest || authorized.contentSourceDigest !== envelope.contentSourceDigest || authorized.binding.shareId !== envelope.shareId || authorized.binding.delegationCid !== envelope.delegationCid || authorized.binding.authorityMaterialHandle !== envelope.authorityMaterialHandle || authorized.binding.authorityMaterialDigest !== envelope.authorityMaterialDigest || authorized.binding.resource.kind !== envelope.resource.kind || authorized.binding.resource.path !== envelope.resource.path || authorized.binding.action !== void 0 && !envelope.actions.some((action) => action === authorized.binding.action || `tinycloud.kv/${action}` === authorized.binding.action) || envelope.metadata.byteLength !== void 0 && envelope.metadata.byteLength !== bytes3.length) {
26942
+ throw new ShareReceiveError("content-integrity-failed", "legacy content binding does not match");
26943
+ }
26944
+ let text;
26945
+ try {
26946
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes3);
26947
+ } catch {
26948
+ }
26949
+ return { metadata: metadataFor(envelope, resolved.origin), link: { origin: resolved.origin, cid: resolved.cid, kind: "compact" }, bytes: bytes3, ...text === void 0 ? {} : { text } };
26950
+ }
25261
26951
  var SHARE_CONTENT_LIMIT = 100 * 1024 * 1024;
25262
26952
  var SHARE_PUBLISH_RESULT_VERSION = 1;
25263
26953
  var DEFAULT_SHARE_LIFETIME_MS = 7 * 24 * 60 * 60 * 1e3;
@@ -25745,7 +27435,10 @@ async function publishTargetShare(input) {
25745
27435
  expiresAt,
25746
27436
  expiryWasExplicit: input.expiryWasExplicit ?? input.expiresAt !== void 0,
25747
27437
  origin: input.origin,
25748
- ...input.notify === void 0 ? {} : { notify: input.notify }
27438
+ ...input.notify === void 0 ? {} : { notify: input.notify },
27439
+ ...input.credentialDescriptor === void 0 ? {} : { credentialDescriptor: input.credentialDescriptor },
27440
+ ...input.issuerDid === void 0 ? {} : { issuerDid: input.issuerDid },
27441
+ ...input.issuerKid === void 0 ? {} : { issuerKid: input.issuerKid }
25749
27442
  });
25750
27443
  }
25751
27444
  var POLICY_V1_DOMAIN = "xyz.tinycloud.policy/policy/v1\0";
@@ -25831,7 +27524,7 @@ async function createPolicy(options, capabilities) {
25831
27524
  function addressedPlan(options) {
25832
27525
  const capabilities = sortCanonical([
25833
27526
  { kind: "kv", resource: options.contentSource.kvResource, selector: options.resource.kind, actions: [...options.policyActions] },
25834
- { kind: "encryption", resource: options.contentSource.encryptionNetwork, action: "tinycloud.encryption/decrypt" }
27527
+ { kind: "encryption", resource: options.contentSource.encryptionKeyPath === void 0 ? options.contentSource.encryptionNetwork : `${options.contentSource.encryptionNetwork}/${options.contentSource.encryptionKeyPath}`, action: "tinycloud.encryption/decrypt" }
25835
27528
  ]);
25836
27529
  return {
25837
27530
  expiry: rfc3339Seconds(options.expiresAt),
@@ -26156,6 +27849,7 @@ async function addressedShareBodyUpperBound(input) {
26156
27849
  kvResource: `${input.spaceId}/kv/${path}`,
26157
27850
  selector: input.resource.kind,
26158
27851
  encryptionNetwork: input.encryptionNetwork,
27852
+ ...input.encryptionKeyPath === void 0 ? {} : { encryptionKeyPath: input.encryptionKeyPath },
26159
27853
  encryptedSymmetricKeyDigestHex: "f".repeat(64),
26160
27854
  keyVersion: Number.MAX_SAFE_INTEGER,
26161
27855
  mode: "immutable",
@@ -26875,9 +28569,9 @@ async function validateReceipt(receipt, shareUrl) {
26875
28569
  }
26876
28570
  const links = await Promise.resolve().then(() => (init_links(), links_exports));
26877
28571
  try {
26878
- const origin = new URL(shareUrl).origin;
26879
- const parsed = links.parseLink(shareUrl, { trustedOrigins: [origin] });
26880
- if (parsed.form !== "short" || parsed.pathType !== "share" || shareUrl.length > MAX_INVITATION_LINK_BYTES || shareUrl !== links.buildShortLink({ origin, type: "share", id: parsed.id, key: parsed.key, bodyCid: parsed.c })) {
28572
+ const origin2 = new URL(shareUrl).origin;
28573
+ const parsed = links.parseLink(shareUrl, { trustedOrigins: [origin2] });
28574
+ if (parsed.form !== "short" || parsed.pathType !== "share" || shareUrl.length > MAX_INVITATION_LINK_BYTES || shareUrl !== links.buildShortLink({ origin: origin2, type: "share", id: parsed.id, key: parsed.key, bodyCid: parsed.c })) {
26881
28575
  throw new Error("not a short share link");
26882
28576
  }
26883
28577
  } catch {
@@ -28200,6 +29894,23 @@ var unifiedEncryptionNetworkSchema3 = external_exports2.string().refine((value)
28200
29894
  const network = separator < 0 ? "" : rest.slice(separator + 1);
28201
29895
  return owner.startsWith("did:") && owner.length > 4 && network.length > 0 && !/[:/%?#\s]/.test(network);
28202
29896
  }, { message: "expected canonical TinyCloud encryption network" });
29897
+ var unifiedEncryptionResourceSchema3 = external_exports2.string().refine((value) => {
29898
+ const prefix = "urn:tinycloud:encryption:";
29899
+ if (!value.startsWith(prefix)) return false;
29900
+ const match = /^(did:.+):([^/:?#\s]+)(?:\/(.+))?$/.exec(value.slice(prefix.length));
29901
+ if (match === null) return false;
29902
+ const path = match[3];
29903
+ return path === void 0 || path.split("/").every(
29904
+ (segment) => segment.length > 0 && segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment)
29905
+ );
29906
+ }, { message: "expected a canonical TinyCloud encryption resource" });
29907
+ var unifiedEncryptionKeyPathSchema3 = external_exports2.string().regex(/^share\/[^/]+$/).refine(
29908
+ (value) => {
29909
+ const segment = value.slice("share/".length);
29910
+ return segment !== "." && segment !== ".." && !/[\\:%?#\s]/.test(segment);
29911
+ },
29912
+ { message: "expected an exact share key path" }
29913
+ );
28203
29914
  var unifiedKvCapabilitySchema3 = external_exports2.object({
28204
29915
  kind: external_exports2.literal("kv"),
28205
29916
  resource: unifiedResourceSchema3,
@@ -28213,7 +29924,7 @@ var unifiedKvCapabilitySchema3 = external_exports2.object({
28213
29924
  }).strict();
28214
29925
  var unifiedEncryptionCapabilitySchema3 = external_exports2.object({
28215
29926
  kind: external_exports2.literal("encryption"),
28216
- resource: unifiedEncryptionNetworkSchema3,
29927
+ resource: unifiedEncryptionResourceSchema3,
28217
29928
  action: external_exports2.literal("tinycloud.encryption/decrypt")
28218
29929
  }).strict();
28219
29930
  var unifiedCapabilitySchema3 = external_exports2.union([unifiedKvCapabilitySchema3, unifiedEncryptionCapabilitySchema3]);
@@ -28222,6 +29933,7 @@ var unifiedContentSourceSchema3 = external_exports2.object({
28222
29933
  kvResource: unifiedResourceSchema3,
28223
29934
  selector: external_exports2.union([external_exports2.literal("exact"), external_exports2.literal("prefix")]),
28224
29935
  encryptionNetwork: unifiedEncryptionNetworkSchema3,
29936
+ encryptionKeyPath: unifiedEncryptionKeyPathSchema3.optional(),
28225
29937
  encryptedSymmetricKeyDigestHex: external_exports2.string().regex(/^[0-9a-f]{64}$/),
28226
29938
  keyVersion: external_exports2.number().int().positive(),
28227
29939
  mode: external_exports2.union([external_exports2.literal("mutable"), external_exports2.literal("immutable")]),
@@ -28339,16 +30051,21 @@ function validateV3Invariants3(value, ctx) {
28339
30051
  if (value.attestedEnforcerBinding.nodeAudience !== value.target.nodeAudience || value.attestedEnforcerBinding.signature.signerDid !== value.attestedEnforcerBinding.nodeAudience || Date.parse(value.attestedEnforcerBinding.expiresAt) < Date.parse(value.expiry)) {
28340
30052
  ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["attestedEnforcerBinding"], message: "enforcer binding does not cover the target and share lifetime" });
28341
30053
  }
28342
- if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
30054
+ const encryptionKeyPath = value.contentSource.encryptionKeyPath;
30055
+ if (encryptionKeyPath !== void 0 && encryptionKeyPath !== `share/${value.contentSource.shareId}`) {
30056
+ ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource", "encryptionKeyPath"], message: "share key path must name this share" });
30057
+ }
30058
+ if (value.policy.contentSource.shareId !== value.contentSource.shareId || value.policy.contentSource.kvResource !== value.contentSource.kvResource || value.policy.contentSource.selector !== value.contentSource.selector || value.policy.contentSource.encryptionNetwork !== value.encryptionNetwork || value.policy.contentSource.encryptionKeyPath !== encryptionKeyPath || value.policy.contentSource.encryptedSymmetricKeyDigestHex !== value.contentSource.encryptedSymmetricKeyDigestHex || value.policy.contentSource.keyVersion !== value.contentSource.keyVersion || value.policy.contentSource.mode !== value.contentSource.mode || value.policy.contentSource.initialCiphertextDigestHex !== value.contentSource.initialCiphertextDigestHex) {
28343
30059
  ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["contentSource"], message: "content source is not bound to policy" });
28344
30060
  }
28345
30061
  if (value.policy.signature.suite !== "Ed25519" || value.policy.signature.signerDid !== value.policy.ownerDid) {
28346
30062
  ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "signature"], message: "policy must be signed by its owner" });
28347
30063
  }
28348
30064
  const kvCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "kv");
28349
- const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === value.encryptionNetwork && capability.action === "tinycloud.encryption/decrypt");
30065
+ const expectedEncryptionResource = encryptionKeyPath === void 0 ? value.encryptionNetwork : `${value.encryptionNetwork}/${encryptionKeyPath}`;
30066
+ const decryptCapabilities = value.policy.capabilityCeiling.filter((capability) => capability.kind === "encryption" && capability.resource === expectedEncryptionResource && capability.action === "tinycloud.encryption/decrypt");
28350
30067
  if (value.policy.capabilityCeiling.length !== 2 || kvCapabilities.length !== 1 || decryptCapabilities.length !== 1 || kvCapabilities[0]?.resource !== value.contentSource.kvResource || kvCapabilities[0]?.selector !== value.contentSource.selector) {
28351
- ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain exact decrypt network" });
30068
+ ctx.addIssue({ code: external_exports2.ZodIssueCode.custom, path: ["policy", "capabilityCeiling"], message: "policy ceiling must contain the exact decrypt resource" });
28352
30069
  }
28353
30070
  }
28354
30071
  var unsignedShareEnvelopeV3Schema3 = unsignedShareEnvelopeV3BaseSchema3.superRefine(validateV3Invariants3);
@@ -28555,7 +30272,7 @@ function receiveJson(result, path) {
28555
30272
 
28556
30273
  // src/share/io.ts
28557
30274
  import { constants } from "fs";
28558
- import { lstat as lstat6, mkdir as mkdir4, mkdtemp, open as open7, readFile as readFile6, realpath as realpath2, stat as stat4, link as link2, rename as rename3, rm as rm5, unlink as unlink4 } from "fs/promises";
30275
+ import { lstat as lstat6, mkdir as mkdir4, mkdtemp, open as open8, readFile as readFile6, realpath as realpath2, stat as stat4, link as link2, rename as rename3, rm as rm6, unlink as unlink4 } from "fs/promises";
28559
30276
  import { randomBytes as randomBytes3 } from "crypto";
28560
30277
  import { basename as basename2, join as join11, resolve as resolve4, sep as sep3 } from "path";
28561
30278
  init_errors();
@@ -28631,7 +30348,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
28631
30348
  const outputDirectory = resolve4(directory);
28632
30349
  await assertDirectory(outputDirectory);
28633
30350
  const safeName = safeFilename(filename);
28634
- const directoryHandle = await open7(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
30351
+ const directoryHandle = await open8(outputDirectory, constants.O_RDONLY | (constants.O_DIRECTORY ?? 0) | (constants.O_NOFOLLOW ?? 0));
28635
30352
  const stableDirectory = await realpath2(outputDirectory);
28636
30353
  const outputPath = join11(stableDirectory, safeName);
28637
30354
  const directoryIdentity = await directoryHandle.stat();
@@ -28655,7 +30372,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
28655
30372
  if (error.code !== "ENOENT") throw error;
28656
30373
  }
28657
30374
  temporaryPath = stagingPath;
28658
- handle = await open7(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
30375
+ handle = await open8(temporaryPath, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (constants.O_NOFOLLOW ?? 0), 384);
28659
30376
  await handle.writeFile(bytes);
28660
30377
  await handle.close();
28661
30378
  handle = void 0;
@@ -28677,7 +30394,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
28677
30394
  if (temporaryPath !== void 0) await unlink4(temporaryPath);
28678
30395
  } catch {
28679
30396
  }
28680
- await rm5(stagingDirectory, { recursive: true, force: true });
30397
+ await rm6(stagingDirectory, { recursive: true, force: true });
28681
30398
  await directoryHandle.close();
28682
30399
  }
28683
30400
  return join11(outputDirectory, safeName);
@@ -28805,6 +30522,38 @@ function createShareLinks(input) {
28805
30522
  };
28806
30523
  }
28807
30524
 
30525
+ // src/share/email-publish-v3.ts
30526
+ import {
30527
+ canonicalDigest,
30528
+ createEmailCredentialRequirement,
30529
+ credentialRequirementDigest,
30530
+ validateCredentialFlowDescriptor
30531
+ } from "@tinycloud/sdk-core";
30532
+ async function publishEmailShareV3(input) {
30533
+ const { contentSource } = input;
30534
+ if (input.resource.kind !== "exact" || contentSource.encryptionKeyPath !== `share/${input.shareId}` || !/^urn:tinycloud:encryption:did:pkh:eip155:\d+:0x[0-9a-fA-F]{40}:default$/.test(contentSource.encryptionNetwork)) {
30535
+ throw new TypeError("email share binding is invalid");
30536
+ }
30537
+ const descriptor = validateCredentialFlowDescriptor(input.credentialDescriptor);
30538
+ if (descriptor.issuer.did !== input.issuerDid || descriptor.issuer.kid !== input.issuerKid || !descriptor.claims.some((claim) => claim.name === "email" && claim.matching === "normalized_exact")) {
30539
+ throw new TypeError("email credential issuer or claim is invalid");
30540
+ }
30541
+ const profile = { id: descriptor.profile, version: 1 };
30542
+ const credentialType = { id: descriptor.format.vct, version: 1 };
30543
+ const requirement = createEmailCredentialRequirement({ email: input.target.address, profile, credentialType });
30544
+ const credentialRequirement = {
30545
+ type: "TinyCloudPolicyCredentialRequirement",
30546
+ version: 1,
30547
+ requirementDigest: await credentialRequirementDigest(requirement),
30548
+ descriptorDigest: await canonicalDigest(descriptor),
30549
+ issuerDid: input.issuerDid,
30550
+ issuerKid: input.issuerKid,
30551
+ profile,
30552
+ credentialType
30553
+ };
30554
+ return publishAddressedShare({ ...input, credentialRequirement });
30555
+ }
30556
+
28808
30557
  // src/share/errors.ts
28809
30558
  var SharePublishAuthorityError = class extends Error {
28810
30559
  constructor(failure, options) {
@@ -28866,7 +30615,7 @@ init_profiles();
28866
30615
  init_constants();
28867
30616
  init_errors();
28868
30617
  init_session_expired();
28869
- import { chmod as chmod4, link as link3, open as open8, readFile as readFile7, stat as stat5, unlink as unlink5 } from "fs/promises";
30618
+ import { chmod as chmod4, link as link3, open as open9, readFile as readFile7, stat as stat5, unlink as unlink5 } from "fs/promises";
28870
30619
  import { dirname as dirname5, join as join12 } from "path";
28871
30620
  import { createHash } from "crypto";
28872
30621
  import { writeJsonAtomic as writeJsonAtomic2 } from "@tinycloud/operations/state";
@@ -29223,7 +30972,7 @@ function createEncryptedProfileHistory(profileName, sessionSigner) {
29223
30972
  await link3(found.file, target);
29224
30973
  await chmod4(target, PRIVATE_HISTORY_MODE);
29225
30974
  await unlink5(found.file);
29226
- const directory = await open8(dirname5(found.file), "r");
30975
+ const directory = await open9(dirname5(found.file), "r");
29227
30976
  try {
29228
30977
  await directory.sync();
29229
30978
  } finally {
@@ -29271,7 +31020,7 @@ function quarantineUnreadableProfileHistory(profileName) {
29271
31020
  return createEncryptedProfileHistory(async () => profileName, signShareHistoryBytes).quarantineUnreadable();
29272
31021
  }
29273
31022
  function createShareAuthorityAdapters(input = {}) {
29274
- const origin = input.origin ?? DEFAULT_SHARE_ORIGIN;
31023
+ const origin2 = input.origin ?? DEFAULT_SHARE_ORIGIN;
29275
31024
  const fetchFn = input.fetchFn ?? globalThis.fetch;
29276
31025
  let selectedProfile;
29277
31026
  const profileName = () => selectedProfile ??= input.profileName?.() ?? selectedProfileName();
@@ -29286,7 +31035,7 @@ function createShareAuthorityAdapters(input = {}) {
29286
31035
  const publicConfig = async () => configPromise ??= (async () => {
29287
31036
  let response;
29288
31037
  try {
29289
- response = await fetchFn(`${origin}/.well-known/tinycloud-share/config.json`, {
31038
+ response = await fetchFn(`${origin2}/.well-known/tinycloud-share/config.json`, {
29290
31039
  headers: { accept: "application/json" },
29291
31040
  credentials: "omit",
29292
31041
  redirect: "error",
@@ -29294,9 +31043,9 @@ function createShareAuthorityAdapters(input = {}) {
29294
31043
  signal: AbortSignal.timeout(1e4)
29295
31044
  });
29296
31045
  } catch (error) {
29297
- throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin }, { cause: error });
31046
+ throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin: origin2 }, { cause: error });
29298
31047
  }
29299
- if (!response.ok) throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin });
31048
+ if (!response.ok) throw new SharePublishAuthorityError({ kind: "share-service-unavailable", origin: origin2 });
29300
31049
  const value = await response.json();
29301
31050
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("share public config is invalid");
29302
31051
  const object3 = value;
@@ -29380,6 +31129,8 @@ function createShareAuthorityAdapters(input = {}) {
29380
31129
  });
29381
31130
  const targetAdapter = { async publish(targetInput) {
29382
31131
  if (input.publishTarget !== void 0) return input.publishTarget(targetInput);
31132
+ const refusedKind = { emailDomain: "domain", recipientDid: "did" }[targetInput.target.kind];
31133
+ if (refusedKind !== void 0) throw new CLIError("UNAVAILABLE", `${refusedKind}-addressed shares are not available in this release; nothing was shared`, 4);
29383
31134
  const node = await authenticatedNode();
29384
31135
  const session = node.restorableSession;
29385
31136
  const ownerSpaceId = session?.spaceId;
@@ -29426,8 +31177,15 @@ function createShareAuthorityAdapters(input = {}) {
29426
31177
  profileName: activeProfileName2
29427
31178
  });
29428
31179
  }
29429
- const addressedEncryptionNetwork = targetInput.target.kind === "bearer" ? void 0 : node.getEncryptionNetworkIdForSpace(ownerSpaceId);
29430
- if (addressedEncryptionNetwork !== void 0 && node.isSessionOnly && !sessionHoldsEncryptionDecrypt(node, addressedEncryptionNetwork)) {
31180
+ if (targetInput.target.kind === "email" && (targetInput.credentialDescriptor === void 0 || targetInput.issuerDid === void 0 || targetInput.issuerKid === void 0)) {
31181
+ throw new TypeError("email credential descriptor and issuer are required");
31182
+ }
31183
+ const addressedEncryptionNetwork = targetInput.target.kind === "bearer" ? void 0 : targetInput.target.kind === "email" ? node.getDefaultEncryptionNetworkId() : node.getEncryptionNetworkIdForSpace(ownerSpaceId);
31184
+ const emailKeyPath = targetInput.target.kind === "email" ? `share/${crypto.randomUUID().replaceAll("-", "")}` : void 0;
31185
+ if (addressedEncryptionNetwork !== void 0 && node.isSessionOnly && !sessionHoldsEncryptionDecrypt(
31186
+ node,
31187
+ emailKeyPath === void 0 ? addressedEncryptionNetwork : `${addressedEncryptionNetwork}/${emailKeyPath}`
31188
+ )) {
29431
31189
  throw new SharePublishAuthorityError({ kind: "decrypt-not-held" });
29432
31190
  }
29433
31191
  const config = await publicConfig();
@@ -29436,7 +31194,7 @@ function createShareAuthorityAdapters(input = {}) {
29436
31194
  if (targetInput.notify === true && targetInput.target.kind === "emailDomain") {
29437
31195
  await assertDomainDeliveryForOrigin(activeNode.origin, "publish");
29438
31196
  }
29439
- const shareId = crypto.randomUUID().replaceAll("-", "");
31197
+ const shareId = emailKeyPath?.slice("share/".length) ?? crypto.randomUUID().replaceAll("-", "");
29440
31198
  const files = targetInput.files === void 0 || targetInput.files.length === 0 ? [{ bytes: targetInput.source, filename: targetInput.filename, mediaType: targetInput.mediaType }] : targetInput.files;
29441
31199
  const resourceKind = targetInput.resourceKind ?? "exact";
29442
31200
  if (targetInput.target.kind === "bearer") {
@@ -29558,6 +31316,7 @@ function createShareAuthorityAdapters(input = {}) {
29558
31316
  resource: { kind: resourceKind },
29559
31317
  storage: artifact === void 0 ? { path: resourcePath } : { artifactId: artifact.id, storageName },
29560
31318
  encryptionNetwork: addressedEncryptionNetwork,
31319
+ ...emailKeyPath === void 0 ? {} : { encryptionKeyPath: emailKeyPath },
29561
31320
  actions,
29562
31321
  policyActions,
29563
31322
  ...deliveryEmail === void 0 ? {} : { deliveryEmail },
@@ -29573,8 +31332,14 @@ function createShareAuthorityAdapters(input = {}) {
29573
31332
  throw new SharePublishAuthorityError({ kind: rejected ? "registry-rejected" : "registry-unavailable" });
29574
31333
  }
29575
31334
  const encryptionNetwork = addressedEncryptionNetwork;
29576
- const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, { metadata: { contentType: mediaType } });
31335
+ const encrypted = await node.encryption.encryptToNetwork(encryptionNetwork, file.bytes, {
31336
+ ...emailKeyPath === void 0 ? {} : { keyPath: emailKeyPath },
31337
+ metadata: { contentType: mediaType }
31338
+ });
29577
31339
  if (!encrypted.ok) throw new Error("addressed source encryption was rejected");
31340
+ if (emailKeyPath !== void 0 && (encrypted.data.networkId !== encryptionNetwork || encrypted.data.keyPath !== emailKeyPath)) {
31341
+ throw new Error("email share encryption was rejected");
31342
+ }
29578
31343
  const storedBytes = new TextEncoder().encode(canonicalize4(encrypted.data));
29579
31344
  let artifactVersion;
29580
31345
  if (artifact !== void 0) {
@@ -29607,6 +31372,7 @@ function createShareAuthorityAdapters(input = {}) {
29607
31372
  kvResource: `${ownerSpaceId}/kv/${resourcePath}`,
29608
31373
  selector: resourceKind,
29609
31374
  encryptionNetwork: encrypted.data.networkId,
31375
+ ...emailKeyPath === void 0 ? {} : { encryptionKeyPath: emailKeyPath },
29610
31376
  encryptedSymmetricKeyDigestHex: encrypted.data.encryptedSymmetricKeyHash,
29611
31377
  keyVersion: encrypted.data.keyVersion,
29612
31378
  mode: "immutable",
@@ -29648,7 +31414,13 @@ function createShareAuthorityAdapters(input = {}) {
29648
31414
  };
29649
31415
  let published;
29650
31416
  try {
29651
- published = await publishAddressedShare(addressedOptions);
31417
+ published = prepared.target.kind === "email" ? await publishEmailShareV3({
31418
+ ...addressedOptions,
31419
+ target: prepared.target,
31420
+ credentialDescriptor: targetInput.credentialDescriptor,
31421
+ issuerDid: targetInput.issuerDid,
31422
+ issuerKid: targetInput.issuerKid
31423
+ }) : await publishAddressedShare(addressedOptions);
29652
31424
  } catch (error) {
29653
31425
  if (!(error instanceof AddressedShareOverLimitError)) throw error;
29654
31426
  const remaining = await removeOverLimitShare({
@@ -29841,7 +31613,7 @@ init_profiles();
29841
31613
 
29842
31614
  // src/share/html-folder.ts
29843
31615
  import { constants as constants2, existsSync } from "fs";
29844
- import { lstat as lstat7, open as open9, readdir as readdir6, realpath as realpath3, stat as stat6 } from "fs/promises";
31616
+ import { lstat as lstat7, open as open10, readdir as readdir6, realpath as realpath3, stat as stat6 } from "fs/promises";
29845
31617
  import { basename as basename3, dirname as dirname6, isAbsolute, join as join13, relative as relativePath, resolve as resolve5, sep as sep4 } from "path";
29846
31618
 
29847
31619
  // ../share-sdk/dist/html-bundle.js
@@ -30196,9 +31968,9 @@ function scanMarkup(html, options) {
30196
31968
  if (comments > MAX_ARTIFACT_COMMENTS) fail("limit", "artifact page has too many comments");
30197
31969
  };
30198
31970
  while (index < length5) {
30199
- const open10 = html.indexOf("<", index);
30200
- if (open10 === -1) return;
30201
- index = open10 + 1;
31971
+ const open11 = html.indexOf("<", index);
31972
+ if (open11 === -1) return;
31973
+ index = open11 + 1;
30202
31974
  const next = html[index] ?? "";
30203
31975
  if (html.startsWith("!--", index)) {
30204
31976
  countComment();
@@ -30799,7 +32571,7 @@ async function readRegularFile(root, path, relative, remaining, limit, hooks = {
30799
32571
  await hooks.beforeOpen?.();
30800
32572
  before = await lstat7(path);
30801
32573
  await hooks.afterLstat?.();
30802
- handle = await open9(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0) | (constants2.O_NONBLOCK ?? 0));
32574
+ handle = await open10(path, constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0) | (constants2.O_NONBLOCK ?? 0));
30803
32575
  } catch (error) {
30804
32576
  if (error.code === "ELOOP") return problem("symbolic link");
30805
32577
  if (isRaceError(error)) return problem(CHANGED);
@@ -30858,7 +32630,7 @@ async function listFolderDirectory(root, absolute, relative, hooks = {}) {
30858
32630
  if (before.isSymbolicLink()) return problem("symbolic link");
30859
32631
  if (!before.isDirectory()) return problem(CHANGED);
30860
32632
  await hooks.afterLstat?.();
30861
- const handle = await open9(absolute, constants2.O_RDONLY | (constants2.O_DIRECTORY ?? 0) | (constants2.O_NOFOLLOW ?? 0));
32633
+ const handle = await open10(absolute, constants2.O_RDONLY | (constants2.O_DIRECTORY ?? 0) | (constants2.O_NOFOLLOW ?? 0));
30862
32634
  try {
30863
32635
  await hooks.afterOpen?.();
30864
32636
  const info = await handle.stat();
@@ -31150,12 +32922,7 @@ function shareCliError(error, operation = "publish") {
31150
32922
  return new CLIError("UPLOAD_FAILED", "share source upload failed; nothing was shared", 4);
31151
32923
  }
31152
32924
  if (failure.kind === "decrypt-not-held") {
31153
- return new CLIError(
31154
- "PERMISSION_DENIED",
31155
- "this sign-in can't create email-addressed shares: it has no permission to decrypt with the account's key. Nothing was shared.",
31156
- 5,
31157
- { hint: "Share it from https://share.tinycloud.xyz while signed in as the account owner, or ask the owner to share it. A link anyone can open works from this sign-in: --to anyone." }
31158
- );
32925
+ return new CLIError("PERMISSION_DENIED", `Email shares need a paste sign-in: run ${CLI_NAME12} auth login --paste --manifest builtin:share-publishing`, 5);
31159
32926
  }
31160
32927
  if (failure.kind === "over-limit") {
31161
32928
  return new CLIError("MAX_BYTES_EXCEEDED", ADDRESSED_SHARE_TOO_LARGE_MESSAGE, 7, { hint: `What stays behind: ${failure.remaining.join("; ")}.` });
@@ -31290,14 +33057,20 @@ function assertAggregateInputLimit(inputs, maxBytes) {
31290
33057
  }
31291
33058
  function registerShareCommand(program2) {
31292
33059
  const share = program2.command("share").description("Publish and consume TinyCloud Share links");
31293
- share.command("publish <files...>").description("Publish one or more bounded files as a Share, or a folder with an index.html as one self-contained page (anyone links only)").option("--name <filename>", "Filename for stdin input, or the published .html name of a folder").option("--to <target>", "Share target", "anyone").option("--notify", "Email an exact-email recipient, or a domain mailbox on node 1.17.3+").option("--notify-to <address>", "Mailbox to invite for --to domain:<name> --notify (node 1.17.3+)").option("--expires <duration>", "Share lifetime").option("--max-bytes <bytes>", "Bound input bytes").option("--media-type <type>", "Media type for a single input").option("--action <actions...>", "Addressed permission: read, list, or edit").option("--prefix", "Publish multiple inputs beneath one addressed prefix").option("--binary", "Allow non-UTF-8 bearer content").option("--artifact <id>", 'Publish as the next write-once version of an artifact ("new" starts one); the share is pinned to that version').addOption(new Option("--ongoing").hideHelp()).option("--note <text>", "Note stored with the artifact version").option("--json", "Print versioned redacted JSON").option("--full-link", "Print the full self-contained link instead of a short link (addressed shares)").option("--viewer-origin <origin>", "Canonical HTTPS viewer origin", SHARE_ORIGIN).action(async (files, options, command) => {
33060
+ share.command("publish <files...>").description("Publish one or more bounded files as a Share, or a folder with an index.html as one self-contained page (anyone links only)").option("--name <filename>", "Filename for stdin input, or the published .html name of a folder").option("--to <target>", "Share target", "anyone").option("--credential-descriptor <path>", "Email credential flow descriptor JSON").option("--issuer-did <did>", "Trusted email credential issuer DID").option("--issuer-kid <kid>", "Trusted email credential issuer key ID").option("--notify", "Email an exact-email recipient, or a domain mailbox on node 1.17.3+").option("--notify-to <address>", "Mailbox to invite for --to domain:<name> --notify (node 1.17.3+)").option("--expires <duration>", "Share lifetime").option("--max-bytes <bytes>", "Bound input bytes").option("--media-type <type>", "Media type for a single input").option("--action <actions...>", "Addressed permission: read, list, or edit").option("--prefix", "Publish multiple inputs beneath one addressed prefix").option("--binary", "Allow non-UTF-8 bearer content").option("--artifact <id>", 'Publish as the next write-once version of an artifact ("new" starts one); the share is pinned to that version').addOption(new Option("--ongoing").hideHelp()).option("--note <text>", "Note stored with the artifact version").option("--json", "Print versioned redacted JSON").option("--full-link", "Print the full self-contained link instead of a short link (addressed shares)").option("--viewer-origin <origin>", "Canonical HTTPS viewer origin", SHARE_ORIGIN).action(async (files, options, command) => {
31294
33061
  try {
31295
33062
  const json = jsonOutput(options, command);
31296
33063
  if (options.ongoing === true) throw new CLIError("UNSUPPORTED_TARGET", ONGOING_UNAVAILABLE, 2);
33064
+ const target = parseShareTarget(options.to);
33065
+ if (target.kind === "email") throw new CLIError("UNAVAILABLE", "email-addressed shares are not available in this release; nothing was shared", 4);
31297
33066
  const maxBytes = byteLimit(options.maxBytes);
31298
33067
  if (files.length === 0 || files.includes("-") && files.length > 1) throw new CLIError("INVALID_ARGUMENT", "stdin must be the only publish input", 2);
31299
33068
  const name = files.length === 1 ? options.name : void 0;
31300
- const target = parseShareTarget(options.to);
33069
+ const actions = requestedActions(options.action);
33070
+ if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
33071
+ if (options.credentialDescriptor || options.issuerDid || options.issuerKid) {
33072
+ throw new CLIError("INVALID_ARGUMENT", "credential options require an exact email target", 2);
33073
+ }
31301
33074
  const folder = files.length === 1 && target.kind === "bearer" && options.prefix !== true && await isDirectoryInput(files[0]);
31302
33075
  let inputs;
31303
33076
  if (folder) {
@@ -31314,19 +33087,16 @@ function registerShareCommand(program2) {
31314
33087
  inputs = await Promise.all(files.map((file) => readShareInput(file, name, maxBytes)));
31315
33088
  }
31316
33089
  assertAggregateInputLimit(inputs, maxBytes);
31317
- const actions = requestedActions(options.action);
31318
33090
  if (options.prefix && target.kind === "bearer") throw new CLIError("INVALID_ARGUMENT", "--prefix requires an addressed target", 2);
31319
33091
  if (target.kind === "bearer" && actions.includes("edit")) throw new CLIError("INVALID_ARGUMENT", `--action edit is not available with --to ${options.to}: a link can only be read; address a recipient to allow edits`, 2);
31320
33092
  if (inputs.length > 1 && target.kind === "bearer") throw new CLIError("UNSUPPORTED_LINK", "multiple files require an addressed target", 2);
31321
33093
  const artifact = artifactRequest(options, actions, inputs.length);
31322
33094
  if (inputs.length > 1 && !options.prefix) throw new CLIError("INVALID_ARGUMENT", "multiple files require --prefix", 2);
31323
- if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
31324
33095
  if (options.notifyTo !== void 0 && (options.notify !== true || target.kind !== "emailDomain")) {
31325
33096
  throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
31326
33097
  }
31327
33098
  let notifyRecipient;
31328
- if (options.notify === true && target.kind === "email") notifyRecipient = target.address;
31329
- else if (options.notify === true && target.kind === "emailDomain") {
33099
+ if (options.notify === true && target.kind === "emailDomain") {
31330
33100
  const mailbox = options.notifyTo === void 0 ? void 0 : canonicalMailbox2(options.notifyTo);
31331
33101
  if (mailbox === void 0 || mailbox.domain !== target.domain) {
31332
33102
  throw new CLIError("INVALID_ARGUMENT", "--to domain:<name> --notify requires --notify-to <email> at that exact domain (node 1.17.3+)", 2);
@@ -31473,6 +33243,7 @@ function registerShareCommand(program2) {
31473
33243
  process.exitCode = 6;
31474
33244
  return;
31475
33245
  }
33246
+ if (result.method === "email-claim") throw new CLIError("CLAIM_REQUIRED", "email-addressed shares cannot be opened with this version of the CLI yet; open the link in a web browser", 6);
31476
33247
  throw new CLIError(result.method === "openkey-device" ? "DEVICE_AUTH_REQUIRED" : "CLAIM_REQUIRED", "recipient authorization is required; resume through the configured authority adapter", 6);
31477
33248
  }
31478
33249
  if (options.stdout) {
@@ -31659,7 +33430,8 @@ configureShareCommandServices({
31659
33430
  revocation: shareAuthority.revocation,
31660
33431
  nativeReader: shareAuthority.nativeReader,
31661
33432
  artifactStore: shareAuthority.artifactStore,
31662
- links: shareAuthority.links
33433
+ links: shareAuthority.links,
33434
+ shortLinkInvitations: true
31663
33435
  });
31664
33436
  var argv = process.argv.slice(2);
31665
33437
  var globalLongOptionsWithValues = { "--profile": true, "--host": true };
@@ -31746,6 +33518,10 @@ if (argv[0] === "courier") {
31746
33518
  @noble/curves/esm/abstract/curve.js:
31747
33519
  @noble/curves/esm/abstract/edwards.js:
31748
33520
  @noble/curves/esm/ed25519.js:
33521
+ @noble/curves/esm/abstract/weierstrass.js:
33522
+ @noble/curves/esm/_shortw_utils.js:
33523
+ @noble/curves/esm/nist.js:
33524
+ @noble/curves/esm/p256.js:
31749
33525
  (*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
31750
33526
  */
31751
33527
  //# sourceMappingURL=index.js.map