@kehto/paja 0.3.7 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/browser-host.js +2382 -451
- package/dist/browser-host.js.map +1 -1
- package/dist/{chunk-WYIXZLDJ.js → chunk-5QKVKI4K.js} +244 -20
- package/dist/chunk-5QKVKI4K.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +55 -6
- package/dist/index.js +13 -1
- package/dist/{server-Ca1k_vlt.d.ts → server-qAXYczds.d.ts} +20 -3
- package/package.json +11 -11
- package/dist/chunk-WYIXZLDJ.js.map +0 -1
package/dist/browser-host.js
CHANGED
|
@@ -192,6 +192,9 @@ function relayMap(action) {
|
|
|
192
192
|
if (action === "publishEncrypted") return { senderCap: "relay:write", recipientCap: null };
|
|
193
193
|
return { senderCap: "relay:read", recipientCap: null };
|
|
194
194
|
}
|
|
195
|
+
function countMap(_action) {
|
|
196
|
+
return { senderCap: "relay:read", recipientCap: null };
|
|
197
|
+
}
|
|
195
198
|
function identityMap(action) {
|
|
196
199
|
if (action === "getPublicKey" || action === "getRelays") {
|
|
197
200
|
return { senderCap: null, recipientCap: null };
|
|
@@ -278,6 +281,8 @@ function resolveCapabilitiesNap(msg) {
|
|
|
278
281
|
switch (domain) {
|
|
279
282
|
case "relay":
|
|
280
283
|
return relayMap(action);
|
|
284
|
+
case "count":
|
|
285
|
+
return countMap(action);
|
|
281
286
|
case "identity":
|
|
282
287
|
return identityMap(action);
|
|
283
288
|
case "keys":
|
|
@@ -607,7 +612,7 @@ function deserialize2(json) {
|
|
|
607
612
|
return defaultConfig();
|
|
608
613
|
}
|
|
609
614
|
|
|
610
|
-
// ../../node_modules/.pnpm/@napplet+core@0.
|
|
615
|
+
// ../../node_modules/.pnpm/@napplet+core@0.25.0/node_modules/@napplet/core/dist/index.js
|
|
611
616
|
function createDispatch() {
|
|
612
617
|
const handlers = /* @__PURE__ */ new Map();
|
|
613
618
|
function registerNap2(domain, handler) {
|
|
@@ -781,11 +786,11 @@ function capToBit(cap) {
|
|
|
781
786
|
return CAP_MAP[cap] ?? 0;
|
|
782
787
|
}
|
|
783
788
|
function bitsToCapabilities(bits) {
|
|
784
|
-
const
|
|
789
|
+
const result2 = [];
|
|
785
790
|
for (const [cap, bit] of Object.entries(CAP_MAP)) {
|
|
786
|
-
if (bits & bit)
|
|
791
|
+
if (bits & bit) result2.push(cap);
|
|
787
792
|
}
|
|
788
|
-
return
|
|
793
|
+
return result2;
|
|
789
794
|
}
|
|
790
795
|
function toIdentity(pubkey, dTag, hash) {
|
|
791
796
|
return { pubkey, dTag, hash };
|
|
@@ -881,9 +886,9 @@ function createFirewallState(persistence) {
|
|
|
881
886
|
let counters = createState2();
|
|
882
887
|
return {
|
|
883
888
|
evaluate(observation) {
|
|
884
|
-
const
|
|
885
|
-
counters =
|
|
886
|
-
return
|
|
889
|
+
const result2 = evaluate(config, counters, observation);
|
|
890
|
+
counters = result2.newState;
|
|
891
|
+
return result2;
|
|
887
892
|
},
|
|
888
893
|
setPolicy(napplet, policy) {
|
|
889
894
|
config = setPolicy(config, napplet, policy);
|
|
@@ -979,8 +984,8 @@ function createManifestCache(persistence) {
|
|
|
979
984
|
getVerification(eventId) {
|
|
980
985
|
return verificationCache.get(eventId);
|
|
981
986
|
},
|
|
982
|
-
setVerification(eventId,
|
|
983
|
-
verificationCache.set(eventId,
|
|
987
|
+
setVerification(eventId, result2) {
|
|
988
|
+
verificationCache.set(eventId, result2);
|
|
984
989
|
},
|
|
985
990
|
hasVerification(eventId) {
|
|
986
991
|
return verificationCache.has(eventId);
|
|
@@ -1498,6 +1503,65 @@ function createIdentityHandler(context) {
|
|
|
1498
1503
|
}
|
|
1499
1504
|
};
|
|
1500
1505
|
}
|
|
1506
|
+
function createCountHandler(context) {
|
|
1507
|
+
return function handleCountMessage(windowId, msg) {
|
|
1508
|
+
if (msg.type !== "count.query") return;
|
|
1509
|
+
const message = msg;
|
|
1510
|
+
const id = typeof message.id === "string" ? message.id : "";
|
|
1511
|
+
const filters = message.filters;
|
|
1512
|
+
if (!isValidFilterArray(filters)) {
|
|
1513
|
+
sendCountError(context.hooks, windowId, id, "invalid-filter", "count.query requires a non-empty filters array");
|
|
1514
|
+
return;
|
|
1515
|
+
}
|
|
1516
|
+
if (message.options !== void 0 && !isPlainObject(message.options)) {
|
|
1517
|
+
sendCountError(context.hooks, windowId, id, "invalid-filter", "count.query options must be an object when present");
|
|
1518
|
+
return;
|
|
1519
|
+
}
|
|
1520
|
+
const service = context.serviceRegistry["count"];
|
|
1521
|
+
if (!service) {
|
|
1522
|
+
sendCountError(
|
|
1523
|
+
context.hooks,
|
|
1524
|
+
windowId,
|
|
1525
|
+
id,
|
|
1526
|
+
"count-unavailable",
|
|
1527
|
+
"count service unavailable; refusing to emulate counts by fetching event payloads"
|
|
1528
|
+
);
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
service.handleMessage(windowId, msg, (resp) => {
|
|
1532
|
+
context.hooks.sendToNapplet(windowId, normalizeCountResult(resp, id));
|
|
1533
|
+
});
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1536
|
+
function normalizeCountResult(resp, id) {
|
|
1537
|
+
const value = resp;
|
|
1538
|
+
return {
|
|
1539
|
+
type: "count.query.result",
|
|
1540
|
+
id: typeof value.id === "string" ? value.id : id,
|
|
1541
|
+
ok: value.ok === true,
|
|
1542
|
+
...typeof value.count === "number" && Number.isFinite(value.count) && value.count >= 0 ? { count: Math.floor(value.count) } : {},
|
|
1543
|
+
...typeof value.approximate === "boolean" ? { approximate: value.approximate } : {},
|
|
1544
|
+
...typeof value.hll === "string" ? { hll: value.hll } : {},
|
|
1545
|
+
...Array.isArray(value.relays) ? { relays: value.relays.filter((relay) => typeof relay === "string") } : {},
|
|
1546
|
+
...typeof value.error === "string" ? { error: value.error } : {},
|
|
1547
|
+
...typeof value.reason === "string" ? { reason: value.reason } : {}
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
function sendCountError(hooks, windowId, id, error, reason) {
|
|
1551
|
+
hooks.sendToNapplet(windowId, {
|
|
1552
|
+
type: "count.query.result",
|
|
1553
|
+
id,
|
|
1554
|
+
ok: false,
|
|
1555
|
+
error,
|
|
1556
|
+
reason
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
function isValidFilterArray(value) {
|
|
1560
|
+
return Array.isArray(value) && value.length > 0 && value.every((filter) => isPlainObject(filter));
|
|
1561
|
+
}
|
|
1562
|
+
function isPlainObject(value) {
|
|
1563
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1564
|
+
}
|
|
1501
1565
|
function createIncRuntime(hooks, sessionRegistry2) {
|
|
1502
1566
|
const state = {
|
|
1503
1567
|
subscriptions: /* @__PURE__ */ new Map(),
|
|
@@ -1697,13 +1761,13 @@ function legacyScopedKey(pubkey, dTag, aggregateHash, userKey) {
|
|
|
1697
1761
|
}
|
|
1698
1762
|
function byteLength(str) {
|
|
1699
1763
|
let bytes = 0;
|
|
1700
|
-
for (let
|
|
1701
|
-
const c = str.charCodeAt(
|
|
1764
|
+
for (let i4 = 0; i4 < str.length; i4++) {
|
|
1765
|
+
const c = str.charCodeAt(i4);
|
|
1702
1766
|
if (c < 128) bytes += 1;
|
|
1703
1767
|
else if (c < 2048) bytes += 2;
|
|
1704
1768
|
else if (c < 55296 || c >= 57344) bytes += 3;
|
|
1705
1769
|
else {
|
|
1706
|
-
|
|
1770
|
+
i4++;
|
|
1707
1771
|
bytes += 4;
|
|
1708
1772
|
}
|
|
1709
1773
|
}
|
|
@@ -1747,14 +1811,14 @@ function handleStorageNap(windowId, msg, sendToNapplet, sessionRegistry2, aclSta
|
|
|
1747
1811
|
break;
|
|
1748
1812
|
}
|
|
1749
1813
|
const newKey = scopedKey(dTag, aggregateHash, key);
|
|
1750
|
-
let
|
|
1751
|
-
if (
|
|
1752
|
-
|
|
1814
|
+
let result2 = statePersistence.get(newKey);
|
|
1815
|
+
if (result2 === null && pubkey) {
|
|
1816
|
+
result2 = statePersistence.get(legacyScopedKey(pubkey, dTag, aggregateHash, key));
|
|
1753
1817
|
}
|
|
1754
|
-
if (
|
|
1755
|
-
|
|
1818
|
+
if (result2 === null && pubkey) {
|
|
1819
|
+
result2 = statePersistence.get(`napp-state:${pubkey}:${dTag}:${aggregateHash}:${key}`);
|
|
1756
1820
|
}
|
|
1757
|
-
sendResult({ value:
|
|
1821
|
+
sendResult({ value: result2 });
|
|
1758
1822
|
break;
|
|
1759
1823
|
}
|
|
1760
1824
|
case "set": {
|
|
@@ -1973,6 +2037,7 @@ function createNapEnvelopeDispatcher(handlers) {
|
|
|
1973
2037
|
};
|
|
1974
2038
|
napDispatch.registerNap("relay", adapt(handlers.relay));
|
|
1975
2039
|
napDispatch.registerNap("identity", adapt(handlers.identity));
|
|
2040
|
+
napDispatch.registerNap("count", adapt(handlers.count));
|
|
1976
2041
|
napDispatch.registerNap("keys", adapt(handlers.keys));
|
|
1977
2042
|
napDispatch.registerNap("media", adapt(handlers.media));
|
|
1978
2043
|
napDispatch.registerNap("notify", adapt(handlers.notify));
|
|
@@ -2003,13 +2068,13 @@ function createNapEnvelopeDispatcher(handlers) {
|
|
|
2003
2068
|
}
|
|
2004
2069
|
function utf8ByteLength(str) {
|
|
2005
2070
|
let bytes = 0;
|
|
2006
|
-
for (let
|
|
2007
|
-
const c = str.charCodeAt(
|
|
2071
|
+
for (let i4 = 0; i4 < str.length; i4++) {
|
|
2072
|
+
const c = str.charCodeAt(i4);
|
|
2008
2073
|
if (c < 128) bytes += 1;
|
|
2009
2074
|
else if (c < 2048) bytes += 2;
|
|
2010
2075
|
else if (c < 55296 || c >= 57344) bytes += 3;
|
|
2011
2076
|
else {
|
|
2012
|
-
|
|
2077
|
+
i4++;
|
|
2013
2078
|
bytes += 4;
|
|
2014
2079
|
}
|
|
2015
2080
|
}
|
|
@@ -2040,8 +2105,8 @@ function createFirewallGate(config) {
|
|
|
2040
2105
|
const { firewallState, sessionRegistry: sessionRegistry2, hooks, fireConsent } = config;
|
|
2041
2106
|
return function firewallGate(windowId, envelope, senderCap) {
|
|
2042
2107
|
const obs = buildObservation(envelope, windowId, senderCap, sessionRegistry2, hooks.getFocusContext);
|
|
2043
|
-
const
|
|
2044
|
-
const { decision, action, ruleId, reason } =
|
|
2108
|
+
const result2 = firewallState.evaluate(obs);
|
|
2109
|
+
const { decision, action, ruleId, reason } = result2;
|
|
2045
2110
|
const napplet = obs.napplet;
|
|
2046
2111
|
const opClass = obs.opClass;
|
|
2047
2112
|
if (decision === "reject" || decision === "prompt") {
|
|
@@ -2069,11 +2134,11 @@ function createMessageHandler(hooks, enforceNap, dispatchNapEnvelope, firewallGa
|
|
|
2069
2134
|
if (dotIdx === -1) return;
|
|
2070
2135
|
const caps = resolveCapabilitiesNap(envelope);
|
|
2071
2136
|
if (caps.senderCap) {
|
|
2072
|
-
const
|
|
2073
|
-
if (!
|
|
2137
|
+
const result2 = enforceNap(windowId, caps.senderCap, envelope);
|
|
2138
|
+
if (!result2.allowed) {
|
|
2074
2139
|
const id = envelope.id ?? "";
|
|
2075
2140
|
const isStorageEnvelope = envelope.type.startsWith("storage.");
|
|
2076
|
-
const error = formatDenialReason(
|
|
2141
|
+
const error = formatDenialReason(result2.capability);
|
|
2077
2142
|
const type = isStorageEnvelope ? `${envelope.type}.result` : `${envelope.type}.error`;
|
|
2078
2143
|
hooks.sendToNapplet(windowId, { type, id, error });
|
|
2079
2144
|
return;
|
|
@@ -2225,6 +2290,7 @@ function createRuntime(hooks) {
|
|
|
2225
2290
|
const dispatchNapEnvelope = createNapEnvelopeDispatcher({
|
|
2226
2291
|
relay: createRelayHandler({ hooks, serviceRegistry, subscriptions, eventBuffer, replayDetector }),
|
|
2227
2292
|
identity: createIdentityHandler({ hooks, serviceRegistry }),
|
|
2293
|
+
count: createCountHandler({ hooks, serviceRegistry }),
|
|
2228
2294
|
inc: incRuntime.handleMessage,
|
|
2229
2295
|
...domainHandlers
|
|
2230
2296
|
});
|
|
@@ -2252,8 +2318,8 @@ function bytesToHex(bytes) {
|
|
|
2252
2318
|
}
|
|
2253
2319
|
function hexToBytes(hex) {
|
|
2254
2320
|
const bytes = new Uint8Array(hex.length / 2);
|
|
2255
|
-
for (let
|
|
2256
|
-
bytes[
|
|
2321
|
+
for (let i4 = 0; i4 < hex.length; i4 += 2) {
|
|
2322
|
+
bytes[i4 / 2] = parseInt(hex.substring(i4, i4 + 2), 16);
|
|
2257
2323
|
}
|
|
2258
2324
|
return bytes;
|
|
2259
2325
|
}
|
|
@@ -2427,8 +2493,8 @@ function createStatePersistence() {
|
|
|
2427
2493
|
clear(prefix) {
|
|
2428
2494
|
try {
|
|
2429
2495
|
const keysToRemove = [];
|
|
2430
|
-
for (let
|
|
2431
|
-
const key = localStorage.key(
|
|
2496
|
+
for (let i4 = 0; i4 < localStorage.length; i4++) {
|
|
2497
|
+
const key = localStorage.key(i4);
|
|
2432
2498
|
if (key?.startsWith(prefix)) keysToRemove.push(key);
|
|
2433
2499
|
}
|
|
2434
2500
|
for (const key of keysToRemove) localStorage.removeItem(key);
|
|
@@ -2437,12 +2503,12 @@ function createStatePersistence() {
|
|
|
2437
2503
|
},
|
|
2438
2504
|
keys(prefix) {
|
|
2439
2505
|
try {
|
|
2440
|
-
const
|
|
2441
|
-
for (let
|
|
2442
|
-
const key = localStorage.key(
|
|
2443
|
-
if (key?.startsWith(prefix))
|
|
2506
|
+
const result2 = [];
|
|
2507
|
+
for (let i4 = 0; i4 < localStorage.length; i4++) {
|
|
2508
|
+
const key = localStorage.key(i4);
|
|
2509
|
+
if (key?.startsWith(prefix)) result2.push(key);
|
|
2444
2510
|
}
|
|
2445
|
-
return
|
|
2511
|
+
return result2;
|
|
2446
2512
|
} catch {
|
|
2447
2513
|
return [];
|
|
2448
2514
|
}
|
|
@@ -2450,8 +2516,8 @@ function createStatePersistence() {
|
|
|
2450
2516
|
calculateBytes(prefix, excludeKey) {
|
|
2451
2517
|
try {
|
|
2452
2518
|
let total = 0;
|
|
2453
|
-
for (let
|
|
2454
|
-
const key = localStorage.key(
|
|
2519
|
+
for (let i4 = 0; i4 < localStorage.length; i4++) {
|
|
2520
|
+
const key = localStorage.key(i4);
|
|
2455
2521
|
if (!key?.startsWith(prefix)) continue;
|
|
2456
2522
|
if (excludeKey && key === excludeKey) continue;
|
|
2457
2523
|
const value = localStorage.getItem(key) ?? "";
|
|
@@ -3245,6 +3311,7 @@ function buildShellCapabilities(hooks) {
|
|
|
3245
3311
|
const domains = hooks.relayPool ? ["relay", "outbox", ...NAP_DOMAINS] : [...NAP_DOMAINS];
|
|
3246
3312
|
if (hooks.upload) domains.push("upload");
|
|
3247
3313
|
if (hooks.intent?.isAvailable()) domains.push("intent");
|
|
3314
|
+
if (hooks.services?.count) domains.push("count");
|
|
3248
3315
|
if (hooks.link?.isAvailable()) domains.push("link");
|
|
3249
3316
|
if (hooks.common?.isAvailable()) domains.push("common");
|
|
3250
3317
|
if (hooks.lists?.isAvailable()) domains.push("lists");
|
|
@@ -3262,6 +3329,7 @@ function buildShellCapabilities(hooks) {
|
|
|
3262
3329
|
const naps = hooks.relayPool ? ["relay", "outbox", ...NAP_DOMAINS, ...NAP_INC_PROTOCOLS] : [...NAP_DOMAINS, ...NAP_INC_PROTOCOLS];
|
|
3263
3330
|
if (hooks.upload) naps.push("upload");
|
|
3264
3331
|
if (hooks.intent?.isAvailable()) naps.push("intent");
|
|
3332
|
+
if (hooks.services?.count) naps.push("count");
|
|
3265
3333
|
if (hooks.link?.isAvailable()) naps.push("link");
|
|
3266
3334
|
if (hooks.common?.isAvailable()) naps.push("common");
|
|
3267
3335
|
if (hooks.lists?.isAvailable()) naps.push("lists");
|
|
@@ -3503,8 +3571,8 @@ function aoutput(out, instance) {
|
|
|
3503
3571
|
}
|
|
3504
3572
|
}
|
|
3505
3573
|
function clean(...arrays) {
|
|
3506
|
-
for (let
|
|
3507
|
-
arrays[
|
|
3574
|
+
for (let i4 = 0; i4 < arrays.length; i4++) {
|
|
3575
|
+
arrays[i4].fill(0);
|
|
3508
3576
|
}
|
|
3509
3577
|
}
|
|
3510
3578
|
function createView(arr) {
|
|
@@ -3517,14 +3585,14 @@ var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
|
3517
3585
|
// @ts-ignore
|
|
3518
3586
|
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
3519
3587
|
))();
|
|
3520
|
-
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_,
|
|
3588
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i4) => i4.toString(16).padStart(2, "0"));
|
|
3521
3589
|
function bytesToHex2(bytes) {
|
|
3522
3590
|
abytes(bytes);
|
|
3523
3591
|
if (hasHexBuiltin)
|
|
3524
3592
|
return bytes.toHex();
|
|
3525
3593
|
let hex = "";
|
|
3526
|
-
for (let
|
|
3527
|
-
hex += hexes[bytes[
|
|
3594
|
+
for (let i4 = 0; i4 < bytes.length; i4++) {
|
|
3595
|
+
hex += hexes[bytes[i4]];
|
|
3528
3596
|
}
|
|
3529
3597
|
return hex;
|
|
3530
3598
|
}
|
|
@@ -3561,14 +3629,14 @@ function hexToBytes2(hex) {
|
|
|
3561
3629
|
}
|
|
3562
3630
|
function concatBytes(...arrays) {
|
|
3563
3631
|
let sum = 0;
|
|
3564
|
-
for (let
|
|
3565
|
-
const a = arrays[
|
|
3632
|
+
for (let i4 = 0; i4 < arrays.length; i4++) {
|
|
3633
|
+
const a = arrays[i4];
|
|
3566
3634
|
abytes(a);
|
|
3567
3635
|
sum += a.length;
|
|
3568
3636
|
}
|
|
3569
3637
|
const res = new Uint8Array(sum);
|
|
3570
|
-
for (let
|
|
3571
|
-
const a = arrays[
|
|
3638
|
+
for (let i4 = 0, pad2 = 0; i4 < arrays.length; i4++) {
|
|
3639
|
+
const a = arrays[i4];
|
|
3572
3640
|
res.set(a, pad2);
|
|
3573
3641
|
pad2 += a.length;
|
|
3574
3642
|
}
|
|
@@ -3651,24 +3719,24 @@ function alphabet(letters) {
|
|
|
3651
3719
|
const lettersA = typeof letters === "string" ? letters.split("") : letters;
|
|
3652
3720
|
const len = lettersA.length;
|
|
3653
3721
|
astrArr("alphabet", lettersA);
|
|
3654
|
-
const indexes = new Map(lettersA.map((l,
|
|
3722
|
+
const indexes = new Map(lettersA.map((l, i4) => [l, i4]));
|
|
3655
3723
|
return {
|
|
3656
3724
|
encode: (digits) => {
|
|
3657
3725
|
aArr(digits);
|
|
3658
|
-
return digits.map((
|
|
3659
|
-
if (!Number.isSafeInteger(
|
|
3660
|
-
throw new Error(`alphabet.encode: digit index outside alphabet "${
|
|
3661
|
-
return lettersA[
|
|
3726
|
+
return digits.map((i4) => {
|
|
3727
|
+
if (!Number.isSafeInteger(i4) || i4 < 0 || i4 >= len)
|
|
3728
|
+
throw new Error(`alphabet.encode: digit index outside alphabet "${i4}". Allowed: ${letters}`);
|
|
3729
|
+
return lettersA[i4];
|
|
3662
3730
|
});
|
|
3663
3731
|
},
|
|
3664
3732
|
decode: (input) => {
|
|
3665
3733
|
aArr(input);
|
|
3666
3734
|
return input.map((letter) => {
|
|
3667
3735
|
astr("alphabet.decode", letter);
|
|
3668
|
-
const
|
|
3669
|
-
if (
|
|
3736
|
+
const i4 = indexes.get(letter);
|
|
3737
|
+
if (i4 === void 0)
|
|
3670
3738
|
throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
|
|
3671
|
-
return
|
|
3739
|
+
return i4;
|
|
3672
3740
|
});
|
|
3673
3741
|
}
|
|
3674
3742
|
};
|
|
@@ -3717,8 +3785,8 @@ var gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
|
3717
3785
|
var radix2carry = /* @__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
|
|
3718
3786
|
var powers = /* @__PURE__ */ (() => {
|
|
3719
3787
|
let res = [];
|
|
3720
|
-
for (let
|
|
3721
|
-
res.push(2 **
|
|
3788
|
+
for (let i4 = 0; i4 < 40; i4++)
|
|
3789
|
+
res.push(2 ** i4);
|
|
3722
3790
|
return res;
|
|
3723
3791
|
})();
|
|
3724
3792
|
function convertRadix2(data, from, to, padding2) {
|
|
@@ -3810,27 +3878,27 @@ var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059
|
|
|
3810
3878
|
function bech32Polymod(pre) {
|
|
3811
3879
|
const b = pre >> 25;
|
|
3812
3880
|
let chk = (pre & 33554431) << 5;
|
|
3813
|
-
for (let
|
|
3814
|
-
if ((b >>
|
|
3815
|
-
chk ^= POLYMOD_GENERATORS[
|
|
3881
|
+
for (let i4 = 0; i4 < POLYMOD_GENERATORS.length; i4++) {
|
|
3882
|
+
if ((b >> i4 & 1) === 1)
|
|
3883
|
+
chk ^= POLYMOD_GENERATORS[i4];
|
|
3816
3884
|
}
|
|
3817
3885
|
return chk;
|
|
3818
3886
|
}
|
|
3819
3887
|
function bechChecksum(prefix, words, encodingConst = 1) {
|
|
3820
3888
|
const len = prefix.length;
|
|
3821
3889
|
let chk = 1;
|
|
3822
|
-
for (let
|
|
3823
|
-
const c = prefix.charCodeAt(
|
|
3890
|
+
for (let i4 = 0; i4 < len; i4++) {
|
|
3891
|
+
const c = prefix.charCodeAt(i4);
|
|
3824
3892
|
if (c < 33 || c > 126)
|
|
3825
3893
|
throw new Error(`Invalid prefix (${prefix})`);
|
|
3826
3894
|
chk = bech32Polymod(chk) ^ c >> 5;
|
|
3827
3895
|
}
|
|
3828
3896
|
chk = bech32Polymod(chk);
|
|
3829
|
-
for (let
|
|
3830
|
-
chk = bech32Polymod(chk) ^ prefix.charCodeAt(
|
|
3897
|
+
for (let i4 = 0; i4 < len; i4++)
|
|
3898
|
+
chk = bech32Polymod(chk) ^ prefix.charCodeAt(i4) & 31;
|
|
3831
3899
|
for (let v of words)
|
|
3832
3900
|
chk = bech32Polymod(chk) ^ v;
|
|
3833
|
-
for (let
|
|
3901
|
+
for (let i4 = 0; i4 < 6; i4++)
|
|
3834
3902
|
chk = bech32Polymod(chk);
|
|
3835
3903
|
chk ^= encodingConst;
|
|
3836
3904
|
return BECH_ALPHABET.encode(convertRadix2([chk % powers[30]], 30, 5, false));
|
|
@@ -3981,7 +4049,7 @@ function decode(code) {
|
|
|
3981
4049
|
}
|
|
3982
4050
|
}
|
|
3983
4051
|
function parseTLV(data) {
|
|
3984
|
-
let
|
|
4052
|
+
let result2 = {};
|
|
3985
4053
|
let rest = data;
|
|
3986
4054
|
while (rest.length > 0) {
|
|
3987
4055
|
let t = rest[0];
|
|
@@ -3990,10 +4058,10 @@ function parseTLV(data) {
|
|
|
3990
4058
|
rest = rest.slice(2 + l);
|
|
3991
4059
|
if (v.length < l)
|
|
3992
4060
|
throw new Error(`not enough data to read on TLV ${t}`);
|
|
3993
|
-
|
|
3994
|
-
|
|
4061
|
+
result2[t] = result2[t] || [];
|
|
4062
|
+
result2[t].push(v);
|
|
3995
4063
|
}
|
|
3996
|
-
return
|
|
4064
|
+
return result2;
|
|
3997
4065
|
}
|
|
3998
4066
|
function npubEncode(hex) {
|
|
3999
4067
|
return encodeBytes("npub", hexToBytes2(hex));
|
|
@@ -4117,8 +4185,8 @@ var HashMD = class {
|
|
|
4117
4185
|
this.process(view, 0);
|
|
4118
4186
|
pos = 0;
|
|
4119
4187
|
}
|
|
4120
|
-
for (let
|
|
4121
|
-
buffer[
|
|
4188
|
+
for (let i4 = pos; i4 < blockLen; i4++)
|
|
4189
|
+
buffer[i4] = 0;
|
|
4122
4190
|
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE2);
|
|
4123
4191
|
this.process(view, 0);
|
|
4124
4192
|
const oview = createView(out);
|
|
@@ -4129,8 +4197,8 @@ var HashMD = class {
|
|
|
4129
4197
|
const state = this.get();
|
|
4130
4198
|
if (outLen > state.length)
|
|
4131
4199
|
throw new Error("_sha2: outputLen bigger than state");
|
|
4132
|
-
for (let
|
|
4133
|
-
oview.setUint32(4 *
|
|
4200
|
+
for (let i4 = 0; i4 < outLen; i4++)
|
|
4201
|
+
oview.setUint32(4 * i4, state[i4], isLE2);
|
|
4134
4202
|
}
|
|
4135
4203
|
digest() {
|
|
4136
4204
|
const { buffer, outputLen } = this;
|
|
@@ -4254,19 +4322,19 @@ var SHA2_32B = class extends HashMD {
|
|
|
4254
4322
|
this.H = H | 0;
|
|
4255
4323
|
}
|
|
4256
4324
|
process(view, offset) {
|
|
4257
|
-
for (let
|
|
4258
|
-
SHA256_W[
|
|
4259
|
-
for (let
|
|
4260
|
-
const W15 = SHA256_W[
|
|
4261
|
-
const W2 = SHA256_W[
|
|
4325
|
+
for (let i4 = 0; i4 < 16; i4++, offset += 4)
|
|
4326
|
+
SHA256_W[i4] = view.getUint32(offset, false);
|
|
4327
|
+
for (let i4 = 16; i4 < 64; i4++) {
|
|
4328
|
+
const W15 = SHA256_W[i4 - 15];
|
|
4329
|
+
const W2 = SHA256_W[i4 - 2];
|
|
4262
4330
|
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
4263
4331
|
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
4264
|
-
SHA256_W[
|
|
4332
|
+
SHA256_W[i4] = s1 + SHA256_W[i4 - 7] + s0 + SHA256_W[i4 - 16] | 0;
|
|
4265
4333
|
}
|
|
4266
4334
|
let { A, B, C, D, E, F, G, H } = this;
|
|
4267
|
-
for (let
|
|
4335
|
+
for (let i4 = 0; i4 < 64; i4++) {
|
|
4268
4336
|
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
4269
|
-
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[
|
|
4337
|
+
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i4] + SHA256_W[i4] | 0;
|
|
4270
4338
|
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
|
4271
4339
|
const T2 = sigma0 + Maj(A, B, C) | 0;
|
|
4272
4340
|
H = G;
|
|
@@ -4364,10 +4432,10 @@ function copyBytes(bytes) {
|
|
|
4364
4432
|
return Uint8Array.from(bytes);
|
|
4365
4433
|
}
|
|
4366
4434
|
function asciiToBytes(ascii) {
|
|
4367
|
-
return Uint8Array.from(ascii, (c,
|
|
4435
|
+
return Uint8Array.from(ascii, (c, i4) => {
|
|
4368
4436
|
const charCode = c.charCodeAt(0);
|
|
4369
4437
|
if (c.length !== 1 || charCode > 127) {
|
|
4370
|
-
throw new Error(`string contains non-ASCII character "${ascii[
|
|
4438
|
+
throw new Error(`string contains non-ASCII character "${ascii[i4]}" with code ${charCode} at position ${i4}`);
|
|
4371
4439
|
}
|
|
4372
4440
|
return charCode;
|
|
4373
4441
|
});
|
|
@@ -4399,11 +4467,11 @@ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
|
|
4399
4467
|
const _maxDrbgIters = 1e3;
|
|
4400
4468
|
let v = u8n(hashLen);
|
|
4401
4469
|
let k = u8n(hashLen);
|
|
4402
|
-
let
|
|
4470
|
+
let i4 = 0;
|
|
4403
4471
|
const reset = () => {
|
|
4404
4472
|
v.fill(1);
|
|
4405
4473
|
k.fill(0);
|
|
4406
|
-
|
|
4474
|
+
i4 = 0;
|
|
4407
4475
|
};
|
|
4408
4476
|
const h = (...msgs) => hmacFn(k, concatBytes(v, ...msgs));
|
|
4409
4477
|
const reseed = (seed = NULL) => {
|
|
@@ -4415,7 +4483,7 @@ function createHmacDrbg(hashLen, qByteLen, hmacFn) {
|
|
|
4415
4483
|
v = h();
|
|
4416
4484
|
};
|
|
4417
4485
|
const gen = () => {
|
|
4418
|
-
if (
|
|
4486
|
+
if (i4++ >= _maxDrbgIters)
|
|
4419
4487
|
throw new Error("drbg: tried max amount of iterations");
|
|
4420
4488
|
let len = 0;
|
|
4421
4489
|
const out = [];
|
|
@@ -4477,8 +4545,8 @@ var _8n = /* @__PURE__ */ BigInt(8);
|
|
|
4477
4545
|
var _9n = /* @__PURE__ */ BigInt(9);
|
|
4478
4546
|
var _16n = /* @__PURE__ */ BigInt(16);
|
|
4479
4547
|
function mod(a, b) {
|
|
4480
|
-
const
|
|
4481
|
-
return
|
|
4548
|
+
const result2 = a % b;
|
|
4549
|
+
return result2 >= _0n2 ? result2 : b + result2;
|
|
4482
4550
|
}
|
|
4483
4551
|
function pow2(x, power, modulo) {
|
|
4484
4552
|
let res = x;
|
|
@@ -4523,8 +4591,8 @@ function sqrt5mod8(Fp, n) {
|
|
|
4523
4591
|
const n2 = Fp.mul(n, _2n);
|
|
4524
4592
|
const v = Fp.pow(n2, p5div8);
|
|
4525
4593
|
const nv = Fp.mul(n, v);
|
|
4526
|
-
const
|
|
4527
|
-
const root = Fp.mul(nv, Fp.sub(
|
|
4594
|
+
const i4 = Fp.mul(Fp.mul(nv, _2n), v);
|
|
4595
|
+
const root = Fp.mul(nv, Fp.sub(i4, Fp.ONE));
|
|
4528
4596
|
assertIsSquare(Fp, root, n);
|
|
4529
4597
|
return root;
|
|
4530
4598
|
}
|
|
@@ -4581,17 +4649,17 @@ function tonelliShanks(P) {
|
|
|
4581
4649
|
while (!Fp.eql(t, Fp.ONE)) {
|
|
4582
4650
|
if (Fp.is0(t))
|
|
4583
4651
|
return Fp.ZERO;
|
|
4584
|
-
let
|
|
4652
|
+
let i4 = 1;
|
|
4585
4653
|
let t_tmp = Fp.sqr(t);
|
|
4586
4654
|
while (!Fp.eql(t_tmp, Fp.ONE)) {
|
|
4587
|
-
|
|
4655
|
+
i4++;
|
|
4588
4656
|
t_tmp = Fp.sqr(t_tmp);
|
|
4589
|
-
if (
|
|
4657
|
+
if (i4 === M)
|
|
4590
4658
|
throw new Error("Cannot find square root");
|
|
4591
4659
|
}
|
|
4592
|
-
const exponent = _1n2 << BigInt(M -
|
|
4660
|
+
const exponent = _1n2 << BigInt(M - i4 - 1);
|
|
4593
4661
|
const b = Fp.pow(c, exponent);
|
|
4594
|
-
M =
|
|
4662
|
+
M = i4;
|
|
4595
4663
|
c = Fp.sqr(b);
|
|
4596
4664
|
t = Fp.mul(t, c);
|
|
4597
4665
|
R = Fp.mul(R, b);
|
|
@@ -4659,17 +4727,17 @@ function FpPow(Fp, num2, power) {
|
|
|
4659
4727
|
}
|
|
4660
4728
|
function FpInvertBatch(Fp, nums, passZero = false) {
|
|
4661
4729
|
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : void 0);
|
|
4662
|
-
const multipliedAcc = nums.reduce((acc, num2,
|
|
4730
|
+
const multipliedAcc = nums.reduce((acc, num2, i4) => {
|
|
4663
4731
|
if (Fp.is0(num2))
|
|
4664
4732
|
return acc;
|
|
4665
|
-
inverted[
|
|
4733
|
+
inverted[i4] = acc;
|
|
4666
4734
|
return Fp.mul(acc, num2);
|
|
4667
4735
|
}, Fp.ONE);
|
|
4668
4736
|
const invertedAcc = Fp.inv(multipliedAcc);
|
|
4669
|
-
nums.reduceRight((acc, num2,
|
|
4737
|
+
nums.reduceRight((acc, num2, i4) => {
|
|
4670
4738
|
if (Fp.is0(num2))
|
|
4671
4739
|
return acc;
|
|
4672
|
-
inverted[
|
|
4740
|
+
inverted[i4] = Fp.mul(acc, inverted[i4]);
|
|
4673
4741
|
return Fp.mul(acc, num2);
|
|
4674
4742
|
}, invertedAcc);
|
|
4675
4743
|
return inverted;
|
|
@@ -4860,7 +4928,7 @@ function negateCt(condition, item) {
|
|
|
4860
4928
|
}
|
|
4861
4929
|
function normalizeZ(c, points) {
|
|
4862
4930
|
const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z));
|
|
4863
|
-
return points.map((p,
|
|
4931
|
+
return points.map((p, i4) => c.fromAffine(p.toAffine(invertedZs[i4])));
|
|
4864
4932
|
}
|
|
4865
4933
|
function validateW(W, bits) {
|
|
4866
4934
|
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
|
|
@@ -4943,7 +5011,7 @@ var wNAF = class {
|
|
|
4943
5011
|
for (let window2 = 0; window2 < windows; window2++) {
|
|
4944
5012
|
base = p;
|
|
4945
5013
|
points.push(base);
|
|
4946
|
-
for (let
|
|
5014
|
+
for (let i4 = 1; i4 < windowSize; i4++) {
|
|
4947
5015
|
base = base.add(p);
|
|
4948
5016
|
points.push(base);
|
|
4949
5017
|
}
|
|
@@ -5077,10 +5145,10 @@ function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
|
|
|
5077
5145
|
CURVE = Object.freeze(Object.assign({}, CURVE));
|
|
5078
5146
|
return { CURVE, Fp, Fn };
|
|
5079
5147
|
}
|
|
5080
|
-
function createKeygen(randomSecretKey,
|
|
5148
|
+
function createKeygen(randomSecretKey, getPublicKey4) {
|
|
5081
5149
|
return function keygen(seed) {
|
|
5082
5150
|
const secretKey = randomSecretKey(seed);
|
|
5083
|
-
return { secretKey, publicKey:
|
|
5151
|
+
return { secretKey, publicKey: getPublicKey4(secretKey) };
|
|
5084
5152
|
};
|
|
5085
5153
|
}
|
|
5086
5154
|
|
|
@@ -5103,12 +5171,12 @@ var _HMAC = class {
|
|
|
5103
5171
|
const blockLen = this.blockLen;
|
|
5104
5172
|
const pad2 = new Uint8Array(blockLen);
|
|
5105
5173
|
pad2.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
|
5106
|
-
for (let
|
|
5107
|
-
pad2[
|
|
5174
|
+
for (let i4 = 0; i4 < pad2.length; i4++)
|
|
5175
|
+
pad2[i4] ^= 54;
|
|
5108
5176
|
this.iHash.update(pad2);
|
|
5109
5177
|
this.oHash = hash.create();
|
|
5110
|
-
for (let
|
|
5111
|
-
pad2[
|
|
5178
|
+
for (let i4 = 0; i4 < pad2.length; i4++)
|
|
5179
|
+
pad2[i4] ^= 54 ^ 92;
|
|
5112
5180
|
this.oHash.update(pad2);
|
|
5113
5181
|
clean(pad2);
|
|
5114
5182
|
}
|
|
@@ -5765,7 +5833,7 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
5765
5833
|
function randomSecretKey(seed = randomBytes_(lengths.seed)) {
|
|
5766
5834
|
return mapHashToField(abytes(seed, lengths.seed, "seed"), Fn.ORDER);
|
|
5767
5835
|
}
|
|
5768
|
-
function
|
|
5836
|
+
function getPublicKey4(secretKey, isCompressed = true) {
|
|
5769
5837
|
return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
|
|
5770
5838
|
}
|
|
5771
5839
|
function isProbPub(item) {
|
|
@@ -5791,8 +5859,8 @@ function ecdh(Point, ecdhOpts = {}) {
|
|
|
5791
5859
|
isValidPublicKey,
|
|
5792
5860
|
randomSecretKey
|
|
5793
5861
|
};
|
|
5794
|
-
const keygen = createKeygen(randomSecretKey,
|
|
5795
|
-
return Object.freeze({ getPublicKey:
|
|
5862
|
+
const keygen = createKeygen(randomSecretKey, getPublicKey4);
|
|
5863
|
+
return Object.freeze({ getPublicKey: getPublicKey4, getSharedSecret, keygen, Point, utils, lengths });
|
|
5796
5864
|
}
|
|
5797
5865
|
function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
5798
5866
|
ahash(hash);
|
|
@@ -5808,7 +5876,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
5808
5876
|
const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
|
|
5809
5877
|
const { Fp, Fn } = Point;
|
|
5810
5878
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
5811
|
-
const { keygen, getPublicKey:
|
|
5879
|
+
const { keygen, getPublicKey: getPublicKey4, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
|
|
5812
5880
|
const defaultSigOpts = {
|
|
5813
5881
|
prehash: true,
|
|
5814
5882
|
lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : true,
|
|
@@ -6014,7 +6082,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
6014
6082
|
}
|
|
6015
6083
|
return Object.freeze({
|
|
6016
6084
|
keygen,
|
|
6017
|
-
getPublicKey:
|
|
6085
|
+
getPublicKey: getPublicKey4,
|
|
6018
6086
|
getSharedSecret,
|
|
6019
6087
|
utils,
|
|
6020
6088
|
lengths,
|
|
@@ -6300,8 +6368,8 @@ function u32(arr) {
|
|
|
6300
6368
|
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
|
|
6301
6369
|
}
|
|
6302
6370
|
function clean2(...arrays) {
|
|
6303
|
-
for (let
|
|
6304
|
-
arrays[
|
|
6371
|
+
for (let i4 = 0; i4 < arrays.length; i4++) {
|
|
6372
|
+
arrays[i4].fill(0);
|
|
6305
6373
|
}
|
|
6306
6374
|
}
|
|
6307
6375
|
function createView2(arr) {
|
|
@@ -6327,8 +6395,8 @@ function equalBytes(a, b) {
|
|
|
6327
6395
|
if (a.length !== b.length)
|
|
6328
6396
|
return false;
|
|
6329
6397
|
let diff = 0;
|
|
6330
|
-
for (let
|
|
6331
|
-
diff |= a[
|
|
6398
|
+
for (let i4 = 0; i4 < a.length; i4++)
|
|
6399
|
+
diff |= a[i4] ^ b[i4];
|
|
6332
6400
|
return diff === 0;
|
|
6333
6401
|
}
|
|
6334
6402
|
var wrapCipher = /* @__NO_SIDE_EFFECTS__ */ (params, constructor) => {
|
|
@@ -6508,8 +6576,8 @@ function createCipher(core, opts) {
|
|
|
6508
6576
|
}
|
|
6509
6577
|
|
|
6510
6578
|
// ../../node_modules/.pnpm/@noble+ciphers@2.1.1/node_modules/@noble/ciphers/_poly1305.js
|
|
6511
|
-
function u8to16(a,
|
|
6512
|
-
return a[
|
|
6579
|
+
function u8to16(a, i4) {
|
|
6580
|
+
return a[i4++] & 255 | (a[i4++] & 255) << 8;
|
|
6513
6581
|
}
|
|
6514
6582
|
var Poly1305 = class {
|
|
6515
6583
|
blockLen = 16;
|
|
@@ -6542,8 +6610,8 @@ var Poly1305 = class {
|
|
|
6542
6610
|
this.r[7] = (t5 >>> 11 | t6 << 5) & 8065;
|
|
6543
6611
|
this.r[8] = (t6 >>> 8 | t7 << 8) & 8191;
|
|
6544
6612
|
this.r[9] = t7 >>> 5 & 127;
|
|
6545
|
-
for (let
|
|
6546
|
-
this.pad[
|
|
6613
|
+
for (let i4 = 0; i4 < 8; i4++)
|
|
6614
|
+
this.pad[i4] = u8to16(key, 16 + 2 * i4);
|
|
6547
6615
|
}
|
|
6548
6616
|
process(data, offset, isLast = false) {
|
|
6549
6617
|
const hibit = isLast ? 0 : 1 << 11;
|
|
@@ -6658,10 +6726,10 @@ var Poly1305 = class {
|
|
|
6658
6726
|
const g = new Uint16Array(10);
|
|
6659
6727
|
let c = h[1] >>> 13;
|
|
6660
6728
|
h[1] &= 8191;
|
|
6661
|
-
for (let
|
|
6662
|
-
h[
|
|
6663
|
-
c = h[
|
|
6664
|
-
h[
|
|
6729
|
+
for (let i4 = 2; i4 < 10; i4++) {
|
|
6730
|
+
h[i4] += c;
|
|
6731
|
+
c = h[i4] >>> 13;
|
|
6732
|
+
h[i4] &= 8191;
|
|
6665
6733
|
}
|
|
6666
6734
|
h[0] += c * 5;
|
|
6667
6735
|
c = h[0] >>> 13;
|
|
@@ -6673,18 +6741,18 @@ var Poly1305 = class {
|
|
|
6673
6741
|
g[0] = h[0] + 5;
|
|
6674
6742
|
c = g[0] >>> 13;
|
|
6675
6743
|
g[0] &= 8191;
|
|
6676
|
-
for (let
|
|
6677
|
-
g[
|
|
6678
|
-
c = g[
|
|
6679
|
-
g[
|
|
6744
|
+
for (let i4 = 1; i4 < 10; i4++) {
|
|
6745
|
+
g[i4] = h[i4] + c;
|
|
6746
|
+
c = g[i4] >>> 13;
|
|
6747
|
+
g[i4] &= 8191;
|
|
6680
6748
|
}
|
|
6681
6749
|
g[9] -= 1 << 13;
|
|
6682
6750
|
let mask = (c ^ 1) - 1;
|
|
6683
|
-
for (let
|
|
6684
|
-
g[
|
|
6751
|
+
for (let i4 = 0; i4 < 10; i4++)
|
|
6752
|
+
g[i4] &= mask;
|
|
6685
6753
|
mask = ~mask;
|
|
6686
|
-
for (let
|
|
6687
|
-
h[
|
|
6754
|
+
for (let i4 = 0; i4 < 10; i4++)
|
|
6755
|
+
h[i4] = h[i4] & mask | g[i4];
|
|
6688
6756
|
h[0] = (h[0] | h[1] << 13) & 65535;
|
|
6689
6757
|
h[1] = (h[1] >>> 3 | h[2] << 10) & 65535;
|
|
6690
6758
|
h[2] = (h[2] >>> 6 | h[3] << 7) & 65535;
|
|
@@ -6695,9 +6763,9 @@ var Poly1305 = class {
|
|
|
6695
6763
|
h[7] = (h[8] >>> 8 | h[9] << 5) & 65535;
|
|
6696
6764
|
let f = h[0] + pad2[0];
|
|
6697
6765
|
h[0] = f & 65535;
|
|
6698
|
-
for (let
|
|
6699
|
-
f = (h[
|
|
6700
|
-
h[
|
|
6766
|
+
for (let i4 = 1; i4 < 8; i4++) {
|
|
6767
|
+
f = (h[i4] + pad2[i4] | 0) + (f >>> 16) | 0;
|
|
6768
|
+
h[i4] = f & 65535;
|
|
6701
6769
|
}
|
|
6702
6770
|
clean2(g);
|
|
6703
6771
|
}
|
|
@@ -6741,9 +6809,9 @@ var Poly1305 = class {
|
|
|
6741
6809
|
}
|
|
6742
6810
|
this.finalize();
|
|
6743
6811
|
let opos = 0;
|
|
6744
|
-
for (let
|
|
6745
|
-
out[opos++] = h[
|
|
6746
|
-
out[opos++] = h[
|
|
6812
|
+
for (let i4 = 0; i4 < 8; i4++) {
|
|
6813
|
+
out[opos++] = h[i4] >>> 0;
|
|
6814
|
+
out[opos++] = h[i4] >>> 8;
|
|
6747
6815
|
}
|
|
6748
6816
|
return out;
|
|
6749
6817
|
}
|
|
@@ -6853,8 +6921,8 @@ function chachaCore(s, k, n, out, cnt, rounds = 20) {
|
|
|
6853
6921
|
out[oi++] = y14 + x14 | 0;
|
|
6854
6922
|
out[oi++] = y15 + x15 | 0;
|
|
6855
6923
|
}
|
|
6856
|
-
function hchacha(s, k,
|
|
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 =
|
|
6924
|
+
function hchacha(s, k, i4, out) {
|
|
6925
|
+
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
6926
|
for (let r = 0; r < 20; r += 2) {
|
|
6859
6927
|
x00 = x00 + x04 | 0;
|
|
6860
6928
|
x12 = rotl(x12 ^ x00, 16);
|
|
@@ -7194,9 +7262,9 @@ function createNotificationService(options) {
|
|
|
7194
7262
|
};
|
|
7195
7263
|
}
|
|
7196
7264
|
var IDENTITY_SERVICE_VERSION = "1.0.0";
|
|
7197
|
-
function sendProviderError(send,
|
|
7265
|
+
function sendProviderError(send, result2, fallback, err2) {
|
|
7198
7266
|
send({
|
|
7199
|
-
...
|
|
7267
|
+
...result2,
|
|
7200
7268
|
error: err2?.message ?? fallback
|
|
7201
7269
|
});
|
|
7202
7270
|
}
|
|
@@ -7214,7 +7282,7 @@ function sendOptionalProviderResult(options, send, fallbackResult, errorFallback
|
|
|
7214
7282
|
send(fallbackResult);
|
|
7215
7283
|
return;
|
|
7216
7284
|
}
|
|
7217
|
-
Promise.resolve(getCurrentPubkey(options)).then((pubkey) => buildResult(pubkey)).then((
|
|
7285
|
+
Promise.resolve(getCurrentPubkey(options)).then((pubkey) => buildResult(pubkey)).then((result2) => send(result2)).catch((err2) => sendProviderError(send, fallbackResult, errorFallback, err2));
|
|
7218
7286
|
}
|
|
7219
7287
|
function sendIdentityError(send, id, typeBase, error) {
|
|
7220
7288
|
send({ type: `${typeBase}.error`, id, error });
|
|
@@ -7225,21 +7293,21 @@ function sendSignerError(send, id, typeBase, fallback, err2) {
|
|
|
7225
7293
|
function handleGetPublicKey(options, id, send) {
|
|
7226
7294
|
const signer = options.getSigner();
|
|
7227
7295
|
if (!signer) {
|
|
7228
|
-
const
|
|
7296
|
+
const result2 = {
|
|
7229
7297
|
type: "identity.getPublicKey.result",
|
|
7230
7298
|
id,
|
|
7231
7299
|
pubkey: ""
|
|
7232
7300
|
};
|
|
7233
|
-
send(
|
|
7301
|
+
send(result2);
|
|
7234
7302
|
return;
|
|
7235
7303
|
}
|
|
7236
7304
|
Promise.resolve(signer.getPublicKey?.()).then((pubkey) => {
|
|
7237
|
-
const
|
|
7305
|
+
const result2 = {
|
|
7238
7306
|
type: "identity.getPublicKey.result",
|
|
7239
7307
|
id,
|
|
7240
7308
|
pubkey: pubkey ?? ""
|
|
7241
7309
|
};
|
|
7242
|
-
send(
|
|
7310
|
+
send(result2);
|
|
7243
7311
|
}).catch((err2) => sendSignerError(send, id, "identity.getPublicKey", "getPublicKey failed", err2));
|
|
7244
7312
|
}
|
|
7245
7313
|
function handleGetRelays(options, id, send) {
|
|
@@ -7249,12 +7317,12 @@ function handleGetRelays(options, id, send) {
|
|
|
7249
7317
|
return;
|
|
7250
7318
|
}
|
|
7251
7319
|
Promise.resolve(signer.getRelays?.() ?? {}).then((relays) => {
|
|
7252
|
-
const
|
|
7320
|
+
const result2 = {
|
|
7253
7321
|
type: "identity.getRelays.result",
|
|
7254
7322
|
id,
|
|
7255
7323
|
relays
|
|
7256
7324
|
};
|
|
7257
|
-
send(
|
|
7325
|
+
send(result2);
|
|
7258
7326
|
}).catch((err2) => sendSignerError(send, id, "identity.getRelays", "getRelays failed", err2));
|
|
7259
7327
|
}
|
|
7260
7328
|
function handleReadProvider(options, id, message, send) {
|
|
@@ -7475,6 +7543,90 @@ function createRelayPoolService(options) {
|
|
|
7475
7543
|
}
|
|
7476
7544
|
};
|
|
7477
7545
|
}
|
|
7546
|
+
var DEFAULT_MAX_FILTERS = 16;
|
|
7547
|
+
function createCountService(options) {
|
|
7548
|
+
return {
|
|
7549
|
+
descriptor: {
|
|
7550
|
+
name: "count",
|
|
7551
|
+
version: "1.0.0",
|
|
7552
|
+
description: "Runtime-mediated NIP-01 filter counts"
|
|
7553
|
+
},
|
|
7554
|
+
handleMessage(windowId, message, send) {
|
|
7555
|
+
if (message.type !== "count.query") return;
|
|
7556
|
+
const countMessage = message;
|
|
7557
|
+
const id = typeof countMessage.id === "string" ? countMessage.id : "";
|
|
7558
|
+
const filters = countMessage.filters;
|
|
7559
|
+
if (!isValidFilterArray2(filters)) {
|
|
7560
|
+
send(result(id, { ok: false, error: "invalid-filter", reason: "count.query requires a non-empty filters array" }));
|
|
7561
|
+
return;
|
|
7562
|
+
}
|
|
7563
|
+
const maxFilters = options.maxFilters ?? DEFAULT_MAX_FILTERS;
|
|
7564
|
+
if (filters.length > maxFilters) {
|
|
7565
|
+
send(result(id, { ok: false, error: "too-expensive", reason: `count.query accepts at most ${maxFilters} filters` }));
|
|
7566
|
+
return;
|
|
7567
|
+
}
|
|
7568
|
+
for (let i4 = 0; i4 < filters.length; i4++) {
|
|
7569
|
+
const supported = options.isFilterSupported?.(filters[i4], i4) ?? true;
|
|
7570
|
+
if (supported !== true) {
|
|
7571
|
+
send(result(id, {
|
|
7572
|
+
ok: false,
|
|
7573
|
+
error: "unsupported-filter",
|
|
7574
|
+
reason: typeof supported === "string" ? supported : `filter ${i4} is not supported by this count backend`
|
|
7575
|
+
}));
|
|
7576
|
+
return;
|
|
7577
|
+
}
|
|
7578
|
+
}
|
|
7579
|
+
const request = {
|
|
7580
|
+
filters,
|
|
7581
|
+
windowId,
|
|
7582
|
+
...isPlainObject2(countMessage.options) ? { options: countMessage.options } : {}
|
|
7583
|
+
};
|
|
7584
|
+
Promise.resolve(options.count(request)).then((countResult) => {
|
|
7585
|
+
send(result(id, normalizeCountResult2(countResult)));
|
|
7586
|
+
}).catch((error) => {
|
|
7587
|
+
send(result(id, {
|
|
7588
|
+
ok: false,
|
|
7589
|
+
error: "count-unavailable",
|
|
7590
|
+
reason: error instanceof Error ? error.message : "count backend failed"
|
|
7591
|
+
}));
|
|
7592
|
+
});
|
|
7593
|
+
}
|
|
7594
|
+
};
|
|
7595
|
+
}
|
|
7596
|
+
function result(id, value) {
|
|
7597
|
+
return {
|
|
7598
|
+
type: "count.query.result",
|
|
7599
|
+
id,
|
|
7600
|
+
ok: value.ok,
|
|
7601
|
+
...typeof value.count === "number" ? { count: value.count } : {},
|
|
7602
|
+
...typeof value.approximate === "boolean" ? { approximate: value.approximate } : {},
|
|
7603
|
+
...typeof value.hll === "string" ? { hll: value.hll } : {},
|
|
7604
|
+
...Array.isArray(value.relays) ? { relays: value.relays.filter((relay) => typeof relay === "string") } : {},
|
|
7605
|
+
...typeof value.error === "string" ? { error: value.error } : {},
|
|
7606
|
+
...typeof value.reason === "string" ? { reason: value.reason } : {}
|
|
7607
|
+
};
|
|
7608
|
+
}
|
|
7609
|
+
function normalizeCountResult2(value) {
|
|
7610
|
+
if (typeof value === "number") {
|
|
7611
|
+
return Number.isFinite(value) && value >= 0 ? { ok: true, count: Math.floor(value), approximate: false } : { ok: false, error: "count-unavailable", reason: "count backend returned an invalid count" };
|
|
7612
|
+
}
|
|
7613
|
+
const count = typeof value.count === "number" && Number.isFinite(value.count) && value.count >= 0 ? Math.floor(value.count) : void 0;
|
|
7614
|
+
return {
|
|
7615
|
+
ok: value.ok === true,
|
|
7616
|
+
...count !== void 0 ? { count } : {},
|
|
7617
|
+
...typeof value.approximate === "boolean" ? { approximate: value.approximate } : {},
|
|
7618
|
+
...typeof value.hll === "string" ? { hll: value.hll } : {},
|
|
7619
|
+
...Array.isArray(value.relays) ? { relays: value.relays } : {},
|
|
7620
|
+
...typeof value.error === "string" ? { error: value.error } : {},
|
|
7621
|
+
...typeof value.reason === "string" ? { reason: value.reason } : {}
|
|
7622
|
+
};
|
|
7623
|
+
}
|
|
7624
|
+
function isValidFilterArray2(value) {
|
|
7625
|
+
return Array.isArray(value) && value.length > 0 && value.every((filter) => isPlainObject2(filter));
|
|
7626
|
+
}
|
|
7627
|
+
function isPlainObject2(value) {
|
|
7628
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7629
|
+
}
|
|
7478
7630
|
var KEYS_SERVICE_VERSION = "1.2.0";
|
|
7479
7631
|
var MODIFIER_ALIASES = {
|
|
7480
7632
|
ctrl: "ctrl",
|
|
@@ -7492,11 +7644,11 @@ function parseChord(chord) {
|
|
|
7492
7644
|
if (chord.length === 0) throw new Error("empty chord");
|
|
7493
7645
|
const parts = chord.split("+");
|
|
7494
7646
|
const out = { ctrl: false, alt: false, shift: false, meta: false, key: "" };
|
|
7495
|
-
for (let
|
|
7496
|
-
const tok = parts[
|
|
7647
|
+
for (let i4 = 0; i4 < parts.length - 1; i4++) {
|
|
7648
|
+
const tok = parts[i4].trim().toLowerCase();
|
|
7497
7649
|
if (tok.length === 0) continue;
|
|
7498
7650
|
const slot = MODIFIER_ALIASES[tok];
|
|
7499
|
-
if (!slot) throw new Error(`unknown modifier: ${parts[
|
|
7651
|
+
if (!slot) throw new Error(`unknown modifier: ${parts[i4]}`);
|
|
7500
7652
|
out[slot] = true;
|
|
7501
7653
|
}
|
|
7502
7654
|
const keyTok = parts[parts.length - 1].trim();
|
|
@@ -7588,13 +7740,13 @@ function createKeysService(options = {}) {
|
|
|
7588
7740
|
return;
|
|
7589
7741
|
}
|
|
7590
7742
|
}
|
|
7591
|
-
const
|
|
7743
|
+
const result2 = {
|
|
7592
7744
|
type: "keys.registerAction.result",
|
|
7593
7745
|
id: m.id,
|
|
7594
7746
|
actionId: m.action.id,
|
|
7595
7747
|
...m.action.defaultKey ? { binding: m.action.defaultKey } : {}
|
|
7596
7748
|
};
|
|
7597
|
-
send(
|
|
7749
|
+
send(result2);
|
|
7598
7750
|
return;
|
|
7599
7751
|
}
|
|
7600
7752
|
case "keys.unregisterAction": {
|
|
@@ -7735,13 +7887,13 @@ function createKeysService(options = {}) {
|
|
|
7735
7887
|
return;
|
|
7736
7888
|
}
|
|
7737
7889
|
}
|
|
7738
|
-
const
|
|
7890
|
+
const result2 = {
|
|
7739
7891
|
type: "keys.registerAction.result",
|
|
7740
7892
|
id: m.id,
|
|
7741
7893
|
actionId: m.action.id,
|
|
7742
7894
|
...m.action.defaultKey ? { binding: m.action.defaultKey } : {}
|
|
7743
7895
|
};
|
|
7744
|
-
send(
|
|
7896
|
+
send(result2);
|
|
7745
7897
|
return;
|
|
7746
7898
|
}
|
|
7747
7899
|
case "keys.unregisterAction": {
|
|
@@ -8166,12 +8318,12 @@ function createNotifyService(options = {}) {
|
|
|
8166
8318
|
case "notify.send": {
|
|
8167
8319
|
const m = message;
|
|
8168
8320
|
options.onSend?.(windowId, m);
|
|
8169
|
-
const
|
|
8321
|
+
const result2 = {
|
|
8170
8322
|
type: "notify.send.result",
|
|
8171
8323
|
id: m.id,
|
|
8172
8324
|
notificationId: gen()
|
|
8173
8325
|
};
|
|
8174
|
-
send(
|
|
8326
|
+
send(result2);
|
|
8175
8327
|
return;
|
|
8176
8328
|
}
|
|
8177
8329
|
case "notify.dismiss":
|
|
@@ -8180,12 +8332,12 @@ function createNotifyService(options = {}) {
|
|
|
8180
8332
|
return;
|
|
8181
8333
|
case "notify.permission.request": {
|
|
8182
8334
|
const m = message;
|
|
8183
|
-
const
|
|
8335
|
+
const result2 = {
|
|
8184
8336
|
type: "notify.permission.result",
|
|
8185
8337
|
id: m.id,
|
|
8186
8338
|
granted: defaultGrant
|
|
8187
8339
|
};
|
|
8188
|
-
send(
|
|
8340
|
+
send(result2);
|
|
8189
8341
|
return;
|
|
8190
8342
|
}
|
|
8191
8343
|
default: {
|
|
@@ -8224,12 +8376,12 @@ function createThemeService(options = {}) {
|
|
|
8224
8376
|
handleMessage(_windowId, message, send) {
|
|
8225
8377
|
const id = message.id ?? "";
|
|
8226
8378
|
if (message.type === "theme.get") {
|
|
8227
|
-
const
|
|
8379
|
+
const result2 = {
|
|
8228
8380
|
type: "theme.get.result",
|
|
8229
8381
|
id,
|
|
8230
8382
|
theme: currentTheme
|
|
8231
8383
|
};
|
|
8232
|
-
send(
|
|
8384
|
+
send(result2);
|
|
8233
8385
|
return;
|
|
8234
8386
|
}
|
|
8235
8387
|
send({
|
|
@@ -8351,14 +8503,14 @@ function createConfigService(options) {
|
|
|
8351
8503
|
case "config.registerSchema": {
|
|
8352
8504
|
const m = message;
|
|
8353
8505
|
const validation = options.registerSchema ? options.registerSchema(windowId, m.schema, m.version) : validateCoreSubset(m.schema);
|
|
8354
|
-
const
|
|
8506
|
+
const result2 = validation.ok ? { type: "config.registerSchema.result", id: m.id, ok: true } : {
|
|
8355
8507
|
type: "config.registerSchema.result",
|
|
8356
8508
|
id: m.id,
|
|
8357
8509
|
ok: false,
|
|
8358
8510
|
code: validation.code,
|
|
8359
8511
|
error: validation.error
|
|
8360
8512
|
};
|
|
8361
|
-
send(
|
|
8513
|
+
send(result2);
|
|
8362
8514
|
return;
|
|
8363
8515
|
}
|
|
8364
8516
|
case "config.openSettings": {
|
|
@@ -8393,8 +8545,8 @@ function arrayBufferToBase64(buf) {
|
|
|
8393
8545
|
const bytes = new Uint8Array(buf);
|
|
8394
8546
|
const CHUNK = 32768;
|
|
8395
8547
|
let binary = "";
|
|
8396
|
-
for (let
|
|
8397
|
-
binary += String.fromCharCode(...bytes.subarray(
|
|
8548
|
+
for (let i4 = 0; i4 < bytes.length; i4 += CHUNK) {
|
|
8549
|
+
binary += String.fromCharCode(...bytes.subarray(i4, i4 + CHUNK));
|
|
8398
8550
|
}
|
|
8399
8551
|
return btoa(binary);
|
|
8400
8552
|
}
|
|
@@ -8725,33 +8877,33 @@ function buildEventQuery(eventId, eventOptions) {
|
|
|
8725
8877
|
if (eventOptions?.timeoutMs !== void 0) queryOptions.timeoutMs = eventOptions.timeoutMs;
|
|
8726
8878
|
return { filter, queryOptions };
|
|
8727
8879
|
}
|
|
8728
|
-
function eventResultFromQuery(eventId,
|
|
8729
|
-
const event =
|
|
8880
|
+
function eventResultFromQuery(eventId, result2) {
|
|
8881
|
+
const event = result2.events.find((candidate) => candidate.id === eventId);
|
|
8730
8882
|
const eventResult = {
|
|
8731
|
-
relays: event ?
|
|
8883
|
+
relays: event ? result2.relays[eventId] ?? [] : []
|
|
8732
8884
|
};
|
|
8733
8885
|
if (event) eventResult.event = event;
|
|
8734
|
-
if (!event) eventResult.error =
|
|
8735
|
-
else if (
|
|
8736
|
-
if (
|
|
8886
|
+
if (!event) eventResult.error = result2.error ?? "not found";
|
|
8887
|
+
else if (result2.error !== void 0) eventResult.error = result2.error;
|
|
8888
|
+
if (result2.incomplete !== void 0) eventResult.incomplete = result2.incomplete;
|
|
8737
8889
|
return eventResult;
|
|
8738
8890
|
}
|
|
8739
8891
|
function fallbackGetEvent(router, eventId, eventOptions) {
|
|
8740
8892
|
const { filter, queryOptions } = buildEventQuery(eventId, eventOptions);
|
|
8741
|
-
return router.query([filter], queryOptions).then((
|
|
8893
|
+
return router.query([filter], queryOptions).then((result2) => eventResultFromQuery(eventId, result2));
|
|
8742
8894
|
}
|
|
8743
|
-
function sendEventResult(id, eventId,
|
|
8744
|
-
if (
|
|
8895
|
+
function sendEventResult(id, eventId, result2, send) {
|
|
8896
|
+
if (result2.event && result2.event.id !== eventId) {
|
|
8745
8897
|
send({ type: "outbox.getEvent.result", id, relays: [], error: "not found" });
|
|
8746
8898
|
return;
|
|
8747
8899
|
}
|
|
8748
8900
|
send({
|
|
8749
8901
|
type: "outbox.getEvent.result",
|
|
8750
8902
|
id,
|
|
8751
|
-
...
|
|
8752
|
-
relays:
|
|
8753
|
-
...
|
|
8754
|
-
...
|
|
8903
|
+
...result2.event === void 0 ? {} : { event: result2.event },
|
|
8904
|
+
relays: result2.relays,
|
|
8905
|
+
...result2.incomplete === void 0 ? {} : { incomplete: result2.incomplete },
|
|
8906
|
+
...result2.error === void 0 ? {} : { error: result2.error }
|
|
8755
8907
|
});
|
|
8756
8908
|
}
|
|
8757
8909
|
function handleGetEvent(router, msg, send) {
|
|
@@ -8762,7 +8914,7 @@ function handleGetEvent(router, msg, send) {
|
|
|
8762
8914
|
return;
|
|
8763
8915
|
}
|
|
8764
8916
|
const getEvent = router.getEvent ?? ((eventId, eventOptions) => fallbackGetEvent(router, eventId, eventOptions));
|
|
8765
|
-
void getEvent(m.eventId, m.options).then((
|
|
8917
|
+
void getEvent(m.eventId, m.options).then((result2) => sendEventResult(id, m.eventId, result2, send)).catch(
|
|
8766
8918
|
(err2) => send({ type: "outbox.getEvent.result", id, relays: [], error: toErrorMessage(err2) })
|
|
8767
8919
|
);
|
|
8768
8920
|
}
|
|
@@ -8781,13 +8933,13 @@ function createOutboxService(options) {
|
|
|
8781
8933
|
return;
|
|
8782
8934
|
}
|
|
8783
8935
|
void router.query(filters, m.options).then(
|
|
8784
|
-
(
|
|
8936
|
+
(result2) => send({
|
|
8785
8937
|
type: "outbox.query.result",
|
|
8786
8938
|
id,
|
|
8787
|
-
events:
|
|
8788
|
-
relays:
|
|
8789
|
-
...
|
|
8790
|
-
...
|
|
8939
|
+
events: result2.events,
|
|
8940
|
+
relays: result2.relays,
|
|
8941
|
+
...result2.incomplete === void 0 ? {} : { incomplete: result2.incomplete },
|
|
8942
|
+
...result2.error === void 0 ? {} : { error: result2.error }
|
|
8791
8943
|
})
|
|
8792
8944
|
).catch(
|
|
8793
8945
|
(err2) => send({ type: "outbox.query.result", id, events: [], relays: {}, error: toErrorMessage(err2) })
|
|
@@ -8832,14 +8984,14 @@ function createOutboxService(options) {
|
|
|
8832
8984
|
return;
|
|
8833
8985
|
}
|
|
8834
8986
|
void router.publish(m.event, m.options).then(
|
|
8835
|
-
(
|
|
8987
|
+
(result2) => send({
|
|
8836
8988
|
type: "outbox.publish.result",
|
|
8837
8989
|
id,
|
|
8838
|
-
ok:
|
|
8839
|
-
...
|
|
8840
|
-
...
|
|
8841
|
-
...
|
|
8842
|
-
...
|
|
8990
|
+
ok: result2.ok,
|
|
8991
|
+
...result2.event === void 0 ? {} : { event: result2.event },
|
|
8992
|
+
...result2.eventId === void 0 ? {} : { eventId: result2.eventId },
|
|
8993
|
+
...result2.relays === void 0 ? {} : { relays: result2.relays },
|
|
8994
|
+
...result2.error === void 0 ? {} : { error: result2.error }
|
|
8843
8995
|
})
|
|
8844
8996
|
).catch(
|
|
8845
8997
|
(err2) => send({ type: "outbox.publish.result", id, ok: false, error: toErrorMessage(err2) })
|
|
@@ -8957,8 +9109,8 @@ function createUploadService(options) {
|
|
|
8957
9109
|
send({ type: "upload.status.changed", status: stamped });
|
|
8958
9110
|
}
|
|
8959
9111
|
};
|
|
8960
|
-
void uploader.upload(request, ctx).then((
|
|
8961
|
-
const stamped = { ...
|
|
9112
|
+
void uploader.upload(request, ctx).then((result2) => {
|
|
9113
|
+
const stamped = { ...result2, uploadId };
|
|
8962
9114
|
const entry = entries.get(key);
|
|
8963
9115
|
if (entry) entry.status = { ...stamped, updatedAt: now2() };
|
|
8964
9116
|
send({ type: "upload.upload.result", id, result: stamped });
|
|
@@ -9070,7 +9222,7 @@ function createIntentService(options) {
|
|
|
9070
9222
|
send,
|
|
9071
9223
|
"intent.invoke.result",
|
|
9072
9224
|
id,
|
|
9073
|
-
(
|
|
9225
|
+
(result2) => ({ type: "intent.invoke.result", id, result: result2 })
|
|
9074
9226
|
);
|
|
9075
9227
|
}
|
|
9076
9228
|
function handleAvailable(msg, send) {
|
|
@@ -9258,12 +9410,12 @@ async function handleOpen(options, windowId, message, send) {
|
|
|
9258
9410
|
return;
|
|
9259
9411
|
}
|
|
9260
9412
|
try {
|
|
9261
|
-
const
|
|
9413
|
+
const result2 = await options.open({ windowId, url: parsed, options: message.options });
|
|
9262
9414
|
send({
|
|
9263
9415
|
type: "link.open.result",
|
|
9264
9416
|
id: message.id,
|
|
9265
|
-
status:
|
|
9266
|
-
...
|
|
9417
|
+
status: result2.status,
|
|
9418
|
+
...result2.status === "denied" ? { error: "blocked-by-policy" } : {}
|
|
9267
9419
|
});
|
|
9268
9420
|
} catch {
|
|
9269
9421
|
send(denied(message.id, "blocked-by-policy"));
|
|
@@ -9333,7 +9485,7 @@ function settleMutation(hook, message, context, send, resultType) {
|
|
|
9333
9485
|
() => hook(message.list, message.items, message.options, context),
|
|
9334
9486
|
send,
|
|
9335
9487
|
(error) => ({ type: resultType, id: message.id, ok: false, error: "list-unavailable", reason: error }),
|
|
9336
|
-
(
|
|
9488
|
+
(result2) => ({ type: resultType, id: message.id, ...result2 })
|
|
9337
9489
|
);
|
|
9338
9490
|
}
|
|
9339
9491
|
function createListsService(options = {}) {
|
|
@@ -9417,7 +9569,7 @@ function createSerialService(options = {}) {
|
|
|
9417
9569
|
() => options.open(serialMessage.request, context),
|
|
9418
9570
|
send,
|
|
9419
9571
|
(error) => ({ type: "serial.open.result", id, error }),
|
|
9420
|
-
(
|
|
9572
|
+
(result2) => ({ type: "serial.open.result", id, session: result2.session })
|
|
9421
9573
|
);
|
|
9422
9574
|
return;
|
|
9423
9575
|
}
|
|
@@ -9512,7 +9664,7 @@ function createBleService(options = {}) {
|
|
|
9512
9664
|
() => options.open(bleMessage.request, context),
|
|
9513
9665
|
send,
|
|
9514
9666
|
(error) => ({ type: "ble.open.result", id, error }),
|
|
9515
|
-
(
|
|
9667
|
+
(result2) => ({ type: "ble.open.result", id, session: result2.session })
|
|
9516
9668
|
);
|
|
9517
9669
|
return;
|
|
9518
9670
|
}
|
|
@@ -9663,7 +9815,7 @@ function createWebrtcService(options = {}) {
|
|
|
9663
9815
|
() => options.open(webrtcMessage.request, context),
|
|
9664
9816
|
send,
|
|
9665
9817
|
(error) => ({ type: "webrtc.open.result", id, error }),
|
|
9666
|
-
(
|
|
9818
|
+
(result2) => ({ type: "webrtc.open.result", id, session: result2.session })
|
|
9667
9819
|
);
|
|
9668
9820
|
return;
|
|
9669
9821
|
}
|
|
@@ -9803,7 +9955,7 @@ function decodeNrelay(value) {
|
|
|
9803
9955
|
function convertBits(data, fromBits, toBits, pad2) {
|
|
9804
9956
|
let acc = 0;
|
|
9805
9957
|
let bits = 0;
|
|
9806
|
-
const
|
|
9958
|
+
const result2 = [];
|
|
9807
9959
|
const maxv = (1 << toBits) - 1;
|
|
9808
9960
|
const maxAcc = (1 << fromBits + toBits - 1) - 1;
|
|
9809
9961
|
for (const value of data) {
|
|
@@ -9812,15 +9964,15 @@ function convertBits(data, fromBits, toBits, pad2) {
|
|
|
9812
9964
|
bits += fromBits;
|
|
9813
9965
|
while (bits >= toBits) {
|
|
9814
9966
|
bits -= toBits;
|
|
9815
|
-
|
|
9967
|
+
result2.push(acc >> bits & maxv);
|
|
9816
9968
|
}
|
|
9817
9969
|
}
|
|
9818
9970
|
if (pad2) {
|
|
9819
|
-
if (bits > 0)
|
|
9971
|
+
if (bits > 0) result2.push(acc << toBits - bits & maxv);
|
|
9820
9972
|
} else if (bits >= fromBits || (acc << toBits - bits & maxv) !== 0) {
|
|
9821
9973
|
throw new Error("invalid bech32 padding");
|
|
9822
9974
|
}
|
|
9823
|
-
return
|
|
9975
|
+
return result2;
|
|
9824
9976
|
}
|
|
9825
9977
|
function settle5(call, send, okFalse, onValue) {
|
|
9826
9978
|
let pending;
|
|
@@ -9840,14 +9992,14 @@ function createCommonService(options = {}) {
|
|
|
9840
9992
|
const context = { windowId };
|
|
9841
9993
|
if (message.type === "common.encodeNip19") {
|
|
9842
9994
|
const input = message.input;
|
|
9843
|
-
const
|
|
9844
|
-
send({ type: "common.encodeNip19.result", id, ...
|
|
9995
|
+
const result2 = input ? encodeNip19(input) : { ok: false, error: "invalid input" };
|
|
9996
|
+
send({ type: "common.encodeNip19.result", id, ...result2 });
|
|
9845
9997
|
return;
|
|
9846
9998
|
}
|
|
9847
9999
|
if (message.type === "common.decodeNip19") {
|
|
9848
10000
|
const value = message.value;
|
|
9849
|
-
const
|
|
9850
|
-
send({ type: "common.decodeNip19.result", id, ...
|
|
10001
|
+
const result2 = typeof value === "string" ? decodeNip19Value(value) : { ok: false, error: "invalid value" };
|
|
10002
|
+
send({ type: "common.decodeNip19.result", id, ...result2 });
|
|
9851
10003
|
return;
|
|
9852
10004
|
}
|
|
9853
10005
|
if (message.type === "common.getProfile") {
|
|
@@ -9860,7 +10012,7 @@ function createCommonService(options = {}) {
|
|
|
9860
10012
|
() => options.getProfile(target, context),
|
|
9861
10013
|
send,
|
|
9862
10014
|
(error) => ({ type: "common.getProfile.result", id, ok: false, pubkey: target ?? "", error }),
|
|
9863
|
-
(
|
|
10015
|
+
(result2) => ({ type: "common.getProfile.result", id, ...result2 })
|
|
9864
10016
|
);
|
|
9865
10017
|
return;
|
|
9866
10018
|
}
|
|
@@ -9873,7 +10025,7 @@ function createCommonService(options = {}) {
|
|
|
9873
10025
|
() => options.follows(context),
|
|
9874
10026
|
send,
|
|
9875
10027
|
(error) => ({ type: "common.follows.result", id, ok: false, pubkeys: [], error }),
|
|
9876
|
-
(
|
|
10028
|
+
(result2) => ({ type: "common.follows.result", id, ...result2 })
|
|
9877
10029
|
);
|
|
9878
10030
|
return;
|
|
9879
10031
|
}
|
|
@@ -9897,7 +10049,7 @@ function createCommonService(options = {}) {
|
|
|
9897
10049
|
() => options.react(m.targetEventId, m.reaction, m.customEmojiHref, context),
|
|
9898
10050
|
send,
|
|
9899
10051
|
(error) => ({ type: "common.react.result", id, ok: false, error }),
|
|
9900
|
-
(
|
|
10052
|
+
(result2) => ({ type: "common.react.result", id, ...result2 })
|
|
9901
10053
|
);
|
|
9902
10054
|
return;
|
|
9903
10055
|
}
|
|
@@ -9911,7 +10063,7 @@ function createCommonService(options = {}) {
|
|
|
9911
10063
|
() => options.report(m.target, m.reason, m.text, context),
|
|
9912
10064
|
send,
|
|
9913
10065
|
(error) => ({ type: "common.report.result", id, ok: false, error }),
|
|
9914
|
-
(
|
|
10066
|
+
(result2) => ({ type: "common.report.result", id, ...result2 })
|
|
9915
10067
|
);
|
|
9916
10068
|
return;
|
|
9917
10069
|
}
|
|
@@ -9934,7 +10086,7 @@ function settleAction(action, pubkeys, context, send, resultType, id, unavailabl
|
|
|
9934
10086
|
() => action(pubkeys, context),
|
|
9935
10087
|
send,
|
|
9936
10088
|
(error) => ({ type: resultType, id, ok: false, error }),
|
|
9937
|
-
(
|
|
10089
|
+
(result2) => ({ type: resultType, id, ...result2 })
|
|
9938
10090
|
);
|
|
9939
10091
|
}
|
|
9940
10092
|
|
|
@@ -10183,6 +10335,13 @@ function createMemoryRelayPool(getSimulation, confirmRequest) {
|
|
|
10183
10335
|
} };
|
|
10184
10336
|
}
|
|
10185
10337
|
};
|
|
10338
|
+
},
|
|
10339
|
+
count(_relayUrls, filters) {
|
|
10340
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10341
|
+
for (const event of events) {
|
|
10342
|
+
if (matchesAnyFilter2(event, filters)) seen.add(event.id);
|
|
10343
|
+
}
|
|
10344
|
+
return seen.size;
|
|
10186
10345
|
}
|
|
10187
10346
|
};
|
|
10188
10347
|
}
|
|
@@ -10241,7 +10400,7 @@ function createDevUploader(getSimulation) {
|
|
|
10241
10400
|
throw new Error("upload simulation is disabled");
|
|
10242
10401
|
}
|
|
10243
10402
|
const size = request.data instanceof Blob ? request.data.size : request.data.byteLength;
|
|
10244
|
-
const
|
|
10403
|
+
const result2 = {
|
|
10245
10404
|
ok: true,
|
|
10246
10405
|
uploadId: ctx.uploadId,
|
|
10247
10406
|
status: "complete",
|
|
@@ -10250,8 +10409,8 @@ function createDevUploader(getSimulation) {
|
|
|
10250
10409
|
size,
|
|
10251
10410
|
mimeType: request.mimeType ?? (request.data instanceof Blob ? request.data.type : void 0)
|
|
10252
10411
|
};
|
|
10253
|
-
ctx.onStatus({ ...
|
|
10254
|
-
return
|
|
10412
|
+
ctx.onStatus({ ...result2, updatedAt: Date.now() });
|
|
10413
|
+
return result2;
|
|
10255
10414
|
},
|
|
10256
10415
|
async status(uploadId) {
|
|
10257
10416
|
const simulation = getSimulation();
|
|
@@ -10426,6 +10585,25 @@ function createDevServices(pool, getSimulation, onThemeService, confirmRequest,
|
|
|
10426
10585
|
});
|
|
10427
10586
|
services.outbox = createOutboxService({ router: createOutboxRouter(pool, getSimulation, confirmRequest, signerProvider) });
|
|
10428
10587
|
}
|
|
10588
|
+
if (getSimulation().capabilities.domains.count && typeof pool.count === "function") {
|
|
10589
|
+
services.count = createCountService({
|
|
10590
|
+
count: async ({ filters }) => {
|
|
10591
|
+
const relays = getRelayUrls(getSimulation());
|
|
10592
|
+
return {
|
|
10593
|
+
ok: true,
|
|
10594
|
+
count: await pool.count(relays, filters),
|
|
10595
|
+
approximate: false,
|
|
10596
|
+
relays
|
|
10597
|
+
};
|
|
10598
|
+
},
|
|
10599
|
+
isFilterSupported: (filter) => {
|
|
10600
|
+
if (Object.keys(filter).length === 0) {
|
|
10601
|
+
return "broad empty filters are too expensive for the Paja count backend";
|
|
10602
|
+
}
|
|
10603
|
+
return true;
|
|
10604
|
+
}
|
|
10605
|
+
});
|
|
10606
|
+
}
|
|
10429
10607
|
if (getSimulation().capabilities.domains.identity) {
|
|
10430
10608
|
services.identity = createIdentityService({ getSigner: () => createRuntimeSigner(getSimulation, confirmRequest, signerProvider) });
|
|
10431
10609
|
}
|
|
@@ -10500,7 +10678,7 @@ function createDevServices(pool, getSimulation, onThemeService, confirmRequest,
|
|
|
10500
10678
|
}
|
|
10501
10679
|
return services;
|
|
10502
10680
|
}
|
|
10503
|
-
function createPajaAdapter(config, getSimulation, onThemeService, confirmRequest, signerProvider) {
|
|
10681
|
+
function createPajaAdapter(config, getSimulation, onThemeService, confirmRequest, signerProvider, getIdentity) {
|
|
10504
10682
|
const pool = createMemoryRelayPool(getSimulation, confirmRequest);
|
|
10505
10683
|
const workerRelayEvents = [];
|
|
10506
10684
|
return {
|
|
@@ -10540,10 +10718,13 @@ function createPajaAdapter(config, getSimulation, onThemeService, confirmRequest
|
|
|
10540
10718
|
crypto: {
|
|
10541
10719
|
verifyEvent: async () => true
|
|
10542
10720
|
},
|
|
10543
|
-
onNip5dIframeCreate: () =>
|
|
10544
|
-
|
|
10545
|
-
|
|
10546
|
-
|
|
10721
|
+
onNip5dIframeCreate: () => {
|
|
10722
|
+
const identity = getIdentity?.();
|
|
10723
|
+
return {
|
|
10724
|
+
dTag: identity?.dTag ?? config.window.dTag,
|
|
10725
|
+
aggregateHash: identity?.aggregateHash ?? config.window.aggregateHash
|
|
10726
|
+
};
|
|
10727
|
+
}
|
|
10547
10728
|
};
|
|
10548
10729
|
}
|
|
10549
10730
|
|
|
@@ -10567,14 +10748,14 @@ function mul(a, b) {
|
|
|
10567
10748
|
}
|
|
10568
10749
|
var sbox = /* @__PURE__ */ (() => {
|
|
10569
10750
|
const t = new Uint8Array(256);
|
|
10570
|
-
for (let
|
|
10571
|
-
t[
|
|
10751
|
+
for (let i4 = 0, x = 1; i4 < 256; i4++, x ^= mul2(x))
|
|
10752
|
+
t[i4] = x;
|
|
10572
10753
|
const box = new Uint8Array(256);
|
|
10573
10754
|
box[0] = 99;
|
|
10574
|
-
for (let
|
|
10575
|
-
let x = t[255 -
|
|
10755
|
+
for (let i4 = 0; i4 < 255; i4++) {
|
|
10756
|
+
let x = t[255 - i4];
|
|
10576
10757
|
x |= x << 8;
|
|
10577
|
-
box[t[
|
|
10758
|
+
box[t[i4]] = (x ^ x >> 4 ^ x >> 5 ^ x >> 6 ^ x >> 7 ^ 99) & 255;
|
|
10578
10759
|
}
|
|
10579
10760
|
clean2(t);
|
|
10580
10761
|
return box;
|
|
@@ -10592,12 +10773,12 @@ function genTtable(sbox2, fn) {
|
|
|
10592
10773
|
const T01 = new Uint32Array(256 * 256);
|
|
10593
10774
|
const T23 = new Uint32Array(256 * 256);
|
|
10594
10775
|
const sbox22 = new Uint16Array(256 * 256);
|
|
10595
|
-
for (let
|
|
10776
|
+
for (let i4 = 0; i4 < 256; i4++) {
|
|
10596
10777
|
for (let j = 0; j < 256; j++) {
|
|
10597
|
-
const idx =
|
|
10598
|
-
T01[idx] = T0[
|
|
10599
|
-
T23[idx] = T2[
|
|
10600
|
-
sbox22[idx] = sbox2[
|
|
10778
|
+
const idx = i4 * 256 + j;
|
|
10779
|
+
T01[idx] = T0[i4] ^ T1[j];
|
|
10780
|
+
T23[idx] = T2[i4] ^ T3[j];
|
|
10781
|
+
sbox22[idx] = sbox2[i4] << 8 | sbox2[j];
|
|
10601
10782
|
}
|
|
10602
10783
|
}
|
|
10603
10784
|
return { sbox: sbox2, sbox2: sbox22, T0, T1, T2, T3, T01, T23 };
|
|
@@ -10606,8 +10787,8 @@ var tableEncoding = /* @__PURE__ */ genTtable(sbox, (s) => mul(s, 3) << 24 | s <
|
|
|
10606
10787
|
var tableDecoding = /* @__PURE__ */ genTtable(invSbox, (s) => mul(s, 11) << 24 | mul(s, 13) << 16 | mul(s, 9) << 8 | mul(s, 14));
|
|
10607
10788
|
var xPowers = /* @__PURE__ */ (() => {
|
|
10608
10789
|
const p = new Uint8Array(16);
|
|
10609
|
-
for (let
|
|
10610
|
-
p[
|
|
10790
|
+
for (let i4 = 0, x = 1; i4 < 16; i4++, x = mul2(x))
|
|
10791
|
+
p[i4] = x;
|
|
10611
10792
|
return p;
|
|
10612
10793
|
})();
|
|
10613
10794
|
function expandKeyLE(key) {
|
|
@@ -10623,13 +10804,13 @@ function expandKeyLE(key) {
|
|
|
10623
10804
|
const subByte = (n) => applySbox(sbox2, n, n, n, n);
|
|
10624
10805
|
const xk = new Uint32Array(len + 28);
|
|
10625
10806
|
xk.set(k32);
|
|
10626
|
-
for (let
|
|
10627
|
-
let t = xk[
|
|
10628
|
-
if (
|
|
10629
|
-
t = subByte(rotr32_8(t)) ^ xPowers[
|
|
10630
|
-
else if (Nk > 6 &&
|
|
10807
|
+
for (let i4 = Nk; i4 < xk.length; i4++) {
|
|
10808
|
+
let t = xk[i4 - 1];
|
|
10809
|
+
if (i4 % Nk === 0)
|
|
10810
|
+
t = subByte(rotr32_8(t)) ^ xPowers[i4 / Nk - 1];
|
|
10811
|
+
else if (Nk > 6 && i4 % Nk === 4)
|
|
10631
10812
|
t = subByte(t);
|
|
10632
|
-
xk[
|
|
10813
|
+
xk[i4] = xk[i4 - Nk] ^ t;
|
|
10633
10814
|
}
|
|
10634
10815
|
clean2(...toClean);
|
|
10635
10816
|
return xk;
|
|
@@ -10640,15 +10821,15 @@ function expandKeyDecLE(key) {
|
|
|
10640
10821
|
const Nk = encKey.length;
|
|
10641
10822
|
const { sbox2 } = tableEncoding;
|
|
10642
10823
|
const { T0, T1, T2, T3 } = tableDecoding;
|
|
10643
|
-
for (let
|
|
10824
|
+
for (let i4 = 0; i4 < Nk; i4 += 4) {
|
|
10644
10825
|
for (let j = 0; j < 4; j++)
|
|
10645
|
-
xk[
|
|
10826
|
+
xk[i4 + j] = encKey[Nk - i4 - 4 + j];
|
|
10646
10827
|
}
|
|
10647
10828
|
clean2(encKey);
|
|
10648
|
-
for (let
|
|
10649
|
-
const x = xk[
|
|
10829
|
+
for (let i4 = 4; i4 < Nk - 4; i4++) {
|
|
10830
|
+
const x = xk[i4];
|
|
10650
10831
|
const w = applySbox(sbox2, x, x, x, x);
|
|
10651
|
-
xk[
|
|
10832
|
+
xk[i4] = T0[w & 255] ^ T1[w >>> 8 & 255] ^ T2[w >>> 16 & 255] ^ T3[w >>> 24];
|
|
10652
10833
|
}
|
|
10653
10834
|
return xk;
|
|
10654
10835
|
}
|
|
@@ -10663,7 +10844,7 @@ function encrypt(xk, s0, s1, s2, s3) {
|
|
|
10663
10844
|
let k = 0;
|
|
10664
10845
|
s0 ^= xk[k++], s1 ^= xk[k++], s2 ^= xk[k++], s3 ^= xk[k++];
|
|
10665
10846
|
const rounds = xk.length / 4 - 2;
|
|
10666
|
-
for (let
|
|
10847
|
+
for (let i4 = 0; i4 < rounds; i4++) {
|
|
10667
10848
|
const t02 = xk[k++] ^ apply0123(T01, T23, s0, s1, s2, s3);
|
|
10668
10849
|
const t12 = xk[k++] ^ apply0123(T01, T23, s1, s2, s3, s0);
|
|
10669
10850
|
const t22 = xk[k++] ^ apply0123(T01, T23, s2, s3, s0, s1);
|
|
@@ -10681,7 +10862,7 @@ function decrypt(xk, s0, s1, s2, s3) {
|
|
|
10681
10862
|
let k = 0;
|
|
10682
10863
|
s0 ^= xk[k++], s1 ^= xk[k++], s2 ^= xk[k++], s3 ^= xk[k++];
|
|
10683
10864
|
const rounds = xk.length / 4 - 2;
|
|
10684
|
-
for (let
|
|
10865
|
+
for (let i4 = 0; i4 < rounds; i4++) {
|
|
10685
10866
|
const t02 = xk[k++] ^ apply0123(T01, T23, s0, s3, s2, s1);
|
|
10686
10867
|
const t12 = xk[k++] ^ apply0123(T01, T23, s1, s0, s3, s2);
|
|
10687
10868
|
const t22 = xk[k++] ^ apply0123(T01, T23, s2, s1, s0, s3);
|
|
@@ -10730,8 +10911,8 @@ function validatePCKS(data, pcks5) {
|
|
|
10730
10911
|
if (lastByte <= 0 || lastByte > 16)
|
|
10731
10912
|
throw new Error("aes/pcks5: wrong padding");
|
|
10732
10913
|
const out = data.subarray(0, -lastByte);
|
|
10733
|
-
for (let
|
|
10734
|
-
if (data[len -
|
|
10914
|
+
for (let i4 = 0; i4 < lastByte; i4++)
|
|
10915
|
+
if (data[len - i4 - 1] !== lastByte)
|
|
10735
10916
|
throw new Error("aes/pcks5: wrong padding");
|
|
10736
10917
|
return out;
|
|
10737
10918
|
}
|
|
@@ -10740,8 +10921,8 @@ function padPCKS(left) {
|
|
|
10740
10921
|
const tmp32 = u32(tmp);
|
|
10741
10922
|
tmp.set(left);
|
|
10742
10923
|
const paddingByte = BLOCK_SIZE - left.length;
|
|
10743
|
-
for (let
|
|
10744
|
-
tmp[
|
|
10924
|
+
for (let i4 = BLOCK_SIZE - paddingByte; i4 < BLOCK_SIZE; i4++)
|
|
10925
|
+
tmp[i4] = paddingByte;
|
|
10745
10926
|
return tmp32;
|
|
10746
10927
|
}
|
|
10747
10928
|
var cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, function aescbc(key, iv, opts = {}) {
|
|
@@ -10756,17 +10937,17 @@ var cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, functio
|
|
|
10756
10937
|
toClean.push(_iv = copyBytes2(_iv));
|
|
10757
10938
|
const n32 = u32(_iv);
|
|
10758
10939
|
let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3];
|
|
10759
|
-
let
|
|
10760
|
-
for (;
|
|
10761
|
-
s0 ^= b[
|
|
10940
|
+
let i4 = 0;
|
|
10941
|
+
for (; i4 + 4 <= b.length; ) {
|
|
10942
|
+
s0 ^= b[i4 + 0], s1 ^= b[i4 + 1], s2 ^= b[i4 + 2], s3 ^= b[i4 + 3];
|
|
10762
10943
|
({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3));
|
|
10763
|
-
o[
|
|
10944
|
+
o[i4++] = s0, o[i4++] = s1, o[i4++] = s2, o[i4++] = s3;
|
|
10764
10945
|
}
|
|
10765
10946
|
if (pcks5) {
|
|
10766
|
-
const tmp32 = padPCKS(plaintext.subarray(
|
|
10947
|
+
const tmp32 = padPCKS(plaintext.subarray(i4 * 4));
|
|
10767
10948
|
s0 ^= tmp32[0], s1 ^= tmp32[1], s2 ^= tmp32[2], s3 ^= tmp32[3];
|
|
10768
10949
|
({ s0, s1, s2, s3 } = encrypt(xk, s0, s1, s2, s3));
|
|
10769
|
-
o[
|
|
10950
|
+
o[i4++] = s0, o[i4++] = s1, o[i4++] = s2, o[i4++] = s3;
|
|
10770
10951
|
}
|
|
10771
10952
|
clean2(...toClean);
|
|
10772
10953
|
return _out;
|
|
@@ -10786,11 +10967,11 @@ var cbc = /* @__PURE__ */ wrapCipher({ blockSize: 16, nonceLength: 16 }, functio
|
|
|
10786
10967
|
const b = u32(ciphertext);
|
|
10787
10968
|
const o = u32(dst);
|
|
10788
10969
|
let s0 = n32[0], s1 = n32[1], s2 = n32[2], s3 = n32[3];
|
|
10789
|
-
for (let
|
|
10970
|
+
for (let i4 = 0; i4 + 4 <= b.length; ) {
|
|
10790
10971
|
const ps0 = s0, ps1 = s1, ps2 = s2, ps3 = s3;
|
|
10791
|
-
s0 = b[
|
|
10972
|
+
s0 = b[i4 + 0], s1 = b[i4 + 1], s2 = b[i4 + 2], s3 = b[i4 + 3];
|
|
10792
10973
|
const { s0: o0, s1: o1, s2: o2, s3: o3 } = decrypt(xk, s0, s1, s2, s3);
|
|
10793
|
-
o[
|
|
10974
|
+
o[i4++] = o0 ^ ps0, o[i4++] = o1 ^ ps1, o[i4++] = o2 ^ ps2, o[i4++] = o3 ^ ps3;
|
|
10794
10975
|
}
|
|
10795
10976
|
clean2(...toClean);
|
|
10796
10977
|
return validatePCKS(dst, pcks5);
|
|
@@ -10811,9 +10992,9 @@ function encryptBlock(xk, block2) {
|
|
|
10811
10992
|
}
|
|
10812
10993
|
function dbl(block2) {
|
|
10813
10994
|
let carry = 0;
|
|
10814
|
-
for (let
|
|
10815
|
-
const newCarry = (block2[
|
|
10816
|
-
block2[
|
|
10995
|
+
for (let i4 = BLOCK_SIZE - 1; i4 >= 0; i4--) {
|
|
10996
|
+
const newCarry = (block2[i4] & 128) >>> 7;
|
|
10997
|
+
block2[i4] = block2[i4] << 1 | carry;
|
|
10817
10998
|
carry = newCarry;
|
|
10818
10999
|
}
|
|
10819
11000
|
if (carry) {
|
|
@@ -10824,8 +11005,8 @@ function dbl(block2) {
|
|
|
10824
11005
|
function xorBlock(a, b) {
|
|
10825
11006
|
if (a.length !== b.length)
|
|
10826
11007
|
throw new Error("xorBlock: blocks must have same length");
|
|
10827
|
-
for (let
|
|
10828
|
-
a[
|
|
11008
|
+
for (let i4 = 0; i4 < a.length; i4++) {
|
|
11009
|
+
a[i4] = a[i4] ^ b[i4];
|
|
10829
11010
|
}
|
|
10830
11011
|
return a;
|
|
10831
11012
|
}
|
|
@@ -10883,8 +11064,8 @@ var _CMAC = class {
|
|
|
10883
11064
|
m_last = xorBlock(padded, this.k2);
|
|
10884
11065
|
}
|
|
10885
11066
|
let x = new Uint8Array(BLOCK_SIZE);
|
|
10886
|
-
for (let
|
|
10887
|
-
const m_i = buffer.subarray(
|
|
11067
|
+
for (let i4 = 0; i4 < n - 1; i4++) {
|
|
11068
|
+
const m_i = buffer.subarray(i4 * BLOCK_SIZE, (i4 + 1) * BLOCK_SIZE);
|
|
10888
11069
|
xorBlock(x, m_i);
|
|
10889
11070
|
encryptBlock(this.xk, x);
|
|
10890
11071
|
}
|
|
@@ -11017,8 +11198,8 @@ function binarySearch(arr, compare) {
|
|
|
11017
11198
|
return [start, false];
|
|
11018
11199
|
}
|
|
11019
11200
|
function mergeReverseSortedLists(list1, list2) {
|
|
11020
|
-
const
|
|
11021
|
-
|
|
11201
|
+
const result2 = new Array(list1.length + list2.length);
|
|
11202
|
+
result2.length = 0;
|
|
11022
11203
|
let i1 = 0;
|
|
11023
11204
|
let i22 = 0;
|
|
11024
11205
|
let sameTimestampIds = [];
|
|
@@ -11031,40 +11212,40 @@ function mergeReverseSortedLists(list1, list2) {
|
|
|
11031
11212
|
next = list2[i22];
|
|
11032
11213
|
i22++;
|
|
11033
11214
|
}
|
|
11034
|
-
if (
|
|
11215
|
+
if (result2.length > 0 && result2[result2.length - 1].created_at === next.created_at) {
|
|
11035
11216
|
if (sameTimestampIds.includes(next.id))
|
|
11036
11217
|
continue;
|
|
11037
11218
|
} else {
|
|
11038
11219
|
sameTimestampIds.length = 0;
|
|
11039
11220
|
}
|
|
11040
|
-
|
|
11221
|
+
result2.push(next);
|
|
11041
11222
|
sameTimestampIds.push(next.id);
|
|
11042
11223
|
}
|
|
11043
11224
|
while (i1 < list1.length) {
|
|
11044
11225
|
const next = list1[i1];
|
|
11045
11226
|
i1++;
|
|
11046
|
-
if (
|
|
11227
|
+
if (result2.length > 0 && result2[result2.length - 1].created_at === next.created_at) {
|
|
11047
11228
|
if (sameTimestampIds.includes(next.id))
|
|
11048
11229
|
continue;
|
|
11049
11230
|
} else {
|
|
11050
11231
|
sameTimestampIds.length = 0;
|
|
11051
11232
|
}
|
|
11052
|
-
|
|
11233
|
+
result2.push(next);
|
|
11053
11234
|
sameTimestampIds.push(next.id);
|
|
11054
11235
|
}
|
|
11055
11236
|
while (i22 < list2.length) {
|
|
11056
11237
|
const next = list2[i22];
|
|
11057
11238
|
i22++;
|
|
11058
|
-
if (
|
|
11239
|
+
if (result2.length > 0 && result2[result2.length - 1].created_at === next.created_at) {
|
|
11059
11240
|
if (sameTimestampIds.includes(next.id))
|
|
11060
11241
|
continue;
|
|
11061
11242
|
} else {
|
|
11062
11243
|
sameTimestampIds.length = 0;
|
|
11063
11244
|
}
|
|
11064
|
-
|
|
11245
|
+
result2.push(next);
|
|
11065
11246
|
sameTimestampIds.push(next.id);
|
|
11066
11247
|
}
|
|
11067
|
-
return
|
|
11248
|
+
return result2;
|
|
11068
11249
|
}
|
|
11069
11250
|
var JS2 = class {
|
|
11070
11251
|
generateSecretKey() {
|
|
@@ -11516,7 +11697,7 @@ function decode2(code) {
|
|
|
11516
11697
|
}
|
|
11517
11698
|
}
|
|
11518
11699
|
function parseTLV2(data) {
|
|
11519
|
-
let
|
|
11700
|
+
let result2 = {};
|
|
11520
11701
|
let rest = data;
|
|
11521
11702
|
while (rest.length > 0) {
|
|
11522
11703
|
let t = rest[0];
|
|
@@ -11525,10 +11706,10 @@ function parseTLV2(data) {
|
|
|
11525
11706
|
rest = rest.slice(2 + l);
|
|
11526
11707
|
if (v.length < l)
|
|
11527
11708
|
throw new Error(`not enough data to read on TLV ${t}`);
|
|
11528
|
-
|
|
11529
|
-
|
|
11709
|
+
result2[t] = result2[t] || [];
|
|
11710
|
+
result2[t].push(v);
|
|
11530
11711
|
}
|
|
11531
|
-
return
|
|
11712
|
+
return result2;
|
|
11532
11713
|
}
|
|
11533
11714
|
function nsecEncode(key) {
|
|
11534
11715
|
return encodeBytes2("nsec", key);
|
|
@@ -11679,7 +11860,7 @@ __export(nip10_exports, {
|
|
|
11679
11860
|
parse: () => parse
|
|
11680
11861
|
});
|
|
11681
11862
|
function parse(event) {
|
|
11682
|
-
const
|
|
11863
|
+
const result2 = {
|
|
11683
11864
|
reply: void 0,
|
|
11684
11865
|
root: void 0,
|
|
11685
11866
|
mentions: [],
|
|
@@ -11698,15 +11879,15 @@ function parse(event) {
|
|
|
11698
11879
|
author: eTagAuthor
|
|
11699
11880
|
};
|
|
11700
11881
|
if (eTagMarker === "root") {
|
|
11701
|
-
|
|
11882
|
+
result2.root = eventPointer;
|
|
11702
11883
|
continue;
|
|
11703
11884
|
}
|
|
11704
11885
|
if (eTagMarker === "reply") {
|
|
11705
|
-
|
|
11886
|
+
result2.reply = eventPointer;
|
|
11706
11887
|
continue;
|
|
11707
11888
|
}
|
|
11708
11889
|
if (eTagMarker === "mention") {
|
|
11709
|
-
|
|
11890
|
+
result2.mentions.push(eventPointer);
|
|
11710
11891
|
continue;
|
|
11711
11892
|
}
|
|
11712
11893
|
if (!maybeParent) {
|
|
@@ -11714,40 +11895,40 @@ function parse(event) {
|
|
|
11714
11895
|
} else {
|
|
11715
11896
|
maybeRoot = eventPointer;
|
|
11716
11897
|
}
|
|
11717
|
-
|
|
11898
|
+
result2.mentions.push(eventPointer);
|
|
11718
11899
|
continue;
|
|
11719
11900
|
}
|
|
11720
11901
|
if (tag[0] === "q" && tag[1]) {
|
|
11721
11902
|
const [_, eTagEventId, eTagRelayUrl] = tag;
|
|
11722
|
-
|
|
11903
|
+
result2.quotes.push({
|
|
11723
11904
|
id: eTagEventId,
|
|
11724
11905
|
relays: eTagRelayUrl ? [eTagRelayUrl] : []
|
|
11725
11906
|
});
|
|
11726
11907
|
}
|
|
11727
11908
|
if (tag[0] === "p" && tag[1]) {
|
|
11728
|
-
|
|
11909
|
+
result2.profiles.push({
|
|
11729
11910
|
pubkey: tag[1],
|
|
11730
11911
|
relays: tag[2] ? [tag[2]] : []
|
|
11731
11912
|
});
|
|
11732
11913
|
continue;
|
|
11733
11914
|
}
|
|
11734
11915
|
}
|
|
11735
|
-
if (!
|
|
11736
|
-
|
|
11916
|
+
if (!result2.root) {
|
|
11917
|
+
result2.root = maybeRoot || maybeParent || result2.reply;
|
|
11737
11918
|
}
|
|
11738
|
-
if (!
|
|
11739
|
-
|
|
11919
|
+
if (!result2.reply) {
|
|
11920
|
+
result2.reply = maybeParent || result2.root;
|
|
11740
11921
|
}
|
|
11741
11922
|
;
|
|
11742
|
-
[
|
|
11923
|
+
[result2.reply, result2.root].forEach((ref) => {
|
|
11743
11924
|
if (!ref)
|
|
11744
11925
|
return;
|
|
11745
|
-
let idx =
|
|
11926
|
+
let idx = result2.mentions.indexOf(ref);
|
|
11746
11927
|
if (idx !== -1) {
|
|
11747
|
-
|
|
11928
|
+
result2.mentions.splice(idx, 1);
|
|
11748
11929
|
}
|
|
11749
11930
|
if (ref.author) {
|
|
11750
|
-
let author =
|
|
11931
|
+
let author = result2.profiles.find((p) => p.pubkey === ref.author);
|
|
11751
11932
|
if (author && author.relays) {
|
|
11752
11933
|
if (!ref.relays) {
|
|
11753
11934
|
ref.relays = [];
|
|
@@ -11760,9 +11941,9 @@ function parse(event) {
|
|
|
11760
11941
|
}
|
|
11761
11942
|
}
|
|
11762
11943
|
});
|
|
11763
|
-
|
|
11944
|
+
result2.mentions.forEach((ref) => {
|
|
11764
11945
|
if (ref.author) {
|
|
11765
|
-
let author =
|
|
11946
|
+
let author = result2.profiles.find((p) => p.pubkey === ref.author);
|
|
11766
11947
|
if (author && author.relays) {
|
|
11767
11948
|
if (!ref.relays) {
|
|
11768
11949
|
ref.relays = [];
|
|
@@ -11775,7 +11956,7 @@ function parse(event) {
|
|
|
11775
11956
|
}
|
|
11776
11957
|
}
|
|
11777
11958
|
});
|
|
11778
|
-
return
|
|
11959
|
+
return result2;
|
|
11779
11960
|
}
|
|
11780
11961
|
var nip11_exports = {};
|
|
11781
11962
|
__export(nip11_exports, {
|
|
@@ -13444,11 +13625,11 @@ function createNipEncryptionMethods(state, prefix) {
|
|
|
13444
13625
|
}
|
|
13445
13626
|
async function connectNip46State(state, secret) {
|
|
13446
13627
|
await openWebSocket(state);
|
|
13447
|
-
const
|
|
13448
|
-
if (typeof
|
|
13449
|
-
state.authorizedPubkey =
|
|
13450
|
-
} else if (
|
|
13451
|
-
state.authorizedPubkey =
|
|
13628
|
+
const result2 = await sendRequestWithId(state, crypto.randomUUID(), "connect", [state.bunkerPubkey, secret ?? ""]);
|
|
13629
|
+
if (typeof result2 === "string") {
|
|
13630
|
+
state.authorizedPubkey = result2;
|
|
13631
|
+
} else if (result2 && typeof result2 === "object" && "pubkey" in result2) {
|
|
13632
|
+
state.authorizedPubkey = result2.pubkey;
|
|
13452
13633
|
} else {
|
|
13453
13634
|
const pkResult = await sendRequestWithId(state, crypto.randomUUID(), "get_public_key", []);
|
|
13454
13635
|
state.authorizedPubkey = pkResult;
|
|
@@ -13462,11 +13643,11 @@ function createNip46Signer(state) {
|
|
|
13462
13643
|
return sendRequestWithId(state, crypto.randomUUID(), "get_public_key", []);
|
|
13463
13644
|
},
|
|
13464
13645
|
signEvent: async (event) => {
|
|
13465
|
-
const
|
|
13466
|
-
if (typeof
|
|
13467
|
-
return JSON.parse(
|
|
13646
|
+
const result2 = await sendRequestWithId(state, crypto.randomUUID(), "sign_event", [JSON.stringify(event)]);
|
|
13647
|
+
if (typeof result2 === "string") {
|
|
13648
|
+
return JSON.parse(result2);
|
|
13468
13649
|
}
|
|
13469
|
-
return
|
|
13650
|
+
return result2;
|
|
13470
13651
|
},
|
|
13471
13652
|
nip04: createNipEncryptionMethods(state, "nip04"),
|
|
13472
13653
|
nip44: createNipEncryptionMethods(state, "nip44")
|
|
@@ -13614,6 +13795,7 @@ var PAJA_SIMULATION_DOMAINS = [
|
|
|
13614
13795
|
"media",
|
|
13615
13796
|
"upload",
|
|
13616
13797
|
"intent",
|
|
13798
|
+
"count",
|
|
13617
13799
|
"link",
|
|
13618
13800
|
"common",
|
|
13619
13801
|
"lists",
|
|
@@ -13726,8 +13908,8 @@ function installPajaOriginRegistryProxy(originRegistry2, stateRef) {
|
|
|
13726
13908
|
};
|
|
13727
13909
|
const originalGetWindowId = originRegistry2.getWindowId.bind(originRegistry2);
|
|
13728
13910
|
originRegistry2.getWindowId = (win) => {
|
|
13729
|
-
const
|
|
13730
|
-
if (
|
|
13911
|
+
const result2 = originalGetWindowId(win);
|
|
13912
|
+
if (result2) return result2;
|
|
13731
13913
|
const real = proxyToReal.get(win);
|
|
13732
13914
|
return real ? originalGetWindowId(real) : void 0;
|
|
13733
13915
|
};
|
|
@@ -13848,117 +14030,1800 @@ function renderSignerStatus(state, signerPubkey) {
|
|
|
13848
14030
|
controls.replaceChildren(devButton, nip07Button, bunkerInput, bunkerButton);
|
|
13849
14031
|
}
|
|
13850
14032
|
|
|
13851
|
-
//
|
|
13852
|
-
var
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
if (!
|
|
13856
|
-
|
|
14033
|
+
// ../../node_modules/.pnpm/nostr-tools@2.23.3_typescript@5.9.3/node_modules/nostr-tools/lib/esm/pool.js
|
|
14034
|
+
var verifiedSymbol3 = /* @__PURE__ */ Symbol("verified");
|
|
14035
|
+
var isRecord3 = (obj) => obj instanceof Object;
|
|
14036
|
+
function validateEvent3(event) {
|
|
14037
|
+
if (!isRecord3(event))
|
|
14038
|
+
return false;
|
|
14039
|
+
if (typeof event.kind !== "number")
|
|
14040
|
+
return false;
|
|
14041
|
+
if (typeof event.content !== "string")
|
|
14042
|
+
return false;
|
|
14043
|
+
if (typeof event.created_at !== "number")
|
|
14044
|
+
return false;
|
|
14045
|
+
if (typeof event.pubkey !== "string")
|
|
14046
|
+
return false;
|
|
14047
|
+
if (!event.pubkey.match(/^[a-f0-9]{64}$/))
|
|
14048
|
+
return false;
|
|
14049
|
+
if (!Array.isArray(event.tags))
|
|
14050
|
+
return false;
|
|
14051
|
+
for (let i22 = 0; i22 < event.tags.length; i22++) {
|
|
14052
|
+
let tag = event.tags[i22];
|
|
14053
|
+
if (!Array.isArray(tag))
|
|
14054
|
+
return false;
|
|
14055
|
+
for (let j = 0; j < tag.length; j++) {
|
|
14056
|
+
if (typeof tag[j] !== "string")
|
|
14057
|
+
return false;
|
|
14058
|
+
}
|
|
13857
14059
|
}
|
|
13858
|
-
return
|
|
14060
|
+
return true;
|
|
13859
14061
|
}
|
|
13860
|
-
|
|
14062
|
+
var utf8Decoder4 = new TextDecoder("utf-8");
|
|
14063
|
+
var utf8Encoder4 = new TextEncoder();
|
|
14064
|
+
function normalizeURL2(url) {
|
|
13861
14065
|
try {
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
14066
|
+
if (url.indexOf("://") === -1)
|
|
14067
|
+
url = "wss://" + url;
|
|
14068
|
+
let p = new URL(url);
|
|
14069
|
+
if (p.protocol === "http:")
|
|
14070
|
+
p.protocol = "ws:";
|
|
14071
|
+
else if (p.protocol === "https:")
|
|
14072
|
+
p.protocol = "wss:";
|
|
14073
|
+
p.pathname = p.pathname.replace(/\/+/g, "/");
|
|
14074
|
+
if (p.pathname.endsWith("/"))
|
|
14075
|
+
p.pathname = p.pathname.slice(0, -1);
|
|
14076
|
+
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
|
|
14077
|
+
p.port = "";
|
|
14078
|
+
p.searchParams.sort();
|
|
14079
|
+
p.hash = "";
|
|
14080
|
+
return p.toString();
|
|
14081
|
+
} catch (e) {
|
|
14082
|
+
throw new Error(`Invalid URL: ${url}`);
|
|
13868
14083
|
}
|
|
13869
14084
|
}
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
13874
|
-
|
|
14085
|
+
var JS3 = class {
|
|
14086
|
+
generateSecretKey() {
|
|
14087
|
+
return schnorr.utils.randomSecretKey();
|
|
14088
|
+
}
|
|
14089
|
+
getPublicKey(secretKey) {
|
|
14090
|
+
return bytesToHex2(schnorr.getPublicKey(secretKey));
|
|
14091
|
+
}
|
|
14092
|
+
finalizeEvent(t, secretKey) {
|
|
14093
|
+
const event = t;
|
|
14094
|
+
event.pubkey = bytesToHex2(schnorr.getPublicKey(secretKey));
|
|
14095
|
+
event.id = getEventHash3(event);
|
|
14096
|
+
event.sig = bytesToHex2(schnorr.sign(hexToBytes2(getEventHash3(event)), secretKey));
|
|
14097
|
+
event[verifiedSymbol3] = true;
|
|
14098
|
+
return event;
|
|
14099
|
+
}
|
|
14100
|
+
verifyEvent(event) {
|
|
14101
|
+
if (typeof event[verifiedSymbol3] === "boolean")
|
|
14102
|
+
return event[verifiedSymbol3];
|
|
14103
|
+
try {
|
|
14104
|
+
const hash = getEventHash3(event);
|
|
14105
|
+
if (hash !== event.id) {
|
|
14106
|
+
event[verifiedSymbol3] = false;
|
|
14107
|
+
return false;
|
|
14108
|
+
}
|
|
14109
|
+
const valid = schnorr.verify(hexToBytes2(event.sig), hexToBytes2(hash), hexToBytes2(event.pubkey));
|
|
14110
|
+
event[verifiedSymbol3] = valid;
|
|
14111
|
+
return valid;
|
|
14112
|
+
} catch (err) {
|
|
14113
|
+
event[verifiedSymbol3] = false;
|
|
14114
|
+
return false;
|
|
14115
|
+
}
|
|
13875
14116
|
}
|
|
13876
|
-
|
|
14117
|
+
};
|
|
14118
|
+
function serializeEvent3(evt) {
|
|
14119
|
+
if (!validateEvent3(evt))
|
|
14120
|
+
throw new Error("can't serialize event with wrong or missing properties");
|
|
14121
|
+
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
|
|
13877
14122
|
}
|
|
13878
|
-
function
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
if (statusEl) statusEl.textContent = status;
|
|
14123
|
+
function getEventHash3(event) {
|
|
14124
|
+
let eventHash = sha256(utf8Encoder4.encode(serializeEvent3(event)));
|
|
14125
|
+
return bytesToHex2(eventHash);
|
|
13882
14126
|
}
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
14127
|
+
var i3 = new JS3();
|
|
14128
|
+
var generateSecretKey3 = i3.generateSecretKey;
|
|
14129
|
+
var getPublicKey3 = i3.getPublicKey;
|
|
14130
|
+
var finalizeEvent3 = i3.finalizeEvent;
|
|
14131
|
+
var verifyEvent3 = i3.verifyEvent;
|
|
14132
|
+
var ClientAuth2 = 22242;
|
|
14133
|
+
function matchFilter(filter, event) {
|
|
14134
|
+
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
|
|
14135
|
+
return false;
|
|
14136
|
+
}
|
|
14137
|
+
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {
|
|
14138
|
+
return false;
|
|
14139
|
+
}
|
|
14140
|
+
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
|
|
14141
|
+
return false;
|
|
14142
|
+
}
|
|
14143
|
+
for (let f in filter) {
|
|
14144
|
+
if (f[0] === "#") {
|
|
14145
|
+
let tagName = f.slice(1);
|
|
14146
|
+
let values = filter[`#${tagName}`];
|
|
14147
|
+
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
|
|
14148
|
+
return false;
|
|
14149
|
+
}
|
|
14150
|
+
}
|
|
14151
|
+
if (filter.since && event.created_at < filter.since)
|
|
14152
|
+
return false;
|
|
14153
|
+
if (filter.until && event.created_at > filter.until)
|
|
14154
|
+
return false;
|
|
14155
|
+
return true;
|
|
13889
14156
|
}
|
|
13890
|
-
function
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
14157
|
+
function matchFilters(filters, event) {
|
|
14158
|
+
for (let i22 = 0; i22 < filters.length; i22++) {
|
|
14159
|
+
if (matchFilter(filters[i22], event)) {
|
|
14160
|
+
return true;
|
|
14161
|
+
}
|
|
13894
14162
|
}
|
|
13895
|
-
|
|
13896
|
-
frame.sandbox.remove("allow-same-origin");
|
|
13897
|
-
return frame;
|
|
14163
|
+
return false;
|
|
13898
14164
|
}
|
|
13899
|
-
function
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
|
|
13905
|
-
|
|
13906
|
-
|
|
13907
|
-
|
|
13908
|
-
|
|
13909
|
-
|
|
13910
|
-
|
|
13911
|
-
|
|
14165
|
+
function getHex642(json, field) {
|
|
14166
|
+
let len = field.length + 3;
|
|
14167
|
+
let idx = json.indexOf(`"${field}":`) + len;
|
|
14168
|
+
let s = json.slice(idx).indexOf(`"`) + idx + 1;
|
|
14169
|
+
return json.slice(s, s + 64);
|
|
14170
|
+
}
|
|
14171
|
+
function getSubscriptionId2(json) {
|
|
14172
|
+
let idx = json.slice(0, 22).indexOf(`"EVENT"`);
|
|
14173
|
+
if (idx === -1)
|
|
14174
|
+
return null;
|
|
14175
|
+
let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
|
|
14176
|
+
if (pstart === -1)
|
|
14177
|
+
return null;
|
|
14178
|
+
let start = idx + 7 + 1 + pstart;
|
|
14179
|
+
let pend = json.slice(start + 1, 80).indexOf(`"`);
|
|
14180
|
+
if (pend === -1)
|
|
14181
|
+
return null;
|
|
14182
|
+
let end = start + 1 + pend;
|
|
14183
|
+
return json.slice(start + 1, end);
|
|
13912
14184
|
}
|
|
13913
|
-
function
|
|
14185
|
+
function makeAuthEvent2(relayURL, challenge2) {
|
|
13914
14186
|
return {
|
|
13915
|
-
|
|
13916
|
-
|
|
13917
|
-
|
|
14187
|
+
kind: ClientAuth2,
|
|
14188
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
14189
|
+
tags: [
|
|
14190
|
+
["relay", relayURL],
|
|
14191
|
+
["challenge", challenge2]
|
|
14192
|
+
],
|
|
14193
|
+
content: ""
|
|
13918
14194
|
};
|
|
13919
14195
|
}
|
|
13920
|
-
|
|
13921
|
-
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
13928
|
-
|
|
13929
|
-
|
|
13930
|
-
|
|
13931
|
-
|
|
13932
|
-
|
|
13933
|
-
|
|
13934
|
-
|
|
13935
|
-
|
|
13936
|
-
|
|
13937
|
-
|
|
13938
|
-
|
|
13939
|
-
|
|
13940
|
-
|
|
13941
|
-
|
|
13942
|
-
|
|
13943
|
-
|
|
13944
|
-
|
|
13945
|
-
|
|
13946
|
-
|
|
13947
|
-
|
|
13948
|
-
|
|
13949
|
-
|
|
13950
|
-
|
|
13951
|
-
|
|
13952
|
-
|
|
13953
|
-
|
|
13954
|
-
|
|
13955
|
-
|
|
13956
|
-
|
|
13957
|
-
|
|
13958
|
-
|
|
13959
|
-
|
|
13960
|
-
|
|
13961
|
-
}
|
|
14196
|
+
var SendingOnClosedConnection = class extends Error {
|
|
14197
|
+
constructor(message, relay) {
|
|
14198
|
+
super(`Tried to send message '${message} on a closed connection to ${relay}.`);
|
|
14199
|
+
this.name = "SendingOnClosedConnection";
|
|
14200
|
+
}
|
|
14201
|
+
};
|
|
14202
|
+
var AbstractRelay = class {
|
|
14203
|
+
url;
|
|
14204
|
+
_connected = false;
|
|
14205
|
+
onclose = null;
|
|
14206
|
+
onnotice = (msg) => console.debug(`NOTICE from ${this.url}: ${msg}`);
|
|
14207
|
+
onauth;
|
|
14208
|
+
baseEoseTimeout = 4400;
|
|
14209
|
+
publishTimeout = 4400;
|
|
14210
|
+
pingFrequency = 29e3;
|
|
14211
|
+
pingTimeout = 2e4;
|
|
14212
|
+
resubscribeBackoff = [1e4, 1e4, 1e4, 2e4, 2e4, 3e4, 6e4];
|
|
14213
|
+
openSubs = /* @__PURE__ */ new Map();
|
|
14214
|
+
enablePing;
|
|
14215
|
+
enableReconnect;
|
|
14216
|
+
idleSince = Date.now();
|
|
14217
|
+
ongoingOperations = 0;
|
|
14218
|
+
reconnectTimeoutHandle;
|
|
14219
|
+
pingIntervalHandle;
|
|
14220
|
+
reconnectAttempts = 0;
|
|
14221
|
+
skipReconnection = false;
|
|
14222
|
+
connectionPromise;
|
|
14223
|
+
openCountRequests = /* @__PURE__ */ new Map();
|
|
14224
|
+
openEventPublishes = /* @__PURE__ */ new Map();
|
|
14225
|
+
ws;
|
|
14226
|
+
challenge;
|
|
14227
|
+
authPromise;
|
|
14228
|
+
serial = 0;
|
|
14229
|
+
verifyEvent;
|
|
14230
|
+
_WebSocket;
|
|
14231
|
+
constructor(url, opts) {
|
|
14232
|
+
this.url = normalizeURL2(url);
|
|
14233
|
+
this.verifyEvent = opts.verifyEvent;
|
|
14234
|
+
this._WebSocket = opts.websocketImplementation || WebSocket;
|
|
14235
|
+
this.enablePing = opts.enablePing;
|
|
14236
|
+
this.enableReconnect = opts.enableReconnect || false;
|
|
14237
|
+
}
|
|
14238
|
+
static async connect(url, opts) {
|
|
14239
|
+
const relay = new AbstractRelay(url, opts);
|
|
14240
|
+
await relay.connect(opts);
|
|
14241
|
+
return relay;
|
|
14242
|
+
}
|
|
14243
|
+
closeAllSubscriptions(reason) {
|
|
14244
|
+
for (let [_, sub] of this.openSubs) {
|
|
14245
|
+
sub.close(reason);
|
|
14246
|
+
}
|
|
14247
|
+
this.openSubs.clear();
|
|
14248
|
+
for (let [_, ep] of this.openEventPublishes) {
|
|
14249
|
+
ep.reject(new Error(reason));
|
|
14250
|
+
}
|
|
14251
|
+
this.openEventPublishes.clear();
|
|
14252
|
+
for (let [_, cr] of this.openCountRequests) {
|
|
14253
|
+
cr.reject(new Error(reason));
|
|
14254
|
+
}
|
|
14255
|
+
this.openCountRequests.clear();
|
|
14256
|
+
}
|
|
14257
|
+
get connected() {
|
|
14258
|
+
return this._connected;
|
|
14259
|
+
}
|
|
14260
|
+
async reconnect() {
|
|
14261
|
+
const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
|
|
14262
|
+
this.reconnectAttempts++;
|
|
14263
|
+
this.reconnectTimeoutHandle = setTimeout(async () => {
|
|
14264
|
+
try {
|
|
14265
|
+
await this.connect();
|
|
14266
|
+
} catch (err) {
|
|
14267
|
+
}
|
|
14268
|
+
}, backoff);
|
|
14269
|
+
}
|
|
14270
|
+
handleHardClose(reason) {
|
|
14271
|
+
if (this.pingIntervalHandle) {
|
|
14272
|
+
clearInterval(this.pingIntervalHandle);
|
|
14273
|
+
this.pingIntervalHandle = void 0;
|
|
14274
|
+
}
|
|
14275
|
+
this._connected = false;
|
|
14276
|
+
this.connectionPromise = void 0;
|
|
14277
|
+
this.idleSince = void 0;
|
|
14278
|
+
if (this.enableReconnect && !this.skipReconnection) {
|
|
14279
|
+
this.reconnect();
|
|
14280
|
+
} else {
|
|
14281
|
+
this.onclose?.();
|
|
14282
|
+
this.closeAllSubscriptions(reason);
|
|
14283
|
+
}
|
|
14284
|
+
}
|
|
14285
|
+
async connect(opts) {
|
|
14286
|
+
let connectionTimeoutHandle;
|
|
14287
|
+
if (this.connectionPromise)
|
|
14288
|
+
return this.connectionPromise;
|
|
14289
|
+
this.challenge = void 0;
|
|
14290
|
+
this.authPromise = void 0;
|
|
14291
|
+
this.skipReconnection = false;
|
|
14292
|
+
this.connectionPromise = new Promise((resolve, reject) => {
|
|
14293
|
+
if (opts?.timeout) {
|
|
14294
|
+
connectionTimeoutHandle = setTimeout(() => {
|
|
14295
|
+
reject("connection timed out");
|
|
14296
|
+
this.connectionPromise = void 0;
|
|
14297
|
+
this.skipReconnection = true;
|
|
14298
|
+
this.onclose?.();
|
|
14299
|
+
this.handleHardClose("relay connection timed out");
|
|
14300
|
+
}, opts.timeout);
|
|
14301
|
+
}
|
|
14302
|
+
if (opts?.abort) {
|
|
14303
|
+
opts.abort.onabort = reject;
|
|
14304
|
+
}
|
|
14305
|
+
try {
|
|
14306
|
+
this.ws = new this._WebSocket(this.url);
|
|
14307
|
+
} catch (err) {
|
|
14308
|
+
clearTimeout(connectionTimeoutHandle);
|
|
14309
|
+
reject(err);
|
|
14310
|
+
return;
|
|
14311
|
+
}
|
|
14312
|
+
this.ws.onopen = () => {
|
|
14313
|
+
if (this.reconnectTimeoutHandle) {
|
|
14314
|
+
clearTimeout(this.reconnectTimeoutHandle);
|
|
14315
|
+
this.reconnectTimeoutHandle = void 0;
|
|
14316
|
+
}
|
|
14317
|
+
clearTimeout(connectionTimeoutHandle);
|
|
14318
|
+
this._connected = true;
|
|
14319
|
+
const isReconnection = this.reconnectAttempts > 0;
|
|
14320
|
+
this.reconnectAttempts = 0;
|
|
14321
|
+
for (const sub of this.openSubs.values()) {
|
|
14322
|
+
sub.eosed = false;
|
|
14323
|
+
if (isReconnection) {
|
|
14324
|
+
for (let f = 0; f < sub.filters.length; f++) {
|
|
14325
|
+
if (sub.lastEmitted) {
|
|
14326
|
+
sub.filters[f].since = sub.lastEmitted + 1;
|
|
14327
|
+
}
|
|
14328
|
+
}
|
|
14329
|
+
}
|
|
14330
|
+
sub.fire();
|
|
14331
|
+
}
|
|
14332
|
+
if (this.enablePing) {
|
|
14333
|
+
this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency);
|
|
14334
|
+
}
|
|
14335
|
+
resolve();
|
|
14336
|
+
};
|
|
14337
|
+
this.ws.onerror = () => {
|
|
14338
|
+
clearTimeout(connectionTimeoutHandle);
|
|
14339
|
+
reject("connection failed");
|
|
14340
|
+
this.connectionPromise = void 0;
|
|
14341
|
+
this.skipReconnection = true;
|
|
14342
|
+
this.onclose?.();
|
|
14343
|
+
this.handleHardClose("relay connection failed");
|
|
14344
|
+
};
|
|
14345
|
+
this.ws.onclose = (ev) => {
|
|
14346
|
+
clearTimeout(connectionTimeoutHandle);
|
|
14347
|
+
reject(ev.message || "websocket closed");
|
|
14348
|
+
this.handleHardClose("relay connection closed");
|
|
14349
|
+
};
|
|
14350
|
+
this.ws.onmessage = this._onmessage.bind(this);
|
|
14351
|
+
});
|
|
14352
|
+
return this.connectionPromise;
|
|
14353
|
+
}
|
|
14354
|
+
waitForPingPong() {
|
|
14355
|
+
return new Promise((resolve) => {
|
|
14356
|
+
;
|
|
14357
|
+
this.ws.once("pong", () => resolve(true));
|
|
14358
|
+
this.ws.ping();
|
|
14359
|
+
});
|
|
14360
|
+
}
|
|
14361
|
+
waitForDummyReq() {
|
|
14362
|
+
return new Promise((resolve, reject) => {
|
|
14363
|
+
if (!this.connectionPromise)
|
|
14364
|
+
return reject(new Error(`no connection to ${this.url}, can't ping`));
|
|
14365
|
+
try {
|
|
14366
|
+
const sub = this.subscribe(
|
|
14367
|
+
[{ ids: ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], limit: 0 }],
|
|
14368
|
+
{
|
|
14369
|
+
label: "<forced-ping>",
|
|
14370
|
+
oneose: () => {
|
|
14371
|
+
resolve(true);
|
|
14372
|
+
sub.close();
|
|
14373
|
+
},
|
|
14374
|
+
onclose() {
|
|
14375
|
+
resolve(true);
|
|
14376
|
+
},
|
|
14377
|
+
eoseTimeout: this.pingTimeout + 1e3
|
|
14378
|
+
}
|
|
14379
|
+
);
|
|
14380
|
+
} catch (err) {
|
|
14381
|
+
reject(err);
|
|
14382
|
+
}
|
|
14383
|
+
});
|
|
14384
|
+
}
|
|
14385
|
+
async pingpong() {
|
|
14386
|
+
if (this.ws?.readyState === 1) {
|
|
14387
|
+
const result2 = await Promise.any([
|
|
14388
|
+
this.ws && this.ws.ping && this.ws.once ? this.waitForPingPong() : this.waitForDummyReq(),
|
|
14389
|
+
new Promise((res) => setTimeout(() => res(false), this.pingTimeout))
|
|
14390
|
+
]);
|
|
14391
|
+
if (!result2) {
|
|
14392
|
+
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
14393
|
+
this.ws?.close();
|
|
14394
|
+
}
|
|
14395
|
+
}
|
|
14396
|
+
}
|
|
14397
|
+
}
|
|
14398
|
+
async send(message) {
|
|
14399
|
+
if (!this.connectionPromise)
|
|
14400
|
+
throw new SendingOnClosedConnection(message, this.url);
|
|
14401
|
+
this.connectionPromise.then(() => {
|
|
14402
|
+
this.ws?.send(message);
|
|
14403
|
+
});
|
|
14404
|
+
}
|
|
14405
|
+
async auth(signAuthEvent) {
|
|
14406
|
+
const challenge2 = this.challenge;
|
|
14407
|
+
if (!challenge2)
|
|
14408
|
+
throw new Error("can't perform auth, no challenge was received");
|
|
14409
|
+
if (this.authPromise)
|
|
14410
|
+
return this.authPromise;
|
|
14411
|
+
this.authPromise = new Promise(async (resolve, reject) => {
|
|
14412
|
+
try {
|
|
14413
|
+
let evt = await signAuthEvent(makeAuthEvent2(this.url, challenge2));
|
|
14414
|
+
let timeout = setTimeout(() => {
|
|
14415
|
+
let ep = this.openEventPublishes.get(evt.id);
|
|
14416
|
+
if (ep) {
|
|
14417
|
+
ep.reject(new Error("auth timed out"));
|
|
14418
|
+
this.openEventPublishes.delete(evt.id);
|
|
14419
|
+
}
|
|
14420
|
+
}, this.publishTimeout);
|
|
14421
|
+
this.openEventPublishes.set(evt.id, { resolve, reject, timeout });
|
|
14422
|
+
this.send('["AUTH",' + JSON.stringify(evt) + "]");
|
|
14423
|
+
} catch (err) {
|
|
14424
|
+
console.warn("subscribe auth function failed:", err);
|
|
14425
|
+
}
|
|
14426
|
+
});
|
|
14427
|
+
return this.authPromise;
|
|
14428
|
+
}
|
|
14429
|
+
async publish(event) {
|
|
14430
|
+
this.idleSince = void 0;
|
|
14431
|
+
this.ongoingOperations++;
|
|
14432
|
+
const ret = new Promise((resolve, reject) => {
|
|
14433
|
+
const timeout = setTimeout(() => {
|
|
14434
|
+
const ep = this.openEventPublishes.get(event.id);
|
|
14435
|
+
if (ep) {
|
|
14436
|
+
ep.reject(new Error("publish timed out"));
|
|
14437
|
+
this.openEventPublishes.delete(event.id);
|
|
14438
|
+
}
|
|
14439
|
+
}, this.publishTimeout);
|
|
14440
|
+
this.openEventPublishes.set(event.id, { resolve, reject, timeout });
|
|
14441
|
+
});
|
|
14442
|
+
this.send('["EVENT",' + JSON.stringify(event) + "]");
|
|
14443
|
+
this.ongoingOperations--;
|
|
14444
|
+
if (this.ongoingOperations === 0)
|
|
14445
|
+
this.idleSince = Date.now();
|
|
14446
|
+
return ret;
|
|
14447
|
+
}
|
|
14448
|
+
async count(filters, params) {
|
|
14449
|
+
this.serial++;
|
|
14450
|
+
const id = params?.id || "count:" + this.serial;
|
|
14451
|
+
const ret = new Promise((resolve, reject) => {
|
|
14452
|
+
this.openCountRequests.set(id, { resolve, reject });
|
|
14453
|
+
});
|
|
14454
|
+
this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
|
|
14455
|
+
return ret;
|
|
14456
|
+
}
|
|
14457
|
+
subscribe(filters, params) {
|
|
14458
|
+
if (params.label !== "<forced-ping>") {
|
|
14459
|
+
this.idleSince = void 0;
|
|
14460
|
+
this.ongoingOperations++;
|
|
14461
|
+
}
|
|
14462
|
+
const sub = this.prepareSubscription(filters, params);
|
|
14463
|
+
sub.fire();
|
|
14464
|
+
if (params.abort) {
|
|
14465
|
+
params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
|
|
14466
|
+
}
|
|
14467
|
+
return sub;
|
|
14468
|
+
}
|
|
14469
|
+
prepareSubscription(filters, params) {
|
|
14470
|
+
this.serial++;
|
|
14471
|
+
const id = params.id || (params.label ? params.label + ":" : "sub:") + this.serial;
|
|
14472
|
+
const sub = new Subscription(this, id, filters, params);
|
|
14473
|
+
this.openSubs.set(id, sub);
|
|
14474
|
+
return sub;
|
|
14475
|
+
}
|
|
14476
|
+
close() {
|
|
14477
|
+
this.skipReconnection = true;
|
|
14478
|
+
if (this.reconnectTimeoutHandle) {
|
|
14479
|
+
clearTimeout(this.reconnectTimeoutHandle);
|
|
14480
|
+
this.reconnectTimeoutHandle = void 0;
|
|
14481
|
+
}
|
|
14482
|
+
if (this.pingIntervalHandle) {
|
|
14483
|
+
clearInterval(this.pingIntervalHandle);
|
|
14484
|
+
this.pingIntervalHandle = void 0;
|
|
14485
|
+
}
|
|
14486
|
+
this.closeAllSubscriptions("relay connection closed by us");
|
|
14487
|
+
this._connected = false;
|
|
14488
|
+
this.idleSince = void 0;
|
|
14489
|
+
this.onclose?.();
|
|
14490
|
+
if (this.ws?.readyState === this._WebSocket.OPEN) {
|
|
14491
|
+
this.ws?.close();
|
|
14492
|
+
}
|
|
14493
|
+
}
|
|
14494
|
+
_onmessage(ev) {
|
|
14495
|
+
const json = ev.data;
|
|
14496
|
+
if (!json) {
|
|
14497
|
+
return;
|
|
14498
|
+
}
|
|
14499
|
+
const subid = getSubscriptionId2(json);
|
|
14500
|
+
if (subid) {
|
|
14501
|
+
const so = this.openSubs.get(subid);
|
|
14502
|
+
if (!so) {
|
|
14503
|
+
return;
|
|
14504
|
+
}
|
|
14505
|
+
const id = getHex642(json, "id");
|
|
14506
|
+
const alreadyHave = so.alreadyHaveEvent?.(id);
|
|
14507
|
+
so.receivedEvent?.(this, id);
|
|
14508
|
+
if (alreadyHave) {
|
|
14509
|
+
return;
|
|
14510
|
+
}
|
|
14511
|
+
}
|
|
14512
|
+
try {
|
|
14513
|
+
let data = JSON.parse(json);
|
|
14514
|
+
switch (data[0]) {
|
|
14515
|
+
case "EVENT": {
|
|
14516
|
+
const so = this.openSubs.get(data[1]);
|
|
14517
|
+
const event = data[2];
|
|
14518
|
+
if (this.verifyEvent(event) && matchFilters(so.filters, event)) {
|
|
14519
|
+
so.onevent(event);
|
|
14520
|
+
} else {
|
|
14521
|
+
so.oninvalidevent?.(event);
|
|
14522
|
+
}
|
|
14523
|
+
if (!so.lastEmitted || so.lastEmitted < event.created_at)
|
|
14524
|
+
so.lastEmitted = event.created_at;
|
|
14525
|
+
return;
|
|
14526
|
+
}
|
|
14527
|
+
case "COUNT": {
|
|
14528
|
+
const id = data[1];
|
|
14529
|
+
const payload = data[2];
|
|
14530
|
+
const cr = this.openCountRequests.get(id);
|
|
14531
|
+
if (cr) {
|
|
14532
|
+
cr.resolve(payload.count);
|
|
14533
|
+
this.openCountRequests.delete(id);
|
|
14534
|
+
}
|
|
14535
|
+
return;
|
|
14536
|
+
}
|
|
14537
|
+
case "EOSE": {
|
|
14538
|
+
const so = this.openSubs.get(data[1]);
|
|
14539
|
+
if (!so)
|
|
14540
|
+
return;
|
|
14541
|
+
so.receivedEose();
|
|
14542
|
+
return;
|
|
14543
|
+
}
|
|
14544
|
+
case "OK": {
|
|
14545
|
+
const id = data[1];
|
|
14546
|
+
const ok = data[2];
|
|
14547
|
+
const reason = data[3];
|
|
14548
|
+
const ep = this.openEventPublishes.get(id);
|
|
14549
|
+
if (ep) {
|
|
14550
|
+
clearTimeout(ep.timeout);
|
|
14551
|
+
if (ok)
|
|
14552
|
+
ep.resolve(reason);
|
|
14553
|
+
else
|
|
14554
|
+
ep.reject(new Error(reason));
|
|
14555
|
+
this.openEventPublishes.delete(id);
|
|
14556
|
+
}
|
|
14557
|
+
return;
|
|
14558
|
+
}
|
|
14559
|
+
case "CLOSED": {
|
|
14560
|
+
const id = data[1];
|
|
14561
|
+
const so = this.openSubs.get(id);
|
|
14562
|
+
if (!so)
|
|
14563
|
+
return;
|
|
14564
|
+
so.closed = true;
|
|
14565
|
+
so.close(data[2]);
|
|
14566
|
+
return;
|
|
14567
|
+
}
|
|
14568
|
+
case "NOTICE": {
|
|
14569
|
+
this.onnotice(data[1]);
|
|
14570
|
+
return;
|
|
14571
|
+
}
|
|
14572
|
+
case "AUTH": {
|
|
14573
|
+
this.challenge = data[1];
|
|
14574
|
+
if (this.onauth) {
|
|
14575
|
+
this.auth(this.onauth);
|
|
14576
|
+
}
|
|
14577
|
+
return;
|
|
14578
|
+
}
|
|
14579
|
+
default: {
|
|
14580
|
+
const so = this.openSubs.get(data[1]);
|
|
14581
|
+
so?.oncustom?.(data);
|
|
14582
|
+
return;
|
|
14583
|
+
}
|
|
14584
|
+
}
|
|
14585
|
+
} catch (err) {
|
|
14586
|
+
try {
|
|
14587
|
+
const [_, __, event] = JSON.parse(json);
|
|
14588
|
+
console.warn(`[nostr] relay ${this.url} error processing message:`, err, event);
|
|
14589
|
+
} catch (_) {
|
|
14590
|
+
console.warn(`[nostr] relay ${this.url} error processing message:`, err);
|
|
14591
|
+
}
|
|
14592
|
+
return;
|
|
14593
|
+
}
|
|
14594
|
+
}
|
|
14595
|
+
};
|
|
14596
|
+
var Subscription = class {
|
|
14597
|
+
relay;
|
|
14598
|
+
id;
|
|
14599
|
+
lastEmitted;
|
|
14600
|
+
closed = false;
|
|
14601
|
+
eosed = false;
|
|
14602
|
+
filters;
|
|
14603
|
+
alreadyHaveEvent;
|
|
14604
|
+
receivedEvent;
|
|
14605
|
+
onevent;
|
|
14606
|
+
oninvalidevent;
|
|
14607
|
+
oneose;
|
|
14608
|
+
onclose;
|
|
14609
|
+
oncustom;
|
|
14610
|
+
eoseTimeout;
|
|
14611
|
+
eoseTimeoutHandle;
|
|
14612
|
+
constructor(relay, id, filters, params) {
|
|
14613
|
+
if (filters.length === 0)
|
|
14614
|
+
throw new Error("subscription can't be created with zero filters");
|
|
14615
|
+
this.relay = relay;
|
|
14616
|
+
this.filters = filters;
|
|
14617
|
+
this.id = id;
|
|
14618
|
+
this.alreadyHaveEvent = params.alreadyHaveEvent;
|
|
14619
|
+
this.receivedEvent = params.receivedEvent;
|
|
14620
|
+
this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout;
|
|
14621
|
+
this.oneose = params.oneose;
|
|
14622
|
+
this.onclose = params.onclose;
|
|
14623
|
+
this.oninvalidevent = params.oninvalidevent;
|
|
14624
|
+
this.onevent = params.onevent || ((event) => {
|
|
14625
|
+
console.warn(
|
|
14626
|
+
`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,
|
|
14627
|
+
event
|
|
14628
|
+
);
|
|
14629
|
+
});
|
|
14630
|
+
}
|
|
14631
|
+
fire() {
|
|
14632
|
+
this.relay.send('["REQ","' + this.id + '",' + JSON.stringify(this.filters).substring(1));
|
|
14633
|
+
this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout);
|
|
14634
|
+
}
|
|
14635
|
+
receivedEose() {
|
|
14636
|
+
if (this.eosed)
|
|
14637
|
+
return;
|
|
14638
|
+
clearTimeout(this.eoseTimeoutHandle);
|
|
14639
|
+
this.eosed = true;
|
|
14640
|
+
this.oneose?.();
|
|
14641
|
+
}
|
|
14642
|
+
close(reason = "closed by caller") {
|
|
14643
|
+
if (!this.closed && this.relay.connected) {
|
|
14644
|
+
try {
|
|
14645
|
+
this.relay.send('["CLOSE",' + JSON.stringify(this.id) + "]");
|
|
14646
|
+
} catch (err) {
|
|
14647
|
+
if (err instanceof SendingOnClosedConnection) {
|
|
14648
|
+
} else {
|
|
14649
|
+
throw err;
|
|
14650
|
+
}
|
|
14651
|
+
}
|
|
14652
|
+
this.closed = true;
|
|
14653
|
+
}
|
|
14654
|
+
this.relay.openSubs.delete(this.id);
|
|
14655
|
+
this.relay.ongoingOperations--;
|
|
14656
|
+
if (this.relay.ongoingOperations === 0)
|
|
14657
|
+
this.relay.idleSince = Date.now();
|
|
14658
|
+
this.onclose?.(reason);
|
|
14659
|
+
}
|
|
14660
|
+
};
|
|
14661
|
+
var alwaysTrue = (t) => {
|
|
14662
|
+
t[verifiedSymbol3] = true;
|
|
14663
|
+
return true;
|
|
14664
|
+
};
|
|
14665
|
+
var AbstractSimplePool = class {
|
|
14666
|
+
relays = /* @__PURE__ */ new Map();
|
|
14667
|
+
seenOn = /* @__PURE__ */ new Map();
|
|
14668
|
+
trackRelays = false;
|
|
14669
|
+
verifyEvent;
|
|
14670
|
+
enablePing;
|
|
14671
|
+
enableReconnect;
|
|
14672
|
+
automaticallyAuth;
|
|
14673
|
+
trustedRelayURLs = /* @__PURE__ */ new Set();
|
|
14674
|
+
onRelayConnectionFailure;
|
|
14675
|
+
onRelayConnectionSuccess;
|
|
14676
|
+
allowConnectingToRelay;
|
|
14677
|
+
maxWaitForConnection;
|
|
14678
|
+
_WebSocket;
|
|
14679
|
+
constructor(opts) {
|
|
14680
|
+
this.verifyEvent = opts.verifyEvent;
|
|
14681
|
+
this._WebSocket = opts.websocketImplementation;
|
|
14682
|
+
this.enablePing = opts.enablePing;
|
|
14683
|
+
this.enableReconnect = opts.enableReconnect || false;
|
|
14684
|
+
this.automaticallyAuth = opts.automaticallyAuth;
|
|
14685
|
+
this.onRelayConnectionFailure = opts.onRelayConnectionFailure;
|
|
14686
|
+
this.onRelayConnectionSuccess = opts.onRelayConnectionSuccess;
|
|
14687
|
+
this.allowConnectingToRelay = opts.allowConnectingToRelay;
|
|
14688
|
+
this.maxWaitForConnection = opts.maxWaitForConnection || 3e3;
|
|
14689
|
+
}
|
|
14690
|
+
async ensureRelay(url, params) {
|
|
14691
|
+
url = normalizeURL2(url);
|
|
14692
|
+
let relay = this.relays.get(url);
|
|
14693
|
+
if (!relay) {
|
|
14694
|
+
relay = new AbstractRelay(url, {
|
|
14695
|
+
verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
|
|
14696
|
+
websocketImplementation: this._WebSocket,
|
|
14697
|
+
enablePing: this.enablePing,
|
|
14698
|
+
enableReconnect: this.enableReconnect
|
|
14699
|
+
});
|
|
14700
|
+
relay.onclose = () => {
|
|
14701
|
+
this.relays.delete(url);
|
|
14702
|
+
};
|
|
14703
|
+
this.relays.set(url, relay);
|
|
14704
|
+
}
|
|
14705
|
+
if (this.automaticallyAuth) {
|
|
14706
|
+
const authSignerFn = this.automaticallyAuth(url);
|
|
14707
|
+
if (authSignerFn) {
|
|
14708
|
+
relay.onauth = authSignerFn;
|
|
14709
|
+
}
|
|
14710
|
+
}
|
|
14711
|
+
try {
|
|
14712
|
+
await relay.connect({
|
|
14713
|
+
timeout: params?.connectionTimeout,
|
|
14714
|
+
abort: params?.abort
|
|
14715
|
+
});
|
|
14716
|
+
} catch (err) {
|
|
14717
|
+
this.relays.delete(url);
|
|
14718
|
+
throw err;
|
|
14719
|
+
}
|
|
14720
|
+
return relay;
|
|
14721
|
+
}
|
|
14722
|
+
close(relays) {
|
|
14723
|
+
relays.map(normalizeURL2).forEach((url) => {
|
|
14724
|
+
this.relays.get(url)?.close();
|
|
14725
|
+
this.relays.delete(url);
|
|
14726
|
+
});
|
|
14727
|
+
}
|
|
14728
|
+
subscribe(relays, filter, params) {
|
|
14729
|
+
const request = [];
|
|
14730
|
+
const uniqUrls = [];
|
|
14731
|
+
for (let i22 = 0; i22 < relays.length; i22++) {
|
|
14732
|
+
const url = normalizeURL2(relays[i22]);
|
|
14733
|
+
if (!request.find((r) => r.url === url)) {
|
|
14734
|
+
if (uniqUrls.indexOf(url) === -1) {
|
|
14735
|
+
uniqUrls.push(url);
|
|
14736
|
+
request.push({ url, filter });
|
|
14737
|
+
}
|
|
14738
|
+
}
|
|
14739
|
+
}
|
|
14740
|
+
return this.subscribeMap(request, params);
|
|
14741
|
+
}
|
|
14742
|
+
subscribeMany(relays, filter, params) {
|
|
14743
|
+
return this.subscribe(relays, filter, params);
|
|
14744
|
+
}
|
|
14745
|
+
subscribeMap(requests, params) {
|
|
14746
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
14747
|
+
for (const req of requests) {
|
|
14748
|
+
const { url, filter } = req;
|
|
14749
|
+
if (!grouped.has(url))
|
|
14750
|
+
grouped.set(url, []);
|
|
14751
|
+
grouped.get(url).push(filter);
|
|
14752
|
+
}
|
|
14753
|
+
const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }));
|
|
14754
|
+
if (this.trackRelays) {
|
|
14755
|
+
params.receivedEvent = (relay, id) => {
|
|
14756
|
+
let set = this.seenOn.get(id);
|
|
14757
|
+
if (!set) {
|
|
14758
|
+
set = /* @__PURE__ */ new Set();
|
|
14759
|
+
this.seenOn.set(id, set);
|
|
14760
|
+
}
|
|
14761
|
+
set.add(relay);
|
|
14762
|
+
};
|
|
14763
|
+
}
|
|
14764
|
+
const _knownIds = /* @__PURE__ */ new Set();
|
|
14765
|
+
const subs = [];
|
|
14766
|
+
const eosesReceived = [];
|
|
14767
|
+
let handleEose = (i22) => {
|
|
14768
|
+
if (eosesReceived[i22])
|
|
14769
|
+
return;
|
|
14770
|
+
eosesReceived[i22] = true;
|
|
14771
|
+
if (eosesReceived.filter((a) => a).length === groupedRequests.length) {
|
|
14772
|
+
params.oneose?.();
|
|
14773
|
+
handleEose = () => {
|
|
14774
|
+
};
|
|
14775
|
+
}
|
|
14776
|
+
};
|
|
14777
|
+
const closesReceived = [];
|
|
14778
|
+
let handleClose = (i22, reason) => {
|
|
14779
|
+
if (closesReceived[i22])
|
|
14780
|
+
return;
|
|
14781
|
+
handleEose(i22);
|
|
14782
|
+
closesReceived[i22] = reason;
|
|
14783
|
+
if (closesReceived.filter((a) => a).length === groupedRequests.length) {
|
|
14784
|
+
params.onclose?.(closesReceived);
|
|
14785
|
+
handleClose = () => {
|
|
14786
|
+
};
|
|
14787
|
+
}
|
|
14788
|
+
};
|
|
14789
|
+
const localAlreadyHaveEventHandler = (id) => {
|
|
14790
|
+
if (params.alreadyHaveEvent?.(id)) {
|
|
14791
|
+
return true;
|
|
14792
|
+
}
|
|
14793
|
+
const have = _knownIds.has(id);
|
|
14794
|
+
_knownIds.add(id);
|
|
14795
|
+
return have;
|
|
14796
|
+
};
|
|
14797
|
+
const allOpened = Promise.all(
|
|
14798
|
+
groupedRequests.map(async ({ url, filters }, i22) => {
|
|
14799
|
+
if (this.allowConnectingToRelay?.(url, ["read", filters]) === false) {
|
|
14800
|
+
handleClose(i22, "connection skipped by allowConnectingToRelay");
|
|
14801
|
+
return;
|
|
14802
|
+
}
|
|
14803
|
+
let relay;
|
|
14804
|
+
try {
|
|
14805
|
+
relay = await this.ensureRelay(url, {
|
|
14806
|
+
connectionTimeout: this.maxWaitForConnection < (params.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
|
|
14807
|
+
abort: params.abort
|
|
14808
|
+
});
|
|
14809
|
+
} catch (err) {
|
|
14810
|
+
this.onRelayConnectionFailure?.(url);
|
|
14811
|
+
handleClose(i22, err?.message || String(err));
|
|
14812
|
+
return;
|
|
14813
|
+
}
|
|
14814
|
+
this.onRelayConnectionSuccess?.(url);
|
|
14815
|
+
let subscription = relay.subscribe(filters, {
|
|
14816
|
+
...params,
|
|
14817
|
+
oneose: () => handleEose(i22),
|
|
14818
|
+
onclose: (reason) => {
|
|
14819
|
+
if (reason.startsWith("auth-required: ") && params.onauth) {
|
|
14820
|
+
relay.auth(params.onauth).then(() => {
|
|
14821
|
+
relay.subscribe(filters, {
|
|
14822
|
+
...params,
|
|
14823
|
+
oneose: () => handleEose(i22),
|
|
14824
|
+
onclose: (reason2) => {
|
|
14825
|
+
handleClose(i22, reason2);
|
|
14826
|
+
},
|
|
14827
|
+
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
|
14828
|
+
eoseTimeout: params.maxWait,
|
|
14829
|
+
abort: params.abort
|
|
14830
|
+
});
|
|
14831
|
+
}).catch((err) => {
|
|
14832
|
+
handleClose(i22, `auth was required and attempted, but failed with: ${err}`);
|
|
14833
|
+
});
|
|
14834
|
+
} else {
|
|
14835
|
+
handleClose(i22, reason);
|
|
14836
|
+
}
|
|
14837
|
+
},
|
|
14838
|
+
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
|
14839
|
+
eoseTimeout: params.maxWait,
|
|
14840
|
+
abort: params.abort
|
|
14841
|
+
});
|
|
14842
|
+
subs.push(subscription);
|
|
14843
|
+
})
|
|
14844
|
+
);
|
|
14845
|
+
return {
|
|
14846
|
+
async close(reason) {
|
|
14847
|
+
await allOpened;
|
|
14848
|
+
subs.forEach((sub) => {
|
|
14849
|
+
sub.close(reason);
|
|
14850
|
+
});
|
|
14851
|
+
}
|
|
14852
|
+
};
|
|
14853
|
+
}
|
|
14854
|
+
subscribeEose(relays, filter, params) {
|
|
14855
|
+
let subcloser;
|
|
14856
|
+
subcloser = this.subscribe(relays, filter, {
|
|
14857
|
+
...params,
|
|
14858
|
+
oneose() {
|
|
14859
|
+
const reason = "closed automatically on eose";
|
|
14860
|
+
if (subcloser)
|
|
14861
|
+
subcloser.close(reason);
|
|
14862
|
+
else
|
|
14863
|
+
params.onclose?.(relays.map((_) => reason));
|
|
14864
|
+
}
|
|
14865
|
+
});
|
|
14866
|
+
return subcloser;
|
|
14867
|
+
}
|
|
14868
|
+
subscribeManyEose(relays, filter, params) {
|
|
14869
|
+
return this.subscribeEose(relays, filter, params);
|
|
14870
|
+
}
|
|
14871
|
+
async querySync(relays, filter, params) {
|
|
14872
|
+
return new Promise(async (resolve) => {
|
|
14873
|
+
const events = [];
|
|
14874
|
+
this.subscribeEose(relays, filter, {
|
|
14875
|
+
...params,
|
|
14876
|
+
onevent(event) {
|
|
14877
|
+
events.push(event);
|
|
14878
|
+
},
|
|
14879
|
+
onclose(_) {
|
|
14880
|
+
resolve(events);
|
|
14881
|
+
}
|
|
14882
|
+
});
|
|
14883
|
+
});
|
|
14884
|
+
}
|
|
14885
|
+
async get(relays, filter, params) {
|
|
14886
|
+
filter.limit = 1;
|
|
14887
|
+
const events = await this.querySync(relays, filter, params);
|
|
14888
|
+
events.sort((a, b) => b.created_at - a.created_at);
|
|
14889
|
+
return events[0] || null;
|
|
14890
|
+
}
|
|
14891
|
+
publish(relays, event, params) {
|
|
14892
|
+
return relays.map(normalizeURL2).map(async (url, i22, arr) => {
|
|
14893
|
+
if (arr.indexOf(url) !== i22) {
|
|
14894
|
+
return Promise.reject("duplicate url");
|
|
14895
|
+
}
|
|
14896
|
+
if (this.allowConnectingToRelay?.(url, ["write", event]) === false) {
|
|
14897
|
+
return Promise.reject("connection skipped by allowConnectingToRelay");
|
|
14898
|
+
}
|
|
14899
|
+
let r;
|
|
14900
|
+
try {
|
|
14901
|
+
r = await this.ensureRelay(url, {
|
|
14902
|
+
connectionTimeout: this.maxWaitForConnection < (params?.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
|
|
14903
|
+
abort: params?.abort
|
|
14904
|
+
});
|
|
14905
|
+
} catch (err) {
|
|
14906
|
+
this.onRelayConnectionFailure?.(url);
|
|
14907
|
+
return String("connection failure: " + String(err));
|
|
14908
|
+
}
|
|
14909
|
+
return r.publish(event).catch(async (err) => {
|
|
14910
|
+
if (err instanceof Error && err.message.startsWith("auth-required: ") && params?.onauth) {
|
|
14911
|
+
await r.auth(params.onauth);
|
|
14912
|
+
return r.publish(event);
|
|
14913
|
+
}
|
|
14914
|
+
throw err;
|
|
14915
|
+
}).then((reason) => {
|
|
14916
|
+
if (this.trackRelays) {
|
|
14917
|
+
let set = this.seenOn.get(event.id);
|
|
14918
|
+
if (!set) {
|
|
14919
|
+
set = /* @__PURE__ */ new Set();
|
|
14920
|
+
this.seenOn.set(event.id, set);
|
|
14921
|
+
}
|
|
14922
|
+
set.add(r);
|
|
14923
|
+
}
|
|
14924
|
+
return reason;
|
|
14925
|
+
});
|
|
14926
|
+
});
|
|
14927
|
+
}
|
|
14928
|
+
listConnectionStatus() {
|
|
14929
|
+
const map = /* @__PURE__ */ new Map();
|
|
14930
|
+
this.relays.forEach((relay, url) => map.set(url, relay.connected));
|
|
14931
|
+
return map;
|
|
14932
|
+
}
|
|
14933
|
+
destroy() {
|
|
14934
|
+
this.relays.forEach((conn) => conn.close());
|
|
14935
|
+
this.relays = /* @__PURE__ */ new Map();
|
|
14936
|
+
}
|
|
14937
|
+
pruneIdleRelays(idleThresholdMs = 1e4) {
|
|
14938
|
+
const prunedUrls = [];
|
|
14939
|
+
for (const [url, relay] of this.relays) {
|
|
14940
|
+
if (relay.idleSince && Date.now() - relay.idleSince >= idleThresholdMs) {
|
|
14941
|
+
this.relays.delete(url);
|
|
14942
|
+
prunedUrls.push(url);
|
|
14943
|
+
relay.close();
|
|
14944
|
+
}
|
|
14945
|
+
}
|
|
14946
|
+
return prunedUrls;
|
|
14947
|
+
}
|
|
14948
|
+
};
|
|
14949
|
+
var _WebSocket3;
|
|
14950
|
+
try {
|
|
14951
|
+
_WebSocket3 = WebSocket;
|
|
14952
|
+
} catch {
|
|
14953
|
+
}
|
|
14954
|
+
var SimplePool = class extends AbstractSimplePool {
|
|
14955
|
+
constructor(options) {
|
|
14956
|
+
super({ verifyEvent: verifyEvent3, websocketImplementation: _WebSocket3, maxWaitForConnection: 3e3, ...options });
|
|
14957
|
+
}
|
|
14958
|
+
};
|
|
14959
|
+
|
|
14960
|
+
// ../nip/dist/chunk-2J3CSGKL.js
|
|
14961
|
+
function computeAggregateHash(entries) {
|
|
14962
|
+
const lines = entries.map((entry) => `${entry.sha256} ${entry.path}
|
|
14963
|
+
`);
|
|
14964
|
+
lines.sort();
|
|
14965
|
+
return bytesToHex2(sha256(new TextEncoder().encode(lines.join(""))));
|
|
14966
|
+
}
|
|
14967
|
+
function pathEntriesFromTags(tags) {
|
|
14968
|
+
const entries = [];
|
|
14969
|
+
for (const tag of tags) {
|
|
14970
|
+
if (tag[0] === "path" && typeof tag[1] === "string" && typeof tag[2] === "string" && tag[1].length > 0 && tag[2].length > 0) {
|
|
14971
|
+
entries.push({ path: tag[1], sha256: tag[2] });
|
|
14972
|
+
}
|
|
14973
|
+
}
|
|
14974
|
+
return entries;
|
|
14975
|
+
}
|
|
14976
|
+
function aggregateTagValue(tags) {
|
|
14977
|
+
for (const tag of tags) {
|
|
14978
|
+
if (tag[0] === "x" && tag[2] === "aggregate" && typeof tag[1] === "string" && tag[1].length > 0) {
|
|
14979
|
+
return tag[1];
|
|
14980
|
+
}
|
|
14981
|
+
}
|
|
14982
|
+
return void 0;
|
|
14983
|
+
}
|
|
14984
|
+
|
|
14985
|
+
// ../nip/dist/chunk-CDBUCFLP.js
|
|
14986
|
+
var MIB = 1024 * 1024;
|
|
14987
|
+
var NAPPLET_ARTIFACT_CACHE_NAME = "kehto:napplet-artifacts:v1";
|
|
14988
|
+
var SCHEMA_VERSION = 1;
|
|
14989
|
+
var DEFAULT_BASE_URL = "https://kehto.invalid";
|
|
14990
|
+
var DEFAULT_UNKNOWN_BUDGET_BYTES = 32 * MIB;
|
|
14991
|
+
var DEFAULT_SOFT_CEILING_BYTES = 128 * MIB;
|
|
14992
|
+
var DEFAULT_HARD_CEILING_BYTES = 256 * MIB;
|
|
14993
|
+
var DEFAULT_FOREGROUND_TTL_MS = 15 * 60 * 1e3;
|
|
14994
|
+
var DEFAULT_BACKGROUND_TTL_MS = 60 * 60 * 1e3;
|
|
14995
|
+
function emptyIndex(now2) {
|
|
14996
|
+
return {
|
|
14997
|
+
schemaVersion: SCHEMA_VERSION,
|
|
14998
|
+
updatedAt: now2,
|
|
14999
|
+
blobs: {},
|
|
15000
|
+
aggregates: {},
|
|
15001
|
+
coordinates: {}
|
|
15002
|
+
};
|
|
15003
|
+
}
|
|
15004
|
+
function aggregateKey(dTag, aggregateHash) {
|
|
15005
|
+
return `${encodeURIComponent(dTag)}:${aggregateHash}`;
|
|
15006
|
+
}
|
|
15007
|
+
function coordinateKey(kind, pubkey, dTag) {
|
|
15008
|
+
return `${kind}:${pubkey}:${encodeURIComponent(dTag)}`;
|
|
15009
|
+
}
|
|
15010
|
+
function isCoordinateFresh(coordinate, options = {}) {
|
|
15011
|
+
const now2 = options.now ?? Date.now();
|
|
15012
|
+
const ttl = options.background ? coordinate.backgroundTtlMs : coordinate.foregroundTtlMs;
|
|
15013
|
+
return ttl === Number.POSITIVE_INFINITY || now2 - coordinate.lastResolvedAt <= ttl;
|
|
15014
|
+
}
|
|
15015
|
+
function byteLength2(bytes) {
|
|
15016
|
+
return bytes.byteLength;
|
|
15017
|
+
}
|
|
15018
|
+
function encodeKeyPart(value) {
|
|
15019
|
+
return encodeURIComponent(value).replaceAll("%2F", "%252F");
|
|
15020
|
+
}
|
|
15021
|
+
function cloneBytes(bytes) {
|
|
15022
|
+
return new Uint8Array(bytes);
|
|
15023
|
+
}
|
|
15024
|
+
function responseBody(bytes) {
|
|
15025
|
+
return cloneBytes(bytes).buffer;
|
|
15026
|
+
}
|
|
15027
|
+
function normalizeBaseUrl(baseUrl) {
|
|
15028
|
+
return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
15029
|
+
}
|
|
15030
|
+
function resolveBaseUrl(baseUrl) {
|
|
15031
|
+
if (baseUrl) return normalizeBaseUrl(baseUrl);
|
|
15032
|
+
const maybeLocation = globalThis;
|
|
15033
|
+
if (maybeLocation.location?.origin) return normalizeBaseUrl(maybeLocation.location.origin);
|
|
15034
|
+
return normalizeBaseUrl(DEFAULT_BASE_URL);
|
|
15035
|
+
}
|
|
15036
|
+
async function responseBytes(response) {
|
|
15037
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
15038
|
+
}
|
|
15039
|
+
async function responseJson(response) {
|
|
15040
|
+
return response.json();
|
|
15041
|
+
}
|
|
15042
|
+
function refCounts(index) {
|
|
15043
|
+
const counts = {};
|
|
15044
|
+
for (const aggregate of Object.values(index.aggregates)) {
|
|
15045
|
+
for (const hash of aggregate.blobHashes) counts[hash] = (counts[hash] ?? 0) + 1;
|
|
15046
|
+
}
|
|
15047
|
+
return counts;
|
|
15048
|
+
}
|
|
15049
|
+
function cachedSize(index) {
|
|
15050
|
+
const blobBytes = Object.values(index.blobs).reduce((sum, entry) => sum + entry.size, 0);
|
|
15051
|
+
const aggregateBytes = Object.values(index.aggregates).reduce((sum, entry) => sum + entry.size, 0);
|
|
15052
|
+
return blobBytes + aggregateBytes;
|
|
15053
|
+
}
|
|
15054
|
+
var CacheStorageNappletArtifactCache = class {
|
|
15055
|
+
cacheStorage;
|
|
15056
|
+
storage;
|
|
15057
|
+
cacheName;
|
|
15058
|
+
baseUrl;
|
|
15059
|
+
now;
|
|
15060
|
+
activeAggregates = /* @__PURE__ */ new Set();
|
|
15061
|
+
onDiagnostic;
|
|
15062
|
+
unknownBudgetBytes;
|
|
15063
|
+
softCeilingBytes;
|
|
15064
|
+
hardCeilingBytes;
|
|
15065
|
+
cachePromise;
|
|
15066
|
+
constructor(options = {}) {
|
|
15067
|
+
const maybeCacheStorage = options.cacheStorage ?? globalThis.caches;
|
|
15068
|
+
if (!maybeCacheStorage) {
|
|
15069
|
+
throw new Error("Cache Storage is unavailable");
|
|
15070
|
+
}
|
|
15071
|
+
this.cacheStorage = maybeCacheStorage;
|
|
15072
|
+
this.storage = options.storage ?? globalThis.navigator?.storage;
|
|
15073
|
+
this.cacheName = options.cacheName ?? NAPPLET_ARTIFACT_CACHE_NAME;
|
|
15074
|
+
this.baseUrl = resolveBaseUrl(options.baseUrl);
|
|
15075
|
+
this.now = options.now ?? Date.now;
|
|
15076
|
+
this.onDiagnostic = options.onDiagnostic;
|
|
15077
|
+
this.unknownBudgetBytes = options.unknownBudgetBytes ?? DEFAULT_UNKNOWN_BUDGET_BYTES;
|
|
15078
|
+
this.softCeilingBytes = options.softCeilingBytes ?? DEFAULT_SOFT_CEILING_BYTES;
|
|
15079
|
+
this.hardCeilingBytes = options.hardCeilingBytes ?? DEFAULT_HARD_CEILING_BYTES;
|
|
15080
|
+
}
|
|
15081
|
+
async readBlob(sha256Hex) {
|
|
15082
|
+
try {
|
|
15083
|
+
const cache2 = await this.open();
|
|
15084
|
+
const response = await cache2.match(this.blobUrl(sha256Hex));
|
|
15085
|
+
if (!response) return void 0;
|
|
15086
|
+
const bytes = await responseBytes(response);
|
|
15087
|
+
const index = await this.readIndex(cache2);
|
|
15088
|
+
const entry = index.blobs[sha256Hex];
|
|
15089
|
+
if (entry) {
|
|
15090
|
+
entry.lastAccessed = this.now();
|
|
15091
|
+
index.updatedAt = entry.lastAccessed;
|
|
15092
|
+
await this.writeIndex(cache2, index);
|
|
15093
|
+
}
|
|
15094
|
+
return bytes;
|
|
15095
|
+
} catch (cause) {
|
|
15096
|
+
this.diagnostic({ type: "cache-read-failed", message: `failed to read blob ${sha256Hex}`, cause });
|
|
15097
|
+
return void 0;
|
|
15098
|
+
}
|
|
15099
|
+
}
|
|
15100
|
+
async deleteBlob(sha256Hex) {
|
|
15101
|
+
try {
|
|
15102
|
+
const cache2 = await this.open();
|
|
15103
|
+
await cache2.delete(this.blobUrl(sha256Hex));
|
|
15104
|
+
const index = await this.readIndex(cache2);
|
|
15105
|
+
delete index.blobs[sha256Hex];
|
|
15106
|
+
index.updatedAt = this.now();
|
|
15107
|
+
await this.writeIndex(cache2, index);
|
|
15108
|
+
} catch (cause) {
|
|
15109
|
+
this.diagnostic({ type: "cache-delete-failed", message: `failed to delete blob ${sha256Hex}`, cause });
|
|
15110
|
+
}
|
|
15111
|
+
}
|
|
15112
|
+
async writeVerifiedResolution(input) {
|
|
15113
|
+
try {
|
|
15114
|
+
await this.writeVerifiedResolutionOnce(input);
|
|
15115
|
+
} catch (firstCause) {
|
|
15116
|
+
try {
|
|
15117
|
+
await this.prune(input.now ?? this.now());
|
|
15118
|
+
await this.writeVerifiedResolutionOnce(input);
|
|
15119
|
+
} catch (cause) {
|
|
15120
|
+
this.diagnostic({
|
|
15121
|
+
type: "cache-write-failed",
|
|
15122
|
+
message: "failed to write verified napplet artifacts after prune retry",
|
|
15123
|
+
cause: cause ?? firstCause
|
|
15124
|
+
});
|
|
15125
|
+
}
|
|
15126
|
+
}
|
|
15127
|
+
}
|
|
15128
|
+
async writeCoordinate(input) {
|
|
15129
|
+
const cache2 = await this.open();
|
|
15130
|
+
const now2 = this.now();
|
|
15131
|
+
const index = await this.readIndex(cache2);
|
|
15132
|
+
const key = coordinateKey(input.kind, input.pubkey, input.dTag);
|
|
15133
|
+
index.coordinates[key] = {
|
|
15134
|
+
key,
|
|
15135
|
+
kind: input.kind,
|
|
15136
|
+
pubkey: input.pubkey,
|
|
15137
|
+
dTag: input.dTag,
|
|
15138
|
+
aggregateHash: input.aggregateHash,
|
|
15139
|
+
lastResolvedAt: input.lastResolvedAt ?? now2,
|
|
15140
|
+
foregroundTtlMs: input.foregroundTtlMs ?? DEFAULT_FOREGROUND_TTL_MS,
|
|
15141
|
+
backgroundTtlMs: input.backgroundTtlMs ?? DEFAULT_BACKGROUND_TTL_MS
|
|
15142
|
+
};
|
|
15143
|
+
index.updatedAt = now2;
|
|
15144
|
+
await this.writeIndex(cache2, index);
|
|
15145
|
+
}
|
|
15146
|
+
async getCoordinate(input, options = {}) {
|
|
15147
|
+
const cache2 = await this.open();
|
|
15148
|
+
const index = await this.readIndex(cache2);
|
|
15149
|
+
const coordinate = index.coordinates[coordinateKey(input.kind, input.pubkey, input.dTag)];
|
|
15150
|
+
if (!coordinate) return void 0;
|
|
15151
|
+
return { ...coordinate, fresh: isCoordinateFresh(coordinate, options) };
|
|
15152
|
+
}
|
|
15153
|
+
async touchAggregate(dTag, aggregateHash, now2 = this.now()) {
|
|
15154
|
+
const cache2 = await this.open();
|
|
15155
|
+
const index = await this.readIndex(cache2);
|
|
15156
|
+
const key = aggregateKey(dTag, aggregateHash);
|
|
15157
|
+
const aggregate = index.aggregates[key];
|
|
15158
|
+
if (!aggregate) return;
|
|
15159
|
+
aggregate.lastAccessed = now2;
|
|
15160
|
+
for (const hash of aggregate.blobHashes) {
|
|
15161
|
+
if (index.blobs[hash]) index.blobs[hash].lastAccessed = now2;
|
|
15162
|
+
}
|
|
15163
|
+
index.updatedAt = now2;
|
|
15164
|
+
await this.writeIndex(cache2, index);
|
|
15165
|
+
}
|
|
15166
|
+
markAggregateActive(dTag, aggregateHash) {
|
|
15167
|
+
this.activeAggregates.add(aggregateKey(dTag, aggregateHash));
|
|
15168
|
+
}
|
|
15169
|
+
releaseAggregateActive(dTag, aggregateHash) {
|
|
15170
|
+
this.activeAggregates.delete(aggregateKey(dTag, aggregateHash));
|
|
15171
|
+
}
|
|
15172
|
+
async prune(now2 = this.now()) {
|
|
15173
|
+
try {
|
|
15174
|
+
const cache2 = await this.open();
|
|
15175
|
+
const index = await this.readIndex(cache2);
|
|
15176
|
+
let size = cachedSize(index);
|
|
15177
|
+
const budget = await this.budgetBytes();
|
|
15178
|
+
const hardBudget = await this.hardBudgetBytes();
|
|
15179
|
+
const shouldPrune = size > budget || await this.originPressureHigh();
|
|
15180
|
+
if (!shouldPrune) return;
|
|
15181
|
+
this.rewriteRefCounts(index);
|
|
15182
|
+
for (const [hash, blob] of Object.entries(index.blobs)) {
|
|
15183
|
+
if (size <= budget) break;
|
|
15184
|
+
if (blob.refCount > 0) continue;
|
|
15185
|
+
await cache2.delete(this.blobUrl(hash));
|
|
15186
|
+
delete index.blobs[hash];
|
|
15187
|
+
size -= blob.size;
|
|
15188
|
+
}
|
|
15189
|
+
const currentAggregateHashes = new Set(
|
|
15190
|
+
Object.values(index.coordinates).map((coordinate) => coordinate.aggregateHash)
|
|
15191
|
+
);
|
|
15192
|
+
const aggregates = Object.values(index.aggregates).filter((entry) => !this.activeAggregates.has(entry.key)).sort((a, b) => {
|
|
15193
|
+
const currentA = currentAggregateHashes.has(a.aggregateHash) ? 1 : 0;
|
|
15194
|
+
const currentB = currentAggregateHashes.has(b.aggregateHash) ? 1 : 0;
|
|
15195
|
+
if (currentA !== currentB) return currentA - currentB;
|
|
15196
|
+
return a.lastAccessed - b.lastAccessed;
|
|
15197
|
+
});
|
|
15198
|
+
for (const aggregate of aggregates) {
|
|
15199
|
+
if (size <= budget) break;
|
|
15200
|
+
await cache2.delete(this.aggregateUrl(aggregate.key));
|
|
15201
|
+
delete index.aggregates[aggregate.key];
|
|
15202
|
+
size -= aggregate.size;
|
|
15203
|
+
this.rewriteRefCounts(index);
|
|
15204
|
+
}
|
|
15205
|
+
if (size > hardBudget) {
|
|
15206
|
+
const active = Object.values(index.aggregates).filter((entry) => this.activeAggregates.has(entry.key)).sort((a, b) => a.lastAccessed - b.lastAccessed);
|
|
15207
|
+
for (const aggregate of active) {
|
|
15208
|
+
if (size <= hardBudget) break;
|
|
15209
|
+
await cache2.delete(this.aggregateUrl(aggregate.key));
|
|
15210
|
+
delete index.aggregates[aggregate.key];
|
|
15211
|
+
size -= aggregate.size;
|
|
15212
|
+
}
|
|
15213
|
+
}
|
|
15214
|
+
this.rewriteRefCounts(index);
|
|
15215
|
+
for (const [hash, blob] of Object.entries(index.blobs)) {
|
|
15216
|
+
if (blob.refCount === 0) {
|
|
15217
|
+
await cache2.delete(this.blobUrl(hash));
|
|
15218
|
+
delete index.blobs[hash];
|
|
15219
|
+
}
|
|
15220
|
+
}
|
|
15221
|
+
index.updatedAt = now2;
|
|
15222
|
+
await this.writeIndex(cache2, index);
|
|
15223
|
+
} catch (cause) {
|
|
15224
|
+
this.diagnostic({ type: "cache-prune-failed", message: "failed to prune napplet artifact cache", cause });
|
|
15225
|
+
}
|
|
15226
|
+
}
|
|
15227
|
+
async snapshotIndex() {
|
|
15228
|
+
return this.readIndex(await this.open());
|
|
15229
|
+
}
|
|
15230
|
+
async writeVerifiedResolutionOnce(input) {
|
|
15231
|
+
const cache2 = await this.open();
|
|
15232
|
+
const now2 = input.now ?? this.now();
|
|
15233
|
+
const index = await this.readIndex(cache2);
|
|
15234
|
+
const blobHashes = [];
|
|
15235
|
+
for (const pathEntry of input.manifest.paths) {
|
|
15236
|
+
const bytes = input.files.get(pathEntry.path);
|
|
15237
|
+
if (!bytes) continue;
|
|
15238
|
+
blobHashes.push(pathEntry.sha256);
|
|
15239
|
+
await cache2.put(this.blobUrl(pathEntry.sha256), new Response(responseBody(bytes)));
|
|
15240
|
+
index.blobs[pathEntry.sha256] = {
|
|
15241
|
+
size: byteLength2(bytes),
|
|
15242
|
+
lastAccessed: now2,
|
|
15243
|
+
refCount: index.blobs[pathEntry.sha256]?.refCount ?? 0
|
|
15244
|
+
};
|
|
15245
|
+
}
|
|
15246
|
+
const key = aggregateKey(input.manifest.dTag, input.manifest.aggregateHash);
|
|
15247
|
+
const record = {
|
|
15248
|
+
schemaVersion: SCHEMA_VERSION,
|
|
15249
|
+
dTag: input.manifest.dTag,
|
|
15250
|
+
aggregateHash: input.manifest.aggregateHash,
|
|
15251
|
+
manifest: {
|
|
15252
|
+
kind: input.manifest.kind,
|
|
15253
|
+
pubkey: input.manifest.pubkey,
|
|
15254
|
+
dTag: input.manifest.dTag,
|
|
15255
|
+
paths: input.manifest.paths.map((entry) => ({ path: entry.path, sha256: entry.sha256 })),
|
|
15256
|
+
requires: [...input.manifest.requires],
|
|
15257
|
+
...input.manifest.title === void 0 ? {} : { title: input.manifest.title },
|
|
15258
|
+
...input.manifest.description === void 0 ? {} : { description: input.manifest.description }
|
|
15259
|
+
},
|
|
15260
|
+
indexHtml: input.indexHtml,
|
|
15261
|
+
blobHashes,
|
|
15262
|
+
writtenAt: now2
|
|
15263
|
+
};
|
|
15264
|
+
const aggregateBytes = new TextEncoder().encode(JSON.stringify(record));
|
|
15265
|
+
await cache2.put(this.aggregateUrl(key), new Response(responseBody(aggregateBytes), {
|
|
15266
|
+
headers: { "content-type": "application/json" }
|
|
15267
|
+
}));
|
|
15268
|
+
const coordKey = coordinateKey(input.manifest.kind, input.manifest.pubkey, input.manifest.dTag);
|
|
15269
|
+
index.aggregates[key] = {
|
|
15270
|
+
dTag: input.manifest.dTag,
|
|
15271
|
+
aggregateHash: input.manifest.aggregateHash,
|
|
15272
|
+
key,
|
|
15273
|
+
blobHashes,
|
|
15274
|
+
size: byteLength2(aggregateBytes),
|
|
15275
|
+
lastAccessed: now2,
|
|
15276
|
+
coordinateKey: coordKey
|
|
15277
|
+
};
|
|
15278
|
+
index.coordinates[coordKey] = {
|
|
15279
|
+
key: coordKey,
|
|
15280
|
+
kind: input.manifest.kind,
|
|
15281
|
+
pubkey: input.manifest.pubkey,
|
|
15282
|
+
dTag: input.manifest.dTag,
|
|
15283
|
+
aggregateHash: input.manifest.aggregateHash,
|
|
15284
|
+
lastResolvedAt: now2,
|
|
15285
|
+
foregroundTtlMs: DEFAULT_FOREGROUND_TTL_MS,
|
|
15286
|
+
backgroundTtlMs: DEFAULT_BACKGROUND_TTL_MS
|
|
15287
|
+
};
|
|
15288
|
+
this.rewriteRefCounts(index);
|
|
15289
|
+
index.updatedAt = now2;
|
|
15290
|
+
await this.writeIndex(cache2, index);
|
|
15291
|
+
await this.prune(now2);
|
|
15292
|
+
}
|
|
15293
|
+
async open() {
|
|
15294
|
+
this.cachePromise ??= this.cacheStorage.open(this.cacheName);
|
|
15295
|
+
return this.cachePromise;
|
|
15296
|
+
}
|
|
15297
|
+
indexUrl() {
|
|
15298
|
+
return new URL("__kehto_napplet_cache/index.json", this.baseUrl).toString();
|
|
15299
|
+
}
|
|
15300
|
+
blobUrl(hash) {
|
|
15301
|
+
return new URL(`__kehto_napplet_cache/blob/${encodeKeyPart(hash)}`, this.baseUrl).toString();
|
|
15302
|
+
}
|
|
15303
|
+
aggregateUrl(key) {
|
|
15304
|
+
return new URL(`__kehto_napplet_cache/aggregate/${encodeKeyPart(key)}.json`, this.baseUrl).toString();
|
|
15305
|
+
}
|
|
15306
|
+
async readIndex(cache2) {
|
|
15307
|
+
const response = await cache2.match(this.indexUrl());
|
|
15308
|
+
if (!response) return emptyIndex(this.now());
|
|
15309
|
+
try {
|
|
15310
|
+
const index = await responseJson(response);
|
|
15311
|
+
if (index.schemaVersion !== SCHEMA_VERSION) return emptyIndex(this.now());
|
|
15312
|
+
return index;
|
|
15313
|
+
} catch {
|
|
15314
|
+
return emptyIndex(this.now());
|
|
15315
|
+
}
|
|
15316
|
+
}
|
|
15317
|
+
async writeIndex(cache2, index) {
|
|
15318
|
+
await cache2.put(this.indexUrl(), new Response(JSON.stringify(index), {
|
|
15319
|
+
headers: { "content-type": "application/json" }
|
|
15320
|
+
}));
|
|
15321
|
+
}
|
|
15322
|
+
rewriteRefCounts(index) {
|
|
15323
|
+
const counts = refCounts(index);
|
|
15324
|
+
for (const [hash, blob] of Object.entries(index.blobs)) {
|
|
15325
|
+
blob.refCount = counts[hash] ?? 0;
|
|
15326
|
+
}
|
|
15327
|
+
}
|
|
15328
|
+
async budgetBytes() {
|
|
15329
|
+
const estimate = await this.estimateStorage();
|
|
15330
|
+
if (!estimate?.quota) return this.unknownBudgetBytes;
|
|
15331
|
+
return Math.min(this.softCeilingBytes, Math.floor(estimate.quota * 0.1));
|
|
15332
|
+
}
|
|
15333
|
+
async hardBudgetBytes() {
|
|
15334
|
+
const estimate = await this.estimateStorage();
|
|
15335
|
+
if (!estimate?.quota) return this.unknownBudgetBytes;
|
|
15336
|
+
return Math.min(this.hardCeilingBytes, Math.floor(estimate.quota * 0.2));
|
|
15337
|
+
}
|
|
15338
|
+
async originPressureHigh() {
|
|
15339
|
+
const estimate = await this.estimateStorage();
|
|
15340
|
+
if (!estimate?.quota || estimate.usage === void 0) return false;
|
|
15341
|
+
return estimate.usage / estimate.quota >= 0.8;
|
|
15342
|
+
}
|
|
15343
|
+
async estimateStorage() {
|
|
15344
|
+
if (!this.storage?.estimate) return void 0;
|
|
15345
|
+
try {
|
|
15346
|
+
return this.storage.estimate();
|
|
15347
|
+
} catch (cause) {
|
|
15348
|
+
this.diagnostic({
|
|
15349
|
+
type: "storage-estimate-unavailable",
|
|
15350
|
+
message: "storage estimate failed; using unknown quota cache budget",
|
|
15351
|
+
cause
|
|
15352
|
+
});
|
|
15353
|
+
return void 0;
|
|
15354
|
+
}
|
|
15355
|
+
}
|
|
15356
|
+
diagnostic(diagnostic) {
|
|
15357
|
+
this.onDiagnostic?.(diagnostic);
|
|
15358
|
+
}
|
|
15359
|
+
};
|
|
15360
|
+
async function openNappletArtifactCache(options = {}) {
|
|
15361
|
+
const cacheStorage = options.cacheStorage ?? globalThis.caches;
|
|
15362
|
+
if (!cacheStorage) return void 0;
|
|
15363
|
+
const storage = options.storage ?? globalThis.navigator?.storage;
|
|
15364
|
+
if (options.requireStorageEstimate && !storage?.estimate) {
|
|
15365
|
+
options.onDiagnostic?.({
|
|
15366
|
+
type: "storage-estimate-unavailable",
|
|
15367
|
+
message: "storage estimates are unavailable; using network-only loading"
|
|
15368
|
+
});
|
|
15369
|
+
return void 0;
|
|
15370
|
+
}
|
|
15371
|
+
try {
|
|
15372
|
+
const cache2 = new CacheStorageNappletArtifactCache({ ...options, cacheStorage, storage });
|
|
15373
|
+
await cache2.snapshotIndex();
|
|
15374
|
+
return cache2;
|
|
15375
|
+
} catch (cause) {
|
|
15376
|
+
options.onDiagnostic?.({
|
|
15377
|
+
type: "cache-open-failed",
|
|
15378
|
+
message: "Cache Storage napplet artifact cache could not be opened",
|
|
15379
|
+
cause
|
|
15380
|
+
});
|
|
15381
|
+
return void 0;
|
|
15382
|
+
}
|
|
15383
|
+
}
|
|
15384
|
+
var NAPPLET_KIND_SNAPSHOT = 5129;
|
|
15385
|
+
var NAPPLET_KIND_ROOT = 15129;
|
|
15386
|
+
var NAPPLET_KIND_NAMED = 35129;
|
|
15387
|
+
var NAPPLET_KINDS = [
|
|
15388
|
+
NAPPLET_KIND_SNAPSHOT,
|
|
15389
|
+
NAPPLET_KIND_ROOT,
|
|
15390
|
+
NAPPLET_KIND_NAMED
|
|
15391
|
+
];
|
|
15392
|
+
function isNappletManifestKind(kind) {
|
|
15393
|
+
return NAPPLET_KINDS.includes(kind);
|
|
15394
|
+
}
|
|
15395
|
+
var NappletResolutionError = class extends Error {
|
|
15396
|
+
code;
|
|
15397
|
+
constructor(code, message) {
|
|
15398
|
+
super(message);
|
|
15399
|
+
this.name = "NappletResolutionError";
|
|
15400
|
+
this.code = code;
|
|
15401
|
+
}
|
|
15402
|
+
};
|
|
15403
|
+
function firstTagValue(tags, name) {
|
|
15404
|
+
for (const tag of tags) {
|
|
15405
|
+
if (tag[0] === name && typeof tag[1] === "string" && tag[1].length > 0) return tag[1];
|
|
15406
|
+
}
|
|
15407
|
+
return void 0;
|
|
15408
|
+
}
|
|
15409
|
+
function allTagValues(tags, name) {
|
|
15410
|
+
const out = [];
|
|
15411
|
+
for (const tag of tags) {
|
|
15412
|
+
if (tag[0] === name && typeof tag[1] === "string" && tag[1].length > 0) out.push(tag[1]);
|
|
15413
|
+
}
|
|
15414
|
+
return out;
|
|
15415
|
+
}
|
|
15416
|
+
function archetypesFromTags(tags) {
|
|
15417
|
+
const out = [];
|
|
15418
|
+
for (const tag of tags) {
|
|
15419
|
+
if (tag[0] !== "archetype") continue;
|
|
15420
|
+
if (typeof tag[1] !== "string" || tag[1].length === 0) continue;
|
|
15421
|
+
out.push(
|
|
15422
|
+
typeof tag[2] === "string" && tag[2].length > 0 ? { slug: tag[1], nap: tag[2] } : { slug: tag[1] }
|
|
15423
|
+
);
|
|
15424
|
+
}
|
|
15425
|
+
return out;
|
|
15426
|
+
}
|
|
15427
|
+
function parseNappletManifest(event) {
|
|
15428
|
+
if (!isNappletManifestKind(event.kind)) {
|
|
15429
|
+
throw new NappletResolutionError("invalid-manifest", `not a NIP-5D napplet kind: ${event.kind}`);
|
|
15430
|
+
}
|
|
15431
|
+
const paths = pathEntriesFromTags(event.tags);
|
|
15432
|
+
if (paths.length === 0) {
|
|
15433
|
+
throw new NappletResolutionError("invalid-manifest", "manifest has no path tags");
|
|
15434
|
+
}
|
|
15435
|
+
const aggregateHash = aggregateTagValue(event.tags);
|
|
15436
|
+
if (!aggregateHash) {
|
|
15437
|
+
throw new NappletResolutionError("invalid-manifest", "manifest has no aggregate x tag");
|
|
15438
|
+
}
|
|
15439
|
+
return {
|
|
15440
|
+
kind: event.kind,
|
|
15441
|
+
pubkey: event.pubkey,
|
|
15442
|
+
dTag: firstTagValue(event.tags, "d") ?? "",
|
|
15443
|
+
paths,
|
|
15444
|
+
aggregateHash,
|
|
15445
|
+
servers: allTagValues(event.tags, "server"),
|
|
15446
|
+
requires: allTagValues(event.tags, "requires"),
|
|
15447
|
+
archetypes: archetypesFromTags(event.tags),
|
|
15448
|
+
title: firstTagValue(event.tags, "title"),
|
|
15449
|
+
description: firstTagValue(event.tags, "description"),
|
|
15450
|
+
source: firstTagValue(event.tags, "source")
|
|
15451
|
+
};
|
|
15452
|
+
}
|
|
15453
|
+
function verifyManifestSignature(event) {
|
|
15454
|
+
try {
|
|
15455
|
+
return verifyEvent(event);
|
|
15456
|
+
} catch {
|
|
15457
|
+
return false;
|
|
15458
|
+
}
|
|
15459
|
+
}
|
|
15460
|
+
function verifyBlobHash(bytes, sha256Hex) {
|
|
15461
|
+
return bytesToHex2(sha256(bytes)) === sha256Hex;
|
|
15462
|
+
}
|
|
15463
|
+
function stripTrailingSlash(url) {
|
|
15464
|
+
return url.endsWith("/") ? url.slice(0, -1) : url;
|
|
15465
|
+
}
|
|
15466
|
+
async function fetchBlob(servers, sha256Hex, fetchBytes) {
|
|
15467
|
+
for (const server of servers) {
|
|
15468
|
+
const url = `${stripTrailingSlash(server)}/${sha256Hex}`;
|
|
15469
|
+
try {
|
|
15470
|
+
const bytes = await fetchBytes(url);
|
|
15471
|
+
if (verifyBlobHash(bytes, sha256Hex)) return bytes;
|
|
15472
|
+
} catch {
|
|
15473
|
+
}
|
|
15474
|
+
}
|
|
15475
|
+
throw new NappletResolutionError("blob-unavailable", `no server served blob ${sha256Hex}`);
|
|
15476
|
+
}
|
|
15477
|
+
var INDEX_PATHS = ["/index.html", "index.html", "/"];
|
|
15478
|
+
function defaultDecode(bytes) {
|
|
15479
|
+
return new TextDecoder().decode(bytes);
|
|
15480
|
+
}
|
|
15481
|
+
async function resolveNapplet(options) {
|
|
15482
|
+
const { event, fetchBlob: fetchBlobBytes, textDecode = defaultDecode, cache: cache2 } = options;
|
|
15483
|
+
if (!verifyManifestSignature(event)) {
|
|
15484
|
+
throw new NappletResolutionError("invalid-signature", "manifest signature is invalid");
|
|
15485
|
+
}
|
|
15486
|
+
const manifest = parseNappletManifest(event);
|
|
15487
|
+
const recomputed = computeAggregateHash(manifest.paths);
|
|
15488
|
+
if (recomputed !== manifest.aggregateHash) {
|
|
15489
|
+
throw new NappletResolutionError(
|
|
15490
|
+
"aggregate-mismatch",
|
|
15491
|
+
`recomputed aggregate ${recomputed} != manifest ${manifest.aggregateHash}`
|
|
15492
|
+
);
|
|
15493
|
+
}
|
|
15494
|
+
const files = /* @__PURE__ */ new Map();
|
|
15495
|
+
for (const entry of manifest.paths) {
|
|
15496
|
+
let bytes = await cache2?.readBlob(entry.sha256);
|
|
15497
|
+
if (bytes && !verifyBlobHash(bytes, entry.sha256)) {
|
|
15498
|
+
await cache2?.deleteBlob(entry.sha256);
|
|
15499
|
+
bytes = void 0;
|
|
15500
|
+
}
|
|
15501
|
+
bytes ??= await fetchBlobBytes(entry.sha256, manifest.servers);
|
|
15502
|
+
if (!verifyBlobHash(bytes, entry.sha256)) {
|
|
15503
|
+
throw new NappletResolutionError(
|
|
15504
|
+
"blob-hash-mismatch",
|
|
15505
|
+
`blob for ${entry.path} does not match hash ${entry.sha256}`
|
|
15506
|
+
);
|
|
15507
|
+
}
|
|
15508
|
+
files.set(entry.path, bytes);
|
|
15509
|
+
}
|
|
15510
|
+
const indexEntry = manifest.paths.find((e) => INDEX_PATHS.includes(e.path));
|
|
15511
|
+
if (!indexEntry) {
|
|
15512
|
+
throw new NappletResolutionError("missing-index", "manifest has no /index.html entry");
|
|
15513
|
+
}
|
|
15514
|
+
const indexHtml = textDecode(files.get(indexEntry.path));
|
|
15515
|
+
await cache2?.writeVerifiedResolution({ event, manifest, files, indexHtml });
|
|
15516
|
+
return {
|
|
15517
|
+
dTag: manifest.dTag,
|
|
15518
|
+
aggregateHash: manifest.aggregateHash,
|
|
15519
|
+
files,
|
|
15520
|
+
indexHtml,
|
|
15521
|
+
manifest
|
|
15522
|
+
};
|
|
15523
|
+
}
|
|
15524
|
+
|
|
15525
|
+
// src/runtime-resolver.ts
|
|
15526
|
+
var PAJA_NAPPLET_MANIFEST_KIND = 35129;
|
|
15527
|
+
function decodePajaPointer(value) {
|
|
15528
|
+
const trimmed = value.trim();
|
|
15529
|
+
const decoded = decode(trimmed);
|
|
15530
|
+
if (decoded.type === "naddr") {
|
|
15531
|
+
return {
|
|
15532
|
+
type: "naddr",
|
|
15533
|
+
value: trimmed,
|
|
15534
|
+
identifier: decoded.data.identifier,
|
|
15535
|
+
pubkey: decoded.data.pubkey,
|
|
15536
|
+
kind: decoded.data.kind,
|
|
15537
|
+
relays: [...decoded.data.relays ?? []]
|
|
15538
|
+
};
|
|
15539
|
+
}
|
|
15540
|
+
if (decoded.type === "nevent") {
|
|
15541
|
+
return {
|
|
15542
|
+
type: "nevent",
|
|
15543
|
+
value: trimmed,
|
|
15544
|
+
id: decoded.data.id,
|
|
15545
|
+
...decoded.data.author ? { author: decoded.data.author } : {},
|
|
15546
|
+
...decoded.data.kind ? { kind: decoded.data.kind } : {},
|
|
15547
|
+
relays: [...decoded.data.relays ?? []]
|
|
15548
|
+
};
|
|
15549
|
+
}
|
|
15550
|
+
throw new Error(`Expected naddr or nevent pointer, got ${decoded.type}.`);
|
|
15551
|
+
}
|
|
15552
|
+
async function resolvePajaPointer(value, options = {}) {
|
|
15553
|
+
const pointer = decodePajaPointer(value);
|
|
15554
|
+
const relays = uniqueRelayUrls([...pointer.relays, ...options.relays ?? []]);
|
|
15555
|
+
if (relays.length === 0) {
|
|
15556
|
+
throw new Error("Pointer does not include relay hints; add a relay-bearing naddr or nevent.");
|
|
15557
|
+
}
|
|
15558
|
+
const pool = options.pool ?? new SimplePool();
|
|
15559
|
+
const ownsPool = options.pool === void 0;
|
|
15560
|
+
try {
|
|
15561
|
+
const event = await resolvePointerEvent(pointer, pool, relays, options.maxWaitMs ?? 5e3);
|
|
15562
|
+
const blossomServers = [...options.blossomServers ?? []];
|
|
15563
|
+
const resolved = await resolveNapplet({
|
|
15564
|
+
event,
|
|
15565
|
+
cache: await openNappletArtifactCache({ requireStorageEstimate: false }),
|
|
15566
|
+
fetchBlob: (sha256Hex, servers) => fetchBlob([...servers, ...blossomServers], sha256Hex, async (url) => {
|
|
15567
|
+
const response = await (options.fetcher ?? fetch)(url);
|
|
15568
|
+
if (!response.ok) throw new Error(`[paja-runtime] blob ${url}: ${response.status}`);
|
|
15569
|
+
return new Uint8Array(await response.arrayBuffer());
|
|
15570
|
+
})
|
|
15571
|
+
});
|
|
15572
|
+
return {
|
|
15573
|
+
pointer,
|
|
15574
|
+
event,
|
|
15575
|
+
relays,
|
|
15576
|
+
blossomServers,
|
|
15577
|
+
dTag: resolved.dTag,
|
|
15578
|
+
aggregateHash: resolved.aggregateHash,
|
|
15579
|
+
indexHtml: resolved.indexHtml,
|
|
15580
|
+
manifest: resolved.manifest
|
|
15581
|
+
};
|
|
15582
|
+
} finally {
|
|
15583
|
+
if (ownsPool) {
|
|
15584
|
+
pool.close?.(relays);
|
|
15585
|
+
pool.destroy?.();
|
|
15586
|
+
}
|
|
15587
|
+
}
|
|
15588
|
+
}
|
|
15589
|
+
function injectPajaRuntimeCsp(html, origins) {
|
|
15590
|
+
const value = origins.length > 0 ? `connect-src ${[...new Set(origins)].sort().join(" ")}` : "connect-src 'none'";
|
|
15591
|
+
const meta = `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute(value)}">`;
|
|
15592
|
+
if (/<head[^>]*>/i.test(html)) {
|
|
15593
|
+
return html.replace(/<head[^>]*>/i, (open) => `${open}${meta}`);
|
|
15594
|
+
}
|
|
15595
|
+
if (/<html[^>]*>/i.test(html)) {
|
|
15596
|
+
return html.replace(/<html[^>]*>/i, (open) => `${open}<head>${meta}</head>`);
|
|
15597
|
+
}
|
|
15598
|
+
return `${meta}${html}`;
|
|
15599
|
+
}
|
|
15600
|
+
async function resolvePointerEvent(pointer, pool, relays, maxWaitMs) {
|
|
15601
|
+
const filter = pointer.type === "naddr" ? addressableFilter(pointer) : eventFilter(pointer);
|
|
15602
|
+
const events = await pool.querySync([...relays], filter, {
|
|
15603
|
+
maxWait: maxWaitMs,
|
|
15604
|
+
label: "kehto-paja-runtime"
|
|
15605
|
+
});
|
|
15606
|
+
const event = events.filter((candidate) => matchesPointer(pointer, candidate)).sort((a, b) => b.created_at - a.created_at)[0];
|
|
15607
|
+
if (!event) {
|
|
15608
|
+
throw new Error(`No napplet manifest event found for ${pointer.type} pointer.`);
|
|
15609
|
+
}
|
|
15610
|
+
if (event.kind !== PAJA_NAPPLET_MANIFEST_KIND) {
|
|
15611
|
+
throw new Error(`Pointer resolved kind ${event.kind}; expected ${PAJA_NAPPLET_MANIFEST_KIND}.`);
|
|
15612
|
+
}
|
|
15613
|
+
return event;
|
|
15614
|
+
}
|
|
15615
|
+
function addressableFilter(pointer) {
|
|
15616
|
+
if (pointer.kind !== PAJA_NAPPLET_MANIFEST_KIND) {
|
|
15617
|
+
throw new Error(`naddr kind ${pointer.kind} is not a napplet manifest kind.`);
|
|
15618
|
+
}
|
|
15619
|
+
return {
|
|
15620
|
+
kinds: [PAJA_NAPPLET_MANIFEST_KIND],
|
|
15621
|
+
authors: [pointer.pubkey],
|
|
15622
|
+
"#d": [pointer.identifier],
|
|
15623
|
+
limit: 1
|
|
15624
|
+
};
|
|
15625
|
+
}
|
|
15626
|
+
function eventFilter(pointer) {
|
|
15627
|
+
return {
|
|
15628
|
+
ids: [pointer.id],
|
|
15629
|
+
...pointer.kind ? { kinds: [pointer.kind] } : {},
|
|
15630
|
+
...pointer.author ? { authors: [pointer.author] } : {},
|
|
15631
|
+
limit: 1
|
|
15632
|
+
};
|
|
15633
|
+
}
|
|
15634
|
+
function matchesPointer(pointer, event) {
|
|
15635
|
+
if (pointer.type === "nevent") {
|
|
15636
|
+
if (event.id !== pointer.id) return false;
|
|
15637
|
+
if (pointer.author && event.pubkey !== pointer.author) return false;
|
|
15638
|
+
if (pointer.kind && event.kind !== pointer.kind) return false;
|
|
15639
|
+
return true;
|
|
15640
|
+
}
|
|
15641
|
+
return event.kind === pointer.kind && event.pubkey === pointer.pubkey && event.tags.some((tag) => tag[0] === "d" && tag[1] === pointer.identifier);
|
|
15642
|
+
}
|
|
15643
|
+
function uniqueRelayUrls(values) {
|
|
15644
|
+
const out = [];
|
|
15645
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15646
|
+
for (const value of values) {
|
|
15647
|
+
const url = normalizeRelayUrl(value);
|
|
15648
|
+
if (!url || seen.has(url)) continue;
|
|
15649
|
+
seen.add(url);
|
|
15650
|
+
out.push(url);
|
|
15651
|
+
}
|
|
15652
|
+
return out;
|
|
15653
|
+
}
|
|
15654
|
+
function normalizeRelayUrl(value) {
|
|
15655
|
+
const raw = value.trim();
|
|
15656
|
+
if (!raw) return void 0;
|
|
15657
|
+
try {
|
|
15658
|
+
const url = new URL(raw);
|
|
15659
|
+
if (url.protocol !== "wss:" && url.protocol !== "ws:") return void 0;
|
|
15660
|
+
url.hash = "";
|
|
15661
|
+
url.search = "";
|
|
15662
|
+
return url.href.replace(/\/$/, "");
|
|
15663
|
+
} catch {
|
|
15664
|
+
return void 0;
|
|
15665
|
+
}
|
|
15666
|
+
}
|
|
15667
|
+
function escapeAttribute(value) {
|
|
15668
|
+
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
15669
|
+
}
|
|
15670
|
+
|
|
15671
|
+
// src/browser-host.ts
|
|
15672
|
+
var bridgeRef = null;
|
|
15673
|
+
function readConfig() {
|
|
15674
|
+
const script = document.getElementById("kehto-paja-config");
|
|
15675
|
+
if (!script?.textContent) {
|
|
15676
|
+
throw new Error("Missing Kehto Paja config.");
|
|
15677
|
+
}
|
|
15678
|
+
return JSON.parse(script.textContent);
|
|
15679
|
+
}
|
|
15680
|
+
async function readLatestConfig(fallback) {
|
|
15681
|
+
try {
|
|
15682
|
+
const response = await fetch(new URL("./__kehto/config.json", window.location.href), { cache: "no-store" });
|
|
15683
|
+
if (!response.ok) return fallback;
|
|
15684
|
+
return await response.json();
|
|
15685
|
+
} catch (error) {
|
|
15686
|
+
console.warn("[paja] config refresh failed; using embedded config", error);
|
|
15687
|
+
return fallback;
|
|
15688
|
+
}
|
|
15689
|
+
}
|
|
15690
|
+
function setTargetUrlDisplay(config, frame) {
|
|
15691
|
+
const label = getTargetLabel(config);
|
|
15692
|
+
const targetEl = document.querySelector(".target");
|
|
15693
|
+
if (targetEl) {
|
|
15694
|
+
targetEl.textContent = label;
|
|
15695
|
+
targetEl.setAttribute("title", label);
|
|
15696
|
+
}
|
|
15697
|
+
frame.dataset.targetUrl = label;
|
|
15698
|
+
}
|
|
15699
|
+
function getTargetLabel(config) {
|
|
15700
|
+
if (config.target.mode === "runtime-pointer") return config.target.pointer?.value ?? "runtime pointer";
|
|
15701
|
+
return config.target.url;
|
|
15702
|
+
}
|
|
15703
|
+
function readInitialPointerValue(config) {
|
|
15704
|
+
if (config.target.mode !== "runtime-pointer") return "";
|
|
15705
|
+
const params = new URLSearchParams(window.location.search);
|
|
15706
|
+
return params.get("naddr") ?? params.get("nevent") ?? params.get("pointer") ?? config.target.pointer?.value ?? "";
|
|
15707
|
+
}
|
|
15708
|
+
function connectOrigins(urls) {
|
|
15709
|
+
const out = /* @__PURE__ */ new Set();
|
|
15710
|
+
for (const value of urls) {
|
|
15711
|
+
try {
|
|
15712
|
+
const url = new URL(value);
|
|
15713
|
+
if (url.protocol === "wss:" || url.protocol === "ws:") {
|
|
15714
|
+
out.add(value.replace(/\/$/, ""));
|
|
15715
|
+
} else {
|
|
15716
|
+
out.add(url.origin);
|
|
15717
|
+
}
|
|
15718
|
+
} catch {
|
|
15719
|
+
}
|
|
15720
|
+
}
|
|
15721
|
+
return [...out];
|
|
15722
|
+
}
|
|
15723
|
+
function setStatus(state, status) {
|
|
15724
|
+
state.status = status;
|
|
15725
|
+
const statusEl = document.getElementById("lifecycle-status");
|
|
15726
|
+
if (statusEl) statusEl.textContent = status;
|
|
15727
|
+
}
|
|
15728
|
+
function setSimulationStatus(state) {
|
|
15729
|
+
const statusEl = document.getElementById("simulation-status");
|
|
15730
|
+
if (statusEl) statusEl.textContent = summarizePajaSimulation(state.simulation);
|
|
15731
|
+
const themeSelect = document.getElementById("simulation-theme");
|
|
15732
|
+
if (themeSelect instanceof HTMLSelectElement) themeSelect.value = state.simulation.theme.mode;
|
|
15733
|
+
renderPajaDevtools(state, { bridge: bridgeRef, devSignerPubkey: PAJA_DEV_SIGNER_PUBKEY });
|
|
15734
|
+
}
|
|
15735
|
+
function setPointerStatus(state, message) {
|
|
15736
|
+
state.pointerStatus = message;
|
|
15737
|
+
const statusEl = document.getElementById("runtime-pointer-status");
|
|
15738
|
+
if (statusEl) statusEl.textContent = message;
|
|
15739
|
+
}
|
|
15740
|
+
function getFrame() {
|
|
15741
|
+
const frame = document.getElementById("napplet-frame");
|
|
15742
|
+
if (!(frame instanceof HTMLIFrameElement)) {
|
|
15743
|
+
throw new Error("Missing Kehto Paja iframe.");
|
|
15744
|
+
}
|
|
15745
|
+
frame.sandbox.add("allow-scripts");
|
|
15746
|
+
frame.sandbox.remove("allow-same-origin");
|
|
15747
|
+
return frame;
|
|
15748
|
+
}
|
|
15749
|
+
function confirmPajaRequest(state, request) {
|
|
15750
|
+
const event = request.event;
|
|
15751
|
+
const kind = typeof event.kind === "number" ? event.kind : "unknown";
|
|
15752
|
+
const content = typeof event.content === "string" && event.content.length > 0 ? `
|
|
15753
|
+
|
|
15754
|
+
${event.content.slice(0, 240)}` : "";
|
|
15755
|
+
const allowed = window.confirm(`Paja ${request.action} request
|
|
15756
|
+
kind: ${kind}${content}`);
|
|
15757
|
+
appendPajaMessageLog(state, "paja", {
|
|
15758
|
+
type: `paja.${request.action}.${allowed ? "confirmed" : "denied"}`,
|
|
15759
|
+
kind
|
|
15760
|
+
});
|
|
15761
|
+
return allowed;
|
|
15762
|
+
}
|
|
15763
|
+
function getTargetIdentity2(config, resolvedTarget) {
|
|
15764
|
+
return {
|
|
15765
|
+
pubkey: "",
|
|
15766
|
+
dTag: resolvedTarget?.dTag ?? config.window.dTag,
|
|
15767
|
+
aggregateHash: resolvedTarget?.aggregateHash ?? config.window.aggregateHash
|
|
15768
|
+
};
|
|
15769
|
+
}
|
|
15770
|
+
function registerFrameForGeneration(bridge, frame, config, generation, resolvedTarget) {
|
|
15771
|
+
const win = frame.contentWindow;
|
|
15772
|
+
if (!win) return null;
|
|
15773
|
+
const windowId = `${config.window.id}:${generation}`;
|
|
15774
|
+
const identity = getTargetIdentity2(config, resolvedTarget);
|
|
15775
|
+
originRegistry.register(win, windowId, {
|
|
15776
|
+
dTag: identity.dTag,
|
|
15777
|
+
aggregateHash: identity.aggregateHash
|
|
15778
|
+
});
|
|
15779
|
+
bridge.runtime.sessionRegistry.register(windowId, {
|
|
15780
|
+
...identity,
|
|
15781
|
+
windowId,
|
|
15782
|
+
origin: "null",
|
|
15783
|
+
type: "napplet",
|
|
15784
|
+
registeredAt: Date.now(),
|
|
15785
|
+
instanceId: `${windowId}:${Date.now()}`,
|
|
15786
|
+
provenance: "nip-5d"
|
|
15787
|
+
});
|
|
15788
|
+
return windowId;
|
|
15789
|
+
}
|
|
15790
|
+
function navigateFrame(bridge, frame, config, generation, resolvedTarget) {
|
|
15791
|
+
if (config.target.mode === "runtime-pointer") {
|
|
15792
|
+
if (!resolvedTarget) {
|
|
15793
|
+
frame.removeAttribute("src");
|
|
15794
|
+
frame.srcdoc = "<!doctype html><html><body></body></html>";
|
|
15795
|
+
return null;
|
|
15796
|
+
}
|
|
15797
|
+
const windowId2 = registerFrameForGeneration(bridge, frame, config, generation, resolvedTarget);
|
|
15798
|
+
frame.removeAttribute("src");
|
|
15799
|
+
frame.srcdoc = injectPajaRuntimeCsp(
|
|
15800
|
+
resolvedTarget.indexHtml,
|
|
15801
|
+
connectOrigins([...resolvedTarget.relays, ...resolvedTarget.blossomServers])
|
|
15802
|
+
);
|
|
15803
|
+
return windowId2;
|
|
15804
|
+
}
|
|
15805
|
+
const windowId = registerFrameForGeneration(bridge, frame, config, generation, resolvedTarget);
|
|
15806
|
+
frame.src = config.target.url;
|
|
15807
|
+
return windowId;
|
|
15808
|
+
}
|
|
15809
|
+
function createHostSignerController(getState) {
|
|
15810
|
+
return createPajaSignerController({
|
|
15811
|
+
confirmRequest: (request) => confirmPajaRequest(getState(), request),
|
|
15812
|
+
onChange(signer) {
|
|
15813
|
+
const state = getState();
|
|
15814
|
+
if (!state) return;
|
|
15815
|
+
state.signer = signer;
|
|
15816
|
+
appendPajaMessageLog(state, "paja", {
|
|
15817
|
+
type: `paja.signer.${signer.method}.${signer.status}`,
|
|
15818
|
+
pubkey: signer.pubkey,
|
|
15819
|
+
relay: signer.relay,
|
|
15820
|
+
error: signer.error
|
|
15821
|
+
});
|
|
15822
|
+
setSimulationStatus(state);
|
|
15823
|
+
if (signer.status === "connected") state.reload();
|
|
15824
|
+
}
|
|
15825
|
+
});
|
|
15826
|
+
}
|
|
13962
15827
|
function installPajaControlListeners(state) {
|
|
13963
15828
|
document.getElementById("reload-target")?.addEventListener("click", () => {
|
|
13964
15829
|
state.reload();
|
|
@@ -13979,80 +15844,72 @@ function installPajaControlListeners(state) {
|
|
|
13979
15844
|
document.getElementById("clear-log")?.addEventListener("click", () => {
|
|
13980
15845
|
state.clearLog();
|
|
13981
15846
|
});
|
|
15847
|
+
document.getElementById("runtime-pointer-form")?.addEventListener("submit", (event) => {
|
|
15848
|
+
event.preventDefault();
|
|
15849
|
+
const input = document.getElementById("runtime-pointer-input");
|
|
15850
|
+
if (!(input instanceof HTMLInputElement)) return;
|
|
15851
|
+
void state.loadPointer(input.value);
|
|
15852
|
+
});
|
|
13982
15853
|
}
|
|
13983
|
-
|
|
13984
|
-
const config =
|
|
13985
|
-
|
|
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 = {
|
|
15854
|
+
function createPajaBrowserState(context) {
|
|
15855
|
+
const { config, frame, bridge, adapter, signerController, capabilities, runtime } = context;
|
|
15856
|
+
return {
|
|
14003
15857
|
config,
|
|
14004
15858
|
capabilities,
|
|
14005
|
-
services,
|
|
14006
|
-
simulation: currentSimulation,
|
|
15859
|
+
services: Object.keys(adapter.services ?? {}).sort(),
|
|
15860
|
+
simulation: runtime.currentSimulation,
|
|
14007
15861
|
signer: signerController.getState(),
|
|
15862
|
+
resolvedTarget: null,
|
|
15863
|
+
pointerValue: readInitialPointerValue(config),
|
|
15864
|
+
pointerStatus: config.target.mode === "runtime-pointer" ? "idle" : "",
|
|
14008
15865
|
generation: 0,
|
|
14009
15866
|
status: "booting",
|
|
14010
15867
|
messageFilter: "",
|
|
14011
15868
|
messageLog: [],
|
|
14012
15869
|
reload() {
|
|
14013
|
-
if (currentWindowId) {
|
|
14014
|
-
bridge.runtime.destroyWindow(currentWindowId);
|
|
14015
|
-
bridge.runtime.sessionRegistry.unregister(currentWindowId);
|
|
14016
|
-
originRegistry.unregister(currentWindowId);
|
|
15870
|
+
if (runtime.currentWindowId) {
|
|
15871
|
+
bridge.runtime.destroyWindow(runtime.currentWindowId);
|
|
15872
|
+
bridge.runtime.sessionRegistry.unregister(runtime.currentWindowId);
|
|
15873
|
+
originRegistry.unregister(runtime.currentWindowId);
|
|
14017
15874
|
}
|
|
14018
15875
|
this.generation += 1;
|
|
14019
|
-
initReceivedGeneration = -1;
|
|
15876
|
+
runtime.initReceivedGeneration = -1;
|
|
14020
15877
|
setStatus(this, "reloading");
|
|
14021
|
-
currentWindowId = navigateFrame(bridge, frame, config, this.generation);
|
|
15878
|
+
runtime.currentWindowId = navigateFrame(bridge, frame, config, this.generation, this.resolvedTarget);
|
|
14022
15879
|
},
|
|
14023
15880
|
setThemeMode(mode) {
|
|
14024
|
-
currentSimulation = {
|
|
14025
|
-
...currentSimulation,
|
|
15881
|
+
runtime.currentSimulation = {
|
|
15882
|
+
...runtime.currentSimulation,
|
|
14026
15883
|
theme: {
|
|
14027
|
-
...currentSimulation.theme,
|
|
15884
|
+
...runtime.currentSimulation.theme,
|
|
14028
15885
|
mode
|
|
14029
15886
|
}
|
|
14030
15887
|
};
|
|
14031
|
-
this.simulation = currentSimulation;
|
|
14032
|
-
themeService?.publishTheme(createDevTheme(currentSimulation.theme.mode, currentSimulation.theme.values));
|
|
15888
|
+
this.simulation = runtime.currentSimulation;
|
|
15889
|
+
runtime.themeService?.publishTheme(createDevTheme(runtime.currentSimulation.theme.mode, runtime.currentSimulation.theme.values));
|
|
14033
15890
|
setSimulationStatus(this);
|
|
14034
15891
|
},
|
|
14035
15892
|
setDomainEnabled(domain, enabled) {
|
|
14036
|
-
currentSimulation = {
|
|
14037
|
-
...currentSimulation,
|
|
15893
|
+
runtime.currentSimulation = {
|
|
15894
|
+
...runtime.currentSimulation,
|
|
14038
15895
|
capabilities: {
|
|
14039
15896
|
domains: {
|
|
14040
|
-
...currentSimulation.capabilities.domains,
|
|
15897
|
+
...runtime.currentSimulation.capabilities.domains,
|
|
14041
15898
|
[domain]: enabled
|
|
14042
15899
|
},
|
|
14043
15900
|
disabledDomains: PAJA_SIMULATION_DOMAINS.filter(
|
|
14044
|
-
(entry) => entry === domain ? !enabled : !currentSimulation.capabilities.domains[entry]
|
|
15901
|
+
(entry) => entry === domain ? !enabled : !runtime.currentSimulation.capabilities.domains[entry]
|
|
14045
15902
|
)
|
|
14046
15903
|
}
|
|
14047
15904
|
};
|
|
14048
|
-
this.simulation = currentSimulation;
|
|
14049
|
-
this.services = Object.keys(adapter.services ?? {}).filter((name) => currentSimulation.capabilities.domains[name] !== false).sort();
|
|
15905
|
+
this.simulation = runtime.currentSimulation;
|
|
15906
|
+
this.services = Object.keys(adapter.services ?? {}).filter((name) => runtime.currentSimulation.capabilities.domains[name] !== false).sort();
|
|
14050
15907
|
setSimulationStatus(this);
|
|
14051
15908
|
appendPajaMessageLog(this, "paja", { type: `paja.interface.${enabled ? "enabled" : "disabled"}`, domain });
|
|
14052
15909
|
this.reload();
|
|
14053
15910
|
},
|
|
14054
15911
|
setAclCapability(capability, enabled) {
|
|
14055
|
-
const identity = getTargetIdentity2(config);
|
|
15912
|
+
const identity = getTargetIdentity2(config, this.resolvedTarget);
|
|
14056
15913
|
if (enabled) bridge.runtime.aclState.grant(identity.pubkey, identity.dTag, identity.aggregateHash, capability);
|
|
14057
15914
|
else bridge.runtime.aclState.revoke(identity.pubkey, identity.dTag, identity.aggregateHash, capability);
|
|
14058
15915
|
bridge.runtime.aclState.persist();
|
|
@@ -14068,6 +15925,40 @@ async function installPajaHost() {
|
|
|
14068
15925
|
connectBunker(uri) {
|
|
14069
15926
|
return signerController.connectBunker(uri);
|
|
14070
15927
|
},
|
|
15928
|
+
async loadPointer(value) {
|
|
15929
|
+
if (config.target.mode !== "runtime-pointer") return;
|
|
15930
|
+
const pointer = value.trim();
|
|
15931
|
+
const input = document.getElementById("runtime-pointer-input");
|
|
15932
|
+
if (input instanceof HTMLInputElement) input.value = pointer;
|
|
15933
|
+
this.pointerValue = pointer;
|
|
15934
|
+
if (!pointer) {
|
|
15935
|
+
setPointerStatus(this, "idle");
|
|
15936
|
+
return;
|
|
15937
|
+
}
|
|
15938
|
+
setPointerStatus(this, "resolving");
|
|
15939
|
+
setStatus(this, "booting");
|
|
15940
|
+
appendPajaMessageLog(this, "paja", { type: "paja.pointer.resolve", pointer });
|
|
15941
|
+
try {
|
|
15942
|
+
this.resolvedTarget = await resolvePajaPointer(pointer, {
|
|
15943
|
+
relays: config.target.pointer?.relays ?? [],
|
|
15944
|
+
blossomServers: config.target.pointer?.blossomServers ?? [],
|
|
15945
|
+
maxWaitMs: config.target.pointer?.maxWaitMs
|
|
15946
|
+
});
|
|
15947
|
+
setPointerStatus(this, `${this.resolvedTarget.dTag}:${this.resolvedTarget.aggregateHash.slice(0, 12)}`);
|
|
15948
|
+
appendPajaMessageLog(this, "paja", {
|
|
15949
|
+
type: "paja.pointer.resolved",
|
|
15950
|
+
dTag: this.resolvedTarget.dTag,
|
|
15951
|
+
aggregateHash: this.resolvedTarget.aggregateHash
|
|
15952
|
+
});
|
|
15953
|
+
this.reload();
|
|
15954
|
+
} catch (error) {
|
|
15955
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15956
|
+
this.resolvedTarget = null;
|
|
15957
|
+
setPointerStatus(this, message);
|
|
15958
|
+
setStatus(this, "error");
|
|
15959
|
+
appendPajaMessageLog(this, "paja", { type: "paja.pointer.error", error: message });
|
|
15960
|
+
}
|
|
15961
|
+
},
|
|
14071
15962
|
clearLog() {
|
|
14072
15963
|
this.messageLog.length = 0;
|
|
14073
15964
|
renderPajaMessageLog(this);
|
|
@@ -14077,20 +15968,52 @@ async function installPajaHost() {
|
|
|
14077
15968
|
generation: this.generation,
|
|
14078
15969
|
status: this.status,
|
|
14079
15970
|
iframeCount: document.querySelectorAll("iframe").length,
|
|
14080
|
-
initSent: initReceivedGeneration === this.generation,
|
|
15971
|
+
initSent: runtime.initReceivedGeneration === this.generation,
|
|
14081
15972
|
services: this.services,
|
|
14082
|
-
simulation: currentSimulation,
|
|
15973
|
+
simulation: runtime.currentSimulation,
|
|
14083
15974
|
signer: this.signer,
|
|
15975
|
+
resolvedTarget: this.resolvedTarget,
|
|
15976
|
+
pointerStatus: this.pointerStatus,
|
|
14084
15977
|
messageLog: [...this.messageLog]
|
|
14085
15978
|
};
|
|
14086
15979
|
}
|
|
14087
15980
|
};
|
|
15981
|
+
}
|
|
15982
|
+
async function installPajaHost() {
|
|
15983
|
+
const config = await readLatestConfig(readConfig());
|
|
15984
|
+
const frame = getFrame();
|
|
15985
|
+
setTargetUrlDisplay(config, frame);
|
|
15986
|
+
const runtime = {
|
|
15987
|
+
currentSimulation: config.simulation,
|
|
15988
|
+
themeService: null,
|
|
15989
|
+
currentWindowId: null,
|
|
15990
|
+
initReceivedGeneration: -1
|
|
15991
|
+
};
|
|
15992
|
+
const getSimulation = () => runtime.currentSimulation;
|
|
15993
|
+
let stateRef = null;
|
|
15994
|
+
const signerController = createHostSignerController(() => stateRef);
|
|
15995
|
+
const adapter = createPajaAdapter(config, getSimulation, (theme) => {
|
|
15996
|
+
runtime.themeService = theme;
|
|
15997
|
+
}, (request) => confirmPajaRequest(stateRef, request), signerController, () => getTargetIdentity2(config, stateRef?.resolvedTarget));
|
|
15998
|
+
const bridge = createShellBridge(adapter);
|
|
15999
|
+
bridgeRef = bridge;
|
|
16000
|
+
installPajaOriginRegistryProxy(originRegistry, () => stateRef);
|
|
16001
|
+
const capabilities = buildShellCapabilities(adapter);
|
|
16002
|
+
const state = createPajaBrowserState({
|
|
16003
|
+
config,
|
|
16004
|
+
frame,
|
|
16005
|
+
bridge,
|
|
16006
|
+
adapter,
|
|
16007
|
+
signerController,
|
|
16008
|
+
capabilities,
|
|
16009
|
+
runtime
|
|
16010
|
+
});
|
|
14088
16011
|
stateRef = state;
|
|
14089
16012
|
window.__KEHTO_PAJA__ = state;
|
|
14090
16013
|
window.addEventListener("message", (event) => {
|
|
14091
16014
|
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);
|
|
16015
|
+
appendPajaMessageLog(state, "napplet->shell", event.data, runtime.currentWindowId ?? void 0);
|
|
16016
|
+
const proxiedSource = createPajaPostMessageProxy(event.source, state, runtime.currentWindowId ?? void 0);
|
|
14094
16017
|
const syntheticEvent = new Proxy(event, {
|
|
14095
16018
|
get(target, prop) {
|
|
14096
16019
|
if (prop === "source") return proxiedSource;
|
|
@@ -14101,13 +16024,13 @@ async function installPajaHost() {
|
|
|
14101
16024
|
bridge.handleMessage(syntheticEvent);
|
|
14102
16025
|
const data = event.data;
|
|
14103
16026
|
if (data && typeof data === "object" && data.type === "shell.ready") {
|
|
14104
|
-
initReceivedGeneration = state.generation;
|
|
16027
|
+
runtime.initReceivedGeneration = state.generation;
|
|
14105
16028
|
setStatus(state, "ready");
|
|
14106
16029
|
}
|
|
14107
16030
|
});
|
|
14108
16031
|
frame.addEventListener("load", () => {
|
|
14109
16032
|
if (state.status === "booting" || state.status === "reloading") {
|
|
14110
|
-
registerFrameForGeneration(bridge, frame, config, state.generation);
|
|
16033
|
+
runtime.currentWindowId = registerFrameForGeneration(bridge, frame, config, state.generation, state.resolvedTarget);
|
|
14111
16034
|
}
|
|
14112
16035
|
});
|
|
14113
16036
|
frame.addEventListener("error", () => {
|
|
@@ -14116,7 +16039,15 @@ async function installPajaHost() {
|
|
|
14116
16039
|
installPajaControlListeners(state);
|
|
14117
16040
|
setStatus(state, "booting");
|
|
14118
16041
|
setSimulationStatus(state);
|
|
14119
|
-
|
|
16042
|
+
setPointerStatus(state, state.pointerStatus);
|
|
16043
|
+
if (config.target.mode === "runtime-pointer") {
|
|
16044
|
+
const input = document.getElementById("runtime-pointer-input");
|
|
16045
|
+
if (input instanceof HTMLInputElement) input.value = state.pointerValue;
|
|
16046
|
+
if (state.pointerValue) void state.loadPointer(state.pointerValue);
|
|
16047
|
+
else runtime.currentWindowId = navigateFrame(bridge, frame, config, state.generation, state.resolvedTarget);
|
|
16048
|
+
} else {
|
|
16049
|
+
runtime.currentWindowId = navigateFrame(bridge, frame, config, state.generation, state.resolvedTarget);
|
|
16050
|
+
}
|
|
14120
16051
|
}
|
|
14121
16052
|
try {
|
|
14122
16053
|
void installPajaHost().catch((error) => {
|