@kehto/paja 0.3.7 → 0.4.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.
@@ -1697,13 +1697,13 @@ function legacyScopedKey(pubkey, dTag, aggregateHash, userKey) {
1697
1697
  }
1698
1698
  function byteLength(str) {
1699
1699
  let bytes = 0;
1700
- for (let i3 = 0; i3 < str.length; i3++) {
1701
- const c = str.charCodeAt(i3);
1700
+ for (let i4 = 0; i4 < str.length; i4++) {
1701
+ const c = str.charCodeAt(i4);
1702
1702
  if (c < 128) bytes += 1;
1703
1703
  else if (c < 2048) bytes += 2;
1704
1704
  else if (c < 55296 || c >= 57344) bytes += 3;
1705
1705
  else {
1706
- i3++;
1706
+ i4++;
1707
1707
  bytes += 4;
1708
1708
  }
1709
1709
  }
@@ -2003,13 +2003,13 @@ function createNapEnvelopeDispatcher(handlers) {
2003
2003
  }
2004
2004
  function utf8ByteLength(str) {
2005
2005
  let bytes = 0;
2006
- for (let i3 = 0; i3 < str.length; i3++) {
2007
- const c = str.charCodeAt(i3);
2006
+ for (let i4 = 0; i4 < str.length; i4++) {
2007
+ const c = str.charCodeAt(i4);
2008
2008
  if (c < 128) bytes += 1;
2009
2009
  else if (c < 2048) bytes += 2;
2010
2010
  else if (c < 55296 || c >= 57344) bytes += 3;
2011
2011
  else {
2012
- i3++;
2012
+ i4++;
2013
2013
  bytes += 4;
2014
2014
  }
2015
2015
  }
@@ -2252,8 +2252,8 @@ function bytesToHex(bytes) {
2252
2252
  }
2253
2253
  function hexToBytes(hex) {
2254
2254
  const bytes = new Uint8Array(hex.length / 2);
2255
- for (let i3 = 0; i3 < hex.length; i3 += 2) {
2256
- bytes[i3 / 2] = parseInt(hex.substring(i3, i3 + 2), 16);
2255
+ for (let i4 = 0; i4 < hex.length; i4 += 2) {
2256
+ bytes[i4 / 2] = parseInt(hex.substring(i4, i4 + 2), 16);
2257
2257
  }
2258
2258
  return bytes;
2259
2259
  }
@@ -2427,8 +2427,8 @@ function createStatePersistence() {
2427
2427
  clear(prefix) {
2428
2428
  try {
2429
2429
  const keysToRemove = [];
2430
- for (let i3 = 0; i3 < localStorage.length; i3++) {
2431
- const key = localStorage.key(i3);
2430
+ for (let i4 = 0; i4 < localStorage.length; i4++) {
2431
+ const key = localStorage.key(i4);
2432
2432
  if (key?.startsWith(prefix)) keysToRemove.push(key);
2433
2433
  }
2434
2434
  for (const key of keysToRemove) localStorage.removeItem(key);
@@ -2438,8 +2438,8 @@ function createStatePersistence() {
2438
2438
  keys(prefix) {
2439
2439
  try {
2440
2440
  const result = [];
2441
- for (let i3 = 0; i3 < localStorage.length; i3++) {
2442
- const key = localStorage.key(i3);
2441
+ for (let i4 = 0; i4 < localStorage.length; i4++) {
2442
+ const key = localStorage.key(i4);
2443
2443
  if (key?.startsWith(prefix)) result.push(key);
2444
2444
  }
2445
2445
  return result;
@@ -2450,8 +2450,8 @@ function createStatePersistence() {
2450
2450
  calculateBytes(prefix, excludeKey) {
2451
2451
  try {
2452
2452
  let total = 0;
2453
- for (let i3 = 0; i3 < localStorage.length; i3++) {
2454
- const key = localStorage.key(i3);
2453
+ for (let i4 = 0; i4 < localStorage.length; i4++) {
2454
+ const key = localStorage.key(i4);
2455
2455
  if (!key?.startsWith(prefix)) continue;
2456
2456
  if (excludeKey && key === excludeKey) continue;
2457
2457
  const value = localStorage.getItem(key) ?? "";
@@ -3503,8 +3503,8 @@ function aoutput(out, instance) {
3503
3503
  }
3504
3504
  }
3505
3505
  function clean(...arrays) {
3506
- for (let i3 = 0; i3 < arrays.length; i3++) {
3507
- arrays[i3].fill(0);
3506
+ for (let i4 = 0; i4 < arrays.length; i4++) {
3507
+ arrays[i4].fill(0);
3508
3508
  }
3509
3509
  }
3510
3510
  function createView(arr) {
@@ -3517,14 +3517,14 @@ var hasHexBuiltin = /* @__PURE__ */ (() => (
3517
3517
  // @ts-ignore
3518
3518
  typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
3519
3519
  ))();
3520
- var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i3) => i3.toString(16).padStart(2, "0"));
3520
+ var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i4) => i4.toString(16).padStart(2, "0"));
3521
3521
  function bytesToHex2(bytes) {
3522
3522
  abytes(bytes);
3523
3523
  if (hasHexBuiltin)
3524
3524
  return bytes.toHex();
3525
3525
  let hex = "";
3526
- for (let i3 = 0; i3 < bytes.length; i3++) {
3527
- hex += hexes[bytes[i3]];
3526
+ for (let i4 = 0; i4 < bytes.length; i4++) {
3527
+ hex += hexes[bytes[i4]];
3528
3528
  }
3529
3529
  return hex;
3530
3530
  }
@@ -3561,14 +3561,14 @@ function hexToBytes2(hex) {
3561
3561
  }
3562
3562
  function concatBytes(...arrays) {
3563
3563
  let sum = 0;
3564
- for (let i3 = 0; i3 < arrays.length; i3++) {
3565
- const a = arrays[i3];
3564
+ for (let i4 = 0; i4 < arrays.length; i4++) {
3565
+ const a = arrays[i4];
3566
3566
  abytes(a);
3567
3567
  sum += a.length;
3568
3568
  }
3569
3569
  const res = new Uint8Array(sum);
3570
- for (let i3 = 0, pad2 = 0; i3 < arrays.length; i3++) {
3571
- const a = arrays[i3];
3570
+ for (let i4 = 0, pad2 = 0; i4 < arrays.length; i4++) {
3571
+ const a = arrays[i4];
3572
3572
  res.set(a, pad2);
3573
3573
  pad2 += a.length;
3574
3574
  }
@@ -3651,24 +3651,24 @@ function alphabet(letters) {
3651
3651
  const lettersA = typeof letters === "string" ? letters.split("") : letters;
3652
3652
  const len = lettersA.length;
3653
3653
  astrArr("alphabet", lettersA);
3654
- const indexes = new Map(lettersA.map((l, i3) => [l, i3]));
3654
+ const indexes = new Map(lettersA.map((l, i4) => [l, i4]));
3655
3655
  return {
3656
3656
  encode: (digits) => {
3657
3657
  aArr(digits);
3658
- return digits.map((i3) => {
3659
- if (!Number.isSafeInteger(i3) || i3 < 0 || i3 >= len)
3660
- throw new Error(`alphabet.encode: digit index outside alphabet "${i3}". Allowed: ${letters}`);
3661
- return lettersA[i3];
3658
+ return digits.map((i4) => {
3659
+ if (!Number.isSafeInteger(i4) || i4 < 0 || i4 >= len)
3660
+ throw new Error(`alphabet.encode: digit index outside alphabet "${i4}". Allowed: ${letters}`);
3661
+ return lettersA[i4];
3662
3662
  });
3663
3663
  },
3664
3664
  decode: (input) => {
3665
3665
  aArr(input);
3666
3666
  return input.map((letter) => {
3667
3667
  astr("alphabet.decode", letter);
3668
- const i3 = indexes.get(letter);
3669
- if (i3 === void 0)
3668
+ const i4 = indexes.get(letter);
3669
+ if (i4 === void 0)
3670
3670
  throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
3671
- return i3;
3671
+ return i4;
3672
3672
  });
3673
3673
  }
3674
3674
  };
@@ -3717,8 +3717,8 @@ var gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
3717
3717
  var radix2carry = /* @__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
3718
3718
  var powers = /* @__PURE__ */ (() => {
3719
3719
  let res = [];
3720
- for (let i3 = 0; i3 < 40; i3++)
3721
- res.push(2 ** i3);
3720
+ for (let i4 = 0; i4 < 40; i4++)
3721
+ res.push(2 ** i4);
3722
3722
  return res;
3723
3723
  })();
3724
3724
  function convertRadix2(data, from, to, padding2) {
@@ -3810,27 +3810,27 @@ var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059
3810
3810
  function bech32Polymod(pre) {
3811
3811
  const b = pre >> 25;
3812
3812
  let chk = (pre & 33554431) << 5;
3813
- for (let i3 = 0; i3 < POLYMOD_GENERATORS.length; i3++) {
3814
- if ((b >> i3 & 1) === 1)
3815
- chk ^= POLYMOD_GENERATORS[i3];
3813
+ for (let i4 = 0; i4 < POLYMOD_GENERATORS.length; i4++) {
3814
+ if ((b >> i4 & 1) === 1)
3815
+ chk ^= POLYMOD_GENERATORS[i4];
3816
3816
  }
3817
3817
  return chk;
3818
3818
  }
3819
3819
  function bechChecksum(prefix, words, encodingConst = 1) {
3820
3820
  const len = prefix.length;
3821
3821
  let chk = 1;
3822
- for (let i3 = 0; i3 < len; i3++) {
3823
- const c = prefix.charCodeAt(i3);
3822
+ for (let i4 = 0; i4 < len; i4++) {
3823
+ const c = prefix.charCodeAt(i4);
3824
3824
  if (c < 33 || c > 126)
3825
3825
  throw new Error(`Invalid prefix (${prefix})`);
3826
3826
  chk = bech32Polymod(chk) ^ c >> 5;
3827
3827
  }
3828
3828
  chk = bech32Polymod(chk);
3829
- for (let i3 = 0; i3 < len; i3++)
3830
- chk = bech32Polymod(chk) ^ prefix.charCodeAt(i3) & 31;
3829
+ for (let i4 = 0; i4 < len; i4++)
3830
+ chk = bech32Polymod(chk) ^ prefix.charCodeAt(i4) & 31;
3831
3831
  for (let v of words)
3832
3832
  chk = bech32Polymod(chk) ^ v;
3833
- for (let i3 = 0; i3 < 6; i3++)
3833
+ for (let i4 = 0; i4 < 6; i4++)
3834
3834
  chk = bech32Polymod(chk);
3835
3835
  chk ^= encodingConst;
3836
3836
  return BECH_ALPHABET.encode(convertRadix2([chk % powers[30]], 30, 5, false));
@@ -4117,8 +4117,8 @@ var HashMD = class {
4117
4117
  this.process(view, 0);
4118
4118
  pos = 0;
4119
4119
  }
4120
- for (let i3 = pos; i3 < blockLen; i3++)
4121
- buffer[i3] = 0;
4120
+ for (let i4 = pos; i4 < blockLen; i4++)
4121
+ buffer[i4] = 0;
4122
4122
  view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE2);
4123
4123
  this.process(view, 0);
4124
4124
  const oview = createView(out);
@@ -4129,8 +4129,8 @@ var HashMD = class {
4129
4129
  const state = this.get();
4130
4130
  if (outLen > state.length)
4131
4131
  throw new Error("_sha2: outputLen bigger than state");
4132
- for (let i3 = 0; i3 < outLen; i3++)
4133
- oview.setUint32(4 * i3, state[i3], isLE2);
4132
+ for (let i4 = 0; i4 < outLen; i4++)
4133
+ oview.setUint32(4 * i4, state[i4], isLE2);
4134
4134
  }
4135
4135
  digest() {
4136
4136
  const { buffer, outputLen } = this;
@@ -4254,19 +4254,19 @@ var SHA2_32B = class extends HashMD {
4254
4254
  this.H = H | 0;
4255
4255
  }
4256
4256
  process(view, offset) {
4257
- for (let i3 = 0; i3 < 16; i3++, offset += 4)
4258
- SHA256_W[i3] = view.getUint32(offset, false);
4259
- for (let i3 = 16; i3 < 64; i3++) {
4260
- const W15 = SHA256_W[i3 - 15];
4261
- const W2 = SHA256_W[i3 - 2];
4257
+ for (let i4 = 0; i4 < 16; i4++, offset += 4)
4258
+ SHA256_W[i4] = view.getUint32(offset, false);
4259
+ for (let i4 = 16; i4 < 64; i4++) {
4260
+ const W15 = SHA256_W[i4 - 15];
4261
+ const W2 = SHA256_W[i4 - 2];
4262
4262
  const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
4263
4263
  const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
4264
- SHA256_W[i3] = s1 + SHA256_W[i3 - 7] + s0 + SHA256_W[i3 - 16] | 0;
4264
+ SHA256_W[i4] = s1 + SHA256_W[i4 - 7] + s0 + SHA256_W[i4 - 16] | 0;
4265
4265
  }
4266
4266
  let { A, B, C, D, E, F, G, H } = this;
4267
- for (let i3 = 0; i3 < 64; i3++) {
4267
+ for (let i4 = 0; i4 < 64; i4++) {
4268
4268
  const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
4269
- const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i3] + SHA256_W[i3] | 0;
4269
+ const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i4] + SHA256_W[i4] | 0;
4270
4270
  const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
4271
4271
  const T2 = sigma0 + Maj(A, B, C) | 0;
4272
4272
  H = G;
@@ -4364,10 +4364,10 @@ function copyBytes(bytes) {
4364
4364
  return Uint8Array.from(bytes);
4365
4365
  }
4366
4366
  function asciiToBytes(ascii) {
4367
- return Uint8Array.from(ascii, (c, i3) => {
4367
+ return Uint8Array.from(ascii, (c, i4) => {
4368
4368
  const charCode = c.charCodeAt(0);
4369
4369
  if (c.length !== 1 || charCode > 127) {
4370
- throw new Error(`string contains non-ASCII character "${ascii[i3]}" with code ${charCode} at position ${i3}`);
4370
+ throw new Error(`string contains non-ASCII character "${ascii[i4]}" with code ${charCode} at position ${i4}`);
4371
4371
  }
4372
4372
  return charCode;
4373
4373
  });
@@ -4399,11 +4399,11 @@ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
4399
4399
  const _maxDrbgIters = 1e3;
4400
4400
  let v = u8n(hashLen);
4401
4401
  let k = u8n(hashLen);
4402
- let i3 = 0;
4402
+ let i4 = 0;
4403
4403
  const reset = () => {
4404
4404
  v.fill(1);
4405
4405
  k.fill(0);
4406
- i3 = 0;
4406
+ i4 = 0;
4407
4407
  };
4408
4408
  const h = (...msgs) => hmacFn(k, concatBytes(v, ...msgs));
4409
4409
  const reseed = (seed = NULL) => {
@@ -4415,7 +4415,7 @@ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
4415
4415
  v = h();
4416
4416
  };
4417
4417
  const gen = () => {
4418
- if (i3++ >= _maxDrbgIters)
4418
+ if (i4++ >= _maxDrbgIters)
4419
4419
  throw new Error("drbg: tried max amount of iterations");
4420
4420
  let len = 0;
4421
4421
  const out = [];
@@ -4523,8 +4523,8 @@ function sqrt5mod8(Fp, n) {
4523
4523
  const n2 = Fp.mul(n, _2n);
4524
4524
  const v = Fp.pow(n2, p5div8);
4525
4525
  const nv = Fp.mul(n, v);
4526
- const i3 = Fp.mul(Fp.mul(nv, _2n), v);
4527
- const root = Fp.mul(nv, Fp.sub(i3, Fp.ONE));
4526
+ const i4 = Fp.mul(Fp.mul(nv, _2n), v);
4527
+ const root = Fp.mul(nv, Fp.sub(i4, Fp.ONE));
4528
4528
  assertIsSquare(Fp, root, n);
4529
4529
  return root;
4530
4530
  }
@@ -4581,17 +4581,17 @@ function tonelliShanks(P) {
4581
4581
  while (!Fp.eql(t, Fp.ONE)) {
4582
4582
  if (Fp.is0(t))
4583
4583
  return Fp.ZERO;
4584
- let i3 = 1;
4584
+ let i4 = 1;
4585
4585
  let t_tmp = Fp.sqr(t);
4586
4586
  while (!Fp.eql(t_tmp, Fp.ONE)) {
4587
- i3++;
4587
+ i4++;
4588
4588
  t_tmp = Fp.sqr(t_tmp);
4589
- if (i3 === M)
4589
+ if (i4 === M)
4590
4590
  throw new Error("Cannot find square root");
4591
4591
  }
4592
- const exponent = _1n2 << BigInt(M - i3 - 1);
4592
+ const exponent = _1n2 << BigInt(M - i4 - 1);
4593
4593
  const b = Fp.pow(c, exponent);
4594
- M = i3;
4594
+ M = i4;
4595
4595
  c = Fp.sqr(b);
4596
4596
  t = Fp.mul(t, c);
4597
4597
  R = Fp.mul(R, b);
@@ -4659,17 +4659,17 @@ function FpPow(Fp, num2, power) {
4659
4659
  }
4660
4660
  function FpInvertBatch(Fp, nums, passZero = false) {
4661
4661
  const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : void 0);
4662
- const multipliedAcc = nums.reduce((acc, num2, i3) => {
4662
+ const multipliedAcc = nums.reduce((acc, num2, i4) => {
4663
4663
  if (Fp.is0(num2))
4664
4664
  return acc;
4665
- inverted[i3] = acc;
4665
+ inverted[i4] = acc;
4666
4666
  return Fp.mul(acc, num2);
4667
4667
  }, Fp.ONE);
4668
4668
  const invertedAcc = Fp.inv(multipliedAcc);
4669
- nums.reduceRight((acc, num2, i3) => {
4669
+ nums.reduceRight((acc, num2, i4) => {
4670
4670
  if (Fp.is0(num2))
4671
4671
  return acc;
4672
- inverted[i3] = Fp.mul(acc, inverted[i3]);
4672
+ inverted[i4] = Fp.mul(acc, inverted[i4]);
4673
4673
  return Fp.mul(acc, num2);
4674
4674
  }, invertedAcc);
4675
4675
  return inverted;
@@ -4860,7 +4860,7 @@ function negateCt(condition, item) {
4860
4860
  }
4861
4861
  function normalizeZ(c, points) {
4862
4862
  const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z));
4863
- return points.map((p, i3) => c.fromAffine(p.toAffine(invertedZs[i3])));
4863
+ return points.map((p, i4) => c.fromAffine(p.toAffine(invertedZs[i4])));
4864
4864
  }
4865
4865
  function validateW(W, bits) {
4866
4866
  if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
@@ -4943,7 +4943,7 @@ var wNAF = class {
4943
4943
  for (let window2 = 0; window2 < windows; window2++) {
4944
4944
  base = p;
4945
4945
  points.push(base);
4946
- for (let i3 = 1; i3 < windowSize; i3++) {
4946
+ for (let i4 = 1; i4 < windowSize; i4++) {
4947
4947
  base = base.add(p);
4948
4948
  points.push(base);
4949
4949
  }
@@ -5077,10 +5077,10 @@ function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
5077
5077
  CURVE = Object.freeze(Object.assign({}, CURVE));
5078
5078
  return { CURVE, Fp, Fn };
5079
5079
  }
5080
- function createKeygen(randomSecretKey, getPublicKey3) {
5080
+ function createKeygen(randomSecretKey, getPublicKey4) {
5081
5081
  return function keygen(seed) {
5082
5082
  const secretKey = randomSecretKey(seed);
5083
- return { secretKey, publicKey: getPublicKey3(secretKey) };
5083
+ return { secretKey, publicKey: getPublicKey4(secretKey) };
5084
5084
  };
5085
5085
  }
5086
5086
 
@@ -5103,12 +5103,12 @@ var _HMAC = class {
5103
5103
  const blockLen = this.blockLen;
5104
5104
  const pad2 = new Uint8Array(blockLen);
5105
5105
  pad2.set(key.length > blockLen ? hash.create().update(key).digest() : key);
5106
- for (let i3 = 0; i3 < pad2.length; i3++)
5107
- pad2[i3] ^= 54;
5106
+ for (let i4 = 0; i4 < pad2.length; i4++)
5107
+ pad2[i4] ^= 54;
5108
5108
  this.iHash.update(pad2);
5109
5109
  this.oHash = hash.create();
5110
- for (let i3 = 0; i3 < pad2.length; i3++)
5111
- pad2[i3] ^= 54 ^ 92;
5110
+ for (let i4 = 0; i4 < pad2.length; i4++)
5111
+ pad2[i4] ^= 54 ^ 92;
5112
5112
  this.oHash.update(pad2);
5113
5113
  clean(pad2);
5114
5114
  }
@@ -5765,7 +5765,7 @@ function ecdh(Point, ecdhOpts = {}) {
5765
5765
  function randomSecretKey(seed = randomBytes_(lengths.seed)) {
5766
5766
  return mapHashToField(abytes(seed, lengths.seed, "seed"), Fn.ORDER);
5767
5767
  }
5768
- function getPublicKey3(secretKey, isCompressed = true) {
5768
+ function getPublicKey4(secretKey, isCompressed = true) {
5769
5769
  return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
5770
5770
  }
5771
5771
  function isProbPub(item) {
@@ -5791,8 +5791,8 @@ function ecdh(Point, ecdhOpts = {}) {
5791
5791
  isValidPublicKey,
5792
5792
  randomSecretKey
5793
5793
  };
5794
- const keygen = createKeygen(randomSecretKey, getPublicKey3);
5795
- return Object.freeze({ getPublicKey: getPublicKey3, getSharedSecret, keygen, Point, utils, lengths });
5794
+ const keygen = createKeygen(randomSecretKey, getPublicKey4);
5795
+ return Object.freeze({ getPublicKey: getPublicKey4, getSharedSecret, keygen, Point, utils, lengths });
5796
5796
  }
5797
5797
  function ecdsa(Point, hash, ecdsaOpts = {}) {
5798
5798
  ahash(hash);
@@ -5808,7 +5808,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
5808
5808
  const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
5809
5809
  const { Fp, Fn } = Point;
5810
5810
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
5811
- const { keygen, getPublicKey: getPublicKey3, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
5811
+ const { keygen, getPublicKey: getPublicKey4, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
5812
5812
  const defaultSigOpts = {
5813
5813
  prehash: true,
5814
5814
  lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : true,
@@ -6014,7 +6014,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
6014
6014
  }
6015
6015
  return Object.freeze({
6016
6016
  keygen,
6017
- getPublicKey: getPublicKey3,
6017
+ getPublicKey: getPublicKey4,
6018
6018
  getSharedSecret,
6019
6019
  utils,
6020
6020
  lengths,
@@ -6300,8 +6300,8 @@ function u32(arr) {
6300
6300
  return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
6301
6301
  }
6302
6302
  function clean2(...arrays) {
6303
- for (let i3 = 0; i3 < arrays.length; i3++) {
6304
- arrays[i3].fill(0);
6303
+ for (let i4 = 0; i4 < arrays.length; i4++) {
6304
+ arrays[i4].fill(0);
6305
6305
  }
6306
6306
  }
6307
6307
  function createView2(arr) {
@@ -6327,8 +6327,8 @@ function equalBytes(a, b) {
6327
6327
  if (a.length !== b.length)
6328
6328
  return false;
6329
6329
  let diff = 0;
6330
- for (let i3 = 0; i3 < a.length; i3++)
6331
- diff |= a[i3] ^ b[i3];
6330
+ for (let i4 = 0; i4 < a.length; i4++)
6331
+ diff |= a[i4] ^ b[i4];
6332
6332
  return diff === 0;
6333
6333
  }
6334
6334
  var wrapCipher = /* @__NO_SIDE_EFFECTS__ */ (params, constructor) => {
@@ -6508,8 +6508,8 @@ function createCipher(core, opts) {
6508
6508
  }
6509
6509
 
6510
6510
  // ../../node_modules/.pnpm/@noble+ciphers@2.1.1/node_modules/@noble/ciphers/_poly1305.js
6511
- function u8to16(a, i3) {
6512
- return a[i3++] & 255 | (a[i3++] & 255) << 8;
6511
+ function u8to16(a, i4) {
6512
+ return a[i4++] & 255 | (a[i4++] & 255) << 8;
6513
6513
  }
6514
6514
  var Poly1305 = class {
6515
6515
  blockLen = 16;
@@ -6542,8 +6542,8 @@ var Poly1305 = class {
6542
6542
  this.r[7] = (t5 >>> 11 | t6 << 5) & 8065;
6543
6543
  this.r[8] = (t6 >>> 8 | t7 << 8) & 8191;
6544
6544
  this.r[9] = t7 >>> 5 & 127;
6545
- for (let i3 = 0; i3 < 8; i3++)
6546
- this.pad[i3] = u8to16(key, 16 + 2 * i3);
6545
+ for (let i4 = 0; i4 < 8; i4++)
6546
+ this.pad[i4] = u8to16(key, 16 + 2 * i4);
6547
6547
  }
6548
6548
  process(data, offset, isLast = false) {
6549
6549
  const hibit = isLast ? 0 : 1 << 11;
@@ -6658,10 +6658,10 @@ var Poly1305 = class {
6658
6658
  const g = new Uint16Array(10);
6659
6659
  let c = h[1] >>> 13;
6660
6660
  h[1] &= 8191;
6661
- for (let i3 = 2; i3 < 10; i3++) {
6662
- h[i3] += c;
6663
- c = h[i3] >>> 13;
6664
- h[i3] &= 8191;
6661
+ for (let i4 = 2; i4 < 10; i4++) {
6662
+ h[i4] += c;
6663
+ c = h[i4] >>> 13;
6664
+ h[i4] &= 8191;
6665
6665
  }
6666
6666
  h[0] += c * 5;
6667
6667
  c = h[0] >>> 13;
@@ -6673,18 +6673,18 @@ var Poly1305 = class {
6673
6673
  g[0] = h[0] + 5;
6674
6674
  c = g[0] >>> 13;
6675
6675
  g[0] &= 8191;
6676
- for (let i3 = 1; i3 < 10; i3++) {
6677
- g[i3] = h[i3] + c;
6678
- c = g[i3] >>> 13;
6679
- g[i3] &= 8191;
6676
+ for (let i4 = 1; i4 < 10; i4++) {
6677
+ g[i4] = h[i4] + c;
6678
+ c = g[i4] >>> 13;
6679
+ g[i4] &= 8191;
6680
6680
  }
6681
6681
  g[9] -= 1 << 13;
6682
6682
  let mask = (c ^ 1) - 1;
6683
- for (let i3 = 0; i3 < 10; i3++)
6684
- g[i3] &= mask;
6683
+ for (let i4 = 0; i4 < 10; i4++)
6684
+ g[i4] &= mask;
6685
6685
  mask = ~mask;
6686
- for (let i3 = 0; i3 < 10; i3++)
6687
- h[i3] = h[i3] & mask | g[i3];
6686
+ for (let i4 = 0; i4 < 10; i4++)
6687
+ h[i4] = h[i4] & mask | g[i4];
6688
6688
  h[0] = (h[0] | h[1] << 13) & 65535;
6689
6689
  h[1] = (h[1] >>> 3 | h[2] << 10) & 65535;
6690
6690
  h[2] = (h[2] >>> 6 | h[3] << 7) & 65535;
@@ -6695,9 +6695,9 @@ var Poly1305 = class {
6695
6695
  h[7] = (h[8] >>> 8 | h[9] << 5) & 65535;
6696
6696
  let f = h[0] + pad2[0];
6697
6697
  h[0] = f & 65535;
6698
- for (let i3 = 1; i3 < 8; i3++) {
6699
- f = (h[i3] + pad2[i3] | 0) + (f >>> 16) | 0;
6700
- h[i3] = f & 65535;
6698
+ for (let i4 = 1; i4 < 8; i4++) {
6699
+ f = (h[i4] + pad2[i4] | 0) + (f >>> 16) | 0;
6700
+ h[i4] = f & 65535;
6701
6701
  }
6702
6702
  clean2(g);
6703
6703
  }
@@ -6741,9 +6741,9 @@ var Poly1305 = class {
6741
6741
  }
6742
6742
  this.finalize();
6743
6743
  let opos = 0;
6744
- for (let i3 = 0; i3 < 8; i3++) {
6745
- out[opos++] = h[i3] >>> 0;
6746
- out[opos++] = h[i3] >>> 8;
6744
+ for (let i4 = 0; i4 < 8; i4++) {
6745
+ out[opos++] = h[i4] >>> 0;
6746
+ out[opos++] = h[i4] >>> 8;
6747
6747
  }
6748
6748
  return out;
6749
6749
  }
@@ -6853,8 +6853,8 @@ function chachaCore(s, k, n, out, cnt, rounds = 20) {
6853
6853
  out[oi++] = y14 + x14 | 0;
6854
6854
  out[oi++] = y15 + x15 | 0;
6855
6855
  }
6856
- function hchacha(s, k, i3, out) {
6857
- let x00 = s[0], x01 = s[1], x02 = s[2], x03 = s[3], x04 = k[0], x05 = k[1], x06 = k[2], x07 = k[3], x08 = k[4], x09 = k[5], x10 = k[6], x11 = k[7], x12 = i3[0], x13 = i3[1], x14 = i3[2], x15 = i3[3];
6856
+ function hchacha(s, k, i4, out) {
6857
+ let x00 = s[0], x01 = s[1], x02 = s[2], x03 = s[3], x04 = k[0], x05 = k[1], x06 = k[2], x07 = k[3], x08 = k[4], x09 = k[5], x10 = k[6], x11 = k[7], x12 = i4[0], x13 = i4[1], x14 = i4[2], x15 = i4[3];
6858
6858
  for (let r = 0; r < 20; r += 2) {
6859
6859
  x00 = x00 + x04 | 0;
6860
6860
  x12 = rotl(x12 ^ x00, 16);
@@ -7492,11 +7492,11 @@ function parseChord(chord) {
7492
7492
  if (chord.length === 0) throw new Error("empty chord");
7493
7493
  const parts = chord.split("+");
7494
7494
  const out = { ctrl: false, alt: false, shift: false, meta: false, key: "" };
7495
- for (let i3 = 0; i3 < parts.length - 1; i3++) {
7496
- const tok = parts[i3].trim().toLowerCase();
7495
+ for (let i4 = 0; i4 < parts.length - 1; i4++) {
7496
+ const tok = parts[i4].trim().toLowerCase();
7497
7497
  if (tok.length === 0) continue;
7498
7498
  const slot = MODIFIER_ALIASES[tok];
7499
- if (!slot) throw new Error(`unknown modifier: ${parts[i3]}`);
7499
+ if (!slot) throw new Error(`unknown modifier: ${parts[i4]}`);
7500
7500
  out[slot] = true;
7501
7501
  }
7502
7502
  const keyTok = parts[parts.length - 1].trim();
@@ -8393,8 +8393,8 @@ function arrayBufferToBase64(buf) {
8393
8393
  const bytes = new Uint8Array(buf);
8394
8394
  const CHUNK = 32768;
8395
8395
  let binary = "";
8396
- for (let i3 = 0; i3 < bytes.length; i3 += CHUNK) {
8397
- binary += String.fromCharCode(...bytes.subarray(i3, i3 + CHUNK));
8396
+ for (let i4 = 0; i4 < bytes.length; i4 += CHUNK) {
8397
+ binary += String.fromCharCode(...bytes.subarray(i4, i4 + CHUNK));
8398
8398
  }
8399
8399
  return btoa(binary);
8400
8400
  }
@@ -10500,7 +10500,7 @@ function createDevServices(pool, getSimulation, onThemeService, confirmRequest,
10500
10500
  }
10501
10501
  return services;
10502
10502
  }
10503
- function createPajaAdapter(config, getSimulation, onThemeService, confirmRequest, signerProvider) {
10503
+ function createPajaAdapter(config, getSimulation, onThemeService, confirmRequest, signerProvider, getIdentity) {
10504
10504
  const pool = createMemoryRelayPool(getSimulation, confirmRequest);
10505
10505
  const workerRelayEvents = [];
10506
10506
  return {
@@ -10540,10 +10540,13 @@ function createPajaAdapter(config, getSimulation, onThemeService, confirmRequest
10540
10540
  crypto: {
10541
10541
  verifyEvent: async () => true
10542
10542
  },
10543
- onNip5dIframeCreate: () => ({
10544
- dTag: config.window.dTag,
10545
- aggregateHash: config.window.aggregateHash
10546
- })
10543
+ onNip5dIframeCreate: () => {
10544
+ const identity = getIdentity?.();
10545
+ return {
10546
+ dTag: identity?.dTag ?? config.window.dTag,
10547
+ aggregateHash: identity?.aggregateHash ?? config.window.aggregateHash
10548
+ };
10549
+ }
10547
10550
  };
10548
10551
  }
10549
10552
 
@@ -10567,14 +10570,14 @@ function mul(a, b) {
10567
10570
  }
10568
10571
  var sbox = /* @__PURE__ */ (() => {
10569
10572
  const t = new Uint8Array(256);
10570
- for (let i3 = 0, x = 1; i3 < 256; i3++, x ^= mul2(x))
10571
- t[i3] = x;
10573
+ for (let i4 = 0, x = 1; i4 < 256; i4++, x ^= mul2(x))
10574
+ t[i4] = x;
10572
10575
  const box = new Uint8Array(256);
10573
10576
  box[0] = 99;
10574
- for (let i3 = 0; i3 < 255; i3++) {
10575
- let x = t[255 - i3];
10577
+ for (let i4 = 0; i4 < 255; i4++) {
10578
+ let x = t[255 - i4];
10576
10579
  x |= x << 8;
10577
- box[t[i3]] = (x ^ x >> 4 ^ x >> 5 ^ x >> 6 ^ x >> 7 ^ 99) & 255;
10580
+ box[t[i4]] = (x ^ x >> 4 ^ x >> 5 ^ x >> 6 ^ x >> 7 ^ 99) & 255;
10578
10581
  }
10579
10582
  clean2(t);
10580
10583
  return box;
@@ -10592,12 +10595,12 @@ function genTtable(sbox2, fn) {
10592
10595
  const T01 = new Uint32Array(256 * 256);
10593
10596
  const T23 = new Uint32Array(256 * 256);
10594
10597
  const sbox22 = new Uint16Array(256 * 256);
10595
- for (let i3 = 0; i3 < 256; i3++) {
10598
+ for (let i4 = 0; i4 < 256; i4++) {
10596
10599
  for (let j = 0; j < 256; j++) {
10597
- const idx = i3 * 256 + j;
10598
- T01[idx] = T0[i3] ^ T1[j];
10599
- T23[idx] = T2[i3] ^ T3[j];
10600
- sbox22[idx] = sbox2[i3] << 8 | sbox2[j];
10600
+ const idx = i4 * 256 + j;
10601
+ T01[idx] = T0[i4] ^ T1[j];
10602
+ T23[idx] = T2[i4] ^ T3[j];
10603
+ sbox22[idx] = sbox2[i4] << 8 | sbox2[j];
10601
10604
  }
10602
10605
  }
10603
10606
  return { sbox: sbox2, sbox2: sbox22, T0, T1, T2, T3, T01, T23 };
@@ -10606,8 +10609,8 @@ var tableEncoding = /* @__PURE__ */ genTtable(sbox, (s) => mul(s, 3) << 24 | s <
10606
10609
  var tableDecoding = /* @__PURE__ */ genTtable(invSbox, (s) => mul(s, 11) << 24 | mul(s, 13) << 16 | mul(s, 9) << 8 | mul(s, 14));
10607
10610
  var xPowers = /* @__PURE__ */ (() => {
10608
10611
  const p = new Uint8Array(16);
10609
- for (let i3 = 0, x = 1; i3 < 16; i3++, x = mul2(x))
10610
- p[i3] = x;
10612
+ for (let i4 = 0, x = 1; i4 < 16; i4++, x = mul2(x))
10613
+ p[i4] = x;
10611
10614
  return p;
10612
10615
  })();
10613
10616
  function expandKeyLE(key) {
@@ -10623,13 +10626,13 @@ function expandKeyLE(key) {
10623
10626
  const subByte = (n) => applySbox(sbox2, n, n, n, n);
10624
10627
  const xk = new Uint32Array(len + 28);
10625
10628
  xk.set(k32);
10626
- for (let i3 = Nk; i3 < xk.length; i3++) {
10627
- let t = xk[i3 - 1];
10628
- if (i3 % Nk === 0)
10629
- t = subByte(rotr32_8(t)) ^ xPowers[i3 / Nk - 1];
10630
- else if (Nk > 6 && i3 % Nk === 4)
10629
+ for (let i4 = Nk; i4 < xk.length; i4++) {
10630
+ let t = xk[i4 - 1];
10631
+ if (i4 % Nk === 0)
10632
+ t = subByte(rotr32_8(t)) ^ xPowers[i4 / Nk - 1];
10633
+ else if (Nk > 6 && i4 % Nk === 4)
10631
10634
  t = subByte(t);
10632
- xk[i3] = xk[i3 - Nk] ^ t;
10635
+ xk[i4] = xk[i4 - Nk] ^ t;
10633
10636
  }
10634
10637
  clean2(...toClean);
10635
10638
  return xk;
@@ -10640,15 +10643,15 @@ function expandKeyDecLE(key) {
10640
10643
  const Nk = encKey.length;
10641
10644
  const { sbox2 } = tableEncoding;
10642
10645
  const { T0, T1, T2, T3 } = tableDecoding;
10643
- for (let i3 = 0; i3 < Nk; i3 += 4) {
10646
+ for (let i4 = 0; i4 < Nk; i4 += 4) {
10644
10647
  for (let j = 0; j < 4; j++)
10645
- xk[i3 + j] = encKey[Nk - i3 - 4 + j];
10648
+ xk[i4 + j] = encKey[Nk - i4 - 4 + j];
10646
10649
  }
10647
10650
  clean2(encKey);
10648
- for (let i3 = 4; i3 < Nk - 4; i3++) {
10649
- const x = xk[i3];
10651
+ for (let i4 = 4; i4 < Nk - 4; i4++) {
10652
+ const x = xk[i4];
10650
10653
  const w = applySbox(sbox2, x, x, x, x);
10651
- xk[i3] = T0[w & 255] ^ T1[w >>> 8 & 255] ^ T2[w >>> 16 & 255] ^ T3[w >>> 24];
10654
+ xk[i4] = T0[w & 255] ^ T1[w >>> 8 & 255] ^ T2[w >>> 16 & 255] ^ T3[w >>> 24];
10652
10655
  }
10653
10656
  return xk;
10654
10657
  }
@@ -10663,7 +10666,7 @@ function encrypt(xk, s0, s1, s2, s3) {
10663
10666
  let k = 0;
10664
10667
  s0 ^= xk[k++], s1 ^= xk[k++], s2 ^= xk[k++], s3 ^= xk[k++];
10665
10668
  const rounds = xk.length / 4 - 2;
10666
- for (let i3 = 0; i3 < rounds; i3++) {
10669
+ for (let i4 = 0; i4 < rounds; i4++) {
10667
10670
  const t02 = xk[k++] ^ apply0123(T01, T23, s0, s1, s2, s3);
10668
10671
  const t12 = xk[k++] ^ apply0123(T01, T23, s1, s2, s3, s0);
10669
10672
  const t22 = xk[k++] ^ apply0123(T01, T23, s2, s3, s0, s1);
@@ -10681,7 +10684,7 @@ function decrypt(xk, s0, s1, s2, s3) {
10681
10684
  let k = 0;
10682
10685
  s0 ^= xk[k++], s1 ^= xk[k++], s2 ^= xk[k++], s3 ^= xk[k++];
10683
10686
  const rounds = xk.length / 4 - 2;
10684
- for (let i3 = 0; i3 < rounds; i3++) {
10687
+ for (let i4 = 0; i4 < rounds; i4++) {
10685
10688
  const t02 = xk[k++] ^ apply0123(T01, T23, s0, s3, s2, s1);
10686
10689
  const t12 = xk[k++] ^ apply0123(T01, T23, s1, s0, s3, s2);
10687
10690
  const t22 = xk[k++] ^ apply0123(T01, T23, s2, s1, s0, s3);
@@ -10730,8 +10733,8 @@ function validatePCKS(data, pcks5) {
10730
10733
  if (lastByte <= 0 || lastByte > 16)
10731
10734
  throw new Error("aes/pcks5: wrong padding");
10732
10735
  const out = data.subarray(0, -lastByte);
10733
- for (let i3 = 0; i3 < lastByte; i3++)
10734
- if (data[len - i3 - 1] !== lastByte)
10736
+ for (let i4 = 0; i4 < lastByte; i4++)
10737
+ if (data[len - i4 - 1] !== lastByte)
10735
10738
  throw new Error("aes/pcks5: wrong padding");
10736
10739
  return out;
10737
10740
  }
@@ -10740,8 +10743,8 @@ function padPCKS(left) {
10740
10743
  const tmp32 = u32(tmp);
10741
10744
  tmp.set(left);
10742
10745
  const paddingByte = BLOCK_SIZE - left.length;
10743
- for (let i3 = BLOCK_SIZE - paddingByte; i3 < BLOCK_SIZE; i3++)
10744
- tmp[i3] = paddingByte;
10746
+ for (let i4 = BLOCK_SIZE - paddingByte; i4 < BLOCK_SIZE; i4++)
10747
+ tmp[i4] = paddingByte;
10745
10748
  return tmp32;
10746
10749
  }
10747
10750
  var cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, function aescbc(key, iv, opts = {}) {
@@ -10756,17 +10759,17 @@ var cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, functio
10756
10759
  toClean.push(_iv = copyBytes2(_iv));
10757
10760
  const n32 = u32(_iv);
10758
10761
  let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3];
10759
- let i3 = 0;
10760
- for (; i3 + 4 <= b.length; ) {
10761
- s0 ^= b[i3 + 0], s1 ^= b[i3 + 1], s2 ^= b[i3 + 2], s3 ^= b[i3 + 3];
10762
+ let i4 = 0;
10763
+ for (; i4 + 4 <= b.length; ) {
10764
+ s0 ^= b[i4 + 0], s1 ^= b[i4 + 1], s2 ^= b[i4 + 2], s3 ^= b[i4 + 3];
10762
10765
  ({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3));
10763
- o[i3++] = s0, o[i3++] = s1, o[i3++] = s2, o[i3++] = s3;
10766
+ o[i4++] = s0, o[i4++] = s1, o[i4++] = s2, o[i4++] = s3;
10764
10767
  }
10765
10768
  if (pcks5) {
10766
- const tmp32 = padPCKS(plaintext.subarray(i3 * 4));
10769
+ const tmp32 = padPCKS(plaintext.subarray(i4 * 4));
10767
10770
  s0 ^= tmp32[0], s1 ^= tmp32[1], s2 ^= tmp32[2], s3 ^= tmp32[3];
10768
10771
  ({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3));
10769
- o[i3++] = s0, o[i3++] = s1, o[i3++] = s2, o[i3++] = s3;
10772
+ o[i4++] = s0, o[i4++] = s1, o[i4++] = s2, o[i4++] = s3;
10770
10773
  }
10771
10774
  clean2(...toClean);
10772
10775
  return _out;
@@ -10786,11 +10789,11 @@ var cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, functio
10786
10789
  const b = u32(ciphertext);
10787
10790
  const o = u32(dst);
10788
10791
  let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3];
10789
- for (let i3 = 0; i3 + 4 <= b.length; ) {
10792
+ for (let i4 = 0; i4 + 4 <= b.length; ) {
10790
10793
  const ps0 = s0, ps1 = s1, ps2 = s2, ps3 = s3;
10791
- s0 = b[i3 + 0], s1 = b[i3 + 1], s2 = b[i3 + 2], s3 = b[i3 + 3];
10794
+ s0 = b[i4 + 0], s1 = b[i4 + 1], s2 = b[i4 + 2], s3 = b[i4 + 3];
10792
10795
  const { s0: o0, s1: o1, s2: o2, s3: o3 } = decrypt(xk, s0, s1, s2, s3);
10793
- o[i3++] = o0 ^ ps0, o[i3++] = o1 ^ ps1, o[i3++] = o2 ^ ps2, o[i3++] = o3 ^ ps3;
10796
+ o[i4++] = o0 ^ ps0, o[i4++] = o1 ^ ps1, o[i4++] = o2 ^ ps2, o[i4++] = o3 ^ ps3;
10794
10797
  }
10795
10798
  clean2(...toClean);
10796
10799
  return validatePCKS(dst, pcks5);
@@ -10811,9 +10814,9 @@ function encryptBlock(xk, block2) {
10811
10814
  }
10812
10815
  function dbl(block2) {
10813
10816
  let carry = 0;
10814
- for (let i3 = BLOCK_SIZE - 1; i3 >= 0; i3--) {
10815
- const newCarry = (block2[i3] & 128) >>> 7;
10816
- block2[i3] = block2[i3] << 1 | carry;
10817
+ for (let i4 = BLOCK_SIZE - 1; i4 >= 0; i4--) {
10818
+ const newCarry = (block2[i4] & 128) >>> 7;
10819
+ block2[i4] = block2[i4] << 1 | carry;
10817
10820
  carry = newCarry;
10818
10821
  }
10819
10822
  if (carry) {
@@ -10824,8 +10827,8 @@ function dbl(block2) {
10824
10827
  function xorBlock(a, b) {
10825
10828
  if (a.length !== b.length)
10826
10829
  throw new Error("xorBlock: blocks must have same length");
10827
- for (let i3 = 0; i3 < a.length; i3++) {
10828
- a[i3] = a[i3] ^ b[i3];
10830
+ for (let i4 = 0; i4 < a.length; i4++) {
10831
+ a[i4] = a[i4] ^ b[i4];
10829
10832
  }
10830
10833
  return a;
10831
10834
  }
@@ -10883,8 +10886,8 @@ var _CMAC = class {
10883
10886
  m_last = xorBlock(padded, this.k2);
10884
10887
  }
10885
10888
  let x = new Uint8Array(BLOCK_SIZE);
10886
- for (let i3 = 0; i3 < n - 1; i3++) {
10887
- const m_i = buffer.subarray(i3 * BLOCK_SIZE, (i3 + 1) * BLOCK_SIZE);
10889
+ for (let i4 = 0; i4 < n - 1; i4++) {
10890
+ const m_i = buffer.subarray(i4 * BLOCK_SIZE, (i4 + 1) * BLOCK_SIZE);
10888
10891
  xorBlock(x, m_i);
10889
10892
  encryptBlock(this.xk, x);
10890
10893
  }
@@ -13848,211 +13851,1886 @@ function renderSignerStatus(state, signerPubkey) {
13848
13851
  controls.replaceChildren(devButton, nip07Button, bunkerInput, bunkerButton);
13849
13852
  }
13850
13853
 
13851
- // src/browser-host.ts
13852
- var bridgeRef = null;
13853
- function readConfig() {
13854
- const script = document.getElementById("kehto-paja-config");
13855
- if (!script?.textContent) {
13856
- throw new Error("Missing Kehto Paja config.");
13854
+ // ../../node_modules/.pnpm/nostr-tools@2.23.3_typescript@5.9.3/node_modules/nostr-tools/lib/esm/pool.js
13855
+ var verifiedSymbol3 = /* @__PURE__ */ Symbol("verified");
13856
+ var isRecord3 = (obj) => obj instanceof Object;
13857
+ function validateEvent3(event) {
13858
+ if (!isRecord3(event))
13859
+ return false;
13860
+ if (typeof event.kind !== "number")
13861
+ return false;
13862
+ if (typeof event.content !== "string")
13863
+ return false;
13864
+ if (typeof event.created_at !== "number")
13865
+ return false;
13866
+ if (typeof event.pubkey !== "string")
13867
+ return false;
13868
+ if (!event.pubkey.match(/^[a-f0-9]{64}$/))
13869
+ return false;
13870
+ if (!Array.isArray(event.tags))
13871
+ return false;
13872
+ for (let i22 = 0; i22 < event.tags.length; i22++) {
13873
+ let tag = event.tags[i22];
13874
+ if (!Array.isArray(tag))
13875
+ return false;
13876
+ for (let j = 0; j < tag.length; j++) {
13877
+ if (typeof tag[j] !== "string")
13878
+ return false;
13879
+ }
13857
13880
  }
13858
- return JSON.parse(script.textContent);
13881
+ return true;
13859
13882
  }
13860
- async function readLatestConfig(fallback) {
13883
+ var utf8Decoder4 = new TextDecoder("utf-8");
13884
+ var utf8Encoder4 = new TextEncoder();
13885
+ function normalizeURL2(url) {
13861
13886
  try {
13862
- const response = await fetch("/__kehto/config.json", { cache: "no-store" });
13863
- if (!response.ok) return fallback;
13864
- return await response.json();
13865
- } catch (error) {
13866
- console.warn("[paja] config refresh failed; using embedded config", error);
13867
- return fallback;
13887
+ if (url.indexOf("://") === -1)
13888
+ url = "wss://" + url;
13889
+ let p = new URL(url);
13890
+ if (p.protocol === "http:")
13891
+ p.protocol = "ws:";
13892
+ else if (p.protocol === "https:")
13893
+ p.protocol = "wss:";
13894
+ p.pathname = p.pathname.replace(/\/+/g, "/");
13895
+ if (p.pathname.endsWith("/"))
13896
+ p.pathname = p.pathname.slice(0, -1);
13897
+ if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
13898
+ p.port = "";
13899
+ p.searchParams.sort();
13900
+ p.hash = "";
13901
+ return p.toString();
13902
+ } catch (e) {
13903
+ throw new Error(`Invalid URL: ${url}`);
13868
13904
  }
13869
13905
  }
13870
- function setTargetUrlDisplay(config, frame) {
13871
- const targetEl = document.querySelector(".target");
13872
- if (targetEl) {
13873
- targetEl.textContent = config.target.url;
13874
- targetEl.setAttribute("title", config.target.url);
13906
+ var JS3 = class {
13907
+ generateSecretKey() {
13908
+ return schnorr.utils.randomSecretKey();
13909
+ }
13910
+ getPublicKey(secretKey) {
13911
+ return bytesToHex2(schnorr.getPublicKey(secretKey));
13875
13912
  }
13876
- frame.dataset.targetUrl = config.target.url;
13913
+ finalizeEvent(t, secretKey) {
13914
+ const event = t;
13915
+ event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
13916
+ event.id = getEventHash3(event);
13917
+ event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash3(event)), secretKey));
13918
+ event[verifiedSymbol3] = true;
13919
+ return event;
13920
+ }
13921
+ verifyEvent(event) {
13922
+ if (typeof event[verifiedSymbol3] === "boolean")
13923
+ return event[verifiedSymbol3];
13924
+ try {
13925
+ const hash = getEventHash3(event);
13926
+ if (hash !== event.id) {
13927
+ event[verifiedSymbol3] = false;
13928
+ return false;
13929
+ }
13930
+ const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
13931
+ event[verifiedSymbol3] = valid;
13932
+ return valid;
13933
+ } catch (err) {
13934
+ event[verifiedSymbol3] = false;
13935
+ return false;
13936
+ }
13937
+ }
13938
+ };
13939
+ function serializeEvent3(evt) {
13940
+ if (!validateEvent3(evt))
13941
+ throw new Error("can't serialize event with wrong or missing properties");
13942
+ return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
13877
13943
  }
13878
- function setStatus(state, status) {
13879
- state.status = status;
13880
- const statusEl = document.getElementById("lifecycle-status");
13881
- if (statusEl) statusEl.textContent = status;
13944
+ function getEventHash3(event) {
13945
+ let eventHash = sha256(utf8Encoder4.encode(serializeEvent3(event)));
13946
+ return bytesToHex2(eventHash);
13882
13947
  }
13883
- function setSimulationStatus(state) {
13884
- const statusEl = document.getElementById("simulation-status");
13885
- if (statusEl) statusEl.textContent = summarizePajaSimulation(state.simulation);
13886
- const themeSelect = document.getElementById("simulation-theme");
13887
- if (themeSelect instanceof HTMLSelectElement) themeSelect.value = state.simulation.theme.mode;
13888
- renderPajaDevtools(state, { bridge: bridgeRef, devSignerPubkey: PAJA_DEV_SIGNER_PUBKEY });
13948
+ var i3 = new JS3();
13949
+ var generateSecretKey3 = i3.generateSecretKey;
13950
+ var getPublicKey3 = i3.getPublicKey;
13951
+ var finalizeEvent3 = i3.finalizeEvent;
13952
+ var verifyEvent3 = i3.verifyEvent;
13953
+ var ClientAuth2 = 22242;
13954
+ function matchFilter(filter, event) {
13955
+ if (filter.ids && filter.ids.indexOf(event.id) === -1) {
13956
+ return false;
13957
+ }
13958
+ if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {
13959
+ return false;
13960
+ }
13961
+ if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
13962
+ return false;
13963
+ }
13964
+ for (let f in filter) {
13965
+ if (f[0] === "#") {
13966
+ let tagName = f.slice(1);
13967
+ let values = filter[`#${tagName}`];
13968
+ if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
13969
+ return false;
13970
+ }
13971
+ }
13972
+ if (filter.since && event.created_at < filter.since)
13973
+ return false;
13974
+ if (filter.until && event.created_at > filter.until)
13975
+ return false;
13976
+ return true;
13889
13977
  }
13890
- function getFrame() {
13891
- const frame = document.getElementById("napplet-frame");
13892
- if (!(frame instanceof HTMLIFrameElement)) {
13893
- throw new Error("Missing Kehto Paja iframe.");
13978
+ function matchFilters(filters, event) {
13979
+ for (let i22 = 0; i22 < filters.length; i22++) {
13980
+ if (matchFilter(filters[i22], event)) {
13981
+ return true;
13982
+ }
13894
13983
  }
13895
- frame.sandbox.add("allow-scripts");
13896
- frame.sandbox.remove("allow-same-origin");
13897
- return frame;
13984
+ return false;
13898
13985
  }
13899
- function confirmPajaRequest(state, request) {
13900
- const event = request.event;
13901
- const kind = typeof event.kind === "number" ? event.kind : "unknown";
13902
- const content = typeof event.content === "string" && event.content.length > 0 ? `
13903
-
13904
- ${event.content.slice(0, 240)}` : "";
13905
- const allowed = window.confirm(`Paja ${request.action} request
13906
- kind: ${kind}${content}`);
13907
- appendPajaMessageLog(state, "paja", {
13908
- type: `paja.${request.action}.${allowed ? "confirmed" : "denied"}`,
13909
- kind
13910
- });
13911
- return allowed;
13986
+ function getHex642(json, field) {
13987
+ let len = field.length + 3;
13988
+ let idx = json.indexOf(`"${field}":`) + len;
13989
+ let s = json.slice(idx).indexOf(`"`) + idx + 1;
13990
+ return json.slice(s, s + 64);
13991
+ }
13992
+ function getSubscriptionId2(json) {
13993
+ let idx = json.slice(0, 22).indexOf(`"EVENT"`);
13994
+ if (idx === -1)
13995
+ return null;
13996
+ let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
13997
+ if (pstart === -1)
13998
+ return null;
13999
+ let start = idx + 7 + 1 + pstart;
14000
+ let pend = json.slice(start + 1, 80).indexOf(`"`);
14001
+ if (pend === -1)
14002
+ return null;
14003
+ let end = start + 1 + pend;
14004
+ return json.slice(start + 1, end);
13912
14005
  }
13913
- function getTargetIdentity2(config) {
14006
+ function makeAuthEvent2(relayURL, challenge2) {
13914
14007
  return {
13915
- pubkey: "",
13916
- dTag: config.window.dTag,
13917
- aggregateHash: config.window.aggregateHash
14008
+ kind: ClientAuth2,
14009
+ created_at: Math.floor(Date.now() / 1e3),
14010
+ tags: [
14011
+ ["relay", relayURL],
14012
+ ["challenge", challenge2]
14013
+ ],
14014
+ content: ""
13918
14015
  };
13919
14016
  }
13920
- function registerFrameForGeneration(bridge, frame, config, generation) {
13921
- const win = frame.contentWindow;
13922
- if (!win) return null;
13923
- const windowId = `${config.window.id}:${generation}`;
13924
- originRegistry.register(win, windowId, {
13925
- dTag: config.window.dTag,
13926
- aggregateHash: config.window.aggregateHash
13927
- });
13928
- bridge.runtime.sessionRegistry.register(windowId, {
13929
- ...getTargetIdentity2(config),
13930
- windowId,
13931
- origin: "null",
13932
- type: "napplet",
13933
- registeredAt: Date.now(),
13934
- instanceId: `${windowId}:${Date.now()}`,
13935
- provenance: "nip-5d"
13936
- });
13937
- return windowId;
13938
- }
13939
- function navigateFrame(bridge, frame, config, generation) {
13940
- const windowId = registerFrameForGeneration(bridge, frame, config, generation);
13941
- frame.src = config.target.url;
13942
- return windowId;
13943
- }
13944
- function createHostSignerController(getState) {
13945
- return createPajaSignerController({
13946
- confirmRequest: (request) => confirmPajaRequest(getState(), request),
13947
- onChange(signer) {
13948
- const state = getState();
13949
- if (!state) return;
13950
- state.signer = signer;
13951
- appendPajaMessageLog(state, "paja", {
13952
- type: `paja.signer.${signer.method}.${signer.status}`,
13953
- pubkey: signer.pubkey,
13954
- relay: signer.relay,
13955
- error: signer.error
13956
- });
13957
- setSimulationStatus(state);
13958
- if (signer.status === "connected") state.reload();
13959
- }
13960
- });
13961
- }
13962
- function installPajaControlListeners(state) {
13963
- document.getElementById("reload-target")?.addEventListener("click", () => {
13964
- state.reload();
13965
- });
13966
- document.getElementById("simulation-theme")?.addEventListener("change", (event) => {
13967
- const target = event.target;
13968
- if (!(target instanceof HTMLSelectElement)) return;
13969
- if (target.value === "dark" || target.value === "light") {
13970
- state.setThemeMode(target.value);
14017
+ var SendingOnClosedConnection = class extends Error {
14018
+ constructor(message, relay) {
14019
+ super(`Tried to send message '${message} on a closed connection to ${relay}.`);
14020
+ this.name = "SendingOnClosedConnection";
14021
+ }
14022
+ };
14023
+ var AbstractRelay = class {
14024
+ url;
14025
+ _connected = false;
14026
+ onclose = null;
14027
+ onnotice = (msg) => console.debug(`NOTICE from ${this.url}: ${msg}`);
14028
+ onauth;
14029
+ baseEoseTimeout = 4400;
14030
+ publishTimeout = 4400;
14031
+ pingFrequency = 29e3;
14032
+ pingTimeout = 2e4;
14033
+ resubscribeBackoff = [1e4, 1e4, 1e4, 2e4, 2e4, 3e4, 6e4];
14034
+ openSubs = /* @__PURE__ */ new Map();
14035
+ enablePing;
14036
+ enableReconnect;
14037
+ idleSince = Date.now();
14038
+ ongoingOperations = 0;
14039
+ reconnectTimeoutHandle;
14040
+ pingIntervalHandle;
14041
+ reconnectAttempts = 0;
14042
+ skipReconnection = false;
14043
+ connectionPromise;
14044
+ openCountRequests = /* @__PURE__ */ new Map();
14045
+ openEventPublishes = /* @__PURE__ */ new Map();
14046
+ ws;
14047
+ challenge;
14048
+ authPromise;
14049
+ serial = 0;
14050
+ verifyEvent;
14051
+ _WebSocket;
14052
+ constructor(url, opts) {
14053
+ this.url = normalizeURL2(url);
14054
+ this.verifyEvent = opts.verifyEvent;
14055
+ this._WebSocket = opts.websocketImplementation || WebSocket;
14056
+ this.enablePing = opts.enablePing;
14057
+ this.enableReconnect = opts.enableReconnect || false;
14058
+ }
14059
+ static async connect(url, opts) {
14060
+ const relay = new AbstractRelay(url, opts);
14061
+ await relay.connect(opts);
14062
+ return relay;
14063
+ }
14064
+ closeAllSubscriptions(reason) {
14065
+ for (let [_, sub] of this.openSubs) {
14066
+ sub.close(reason);
14067
+ }
14068
+ this.openSubs.clear();
14069
+ for (let [_, ep] of this.openEventPublishes) {
14070
+ ep.reject(new Error(reason));
14071
+ }
14072
+ this.openEventPublishes.clear();
14073
+ for (let [_, cr] of this.openCountRequests) {
14074
+ cr.reject(new Error(reason));
14075
+ }
14076
+ this.openCountRequests.clear();
14077
+ }
14078
+ get connected() {
14079
+ return this._connected;
14080
+ }
14081
+ async reconnect() {
14082
+ const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
14083
+ this.reconnectAttempts++;
14084
+ this.reconnectTimeoutHandle = setTimeout(async () => {
14085
+ try {
14086
+ await this.connect();
14087
+ } catch (err) {
14088
+ }
14089
+ }, backoff);
14090
+ }
14091
+ handleHardClose(reason) {
14092
+ if (this.pingIntervalHandle) {
14093
+ clearInterval(this.pingIntervalHandle);
14094
+ this.pingIntervalHandle = void 0;
13971
14095
  }
13972
- });
13973
- document.getElementById("message-filter")?.addEventListener("input", (event) => {
13974
- const target = event.target;
13975
- if (!(target instanceof HTMLInputElement)) return;
13976
- state.messageFilter = target.value;
13977
- renderPajaMessageLog(state);
13978
- });
13979
- document.getElementById("clear-log")?.addEventListener("click", () => {
13980
- state.clearLog();
13981
- });
13982
- }
13983
- async function installPajaHost() {
13984
- const config = await readLatestConfig(readConfig());
13985
- const frame = getFrame();
13986
- setTargetUrlDisplay(config, frame);
13987
- let currentSimulation = config.simulation;
13988
- const getSimulation = () => currentSimulation;
13989
- let themeService = null;
13990
- let stateRef = null;
13991
- const signerController = createHostSignerController(() => stateRef);
13992
- const adapter = createPajaAdapter(config, getSimulation, (theme) => {
13993
- themeService = theme;
13994
- }, (request) => confirmPajaRequest(stateRef, request), signerController);
13995
- const bridge = createShellBridge(adapter);
13996
- bridgeRef = bridge;
13997
- installPajaOriginRegistryProxy(originRegistry, () => stateRef);
13998
- const capabilities = buildShellCapabilities(adapter);
13999
- const services = Object.keys(adapter.services ?? {}).sort();
14000
- let currentWindowId = null;
14001
- let initReceivedGeneration = -1;
14002
- const state = {
14003
- config,
14004
- capabilities,
14005
- services,
14006
- simulation: currentSimulation,
14007
- signer: signerController.getState(),
14008
- generation: 0,
14009
- status: "booting",
14010
- messageFilter: "",
14011
- messageLog: [],
14012
- reload() {
14013
- if (currentWindowId) {
14014
- bridge.runtime.destroyWindow(currentWindowId);
14015
- bridge.runtime.sessionRegistry.unregister(currentWindowId);
14016
- originRegistry.unregister(currentWindowId);
14096
+ this._connected = false;
14097
+ this.connectionPromise = void 0;
14098
+ this.idleSince = void 0;
14099
+ if (this.enableReconnect && !this.skipReconnection) {
14100
+ this.reconnect();
14101
+ } else {
14102
+ this.onclose?.();
14103
+ this.closeAllSubscriptions(reason);
14104
+ }
14105
+ }
14106
+ async connect(opts) {
14107
+ let connectionTimeoutHandle;
14108
+ if (this.connectionPromise)
14109
+ return this.connectionPromise;
14110
+ this.challenge = void 0;
14111
+ this.authPromise = void 0;
14112
+ this.skipReconnection = false;
14113
+ this.connectionPromise = new Promise((resolve, reject) => {
14114
+ if (opts?.timeout) {
14115
+ connectionTimeoutHandle = setTimeout(() => {
14116
+ reject("connection timed out");
14117
+ this.connectionPromise = void 0;
14118
+ this.skipReconnection = true;
14119
+ this.onclose?.();
14120
+ this.handleHardClose("relay connection timed out");
14121
+ }, opts.timeout);
14122
+ }
14123
+ if (opts?.abort) {
14124
+ opts.abort.onabort = reject;
14017
14125
  }
14018
- this.generation += 1;
14019
- initReceivedGeneration = -1;
14020
- setStatus(this, "reloading");
14021
- currentWindowId = navigateFrame(bridge, frame, config, this.generation);
14022
- },
14023
- setThemeMode(mode) {
14024
- currentSimulation = {
14025
- ...currentSimulation,
14026
- theme: {
14027
- ...currentSimulation.theme,
14028
- mode
14126
+ try {
14127
+ this.ws = new this._WebSocket(this.url);
14128
+ } catch (err) {
14129
+ clearTimeout(connectionTimeoutHandle);
14130
+ reject(err);
14131
+ return;
14132
+ }
14133
+ this.ws.onopen = () => {
14134
+ if (this.reconnectTimeoutHandle) {
14135
+ clearTimeout(this.reconnectTimeoutHandle);
14136
+ this.reconnectTimeoutHandle = void 0;
14137
+ }
14138
+ clearTimeout(connectionTimeoutHandle);
14139
+ this._connected = true;
14140
+ const isReconnection = this.reconnectAttempts > 0;
14141
+ this.reconnectAttempts = 0;
14142
+ for (const sub of this.openSubs.values()) {
14143
+ sub.eosed = false;
14144
+ if (isReconnection) {
14145
+ for (let f = 0; f < sub.filters.length; f++) {
14146
+ if (sub.lastEmitted) {
14147
+ sub.filters[f].since = sub.lastEmitted + 1;
14148
+ }
14149
+ }
14150
+ }
14151
+ sub.fire();
14152
+ }
14153
+ if (this.enablePing) {
14154
+ this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency);
14029
14155
  }
14156
+ resolve();
14030
14157
  };
14031
- this.simulation = currentSimulation;
14032
- themeService?.publishTheme(createDevTheme(currentSimulation.theme.mode, currentSimulation.theme.values));
14033
- setSimulationStatus(this);
14034
- },
14158
+ this.ws.onerror = () => {
14159
+ clearTimeout(connectionTimeoutHandle);
14160
+ reject("connection failed");
14161
+ this.connectionPromise = void 0;
14162
+ this.skipReconnection = true;
14163
+ this.onclose?.();
14164
+ this.handleHardClose("relay connection failed");
14165
+ };
14166
+ this.ws.onclose = (ev) => {
14167
+ clearTimeout(connectionTimeoutHandle);
14168
+ reject(ev.message || "websocket closed");
14169
+ this.handleHardClose("relay connection closed");
14170
+ };
14171
+ this.ws.onmessage = this._onmessage.bind(this);
14172
+ });
14173
+ return this.connectionPromise;
14174
+ }
14175
+ waitForPingPong() {
14176
+ return new Promise((resolve) => {
14177
+ ;
14178
+ this.ws.once("pong", () => resolve(true));
14179
+ this.ws.ping();
14180
+ });
14181
+ }
14182
+ waitForDummyReq() {
14183
+ return new Promise((resolve, reject) => {
14184
+ if (!this.connectionPromise)
14185
+ return reject(new Error(`no connection to ${this.url}, can't ping`));
14186
+ try {
14187
+ const sub = this.subscribe(
14188
+ [{ ids: ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], limit: 0 }],
14189
+ {
14190
+ label: "<forced-ping>",
14191
+ oneose: () => {
14192
+ resolve(true);
14193
+ sub.close();
14194
+ },
14195
+ onclose() {
14196
+ resolve(true);
14197
+ },
14198
+ eoseTimeout: this.pingTimeout + 1e3
14199
+ }
14200
+ );
14201
+ } catch (err) {
14202
+ reject(err);
14203
+ }
14204
+ });
14205
+ }
14206
+ async pingpong() {
14207
+ if (this.ws?.readyState === 1) {
14208
+ const result = await Promise.any([
14209
+ this.ws && this.ws.ping && this.ws.once ? this.waitForPingPong() : this.waitForDummyReq(),
14210
+ new Promise((res) => setTimeout(() => res(false), this.pingTimeout))
14211
+ ]);
14212
+ if (!result) {
14213
+ if (this.ws?.readyState === this._WebSocket.OPEN) {
14214
+ this.ws?.close();
14215
+ }
14216
+ }
14217
+ }
14218
+ }
14219
+ async send(message) {
14220
+ if (!this.connectionPromise)
14221
+ throw new SendingOnClosedConnection(message, this.url);
14222
+ this.connectionPromise.then(() => {
14223
+ this.ws?.send(message);
14224
+ });
14225
+ }
14226
+ async auth(signAuthEvent) {
14227
+ const challenge2 = this.challenge;
14228
+ if (!challenge2)
14229
+ throw new Error("can't perform auth, no challenge was received");
14230
+ if (this.authPromise)
14231
+ return this.authPromise;
14232
+ this.authPromise = new Promise(async (resolve, reject) => {
14233
+ try {
14234
+ let evt = await signAuthEvent(makeAuthEvent2(this.url, challenge2));
14235
+ let timeout = setTimeout(() => {
14236
+ let ep = this.openEventPublishes.get(evt.id);
14237
+ if (ep) {
14238
+ ep.reject(new Error("auth timed out"));
14239
+ this.openEventPublishes.delete(evt.id);
14240
+ }
14241
+ }, this.publishTimeout);
14242
+ this.openEventPublishes.set(evt.id, { resolve, reject, timeout });
14243
+ this.send('["AUTH",' + JSON.stringify(evt) + "]");
14244
+ } catch (err) {
14245
+ console.warn("subscribe auth function failed:", err);
14246
+ }
14247
+ });
14248
+ return this.authPromise;
14249
+ }
14250
+ async publish(event) {
14251
+ this.idleSince = void 0;
14252
+ this.ongoingOperations++;
14253
+ const ret = new Promise((resolve, reject) => {
14254
+ const timeout = setTimeout(() => {
14255
+ const ep = this.openEventPublishes.get(event.id);
14256
+ if (ep) {
14257
+ ep.reject(new Error("publish timed out"));
14258
+ this.openEventPublishes.delete(event.id);
14259
+ }
14260
+ }, this.publishTimeout);
14261
+ this.openEventPublishes.set(event.id, { resolve, reject, timeout });
14262
+ });
14263
+ this.send('["EVENT",' + JSON.stringify(event) + "]");
14264
+ this.ongoingOperations--;
14265
+ if (this.ongoingOperations === 0)
14266
+ this.idleSince = Date.now();
14267
+ return ret;
14268
+ }
14269
+ async count(filters, params) {
14270
+ this.serial++;
14271
+ const id = params?.id || "count:" + this.serial;
14272
+ const ret = new Promise((resolve, reject) => {
14273
+ this.openCountRequests.set(id, { resolve, reject });
14274
+ });
14275
+ this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
14276
+ return ret;
14277
+ }
14278
+ subscribe(filters, params) {
14279
+ if (params.label !== "<forced-ping>") {
14280
+ this.idleSince = void 0;
14281
+ this.ongoingOperations++;
14282
+ }
14283
+ const sub = this.prepareSubscription(filters, params);
14284
+ sub.fire();
14285
+ if (params.abort) {
14286
+ params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
14287
+ }
14288
+ return sub;
14289
+ }
14290
+ prepareSubscription(filters, params) {
14291
+ this.serial++;
14292
+ const id = params.id || (params.label ? params.label + ":" : "sub:") + this.serial;
14293
+ const sub = new Subscription(this, id, filters, params);
14294
+ this.openSubs.set(id, sub);
14295
+ return sub;
14296
+ }
14297
+ close() {
14298
+ this.skipReconnection = true;
14299
+ if (this.reconnectTimeoutHandle) {
14300
+ clearTimeout(this.reconnectTimeoutHandle);
14301
+ this.reconnectTimeoutHandle = void 0;
14302
+ }
14303
+ if (this.pingIntervalHandle) {
14304
+ clearInterval(this.pingIntervalHandle);
14305
+ this.pingIntervalHandle = void 0;
14306
+ }
14307
+ this.closeAllSubscriptions("relay connection closed by us");
14308
+ this._connected = false;
14309
+ this.idleSince = void 0;
14310
+ this.onclose?.();
14311
+ if (this.ws?.readyState === this._WebSocket.OPEN) {
14312
+ this.ws?.close();
14313
+ }
14314
+ }
14315
+ _onmessage(ev) {
14316
+ const json = ev.data;
14317
+ if (!json) {
14318
+ return;
14319
+ }
14320
+ const subid = getSubscriptionId2(json);
14321
+ if (subid) {
14322
+ const so = this.openSubs.get(subid);
14323
+ if (!so) {
14324
+ return;
14325
+ }
14326
+ const id = getHex642(json, "id");
14327
+ const alreadyHave = so.alreadyHaveEvent?.(id);
14328
+ so.receivedEvent?.(this, id);
14329
+ if (alreadyHave) {
14330
+ return;
14331
+ }
14332
+ }
14333
+ try {
14334
+ let data = JSON.parse(json);
14335
+ switch (data[0]) {
14336
+ case "EVENT": {
14337
+ const so = this.openSubs.get(data[1]);
14338
+ const event = data[2];
14339
+ if (this.verifyEvent(event) && matchFilters(so.filters, event)) {
14340
+ so.onevent(event);
14341
+ } else {
14342
+ so.oninvalidevent?.(event);
14343
+ }
14344
+ if (!so.lastEmitted || so.lastEmitted < event.created_at)
14345
+ so.lastEmitted = event.created_at;
14346
+ return;
14347
+ }
14348
+ case "COUNT": {
14349
+ const id = data[1];
14350
+ const payload = data[2];
14351
+ const cr = this.openCountRequests.get(id);
14352
+ if (cr) {
14353
+ cr.resolve(payload.count);
14354
+ this.openCountRequests.delete(id);
14355
+ }
14356
+ return;
14357
+ }
14358
+ case "EOSE": {
14359
+ const so = this.openSubs.get(data[1]);
14360
+ if (!so)
14361
+ return;
14362
+ so.receivedEose();
14363
+ return;
14364
+ }
14365
+ case "OK": {
14366
+ const id = data[1];
14367
+ const ok = data[2];
14368
+ const reason = data[3];
14369
+ const ep = this.openEventPublishes.get(id);
14370
+ if (ep) {
14371
+ clearTimeout(ep.timeout);
14372
+ if (ok)
14373
+ ep.resolve(reason);
14374
+ else
14375
+ ep.reject(new Error(reason));
14376
+ this.openEventPublishes.delete(id);
14377
+ }
14378
+ return;
14379
+ }
14380
+ case "CLOSED": {
14381
+ const id = data[1];
14382
+ const so = this.openSubs.get(id);
14383
+ if (!so)
14384
+ return;
14385
+ so.closed = true;
14386
+ so.close(data[2]);
14387
+ return;
14388
+ }
14389
+ case "NOTICE": {
14390
+ this.onnotice(data[1]);
14391
+ return;
14392
+ }
14393
+ case "AUTH": {
14394
+ this.challenge = data[1];
14395
+ if (this.onauth) {
14396
+ this.auth(this.onauth);
14397
+ }
14398
+ return;
14399
+ }
14400
+ default: {
14401
+ const so = this.openSubs.get(data[1]);
14402
+ so?.oncustom?.(data);
14403
+ return;
14404
+ }
14405
+ }
14406
+ } catch (err) {
14407
+ try {
14408
+ const [_, __, event] = JSON.parse(json);
14409
+ console.warn(`[nostr] relay ${this.url} error processing message:`, err, event);
14410
+ } catch (_) {
14411
+ console.warn(`[nostr] relay ${this.url} error processing message:`, err);
14412
+ }
14413
+ return;
14414
+ }
14415
+ }
14416
+ };
14417
+ var Subscription = class {
14418
+ relay;
14419
+ id;
14420
+ lastEmitted;
14421
+ closed = false;
14422
+ eosed = false;
14423
+ filters;
14424
+ alreadyHaveEvent;
14425
+ receivedEvent;
14426
+ onevent;
14427
+ oninvalidevent;
14428
+ oneose;
14429
+ onclose;
14430
+ oncustom;
14431
+ eoseTimeout;
14432
+ eoseTimeoutHandle;
14433
+ constructor(relay, id, filters, params) {
14434
+ if (filters.length === 0)
14435
+ throw new Error("subscription can't be created with zero filters");
14436
+ this.relay = relay;
14437
+ this.filters = filters;
14438
+ this.id = id;
14439
+ this.alreadyHaveEvent = params.alreadyHaveEvent;
14440
+ this.receivedEvent = params.receivedEvent;
14441
+ this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout;
14442
+ this.oneose = params.oneose;
14443
+ this.onclose = params.onclose;
14444
+ this.oninvalidevent = params.oninvalidevent;
14445
+ this.onevent = params.onevent || ((event) => {
14446
+ console.warn(
14447
+ `onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,
14448
+ event
14449
+ );
14450
+ });
14451
+ }
14452
+ fire() {
14453
+ this.relay.send('["REQ","' + this.id + '",' + JSON.stringify(this.filters).substring(1));
14454
+ this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout);
14455
+ }
14456
+ receivedEose() {
14457
+ if (this.eosed)
14458
+ return;
14459
+ clearTimeout(this.eoseTimeoutHandle);
14460
+ this.eosed = true;
14461
+ this.oneose?.();
14462
+ }
14463
+ close(reason = "closed by caller") {
14464
+ if (!this.closed && this.relay.connected) {
14465
+ try {
14466
+ this.relay.send('["CLOSE",' + JSON.stringify(this.id) + "]");
14467
+ } catch (err) {
14468
+ if (err instanceof SendingOnClosedConnection) {
14469
+ } else {
14470
+ throw err;
14471
+ }
14472
+ }
14473
+ this.closed = true;
14474
+ }
14475
+ this.relay.openSubs.delete(this.id);
14476
+ this.relay.ongoingOperations--;
14477
+ if (this.relay.ongoingOperations === 0)
14478
+ this.relay.idleSince = Date.now();
14479
+ this.onclose?.(reason);
14480
+ }
14481
+ };
14482
+ var alwaysTrue = (t) => {
14483
+ t[verifiedSymbol3] = true;
14484
+ return true;
14485
+ };
14486
+ var AbstractSimplePool = class {
14487
+ relays = /* @__PURE__ */ new Map();
14488
+ seenOn = /* @__PURE__ */ new Map();
14489
+ trackRelays = false;
14490
+ verifyEvent;
14491
+ enablePing;
14492
+ enableReconnect;
14493
+ automaticallyAuth;
14494
+ trustedRelayURLs = /* @__PURE__ */ new Set();
14495
+ onRelayConnectionFailure;
14496
+ onRelayConnectionSuccess;
14497
+ allowConnectingToRelay;
14498
+ maxWaitForConnection;
14499
+ _WebSocket;
14500
+ constructor(opts) {
14501
+ this.verifyEvent = opts.verifyEvent;
14502
+ this._WebSocket = opts.websocketImplementation;
14503
+ this.enablePing = opts.enablePing;
14504
+ this.enableReconnect = opts.enableReconnect || false;
14505
+ this.automaticallyAuth = opts.automaticallyAuth;
14506
+ this.onRelayConnectionFailure = opts.onRelayConnectionFailure;
14507
+ this.onRelayConnectionSuccess = opts.onRelayConnectionSuccess;
14508
+ this.allowConnectingToRelay = opts.allowConnectingToRelay;
14509
+ this.maxWaitForConnection = opts.maxWaitForConnection || 3e3;
14510
+ }
14511
+ async ensureRelay(url, params) {
14512
+ url = normalizeURL2(url);
14513
+ let relay = this.relays.get(url);
14514
+ if (!relay) {
14515
+ relay = new AbstractRelay(url, {
14516
+ verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
14517
+ websocketImplementation: this._WebSocket,
14518
+ enablePing: this.enablePing,
14519
+ enableReconnect: this.enableReconnect
14520
+ });
14521
+ relay.onclose = () => {
14522
+ this.relays.delete(url);
14523
+ };
14524
+ this.relays.set(url, relay);
14525
+ }
14526
+ if (this.automaticallyAuth) {
14527
+ const authSignerFn = this.automaticallyAuth(url);
14528
+ if (authSignerFn) {
14529
+ relay.onauth = authSignerFn;
14530
+ }
14531
+ }
14532
+ try {
14533
+ await relay.connect({
14534
+ timeout: params?.connectionTimeout,
14535
+ abort: params?.abort
14536
+ });
14537
+ } catch (err) {
14538
+ this.relays.delete(url);
14539
+ throw err;
14540
+ }
14541
+ return relay;
14542
+ }
14543
+ close(relays) {
14544
+ relays.map(normalizeURL2).forEach((url) => {
14545
+ this.relays.get(url)?.close();
14546
+ this.relays.delete(url);
14547
+ });
14548
+ }
14549
+ subscribe(relays, filter, params) {
14550
+ const request = [];
14551
+ const uniqUrls = [];
14552
+ for (let i22 = 0; i22 < relays.length; i22++) {
14553
+ const url = normalizeURL2(relays[i22]);
14554
+ if (!request.find((r) => r.url === url)) {
14555
+ if (uniqUrls.indexOf(url) === -1) {
14556
+ uniqUrls.push(url);
14557
+ request.push({ url, filter });
14558
+ }
14559
+ }
14560
+ }
14561
+ return this.subscribeMap(request, params);
14562
+ }
14563
+ subscribeMany(relays, filter, params) {
14564
+ return this.subscribe(relays, filter, params);
14565
+ }
14566
+ subscribeMap(requests, params) {
14567
+ const grouped = /* @__PURE__ */ new Map();
14568
+ for (const req of requests) {
14569
+ const { url, filter } = req;
14570
+ if (!grouped.has(url))
14571
+ grouped.set(url, []);
14572
+ grouped.get(url).push(filter);
14573
+ }
14574
+ const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }));
14575
+ if (this.trackRelays) {
14576
+ params.receivedEvent = (relay, id) => {
14577
+ let set = this.seenOn.get(id);
14578
+ if (!set) {
14579
+ set = /* @__PURE__ */ new Set();
14580
+ this.seenOn.set(id, set);
14581
+ }
14582
+ set.add(relay);
14583
+ };
14584
+ }
14585
+ const _knownIds = /* @__PURE__ */ new Set();
14586
+ const subs = [];
14587
+ const eosesReceived = [];
14588
+ let handleEose = (i22) => {
14589
+ if (eosesReceived[i22])
14590
+ return;
14591
+ eosesReceived[i22] = true;
14592
+ if (eosesReceived.filter((a) => a).length === groupedRequests.length) {
14593
+ params.oneose?.();
14594
+ handleEose = () => {
14595
+ };
14596
+ }
14597
+ };
14598
+ const closesReceived = [];
14599
+ let handleClose = (i22, reason) => {
14600
+ if (closesReceived[i22])
14601
+ return;
14602
+ handleEose(i22);
14603
+ closesReceived[i22] = reason;
14604
+ if (closesReceived.filter((a) => a).length === groupedRequests.length) {
14605
+ params.onclose?.(closesReceived);
14606
+ handleClose = () => {
14607
+ };
14608
+ }
14609
+ };
14610
+ const localAlreadyHaveEventHandler = (id) => {
14611
+ if (params.alreadyHaveEvent?.(id)) {
14612
+ return true;
14613
+ }
14614
+ const have = _knownIds.has(id);
14615
+ _knownIds.add(id);
14616
+ return have;
14617
+ };
14618
+ const allOpened = Promise.all(
14619
+ groupedRequests.map(async ({ url, filters }, i22) => {
14620
+ if (this.allowConnectingToRelay?.(url, ["read", filters]) === false) {
14621
+ handleClose(i22, "connection skipped by allowConnectingToRelay");
14622
+ return;
14623
+ }
14624
+ let relay;
14625
+ try {
14626
+ relay = await this.ensureRelay(url, {
14627
+ connectionTimeout: this.maxWaitForConnection < (params.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
14628
+ abort: params.abort
14629
+ });
14630
+ } catch (err) {
14631
+ this.onRelayConnectionFailure?.(url);
14632
+ handleClose(i22, err?.message || String(err));
14633
+ return;
14634
+ }
14635
+ this.onRelayConnectionSuccess?.(url);
14636
+ let subscription = relay.subscribe(filters, {
14637
+ ...params,
14638
+ oneose: () => handleEose(i22),
14639
+ onclose: (reason) => {
14640
+ if (reason.startsWith("auth-required: ") && params.onauth) {
14641
+ relay.auth(params.onauth).then(() => {
14642
+ relay.subscribe(filters, {
14643
+ ...params,
14644
+ oneose: () => handleEose(i22),
14645
+ onclose: (reason2) => {
14646
+ handleClose(i22, reason2);
14647
+ },
14648
+ alreadyHaveEvent: localAlreadyHaveEventHandler,
14649
+ eoseTimeout: params.maxWait,
14650
+ abort: params.abort
14651
+ });
14652
+ }).catch((err) => {
14653
+ handleClose(i22, `auth was required and attempted, but failed with: ${err}`);
14654
+ });
14655
+ } else {
14656
+ handleClose(i22, reason);
14657
+ }
14658
+ },
14659
+ alreadyHaveEvent: localAlreadyHaveEventHandler,
14660
+ eoseTimeout: params.maxWait,
14661
+ abort: params.abort
14662
+ });
14663
+ subs.push(subscription);
14664
+ })
14665
+ );
14666
+ return {
14667
+ async close(reason) {
14668
+ await allOpened;
14669
+ subs.forEach((sub) => {
14670
+ sub.close(reason);
14671
+ });
14672
+ }
14673
+ };
14674
+ }
14675
+ subscribeEose(relays, filter, params) {
14676
+ let subcloser;
14677
+ subcloser = this.subscribe(relays, filter, {
14678
+ ...params,
14679
+ oneose() {
14680
+ const reason = "closed automatically on eose";
14681
+ if (subcloser)
14682
+ subcloser.close(reason);
14683
+ else
14684
+ params.onclose?.(relays.map((_) => reason));
14685
+ }
14686
+ });
14687
+ return subcloser;
14688
+ }
14689
+ subscribeManyEose(relays, filter, params) {
14690
+ return this.subscribeEose(relays, filter, params);
14691
+ }
14692
+ async querySync(relays, filter, params) {
14693
+ return new Promise(async (resolve) => {
14694
+ const events = [];
14695
+ this.subscribeEose(relays, filter, {
14696
+ ...params,
14697
+ onevent(event) {
14698
+ events.push(event);
14699
+ },
14700
+ onclose(_) {
14701
+ resolve(events);
14702
+ }
14703
+ });
14704
+ });
14705
+ }
14706
+ async get(relays, filter, params) {
14707
+ filter.limit = 1;
14708
+ const events = await this.querySync(relays, filter, params);
14709
+ events.sort((a, b) => b.created_at - a.created_at);
14710
+ return events[0] || null;
14711
+ }
14712
+ publish(relays, event, params) {
14713
+ return relays.map(normalizeURL2).map(async (url, i22, arr) => {
14714
+ if (arr.indexOf(url) !== i22) {
14715
+ return Promise.reject("duplicate url");
14716
+ }
14717
+ if (this.allowConnectingToRelay?.(url, ["write", event]) === false) {
14718
+ return Promise.reject("connection skipped by allowConnectingToRelay");
14719
+ }
14720
+ let r;
14721
+ try {
14722
+ r = await this.ensureRelay(url, {
14723
+ connectionTimeout: this.maxWaitForConnection < (params?.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
14724
+ abort: params?.abort
14725
+ });
14726
+ } catch (err) {
14727
+ this.onRelayConnectionFailure?.(url);
14728
+ return String("connection failure: " + String(err));
14729
+ }
14730
+ return r.publish(event).catch(async (err) => {
14731
+ if (err instanceof Error && err.message.startsWith("auth-required: ") && params?.onauth) {
14732
+ await r.auth(params.onauth);
14733
+ return r.publish(event);
14734
+ }
14735
+ throw err;
14736
+ }).then((reason) => {
14737
+ if (this.trackRelays) {
14738
+ let set = this.seenOn.get(event.id);
14739
+ if (!set) {
14740
+ set = /* @__PURE__ */ new Set();
14741
+ this.seenOn.set(event.id, set);
14742
+ }
14743
+ set.add(r);
14744
+ }
14745
+ return reason;
14746
+ });
14747
+ });
14748
+ }
14749
+ listConnectionStatus() {
14750
+ const map = /* @__PURE__ */ new Map();
14751
+ this.relays.forEach((relay, url) => map.set(url, relay.connected));
14752
+ return map;
14753
+ }
14754
+ destroy() {
14755
+ this.relays.forEach((conn) => conn.close());
14756
+ this.relays = /* @__PURE__ */ new Map();
14757
+ }
14758
+ pruneIdleRelays(idleThresholdMs = 1e4) {
14759
+ const prunedUrls = [];
14760
+ for (const [url, relay] of this.relays) {
14761
+ if (relay.idleSince && Date.now() - relay.idleSince >= idleThresholdMs) {
14762
+ this.relays.delete(url);
14763
+ prunedUrls.push(url);
14764
+ relay.close();
14765
+ }
14766
+ }
14767
+ return prunedUrls;
14768
+ }
14769
+ };
14770
+ var _WebSocket3;
14771
+ try {
14772
+ _WebSocket3 = WebSocket;
14773
+ } catch {
14774
+ }
14775
+ var SimplePool = class extends AbstractSimplePool {
14776
+ constructor(options) {
14777
+ super({ verifyEvent: verifyEvent3, websocketImplementation: _WebSocket3, maxWaitForConnection: 3e3, ...options });
14778
+ }
14779
+ };
14780
+
14781
+ // ../nip/dist/chunk-2J3CSGKL.js
14782
+ function computeAggregateHash(entries) {
14783
+ const lines = entries.map((entry) => `${entry.sha256} ${entry.path}
14784
+ `);
14785
+ lines.sort();
14786
+ return bytesToHex2(sha256(new TextEncoder().encode(lines.join(""))));
14787
+ }
14788
+ function pathEntriesFromTags(tags) {
14789
+ const entries = [];
14790
+ for (const tag of tags) {
14791
+ if (tag[0] === "path" && typeof tag[1] === "string" && typeof tag[2] === "string" && tag[1].length > 0 && tag[2].length > 0) {
14792
+ entries.push({ path: tag[1], sha256: tag[2] });
14793
+ }
14794
+ }
14795
+ return entries;
14796
+ }
14797
+ function aggregateTagValue(tags) {
14798
+ for (const tag of tags) {
14799
+ if (tag[0] === "x" && tag[2] === "aggregate" && typeof tag[1] === "string" && tag[1].length > 0) {
14800
+ return tag[1];
14801
+ }
14802
+ }
14803
+ return void 0;
14804
+ }
14805
+
14806
+ // ../nip/dist/chunk-CDBUCFLP.js
14807
+ var MIB = 1024 * 1024;
14808
+ var NAPPLET_ARTIFACT_CACHE_NAME = "kehto:napplet-artifacts:v1";
14809
+ var SCHEMA_VERSION = 1;
14810
+ var DEFAULT_BASE_URL = "https://kehto.invalid";
14811
+ var DEFAULT_UNKNOWN_BUDGET_BYTES = 32 * MIB;
14812
+ var DEFAULT_SOFT_CEILING_BYTES = 128 * MIB;
14813
+ var DEFAULT_HARD_CEILING_BYTES = 256 * MIB;
14814
+ var DEFAULT_FOREGROUND_TTL_MS = 15 * 60 * 1e3;
14815
+ var DEFAULT_BACKGROUND_TTL_MS = 60 * 60 * 1e3;
14816
+ function emptyIndex(now2) {
14817
+ return {
14818
+ schemaVersion: SCHEMA_VERSION,
14819
+ updatedAt: now2,
14820
+ blobs: {},
14821
+ aggregates: {},
14822
+ coordinates: {}
14823
+ };
14824
+ }
14825
+ function aggregateKey(dTag, aggregateHash) {
14826
+ return `${encodeURIComponent(dTag)}:${aggregateHash}`;
14827
+ }
14828
+ function coordinateKey(kind, pubkey, dTag) {
14829
+ return `${kind}:${pubkey}:${encodeURIComponent(dTag)}`;
14830
+ }
14831
+ function isCoordinateFresh(coordinate, options = {}) {
14832
+ const now2 = options.now ?? Date.now();
14833
+ const ttl = options.background ? coordinate.backgroundTtlMs : coordinate.foregroundTtlMs;
14834
+ return ttl === Number.POSITIVE_INFINITY || now2 - coordinate.lastResolvedAt <= ttl;
14835
+ }
14836
+ function byteLength2(bytes) {
14837
+ return bytes.byteLength;
14838
+ }
14839
+ function encodeKeyPart(value) {
14840
+ return encodeURIComponent(value).replaceAll("%2F", "%252F");
14841
+ }
14842
+ function cloneBytes(bytes) {
14843
+ return new Uint8Array(bytes);
14844
+ }
14845
+ function responseBody(bytes) {
14846
+ return cloneBytes(bytes).buffer;
14847
+ }
14848
+ function normalizeBaseUrl(baseUrl) {
14849
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
14850
+ }
14851
+ function resolveBaseUrl(baseUrl) {
14852
+ if (baseUrl) return normalizeBaseUrl(baseUrl);
14853
+ const maybeLocation = globalThis;
14854
+ if (maybeLocation.location?.origin) return normalizeBaseUrl(maybeLocation.location.origin);
14855
+ return normalizeBaseUrl(DEFAULT_BASE_URL);
14856
+ }
14857
+ async function responseBytes(response) {
14858
+ return new Uint8Array(await response.arrayBuffer());
14859
+ }
14860
+ async function responseJson(response) {
14861
+ return response.json();
14862
+ }
14863
+ function refCounts(index) {
14864
+ const counts = {};
14865
+ for (const aggregate of Object.values(index.aggregates)) {
14866
+ for (const hash of aggregate.blobHashes) counts[hash] = (counts[hash] ?? 0) + 1;
14867
+ }
14868
+ return counts;
14869
+ }
14870
+ function cachedSize(index) {
14871
+ const blobBytes = Object.values(index.blobs).reduce((sum, entry) => sum + entry.size, 0);
14872
+ const aggregateBytes = Object.values(index.aggregates).reduce((sum, entry) => sum + entry.size, 0);
14873
+ return blobBytes + aggregateBytes;
14874
+ }
14875
+ var CacheStorageNappletArtifactCache = class {
14876
+ cacheStorage;
14877
+ storage;
14878
+ cacheName;
14879
+ baseUrl;
14880
+ now;
14881
+ activeAggregates = /* @__PURE__ */ new Set();
14882
+ onDiagnostic;
14883
+ unknownBudgetBytes;
14884
+ softCeilingBytes;
14885
+ hardCeilingBytes;
14886
+ cachePromise;
14887
+ constructor(options = {}) {
14888
+ const maybeCacheStorage = options.cacheStorage ?? globalThis.caches;
14889
+ if (!maybeCacheStorage) {
14890
+ throw new Error("Cache Storage is unavailable");
14891
+ }
14892
+ this.cacheStorage = maybeCacheStorage;
14893
+ this.storage = options.storage ?? globalThis.navigator?.storage;
14894
+ this.cacheName = options.cacheName ?? NAPPLET_ARTIFACT_CACHE_NAME;
14895
+ this.baseUrl = resolveBaseUrl(options.baseUrl);
14896
+ this.now = options.now ?? Date.now;
14897
+ this.onDiagnostic = options.onDiagnostic;
14898
+ this.unknownBudgetBytes = options.unknownBudgetBytes ?? DEFAULT_UNKNOWN_BUDGET_BYTES;
14899
+ this.softCeilingBytes = options.softCeilingBytes ?? DEFAULT_SOFT_CEILING_BYTES;
14900
+ this.hardCeilingBytes = options.hardCeilingBytes ?? DEFAULT_HARD_CEILING_BYTES;
14901
+ }
14902
+ async readBlob(sha256Hex) {
14903
+ try {
14904
+ const cache2 = await this.open();
14905
+ const response = await cache2.match(this.blobUrl(sha256Hex));
14906
+ if (!response) return void 0;
14907
+ const bytes = await responseBytes(response);
14908
+ const index = await this.readIndex(cache2);
14909
+ const entry = index.blobs[sha256Hex];
14910
+ if (entry) {
14911
+ entry.lastAccessed = this.now();
14912
+ index.updatedAt = entry.lastAccessed;
14913
+ await this.writeIndex(cache2, index);
14914
+ }
14915
+ return bytes;
14916
+ } catch (cause) {
14917
+ this.diagnostic({ type: "cache-read-failed", message: `failed to read blob ${sha256Hex}`, cause });
14918
+ return void 0;
14919
+ }
14920
+ }
14921
+ async deleteBlob(sha256Hex) {
14922
+ try {
14923
+ const cache2 = await this.open();
14924
+ await cache2.delete(this.blobUrl(sha256Hex));
14925
+ const index = await this.readIndex(cache2);
14926
+ delete index.blobs[sha256Hex];
14927
+ index.updatedAt = this.now();
14928
+ await this.writeIndex(cache2, index);
14929
+ } catch (cause) {
14930
+ this.diagnostic({ type: "cache-delete-failed", message: `failed to delete blob ${sha256Hex}`, cause });
14931
+ }
14932
+ }
14933
+ async writeVerifiedResolution(input) {
14934
+ try {
14935
+ await this.writeVerifiedResolutionOnce(input);
14936
+ } catch (firstCause) {
14937
+ try {
14938
+ await this.prune(input.now ?? this.now());
14939
+ await this.writeVerifiedResolutionOnce(input);
14940
+ } catch (cause) {
14941
+ this.diagnostic({
14942
+ type: "cache-write-failed",
14943
+ message: "failed to write verified napplet artifacts after prune retry",
14944
+ cause: cause ?? firstCause
14945
+ });
14946
+ }
14947
+ }
14948
+ }
14949
+ async writeCoordinate(input) {
14950
+ const cache2 = await this.open();
14951
+ const now2 = this.now();
14952
+ const index = await this.readIndex(cache2);
14953
+ const key = coordinateKey(input.kind, input.pubkey, input.dTag);
14954
+ index.coordinates[key] = {
14955
+ key,
14956
+ kind: input.kind,
14957
+ pubkey: input.pubkey,
14958
+ dTag: input.dTag,
14959
+ aggregateHash: input.aggregateHash,
14960
+ lastResolvedAt: input.lastResolvedAt ?? now2,
14961
+ foregroundTtlMs: input.foregroundTtlMs ?? DEFAULT_FOREGROUND_TTL_MS,
14962
+ backgroundTtlMs: input.backgroundTtlMs ?? DEFAULT_BACKGROUND_TTL_MS
14963
+ };
14964
+ index.updatedAt = now2;
14965
+ await this.writeIndex(cache2, index);
14966
+ }
14967
+ async getCoordinate(input, options = {}) {
14968
+ const cache2 = await this.open();
14969
+ const index = await this.readIndex(cache2);
14970
+ const coordinate = index.coordinates[coordinateKey(input.kind, input.pubkey, input.dTag)];
14971
+ if (!coordinate) return void 0;
14972
+ return { ...coordinate, fresh: isCoordinateFresh(coordinate, options) };
14973
+ }
14974
+ async touchAggregate(dTag, aggregateHash, now2 = this.now()) {
14975
+ const cache2 = await this.open();
14976
+ const index = await this.readIndex(cache2);
14977
+ const key = aggregateKey(dTag, aggregateHash);
14978
+ const aggregate = index.aggregates[key];
14979
+ if (!aggregate) return;
14980
+ aggregate.lastAccessed = now2;
14981
+ for (const hash of aggregate.blobHashes) {
14982
+ if (index.blobs[hash]) index.blobs[hash].lastAccessed = now2;
14983
+ }
14984
+ index.updatedAt = now2;
14985
+ await this.writeIndex(cache2, index);
14986
+ }
14987
+ markAggregateActive(dTag, aggregateHash) {
14988
+ this.activeAggregates.add(aggregateKey(dTag, aggregateHash));
14989
+ }
14990
+ releaseAggregateActive(dTag, aggregateHash) {
14991
+ this.activeAggregates.delete(aggregateKey(dTag, aggregateHash));
14992
+ }
14993
+ async prune(now2 = this.now()) {
14994
+ try {
14995
+ const cache2 = await this.open();
14996
+ const index = await this.readIndex(cache2);
14997
+ let size = cachedSize(index);
14998
+ const budget = await this.budgetBytes();
14999
+ const hardBudget = await this.hardBudgetBytes();
15000
+ const shouldPrune = size > budget || await this.originPressureHigh();
15001
+ if (!shouldPrune) return;
15002
+ this.rewriteRefCounts(index);
15003
+ for (const [hash, blob] of Object.entries(index.blobs)) {
15004
+ if (size <= budget) break;
15005
+ if (blob.refCount > 0) continue;
15006
+ await cache2.delete(this.blobUrl(hash));
15007
+ delete index.blobs[hash];
15008
+ size -= blob.size;
15009
+ }
15010
+ const currentAggregateHashes = new Set(
15011
+ Object.values(index.coordinates).map((coordinate) => coordinate.aggregateHash)
15012
+ );
15013
+ const aggregates = Object.values(index.aggregates).filter((entry) => !this.activeAggregates.has(entry.key)).sort((a, b) => {
15014
+ const currentA = currentAggregateHashes.has(a.aggregateHash) ? 1 : 0;
15015
+ const currentB = currentAggregateHashes.has(b.aggregateHash) ? 1 : 0;
15016
+ if (currentA !== currentB) return currentA - currentB;
15017
+ return a.lastAccessed - b.lastAccessed;
15018
+ });
15019
+ for (const aggregate of aggregates) {
15020
+ if (size <= budget) break;
15021
+ await cache2.delete(this.aggregateUrl(aggregate.key));
15022
+ delete index.aggregates[aggregate.key];
15023
+ size -= aggregate.size;
15024
+ this.rewriteRefCounts(index);
15025
+ }
15026
+ if (size > hardBudget) {
15027
+ const active = Object.values(index.aggregates).filter((entry) => this.activeAggregates.has(entry.key)).sort((a, b) => a.lastAccessed - b.lastAccessed);
15028
+ for (const aggregate of active) {
15029
+ if (size <= hardBudget) break;
15030
+ await cache2.delete(this.aggregateUrl(aggregate.key));
15031
+ delete index.aggregates[aggregate.key];
15032
+ size -= aggregate.size;
15033
+ }
15034
+ }
15035
+ this.rewriteRefCounts(index);
15036
+ for (const [hash, blob] of Object.entries(index.blobs)) {
15037
+ if (blob.refCount === 0) {
15038
+ await cache2.delete(this.blobUrl(hash));
15039
+ delete index.blobs[hash];
15040
+ }
15041
+ }
15042
+ index.updatedAt = now2;
15043
+ await this.writeIndex(cache2, index);
15044
+ } catch (cause) {
15045
+ this.diagnostic({ type: "cache-prune-failed", message: "failed to prune napplet artifact cache", cause });
15046
+ }
15047
+ }
15048
+ async snapshotIndex() {
15049
+ return this.readIndex(await this.open());
15050
+ }
15051
+ async writeVerifiedResolutionOnce(input) {
15052
+ const cache2 = await this.open();
15053
+ const now2 = input.now ?? this.now();
15054
+ const index = await this.readIndex(cache2);
15055
+ const blobHashes = [];
15056
+ for (const pathEntry of input.manifest.paths) {
15057
+ const bytes = input.files.get(pathEntry.path);
15058
+ if (!bytes) continue;
15059
+ blobHashes.push(pathEntry.sha256);
15060
+ await cache2.put(this.blobUrl(pathEntry.sha256), new Response(responseBody(bytes)));
15061
+ index.blobs[pathEntry.sha256] = {
15062
+ size: byteLength2(bytes),
15063
+ lastAccessed: now2,
15064
+ refCount: index.blobs[pathEntry.sha256]?.refCount ?? 0
15065
+ };
15066
+ }
15067
+ const key = aggregateKey(input.manifest.dTag, input.manifest.aggregateHash);
15068
+ const record = {
15069
+ schemaVersion: SCHEMA_VERSION,
15070
+ dTag: input.manifest.dTag,
15071
+ aggregateHash: input.manifest.aggregateHash,
15072
+ manifest: {
15073
+ kind: input.manifest.kind,
15074
+ pubkey: input.manifest.pubkey,
15075
+ dTag: input.manifest.dTag,
15076
+ paths: input.manifest.paths.map((entry) => ({ path: entry.path, sha256: entry.sha256 })),
15077
+ requires: [...input.manifest.requires],
15078
+ ...input.manifest.title === void 0 ? {} : { title: input.manifest.title },
15079
+ ...input.manifest.description === void 0 ? {} : { description: input.manifest.description }
15080
+ },
15081
+ indexHtml: input.indexHtml,
15082
+ blobHashes,
15083
+ writtenAt: now2
15084
+ };
15085
+ const aggregateBytes = new TextEncoder().encode(JSON.stringify(record));
15086
+ await cache2.put(this.aggregateUrl(key), new Response(responseBody(aggregateBytes), {
15087
+ headers: { "content-type": "application/json" }
15088
+ }));
15089
+ const coordKey = coordinateKey(input.manifest.kind, input.manifest.pubkey, input.manifest.dTag);
15090
+ index.aggregates[key] = {
15091
+ dTag: input.manifest.dTag,
15092
+ aggregateHash: input.manifest.aggregateHash,
15093
+ key,
15094
+ blobHashes,
15095
+ size: byteLength2(aggregateBytes),
15096
+ lastAccessed: now2,
15097
+ coordinateKey: coordKey
15098
+ };
15099
+ index.coordinates[coordKey] = {
15100
+ key: coordKey,
15101
+ kind: input.manifest.kind,
15102
+ pubkey: input.manifest.pubkey,
15103
+ dTag: input.manifest.dTag,
15104
+ aggregateHash: input.manifest.aggregateHash,
15105
+ lastResolvedAt: now2,
15106
+ foregroundTtlMs: DEFAULT_FOREGROUND_TTL_MS,
15107
+ backgroundTtlMs: DEFAULT_BACKGROUND_TTL_MS
15108
+ };
15109
+ this.rewriteRefCounts(index);
15110
+ index.updatedAt = now2;
15111
+ await this.writeIndex(cache2, index);
15112
+ await this.prune(now2);
15113
+ }
15114
+ async open() {
15115
+ this.cachePromise ??= this.cacheStorage.open(this.cacheName);
15116
+ return this.cachePromise;
15117
+ }
15118
+ indexUrl() {
15119
+ return new URL("__kehto_napplet_cache/index.json", this.baseUrl).toString();
15120
+ }
15121
+ blobUrl(hash) {
15122
+ return new URL(`__kehto_napplet_cache/blob/${encodeKeyPart(hash)}`, this.baseUrl).toString();
15123
+ }
15124
+ aggregateUrl(key) {
15125
+ return new URL(`__kehto_napplet_cache/aggregate/${encodeKeyPart(key)}.json`, this.baseUrl).toString();
15126
+ }
15127
+ async readIndex(cache2) {
15128
+ const response = await cache2.match(this.indexUrl());
15129
+ if (!response) return emptyIndex(this.now());
15130
+ try {
15131
+ const index = await responseJson(response);
15132
+ if (index.schemaVersion !== SCHEMA_VERSION) return emptyIndex(this.now());
15133
+ return index;
15134
+ } catch {
15135
+ return emptyIndex(this.now());
15136
+ }
15137
+ }
15138
+ async writeIndex(cache2, index) {
15139
+ await cache2.put(this.indexUrl(), new Response(JSON.stringify(index), {
15140
+ headers: { "content-type": "application/json" }
15141
+ }));
15142
+ }
15143
+ rewriteRefCounts(index) {
15144
+ const counts = refCounts(index);
15145
+ for (const [hash, blob] of Object.entries(index.blobs)) {
15146
+ blob.refCount = counts[hash] ?? 0;
15147
+ }
15148
+ }
15149
+ async budgetBytes() {
15150
+ const estimate = await this.estimateStorage();
15151
+ if (!estimate?.quota) return this.unknownBudgetBytes;
15152
+ return Math.min(this.softCeilingBytes, Math.floor(estimate.quota * 0.1));
15153
+ }
15154
+ async hardBudgetBytes() {
15155
+ const estimate = await this.estimateStorage();
15156
+ if (!estimate?.quota) return this.unknownBudgetBytes;
15157
+ return Math.min(this.hardCeilingBytes, Math.floor(estimate.quota * 0.2));
15158
+ }
15159
+ async originPressureHigh() {
15160
+ const estimate = await this.estimateStorage();
15161
+ if (!estimate?.quota || estimate.usage === void 0) return false;
15162
+ return estimate.usage / estimate.quota >= 0.8;
15163
+ }
15164
+ async estimateStorage() {
15165
+ if (!this.storage?.estimate) return void 0;
15166
+ try {
15167
+ return this.storage.estimate();
15168
+ } catch (cause) {
15169
+ this.diagnostic({
15170
+ type: "storage-estimate-unavailable",
15171
+ message: "storage estimate failed; using unknown quota cache budget",
15172
+ cause
15173
+ });
15174
+ return void 0;
15175
+ }
15176
+ }
15177
+ diagnostic(diagnostic) {
15178
+ this.onDiagnostic?.(diagnostic);
15179
+ }
15180
+ };
15181
+ async function openNappletArtifactCache(options = {}) {
15182
+ const cacheStorage = options.cacheStorage ?? globalThis.caches;
15183
+ if (!cacheStorage) return void 0;
15184
+ const storage = options.storage ?? globalThis.navigator?.storage;
15185
+ if (options.requireStorageEstimate && !storage?.estimate) {
15186
+ options.onDiagnostic?.({
15187
+ type: "storage-estimate-unavailable",
15188
+ message: "storage estimates are unavailable; using network-only loading"
15189
+ });
15190
+ return void 0;
15191
+ }
15192
+ try {
15193
+ const cache2 = new CacheStorageNappletArtifactCache({ ...options, cacheStorage, storage });
15194
+ await cache2.snapshotIndex();
15195
+ return cache2;
15196
+ } catch (cause) {
15197
+ options.onDiagnostic?.({
15198
+ type: "cache-open-failed",
15199
+ message: "Cache Storage napplet artifact cache could not be opened",
15200
+ cause
15201
+ });
15202
+ return void 0;
15203
+ }
15204
+ }
15205
+ var NAPPLET_KIND_SNAPSHOT = 5129;
15206
+ var NAPPLET_KIND_ROOT = 15129;
15207
+ var NAPPLET_KIND_NAMED = 35129;
15208
+ var NAPPLET_KINDS = [
15209
+ NAPPLET_KIND_SNAPSHOT,
15210
+ NAPPLET_KIND_ROOT,
15211
+ NAPPLET_KIND_NAMED
15212
+ ];
15213
+ function isNappletManifestKind(kind) {
15214
+ return NAPPLET_KINDS.includes(kind);
15215
+ }
15216
+ var NappletResolutionError = class extends Error {
15217
+ code;
15218
+ constructor(code, message) {
15219
+ super(message);
15220
+ this.name = "NappletResolutionError";
15221
+ this.code = code;
15222
+ }
15223
+ };
15224
+ function firstTagValue(tags, name) {
15225
+ for (const tag of tags) {
15226
+ if (tag[0] === name && typeof tag[1] === "string" && tag[1].length > 0) return tag[1];
15227
+ }
15228
+ return void 0;
15229
+ }
15230
+ function allTagValues(tags, name) {
15231
+ const out = [];
15232
+ for (const tag of tags) {
15233
+ if (tag[0] === name && typeof tag[1] === "string" && tag[1].length > 0) out.push(tag[1]);
15234
+ }
15235
+ return out;
15236
+ }
15237
+ function archetypesFromTags(tags) {
15238
+ const out = [];
15239
+ for (const tag of tags) {
15240
+ if (tag[0] !== "archetype") continue;
15241
+ if (typeof tag[1] !== "string" || tag[1].length === 0) continue;
15242
+ out.push(
15243
+ typeof tag[2] === "string" && tag[2].length > 0 ? { slug: tag[1], nap: tag[2] } : { slug: tag[1] }
15244
+ );
15245
+ }
15246
+ return out;
15247
+ }
15248
+ function parseNappletManifest(event) {
15249
+ if (!isNappletManifestKind(event.kind)) {
15250
+ throw new NappletResolutionError("invalid-manifest", `not a NIP-5D napplet kind: ${event.kind}`);
15251
+ }
15252
+ const paths = pathEntriesFromTags(event.tags);
15253
+ if (paths.length === 0) {
15254
+ throw new NappletResolutionError("invalid-manifest", "manifest has no path tags");
15255
+ }
15256
+ const aggregateHash = aggregateTagValue(event.tags);
15257
+ if (!aggregateHash) {
15258
+ throw new NappletResolutionError("invalid-manifest", "manifest has no aggregate x tag");
15259
+ }
15260
+ return {
15261
+ kind: event.kind,
15262
+ pubkey: event.pubkey,
15263
+ dTag: firstTagValue(event.tags, "d") ?? "",
15264
+ paths,
15265
+ aggregateHash,
15266
+ servers: allTagValues(event.tags, "server"),
15267
+ requires: allTagValues(event.tags, "requires"),
15268
+ archetypes: archetypesFromTags(event.tags),
15269
+ title: firstTagValue(event.tags, "title"),
15270
+ description: firstTagValue(event.tags, "description"),
15271
+ source: firstTagValue(event.tags, "source")
15272
+ };
15273
+ }
15274
+ function verifyManifestSignature(event) {
15275
+ try {
15276
+ return verifyEvent(event);
15277
+ } catch {
15278
+ return false;
15279
+ }
15280
+ }
15281
+ function verifyBlobHash(bytes, sha256Hex) {
15282
+ return bytesToHex2(sha256(bytes)) === sha256Hex;
15283
+ }
15284
+ function stripTrailingSlash(url) {
15285
+ return url.endsWith("/") ? url.slice(0, -1) : url;
15286
+ }
15287
+ async function fetchBlob(servers, sha256Hex, fetchBytes) {
15288
+ for (const server of servers) {
15289
+ const url = `${stripTrailingSlash(server)}/${sha256Hex}`;
15290
+ try {
15291
+ const bytes = await fetchBytes(url);
15292
+ if (verifyBlobHash(bytes, sha256Hex)) return bytes;
15293
+ } catch {
15294
+ }
15295
+ }
15296
+ throw new NappletResolutionError("blob-unavailable", `no server served blob ${sha256Hex}`);
15297
+ }
15298
+ var INDEX_PATHS = ["/index.html", "index.html", "/"];
15299
+ function defaultDecode(bytes) {
15300
+ return new TextDecoder().decode(bytes);
15301
+ }
15302
+ async function resolveNapplet(options) {
15303
+ const { event, fetchBlob: fetchBlobBytes, textDecode = defaultDecode, cache: cache2 } = options;
15304
+ if (!verifyManifestSignature(event)) {
15305
+ throw new NappletResolutionError("invalid-signature", "manifest signature is invalid");
15306
+ }
15307
+ const manifest = parseNappletManifest(event);
15308
+ const recomputed = computeAggregateHash(manifest.paths);
15309
+ if (recomputed !== manifest.aggregateHash) {
15310
+ throw new NappletResolutionError(
15311
+ "aggregate-mismatch",
15312
+ `recomputed aggregate ${recomputed} != manifest ${manifest.aggregateHash}`
15313
+ );
15314
+ }
15315
+ const files = /* @__PURE__ */ new Map();
15316
+ for (const entry of manifest.paths) {
15317
+ let bytes = await cache2?.readBlob(entry.sha256);
15318
+ if (bytes && !verifyBlobHash(bytes, entry.sha256)) {
15319
+ await cache2?.deleteBlob(entry.sha256);
15320
+ bytes = void 0;
15321
+ }
15322
+ bytes ??= await fetchBlobBytes(entry.sha256, manifest.servers);
15323
+ if (!verifyBlobHash(bytes, entry.sha256)) {
15324
+ throw new NappletResolutionError(
15325
+ "blob-hash-mismatch",
15326
+ `blob for ${entry.path} does not match hash ${entry.sha256}`
15327
+ );
15328
+ }
15329
+ files.set(entry.path, bytes);
15330
+ }
15331
+ const indexEntry = manifest.paths.find((e) => INDEX_PATHS.includes(e.path));
15332
+ if (!indexEntry) {
15333
+ throw new NappletResolutionError("missing-index", "manifest has no /index.html entry");
15334
+ }
15335
+ const indexHtml = textDecode(files.get(indexEntry.path));
15336
+ await cache2?.writeVerifiedResolution({ event, manifest, files, indexHtml });
15337
+ return {
15338
+ dTag: manifest.dTag,
15339
+ aggregateHash: manifest.aggregateHash,
15340
+ files,
15341
+ indexHtml,
15342
+ manifest
15343
+ };
15344
+ }
15345
+
15346
+ // src/runtime-resolver.ts
15347
+ var PAJA_NAPPLET_MANIFEST_KIND = 35129;
15348
+ function decodePajaPointer(value) {
15349
+ const trimmed = value.trim();
15350
+ const decoded = decode(trimmed);
15351
+ if (decoded.type === "naddr") {
15352
+ return {
15353
+ type: "naddr",
15354
+ value: trimmed,
15355
+ identifier: decoded.data.identifier,
15356
+ pubkey: decoded.data.pubkey,
15357
+ kind: decoded.data.kind,
15358
+ relays: [...decoded.data.relays ?? []]
15359
+ };
15360
+ }
15361
+ if (decoded.type === "nevent") {
15362
+ return {
15363
+ type: "nevent",
15364
+ value: trimmed,
15365
+ id: decoded.data.id,
15366
+ ...decoded.data.author ? { author: decoded.data.author } : {},
15367
+ ...decoded.data.kind ? { kind: decoded.data.kind } : {},
15368
+ relays: [...decoded.data.relays ?? []]
15369
+ };
15370
+ }
15371
+ throw new Error(`Expected naddr or nevent pointer, got ${decoded.type}.`);
15372
+ }
15373
+ async function resolvePajaPointer(value, options = {}) {
15374
+ const pointer = decodePajaPointer(value);
15375
+ const relays = uniqueRelayUrls([...pointer.relays, ...options.relays ?? []]);
15376
+ if (relays.length === 0) {
15377
+ throw new Error("Pointer does not include relay hints; add a relay-bearing naddr or nevent.");
15378
+ }
15379
+ const pool = options.pool ?? new SimplePool();
15380
+ const ownsPool = options.pool === void 0;
15381
+ try {
15382
+ const event = await resolvePointerEvent(pointer, pool, relays, options.maxWaitMs ?? 5e3);
15383
+ const blossomServers = [...options.blossomServers ?? []];
15384
+ const resolved = await resolveNapplet({
15385
+ event,
15386
+ cache: await openNappletArtifactCache({ requireStorageEstimate: false }),
15387
+ fetchBlob: (sha256Hex, servers) => fetchBlob([...servers, ...blossomServers], sha256Hex, async (url) => {
15388
+ const response = await (options.fetcher ?? fetch)(url);
15389
+ if (!response.ok) throw new Error(`[paja-runtime] blob ${url}: ${response.status}`);
15390
+ return new Uint8Array(await response.arrayBuffer());
15391
+ })
15392
+ });
15393
+ return {
15394
+ pointer,
15395
+ event,
15396
+ relays,
15397
+ blossomServers,
15398
+ dTag: resolved.dTag,
15399
+ aggregateHash: resolved.aggregateHash,
15400
+ indexHtml: resolved.indexHtml,
15401
+ manifest: resolved.manifest
15402
+ };
15403
+ } finally {
15404
+ if (ownsPool) {
15405
+ pool.close?.(relays);
15406
+ pool.destroy?.();
15407
+ }
15408
+ }
15409
+ }
15410
+ function injectPajaRuntimeCsp(html, origins) {
15411
+ const value = origins.length > 0 ? `connect-src ${[...new Set(origins)].sort().join(" ")}` : "connect-src 'none'";
15412
+ const meta = `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(value)}">`;
15413
+ if (/<head[^>]*>/i.test(html)) {
15414
+ return html.replace(/<head[^>]*>/i, (open) => `${open}${meta}`);
15415
+ }
15416
+ if (/<html[^>]*>/i.test(html)) {
15417
+ return html.replace(/<html[^>]*>/i, (open) => `${open}<head>${meta}</head>`);
15418
+ }
15419
+ return `${meta}${html}`;
15420
+ }
15421
+ async function resolvePointerEvent(pointer, pool, relays, maxWaitMs) {
15422
+ const filter = pointer.type === "naddr" ? addressableFilter(pointer) : eventFilter(pointer);
15423
+ const events = await pool.querySync([...relays], filter, {
15424
+ maxWait: maxWaitMs,
15425
+ label: "kehto-paja-runtime"
15426
+ });
15427
+ const event = events.filter((candidate) => matchesPointer(pointer, candidate)).sort((a, b) => b.created_at - a.created_at)[0];
15428
+ if (!event) {
15429
+ throw new Error(`No napplet manifest event found for ${pointer.type} pointer.`);
15430
+ }
15431
+ if (event.kind !== PAJA_NAPPLET_MANIFEST_KIND) {
15432
+ throw new Error(`Pointer resolved kind ${event.kind}; expected ${PAJA_NAPPLET_MANIFEST_KIND}.`);
15433
+ }
15434
+ return event;
15435
+ }
15436
+ function addressableFilter(pointer) {
15437
+ if (pointer.kind !== PAJA_NAPPLET_MANIFEST_KIND) {
15438
+ throw new Error(`naddr kind ${pointer.kind} is not a napplet manifest kind.`);
15439
+ }
15440
+ return {
15441
+ kinds: [PAJA_NAPPLET_MANIFEST_KIND],
15442
+ authors: [pointer.pubkey],
15443
+ "#d": [pointer.identifier],
15444
+ limit: 1
15445
+ };
15446
+ }
15447
+ function eventFilter(pointer) {
15448
+ return {
15449
+ ids: [pointer.id],
15450
+ ...pointer.kind ? { kinds: [pointer.kind] } : {},
15451
+ ...pointer.author ? { authors: [pointer.author] } : {},
15452
+ limit: 1
15453
+ };
15454
+ }
15455
+ function matchesPointer(pointer, event) {
15456
+ if (pointer.type === "nevent") {
15457
+ if (event.id !== pointer.id) return false;
15458
+ if (pointer.author && event.pubkey !== pointer.author) return false;
15459
+ if (pointer.kind && event.kind !== pointer.kind) return false;
15460
+ return true;
15461
+ }
15462
+ return event.kind === pointer.kind && event.pubkey === pointer.pubkey && event.tags.some((tag) => tag[0] === "d" && tag[1] === pointer.identifier);
15463
+ }
15464
+ function uniqueRelayUrls(values) {
15465
+ const out = [];
15466
+ const seen = /* @__PURE__ */ new Set();
15467
+ for (const value of values) {
15468
+ const url = normalizeRelayUrl(value);
15469
+ if (!url || seen.has(url)) continue;
15470
+ seen.add(url);
15471
+ out.push(url);
15472
+ }
15473
+ return out;
15474
+ }
15475
+ function normalizeRelayUrl(value) {
15476
+ const raw = value.trim();
15477
+ if (!raw) return void 0;
15478
+ try {
15479
+ const url = new URL(raw);
15480
+ if (url.protocol !== "wss:" && url.protocol !== "ws:") return void 0;
15481
+ url.hash = "";
15482
+ url.search = "";
15483
+ return url.href.replace(/\/$/, "");
15484
+ } catch {
15485
+ return void 0;
15486
+ }
15487
+ }
15488
+ function escapeAttribute(value) {
15489
+ return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
15490
+ }
15491
+
15492
+ // src/browser-host.ts
15493
+ var bridgeRef = null;
15494
+ function readConfig() {
15495
+ const script = document.getElementById("kehto-paja-config");
15496
+ if (!script?.textContent) {
15497
+ throw new Error("Missing Kehto Paja config.");
15498
+ }
15499
+ return JSON.parse(script.textContent);
15500
+ }
15501
+ async function readLatestConfig(fallback) {
15502
+ try {
15503
+ const response = await fetch(new URL("./__kehto/config.json", window.location.href), { cache: "no-store" });
15504
+ if (!response.ok) return fallback;
15505
+ return await response.json();
15506
+ } catch (error) {
15507
+ console.warn("[paja] config refresh failed; using embedded config", error);
15508
+ return fallback;
15509
+ }
15510
+ }
15511
+ function setTargetUrlDisplay(config, frame) {
15512
+ const label = getTargetLabel(config);
15513
+ const targetEl = document.querySelector(".target");
15514
+ if (targetEl) {
15515
+ targetEl.textContent = label;
15516
+ targetEl.setAttribute("title", label);
15517
+ }
15518
+ frame.dataset.targetUrl = label;
15519
+ }
15520
+ function getTargetLabel(config) {
15521
+ if (config.target.mode === "runtime-pointer") return config.target.pointer?.value ?? "runtime pointer";
15522
+ return config.target.url;
15523
+ }
15524
+ function readInitialPointerValue(config) {
15525
+ if (config.target.mode !== "runtime-pointer") return "";
15526
+ const params = new URLSearchParams(window.location.search);
15527
+ return params.get("naddr") ?? params.get("nevent") ?? params.get("pointer") ?? config.target.pointer?.value ?? "";
15528
+ }
15529
+ function connectOrigins(urls) {
15530
+ const out = /* @__PURE__ */ new Set();
15531
+ for (const value of urls) {
15532
+ try {
15533
+ const url = new URL(value);
15534
+ if (url.protocol === "wss:" || url.protocol === "ws:") {
15535
+ out.add(value.replace(/\/$/, ""));
15536
+ } else {
15537
+ out.add(url.origin);
15538
+ }
15539
+ } catch {
15540
+ }
15541
+ }
15542
+ return [...out];
15543
+ }
15544
+ function setStatus(state, status) {
15545
+ state.status = status;
15546
+ const statusEl = document.getElementById("lifecycle-status");
15547
+ if (statusEl) statusEl.textContent = status;
15548
+ }
15549
+ function setSimulationStatus(state) {
15550
+ const statusEl = document.getElementById("simulation-status");
15551
+ if (statusEl) statusEl.textContent = summarizePajaSimulation(state.simulation);
15552
+ const themeSelect = document.getElementById("simulation-theme");
15553
+ if (themeSelect instanceof HTMLSelectElement) themeSelect.value = state.simulation.theme.mode;
15554
+ renderPajaDevtools(state, { bridge: bridgeRef, devSignerPubkey: PAJA_DEV_SIGNER_PUBKEY });
15555
+ }
15556
+ function setPointerStatus(state, message) {
15557
+ state.pointerStatus = message;
15558
+ const statusEl = document.getElementById("runtime-pointer-status");
15559
+ if (statusEl) statusEl.textContent = message;
15560
+ }
15561
+ function getFrame() {
15562
+ const frame = document.getElementById("napplet-frame");
15563
+ if (!(frame instanceof HTMLIFrameElement)) {
15564
+ throw new Error("Missing Kehto Paja iframe.");
15565
+ }
15566
+ frame.sandbox.add("allow-scripts");
15567
+ frame.sandbox.remove("allow-same-origin");
15568
+ return frame;
15569
+ }
15570
+ function confirmPajaRequest(state, request) {
15571
+ const event = request.event;
15572
+ const kind = typeof event.kind === "number" ? event.kind : "unknown";
15573
+ const content = typeof event.content === "string" && event.content.length > 0 ? `
15574
+
15575
+ ${event.content.slice(0, 240)}` : "";
15576
+ const allowed = window.confirm(`Paja ${request.action} request
15577
+ kind: ${kind}${content}`);
15578
+ appendPajaMessageLog(state, "paja", {
15579
+ type: `paja.${request.action}.${allowed ? "confirmed" : "denied"}`,
15580
+ kind
15581
+ });
15582
+ return allowed;
15583
+ }
15584
+ function getTargetIdentity2(config, resolvedTarget) {
15585
+ return {
15586
+ pubkey: "",
15587
+ dTag: resolvedTarget?.dTag ?? config.window.dTag,
15588
+ aggregateHash: resolvedTarget?.aggregateHash ?? config.window.aggregateHash
15589
+ };
15590
+ }
15591
+ function registerFrameForGeneration(bridge, frame, config, generation, resolvedTarget) {
15592
+ const win = frame.contentWindow;
15593
+ if (!win) return null;
15594
+ const windowId = `${config.window.id}:${generation}`;
15595
+ const identity = getTargetIdentity2(config, resolvedTarget);
15596
+ originRegistry.register(win, windowId, {
15597
+ dTag: identity.dTag,
15598
+ aggregateHash: identity.aggregateHash
15599
+ });
15600
+ bridge.runtime.sessionRegistry.register(windowId, {
15601
+ ...identity,
15602
+ windowId,
15603
+ origin: "null",
15604
+ type: "napplet",
15605
+ registeredAt: Date.now(),
15606
+ instanceId: `${windowId}:${Date.now()}`,
15607
+ provenance: "nip-5d"
15608
+ });
15609
+ return windowId;
15610
+ }
15611
+ function navigateFrame(bridge, frame, config, generation, resolvedTarget) {
15612
+ if (config.target.mode === "runtime-pointer") {
15613
+ if (!resolvedTarget) {
15614
+ frame.removeAttribute("src");
15615
+ frame.srcdoc = "<!doctype html><html><body></body></html>";
15616
+ return null;
15617
+ }
15618
+ const windowId2 = registerFrameForGeneration(bridge, frame, config, generation, resolvedTarget);
15619
+ frame.removeAttribute("src");
15620
+ frame.srcdoc = injectPajaRuntimeCsp(
15621
+ resolvedTarget.indexHtml,
15622
+ connectOrigins([...resolvedTarget.relays, ...resolvedTarget.blossomServers])
15623
+ );
15624
+ return windowId2;
15625
+ }
15626
+ const windowId = registerFrameForGeneration(bridge, frame, config, generation, resolvedTarget);
15627
+ frame.src = config.target.url;
15628
+ return windowId;
15629
+ }
15630
+ function createHostSignerController(getState) {
15631
+ return createPajaSignerController({
15632
+ confirmRequest: (request) => confirmPajaRequest(getState(), request),
15633
+ onChange(signer) {
15634
+ const state = getState();
15635
+ if (!state) return;
15636
+ state.signer = signer;
15637
+ appendPajaMessageLog(state, "paja", {
15638
+ type: `paja.signer.${signer.method}.${signer.status}`,
15639
+ pubkey: signer.pubkey,
15640
+ relay: signer.relay,
15641
+ error: signer.error
15642
+ });
15643
+ setSimulationStatus(state);
15644
+ if (signer.status === "connected") state.reload();
15645
+ }
15646
+ });
15647
+ }
15648
+ function installPajaControlListeners(state) {
15649
+ document.getElementById("reload-target")?.addEventListener("click", () => {
15650
+ state.reload();
15651
+ });
15652
+ document.getElementById("simulation-theme")?.addEventListener("change", (event) => {
15653
+ const target = event.target;
15654
+ if (!(target instanceof HTMLSelectElement)) return;
15655
+ if (target.value === "dark" || target.value === "light") {
15656
+ state.setThemeMode(target.value);
15657
+ }
15658
+ });
15659
+ document.getElementById("message-filter")?.addEventListener("input", (event) => {
15660
+ const target = event.target;
15661
+ if (!(target instanceof HTMLInputElement)) return;
15662
+ state.messageFilter = target.value;
15663
+ renderPajaMessageLog(state);
15664
+ });
15665
+ document.getElementById("clear-log")?.addEventListener("click", () => {
15666
+ state.clearLog();
15667
+ });
15668
+ document.getElementById("runtime-pointer-form")?.addEventListener("submit", (event) => {
15669
+ event.preventDefault();
15670
+ const input = document.getElementById("runtime-pointer-input");
15671
+ if (!(input instanceof HTMLInputElement)) return;
15672
+ void state.loadPointer(input.value);
15673
+ });
15674
+ }
15675
+ function createPajaBrowserState(context) {
15676
+ const { config, frame, bridge, adapter, signerController, capabilities, runtime } = context;
15677
+ return {
15678
+ config,
15679
+ capabilities,
15680
+ services: Object.keys(adapter.services ?? {}).sort(),
15681
+ simulation: runtime.currentSimulation,
15682
+ signer: signerController.getState(),
15683
+ resolvedTarget: null,
15684
+ pointerValue: readInitialPointerValue(config),
15685
+ pointerStatus: config.target.mode === "runtime-pointer" ? "idle" : "",
15686
+ generation: 0,
15687
+ status: "booting",
15688
+ messageFilter: "",
15689
+ messageLog: [],
15690
+ reload() {
15691
+ if (runtime.currentWindowId) {
15692
+ bridge.runtime.destroyWindow(runtime.currentWindowId);
15693
+ bridge.runtime.sessionRegistry.unregister(runtime.currentWindowId);
15694
+ originRegistry.unregister(runtime.currentWindowId);
15695
+ }
15696
+ this.generation += 1;
15697
+ runtime.initReceivedGeneration = -1;
15698
+ setStatus(this, "reloading");
15699
+ runtime.currentWindowId = navigateFrame(bridge, frame, config, this.generation, this.resolvedTarget);
15700
+ },
15701
+ setThemeMode(mode) {
15702
+ runtime.currentSimulation = {
15703
+ ...runtime.currentSimulation,
15704
+ theme: {
15705
+ ...runtime.currentSimulation.theme,
15706
+ mode
15707
+ }
15708
+ };
15709
+ this.simulation = runtime.currentSimulation;
15710
+ runtime.themeService?.publishTheme(createDevTheme(runtime.currentSimulation.theme.mode, runtime.currentSimulation.theme.values));
15711
+ setSimulationStatus(this);
15712
+ },
14035
15713
  setDomainEnabled(domain, enabled) {
14036
- currentSimulation = {
14037
- ...currentSimulation,
15714
+ runtime.currentSimulation = {
15715
+ ...runtime.currentSimulation,
14038
15716
  capabilities: {
14039
15717
  domains: {
14040
- ...currentSimulation.capabilities.domains,
15718
+ ...runtime.currentSimulation.capabilities.domains,
14041
15719
  [domain]: enabled
14042
15720
  },
14043
15721
  disabledDomains: PAJA_SIMULATION_DOMAINS.filter(
14044
- (entry) => entry === domain ? !enabled : !currentSimulation.capabilities.domains[entry]
15722
+ (entry) => entry === domain ? !enabled : !runtime.currentSimulation.capabilities.domains[entry]
14045
15723
  )
14046
15724
  }
14047
15725
  };
14048
- this.simulation = currentSimulation;
14049
- this.services = Object.keys(adapter.services ?? {}).filter((name) => currentSimulation.capabilities.domains[name] !== false).sort();
15726
+ this.simulation = runtime.currentSimulation;
15727
+ this.services = Object.keys(adapter.services ?? {}).filter((name) => runtime.currentSimulation.capabilities.domains[name] !== false).sort();
14050
15728
  setSimulationStatus(this);
14051
15729
  appendPajaMessageLog(this, "paja", { type: `paja.interface.${enabled ? "enabled" : "disabled"}`, domain });
14052
15730
  this.reload();
14053
15731
  },
14054
15732
  setAclCapability(capability, enabled) {
14055
- const identity = getTargetIdentity2(config);
15733
+ const identity = getTargetIdentity2(config, this.resolvedTarget);
14056
15734
  if (enabled) bridge.runtime.aclState.grant(identity.pubkey, identity.dTag, identity.aggregateHash, capability);
14057
15735
  else bridge.runtime.aclState.revoke(identity.pubkey, identity.dTag, identity.aggregateHash, capability);
14058
15736
  bridge.runtime.aclState.persist();
@@ -14068,6 +15746,40 @@ async function installPajaHost() {
14068
15746
  connectBunker(uri) {
14069
15747
  return signerController.connectBunker(uri);
14070
15748
  },
15749
+ async loadPointer(value) {
15750
+ if (config.target.mode !== "runtime-pointer") return;
15751
+ const pointer = value.trim();
15752
+ const input = document.getElementById("runtime-pointer-input");
15753
+ if (input instanceof HTMLInputElement) input.value = pointer;
15754
+ this.pointerValue = pointer;
15755
+ if (!pointer) {
15756
+ setPointerStatus(this, "idle");
15757
+ return;
15758
+ }
15759
+ setPointerStatus(this, "resolving");
15760
+ setStatus(this, "booting");
15761
+ appendPajaMessageLog(this, "paja", { type: "paja.pointer.resolve", pointer });
15762
+ try {
15763
+ this.resolvedTarget = await resolvePajaPointer(pointer, {
15764
+ relays: config.target.pointer?.relays ?? [],
15765
+ blossomServers: config.target.pointer?.blossomServers ?? [],
15766
+ maxWaitMs: config.target.pointer?.maxWaitMs
15767
+ });
15768
+ setPointerStatus(this, `${this.resolvedTarget.dTag}:${this.resolvedTarget.aggregateHash.slice(0, 12)}`);
15769
+ appendPajaMessageLog(this, "paja", {
15770
+ type: "paja.pointer.resolved",
15771
+ dTag: this.resolvedTarget.dTag,
15772
+ aggregateHash: this.resolvedTarget.aggregateHash
15773
+ });
15774
+ this.reload();
15775
+ } catch (error) {
15776
+ const message = error instanceof Error ? error.message : String(error);
15777
+ this.resolvedTarget = null;
15778
+ setPointerStatus(this, message);
15779
+ setStatus(this, "error");
15780
+ appendPajaMessageLog(this, "paja", { type: "paja.pointer.error", error: message });
15781
+ }
15782
+ },
14071
15783
  clearLog() {
14072
15784
  this.messageLog.length = 0;
14073
15785
  renderPajaMessageLog(this);
@@ -14077,20 +15789,52 @@ async function installPajaHost() {
14077
15789
  generation: this.generation,
14078
15790
  status: this.status,
14079
15791
  iframeCount: document.querySelectorAll("iframe").length,
14080
- initSent: initReceivedGeneration === this.generation,
15792
+ initSent: runtime.initReceivedGeneration === this.generation,
14081
15793
  services: this.services,
14082
- simulation: currentSimulation,
15794
+ simulation: runtime.currentSimulation,
14083
15795
  signer: this.signer,
15796
+ resolvedTarget: this.resolvedTarget,
15797
+ pointerStatus: this.pointerStatus,
14084
15798
  messageLog: [...this.messageLog]
14085
15799
  };
14086
15800
  }
14087
15801
  };
15802
+ }
15803
+ async function installPajaHost() {
15804
+ const config = await readLatestConfig(readConfig());
15805
+ const frame = getFrame();
15806
+ setTargetUrlDisplay(config, frame);
15807
+ const runtime = {
15808
+ currentSimulation: config.simulation,
15809
+ themeService: null,
15810
+ currentWindowId: null,
15811
+ initReceivedGeneration: -1
15812
+ };
15813
+ const getSimulation = () => runtime.currentSimulation;
15814
+ let stateRef = null;
15815
+ const signerController = createHostSignerController(() => stateRef);
15816
+ const adapter = createPajaAdapter(config, getSimulation, (theme) => {
15817
+ runtime.themeService = theme;
15818
+ }, (request) => confirmPajaRequest(stateRef, request), signerController, () => getTargetIdentity2(config, stateRef?.resolvedTarget));
15819
+ const bridge = createShellBridge(adapter);
15820
+ bridgeRef = bridge;
15821
+ installPajaOriginRegistryProxy(originRegistry, () => stateRef);
15822
+ const capabilities = buildShellCapabilities(adapter);
15823
+ const state = createPajaBrowserState({
15824
+ config,
15825
+ frame,
15826
+ bridge,
15827
+ adapter,
15828
+ signerController,
15829
+ capabilities,
15830
+ runtime
15831
+ });
14088
15832
  stateRef = state;
14089
15833
  window.__KEHTO_PAJA__ = state;
14090
15834
  window.addEventListener("message", (event) => {
14091
15835
  if (event.source !== frame.contentWindow) return;
14092
- appendPajaMessageLog(state, "napplet->shell", event.data, currentWindowId ?? void 0);
14093
- const proxiedSource = createPajaPostMessageProxy(event.source, state, currentWindowId ?? void 0);
15836
+ appendPajaMessageLog(state, "napplet->shell", event.data, runtime.currentWindowId ?? void 0);
15837
+ const proxiedSource = createPajaPostMessageProxy(event.source, state, runtime.currentWindowId ?? void 0);
14094
15838
  const syntheticEvent = new Proxy(event, {
14095
15839
  get(target, prop) {
14096
15840
  if (prop === "source") return proxiedSource;
@@ -14101,13 +15845,13 @@ async function installPajaHost() {
14101
15845
  bridge.handleMessage(syntheticEvent);
14102
15846
  const data = event.data;
14103
15847
  if (data && typeof data === "object" && data.type === "shell.ready") {
14104
- initReceivedGeneration = state.generation;
15848
+ runtime.initReceivedGeneration = state.generation;
14105
15849
  setStatus(state, "ready");
14106
15850
  }
14107
15851
  });
14108
15852
  frame.addEventListener("load", () => {
14109
15853
  if (state.status === "booting" || state.status === "reloading") {
14110
- registerFrameForGeneration(bridge, frame, config, state.generation);
15854
+ runtime.currentWindowId = registerFrameForGeneration(bridge, frame, config, state.generation, state.resolvedTarget);
14111
15855
  }
14112
15856
  });
14113
15857
  frame.addEventListener("error", () => {
@@ -14116,7 +15860,15 @@ async function installPajaHost() {
14116
15860
  installPajaControlListeners(state);
14117
15861
  setStatus(state, "booting");
14118
15862
  setSimulationStatus(state);
14119
- currentWindowId = navigateFrame(bridge, frame, config, state.generation);
15863
+ setPointerStatus(state, state.pointerStatus);
15864
+ if (config.target.mode === "runtime-pointer") {
15865
+ const input = document.getElementById("runtime-pointer-input");
15866
+ if (input instanceof HTMLInputElement) input.value = state.pointerValue;
15867
+ if (state.pointerValue) void state.loadPointer(state.pointerValue);
15868
+ else runtime.currentWindowId = navigateFrame(bridge, frame, config, state.generation, state.resolvedTarget);
15869
+ } else {
15870
+ runtime.currentWindowId = navigateFrame(bridge, frame, config, state.generation, state.resolvedTarget);
15871
+ }
14120
15872
  }
14121
15873
  try {
14122
15874
  void installPajaHost().catch((error) => {