@napplet/conformance-cli 0.2.15 → 0.2.17
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 +9 -20
- package/dist/host-bundle.global.js +157 -37
- package/dist/ui/assets/index-B_4r_ePr.js +113 -0
- package/dist/ui/index.html +1 -1
- package/package.json +3 -3
- package/dist/ui/assets/index-j_MRjiMC.js +0 -113
package/README.md
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# @napplet/conformance-cli
|
|
2
2
|
|
|
3
|
-
The headless `napplet-conformance` runner. It drives the
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
The headless `napplet-conformance` runner. It drives the [`@napplet/conformance`](../conformance) engine against a napplet in real headless Chromium (via Playwright), so a napplet can prove it conforms to the NAP protocol **before** publishing — locally and in CI.
|
|
4
|
+
|
|
5
|
+
The runner validates NIP-5D/NAP envelope and manifest carriers. It does not define payload schemas or matching behavior for an archetype convention. The reference shell returns the canonical structured intent result. Payloads remain untrusted.
|
|
6
|
+
|
|
7
|
+
Archetype metadata is one queryless convention per tag. This non-normative description follows [NAP-INC](https://github.com/napplet/naps/blob/master/naps/NAP-INC.md), [the archetype registry](https://github.com/napplet/naps/blob/master/ARCHETYPES.md), and [NAP-INTENT](https://github.com/napplet/naps/blob/master/naps/NAP-INTENT.md).
|
|
7
8
|
|
|
8
9
|
```bash
|
|
9
10
|
# Build your napplet first, then:
|
|
@@ -35,25 +36,13 @@ pnpm test:conformance # npm / yarn / bun all work — the bin is PM-agnostic
|
|
|
35
36
|
napplet-conformance --ui . --exec "vite build --watch"
|
|
36
37
|
```
|
|
37
38
|
|
|
38
|
-
`--ui` serves the standalone conformance web runtime (bundled with this package) plus
|
|
39
|
-
the napplet, opens your browser, and **re-runs conformance live every time the napplet
|
|
40
|
-
changes**. The optional `--exec` runs your build in watch mode so source edits rebuild
|
|
41
|
-
the served `./dist`; the CLI's file watcher then triggers a fresh run — edit, save, see
|
|
42
|
-
the verdict update. Useful flags: `--port <n>`, `--no-open`. (Headless mode is
|
|
43
|
-
unchanged — `--ui` is purely additive.)
|
|
39
|
+
`--ui` serves the standalone conformance web runtime (bundled with this package) plus the napplet, opens your browser, and **re-runs conformance live every time the napplet changes**. The optional `--exec` runs your build in watch mode so source edits rebuild the served `./dist`; the CLI's file watcher then triggers a fresh run — edit, save, see the verdict update. Useful flags: `--port <n>`, `--no-open`. (Headless mode is unchanged — `--ui` is purely additive.)
|
|
44
40
|
|
|
45
41
|
## How it works
|
|
46
42
|
|
|
47
|
-
1. Serves your built napplet on loopback alongside a host harness page and the
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
2. Launches headless Chromium, loads the napplet into a `sandbox="allow-scripts"`
|
|
51
|
-
iframe (no `allow-same-origin`), attaches a reference shell, and records every
|
|
52
|
-
envelope the napplet emits — plus a second no-capability pass to prove graceful
|
|
53
|
-
degradation.
|
|
54
|
-
3. Assembles the conformance context (manifest + static `window.nostr` scan), runs
|
|
55
|
-
the check catalog, prints the report, and exits non-zero on any error-severity
|
|
56
|
-
failure.
|
|
43
|
+
1. Serves your built napplet on loopback alongside a host harness page and the bundled engine. Every response sends `Access-Control-Allow-Origin: *` so the sandboxed napplet's module scripts load across its opaque origin.
|
|
44
|
+
2. Launches headless Chromium, loads the napplet into a `sandbox="allow-scripts"` iframe (no `allow-same-origin`), attaches a reference shell, and records every envelope the napplet emits — plus a second no-capability pass to prove graceful degradation.
|
|
45
|
+
3. Assembles the conformance context (manifest + static `window.nostr` scan), runs the check catalog, prints the report, and exits non-zero on any error-severity failure.
|
|
57
46
|
|
|
58
47
|
## Options
|
|
59
48
|
|
|
@@ -74,7 +74,7 @@ var NappletConformanceHostBundle = (() => {
|
|
|
74
74
|
"storage.remove.result": { dir: "in" },
|
|
75
75
|
"storage.keys.result": { dir: "in" },
|
|
76
76
|
// ── inc (inter-napplet communication) ─────────────────────────────────────
|
|
77
|
-
"inc.emit": { dir: "out", fields: { topic: "string" } },
|
|
77
|
+
"inc.emit": { dir: "out", fields: { topic: "string" }, forbiddenFields: ["sender"] },
|
|
78
78
|
"inc.subscribe": { dir: "out", fields: { ...ID, topic: "string" } },
|
|
79
79
|
"inc.unsubscribe": { dir: "out", fields: { topic: "string" } },
|
|
80
80
|
"inc.channel.open": { dir: "out", fields: { ...ID, target: "string" } },
|
|
@@ -83,8 +83,9 @@ var NappletConformanceHostBundle = (() => {
|
|
|
83
83
|
"inc.channel.list": { dir: "out", fields: { ...ID } },
|
|
84
84
|
"inc.channel.close": { dir: "out", fields: { channelId: "string" } },
|
|
85
85
|
"inc.subscribe.result": { dir: "in" },
|
|
86
|
-
"inc.event": { dir: "in" },
|
|
86
|
+
"inc.event": { dir: "in", fields: { topic: "string", sender: "string" } },
|
|
87
87
|
"inc.channel.open.result": { dir: "in" },
|
|
88
|
+
"inc.channel.opened": { dir: "in", fields: { channelId: "string", peer: "string" } },
|
|
88
89
|
"inc.channel.event": { dir: "in" },
|
|
89
90
|
"inc.channel.list.result": { dir: "in" },
|
|
90
91
|
"inc.channel.closed": { dir: "in" },
|
|
@@ -278,6 +279,33 @@ var NappletConformanceHostBundle = (() => {
|
|
|
278
279
|
if (kind === "present") return value !== void 0 && value !== null;
|
|
279
280
|
return kindOf(value) === kind;
|
|
280
281
|
}
|
|
282
|
+
function validateIntentInvokeRequest(request, errors) {
|
|
283
|
+
if (typeof request !== "object" || request === null || Array.isArray(request)) return;
|
|
284
|
+
const intent = request;
|
|
285
|
+
if (typeof intent.archetype !== "string") {
|
|
286
|
+
errors.push({
|
|
287
|
+
code: intent.archetype === void 0 ? "missing-field" : "wrong-type",
|
|
288
|
+
message: 'Intent request requires a string "archetype" field',
|
|
289
|
+
field: "request.archetype"
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
for (const field of ["action", "convention"]) {
|
|
293
|
+
if (intent[field] !== void 0 && typeof intent[field] !== "string") {
|
|
294
|
+
errors.push({
|
|
295
|
+
code: "wrong-type",
|
|
296
|
+
message: `Intent request field "${field}" must be a string`,
|
|
297
|
+
field: `request.${field}`
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if ("sender" in intent) {
|
|
302
|
+
errors.push({
|
|
303
|
+
code: "forbidden-field",
|
|
304
|
+
message: "Intent request does not define a caller-supplied sender field",
|
|
305
|
+
field: "request.sender"
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
281
309
|
function validateEnvelope(message) {
|
|
282
310
|
const errors = [];
|
|
283
311
|
if (typeof message !== "object" || message === null || Array.isArray(message)) {
|
|
@@ -301,15 +329,6 @@ var NappletConformanceHostBundle = (() => {
|
|
|
301
329
|
if (!spec) {
|
|
302
330
|
return { ok: false, type, domain, errors: [{ code: "unknown-type", message: `"${type}" is not a known ${domain} message type` }] };
|
|
303
331
|
}
|
|
304
|
-
if (spec.dir === "in") {
|
|
305
|
-
return {
|
|
306
|
-
ok: false,
|
|
307
|
-
type,
|
|
308
|
-
domain,
|
|
309
|
-
direction: "in",
|
|
310
|
-
errors: [{ code: "inbound-type-emitted", message: `"${type}" is a shell\u2192napplet message; a napplet must not emit it` }]
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
332
|
for (const [field, kind] of Object.entries(spec.fields ?? {})) {
|
|
314
333
|
if (!(field in record) || record[field] === void 0) {
|
|
315
334
|
errors.push({ code: "missing-field", message: `Required field "${field}" is missing`, field });
|
|
@@ -323,6 +342,30 @@ var NappletConformanceHostBundle = (() => {
|
|
|
323
342
|
});
|
|
324
343
|
}
|
|
325
344
|
}
|
|
345
|
+
if (spec.dir === "in") {
|
|
346
|
+
return {
|
|
347
|
+
ok: false,
|
|
348
|
+
type,
|
|
349
|
+
domain,
|
|
350
|
+
direction: "in",
|
|
351
|
+
errors: [
|
|
352
|
+
{ code: "inbound-type-emitted", message: `"${type}" is a shell\u2192napplet message; a napplet must not emit it` },
|
|
353
|
+
...errors
|
|
354
|
+
]
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
for (const field of spec.forbiddenFields ?? []) {
|
|
358
|
+
if (field in record) {
|
|
359
|
+
errors.push({
|
|
360
|
+
code: "forbidden-field",
|
|
361
|
+
message: `Field "${field}" must be runtime-derived and cannot be emitted by a napplet`,
|
|
362
|
+
field
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (type === "intent.invoke") {
|
|
367
|
+
validateIntentInvokeRequest(record.request, errors);
|
|
368
|
+
}
|
|
326
369
|
return { ok: errors.length === 0, type, domain, direction: "out", errors };
|
|
327
370
|
}
|
|
328
371
|
var NAPPLET_KIND_SNAPSHOT = 5129;
|
|
@@ -410,14 +453,17 @@ var NappletConformanceHostBundle = (() => {
|
|
|
410
453
|
ok: errors.length === 0,
|
|
411
454
|
kind: event.kind,
|
|
412
455
|
dTag,
|
|
413
|
-
nappletType: dTag,
|
|
414
456
|
requires,
|
|
415
457
|
errors,
|
|
416
458
|
warnings
|
|
417
459
|
};
|
|
418
460
|
}
|
|
419
461
|
var REFERENCE_PUBKEY = "f".repeat(64);
|
|
462
|
+
var REFERENCE_ENDPOINT = { dTag: "reference-source" };
|
|
420
463
|
var REFERENCE_BLOB_URL = "https://reference.invalid/blob";
|
|
464
|
+
var REFERENCE_HANDLER = "reference-handler";
|
|
465
|
+
var REFERENCE_SUBSCRIBER = "reference-subscriber";
|
|
466
|
+
var REFERENCE_CONVENTION = "napplet:note/open";
|
|
421
467
|
var ok = (v) => [v];
|
|
422
468
|
var none = () => [];
|
|
423
469
|
function dataUrlToBlob(url) {
|
|
@@ -553,27 +599,6 @@ var NappletConformanceHostBundle = (() => {
|
|
|
553
599
|
}),
|
|
554
600
|
"upload.upload": (e) => ok({ type: "upload.upload.result", id: e.id, result: { url: REFERENCE_BLOB_URL } }),
|
|
555
601
|
"upload.status": (e) => ok({ type: "upload.status.result", id: e.id, status: {} }),
|
|
556
|
-
// intent
|
|
557
|
-
"intent.invoke": (e) => ok({ type: "intent.invoke.result", id: e.id, result: { ok: true, archetype: "reference", action: "open", handled: true } }),
|
|
558
|
-
"intent.available": (e) => ok({
|
|
559
|
-
type: "intent.available.result",
|
|
560
|
-
id: e.id,
|
|
561
|
-
availability: {
|
|
562
|
-
archetype: e.archetype,
|
|
563
|
-
available: true,
|
|
564
|
-
candidates: [
|
|
565
|
-
{
|
|
566
|
-
dTag: "reference-handler",
|
|
567
|
-
actions: ["open"],
|
|
568
|
-
protocols: ["NAP-4"],
|
|
569
|
-
contracts: [{ action: "open", protocol: "NAP-4", eventKinds: [1] }],
|
|
570
|
-
isDefault: true
|
|
571
|
-
}
|
|
572
|
-
],
|
|
573
|
-
hasDefault: true
|
|
574
|
-
}
|
|
575
|
-
}),
|
|
576
|
-
"intent.handlers": (e) => ok({ type: "intent.handlers.result", id: e.id, handlers: [] }),
|
|
577
602
|
// ble
|
|
578
603
|
"ble.open": (e) => ok({
|
|
579
604
|
type: "ble.open.result",
|
|
@@ -628,20 +653,115 @@ var NappletConformanceHostBundle = (() => {
|
|
|
628
653
|
function createReferenceShell(options = {}) {
|
|
629
654
|
const now = options.now ?? (() => Date.now());
|
|
630
655
|
const records = [];
|
|
631
|
-
|
|
656
|
+
const targetQueues = /* @__PURE__ */ new Map();
|
|
657
|
+
function queueDelivery(target, delivery) {
|
|
658
|
+
const queue = targetQueues.get(target);
|
|
659
|
+
if (queue) {
|
|
660
|
+
queue.push(delivery);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
targetQueues.set(target, [delivery]);
|
|
664
|
+
}
|
|
665
|
+
function takeDeliveries(target) {
|
|
666
|
+
const queue = targetQueues.get(target) ?? [];
|
|
667
|
+
targetQueues.delete(target);
|
|
668
|
+
return queue;
|
|
669
|
+
}
|
|
670
|
+
function unavailableIntent(id, archetype, action, error) {
|
|
671
|
+
return ok({
|
|
672
|
+
type: "intent.invoke.result",
|
|
673
|
+
id,
|
|
674
|
+
result: { ok: false, archetype, action, handled: false, error }
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
function handleIntentInvoke(_endpoint, env) {
|
|
678
|
+
const request = env.request;
|
|
679
|
+
if (typeof request !== "object" || request === null || Array.isArray(request)) {
|
|
680
|
+
return unavailableIntent(env.id, "", "open", "invalid intent request");
|
|
681
|
+
}
|
|
682
|
+
const intent = request;
|
|
683
|
+
const archetype = typeof intent.archetype === "string" ? intent.archetype : "";
|
|
684
|
+
const action = typeof intent.action === "string" ? intent.action : "open";
|
|
685
|
+
if (!archetype) {
|
|
686
|
+
return unavailableIntent(env.id, archetype, action, "intent request requires an archetype");
|
|
687
|
+
}
|
|
688
|
+
if (archetype !== "note") {
|
|
689
|
+
return unavailableIntent(env.id, archetype, action, "no handler");
|
|
690
|
+
}
|
|
691
|
+
if (intent.convention !== void 0 && intent.convention !== REFERENCE_CONVENTION) {
|
|
692
|
+
return unavailableIntent(env.id, archetype, action, "unsupported convention");
|
|
693
|
+
}
|
|
694
|
+
return ok({
|
|
695
|
+
type: "intent.invoke.result",
|
|
696
|
+
id: env.id,
|
|
697
|
+
result: {
|
|
698
|
+
ok: true,
|
|
699
|
+
archetype,
|
|
700
|
+
action,
|
|
701
|
+
handled: true,
|
|
702
|
+
handler: REFERENCE_HANDLER,
|
|
703
|
+
windowId: "reference-window",
|
|
704
|
+
convention: typeof intent.convention === "string" ? intent.convention : REFERENCE_CONVENTION
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
function intentAvailability(archetype) {
|
|
709
|
+
if (archetype !== "note") {
|
|
710
|
+
return { archetype, available: false, candidates: [], hasDefault: false };
|
|
711
|
+
}
|
|
712
|
+
return {
|
|
713
|
+
archetype,
|
|
714
|
+
available: true,
|
|
715
|
+
candidates: [{
|
|
716
|
+
dTag: REFERENCE_HANDLER,
|
|
717
|
+
actions: ["open"],
|
|
718
|
+
conventions: [REFERENCE_CONVENTION],
|
|
719
|
+
isDefault: true
|
|
720
|
+
}],
|
|
721
|
+
hasDefault: true
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
function handleFrom(endpoint, envelope) {
|
|
632
725
|
const type = envelope && typeof envelope === "object" && typeof envelope.type === "string" ? envelope.type : void 0;
|
|
633
|
-
|
|
634
|
-
|
|
726
|
+
const verdict = validateEnvelope(envelope);
|
|
727
|
+
records.push({ envelope, verdict, timestamp: now() });
|
|
728
|
+
if (!type || !verdict.ok) return [];
|
|
729
|
+
const env = envelope;
|
|
730
|
+
if (type === "intent.invoke") return handleIntentInvoke(endpoint, env);
|
|
731
|
+
if (type === "intent.available") {
|
|
732
|
+
return ok({ type: "intent.available.result", id: env.id, availability: intentAvailability(env.archetype) });
|
|
733
|
+
}
|
|
734
|
+
if (type === "intent.handlers") {
|
|
735
|
+
return ok({ type: "intent.handlers.result", id: env.id, handlers: [intentAvailability("note")] });
|
|
736
|
+
}
|
|
737
|
+
if (type === "inc.emit") {
|
|
738
|
+
if (env.topic === REFERENCE_CONVENTION) {
|
|
739
|
+
const event = {
|
|
740
|
+
type: "inc.event",
|
|
741
|
+
topic: env.topic,
|
|
742
|
+
sender: endpoint.dTag
|
|
743
|
+
};
|
|
744
|
+
if ("payload" in env) event.payload = env.payload;
|
|
745
|
+
queueDelivery(REFERENCE_SUBSCRIBER, event);
|
|
746
|
+
}
|
|
747
|
+
return [];
|
|
748
|
+
}
|
|
635
749
|
const responder = RESPONDERS[type];
|
|
636
|
-
return responder ? responder(
|
|
750
|
+
return responder ? responder(env) : [];
|
|
751
|
+
}
|
|
752
|
+
function handle(envelope) {
|
|
753
|
+
return handleFrom(REFERENCE_ENDPOINT, envelope);
|
|
637
754
|
}
|
|
638
755
|
return {
|
|
639
756
|
get records() {
|
|
640
757
|
return records;
|
|
641
758
|
},
|
|
642
759
|
handle,
|
|
760
|
+
handleFrom,
|
|
761
|
+
takeDeliveries,
|
|
643
762
|
reset() {
|
|
644
763
|
records.length = 0;
|
|
764
|
+
targetQueues.clear();
|
|
645
765
|
}
|
|
646
766
|
};
|
|
647
767
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&n(o)}).observe(document,{childList:!0,subtree:!0});function r(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function n(i){if(i.ep)return;i.ep=!0;const s=r(i);fetch(i.href,s)}})();var st=["relay","identity","storage","inc","theme","keys","media","notify","config","resource","cvm","outbox","upload","intent","ble","webrtc","link","count","lists","serial","common","dm"],h={id:"string"},Rn={"relay.subscribe":{dir:"out",fields:{...h,subId:"string",filters:"array"}},"relay.close":{dir:"out",fields:{...h,subId:"string"}},"relay.publish":{dir:"out",fields:{...h,event:"object"}},"relay.publishEncrypted":{dir:"out",fields:{...h,event:"object",recipient:"string"}},"relay.query":{dir:"out",fields:{...h,filters:"array"}},"relay.event":{dir:"in"},"relay.eose":{dir:"in"},"relay.closed":{dir:"in"},"relay.publish.result":{dir:"in"},"relay.publishEncrypted.result":{dir:"in"},"relay.query.result":{dir:"in"},"identity.getPublicKey":{dir:"out",fields:{...h}},"identity.getRelays":{dir:"out",fields:{...h}},"identity.getProfile":{dir:"out",fields:{...h}},"identity.getFollows":{dir:"out",fields:{...h}},"identity.getList":{dir:"out",fields:{...h,listType:"string"}},"identity.getZaps":{dir:"out",fields:{...h}},"identity.getMutes":{dir:"out",fields:{...h}},"identity.getBlocked":{dir:"out",fields:{...h}},"identity.getBadges":{dir:"out",fields:{...h}},"identity.changed":{dir:"in"},"identity.getPublicKey.result":{dir:"in"},"identity.getRelays.result":{dir:"in"},"identity.getProfile.result":{dir:"in"},"identity.getFollows.result":{dir:"in"},"identity.getList.result":{dir:"in"},"identity.getZaps.result":{dir:"in"},"identity.getMutes.result":{dir:"in"},"identity.getBlocked.result":{dir:"in"},"identity.getBadges.result":{dir:"in"},"storage.get":{dir:"out",fields:{...h,key:"string"}},"storage.set":{dir:"out",fields:{...h,key:"string",value:"string"}},"storage.remove":{dir:"out",fields:{...h,key:"string"}},"storage.keys":{dir:"out",fields:{...h}},"storage.get.result":{dir:"in"},"storage.set.result":{dir:"in"},"storage.remove.result":{dir:"in"},"storage.keys.result":{dir:"in"},"inc.emit":{dir:"out",fields:{topic:"string"},forbiddenFields:["sender"]},"inc.subscribe":{dir:"out",fields:{...h,topic:"string"}},"inc.unsubscribe":{dir:"out",fields:{topic:"string"}},"inc.channel.open":{dir:"out",fields:{...h,target:"string"}},"inc.channel.emit":{dir:"out",fields:{channelId:"string"}},"inc.channel.broadcast":{dir:"out"},"inc.channel.list":{dir:"out",fields:{...h}},"inc.channel.close":{dir:"out",fields:{channelId:"string"}},"inc.subscribe.result":{dir:"in"},"inc.event":{dir:"in",fields:{topic:"string",sender:"string"}},"inc.channel.open.result":{dir:"in"},"inc.channel.opened":{dir:"in",fields:{channelId:"string",peer:"string"}},"inc.channel.event":{dir:"in"},"inc.channel.list.result":{dir:"in"},"inc.channel.closed":{dir:"in"},"theme.get":{dir:"out",fields:{...h}},"theme.get.result":{dir:"in"},"theme.changed":{dir:"in"},"keys.forward":{dir:"out",fields:{key:"string",code:"string",ctrl:"boolean",alt:"boolean",shift:"boolean",meta:"boolean"}},"keys.registerAction":{dir:"out",fields:{...h,action:"object"}},"keys.unregisterAction":{dir:"out",fields:{actionId:"string"}},"keys.registerAction.result":{dir:"in"},"keys.bindings":{dir:"in"},"keys.action":{dir:"in"},"media.session.create":{dir:"out",fields:{...h,owner:"object"}},"media.session.update":{dir:"out",fields:{sessionId:"string",metadata:"object"}},"media.session.destroy":{dir:"out",fields:{sessionId:"string"}},"media.state":{dir:"out",fields:{sessionId:"string",status:"string"}},"media.capabilities":{dir:"out",fields:{sessionId:"string",actions:"array"}},"media.session.create.result":{dir:"in"},"media.command":{dir:"in"},"media.controls":{dir:"in"},"notify.send":{dir:"out",fields:{...h,title:"string"}},"notify.dismiss":{dir:"out",fields:{notificationId:"string"}},"notify.badge":{dir:"out",fields:{count:"number"}},"notify.channel.register":{dir:"out",fields:{channelId:"string",label:"string"}},"notify.permission.request":{dir:"out",fields:{...h}},"notify.send.result":{dir:"in"},"notify.permission.result":{dir:"in"},"notify.action":{dir:"in"},"notify.clicked":{dir:"in"},"notify.dismissed":{dir:"in"},"notify.controls":{dir:"in"},"config.registerSchema":{dir:"out",fields:{...h,schema:"object"}},"config.get":{dir:"out",fields:{...h}},"config.subscribe":{dir:"out"},"config.unsubscribe":{dir:"out"},"config.openSettings":{dir:"out"},"config.registerSchema.result":{dir:"in"},"config.values":{dir:"in"},"config.schemaError":{dir:"in"},"resource.info":{dir:"out",fields:{...h}},"resource.bytes":{dir:"out",fields:{...h,url:"string"}},"resource.bytesMany":{dir:"out",fields:{...h,urls:"array"}},"resource.cancel":{dir:"out",fields:{...h}},"resource.info.result":{dir:"in"},"resource.info.error":{dir:"in"},"resource.bytes.result":{dir:"in"},"resource.bytes.error":{dir:"in"},"resource.bytesMany.result":{dir:"in"},"resource.bytesMany.error":{dir:"in"},"cvm.discover":{dir:"out",fields:{...h}},"cvm.request":{dir:"out",fields:{...h,server:"object",message:"object"}},"cvm.close":{dir:"out",fields:{...h,server:"object"}},"cvm.registry.list":{dir:"out",fields:{...h}},"cvm.registry.has":{dir:"out",fields:{...h,family:"string"}},"cvm.registry.describe":{dir:"out",fields:{...h,family:"string"}},"cvm.registry.call":{dir:"out",fields:{...h,family:"string",tool:"string"}},"cvm.discover.result":{dir:"in"},"cvm.request.result":{dir:"in"},"cvm.close.result":{dir:"in"},"cvm.event":{dir:"in"},"cvm.registry.list.result":{dir:"in"},"cvm.registry.has.result":{dir:"in"},"cvm.registry.describe.result":{dir:"in"},"cvm.registry.call.result":{dir:"in"},"outbox.getEvent":{dir:"out",fields:{...h,eventId:"string"}},"outbox.query":{dir:"out",fields:{...h,filters:"present"}},"outbox.subscribe":{dir:"out",fields:{...h,subId:"string",filters:"present"}},"outbox.close":{dir:"out",fields:{...h,subId:"string"}},"outbox.publish":{dir:"out",fields:{...h,event:"object"}},"outbox.resolveRelays":{dir:"out",fields:{...h,target:"present"}},"outbox.getEvent.result":{dir:"in"},"outbox.query.result":{dir:"in"},"outbox.event":{dir:"in"},"outbox.closed":{dir:"in"},"outbox.publish.result":{dir:"in"},"outbox.resolveRelays.result":{dir:"in"},"upload.info":{dir:"out",fields:{...h}},"upload.upload":{dir:"out",fields:{...h,request:"object"}},"upload.status":{dir:"out",fields:{...h,uploadId:"string"}},"upload.info.result":{dir:"in"},"upload.upload.result":{dir:"in"},"upload.status.result":{dir:"in"},"upload.status.changed":{dir:"in"},"intent.invoke":{dir:"out",fields:{...h,request:"object"}},"intent.available":{dir:"out",fields:{...h,archetype:"string"}},"intent.handlers":{dir:"out",fields:{...h}},"intent.invoke.result":{dir:"in"},"intent.available.result":{dir:"in"},"intent.handlers.result":{dir:"in"},"intent.changed":{dir:"in"},"ble.open":{dir:"out",fields:{...h,request:"object"}},"ble.services":{dir:"out",fields:{...h,sessionId:"string"}},"ble.read":{dir:"out",fields:{...h,sessionId:"string",target:"object"}},"ble.write":{dir:"out",fields:{...h,sessionId:"string",target:"object",data:"array"}},"ble.subscribe":{dir:"out",fields:{...h,sessionId:"string",target:"object"}},"ble.unsubscribe":{dir:"out",fields:{...h,sessionId:"string",target:"object"}},"ble.close":{dir:"out",fields:{...h,sessionId:"string"}},"ble.open.result":{dir:"in"},"ble.services.result":{dir:"in"},"ble.read.result":{dir:"in"},"ble.write.result":{dir:"in"},"ble.subscribe.result":{dir:"in"},"ble.unsubscribe.result":{dir:"in"},"ble.close.result":{dir:"in"},"ble.event":{dir:"in"},"common.encodeNip19":{dir:"out",fields:{...h,input:"object"}},"common.decodeNip19":{dir:"out",fields:{...h,value:"string"}},"common.getProfile":{dir:"out",fields:{...h,target:"string"}},"common.follows":{dir:"out",fields:{...h}},"common.follow":{dir:"out",fields:{...h,pubkeys:"array"}},"common.unfollow":{dir:"out",fields:{...h,pubkeys:"array"}},"common.react":{dir:"out",fields:{...h,targetEventId:"string",reaction:"string"}},"common.report":{dir:"out",fields:{...h,target:"object",reason:"string",text:"string"}},"common.encodeNip19.result":{dir:"in"},"common.decodeNip19.result":{dir:"in"},"common.getProfile.result":{dir:"in"},"common.follows.result":{dir:"in"},"common.follow.result":{dir:"in"},"common.unfollow.result":{dir:"in"},"common.react.result":{dir:"in"},"common.report.result":{dir:"in"},"webrtc.open":{dir:"out",fields:{...h,request:"object"}},"webrtc.send":{dir:"out",fields:{...h,sessionId:"string",payload:"present"}},"webrtc.close":{dir:"out",fields:{...h,sessionId:"string"}},"webrtc.open.result":{dir:"in"},"webrtc.send.result":{dir:"in"},"webrtc.close.result":{dir:"in"},"webrtc.event":{dir:"in"},"link.open":{dir:"out",fields:{...h,url:"string"}},"link.open.result":{dir:"in"},"count.query":{dir:"out",fields:{...h,filters:"array"}},"count.query.result":{dir:"in"},"lists.supported":{dir:"out",fields:{...h}},"lists.add":{dir:"out",fields:{...h,list:"object",items:"array"}},"lists.remove":{dir:"out",fields:{...h,list:"object",items:"array"}},"lists.supported.result":{dir:"in"},"lists.add.result":{dir:"in"},"lists.remove.result":{dir:"in"},"serial.open":{dir:"out",fields:{...h,request:"object"}},"serial.write":{dir:"out",fields:{...h,sessionId:"string",data:"array"}},"serial.close":{dir:"out",fields:{...h,sessionId:"string"}},"serial.open.result":{dir:"in"},"serial.write.result":{dir:"in"},"serial.close.result":{dir:"in"},"serial.event":{dir:"in"},"dm.status":{dir:"out",fields:{...h}},"dm.conversations":{dir:"out",fields:{...h}},"dm.messages":{dir:"out",fields:{...h,conversationId:"string"}},"dm.send":{dir:"out",fields:{...h,recipients:"array",content:"string"}},"dm.subscribe":{dir:"out",fields:{...h}},"dm.unsubscribe":{dir:"out",fields:{...h,subscriptionId:"string"}},"dm.status.result":{dir:"in"},"dm.conversations.result":{dir:"in"},"dm.messages.result":{dir:"in"},"dm.send.result":{dir:"in"},"dm.subscribe.result":{dir:"in"},"dm.unsubscribe.result":{dir:"in"},"dm.message":{dir:"in"}};function Ut(e){if(e===void 0)return"undefined";if(e===null)return"null";if(Array.isArray(e))return"array";const t=typeof e;return t==="string"||t==="number"||t==="boolean"?t:t==="object"?"object":"present"}function $n(e,t){return t==="present"?e!=null:Ut(e)===t}function In(e,t){if(typeof e!="object"||e===null||Array.isArray(e))return;const r=e;typeof r.archetype!="string"&&t.push({code:r.archetype===void 0?"missing-field":"wrong-type",message:'Intent request requires a string "archetype" field',field:"request.archetype"});for(const n of["action","convention"])r[n]!==void 0&&typeof r[n]!="string"&&t.push({code:"wrong-type",message:`Intent request field "${n}" must be a string`,field:`request.${n}`});"sender"in r&&t.push({code:"forbidden-field",message:"Intent request does not define a caller-supplied sender field",field:"request.sender"})}function Tn(e){const t=[];if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,errors:[{code:"not-an-object",message:"Envelope must be a non-null object"}]};const r=e,n=r.type;if(typeof n!="string")return{ok:!1,errors:[{code:"missing-type",message:"Envelope is missing a string `type` field"}]};const i=n.indexOf(".");if(i<=0)return{ok:!1,type:n,errors:[{code:"malformed-type",message:`Envelope type "${n}" is not in domain.action form`}]};const s=n.slice(0,i);if(!st.includes(s))return{ok:!1,type:n,domain:s,errors:[{code:"unknown-domain",message:`"${s}" is not a known NAP domain`}]};const c=Rn[n];if(!c)return{ok:!1,type:n,domain:s,errors:[{code:"unknown-type",message:`"${n}" is not a known ${s} message type`}]};for(const[a,l]of Object.entries(c.fields??{})){if(!(a in r)||r[a]===void 0){t.push({code:"missing-field",message:`Required field "${a}" is missing`,field:a});continue}$n(r[a],l)||t.push({code:"wrong-type",message:`Field "${a}" should be ${l} but is ${Ut(r[a])}`,field:a})}if(c.dir==="in")return{ok:!1,type:n,domain:s,direction:"in",errors:[{code:"inbound-type-emitted",message:`"${n}" is a shell→napplet message; a napplet must not emit it`},...t]};for(const a of c.forbiddenFields??[])a in r&&t.push({code:"forbidden-field",message:`Field "${a}" must be runtime-derived and cannot be emitted by a napplet`,field:a});return n==="intent.invoke"&&In(r.request,t),{ok:t.length===0,type:n,domain:s,direction:"out",errors:t}}var Ht=5129,jt=15129,ge=35129,ot=[Ht,jt,ge];function Dt(e,t){return e.tags.find(r=>r[0]===t)}function Bn(e){return ot.includes(e)}function An(e){return typeof e=="string"&&/^[0-9a-f]{64}$/i.test(e)}function Mt(e){return Dt(e,"d")?.[1]?.trim()||void 0}function On(e){return e.tags.filter(t=>t[0]==="requires").map(t=>t[1]?.trim()??"").filter(Boolean)}function Zt(e){return Mt(e)??Dt(e,"title")?.[1]??e.id}function at(e){const t=[],r=[];if(!e)return{ok:!1,requires:[],errors:[{code:"missing-manifest-event",message:"No NIP-5D manifest event was resolved"}],warnings:r};const n=Mt(e),i=On(e);Bn(e.kind)||t.push({code:"invalid-napplet-kind",message:`Manifest event kind ${e.kind} is not a NIP-5D napplet kind`}),e.kind===ge&&!n?t.push({code:"missing-d-tag",message:"Named napplet manifest kind 35129 must include a non-empty d tag"}):(e.kind===jt||e.kind===Ht)&&n&&t.push({code:"unexpected-d-tag",message:`Napplet manifest kind ${e.kind} must not include a d tag`});const s=e.tags.find(o=>o[0]==="path"&&o[1]==="/index.html");s?An(s[2])||t.push({code:"invalid-index-html-hash",message:"The /index.html path tag must carry a 64-character sha256 hash"}):t.push({code:"missing-index-html",message:"Napplet manifest must include a path tag for /index.html"});for(const o of i){if(o.startsWith("nap:")||o.startsWith("NAP-")){t.push({code:"invalid-required-nap",message:`requires tag "${o}" must be a bare NAP domain such as "relay"`});continue}st.includes(o)||t.push({code:"unknown-required-nap",message:`requires tag "${o}" is not a known NAP domain`})}return{ok:t.length===0,kind:e.kind,dTag:n,requires:i,errors:t,warnings:r}}var xe="f".repeat(64),Nn={dTag:"reference-source"},qn="https://reference.invalid/blob",mt="reference-handler",Ln="reference-subscriber",ke="napplet:note/open",b=e=>[e],L=()=>[];function yt(e){if(typeof e!="string"||!e.startsWith("data:"))return null;const t=e.indexOf(",");if(t<0)return{blob:new Blob([],{type:"text/plain"}),mime:"text/plain"};const r=e.slice(5,t),n=e.slice(t+1),i=r.split(";").filter(Boolean),s=i.includes("base64"),o=i.find(c=>c.includes("/"))??"text/plain";try{if(s){const c=globalThis.atob(n),a=Uint8Array.from(c,l=>l.charCodeAt(0));return{blob:new Blob([a],{type:o}),mime:o}}return{blob:new Blob([decodeURIComponent(n)],{type:o}),mime:o}}catch{return null}}var Pn={"relay.subscribe":e=>b({type:"relay.eose",subId:e.subId}),"relay.close":L,"relay.publish":e=>b({type:"relay.publish.result",id:e.id,ok:!0,event:e.event}),"relay.publishEncrypted":e=>b({type:"relay.publishEncrypted.result",id:e.id,ok:!0,event:e.event}),"relay.query":e=>b({type:"relay.query.result",id:e.id,events:[]}),"identity.getPublicKey":e=>b({type:"identity.getPublicKey.result",id:e.id,pubkey:xe}),"identity.getRelays":e=>b({type:"identity.getRelays.result",id:e.id,relays:{}}),"identity.getProfile":e=>b({type:"identity.getProfile.result",id:e.id,profile:null}),"identity.getFollows":e=>b({type:"identity.getFollows.result",id:e.id,pubkeys:[]}),"identity.getList":e=>b({type:"identity.getList.result",id:e.id,entries:[]}),"identity.getZaps":e=>b({type:"identity.getZaps.result",id:e.id,zaps:[]}),"identity.getMutes":e=>b({type:"identity.getMutes.result",id:e.id,pubkeys:[]}),"identity.getBlocked":e=>b({type:"identity.getBlocked.result",id:e.id,pubkeys:[]}),"identity.getBadges":e=>b({type:"identity.getBadges.result",id:e.id,badges:[]}),"storage.get":e=>b({type:"storage.get.result",id:e.id,value:null}),"storage.set":e=>b({type:"storage.set.result",id:e.id}),"storage.remove":e=>b({type:"storage.remove.result",id:e.id}),"storage.keys":e=>b({type:"storage.keys.result",id:e.id,keys:[]}),"inc.emit":L,"inc.subscribe":e=>b({type:"inc.subscribe.result",id:e.id}),"inc.unsubscribe":L,"inc.channel.open":e=>b({type:"inc.channel.open.result",id:e.id,channelId:`chan-${String(e.id)}`,peer:"reference-peer"}),"inc.channel.emit":L,"inc.channel.broadcast":L,"inc.channel.list":e=>b({type:"inc.channel.list.result",id:e.id,channels:[]}),"inc.channel.close":L,"theme.get":e=>b({type:"theme.get.result",id:e.id,theme:{colors:{},mode:"dark"}}),"keys.forward":L,"keys.registerAction":e=>b({type:"keys.registerAction.result",id:e.id,actionId:`action-${String(e.id)}`}),"keys.unregisterAction":L,"media.session.create":e=>b({type:"media.session.create.result",id:e.id,sessionId:`session-${String(e.id)}`,owner:e.owner}),"media.session.update":L,"media.session.destroy":L,"media.state":L,"media.capabilities":L,"notify.send":e=>b({type:"notify.send.result",id:e.id,notificationId:`notif-${String(e.id)}`}),"notify.dismiss":L,"notify.badge":L,"notify.channel.register":L,"notify.permission.request":e=>b({type:"notify.permission.result",id:e.id,granted:!0}),"config.registerSchema":e=>b({type:"config.registerSchema.result",id:e.id,ok:!0}),"config.get":e=>b({type:"config.values",id:e.id,values:{}}),"config.subscribe":()=>b({type:"config.values",values:{}}),"config.unsubscribe":L,"config.openSettings":L,"resource.bytes":e=>{const t=yt(e.url);return b(t?{type:"resource.bytes.result",id:e.id,blob:t.blob,mime:t.mime}:{type:"resource.bytes.result",id:e.id,blob:new Blob([]),mime:"application/octet-stream"})},"resource.bytesMany":e=>b({type:"resource.bytesMany.result",id:e.id,items:Array.isArray(e.urls)?e.urls.map(t=>{const r=yt(t);return{url:t,ok:!0,blob:r?.blob??new Blob([]),mime:r?.mime??"application/octet-stream"}}):[]}),"resource.info":e=>b({type:"resource.info.result",id:e.id,info:{schemes:[{scheme:"data",enabled:!0},{scheme:"https",enabled:!0}]}}),"resource.cancel":L,"cvm.discover":e=>b({type:"cvm.discover.result",id:e.id,servers:[]}),"cvm.request":e=>b({type:"cvm.request.result",id:e.id,message:{}}),"cvm.close":e=>b({type:"cvm.close.result",id:e.id}),"outbox.getEvent":e=>b({type:"outbox.getEvent.result",id:e.id}),"outbox.query":e=>b({type:"outbox.query.result",id:e.id,events:[]}),"outbox.subscribe":e=>b({type:"outbox.closed",subId:e.subId,reason:"reference shell complete"}),"outbox.close":L,"outbox.publish":e=>b({type:"outbox.publish.result",id:e.id,ok:!0}),"outbox.resolveRelays":e=>b({type:"outbox.resolveRelays.result",id:e.id,plan:{}}),"upload.info":e=>b({type:"upload.info.result",id:e.id,info:{rails:[{rail:"nip96",enabled:!0,returns:["https"]},{rail:"blossom",enabled:!0,returns:["https","blossom"]}]}}),"upload.upload":e=>b({type:"upload.upload.result",id:e.id,result:{url:qn}}),"upload.status":e=>b({type:"upload.status.result",id:e.id,status:{}}),"ble.open":e=>b({type:"ble.open.result",id:e.id,session:{id:"ble-reference",state:"open",device:{id:"reference-device",name:"Reference BLE"}}}),"ble.services":e=>b({type:"ble.services.result",id:e.id,services:[]}),"ble.read":e=>b({type:"ble.read.result",id:e.id,data:[]}),"ble.write":e=>b({type:"ble.write.result",id:e.id}),"ble.subscribe":e=>b({type:"ble.subscribe.result",id:e.id}),"ble.unsubscribe":e=>b({type:"ble.unsubscribe.result",id:e.id}),"ble.close":e=>b({type:"ble.close.result",id:e.id}),"common.encodeNip19":e=>b({type:"common.encodeNip19.result",id:e.id,ok:!0,value:"npub1reference",nip19Type:"npub"}),"common.decodeNip19":e=>b({type:"common.decodeNip19.result",id:e.id,ok:!0,nip19Type:"npub",hex:xe}),"common.getProfile":e=>b({type:"common.getProfile.result",id:e.id,ok:!0,pubkey:xe,profile:null}),"common.follows":e=>b({type:"common.follows.result",id:e.id,ok:!0,pubkeys:[]}),"common.follow":e=>b({type:"common.follow.result",id:e.id,ok:!0}),"common.unfollow":e=>b({type:"common.unfollow.result",id:e.id,ok:!0}),"common.react":e=>b({type:"common.react.result",id:e.id,ok:!0,eventId:"0".repeat(64)}),"common.report":e=>b({type:"common.report.result",id:e.id,ok:!0,eventId:"1".repeat(64)}),"webrtc.open":e=>b({type:"webrtc.open.result",id:e.id,session:{id:"webrtc-reference",scope:{type:"direct",pubkey:xe},channel:"default",state:"connecting"}}),"webrtc.send":e=>b({type:"webrtc.send.result",id:e.id}),"webrtc.close":e=>b({type:"webrtc.close.result",id:e.id}),"link.open":e=>b({type:"link.open.result",id:e.id,status:"opened"}),"count.query":e=>b({type:"count.query.result",id:e.id,ok:!0,count:0}),"lists.supported":e=>b({type:"lists.supported.result",id:e.id,lists:[]}),"lists.add":e=>b({type:"lists.add.result",id:e.id,ok:!0,added:0,skipped:0}),"lists.remove":e=>b({type:"lists.remove.result",id:e.id,ok:!0,removed:0,skipped:0}),"serial.open":e=>b({type:"serial.open.result",id:e.id,session:{id:`serial-${String(e.id)}`,state:"open"}}),"serial.write":e=>b({type:"serial.write.result",id:e.id}),"serial.close":e=>b({type:"serial.close.result",id:e.id})};function _n(e={}){const t=e.now??(()=>Date.now()),r=[],n=new Map;function i(d,u){const f=n.get(d);if(f){f.push(u);return}n.set(d,[u])}function s(d){const u=n.get(d)??[];return n.delete(d),u}function o(d,u,f,m){return b({type:"intent.invoke.result",id:d,result:{ok:!1,archetype:u,action:f,handled:!1,error:m}})}function c(d,u){const f=u.request;if(typeof f!="object"||f===null||Array.isArray(f))return o(u.id,"","open","invalid intent request");const m=f,w=typeof m.archetype=="string"?m.archetype:"",I=typeof m.action=="string"?m.action:"open";return w?w!=="note"?o(u.id,w,I,"no handler"):m.convention!==void 0&&m.convention!==ke?o(u.id,w,I,"unsupported convention"):b({type:"intent.invoke.result",id:u.id,result:{ok:!0,archetype:w,action:I,handled:!0,handler:mt,windowId:"reference-window",convention:typeof m.convention=="string"?m.convention:ke}}):o(u.id,w,I,"intent request requires an archetype")}function a(d){return d!=="note"?{archetype:d,available:!1,candidates:[],hasDefault:!1}:{archetype:d,available:!0,candidates:[{dTag:mt,actions:["open"],conventions:[ke],isDefault:!0}],hasDefault:!0}}function l(d,u){const f=u&&typeof u=="object"&&typeof u.type=="string"?u.type:void 0,m=Tn(u);if(r.push({envelope:u,verdict:m,timestamp:t()}),!f||!m.ok)return[];const w=u;if(f==="intent.invoke")return c(d,w);if(f==="intent.available")return b({type:"intent.available.result",id:w.id,availability:a(w.archetype)});if(f==="intent.handlers")return b({type:"intent.handlers.result",id:w.id,handlers:[a("note")]});if(f==="inc.emit"){if(w.topic===ke){const N={type:"inc.event",topic:w.topic,sender:d.dTag};"payload"in w&&(N.payload=w.payload),i(Ln,N)}return[]}const I=Pn[f];return I?I(w):[]}function p(d){return l(Nn,d)}return{get records(){return r},handle:p,handleFrom:l,takeDeliveries:s,reset(){r.length=0,n.clear()}}}function Cn(e){return{manifestHtml:e.manifestHtml,manifestEvent:e.manifestEvent??null,sandbox:e.sandbox??{allowScripts:!0,allowSameOrigin:!1},installedGlobal:e.boot.installedGlobal,bootError:e.boot.bootError,emitted:e.boot.emitted,forbiddenGlobals:e.forbiddenGlobals??[],degraded:e.boot.degraded,lifecycle:e.lifecycle??null}}var Vt="__nappletConformance.error";function wt(e){return new Promise(t=>setTimeout(t,e))}function Un(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function Hn(e){return`
|
|
2
|
+
(() => {
|
|
3
|
+
const domains = ${JSON.stringify(e)};
|
|
4
|
+
const napplet = {};
|
|
5
|
+
for (const domain of domains) napplet[domain] = {};
|
|
6
|
+
const pending = new Map();
|
|
7
|
+
let seq = 0;
|
|
8
|
+
const nextId = () => {
|
|
9
|
+
try {
|
|
10
|
+
if (window.crypto && typeof window.crypto.randomUUID === 'function') return window.crypto.randomUUID();
|
|
11
|
+
} catch {}
|
|
12
|
+
seq += 1;
|
|
13
|
+
return 'conformance-' + Date.now().toString(36) + '-' + seq.toString(36);
|
|
14
|
+
};
|
|
15
|
+
const request = (message, resultType, errorType) => new Promise((resolve, reject) => {
|
|
16
|
+
const id = message.id || nextId();
|
|
17
|
+
const timeout = window.setTimeout(() => {
|
|
18
|
+
pending.delete(id);
|
|
19
|
+
reject(new Error(message.type + ' timed out'));
|
|
20
|
+
}, 5000);
|
|
21
|
+
pending.set(id, { resolve, reject, resultType, errorType, timeout });
|
|
22
|
+
window.parent.postMessage({ ...message, id }, '*');
|
|
23
|
+
});
|
|
24
|
+
window.addEventListener('message', (event) => {
|
|
25
|
+
const msg = event.data;
|
|
26
|
+
if (!msg || typeof msg !== 'object' || typeof msg.id !== 'string') return;
|
|
27
|
+
const slot = pending.get(msg.id);
|
|
28
|
+
if (!slot) return;
|
|
29
|
+
if (msg.type !== slot.resultType && msg.type !== slot.errorType) return;
|
|
30
|
+
pending.delete(msg.id);
|
|
31
|
+
window.clearTimeout(slot.timeout);
|
|
32
|
+
if (msg.type === slot.errorType) {
|
|
33
|
+
slot.reject(new Error(msg.message ? msg.error + ': ' + msg.message : String(msg.error || 'request failed')));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
slot.resolve(msg);
|
|
37
|
+
});
|
|
38
|
+
if (napplet.resource) {
|
|
39
|
+
napplet.resource.info = () =>
|
|
40
|
+
request({ type: 'resource.info' }, 'resource.info.result', 'resource.info.error')
|
|
41
|
+
.then((msg) => msg.info);
|
|
42
|
+
napplet.resource.bytes = (url) =>
|
|
43
|
+
request({ type: 'resource.bytes', url: String(url) }, 'resource.bytes.result', 'resource.bytes.error')
|
|
44
|
+
.then((msg) => msg.blob);
|
|
45
|
+
napplet.resource.bytesMany = (urls) =>
|
|
46
|
+
request({ type: 'resource.bytesMany', urls: Array.from(urls || []) }, 'resource.bytesMany.result', 'resource.bytesMany.error')
|
|
47
|
+
.then((msg) => msg.items);
|
|
48
|
+
napplet.resource.bytesAsObjectURL = (url) => {
|
|
49
|
+
const handle = { url: '', revoke: () => {} };
|
|
50
|
+
let objectUrl = '';
|
|
51
|
+
let revoked = false;
|
|
52
|
+
const ready = napplet.resource.bytes(url).then((blob) => {
|
|
53
|
+
if (revoked) return;
|
|
54
|
+
objectUrl = URL.createObjectURL(blob);
|
|
55
|
+
handle.url = objectUrl;
|
|
56
|
+
return objectUrl;
|
|
57
|
+
});
|
|
58
|
+
handle.revoke = () => {
|
|
59
|
+
if (revoked) return;
|
|
60
|
+
revoked = true;
|
|
61
|
+
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
62
|
+
};
|
|
63
|
+
Object.defineProperty(handle, 'ready', { value: ready, enumerable: false });
|
|
64
|
+
return handle;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
window.napplet = napplet;
|
|
68
|
+
const report = (reason) => {
|
|
69
|
+
try {
|
|
70
|
+
window.parent.postMessage({ type: '${Vt}', reason: String(reason && reason.message || reason) }, '*');
|
|
71
|
+
} catch {}
|
|
72
|
+
};
|
|
73
|
+
window.addEventListener('error', (event) => report(event.error || event.message));
|
|
74
|
+
window.addEventListener('unhandledrejection', (event) => report(event.reason));
|
|
75
|
+
})();
|
|
76
|
+
`}function jn(e,t,r){const n=`<base href="${Un(t)}">`,i=`<script>${Hn(r)}<\/script>`,s=/<head(?:\s[^>]*)?>/i.exec(e);if(s){const o=s.index+s[0].length;return`${e.slice(0,o)}${n}${i}${e.slice(o)}`}return`${n}${i}${e}`}function Dn(e){if(!e.startsWith("data:"))return null;const t=e.indexOf(",");if(t<0)return"";const r=e.slice(0,t),n=e.slice(t+1);return r.endsWith(";base64")?atob(n):decodeURIComponent(n)}async function Mn(e){if(e==="about:blank")return"<!doctype html><html><head></head><body></body></html>";const t=Dn(e);if(t!==null)return t;const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch napplet HTML: ${r.status} ${r.statusText}`);return r.text()}async function vt(e,t,r,n){const i=_n(),s=r.createElement("iframe");s.setAttribute("sandbox",t.allowSameOrigin?"allow-scripts allow-same-origin":"allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.position="absolute",s.style.width="1px",s.style.height="1px",s.style.left="-9999px";let o=null;const c=p=>{if(p.source!==s.contentWindow)return;const d=p.data;if(d&&typeof d=="object"&&d.type===Vt){o=`napplet boot error: ${String(d.reason??"unknown error")}`;return}const u=i.handle(p.data),f=p.source;for(const m of u)f?.postMessage(m,"*")};let a=!1;const l=new Promise(p=>{s.addEventListener("load",()=>{a=!0,p()},{once:!0})});n.addEventListener("message",c),(r.body??r.documentElement).appendChild(s);try{const p=await Mn(t.url);s.srcdoc=jn(p,t.url,e)}catch(p){o=p instanceof Error?p.message:String(p)}if(!o){const p=Symbol("timeout");await Promise.race([l.then(()=>"loaded"),wt(t.readyTimeoutMs).then(()=>p)])===p||!a?o=`napplet did not boot (iframe did not load within ${t.readyTimeoutMs}ms; a conformant napplet must run under sandbox="allow-scripts" without allow-same-origin)`:await wt(t.settleMs)}n.removeEventListener("message",c);try{s.remove()}catch{}return{installedGlobal:o===null,bootError:o,emitted:[...i.records]}}async function Zn(e){const t=e.document??document,r=e.window??window,n={url:e.url,readyTimeoutMs:e.readyTimeoutMs??5e3,settleMs:e.settleMs,allowSameOrigin:e.allowSameOrigin??!1},i=await vt(st,n,t,r);let s=null;{const o=await vt([],n,t,r);s={bootError:o.bootError,emitted:o.emitted}}return{installedGlobal:i.installedGlobal,bootError:i.bootError,emitted:i.emitted,degraded:s}}var Vn=e=>({status:"pass",detail:e}),Wn=(e,t)=>({status:"fail",detail:e,diagnostics:t}),Fn=e=>({status:"skip",detail:e}),q={pass:Vn,fail:Wn,skip:Fn};function Kn(e,t){return at(e.manifestEvent).errors.filter(r=>t.includes(r.code))}function je(e,t,r){return{id:e,area:"manifest",severity:"error",title:t,run:n=>{if(!n.manifestEvent)return q.skip("No NIP-5D manifest event was resolved");const i=Kn(n,r);return i.length?q.fail(i[0].message,i):q.pass()}}}var Yn=[je("manifest/event-kind","Resolved event is a NIP-5D napplet manifest",["invalid-napplet-kind","missing-d-tag","unexpected-d-tag"]),je("manifest/index-html","Manifest declares a hashed /index.html",["missing-index-html","invalid-index-html-hash"]),je("manifest/requires","requires tags are bare known NAP domains",["invalid-required-nap","unknown-required-nap"]),{id:"boot/sandbox-allow-scripts",area:"boot",severity:"error",title:"Runs under allow-scripts without allow-same-origin",run:e=>e.sandbox.allowScripts?e.sandbox.allowSameOrigin?q.fail("Napplet relied on allow-same-origin, which a shell must not grant"):q.pass():q.fail("Napplet was not loaded with allow-scripts")},{id:"boot/installs-global",area:"boot",severity:"error",title:"Runs after runtime-injected window.napplet is installed",run:e=>e.installedGlobal?q.pass():q.fail("runtime did not inject window.napplet before load")},{id:"boot/no-boot-error",area:"boot",severity:"error",title:"Boots without an uncaught error",run:e=>e.bootError?q.fail(e.bootError):q.pass()},{id:"boot/no-forbidden-globals",area:"boot",severity:"error",title:"Does not access forbidden browser authority surfaces",run:e=>e.forbiddenGlobals.length?q.fail(`Accessed forbidden surface(s): ${e.forbiddenGlobals.join(", ")}`,e.forbiddenGlobals):q.pass()},{id:"wire/envelope-well-formed",area:"wire",severity:"error",title:"Every emitted envelope is well-formed",run:e=>{if(e.emitted.length===0)return q.skip("Napplet emitted no envelopes");const t=e.emitted.filter(n=>!n.verdict.ok);if(t.length===0)return q.pass(`${e.emitted.length} envelope(s) valid`);const r=t.map(n=>({envelope:n.envelope,errors:n.verdict.errors}));return q.fail(`${t.length}/${e.emitted.length} emitted envelope(s) invalid`,r)}},{id:"degrade/domain-absence",area:"degradation",severity:"error",title:"Does not crash when no NAP domains are injected",run:e=>e.degraded?e.degraded.bootError?q.fail(`Crashed with no injected domains: ${e.degraded.bootError}`):q.pass():q.skip("Host did not run the degraded (no-capabilities) pass")},{id:"lifecycle/clean-teardown",area:"lifecycle",severity:"warning",title:"Tears down listeners on unload",run:e=>e.lifecycle?e.lifecycle.listenerLeak?q.fail("Message listeners remained after unload"):q.pass():q.skip("Lifecycle not measured")}];function zn(e,t={}){const r=t.now??(()=>Date.now()),n=t.checks??Yn,i=r(),s=n.map(a=>{const l=a.run(e);return{id:a.id,area:a.area,severity:a.severity,title:a.title,status:l.status,detail:l.detail,diagnostics:l.diagnostics}}),o={total:s.length,passed:s.filter(a=>a.status==="pass").length,failed:s.filter(a=>a.status==="fail").length,skipped:s.filter(a=>a.status==="skip").length,errors:s.filter(a=>a.status==="fail"&&a.severity==="error").length,warnings:s.filter(a=>a.status==="fail"&&a.severity==="warning").length};return{napplet:e.manifestEvent?Zt(e.manifestEvent):void 0,startedAt:i,finishedAt:r(),checks:s,summary:o,ok:o.errors===0}}/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */function Gn(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function ct(e,t=""){if(!Number.isSafeInteger(e)||e<0){const r=t&&`"${t}" `;throw new Error(`${r}expected integer >= 0, got ${e}`)}}function D(e,t,r=""){const n=Gn(e),i=e?.length,s=t!==void 0;if(!n||s&&i!==t){const o=r&&`"${r}" `,c=s?` of length ${t}`:"",a=n?`length=${i}`:`type=${typeof e}`;throw new Error(o+"expected Uint8Array"+c+", got "+a)}return e}function Et(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Xn(e,t){D(e,void 0,"digestInto() output");const r=t.outputLen;if(e.length<r)throw new Error('"digestInto() output" expected to be of length >='+r)}function Ge(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function De(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function z(e,t){return e<<32-t|e>>>t}const Wt=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Jn=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function _(e){if(D(e),Wt)return e.toHex();let t="";for(let r=0;r<e.length;r++)t+=Jn[e[r]];return t}const J={_0:48,_9:57,A:65,F:70,a:97,f:102};function xt(e){if(e>=J._0&&e<=J._9)return e-J._0;if(e>=J.A&&e<=J.F)return e-(J.A-10);if(e>=J.a&&e<=J.f)return e-(J.a-10)}function X(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);if(Wt)return Uint8Array.fromHex(e);const t=e.length,r=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);const n=new Uint8Array(r);for(let i=0,s=0;i<r;i++,s+=2){const o=xt(e.charCodeAt(s)),c=xt(e.charCodeAt(s+1));if(o===void 0||c===void 0){const a=e[s]+e[s+1];throw new Error('hex string expected, got non-hex character "'+a+'" at index '+s)}n[i]=o*16+c}return n}function Be(...e){let t=0;for(let n=0;n<e.length;n++){const i=e[n];D(i),t+=i.length}const r=new Uint8Array(t);for(let n=0,i=0;n<e.length;n++){const s=e[n];r.set(s,i),i+=s.length}return r}function Qn(e,t={}){const r=(i,s)=>e(s).update(i).digest(),n=e(void 0);return r.outputLen=n.outputLen,r.blockLen=n.blockLen,r.create=i=>e(i),Object.assign(r,t),Object.freeze(r)}function Ft(e=32){const t=typeof globalThis=="object"?globalThis.crypto:null;if(typeof t?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");return t.getRandomValues(new Uint8Array(e))}const er=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */function Kt(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Yt(e,t){return Array.isArray(t)?t.length===0?!0:e?t.every(r=>typeof r=="string"):t.every(r=>Number.isSafeInteger(r)):!1}function tr(e){if(typeof e!="function")throw new Error("function expected");return!0}function me(e,t){if(typeof t!="string")throw new Error(`${e}: string expected`);return!0}function zt(e){if(!Number.isSafeInteger(e))throw new Error(`invalid integer: ${e}`)}function Xe(e){if(!Array.isArray(e))throw new Error("array expected")}function Gt(e,t){if(!Yt(!0,t))throw new Error(`${e}: array of strings expected`)}function Xt(e,t){if(!Yt(!1,t))throw new Error(`${e}: array of numbers expected`)}function nr(...e){const t=s=>s,r=(s,o)=>c=>s(o(c)),n=e.map(s=>s.encode).reduceRight(r,t),i=e.map(s=>s.decode).reduce(r,t);return{encode:n,decode:i}}function rr(e){const t=typeof e=="string"?e.split(""):e,r=t.length;Gt("alphabet",t);const n=new Map(t.map((i,s)=>[i,s]));return{encode:i=>(Xe(i),i.map(s=>{if(!Number.isSafeInteger(s)||s<0||s>=r)throw new Error(`alphabet.encode: digit index outside alphabet "${s}". Allowed: ${e}`);return t[s]})),decode:i=>(Xe(i),i.map(s=>{me("alphabet.decode",s);const o=n.get(s);if(o===void 0)throw new Error(`Unknown letter: "${s}". Allowed: ${e}`);return o}))}}function ir(e=""){return me("join",e),{encode:t=>(Gt("join.decode",t),t.join(e)),decode:t=>(me("join.decode",t),t.split(e))}}const Jt=(e,t)=>t===0?e:Jt(t,e%t),Ae=(e,t)=>e+(t-Jt(e,t)),Ie=(()=>{let e=[];for(let t=0;t<40;t++)e.push(2**t);return e})();function Je(e,t,r,n){if(Xe(e),t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(r<=0||r>32)throw new Error(`convertRadix2: wrong to=${r}`);if(Ae(t,r)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${r} carryBits=${Ae(t,r)}`);let i=0,s=0;const o=Ie[t],c=Ie[r]-1,a=[];for(const l of e){if(zt(l),l>=o)throw new Error(`convertRadix2: invalid data word=${l} from=${t}`);if(i=i<<t|l,s+t>32)throw new Error(`convertRadix2: carry overflow pos=${s} from=${t}`);for(s+=t;s>=r;s-=r)a.push((i>>s-r&c)>>>0);const p=Ie[s];if(p===void 0)throw new Error("invalid carry");i&=p-1}if(i=i<<r-s&c,!n&&s>=t)throw new Error("Excess padding");if(!n&&i>0)throw new Error(`Non-zero padding: ${i}`);return n&&s>0&&a.push(i>>>0),a}function sr(e,t=!1){if(zt(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(Ae(8,e)>32||Ae(e,8)>32)throw new Error("radix2: carry overflow");return{encode:r=>{if(!Kt(r))throw new Error("radix2.encode input should be Uint8Array");return Je(Array.from(r),8,e,!t)},decode:r=>(Xt("radix2.decode",r),Uint8Array.from(Je(r,e,8,t)))}}function kt(e){return tr(e),function(...t){try{return e.apply(null,t)}catch{}}}const Qe=nr(rr("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),ir("")),St=[996825010,642813549,513874426,1027748829,705979059];function fe(e){const t=e>>25;let r=(e&33554431)<<5;for(let n=0;n<St.length;n++)(t>>n&1)===1&&(r^=St[n]);return r}function Rt(e,t,r=1){const n=e.length;let i=1;for(let s=0;s<n;s++){const o=e.charCodeAt(s);if(o<33||o>126)throw new Error(`Invalid prefix (${e})`);i=fe(i)^o>>5}i=fe(i);for(let s=0;s<n;s++)i=fe(i)^e.charCodeAt(s)&31;for(let s of t)i=fe(i)^s;for(let s=0;s<6;s++)i=fe(i);return i^=r,Qe.encode(Je([i%Ie[30]],30,5,!1))}function or(e){const t=e==="bech32"?1:734539939,r=sr(5),n=r.decode,i=r.encode,s=kt(n);function o(d,u,f=90){me("bech32.encode prefix",d),Kt(u)&&(u=Array.from(u)),Xt("bech32.encode",u);const m=d.length;if(m===0)throw new TypeError(`Invalid prefix length ${m}`);const w=m+7+u.length;if(f!==!1&&w>f)throw new TypeError(`Length ${w} exceeds limit ${f}`);const I=d.toLowerCase(),N=Rt(I,u,t);return`${I}1${Qe.encode(u)}${N}`}function c(d,u=90){me("bech32.decode input",d);const f=d.length;if(f<8||u!==!1&&f>u)throw new TypeError(`invalid string length: ${f} (${d}). Expected (8..${u})`);const m=d.toLowerCase();if(d!==m&&d!==d.toUpperCase())throw new Error("String must be lowercase or uppercase");const w=m.lastIndexOf("1");if(w===0||w===-1)throw new Error('Letter "1" must be present between prefix and data only');const I=m.slice(0,w),N=m.slice(w+1);if(N.length<6)throw new Error("Data must be at least 6 characters long");const K=Qe.decode(N).slice(0,-6),Q=Rt(I,K,t);if(!N.endsWith(Q))throw new Error(`Invalid checksum in ${d}: expected "${Q}"`);return{prefix:I,words:K}}const a=kt(c);function l(d){const{prefix:u,words:f}=c(d,!1);return{prefix:u,words:f,bytes:n(f)}}function p(d,u){return o(d,i(u))}return{encode:o,decode:c,encodeFromBytes:p,decodeToBytes:l,decodeUnsafe:a,fromWords:n,fromWordsUnsafe:s,toWords:i}}const $t=or("bech32");var Se=new TextDecoder("utf-8");new TextEncoder;var ar=5e3;function cr(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),lr(e)}catch{return{type:"invalid",data:null}}}function lr(e){let{prefix:t,words:r}=$t.decode(e,ar),n=new Uint8Array($t.fromWords(r));switch(t){case"nprofile":{let i=Me(n);if(!i[0]?.[0])throw new Error("missing TLV 0 for nprofile");if(i[0][0].length!==32)throw new Error("TLV 0 should be 32 bytes");return{type:"nprofile",data:{pubkey:_(i[0][0]),relays:i[1]?i[1].map(s=>Se.decode(s)):[]}}}case"nevent":{let i=Me(n);if(!i[0]?.[0])throw new Error("missing TLV 0 for nevent");if(i[0][0].length!==32)throw new Error("TLV 0 should be 32 bytes");if(i[2]&&i[2][0].length!==32)throw new Error("TLV 2 should be 32 bytes");if(i[3]&&i[3][0].length!==4)throw new Error("TLV 3 should be 4 bytes");return{type:"nevent",data:{id:_(i[0][0]),relays:i[1]?i[1].map(s=>Se.decode(s)):[],author:i[2]?.[0]?_(i[2][0]):void 0,kind:i[3]?.[0]?parseInt(_(i[3][0]),16):void 0}}}case"naddr":{let i=Me(n);if(!i[0]?.[0])throw new Error("missing TLV 0 for naddr");if(!i[2]?.[0])throw new Error("missing TLV 2 for naddr");if(i[2][0].length!==32)throw new Error("TLV 2 should be 32 bytes");if(!i[3]?.[0])throw new Error("missing TLV 3 for naddr");if(i[3][0].length!==4)throw new Error("TLV 3 should be 4 bytes");return{type:"naddr",data:{identifier:Se.decode(i[0][0]),pubkey:_(i[2][0]),kind:parseInt(_(i[3][0]),16),relays:i[1]?i[1].map(s=>Se.decode(s)):[]}}}case"nsec":return{type:t,data:n};case"npub":case"note":return{type:t,data:_(n)};default:throw new Error(`unknown prefix ${t}`)}}function Me(e){let t={},r=e;for(;r.length>0;){let n=r[0],i=r[1],s=r.slice(2,2+i);if(r=r.slice(2+i),s.length<i)throw new Error(`not enough data to read on TLV ${n}`);t[n]=t[n]||[],t[n].push(s)}return t}function dr(e,t,r){return e&t^~e&r}function ur(e,t,r){return e&t^e&r^t&r}class fr{blockLen;outputLen;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(t,r,n,i){this.blockLen=t,this.outputLen=r,this.padOffset=n,this.isLE=i,this.buffer=new Uint8Array(t),this.view=De(this.buffer)}update(t){Et(this),D(t);const{view:r,buffer:n,blockLen:i}=this,s=t.length;for(let o=0;o<s;){const c=Math.min(i-this.pos,s-o);if(c===i){const a=De(t);for(;i<=s-o;o+=i)this.process(a,o);continue}n.set(t.subarray(o,o+c),this.pos),this.pos+=c,o+=c,this.pos===i&&(this.process(r,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){Et(this),Xn(t,this),this.finished=!0;const{buffer:r,view:n,blockLen:i,isLE:s}=this;let{pos:o}=this;r[o++]=128,Ge(this.buffer.subarray(o)),this.padOffset>i-o&&(this.process(n,0),o=0);for(let d=o;d<i;d++)r[d]=0;n.setBigUint64(i-8,BigInt(this.length*8),s),this.process(n,0);const c=De(t),a=this.outputLen;if(a%4)throw new Error("_sha2: outputLen must be aligned to 32bit");const l=a/4,p=this.get();if(l>p.length)throw new Error("_sha2: outputLen bigger than state");for(let d=0;d<l;d++)c.setUint32(4*d,p[d],s)}digest(){const{buffer:t,outputLen:r}=this;this.digestInto(t);const n=t.slice(0,r);return this.destroy(),n}_cloneInto(t){t||=new this.constructor,t.set(...this.get());const{blockLen:r,buffer:n,length:i,finished:s,destroyed:o,pos:c}=this;return t.destroyed=o,t.finished=s,t.length=i,t.pos=c,i%r&&t.buffer.set(n),t}clone(){return this._cloneInto()}}const ee=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),hr=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),te=new Uint32Array(64);class pr extends fr{constructor(t){super(64,t,8,!1)}get(){const{A:t,B:r,C:n,D:i,E:s,F:o,G:c,H:a}=this;return[t,r,n,i,s,o,c,a]}set(t,r,n,i,s,o,c,a){this.A=t|0,this.B=r|0,this.C=n|0,this.D=i|0,this.E=s|0,this.F=o|0,this.G=c|0,this.H=a|0}process(t,r){for(let d=0;d<16;d++,r+=4)te[d]=t.getUint32(r,!1);for(let d=16;d<64;d++){const u=te[d-15],f=te[d-2],m=z(u,7)^z(u,18)^u>>>3,w=z(f,17)^z(f,19)^f>>>10;te[d]=w+te[d-7]+m+te[d-16]|0}let{A:n,B:i,C:s,D:o,E:c,F:a,G:l,H:p}=this;for(let d=0;d<64;d++){const u=z(c,6)^z(c,11)^z(c,25),f=p+u+dr(c,a,l)+hr[d]+te[d]|0,w=(z(n,2)^z(n,13)^z(n,22))+ur(n,i,s)|0;p=l,l=a,a=c,c=o+f|0,o=s,s=i,i=n,n=f+w|0}n=n+this.A|0,i=i+this.B|0,s=s+this.C|0,o=o+this.D|0,c=c+this.E|0,a=a+this.F|0,l=l+this.G|0,p=p+this.H|0,this.set(n,i,s,o,c,a,l,p)}roundClean(){Ge(te)}destroy(){this.set(0,0,0,0,0,0,0,0),Ge(this.buffer)}}class gr extends pr{A=ee[0]|0;B=ee[1]|0;C=ee[2]|0;D=ee[3]|0;E=ee[4]|0;F=ee[5]|0;G=ee[6]|0;H=ee[7]|0;constructor(){super(32)}}const Oe=Qn(()=>new gr,er(1));/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const lt=BigInt(0),et=BigInt(1);function It(e,t=""){if(typeof e!="boolean"){const r=t&&`"${t}" `;throw new Error(r+"expected boolean, got type="+typeof e)}return e}function br(e){if(typeof e=="bigint"){if(!wr(e))throw new Error("positive bigint expected, got "+e)}else ct(e);return e}function Qt(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);return e===""?lt:BigInt("0x"+e)}function dt(e){return Qt(_(e))}function en(e){return Qt(_(mr(D(e)).reverse()))}function ut(e,t){ct(t),e=br(e);const r=X(e.toString(16).padStart(t*2,"0"));if(r.length!==t)throw new Error("number too large");return r}function tn(e,t){return ut(e,t).reverse()}function mr(e){return Uint8Array.from(e)}function yr(e){return Uint8Array.from(e,(t,r)=>{const n=t.charCodeAt(0);if(t.length!==1||n>127)throw new Error(`string contains non-ASCII character "${e[r]}" with code ${n} at position ${r}`);return n})}const wr=e=>typeof e=="bigint"&<<=e;function vr(e){let t;for(t=0;e>lt;e>>=et,t+=1);return t}const nn=e=>(et<<BigInt(e))-et;function rn(e,t={},r={}){if(!e||typeof e!="object")throw new Error("expected valid options object");function n(s,o,c){const a=e[s];if(c&&a===void 0)return;const l=typeof a;if(l!==o||a===null)throw new Error(`param "${s}" is invalid: expected ${o}, got ${l}`)}const i=(s,o)=>Object.entries(s).forEach(([c,a])=>n(c,a,o));i(t,!1),i(r,!0)}function Tt(e){const t=new WeakMap;return(r,...n)=>{const i=t.get(r);if(i!==void 0)return i;const s=e(r,...n);return t.set(r,s),s}}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const j=BigInt(0),H=BigInt(1),se=BigInt(2),sn=BigInt(3),on=BigInt(4),an=BigInt(5),Er=BigInt(7),cn=BigInt(8),xr=BigInt(9),ln=BigInt(16);function F(e,t){const r=e%t;return r>=j?r:t+r}function Z(e,t,r){let n=e;for(;t-- >j;)n*=n,n%=r;return n}function Bt(e,t){if(e===j)throw new Error("invert: expected non-zero number");if(t<=j)throw new Error("invert: expected positive modulus, got "+t);let r=F(e,t),n=t,i=j,s=H;for(;r!==j;){const c=n/r,a=n%r,l=i-s*c;n=r,r=a,i=s,s=l}if(n!==H)throw new Error("invert: does not exist");return F(i,t)}function ft(e,t,r){if(!e.eql(e.sqr(t),r))throw new Error("Cannot find square root")}function dn(e,t){const r=(e.ORDER+H)/on,n=e.pow(t,r);return ft(e,n,t),n}function kr(e,t){const r=(e.ORDER-an)/cn,n=e.mul(t,se),i=e.pow(n,r),s=e.mul(t,i),o=e.mul(e.mul(s,se),i),c=e.mul(s,e.sub(o,e.ONE));return ft(e,c,t),c}function Sr(e){const t=Pe(e),r=un(e),n=r(t,t.neg(t.ONE)),i=r(t,n),s=r(t,t.neg(n)),o=(e+Er)/ln;return(c,a)=>{let l=c.pow(a,o),p=c.mul(l,n);const d=c.mul(l,i),u=c.mul(l,s),f=c.eql(c.sqr(p),a),m=c.eql(c.sqr(d),a);l=c.cmov(l,p,f),p=c.cmov(u,d,m);const w=c.eql(c.sqr(p),a),I=c.cmov(l,p,w);return ft(c,I,a),I}}function un(e){if(e<sn)throw new Error("sqrt is not defined for small field");let t=e-H,r=0;for(;t%se===j;)t/=se,r++;let n=se;const i=Pe(e);for(;At(i,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(r===1)return dn;let s=i.pow(n,t);const o=(t+H)/se;return function(a,l){if(a.is0(l))return l;if(At(a,l)!==1)throw new Error("Cannot find square root");let p=r,d=a.mul(a.ONE,s),u=a.pow(l,t),f=a.pow(l,o);for(;!a.eql(u,a.ONE);){if(a.is0(u))return a.ZERO;let m=1,w=a.sqr(u);for(;!a.eql(w,a.ONE);)if(m++,w=a.sqr(w),m===p)throw new Error("Cannot find square root");const I=H<<BigInt(p-m-1),N=a.pow(d,I);p=m,d=a.sqr(N),u=a.mul(u,d),f=a.mul(f,N)}return f}}function Rr(e){return e%on===sn?dn:e%cn===an?kr:e%ln===xr?Sr(e):un(e)}const $r=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Ir(e){const t={ORDER:"bigint",BYTES:"number",BITS:"number"},r=$r.reduce((n,i)=>(n[i]="function",n),t);return rn(e,r),e}function Tr(e,t,r){if(r<j)throw new Error("invalid exponent, negatives unsupported");if(r===j)return e.ONE;if(r===H)return t;let n=e.ONE,i=t;for(;r>j;)r&H&&(n=e.mul(n,i)),i=e.sqr(i),r>>=H;return n}function fn(e,t,r=!1){const n=new Array(t.length).fill(r?e.ZERO:void 0),i=t.reduce((o,c,a)=>e.is0(c)?o:(n[a]=o,e.mul(o,c)),e.ONE),s=e.inv(i);return t.reduceRight((o,c,a)=>e.is0(c)?o:(n[a]=e.mul(o,n[a]),e.mul(o,c)),s),n}function At(e,t){const r=(e.ORDER-H)/se,n=e.pow(t,r),i=e.eql(n,e.ONE),s=e.eql(n,e.ZERO),o=e.eql(n,e.neg(e.ONE));if(!i&&!s&&!o)throw new Error("invalid Legendre symbol result");return i?1:s?0:-1}function Br(e,t){t!==void 0&&ct(t);const r=t!==void 0?t:e.toString(2).length,n=Math.ceil(r/8);return{nBitLength:r,nByteLength:n}}class Ar{ORDER;BITS;BYTES;isLE;ZERO=j;ONE=H;_lengths;_sqrt;_mod;constructor(t,r={}){if(t<=j)throw new Error("invalid field: expected ORDER > 0, got "+t);let n;this.isLE=!1,r!=null&&typeof r=="object"&&(typeof r.BITS=="number"&&(n=r.BITS),typeof r.sqrt=="function"&&(this.sqrt=r.sqrt),typeof r.isLE=="boolean"&&(this.isLE=r.isLE),r.allowedLengths&&(this._lengths=r.allowedLengths?.slice()),typeof r.modFromBytes=="boolean"&&(this._mod=r.modFromBytes));const{nBitLength:i,nByteLength:s}=Br(t,n);if(s>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=t,this.BITS=i,this.BYTES=s,this._sqrt=void 0,Object.preventExtensions(this)}create(t){return F(t,this.ORDER)}isValid(t){if(typeof t!="bigint")throw new Error("invalid field element: expected bigint, got "+typeof t);return j<=t&&t<this.ORDER}is0(t){return t===j}isValidNot0(t){return!this.is0(t)&&this.isValid(t)}isOdd(t){return(t&H)===H}neg(t){return F(-t,this.ORDER)}eql(t,r){return t===r}sqr(t){return F(t*t,this.ORDER)}add(t,r){return F(t+r,this.ORDER)}sub(t,r){return F(t-r,this.ORDER)}mul(t,r){return F(t*r,this.ORDER)}pow(t,r){return Tr(this,t,r)}div(t,r){return F(t*Bt(r,this.ORDER),this.ORDER)}sqrN(t){return t*t}addN(t,r){return t+r}subN(t,r){return t-r}mulN(t,r){return t*r}inv(t){return Bt(t,this.ORDER)}sqrt(t){return this._sqrt||(this._sqrt=Rr(this.ORDER)),this._sqrt(this,t)}toBytes(t){return this.isLE?tn(t,this.BYTES):ut(t,this.BYTES)}fromBytes(t,r=!1){D(t);const{_lengths:n,BYTES:i,isLE:s,ORDER:o,_mod:c}=this;if(n){if(!n.includes(t.length)||t.length>i)throw new Error("Field.fromBytes: expected "+n+" bytes, got "+t.length);const l=new Uint8Array(i);l.set(t,s?0:l.length-t.length),t=l}if(t.length!==i)throw new Error("Field.fromBytes: expected "+i+" bytes, got "+t.length);let a=s?en(t):dt(t);if(c&&(a=F(a,o)),!r&&!this.isValid(a))throw new Error("invalid field element: outside of range 0..ORDER");return a}invertBatch(t){return fn(this,t)}cmov(t,r,n){return n?r:t}}function Pe(e,t={}){return new Ar(e,t)}function hn(e){if(typeof e!="bigint")throw new Error("field order must be bigint");const t=e.toString(2).length;return Math.ceil(t/8)}function Or(e){const t=hn(e);return t+Math.ceil(t/2)}function Nr(e,t,r=!1){D(e);const n=e.length,i=hn(t),s=Or(t);if(n<16||n<s||n>1024)throw new Error("expected "+s+"-1024 bytes of input, got "+n);const o=r?en(e):dt(e),c=F(o,t-H)+H;return r?tn(c,i):ut(c,i)}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const le=BigInt(0),oe=BigInt(1);function Ne(e,t){const r=t.negate();return e?r:t}function Ot(e,t){const r=fn(e.Fp,t.map(n=>n.Z));return t.map((n,i)=>e.fromAffine(n.toAffine(r[i])))}function pn(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw new Error("invalid window size, expected [1.."+t+"], got W="+e)}function Ze(e,t){pn(e,t);const r=Math.ceil(t/e)+1,n=2**(e-1),i=2**e,s=nn(e),o=BigInt(e);return{windows:r,windowSize:n,mask:s,maxNumber:i,shiftBy:o}}function Nt(e,t,r){const{windowSize:n,mask:i,maxNumber:s,shiftBy:o}=r;let c=Number(e&i),a=e>>o;c>n&&(c-=s,a+=oe);const l=t*n,p=l+Math.abs(c)-1,d=c===0,u=c<0,f=t%2!==0;return{nextN:a,offset:p,isZero:d,isNeg:u,isNegF:f,offsetF:l}}const Ve=new WeakMap,gn=new WeakMap;function We(e){return gn.get(e)||1}function qt(e){if(e!==le)throw new Error("invalid wNAF")}class qr{BASE;ZERO;Fn;bits;constructor(t,r){this.BASE=t.BASE,this.ZERO=t.ZERO,this.Fn=t.Fn,this.bits=r}_unsafeLadder(t,r,n=this.ZERO){let i=t;for(;r>le;)r&oe&&(n=n.add(i)),i=i.double(),r>>=oe;return n}precomputeWindow(t,r){const{windows:n,windowSize:i}=Ze(r,this.bits),s=[];let o=t,c=o;for(let a=0;a<n;a++){c=o,s.push(c);for(let l=1;l<i;l++)c=c.add(o),s.push(c);o=c.double()}return s}wNAF(t,r,n){if(!this.Fn.isValid(n))throw new Error("invalid scalar");let i=this.ZERO,s=this.BASE;const o=Ze(t,this.bits);for(let c=0;c<o.windows;c++){const{nextN:a,offset:l,isZero:p,isNeg:d,isNegF:u,offsetF:f}=Nt(n,c,o);n=a,p?s=s.add(Ne(u,r[f])):i=i.add(Ne(d,r[l]))}return qt(n),{p:i,f:s}}wNAFUnsafe(t,r,n,i=this.ZERO){const s=Ze(t,this.bits);for(let o=0;o<s.windows&&n!==le;o++){const{nextN:c,offset:a,isZero:l,isNeg:p}=Nt(n,o,s);if(n=c,!l){const d=r[a];i=i.add(p?d.negate():d)}}return qt(n),i}getPrecomputes(t,r,n){let i=Ve.get(r);return i||(i=this.precomputeWindow(r,t),t!==1&&(typeof n=="function"&&(i=n(i)),Ve.set(r,i))),i}cached(t,r,n){const i=We(t);return this.wNAF(i,this.getPrecomputes(i,t,n),r)}unsafe(t,r,n,i){const s=We(t);return s===1?this._unsafeLadder(t,r,i):this.wNAFUnsafe(s,this.getPrecomputes(s,t,n),r,i)}createCache(t,r){pn(r,this.bits),gn.set(t,r),Ve.delete(t)}hasCache(t){return We(t)!==1}}function Lr(e,t,r,n){let i=t,s=e.ZERO,o=e.ZERO;for(;r>le||n>le;)r&oe&&(s=s.add(i)),n&oe&&(o=o.add(i)),i=i.double(),r>>=oe,n>>=oe;return{p1:s,p2:o}}function Lt(e,t,r){if(t){if(t.ORDER!==e)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Ir(t),t}else return Pe(e,{isLE:r})}function Pr(e,t,r={},n){if(n===void 0&&(n=e==="edwards"),!t||typeof t!="object")throw new Error(`expected valid ${e} CURVE object`);for(const a of["p","n","h"]){const l=t[a];if(!(typeof l=="bigint"&&l>le))throw new Error(`CURVE.${a} must be positive bigint`)}const i=Lt(t.p,r.Fp,n),s=Lt(t.n,r.Fn,n),c=["Gx","Gy","a","b"];for(const a of c)if(!i.isValid(t[a]))throw new Error(`CURVE.${a} must be valid field element of CURVE.Fp`);return t=Object.freeze(Object.assign({},t)),{CURVE:t,Fp:i,Fn:s}}function _r(e,t){return function(n){const i=e(n);return{secretKey:i,publicKey:t(i)}}}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const Pt=(e,t)=>(e+(e>=0?t:-t)/Ur)/t;function Cr(e,t,r){const[[n,i],[s,o]]=t,c=Pt(o*e,r),a=Pt(-i*e,r);let l=e-c*n-a*s,p=-c*i-a*o;const d=l<he,u=p<he;d&&(l=-l),u&&(p=-p);const f=nn(Math.ceil(vr(r)/2))+Te;if(l<he||l>=f||p<he||p>=f)throw new Error("splitScalar (endomorphism): failed, k="+e);return{k1neg:d,k1:l,k2neg:u,k2:p}}const he=BigInt(0),Te=BigInt(1),Ur=BigInt(2),Re=BigInt(3),Hr=BigInt(4);function jr(e,t={}){const r=Pr("weierstrass",e,t),{Fp:n,Fn:i}=r;let s=r.CURVE;const{h:o,n:c}=s;rn(t,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object"});const{endo:a}=t;if(a&&(!n.is0(s.a)||typeof a.beta!="bigint"||!Array.isArray(a.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');const l=Mr(n,i);function p(){if(!n.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function d(T,g,y){const{x:E,y:x}=g.toAffine(),B=n.toBytes(E);if(It(y,"isCompressed"),y){p();const R=!n.isOdd(x);return Be(Dr(R),B)}else return Be(Uint8Array.of(4),B,n.toBytes(x))}function u(T){D(T,void 0,"Point");const{publicKey:g,publicKeyUncompressed:y}=l,E=T.length,x=T[0],B=T.subarray(1);if(E===g&&(x===2||x===3)){const R=n.fromBytes(B);if(!n.isValid(R))throw new Error("bad point: is not on curve, wrong x");const k=w(R);let v;try{v=n.sqrt(k)}catch(M){const P=M instanceof Error?": "+M.message:"";throw new Error("bad point: is not on curve, sqrt error"+P)}p();const S=n.isOdd(v);return(x&1)===1!==S&&(v=n.neg(v)),{x:R,y:v}}else if(E===y&&x===4){const R=n.BYTES,k=n.fromBytes(B.subarray(0,R)),v=n.fromBytes(B.subarray(R,R*2));if(!I(k,v))throw new Error("bad point: is not on curve");return{x:k,y:v}}else throw new Error(`bad point: got length ${E}, expected compressed=${g} or uncompressed=${y}`)}const f=t.toBytes||d,m=t.fromBytes||u;function w(T){const g=n.sqr(T),y=n.mul(g,T);return n.add(n.add(y,n.mul(T,s.a)),s.b)}function I(T,g){const y=n.sqr(g),E=w(T);return n.eql(y,E)}if(!I(s.Gx,s.Gy))throw new Error("bad curve params: generator point");const N=n.mul(n.pow(s.a,Re),Hr),K=n.mul(n.sqr(s.b),BigInt(27));if(n.is0(n.add(N,K)))throw new Error("bad curve params: a or b");function Q(T,g,y=!1){if(!n.isValid(g)||y&&n.is0(g))throw new Error(`bad point coordinate ${T}`);return g}function we(T){if(!(T instanceof O))throw new Error("Weierstrass Point expected")}function ve(T){if(!a||!a.basises)throw new Error("no endo");return Cr(T,a.basises,i.ORDER)}const Ee=Tt((T,g)=>{const{X:y,Y:E,Z:x}=T;if(n.eql(x,n.ONE))return{x:y,y:E};const B=T.is0();g==null&&(g=B?n.ONE:n.inv(x));const R=n.mul(y,g),k=n.mul(E,g),v=n.mul(x,g);if(B)return{x:n.ZERO,y:n.ZERO};if(!n.eql(v,n.ONE))throw new Error("invZ was invalid");return{x:R,y:k}}),Sn=Tt(T=>{if(T.is0()){if(t.allowInfinityPoint&&!n.is0(T.Y))return;throw new Error("bad point: ZERO")}const{x:g,y}=T.toAffine();if(!n.isValid(g)||!n.isValid(y))throw new Error("bad point: x or y not field elements");if(!I(g,y))throw new Error("bad point: equation left != right");if(!T.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});function gt(T,g,y,E,x){return y=new O(n.mul(y.X,T),y.Y,y.Z),g=Ne(E,g),y=Ne(x,y),g.add(y)}class O{static BASE=new O(s.Gx,s.Gy,n.ONE);static ZERO=new O(n.ZERO,n.ONE,n.ZERO);static Fp=n;static Fn=i;X;Y;Z;constructor(g,y,E){this.X=Q("x",g),this.Y=Q("y",y,!0),this.Z=Q("z",E),Object.freeze(this)}static CURVE(){return s}static fromAffine(g){const{x:y,y:E}=g||{};if(!g||!n.isValid(y)||!n.isValid(E))throw new Error("invalid affine point");if(g instanceof O)throw new Error("projective point not allowed");return n.is0(y)&&n.is0(E)?O.ZERO:new O(y,E,n.ONE)}static fromBytes(g){const y=O.fromAffine(m(D(g,void 0,"point")));return y.assertValidity(),y}static fromHex(g){return O.fromBytes(X(g))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(g=8,y=!0){return ue.createCache(this,g),y||this.multiply(Re),this}assertValidity(){Sn(this)}hasEvenY(){const{y:g}=this.toAffine();if(!n.isOdd)throw new Error("Field doesn't support isOdd");return!n.isOdd(g)}equals(g){we(g);const{X:y,Y:E,Z:x}=this,{X:B,Y:R,Z:k}=g,v=n.eql(n.mul(y,k),n.mul(B,x)),S=n.eql(n.mul(E,k),n.mul(R,x));return v&&S}negate(){return new O(this.X,n.neg(this.Y),this.Z)}double(){const{a:g,b:y}=s,E=n.mul(y,Re),{X:x,Y:B,Z:R}=this;let k=n.ZERO,v=n.ZERO,S=n.ZERO,$=n.mul(x,x),M=n.mul(B,B),P=n.mul(R,R),A=n.mul(x,B);return A=n.add(A,A),S=n.mul(x,R),S=n.add(S,S),k=n.mul(g,S),v=n.mul(E,P),v=n.add(k,v),k=n.sub(M,v),v=n.add(M,v),v=n.mul(k,v),k=n.mul(A,k),S=n.mul(E,S),P=n.mul(g,P),A=n.sub($,P),A=n.mul(g,A),A=n.add(A,S),S=n.add($,$),$=n.add(S,$),$=n.add($,P),$=n.mul($,A),v=n.add(v,$),P=n.mul(B,R),P=n.add(P,P),$=n.mul(P,A),k=n.sub(k,$),S=n.mul(P,M),S=n.add(S,S),S=n.add(S,S),new O(k,v,S)}add(g){we(g);const{X:y,Y:E,Z:x}=this,{X:B,Y:R,Z:k}=g;let v=n.ZERO,S=n.ZERO,$=n.ZERO;const M=s.a,P=n.mul(s.b,Re);let A=n.mul(y,B),V=n.mul(E,R),W=n.mul(x,k),ae=n.add(y,E),U=n.add(B,R);ae=n.mul(ae,U),U=n.add(A,V),ae=n.sub(ae,U),U=n.add(y,x);let Y=n.add(B,k);return U=n.mul(U,Y),Y=n.add(A,W),U=n.sub(U,Y),Y=n.add(E,x),v=n.add(R,k),Y=n.mul(Y,v),v=n.add(V,W),Y=n.sub(Y,v),$=n.mul(M,U),v=n.mul(P,W),$=n.add(v,$),v=n.sub(V,$),$=n.add(V,$),S=n.mul(v,$),V=n.add(A,A),V=n.add(V,A),W=n.mul(M,W),U=n.mul(P,U),V=n.add(V,W),W=n.sub(A,W),W=n.mul(M,W),U=n.add(U,W),A=n.mul(V,U),S=n.add(S,A),A=n.mul(Y,U),v=n.mul(ae,v),v=n.sub(v,A),A=n.mul(ae,V),$=n.mul(Y,$),$=n.add($,A),new O(v,S,$)}subtract(g){return this.add(g.negate())}is0(){return this.equals(O.ZERO)}multiply(g){const{endo:y}=t;if(!i.isValidNot0(g))throw new Error("invalid scalar: out of range");let E,x;const B=R=>ue.cached(this,R,k=>Ot(O,k));if(y){const{k1neg:R,k1:k,k2neg:v,k2:S}=ve(g),{p:$,f:M}=B(k),{p:P,f:A}=B(S);x=M.add(A),E=gt(y.beta,$,P,R,v)}else{const{p:R,f:k}=B(g);E=R,x=k}return Ot(O,[E,x])[0]}multiplyUnsafe(g){const{endo:y}=t,E=this;if(!i.isValid(g))throw new Error("invalid scalar: out of range");if(g===he||E.is0())return O.ZERO;if(g===Te)return E;if(ue.hasCache(this))return this.multiply(g);if(y){const{k1neg:x,k1:B,k2neg:R,k2:k}=ve(g),{p1:v,p2:S}=Lr(O,E,B,k);return gt(y.beta,v,S,x,R)}else return ue.unsafe(E,g)}toAffine(g){return Ee(this,g)}isTorsionFree(){const{isTorsionFree:g}=t;return o===Te?!0:g?g(O,this):ue.unsafe(this,c).is0()}clearCofactor(){const{clearCofactor:g}=t;return o===Te?this:g?g(O,this):this.multiplyUnsafe(o)}isSmallOrder(){return this.multiplyUnsafe(o).is0()}toBytes(g=!0){return It(g,"isCompressed"),this.assertValidity(),f(O,this,g)}toHex(g=!0){return _(this.toBytes(g))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}const bt=i.BITS,ue=new qr(O,t.endo?Math.ceil(bt/2):bt);return O.BASE.precompute(8),O}function Dr(e){return Uint8Array.of(e?2:3)}function Mr(e,t){return{secretKey:t.BYTES,publicKey:1+e.BYTES,publicKeyUncompressed:1+2*e.BYTES,publicKeyHasPrefix:!0,signature:2*t.BYTES}}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const _e={p:BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),n:BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),h:BigInt(1),a:BigInt(0),b:BigInt(7),Gx:BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),Gy:BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")},Zr={beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),basises:[[BigInt("0x3086d221a7d46bcde86c90e49284eb15"),-BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),BigInt("0x3086d221a7d46bcde86c90e49284eb15")]]},Vr=BigInt(0),tt=BigInt(2);function Wr(e){const t=_e.p,r=BigInt(3),n=BigInt(6),i=BigInt(11),s=BigInt(22),o=BigInt(23),c=BigInt(44),a=BigInt(88),l=e*e*e%t,p=l*l*e%t,d=Z(p,r,t)*p%t,u=Z(d,r,t)*p%t,f=Z(u,tt,t)*l%t,m=Z(f,i,t)*f%t,w=Z(m,s,t)*m%t,I=Z(w,c,t)*w%t,N=Z(I,a,t)*I%t,K=Z(N,c,t)*w%t,Q=Z(K,r,t)*p%t,we=Z(Q,o,t)*m%t,ve=Z(we,n,t)*l%t,Ee=Z(ve,tt,t);if(!qe.eql(qe.sqr(Ee),e))throw new Error("Cannot find square root");return Ee}const qe=Pe(_e.p,{sqrt:Wr}),de=jr(_e,{Fp:qe,endo:Zr}),_t={};function Le(e,...t){let r=_t[e];if(r===void 0){const n=Oe(yr(e));r=Be(n,n),_t[e]=r}return Oe(Be(r,...t))}const ht=e=>e.toBytes(!0).slice(1),pt=e=>e%tt===Vr;function nt(e){const{Fn:t,BASE:r}=de,n=t.fromBytes(e),i=r.multiply(n);return{scalar:pt(i.y)?n:t.neg(n),bytes:ht(i)}}function bn(e){const t=qe;if(!t.isValidNot0(e))throw new Error("invalid x: Fail if x ≥ p");const r=t.create(e*e),n=t.create(r*e+BigInt(7));let i=t.sqrt(n);pt(i)||(i=t.neg(i));const s=de.fromAffine({x:e,y:i});return s.assertValidity(),s}const be=dt;function mn(...e){return de.Fn.create(be(Le("BIP0340/challenge",...e)))}function Ct(e){return nt(e).bytes}function Fr(e,t,r=Ft(32)){const{Fn:n}=de,i=D(e,void 0,"message"),{bytes:s,scalar:o}=nt(t),c=D(r,32,"auxRand"),a=n.toBytes(o^be(Le("BIP0340/aux",c))),l=Le("BIP0340/nonce",a,s,i),{bytes:p,scalar:d}=nt(l),u=mn(p,s,i),f=new Uint8Array(64);if(f.set(p,0),f.set(n.toBytes(n.create(d+u*o)),32),!yn(f,i,s))throw new Error("sign: Invalid signature produced");return f}function yn(e,t,r){const{Fp:n,Fn:i,BASE:s}=de,o=D(e,64,"signature"),c=D(t,void 0,"message"),a=D(r,32,"publicKey");try{const l=bn(be(a)),p=be(o.subarray(0,32));if(!n.isValidNot0(p))return!1;const d=be(o.subarray(32,64));if(!i.isValidNot0(d))return!1;const u=mn(i.toBytes(p),ht(l),c),f=s.multiplyUnsafe(d).add(l.multiplyUnsafe(i.neg(u))),{x:m,y:w}=f.toAffine();return!(f.is0()||!pt(w)||m!==p)}catch{return!1}}const G=(()=>{const r=(n=Ft(48))=>Nr(n,_e.n);return{keygen:_r(r,Ct),getPublicKey:Ct,sign:Fr,verify:yn,Point:de,utils:{randomSecretKey:r,taggedHash:Le,lift_x:bn,pointToBytes:ht},lengths:{secretKey:32,publicKey:32,publicKeyHasPrefix:!1,signature:64,seed:48}}})();var ie=Symbol("verified"),Kr=e=>e instanceof Object;function Yr(e){if(!Kr(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!e.pubkey.match(/^[a-f0-9]{64}$/)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let r=e.tags[t];if(!Array.isArray(r))return!1;for(let n=0;n<r.length;n++)if(typeof r[n]!="string")return!1}return!0}new TextDecoder("utf-8");var zr=new TextEncoder;function pe(e){try{e.indexOf("://")===-1&&(e="wss://"+e);let t=new URL(e);return t.protocol==="http:"?t.protocol="ws:":t.protocol==="https:"&&(t.protocol="wss:"),t.pathname=t.pathname.replace(/\/+/g,"/"),t.pathname.endsWith("/")&&(t.pathname=t.pathname.slice(0,-1)),(t.port==="80"&&t.protocol==="ws:"||t.port==="443"&&t.protocol==="wss:")&&(t.port=""),t.searchParams.sort(),t.hash="",t.toString()}catch{throw new Error(`Invalid URL: ${e}`)}}var Gr=class{generateSecretKey(){return G.utils.randomSecretKey()}getPublicKey(t){return _(G.getPublicKey(t))}finalizeEvent(t,r){const n=t;return n.pubkey=_(G.getPublicKey(r)),n.id=Fe(n),n.sig=_(G.sign(X(Fe(n)),r)),n[ie]=!0,n}verifyEvent(t){if(typeof t[ie]=="boolean")return t[ie];try{const r=Fe(t);if(r!==t.id)return t[ie]=!1,!1;const n=G.verify(X(t.sig),X(r),X(t.pubkey));return t[ie]=n,n}catch{return t[ie]=!1,!1}}};function Xr(e){if(!Yr(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function Fe(e){let t=Oe(zr.encode(Xr(e)));return _(t)}var Ce=new Gr;Ce.generateSecretKey;Ce.getPublicKey;Ce.finalizeEvent;var Jr=Ce.verifyEvent,Qr=22242;function ei(e,t){if(e.ids&&e.ids.indexOf(t.id)===-1||e.kinds&&e.kinds.indexOf(t.kind)===-1||e.authors&&e.authors.indexOf(t.pubkey)===-1)return!1;for(let r in e)if(r[0]==="#"){let n=r.slice(1),i=e[`#${n}`];if(i&&!t.tags.find(([s,o])=>s===r.slice(1)&&i.indexOf(o)!==-1))return!1}return!(e.since&&t.created_at<e.since||e.until&&t.created_at>e.until)}function ti(e,t){for(let r=0;r<e.length;r++)if(ei(e[r],t))return!0;return!1}function ni(e,t){let r=t.length+3,n=e.indexOf(`"${t}":`)+r,i=e.slice(n).indexOf('"')+n+1;return e.slice(i,i+64)}function ri(e){let t=e.slice(0,22).indexOf('"EVENT"');if(t===-1)return null;let r=e.slice(t+7+1).indexOf('"');if(r===-1)return null;let n=t+7+1+r,i=e.slice(n+1,80).indexOf('"');if(i===-1)return null;let s=n+1+i;return e.slice(n+1,s)}function ii(e,t){return{kind:Qr,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}var wn=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},vn=class{url;_connected=!1;onclose=null;onnotice=e=>console.debug(`NOTICE from ${this.url}: ${e}`);onauth;baseEoseTimeout=4400;publishTimeout=4400;pingFrequency=29e3;pingTimeout=2e4;resubscribeBackoff=[1e4,1e4,1e4,2e4,2e4,3e4,6e4];openSubs=new Map;enablePing;enableReconnect;idleSince=Date.now();ongoingOperations=0;reconnectTimeoutHandle;pingIntervalHandle;reconnectAttempts=0;skipReconnection=!1;connectionPromise;openCountRequests=new Map;openEventPublishes=new Map;ws;challenge;authPromise;serial=0;verifyEvent;_WebSocket;constructor(e,t){this.url=pe(e),this.verifyEvent=t.verifyEvent,this._WebSocket=t.websocketImplementation||WebSocket,this.enablePing=t.enablePing,this.enableReconnect=t.enableReconnect||!1}static async connect(e,t){const r=new vn(e,t);return await r.connect(t),r}closeAllSubscriptions(e){for(let[t,r]of this.openSubs)r.close(e);this.openSubs.clear();for(let[t,r]of this.openEventPublishes)r.reject(new Error(e));this.openEventPublishes.clear();for(let[t,r]of this.openCountRequests)r.reject(new Error(e));this.openCountRequests.clear()}get connected(){return this._connected}async reconnect(){const e=this.resubscribeBackoff[Math.min(this.reconnectAttempts,this.resubscribeBackoff.length-1)];this.reconnectAttempts++,this.reconnectTimeoutHandle=setTimeout(async()=>{try{await this.connect()}catch{}},e)}handleHardClose(e){this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.enableReconnect&&!this.skipReconnection?this.reconnect():(this.onclose?.(),this.closeAllSubscriptions(e))}async connect(e){let t;return this.connectionPromise?this.connectionPromise:(this.challenge=void 0,this.authPromise=void 0,this.skipReconnection=!1,this.connectionPromise=new Promise((r,n)=>{e?.timeout&&(t=setTimeout(()=>{n("connection timed out"),this.connectionPromise=void 0,this.skipReconnection=!0,this.onclose?.(),this.handleHardClose("relay connection timed out")},e.timeout)),e?.abort&&(e.abort.onabort=n);try{this.ws=new this._WebSocket(this.url)}catch(i){clearTimeout(t),n(i);return}this.ws.onopen=()=>{this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),clearTimeout(t),this._connected=!0;const i=this.reconnectAttempts>0;this.reconnectAttempts=0;for(const s of this.openSubs.values()){if(s.eosed=!1,i)for(let o=0;o<s.filters.length;o++)s.lastEmitted&&(s.filters[o].since=s.lastEmitted+1);s.fire()}this.enablePing&&(this.pingIntervalHandle=setInterval(()=>this.pingpong(),this.pingFrequency)),r()},this.ws.onerror=()=>{clearTimeout(t),n("connection failed"),this.connectionPromise=void 0,this.skipReconnection=!0,this.onclose?.(),this.handleHardClose("relay connection failed")},this.ws.onclose=i=>{clearTimeout(t),n(i.message||"websocket closed"),this.handleHardClose("relay connection closed")},this.ws.onmessage=this._onmessage.bind(this)}),this.connectionPromise)}waitForPingPong(){return new Promise(e=>{this.ws.once("pong",()=>e(!0)),this.ws.ping()})}waitForDummyReq(){return new Promise((e,t)=>{if(!this.connectionPromise)return t(new Error(`no connection to ${this.url}, can't ping`));try{const r=this.subscribe([{ids:["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],limit:0}],{label:"<forced-ping>",oneose:()=>{e(!0),r.close()},onclose(){e(!0)},eoseTimeout:this.pingTimeout+1e3})}catch(r){t(r)}})}async pingpong(){this.ws?.readyState===1&&(await Promise.any([this.ws&&this.ws.ping&&this.ws.once?this.waitForPingPong():this.waitForDummyReq(),new Promise(t=>setTimeout(()=>t(!1),this.pingTimeout))])||this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close())}async send(e){if(!this.connectionPromise)throw new wn(e,this.url);this.connectionPromise.then(()=>{this.ws?.send(e)})}async auth(e){const t=this.challenge;if(!t)throw new Error("can't perform auth, no challenge was received");return this.authPromise?this.authPromise:(this.authPromise=new Promise(async(r,n)=>{try{let i=await e(ii(this.url,t)),s=setTimeout(()=>{let o=this.openEventPublishes.get(i.id);o&&(o.reject(new Error("auth timed out")),this.openEventPublishes.delete(i.id))},this.publishTimeout);this.openEventPublishes.set(i.id,{resolve:r,reject:n,timeout:s}),this.send('["AUTH",'+JSON.stringify(i)+"]")}catch(i){console.warn("subscribe auth function failed:",i)}}),this.authPromise)}async publish(e){this.idleSince=void 0,this.ongoingOperations++;const t=new Promise((r,n)=>{const i=setTimeout(()=>{const s=this.openEventPublishes.get(e.id);s&&(s.reject(new Error("publish timed out")),this.openEventPublishes.delete(e.id))},this.publishTimeout);this.openEventPublishes.set(e.id,{resolve:r,reject:n,timeout:i})});return this.send('["EVENT",'+JSON.stringify(e)+"]"),this.ongoingOperations--,this.ongoingOperations===0&&(this.idleSince=Date.now()),t}async count(e,t){this.serial++;const r=t?.id||"count:"+this.serial,n=new Promise((i,s)=>{this.openCountRequests.set(r,{resolve:i,reject:s})});return this.send('["COUNT","'+r+'",'+JSON.stringify(e).substring(1)),n}subscribe(e,t){t.label!=="<forced-ping>"&&(this.idleSince=void 0,this.ongoingOperations++);const r=this.prepareSubscription(e,t);return r.fire(),t.abort&&(t.abort.onabort=()=>r.close(String(t.abort.reason||"<aborted>"))),r}prepareSubscription(e,t){this.serial++;const r=t.id||(t.label?t.label+":":"sub:")+this.serial,n=new si(this,r,e,t);return this.openSubs.set(r,n),n}close(){this.skipReconnection=!0,this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this.closeAllSubscriptions("relay connection closed by us"),this._connected=!1,this.idleSince=void 0,this.onclose?.(),this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close()}_onmessage(e){const t=e.data;if(!t)return;const r=ri(t);if(r){const n=this.openSubs.get(r);if(!n)return;const i=ni(t,"id"),s=n.alreadyHaveEvent?.(i);if(n.receivedEvent?.(this,i),s)return}try{let n=JSON.parse(t);switch(n[0]){case"EVENT":{const i=this.openSubs.get(n[1]),s=n[2];this.verifyEvent(s)&&ti(i.filters,s)?i.onevent(s):i.oninvalidevent?.(s),(!i.lastEmitted||i.lastEmitted<s.created_at)&&(i.lastEmitted=s.created_at);return}case"COUNT":{const i=n[1],s=n[2],o=this.openCountRequests.get(i);o&&(o.resolve(s.count),this.openCountRequests.delete(i));return}case"EOSE":{const i=this.openSubs.get(n[1]);if(!i)return;i.receivedEose();return}case"OK":{const i=n[1],s=n[2],o=n[3],c=this.openEventPublishes.get(i);c&&(clearTimeout(c.timeout),s?c.resolve(o):c.reject(new Error(o)),this.openEventPublishes.delete(i));return}case"CLOSED":{const i=n[1],s=this.openSubs.get(i);if(!s)return;s.closed=!0,s.close(n[2]);return}case"NOTICE":{this.onnotice(n[1]);return}case"AUTH":{this.challenge=n[1],this.onauth&&this.auth(this.onauth);return}default:{this.openSubs.get(n[1])?.oncustom?.(n);return}}}catch(n){try{const[i,s,o]=JSON.parse(t);console.warn(`[nostr] relay ${this.url} error processing message:`,n,o)}catch{console.warn(`[nostr] relay ${this.url} error processing message:`,n)}return}}},si=class{relay;id;lastEmitted;closed=!1;eosed=!1;filters;alreadyHaveEvent;receivedEvent;onevent;oninvalidevent;oneose;onclose;oncustom;eoseTimeout;eoseTimeoutHandle;constructor(e,t,r,n){if(r.length===0)throw new Error("subscription can't be created with zero filters");this.relay=e,this.filters=r,this.id=t,this.alreadyHaveEvent=n.alreadyHaveEvent,this.receivedEvent=n.receivedEvent,this.eoseTimeout=n.eoseTimeout||e.baseEoseTimeout,this.oneose=n.oneose,this.onclose=n.onclose,this.oninvalidevent=n.oninvalidevent,this.onevent=n.onevent||(i=>{console.warn(`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,i)})}fire(){this.relay.send('["REQ","'+this.id+'",'+JSON.stringify(this.filters).substring(1)),this.eoseTimeoutHandle=setTimeout(this.receivedEose.bind(this),this.eoseTimeout)}receivedEose(){this.eosed||(clearTimeout(this.eoseTimeoutHandle),this.eosed=!0,this.oneose?.())}close(e="closed by caller"){if(!this.closed&&this.relay.connected){try{this.relay.send('["CLOSE",'+JSON.stringify(this.id)+"]")}catch(t){if(!(t instanceof wn))throw t}this.closed=!0}this.relay.openSubs.delete(this.id),this.relay.ongoingOperations--,this.relay.ongoingOperations===0&&(this.relay.idleSince=Date.now()),this.onclose?.(e)}},oi=e=>(e[ie]=!0,!0),ai=class{relays=new Map;seenOn=new Map;trackRelays=!1;verifyEvent;enablePing;enableReconnect;automaticallyAuth;trustedRelayURLs=new Set;onRelayConnectionFailure;onRelayConnectionSuccess;allowConnectingToRelay;maxWaitForConnection;_WebSocket;constructor(e){this.verifyEvent=e.verifyEvent,this._WebSocket=e.websocketImplementation,this.enablePing=e.enablePing,this.enableReconnect=e.enableReconnect||!1,this.automaticallyAuth=e.automaticallyAuth,this.onRelayConnectionFailure=e.onRelayConnectionFailure,this.onRelayConnectionSuccess=e.onRelayConnectionSuccess,this.allowConnectingToRelay=e.allowConnectingToRelay,this.maxWaitForConnection=e.maxWaitForConnection||3e3}async ensureRelay(e,t){e=pe(e);let r=this.relays.get(e);if(r||(r=new vn(e,{verifyEvent:this.trustedRelayURLs.has(e)?oi:this.verifyEvent,websocketImplementation:this._WebSocket,enablePing:this.enablePing,enableReconnect:this.enableReconnect}),r.onclose=()=>{this.relays.delete(e)},this.relays.set(e,r)),this.automaticallyAuth){const n=this.automaticallyAuth(e);n&&(r.onauth=n)}try{await r.connect({timeout:t?.connectionTimeout,abort:t?.abort})}catch(n){throw this.relays.delete(e),n}return r}close(e){e.map(pe).forEach(t=>{this.relays.get(t)?.close(),this.relays.delete(t)})}subscribe(e,t,r){const n=[],i=[];for(let s=0;s<e.length;s++){const o=pe(e[s]);n.find(c=>c.url===o)||i.indexOf(o)===-1&&(i.push(o),n.push({url:o,filter:t}))}return this.subscribeMap(n,r)}subscribeMany(e,t,r){return this.subscribe(e,t,r)}subscribeMap(e,t){const r=new Map;for(const u of e){const{url:f,filter:m}=u;r.has(f)||r.set(f,[]),r.get(f).push(m)}const n=Array.from(r.entries()).map(([u,f])=>({url:u,filters:f}));this.trackRelays&&(t.receivedEvent=(u,f)=>{let m=this.seenOn.get(f);m||(m=new Set,this.seenOn.set(f,m)),m.add(u)});const i=new Set,s=[],o=[];let c=u=>{o[u]||(o[u]=!0,o.filter(f=>f).length===n.length&&(t.oneose?.(),c=()=>{}))};const a=[];let l=(u,f)=>{a[u]||(c(u),a[u]=f,a.filter(m=>m).length===n.length&&(t.onclose?.(a),l=()=>{}))};const p=u=>{if(t.alreadyHaveEvent?.(u))return!0;const f=i.has(u);return i.add(u),f},d=Promise.all(n.map(async({url:u,filters:f},m)=>{if(this.allowConnectingToRelay?.(u,["read",f])===!1){l(m,"connection skipped by allowConnectingToRelay");return}let w;try{w=await this.ensureRelay(u,{connectionTimeout:this.maxWaitForConnection<(t.maxWait||0)?Math.max(t.maxWait*.8,t.maxWait-1e3):this.maxWaitForConnection,abort:t.abort})}catch(N){this.onRelayConnectionFailure?.(u),l(m,N?.message||String(N));return}this.onRelayConnectionSuccess?.(u);let I=w.subscribe(f,{...t,oneose:()=>c(m),onclose:N=>{N.startsWith("auth-required: ")&&t.onauth?w.auth(t.onauth).then(()=>{w.subscribe(f,{...t,oneose:()=>c(m),onclose:K=>{l(m,K)},alreadyHaveEvent:p,eoseTimeout:t.maxWait,abort:t.abort})}).catch(K=>{l(m,`auth was required and attempted, but failed with: ${K}`)}):l(m,N)},alreadyHaveEvent:p,eoseTimeout:t.maxWait,abort:t.abort});s.push(I)}));return{async close(u){await d,s.forEach(f=>{f.close(u)})}}}subscribeEose(e,t,r){let n;return n=this.subscribe(e,t,{...r,oneose(){const i="closed automatically on eose";n?n.close(i):r.onclose?.(e.map(s=>i))}}),n}subscribeManyEose(e,t,r){return this.subscribeEose(e,t,r)}async querySync(e,t,r){return new Promise(async n=>{const i=[];this.subscribeEose(e,t,{...r,onevent(s){i.push(s)},onclose(s){n(i)}})})}async get(e,t,r){t.limit=1;const n=await this.querySync(e,t,r);return n.sort((i,s)=>s.created_at-i.created_at),n[0]||null}publish(e,t,r){return e.map(pe).map(async(n,i,s)=>{if(s.indexOf(n)!==i)return Promise.reject("duplicate url");if(this.allowConnectingToRelay?.(n,["write",t])===!1)return Promise.reject("connection skipped by allowConnectingToRelay");let o;try{o=await this.ensureRelay(n,{connectionTimeout:this.maxWaitForConnection<(r?.maxWait||0)?Math.max(r.maxWait*.8,r.maxWait-1e3):this.maxWaitForConnection,abort:r?.abort})}catch(c){return this.onRelayConnectionFailure?.(n),"connection failure: "+String(c)}return o.publish(t).catch(async c=>{if(c instanceof Error&&c.message.startsWith("auth-required: ")&&r?.onauth)return await o.auth(r.onauth),o.publish(t);throw c}).then(c=>{if(this.trackRelays){let a=this.seenOn.get(t.id);a||(a=new Set,this.seenOn.set(t.id,a)),a.add(o)}return c})})}listConnectionStatus(){const e=new Map;return this.relays.forEach((t,r)=>e.set(r,t.connected)),e}destroy(){this.relays.forEach(e=>e.close()),this.relays=new Map}pruneIdleRelays(e=1e4){const t=[];for(const[r,n]of this.relays)n.idleSince&&Date.now()-n.idleSince>=e&&(this.relays.delete(r),t.push(r),n.close());return t}},En;try{En=WebSocket}catch{}var ci=class extends ai{constructor(e){super({verifyEvent:Jr,websocketImplementation:En,maxWaitForConnection:3e3,...e})}},ce=Symbol("verified"),li=e=>e instanceof Object;function di(e){if(!li(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!e.pubkey.match(/^[a-f0-9]{64}$/)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let r=e.tags[t];if(!Array.isArray(r))return!1;for(let n=0;n<r.length;n++)if(typeof r[n]!="string")return!1}return!0}new TextDecoder("utf-8");var ui=new TextEncoder,fi=class{generateSecretKey(){return G.utils.randomSecretKey()}getPublicKey(e){return _(G.getPublicKey(e))}finalizeEvent(e,t){const r=e;return r.pubkey=_(G.getPublicKey(t)),r.id=Ke(r),r.sig=_(G.sign(X(Ke(r)),t)),r[ce]=!0,r}verifyEvent(e){if(typeof e[ce]=="boolean")return e[ce];try{const t=Ke(e);if(t!==e.id)return e[ce]=!1,!1;const r=G.verify(X(e.sig),X(t),X(e.pubkey));return e[ce]=r,r}catch{return e[ce]=!1,!1}}};function hi(e){if(!di(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function Ke(e){let t=Oe(ui.encode(hi(e)));return _(t)}var Ue=new fi;Ue.generateSecretKey;Ue.getPublicKey;Ue.finalizeEvent;var pi=Ue.verifyEvent;const gi=8e3;function bi(e){return typeof e=="number"&&ot.includes(e)}function mi(e){try{const t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function yi(e){const t=[];for(const r of e??[])try{const n=new URL(r);if(n.protocol!=="ws:"&&n.protocol!=="wss:")continue;t.push(n.href)}catch{}return[...new Set(t)]}function wi(e){const t=cr(e.trim());if(t.type!=="nevent"&&t.type!=="naddr")throw new Error("Enter a NIP-19 nevent or naddr for a NIP-5D napplet manifest event");const r=yi(t.data.relays);if(r.length===0)throw new Error("The pointer does not include relay hints; include at least one relay in the nevent/naddr");if(t.type==="nevent"){if(t.data.kind!==void 0&&!bi(t.data.kind))throw new Error(`nevent points at kind ${t.data.kind}, not a NIP-5D napplet manifest kind`);return{type:"nevent",relays:r,filter:{ids:[t.data.id],kinds:t.data.kind===void 0?[...ot]:[t.data.kind],authors:t.data.author?[t.data.author]:void 0,limit:1}}}if(t.data.kind!==ge)throw new Error(`naddr kind ${t.data.kind} is not the named napplet kind ${ge}`);return{type:"naddr",relays:r,filter:{kinds:[ge],authors:[t.data.pubkey],"#d":[t.data.identifier],limit:1}}}function vi(e){return{id:e.id,pubkey:e.pubkey,kind:e.kind,tags:e.tags}}async function xn(e){const t=typeof e=="string"?new TextEncoder().encode(e):e,r=new Uint8Array(t.byteLength);r.set(t);const n=await crypto.subtle.digest("SHA-256",r.buffer);return[...new Uint8Array(n)].map(i=>i.toString(16).padStart(2,"0")).join("")}function Ei(e){return e.tags.filter(t=>t[0]==="path"&&typeof t[1]=="string"&&typeof t[2]=="string")}async function xi(e){const t=Ei(e).map(r=>`${r[2]} ${r[1]}
|
|
77
|
+
`).sort().join("");return xn(t)}async function ki(e){const t=await xi(e);for(const r of e.tags.filter(n=>n[0]==="x"))if(r[2]!==t)throw new Error(`Manifest x tag does not match recomputed aggregate hash ${t}`)}function Si(e){return e.tags.find(t=>t[0]==="path"&&t[1]==="/index.html")}function Ri(e){const t=[];for(const r of e.tags)if(!(r[0]!=="server"||!r[1]))try{const n=new URL(r[1]);(n.protocol==="http:"||n.protocol==="https:")&&t.push(n.href)}catch{}return[...new Set(t)]}function $i(e,t){const r=e.endsWith("/")?e:`${e}/`;return new URL(t,r).href}async function Ii(e,t=fetch){const n=Si(e)?.[2];if(!n)throw new Error("Manifest does not include a /index.html path hash");const i=Ri(e);if(i.length===0)throw new Error("Manifest does not include any usable Blossom server hints");const s=[];for(const o of i){const c=$i(o,n);try{const a=await t(c,{mode:"cors"});if(!a.ok){s.push(`${c}: HTTP ${a.status}`);continue}const l=new Uint8Array(await a.arrayBuffer()),p=await xn(l);if(p!==n){s.push(`${c}: sha256 ${p} did not match manifest ${n}`);continue}return new TextDecoder().decode(l)}catch(a){s.push(`${c}: ${a instanceof Error?a.message:String(a)}`)}}throw new Error(`Unable to fetch verified /index.html from Blossom servers: ${s.join("; ")}`)}async function Ti(e,t){try{const n=await(await t(e,{mode:"cors"})).text();return{source:"url",input:e,label:e,bootUrl:e,html:n,fetched:!0,manifestEvent:null}}catch{return{source:"url",input:e,label:e,bootUrl:e,html:"",fetched:!1,manifestEvent:null}}}async function Bi(e,t){const r=wi(e),n=!t.pool,i=t.pool??new ci;try{const s=await i.get(r.relays,{...r.filter},{maxWait:t.maxRelayWaitMs??gi});if(!s)throw new Error("No matching napplet manifest event was found on the pointer relay hints");if(!pi(s))throw new Error("Resolved manifest event signature is invalid");const o=vi(s),c=at(o);if(!c.ok)throw new Error(`Resolved event is not a valid NIP-5D napplet manifest: ${c.errors[0]?.message}`);await ki(o);const a=await Ii(o,t.fetcher??fetch),l=(t.createObjectUrl??URL.createObjectURL)(new Blob([a],{type:"text/html;charset=utf-8"})),p=()=>(t.revokeObjectUrl??URL.revokeObjectURL)(l);return{source:"nostr",input:e,label:o.id??e,bootUrl:l,html:a,fetched:!0,manifestEvent:o,revoke:p}}finally{n&&i.destroy()}}async function Ai(e,t={}){const r=e.trim();if(!r)throw new Error("Enter a NIP-19 nevent/naddr, or an HTTP URL for local dev");return mi(r)?Ti(r,t.fetcher??fetch):Bi(r,t)}const Oi=/\bwindow\s*\.\s*nostr\b|\bglobalThis\s*\.\s*nostr\b/,Ni="/__conformance__/events",rt=new URLSearchParams(location.search),kn=rt.get("live")==="1";function ne(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const re=document.getElementById("app");function qi(){return re.innerHTML=`
|
|
78
|
+
<header class="masthead">
|
|
79
|
+
<h1>napplet conformance ${kn?'<span class="live-badge" id="live-badge">● live</span>':""}</h1>
|
|
80
|
+
<p>Load a napplet by <code>nevent</code> or <code>naddr</code> and run NAP protocol conformance live. Same engine as <code>napplet-conformance</code> CI.</p>
|
|
81
|
+
</header>
|
|
82
|
+
<form id="run-form" class="runbar">
|
|
83
|
+
<input id="target" type="text" placeholder="naddr1… or nevent1… for a NIP-5D napplet manifest" autocomplete="off" spellcheck="false" />
|
|
84
|
+
<button id="run" type="submit">Run conformance</button>
|
|
85
|
+
<button id="rerun" type="button" class="secondary" hidden>Re-run</button>
|
|
86
|
+
</form>
|
|
87
|
+
<p id="status" class="status" role="status"></p>
|
|
88
|
+
<section id="output" class="output"></section>
|
|
89
|
+
`,{targetInput:re.querySelector("#target"),runButton:re.querySelector("#run"),rerunButton:re.querySelector("#rerun"),liveBadge:re.querySelector("#live-badge")??document.createElement("span"),status:re.querySelector("#status"),output:re.querySelector("#output")}}const C=qi();let ye="",it=0;function $e(e,t="info"){C.status.textContent=e,C.status.dataset.kind=t}function Ye(e){return String(e).padStart(2,"0")}function Li(e){const t=new Date(e);return`${Ye(t.getHours())}:${Ye(t.getMinutes())}:${Ye(t.getSeconds())}`}function Pi(e){const t=e.ok?"conformant":"non-conformant",n=[...new Set(e.checks.map(o=>o.area))].map(o=>{const c=e.checks.filter(a=>a.area===o).map(a=>{const l=a.severity==="warning"&&a.status==="fail"?' <span class="tag warn">warning</span>':"",p=a.detail?`<span class="detail">${ne(a.detail)}</span>`:"";return`<li class="check ${a.status}"><span class="badge ${a.status}">${a.status}</span><span class="id">${ne(a.id)}</span>${l}${p}</li>`}).join("");return`<div class="area"><h3>${ne(o)}</h3><ul>${c}</ul></div>`}).join(""),i=e.summary,s=it>1?`<span class="run-stamp">run #${it} · ${Li(e.finishedAt)}</span>`:"";return`
|
|
90
|
+
<div class="verdict ${t}">
|
|
91
|
+
<span class="result">${e.ok?"CONFORMANT":"NON-CONFORMANT"}</span>
|
|
92
|
+
<span class="counts">${i.passed} passed · ${i.failed} failed · ${i.skipped} skipped${i.warnings?` · ${i.warnings} warning(s)`:""}</span>
|
|
93
|
+
${s}
|
|
94
|
+
</div>
|
|
95
|
+
<div class="checks">${n}</div>
|
|
96
|
+
`}function _i(e){return e.length===0?'<p class="empty">No envelopes were emitted.</p>':`<ul class="envlog">${e.map(r=>{const n=r.verdict.ok?"ok":"bad",i=r.verdict.ok?"":`<div class="errs">${r.verdict.errors.map(s=>ne(`${s.code}: ${s.message}`)).join("<br>")}</div>`;return`<li class="env ${n}"><code>${ne(JSON.stringify(r.envelope))}</code>${i}</li>`}).join("")}</ul>`}function Ci(e){const t=(r,n)=>`<tr><th>${ne(r)}</th><td>${n?ne(String(n)):"<em>—</em>"}</td></tr>`;if(e.manifestEvent){const r=e.manifestEvent,n=at(r),i=r.tags.find(c=>c[0]==="d")?.[1],s=r.tags.find(c=>c[0]==="path"&&c[1]==="/index.html"),o=r.tags.filter(c=>c[0]==="server").map(c=>c[1]).filter(Boolean);return`
|
|
97
|
+
<table class="manifest">
|
|
98
|
+
${t("event",r.id)}
|
|
99
|
+
${t("kind",r.kind)}
|
|
100
|
+
${t("d",i)}
|
|
101
|
+
${t("name",Zt(r))}
|
|
102
|
+
${t("requires",n.requires.join(", "))}
|
|
103
|
+
${t("/index.html",s?.[2])}
|
|
104
|
+
${t("servers",o.join(", "))}
|
|
105
|
+
</table>
|
|
106
|
+
${n.errors.length?`<div class="errs">${n.errors.map(c=>ne(`${c.code}: ${c.message}`)).join("<br>")}</div>`:""}
|
|
107
|
+
`}return e.fetched?'<p class="empty">Local URL mode booted raw HTML. It does not include a signed NIP-5D manifest event, so manifest-event checks are skipped.</p>':`<p class="empty">Couldn't fetch the local URL HTML, likely because of CORS. Use a NIP-19 <code>nevent</code>/<code>naddr</code> for authoritative manifest checks, or use the CLI for local URL runs.</p>`}function Ui(e,t,r){C.output.innerHTML=`
|
|
108
|
+
${Pi(e)}
|
|
109
|
+
<div class="panels">
|
|
110
|
+
<section class="panel"><h2>Emitted envelopes (${t.length})</h2>${_i(t)}</section>
|
|
111
|
+
<section class="panel"><h2>Manifest</h2>${Ci(r)}</section>
|
|
112
|
+
</div>
|
|
113
|
+
`}async function He(e){ye=e,C.runButton.disabled=!0,C.rerunButton.disabled=!0;let t=null;try{$e(`Resolving ${e} …`),t=await Ai(e);const r=Oi.test(t.html)?["window.nostr"]:[];$e("Booting napplet in a sandboxed iframe …");const n=await Zn({url:t.bootUrl,readyTimeoutMs:5e3,settleMs:800,runDegraded:!0}),i=Cn({manifestHtml:t.html,manifestEvent:t.manifestEvent,boot:n,forbiddenGlobals:r}),s=zn(i);it+=1,$e(s.ok?"Done — conformant.":"Done — non-conformant.",s.ok?"info":"error"),Ui(s,n.emitted,t),C.rerunButton.hidden=!1}catch(r){$e(`Error: ${r instanceof Error?r.message:String(r)}`,"error")}finally{t?.revoke?.(),C.runButton.disabled=!1,C.rerunButton.disabled=!1}}function Hi(){if(!kn||typeof EventSource>"u")return;let e=!1;const t=new EventSource(Ni);t.addEventListener("rerun",()=>{!ye||e||(e=!0,setTimeout(()=>{e=!1,He(ye)},50))}),t.addEventListener("open",()=>{C.liveBadge&&(C.liveBadge.dataset.state="connected")}),t.addEventListener("error",()=>{C.liveBadge&&(C.liveBadge.dataset.state="disconnected")})}C.runButton.parentElement.addEventListener("submit",e=>{e.preventDefault();const t=C.targetInput.value.trim();if(t){const r=new URL(location.href);r.searchParams.set("target",t),r.searchParams.delete("url"),history.replaceState(null,"",r),He(t)}});C.rerunButton.addEventListener("click",()=>{ye&&He(ye)});Hi();const ze=rt.get("target")??rt.get("url");ze&&(C.targetInput.value=ze,He(ze));
|
package/dist/ui/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>napplet conformance runtime</title>
|
|
7
7
|
<meta name="description" content="Load a napplet and run NAP protocol conformance checks live in your browser." />
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-B_4r_ePr.js"></script>
|
|
9
9
|
<link rel="stylesheet" crossorigin href="/assets/index-D4WUxbBl.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@napplet/conformance-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17",
|
|
4
4
|
"description": "Headless CLI that runs @napplet/conformance against a napplet in real Chromium via Playwright — the `test:conformance` runner",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"playwright": "^1.59.1",
|
|
18
|
-
"@napplet/conformance": "^0.
|
|
18
|
+
"@napplet/conformance": "^0.15.0"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/node": "^22.15.0",
|
|
22
22
|
"tsup": "^8.5.0",
|
|
23
23
|
"typescript": "^5.9.3",
|
|
24
24
|
"vitest": "^4.1.2",
|
|
25
|
-
"@napplet/conformance-web": "0.0.
|
|
25
|
+
"@napplet/conformance-web": "0.0.16"
|
|
26
26
|
},
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"repository": {
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))n(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&n(o)}).observe(document,{childList:!0,subtree:!0});function r(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function n(i){if(i.ep)return;i.ep=!0;const s=r(i);fetch(i.href,s)}})();var it=["relay","identity","storage","inc","theme","keys","media","notify","config","resource","cvm","outbox","upload","intent","ble","webrtc","link","count","lists","serial","common","dm"],d={id:"string"},kn={"relay.subscribe":{dir:"out",fields:{...d,subId:"string",filters:"array"}},"relay.close":{dir:"out",fields:{...d,subId:"string"}},"relay.publish":{dir:"out",fields:{...d,event:"object"}},"relay.publishEncrypted":{dir:"out",fields:{...d,event:"object",recipient:"string"}},"relay.query":{dir:"out",fields:{...d,filters:"array"}},"relay.event":{dir:"in"},"relay.eose":{dir:"in"},"relay.closed":{dir:"in"},"relay.publish.result":{dir:"in"},"relay.publishEncrypted.result":{dir:"in"},"relay.query.result":{dir:"in"},"identity.getPublicKey":{dir:"out",fields:{...d}},"identity.getRelays":{dir:"out",fields:{...d}},"identity.getProfile":{dir:"out",fields:{...d}},"identity.getFollows":{dir:"out",fields:{...d}},"identity.getList":{dir:"out",fields:{...d,listType:"string"}},"identity.getZaps":{dir:"out",fields:{...d}},"identity.getMutes":{dir:"out",fields:{...d}},"identity.getBlocked":{dir:"out",fields:{...d}},"identity.getBadges":{dir:"out",fields:{...d}},"identity.changed":{dir:"in"},"identity.getPublicKey.result":{dir:"in"},"identity.getRelays.result":{dir:"in"},"identity.getProfile.result":{dir:"in"},"identity.getFollows.result":{dir:"in"},"identity.getList.result":{dir:"in"},"identity.getZaps.result":{dir:"in"},"identity.getMutes.result":{dir:"in"},"identity.getBlocked.result":{dir:"in"},"identity.getBadges.result":{dir:"in"},"storage.get":{dir:"out",fields:{...d,key:"string"}},"storage.set":{dir:"out",fields:{...d,key:"string",value:"string"}},"storage.remove":{dir:"out",fields:{...d,key:"string"}},"storage.keys":{dir:"out",fields:{...d}},"storage.get.result":{dir:"in"},"storage.set.result":{dir:"in"},"storage.remove.result":{dir:"in"},"storage.keys.result":{dir:"in"},"inc.emit":{dir:"out",fields:{topic:"string"}},"inc.subscribe":{dir:"out",fields:{...d,topic:"string"}},"inc.unsubscribe":{dir:"out",fields:{topic:"string"}},"inc.channel.open":{dir:"out",fields:{...d,target:"string"}},"inc.channel.emit":{dir:"out",fields:{channelId:"string"}},"inc.channel.broadcast":{dir:"out"},"inc.channel.list":{dir:"out",fields:{...d}},"inc.channel.close":{dir:"out",fields:{channelId:"string"}},"inc.subscribe.result":{dir:"in"},"inc.event":{dir:"in"},"inc.channel.open.result":{dir:"in"},"inc.channel.event":{dir:"in"},"inc.channel.list.result":{dir:"in"},"inc.channel.closed":{dir:"in"},"theme.get":{dir:"out",fields:{...d}},"theme.get.result":{dir:"in"},"theme.changed":{dir:"in"},"keys.forward":{dir:"out",fields:{key:"string",code:"string",ctrl:"boolean",alt:"boolean",shift:"boolean",meta:"boolean"}},"keys.registerAction":{dir:"out",fields:{...d,action:"object"}},"keys.unregisterAction":{dir:"out",fields:{actionId:"string"}},"keys.registerAction.result":{dir:"in"},"keys.bindings":{dir:"in"},"keys.action":{dir:"in"},"media.session.create":{dir:"out",fields:{...d,owner:"object"}},"media.session.update":{dir:"out",fields:{sessionId:"string",metadata:"object"}},"media.session.destroy":{dir:"out",fields:{sessionId:"string"}},"media.state":{dir:"out",fields:{sessionId:"string",status:"string"}},"media.capabilities":{dir:"out",fields:{sessionId:"string",actions:"array"}},"media.session.create.result":{dir:"in"},"media.command":{dir:"in"},"media.controls":{dir:"in"},"notify.send":{dir:"out",fields:{...d,title:"string"}},"notify.dismiss":{dir:"out",fields:{notificationId:"string"}},"notify.badge":{dir:"out",fields:{count:"number"}},"notify.channel.register":{dir:"out",fields:{channelId:"string",label:"string"}},"notify.permission.request":{dir:"out",fields:{...d}},"notify.send.result":{dir:"in"},"notify.permission.result":{dir:"in"},"notify.action":{dir:"in"},"notify.clicked":{dir:"in"},"notify.dismissed":{dir:"in"},"notify.controls":{dir:"in"},"config.registerSchema":{dir:"out",fields:{...d,schema:"object"}},"config.get":{dir:"out",fields:{...d}},"config.subscribe":{dir:"out"},"config.unsubscribe":{dir:"out"},"config.openSettings":{dir:"out"},"config.registerSchema.result":{dir:"in"},"config.values":{dir:"in"},"config.schemaError":{dir:"in"},"resource.info":{dir:"out",fields:{...d}},"resource.bytes":{dir:"out",fields:{...d,url:"string"}},"resource.bytesMany":{dir:"out",fields:{...d,urls:"array"}},"resource.cancel":{dir:"out",fields:{...d}},"resource.info.result":{dir:"in"},"resource.info.error":{dir:"in"},"resource.bytes.result":{dir:"in"},"resource.bytes.error":{dir:"in"},"resource.bytesMany.result":{dir:"in"},"resource.bytesMany.error":{dir:"in"},"cvm.discover":{dir:"out",fields:{...d}},"cvm.request":{dir:"out",fields:{...d,server:"object",message:"object"}},"cvm.close":{dir:"out",fields:{...d,server:"object"}},"cvm.registry.list":{dir:"out",fields:{...d}},"cvm.registry.has":{dir:"out",fields:{...d,family:"string"}},"cvm.registry.describe":{dir:"out",fields:{...d,family:"string"}},"cvm.registry.call":{dir:"out",fields:{...d,family:"string",tool:"string"}},"cvm.discover.result":{dir:"in"},"cvm.request.result":{dir:"in"},"cvm.close.result":{dir:"in"},"cvm.event":{dir:"in"},"cvm.registry.list.result":{dir:"in"},"cvm.registry.has.result":{dir:"in"},"cvm.registry.describe.result":{dir:"in"},"cvm.registry.call.result":{dir:"in"},"outbox.getEvent":{dir:"out",fields:{...d,eventId:"string"}},"outbox.query":{dir:"out",fields:{...d,filters:"present"}},"outbox.subscribe":{dir:"out",fields:{...d,subId:"string",filters:"present"}},"outbox.close":{dir:"out",fields:{...d,subId:"string"}},"outbox.publish":{dir:"out",fields:{...d,event:"object"}},"outbox.resolveRelays":{dir:"out",fields:{...d,target:"present"}},"outbox.getEvent.result":{dir:"in"},"outbox.query.result":{dir:"in"},"outbox.event":{dir:"in"},"outbox.closed":{dir:"in"},"outbox.publish.result":{dir:"in"},"outbox.resolveRelays.result":{dir:"in"},"upload.info":{dir:"out",fields:{...d}},"upload.upload":{dir:"out",fields:{...d,request:"object"}},"upload.status":{dir:"out",fields:{...d,uploadId:"string"}},"upload.info.result":{dir:"in"},"upload.upload.result":{dir:"in"},"upload.status.result":{dir:"in"},"upload.status.changed":{dir:"in"},"intent.invoke":{dir:"out",fields:{...d,request:"object"}},"intent.available":{dir:"out",fields:{...d,archetype:"string"}},"intent.handlers":{dir:"out",fields:{...d}},"intent.invoke.result":{dir:"in"},"intent.available.result":{dir:"in"},"intent.handlers.result":{dir:"in"},"intent.changed":{dir:"in"},"ble.open":{dir:"out",fields:{...d,request:"object"}},"ble.services":{dir:"out",fields:{...d,sessionId:"string"}},"ble.read":{dir:"out",fields:{...d,sessionId:"string",target:"object"}},"ble.write":{dir:"out",fields:{...d,sessionId:"string",target:"object",data:"array"}},"ble.subscribe":{dir:"out",fields:{...d,sessionId:"string",target:"object"}},"ble.unsubscribe":{dir:"out",fields:{...d,sessionId:"string",target:"object"}},"ble.close":{dir:"out",fields:{...d,sessionId:"string"}},"ble.open.result":{dir:"in"},"ble.services.result":{dir:"in"},"ble.read.result":{dir:"in"},"ble.write.result":{dir:"in"},"ble.subscribe.result":{dir:"in"},"ble.unsubscribe.result":{dir:"in"},"ble.close.result":{dir:"in"},"ble.event":{dir:"in"},"common.encodeNip19":{dir:"out",fields:{...d,input:"object"}},"common.decodeNip19":{dir:"out",fields:{...d,value:"string"}},"common.getProfile":{dir:"out",fields:{...d,target:"string"}},"common.follows":{dir:"out",fields:{...d}},"common.follow":{dir:"out",fields:{...d,pubkeys:"array"}},"common.unfollow":{dir:"out",fields:{...d,pubkeys:"array"}},"common.react":{dir:"out",fields:{...d,targetEventId:"string",reaction:"string"}},"common.report":{dir:"out",fields:{...d,target:"object",reason:"string",text:"string"}},"common.encodeNip19.result":{dir:"in"},"common.decodeNip19.result":{dir:"in"},"common.getProfile.result":{dir:"in"},"common.follows.result":{dir:"in"},"common.follow.result":{dir:"in"},"common.unfollow.result":{dir:"in"},"common.react.result":{dir:"in"},"common.report.result":{dir:"in"},"webrtc.open":{dir:"out",fields:{...d,request:"object"}},"webrtc.send":{dir:"out",fields:{...d,sessionId:"string",payload:"present"}},"webrtc.close":{dir:"out",fields:{...d,sessionId:"string"}},"webrtc.open.result":{dir:"in"},"webrtc.send.result":{dir:"in"},"webrtc.close.result":{dir:"in"},"webrtc.event":{dir:"in"},"link.open":{dir:"out",fields:{...d,url:"string"}},"link.open.result":{dir:"in"},"count.query":{dir:"out",fields:{...d,filters:"array"}},"count.query.result":{dir:"in"},"lists.supported":{dir:"out",fields:{...d}},"lists.add":{dir:"out",fields:{...d,list:"object",items:"array"}},"lists.remove":{dir:"out",fields:{...d,list:"object",items:"array"}},"lists.supported.result":{dir:"in"},"lists.add.result":{dir:"in"},"lists.remove.result":{dir:"in"},"serial.open":{dir:"out",fields:{...d,request:"object"}},"serial.write":{dir:"out",fields:{...d,sessionId:"string",data:"array"}},"serial.close":{dir:"out",fields:{...d,sessionId:"string"}},"serial.open.result":{dir:"in"},"serial.write.result":{dir:"in"},"serial.close.result":{dir:"in"},"serial.event":{dir:"in"},"dm.status":{dir:"out",fields:{...d}},"dm.conversations":{dir:"out",fields:{...d}},"dm.messages":{dir:"out",fields:{...d,conversationId:"string"}},"dm.send":{dir:"out",fields:{...d,recipients:"array",content:"string"}},"dm.subscribe":{dir:"out",fields:{...d}},"dm.unsubscribe":{dir:"out",fields:{...d,subscriptionId:"string"}},"dm.status.result":{dir:"in"},"dm.conversations.result":{dir:"in"},"dm.messages.result":{dir:"in"},"dm.send.result":{dir:"in"},"dm.subscribe.result":{dir:"in"},"dm.unsubscribe.result":{dir:"in"},"dm.message":{dir:"in"}};function _t(e){if(e===void 0)return"undefined";if(e===null)return"null";if(Array.isArray(e))return"array";const t=typeof e;return t==="string"||t==="number"||t==="boolean"?t:t==="object"?"object":"present"}function Sn(e,t){return t==="present"?e!=null:_t(e)===t}function Rn(e){const t=[];if(typeof e!="object"||e===null||Array.isArray(e))return{ok:!1,errors:[{code:"not-an-object",message:"Envelope must be a non-null object"}]};const r=e,n=r.type;if(typeof n!="string")return{ok:!1,errors:[{code:"missing-type",message:"Envelope is missing a string `type` field"}]};const i=n.indexOf(".");if(i<=0)return{ok:!1,type:n,errors:[{code:"malformed-type",message:`Envelope type "${n}" is not in domain.action form`}]};const s=n.slice(0,i);if(!it.includes(s))return{ok:!1,type:n,domain:s,errors:[{code:"unknown-domain",message:`"${s}" is not a known NAP domain`}]};const c=kn[n];if(!c)return{ok:!1,type:n,domain:s,errors:[{code:"unknown-type",message:`"${n}" is not a known ${s} message type`}]};if(c.dir==="in")return{ok:!1,type:n,domain:s,direction:"in",errors:[{code:"inbound-type-emitted",message:`"${n}" is a shell→napplet message; a napplet must not emit it`}]};for(const[a,l]of Object.entries(c.fields??{})){if(!(a in r)||r[a]===void 0){t.push({code:"missing-field",message:`Required field "${a}" is missing`,field:a});continue}Sn(r[a],l)||t.push({code:"wrong-type",message:`Field "${a}" should be ${l} but is ${_t(r[a])}`,field:a})}return{ok:t.length===0,type:n,domain:s,direction:"out",errors:t}}var Ct=5129,Ut=15129,ge=35129,st=[Ct,Ut,ge];function Ht(e,t){return e.tags.find(r=>r[0]===t)}function $n(e){return st.includes(e)}function Tn(e){return typeof e=="string"&&/^[0-9a-f]{64}$/i.test(e)}function jt(e){return Ht(e,"d")?.[1]?.trim()||void 0}function Bn(e){return e.tags.filter(t=>t[0]==="requires").map(t=>t[1]?.trim()??"").filter(Boolean)}function Mt(e){return jt(e)??Ht(e,"title")?.[1]??e.id}function ot(e){const t=[],r=[];if(!e)return{ok:!1,requires:[],errors:[{code:"missing-manifest-event",message:"No NIP-5D manifest event was resolved"}],warnings:r};const n=jt(e),i=Bn(e);$n(e.kind)||t.push({code:"invalid-napplet-kind",message:`Manifest event kind ${e.kind} is not a NIP-5D napplet kind`}),e.kind===ge&&!n?t.push({code:"missing-d-tag",message:"Named napplet manifest kind 35129 must include a non-empty d tag"}):(e.kind===Ut||e.kind===Ct)&&n&&t.push({code:"unexpected-d-tag",message:`Napplet manifest kind ${e.kind} must not include a d tag`});const s=e.tags.find(o=>o[0]==="path"&&o[1]==="/index.html");s?Tn(s[2])||t.push({code:"invalid-index-html-hash",message:"The /index.html path tag must carry a 64-character sha256 hash"}):t.push({code:"missing-index-html",message:"Napplet manifest must include a path tag for /index.html"});for(const o of i){if(o.startsWith("nap:")||o.startsWith("NAP-")){t.push({code:"invalid-required-nap",message:`requires tag "${o}" must be a bare NAP domain such as "relay"`});continue}it.includes(o)||t.push({code:"unknown-required-nap",message:`requires tag "${o}" is not a known NAP domain`})}return{ok:t.length===0,kind:e.kind,dTag:n,nappletType:n,requires:i,errors:t,warnings:r}}var xe="f".repeat(64),In="https://reference.invalid/blob",p=e=>[e],q=()=>[];function bt(e){if(typeof e!="string"||!e.startsWith("data:"))return null;const t=e.indexOf(",");if(t<0)return{blob:new Blob([],{type:"text/plain"}),mime:"text/plain"};const r=e.slice(5,t),n=e.slice(t+1),i=r.split(";").filter(Boolean),s=i.includes("base64"),o=i.find(c=>c.includes("/"))??"text/plain";try{if(s){const c=globalThis.atob(n),a=Uint8Array.from(c,l=>l.charCodeAt(0));return{blob:new Blob([a],{type:o}),mime:o}}return{blob:new Blob([decodeURIComponent(n)],{type:o}),mime:o}}catch{return null}}var An={"relay.subscribe":e=>p({type:"relay.eose",subId:e.subId}),"relay.close":q,"relay.publish":e=>p({type:"relay.publish.result",id:e.id,ok:!0,event:e.event}),"relay.publishEncrypted":e=>p({type:"relay.publishEncrypted.result",id:e.id,ok:!0,event:e.event}),"relay.query":e=>p({type:"relay.query.result",id:e.id,events:[]}),"identity.getPublicKey":e=>p({type:"identity.getPublicKey.result",id:e.id,pubkey:xe}),"identity.getRelays":e=>p({type:"identity.getRelays.result",id:e.id,relays:{}}),"identity.getProfile":e=>p({type:"identity.getProfile.result",id:e.id,profile:null}),"identity.getFollows":e=>p({type:"identity.getFollows.result",id:e.id,pubkeys:[]}),"identity.getList":e=>p({type:"identity.getList.result",id:e.id,entries:[]}),"identity.getZaps":e=>p({type:"identity.getZaps.result",id:e.id,zaps:[]}),"identity.getMutes":e=>p({type:"identity.getMutes.result",id:e.id,pubkeys:[]}),"identity.getBlocked":e=>p({type:"identity.getBlocked.result",id:e.id,pubkeys:[]}),"identity.getBadges":e=>p({type:"identity.getBadges.result",id:e.id,badges:[]}),"storage.get":e=>p({type:"storage.get.result",id:e.id,value:null}),"storage.set":e=>p({type:"storage.set.result",id:e.id}),"storage.remove":e=>p({type:"storage.remove.result",id:e.id}),"storage.keys":e=>p({type:"storage.keys.result",id:e.id,keys:[]}),"inc.emit":q,"inc.subscribe":e=>p({type:"inc.subscribe.result",id:e.id}),"inc.unsubscribe":q,"inc.channel.open":e=>p({type:"inc.channel.open.result",id:e.id,channelId:`chan-${String(e.id)}`,peer:"reference-peer"}),"inc.channel.emit":q,"inc.channel.broadcast":q,"inc.channel.list":e=>p({type:"inc.channel.list.result",id:e.id,channels:[]}),"inc.channel.close":q,"theme.get":e=>p({type:"theme.get.result",id:e.id,theme:{colors:{},mode:"dark"}}),"keys.forward":q,"keys.registerAction":e=>p({type:"keys.registerAction.result",id:e.id,actionId:`action-${String(e.id)}`}),"keys.unregisterAction":q,"media.session.create":e=>p({type:"media.session.create.result",id:e.id,sessionId:`session-${String(e.id)}`,owner:e.owner}),"media.session.update":q,"media.session.destroy":q,"media.state":q,"media.capabilities":q,"notify.send":e=>p({type:"notify.send.result",id:e.id,notificationId:`notif-${String(e.id)}`}),"notify.dismiss":q,"notify.badge":q,"notify.channel.register":q,"notify.permission.request":e=>p({type:"notify.permission.result",id:e.id,granted:!0}),"config.registerSchema":e=>p({type:"config.registerSchema.result",id:e.id,ok:!0}),"config.get":e=>p({type:"config.values",id:e.id,values:{}}),"config.subscribe":()=>p({type:"config.values",values:{}}),"config.unsubscribe":q,"config.openSettings":q,"resource.bytes":e=>{const t=bt(e.url);return p(t?{type:"resource.bytes.result",id:e.id,blob:t.blob,mime:t.mime}:{type:"resource.bytes.result",id:e.id,blob:new Blob([]),mime:"application/octet-stream"})},"resource.bytesMany":e=>p({type:"resource.bytesMany.result",id:e.id,items:Array.isArray(e.urls)?e.urls.map(t=>{const r=bt(t);return{url:t,ok:!0,blob:r?.blob??new Blob([]),mime:r?.mime??"application/octet-stream"}}):[]}),"resource.info":e=>p({type:"resource.info.result",id:e.id,info:{schemes:[{scheme:"data",enabled:!0},{scheme:"https",enabled:!0}]}}),"resource.cancel":q,"cvm.discover":e=>p({type:"cvm.discover.result",id:e.id,servers:[]}),"cvm.request":e=>p({type:"cvm.request.result",id:e.id,message:{}}),"cvm.close":e=>p({type:"cvm.close.result",id:e.id}),"outbox.getEvent":e=>p({type:"outbox.getEvent.result",id:e.id}),"outbox.query":e=>p({type:"outbox.query.result",id:e.id,events:[]}),"outbox.subscribe":e=>p({type:"outbox.closed",subId:e.subId,reason:"reference shell complete"}),"outbox.close":q,"outbox.publish":e=>p({type:"outbox.publish.result",id:e.id,ok:!0}),"outbox.resolveRelays":e=>p({type:"outbox.resolveRelays.result",id:e.id,plan:{}}),"upload.info":e=>p({type:"upload.info.result",id:e.id,info:{rails:[{rail:"nip96",enabled:!0,returns:["https"]},{rail:"blossom",enabled:!0,returns:["https","blossom"]}]}}),"upload.upload":e=>p({type:"upload.upload.result",id:e.id,result:{url:In}}),"upload.status":e=>p({type:"upload.status.result",id:e.id,status:{}}),"intent.invoke":e=>p({type:"intent.invoke.result",id:e.id,result:{ok:!0,archetype:"reference",action:"open",handled:!0}}),"intent.available":e=>p({type:"intent.available.result",id:e.id,availability:{archetype:e.archetype,available:!0,candidates:[{dTag:"reference-handler",actions:["open"],protocols:["NAP-4"],contracts:[{action:"open",protocol:"NAP-4",eventKinds:[1]}],isDefault:!0}],hasDefault:!0}}),"intent.handlers":e=>p({type:"intent.handlers.result",id:e.id,handlers:[]}),"ble.open":e=>p({type:"ble.open.result",id:e.id,session:{id:"ble-reference",state:"open",device:{id:"reference-device",name:"Reference BLE"}}}),"ble.services":e=>p({type:"ble.services.result",id:e.id,services:[]}),"ble.read":e=>p({type:"ble.read.result",id:e.id,data:[]}),"ble.write":e=>p({type:"ble.write.result",id:e.id}),"ble.subscribe":e=>p({type:"ble.subscribe.result",id:e.id}),"ble.unsubscribe":e=>p({type:"ble.unsubscribe.result",id:e.id}),"ble.close":e=>p({type:"ble.close.result",id:e.id}),"common.encodeNip19":e=>p({type:"common.encodeNip19.result",id:e.id,ok:!0,value:"npub1reference",nip19Type:"npub"}),"common.decodeNip19":e=>p({type:"common.decodeNip19.result",id:e.id,ok:!0,nip19Type:"npub",hex:xe}),"common.getProfile":e=>p({type:"common.getProfile.result",id:e.id,ok:!0,pubkey:xe,profile:null}),"common.follows":e=>p({type:"common.follows.result",id:e.id,ok:!0,pubkeys:[]}),"common.follow":e=>p({type:"common.follow.result",id:e.id,ok:!0}),"common.unfollow":e=>p({type:"common.unfollow.result",id:e.id,ok:!0}),"common.react":e=>p({type:"common.react.result",id:e.id,ok:!0,eventId:"0".repeat(64)}),"common.report":e=>p({type:"common.report.result",id:e.id,ok:!0,eventId:"1".repeat(64)}),"webrtc.open":e=>p({type:"webrtc.open.result",id:e.id,session:{id:"webrtc-reference",scope:{type:"direct",pubkey:xe},channel:"default",state:"connecting"}}),"webrtc.send":e=>p({type:"webrtc.send.result",id:e.id}),"webrtc.close":e=>p({type:"webrtc.close.result",id:e.id}),"link.open":e=>p({type:"link.open.result",id:e.id,status:"opened"}),"count.query":e=>p({type:"count.query.result",id:e.id,ok:!0,count:0}),"lists.supported":e=>p({type:"lists.supported.result",id:e.id,lists:[]}),"lists.add":e=>p({type:"lists.add.result",id:e.id,ok:!0,added:0,skipped:0}),"lists.remove":e=>p({type:"lists.remove.result",id:e.id,ok:!0,removed:0,skipped:0}),"serial.open":e=>p({type:"serial.open.result",id:e.id,session:{id:`serial-${String(e.id)}`,state:"open"}}),"serial.write":e=>p({type:"serial.write.result",id:e.id}),"serial.close":e=>p({type:"serial.close.result",id:e.id})};function On(e={}){const t=e.now??(()=>Date.now()),r=[];function n(i){const s=i&&typeof i=="object"&&typeof i.type=="string"?i.type:void 0;if(r.push({envelope:i,verdict:Rn(i),timestamp:t()}),!s)return[];const o=An[s];return o?o(i):[]}return{get records(){return r},handle:n,reset(){r.length=0}}}function Nn(e){return{manifestHtml:e.manifestHtml,manifestEvent:e.manifestEvent??null,sandbox:e.sandbox??{allowScripts:!0,allowSameOrigin:!1},installedGlobal:e.boot.installedGlobal,bootError:e.boot.bootError,emitted:e.boot.emitted,forbiddenGlobals:e.forbiddenGlobals??[],degraded:e.boot.degraded,lifecycle:e.lifecycle??null}}var Dt="__nappletConformance.error";function mt(e){return new Promise(t=>setTimeout(t,e))}function qn(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function Ln(e){return`
|
|
2
|
-
(() => {
|
|
3
|
-
const domains = ${JSON.stringify(e)};
|
|
4
|
-
const napplet = {};
|
|
5
|
-
for (const domain of domains) napplet[domain] = {};
|
|
6
|
-
const pending = new Map();
|
|
7
|
-
let seq = 0;
|
|
8
|
-
const nextId = () => {
|
|
9
|
-
try {
|
|
10
|
-
if (window.crypto && typeof window.crypto.randomUUID === 'function') return window.crypto.randomUUID();
|
|
11
|
-
} catch {}
|
|
12
|
-
seq += 1;
|
|
13
|
-
return 'conformance-' + Date.now().toString(36) + '-' + seq.toString(36);
|
|
14
|
-
};
|
|
15
|
-
const request = (message, resultType, errorType) => new Promise((resolve, reject) => {
|
|
16
|
-
const id = message.id || nextId();
|
|
17
|
-
const timeout = window.setTimeout(() => {
|
|
18
|
-
pending.delete(id);
|
|
19
|
-
reject(new Error(message.type + ' timed out'));
|
|
20
|
-
}, 5000);
|
|
21
|
-
pending.set(id, { resolve, reject, resultType, errorType, timeout });
|
|
22
|
-
window.parent.postMessage({ ...message, id }, '*');
|
|
23
|
-
});
|
|
24
|
-
window.addEventListener('message', (event) => {
|
|
25
|
-
const msg = event.data;
|
|
26
|
-
if (!msg || typeof msg !== 'object' || typeof msg.id !== 'string') return;
|
|
27
|
-
const slot = pending.get(msg.id);
|
|
28
|
-
if (!slot) return;
|
|
29
|
-
if (msg.type !== slot.resultType && msg.type !== slot.errorType) return;
|
|
30
|
-
pending.delete(msg.id);
|
|
31
|
-
window.clearTimeout(slot.timeout);
|
|
32
|
-
if (msg.type === slot.errorType) {
|
|
33
|
-
slot.reject(new Error(msg.message ? msg.error + ': ' + msg.message : String(msg.error || 'request failed')));
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
slot.resolve(msg);
|
|
37
|
-
});
|
|
38
|
-
if (napplet.resource) {
|
|
39
|
-
napplet.resource.info = () =>
|
|
40
|
-
request({ type: 'resource.info' }, 'resource.info.result', 'resource.info.error')
|
|
41
|
-
.then((msg) => msg.info);
|
|
42
|
-
napplet.resource.bytes = (url) =>
|
|
43
|
-
request({ type: 'resource.bytes', url: String(url) }, 'resource.bytes.result', 'resource.bytes.error')
|
|
44
|
-
.then((msg) => msg.blob);
|
|
45
|
-
napplet.resource.bytesMany = (urls) =>
|
|
46
|
-
request({ type: 'resource.bytesMany', urls: Array.from(urls || []) }, 'resource.bytesMany.result', 'resource.bytesMany.error')
|
|
47
|
-
.then((msg) => msg.items);
|
|
48
|
-
napplet.resource.bytesAsObjectURL = (url) => {
|
|
49
|
-
const handle = { url: '', revoke: () => {} };
|
|
50
|
-
let objectUrl = '';
|
|
51
|
-
let revoked = false;
|
|
52
|
-
const ready = napplet.resource.bytes(url).then((blob) => {
|
|
53
|
-
if (revoked) return;
|
|
54
|
-
objectUrl = URL.createObjectURL(blob);
|
|
55
|
-
handle.url = objectUrl;
|
|
56
|
-
return objectUrl;
|
|
57
|
-
});
|
|
58
|
-
handle.revoke = () => {
|
|
59
|
-
if (revoked) return;
|
|
60
|
-
revoked = true;
|
|
61
|
-
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
62
|
-
};
|
|
63
|
-
Object.defineProperty(handle, 'ready', { value: ready, enumerable: false });
|
|
64
|
-
return handle;
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
window.napplet = napplet;
|
|
68
|
-
const report = (reason) => {
|
|
69
|
-
try {
|
|
70
|
-
window.parent.postMessage({ type: '${Dt}', reason: String(reason && reason.message || reason) }, '*');
|
|
71
|
-
} catch {}
|
|
72
|
-
};
|
|
73
|
-
window.addEventListener('error', (event) => report(event.error || event.message));
|
|
74
|
-
window.addEventListener('unhandledrejection', (event) => report(event.reason));
|
|
75
|
-
})();
|
|
76
|
-
`}function Pn(e,t,r){const n=`<base href="${qn(t)}">`,i=`<script>${Ln(r)}<\/script>`,s=/<head(?:\s[^>]*)?>/i.exec(e);if(s){const o=s.index+s[0].length;return`${e.slice(0,o)}${n}${i}${e.slice(o)}`}return`${n}${i}${e}`}function _n(e){if(!e.startsWith("data:"))return null;const t=e.indexOf(",");if(t<0)return"";const r=e.slice(0,t),n=e.slice(t+1);return r.endsWith(";base64")?atob(n):decodeURIComponent(n)}async function Cn(e){if(e==="about:blank")return"<!doctype html><html><head></head><body></body></html>";const t=_n(e);if(t!==null)return t;const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch napplet HTML: ${r.status} ${r.statusText}`);return r.text()}async function yt(e,t,r,n){const i=On(),s=r.createElement("iframe");s.setAttribute("sandbox",t.allowSameOrigin?"allow-scripts allow-same-origin":"allow-scripts"),s.setAttribute("aria-hidden","true"),s.style.position="absolute",s.style.width="1px",s.style.height="1px",s.style.left="-9999px";let o=null;const c=u=>{if(u.source!==s.contentWindow)return;const f=u.data;if(f&&typeof f=="object"&&f.type===Dt){o=`napplet boot error: ${String(f.reason??"unknown error")}`;return}const g=i.handle(u.data),b=u.source;for(const y of g)b?.postMessage(y,"*")};let a=!1;const l=new Promise(u=>{s.addEventListener("load",()=>{a=!0,u()},{once:!0})});n.addEventListener("message",c),(r.body??r.documentElement).appendChild(s);try{const u=await Cn(t.url);s.srcdoc=Pn(u,t.url,e)}catch(u){o=u instanceof Error?u.message:String(u)}if(!o){const u=Symbol("timeout");await Promise.race([l.then(()=>"loaded"),mt(t.readyTimeoutMs).then(()=>u)])===u||!a?o=`napplet did not boot (iframe did not load within ${t.readyTimeoutMs}ms; a conformant napplet must run under sandbox="allow-scripts" without allow-same-origin)`:await mt(t.settleMs)}n.removeEventListener("message",c);try{s.remove()}catch{}return{installedGlobal:o===null,bootError:o,emitted:[...i.records]}}async function Un(e){const t=e.document??document,r=e.window??window,n={url:e.url,readyTimeoutMs:e.readyTimeoutMs??5e3,settleMs:e.settleMs,allowSameOrigin:e.allowSameOrigin??!1},i=await yt(it,n,t,r);let s=null;{const o=await yt([],n,t,r);s={bootError:o.bootError,emitted:o.emitted}}return{installedGlobal:i.installedGlobal,bootError:i.bootError,emitted:i.emitted,degraded:s}}var Hn=e=>({status:"pass",detail:e}),jn=(e,t)=>({status:"fail",detail:e,diagnostics:t}),Mn=e=>({status:"skip",detail:e}),O={pass:Hn,fail:jn,skip:Mn};function Dn(e,t){return ot(e.manifestEvent).errors.filter(r=>t.includes(r.code))}function He(e,t,r){return{id:e,area:"manifest",severity:"error",title:t,run:n=>{if(!n.manifestEvent)return O.skip("No NIP-5D manifest event was resolved");const i=Dn(n,r);return i.length?O.fail(i[0].message,i):O.pass()}}}var Zn=[He("manifest/event-kind","Resolved event is a NIP-5D napplet manifest",["invalid-napplet-kind","missing-d-tag","unexpected-d-tag"]),He("manifest/index-html","Manifest declares a hashed /index.html",["missing-index-html","invalid-index-html-hash"]),He("manifest/requires","requires tags are bare known NAP domains",["invalid-required-nap","unknown-required-nap"]),{id:"boot/sandbox-allow-scripts",area:"boot",severity:"error",title:"Runs under allow-scripts without allow-same-origin",run:e=>e.sandbox.allowScripts?e.sandbox.allowSameOrigin?O.fail("Napplet relied on allow-same-origin, which a shell must not grant"):O.pass():O.fail("Napplet was not loaded with allow-scripts")},{id:"boot/installs-global",area:"boot",severity:"error",title:"Runs after runtime-injected window.napplet is installed",run:e=>e.installedGlobal?O.pass():O.fail("runtime did not inject window.napplet before load")},{id:"boot/no-boot-error",area:"boot",severity:"error",title:"Boots without an uncaught error",run:e=>e.bootError?O.fail(e.bootError):O.pass()},{id:"boot/no-forbidden-globals",area:"boot",severity:"error",title:"Does not access forbidden browser authority surfaces",run:e=>e.forbiddenGlobals.length?O.fail(`Accessed forbidden surface(s): ${e.forbiddenGlobals.join(", ")}`,e.forbiddenGlobals):O.pass()},{id:"wire/envelope-well-formed",area:"wire",severity:"error",title:"Every emitted envelope is well-formed",run:e=>{if(e.emitted.length===0)return O.skip("Napplet emitted no envelopes");const t=e.emitted.filter(n=>!n.verdict.ok);if(t.length===0)return O.pass(`${e.emitted.length} envelope(s) valid`);const r=t.map(n=>({envelope:n.envelope,errors:n.verdict.errors}));return O.fail(`${t.length}/${e.emitted.length} emitted envelope(s) invalid`,r)}},{id:"degrade/domain-absence",area:"degradation",severity:"error",title:"Does not crash when no NAP domains are injected",run:e=>e.degraded?e.degraded.bootError?O.fail(`Crashed with no injected domains: ${e.degraded.bootError}`):O.pass():O.skip("Host did not run the degraded (no-capabilities) pass")},{id:"lifecycle/clean-teardown",area:"lifecycle",severity:"warning",title:"Tears down listeners on unload",run:e=>e.lifecycle?e.lifecycle.listenerLeak?O.fail("Message listeners remained after unload"):O.pass():O.skip("Lifecycle not measured")}];function Wn(e,t={}){const r=t.now??(()=>Date.now()),n=t.checks??Zn,i=r(),s=n.map(a=>{const l=a.run(e);return{id:a.id,area:a.area,severity:a.severity,title:a.title,status:l.status,detail:l.detail,diagnostics:l.diagnostics}}),o={total:s.length,passed:s.filter(a=>a.status==="pass").length,failed:s.filter(a=>a.status==="fail").length,skipped:s.filter(a=>a.status==="skip").length,errors:s.filter(a=>a.status==="fail"&&a.severity==="error").length,warnings:s.filter(a=>a.status==="fail"&&a.severity==="warning").length};return{napplet:e.manifestEvent?Mt(e.manifestEvent):void 0,startedAt:i,finishedAt:r(),checks:s,summary:o,ok:o.errors===0}}/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */function Vn(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function at(e,t=""){if(!Number.isSafeInteger(e)||e<0){const r=t&&`"${t}" `;throw new Error(`${r}expected integer >= 0, got ${e}`)}}function M(e,t,r=""){const n=Vn(e),i=e?.length,s=t!==void 0;if(!n||s&&i!==t){const o=r&&`"${r}" `,c=s?` of length ${t}`:"",a=n?`length=${i}`:`type=${typeof e}`;throw new Error(o+"expected Uint8Array"+c+", got "+a)}return e}function wt(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Kn(e,t){M(e,void 0,"digestInto() output");const r=t.outputLen;if(e.length<r)throw new Error('"digestInto() output" expected to be of length >='+r)}function ze(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function je(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function z(e,t){return e<<32-t|e>>>t}const Zt=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Fn=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function _(e){if(M(e),Zt)return e.toHex();let t="";for(let r=0;r<e.length;r++)t+=Fn[e[r]];return t}const J={_0:48,_9:57,A:65,F:70,a:97,f:102};function vt(e){if(e>=J._0&&e<=J._9)return e-J._0;if(e>=J.A&&e<=J.F)return e-(J.A-10);if(e>=J.a&&e<=J.f)return e-(J.a-10)}function X(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);if(Zt)return Uint8Array.fromHex(e);const t=e.length,r=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);const n=new Uint8Array(r);for(let i=0,s=0;i<r;i++,s+=2){const o=vt(e.charCodeAt(s)),c=vt(e.charCodeAt(s+1));if(o===void 0||c===void 0){const a=e[s]+e[s+1];throw new Error('hex string expected, got non-hex character "'+a+'" at index '+s)}n[i]=o*16+c}return n}function Be(...e){let t=0;for(let n=0;n<e.length;n++){const i=e[n];M(i),t+=i.length}const r=new Uint8Array(t);for(let n=0,i=0;n<e.length;n++){const s=e[n];r.set(s,i),i+=s.length}return r}function Yn(e,t={}){const r=(i,s)=>e(s).update(i).digest(),n=e(void 0);return r.outputLen=n.outputLen,r.blockLen=n.blockLen,r.create=i=>e(i),Object.assign(r,t),Object.freeze(r)}function Wt(e=32){const t=typeof globalThis=="object"?globalThis.crypto:null;if(typeof t?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");return t.getRandomValues(new Uint8Array(e))}const zn=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */function Vt(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Kt(e,t){return Array.isArray(t)?t.length===0?!0:e?t.every(r=>typeof r=="string"):t.every(r=>Number.isSafeInteger(r)):!1}function Gn(e){if(typeof e!="function")throw new Error("function expected");return!0}function me(e,t){if(typeof t!="string")throw new Error(`${e}: string expected`);return!0}function Ft(e){if(!Number.isSafeInteger(e))throw new Error(`invalid integer: ${e}`)}function Ge(e){if(!Array.isArray(e))throw new Error("array expected")}function Yt(e,t){if(!Kt(!0,t))throw new Error(`${e}: array of strings expected`)}function zt(e,t){if(!Kt(!1,t))throw new Error(`${e}: array of numbers expected`)}function Xn(...e){const t=s=>s,r=(s,o)=>c=>s(o(c)),n=e.map(s=>s.encode).reduceRight(r,t),i=e.map(s=>s.decode).reduce(r,t);return{encode:n,decode:i}}function Jn(e){const t=typeof e=="string"?e.split(""):e,r=t.length;Yt("alphabet",t);const n=new Map(t.map((i,s)=>[i,s]));return{encode:i=>(Ge(i),i.map(s=>{if(!Number.isSafeInteger(s)||s<0||s>=r)throw new Error(`alphabet.encode: digit index outside alphabet "${s}". Allowed: ${e}`);return t[s]})),decode:i=>(Ge(i),i.map(s=>{me("alphabet.decode",s);const o=n.get(s);if(o===void 0)throw new Error(`Unknown letter: "${s}". Allowed: ${e}`);return o}))}}function Qn(e=""){return me("join",e),{encode:t=>(Yt("join.decode",t),t.join(e)),decode:t=>(me("join.decode",t),t.split(e))}}const Gt=(e,t)=>t===0?e:Gt(t,e%t),Ie=(e,t)=>e+(t-Gt(e,t)),$e=(()=>{let e=[];for(let t=0;t<40;t++)e.push(2**t);return e})();function Xe(e,t,r,n){if(Ge(e),t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(r<=0||r>32)throw new Error(`convertRadix2: wrong to=${r}`);if(Ie(t,r)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${r} carryBits=${Ie(t,r)}`);let i=0,s=0;const o=$e[t],c=$e[r]-1,a=[];for(const l of e){if(Ft(l),l>=o)throw new Error(`convertRadix2: invalid data word=${l} from=${t}`);if(i=i<<t|l,s+t>32)throw new Error(`convertRadix2: carry overflow pos=${s} from=${t}`);for(s+=t;s>=r;s-=r)a.push((i>>s-r&c)>>>0);const u=$e[s];if(u===void 0)throw new Error("invalid carry");i&=u-1}if(i=i<<r-s&c,!n&&s>=t)throw new Error("Excess padding");if(!n&&i>0)throw new Error(`Non-zero padding: ${i}`);return n&&s>0&&a.push(i>>>0),a}function er(e,t=!1){if(Ft(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(Ie(8,e)>32||Ie(e,8)>32)throw new Error("radix2: carry overflow");return{encode:r=>{if(!Vt(r))throw new Error("radix2.encode input should be Uint8Array");return Xe(Array.from(r),8,e,!t)},decode:r=>(zt("radix2.decode",r),Uint8Array.from(Xe(r,e,8,t)))}}function Et(e){return Gn(e),function(...t){try{return e.apply(null,t)}catch{}}}const Je=Xn(Jn("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),Qn("")),xt=[996825010,642813549,513874426,1027748829,705979059];function fe(e){const t=e>>25;let r=(e&33554431)<<5;for(let n=0;n<xt.length;n++)(t>>n&1)===1&&(r^=xt[n]);return r}function kt(e,t,r=1){const n=e.length;let i=1;for(let s=0;s<n;s++){const o=e.charCodeAt(s);if(o<33||o>126)throw new Error(`Invalid prefix (${e})`);i=fe(i)^o>>5}i=fe(i);for(let s=0;s<n;s++)i=fe(i)^e.charCodeAt(s)&31;for(let s of t)i=fe(i)^s;for(let s=0;s<6;s++)i=fe(i);return i^=r,Je.encode(Xe([i%$e[30]],30,5,!1))}function tr(e){const t=e==="bech32"?1:734539939,r=er(5),n=r.decode,i=r.encode,s=Et(n);function o(f,g,b=90){me("bech32.encode prefix",f),Vt(g)&&(g=Array.from(g)),zt("bech32.encode",g);const y=f.length;if(y===0)throw new TypeError(`Invalid prefix length ${y}`);const E=y+7+g.length;if(b!==!1&&E>b)throw new TypeError(`Length ${E} exceeds limit ${b}`);const N=f.toLowerCase(),L=kt(N,g,t);return`${N}1${Je.encode(g)}${L}`}function c(f,g=90){me("bech32.decode input",f);const b=f.length;if(b<8||g!==!1&&b>g)throw new TypeError(`invalid string length: ${b} (${f}). Expected (8..${g})`);const y=f.toLowerCase();if(f!==y&&f!==f.toUpperCase())throw new Error("String must be lowercase or uppercase");const E=y.lastIndexOf("1");if(E===0||E===-1)throw new Error('Letter "1" must be present between prefix and data only');const N=y.slice(0,E),L=y.slice(E+1);if(L.length<6)throw new Error("Data must be at least 6 characters long");const F=Je.decode(L).slice(0,-6),Q=kt(N,F,t);if(!L.endsWith(Q))throw new Error(`Invalid checksum in ${f}: expected "${Q}"`);return{prefix:N,words:F}}const a=Et(c);function l(f){const{prefix:g,words:b}=c(f,!1);return{prefix:g,words:b,bytes:n(b)}}function u(f,g){return o(f,i(g))}return{encode:o,decode:c,encodeFromBytes:u,decodeToBytes:l,decodeUnsafe:a,fromWords:n,fromWordsUnsafe:s,toWords:i}}const St=tr("bech32");var ke=new TextDecoder("utf-8");new TextEncoder;var nr=5e3;function rr(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),ir(e)}catch{return{type:"invalid",data:null}}}function ir(e){let{prefix:t,words:r}=St.decode(e,nr),n=new Uint8Array(St.fromWords(r));switch(t){case"nprofile":{let i=Me(n);if(!i[0]?.[0])throw new Error("missing TLV 0 for nprofile");if(i[0][0].length!==32)throw new Error("TLV 0 should be 32 bytes");return{type:"nprofile",data:{pubkey:_(i[0][0]),relays:i[1]?i[1].map(s=>ke.decode(s)):[]}}}case"nevent":{let i=Me(n);if(!i[0]?.[0])throw new Error("missing TLV 0 for nevent");if(i[0][0].length!==32)throw new Error("TLV 0 should be 32 bytes");if(i[2]&&i[2][0].length!==32)throw new Error("TLV 2 should be 32 bytes");if(i[3]&&i[3][0].length!==4)throw new Error("TLV 3 should be 4 bytes");return{type:"nevent",data:{id:_(i[0][0]),relays:i[1]?i[1].map(s=>ke.decode(s)):[],author:i[2]?.[0]?_(i[2][0]):void 0,kind:i[3]?.[0]?parseInt(_(i[3][0]),16):void 0}}}case"naddr":{let i=Me(n);if(!i[0]?.[0])throw new Error("missing TLV 0 for naddr");if(!i[2]?.[0])throw new Error("missing TLV 2 for naddr");if(i[2][0].length!==32)throw new Error("TLV 2 should be 32 bytes");if(!i[3]?.[0])throw new Error("missing TLV 3 for naddr");if(i[3][0].length!==4)throw new Error("TLV 3 should be 4 bytes");return{type:"naddr",data:{identifier:ke.decode(i[0][0]),pubkey:_(i[2][0]),kind:parseInt(_(i[3][0]),16),relays:i[1]?i[1].map(s=>ke.decode(s)):[]}}}case"nsec":return{type:t,data:n};case"npub":case"note":return{type:t,data:_(n)};default:throw new Error(`unknown prefix ${t}`)}}function Me(e){let t={},r=e;for(;r.length>0;){let n=r[0],i=r[1],s=r.slice(2,2+i);if(r=r.slice(2+i),s.length<i)throw new Error(`not enough data to read on TLV ${n}`);t[n]=t[n]||[],t[n].push(s)}return t}function sr(e,t,r){return e&t^~e&r}function or(e,t,r){return e&t^e&r^t&r}class ar{blockLen;outputLen;padOffset;isLE;buffer;view;finished=!1;length=0;pos=0;destroyed=!1;constructor(t,r,n,i){this.blockLen=t,this.outputLen=r,this.padOffset=n,this.isLE=i,this.buffer=new Uint8Array(t),this.view=je(this.buffer)}update(t){wt(this),M(t);const{view:r,buffer:n,blockLen:i}=this,s=t.length;for(let o=0;o<s;){const c=Math.min(i-this.pos,s-o);if(c===i){const a=je(t);for(;i<=s-o;o+=i)this.process(a,o);continue}n.set(t.subarray(o,o+c),this.pos),this.pos+=c,o+=c,this.pos===i&&(this.process(r,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){wt(this),Kn(t,this),this.finished=!0;const{buffer:r,view:n,blockLen:i,isLE:s}=this;let{pos:o}=this;r[o++]=128,ze(this.buffer.subarray(o)),this.padOffset>i-o&&(this.process(n,0),o=0);for(let f=o;f<i;f++)r[f]=0;n.setBigUint64(i-8,BigInt(this.length*8),s),this.process(n,0);const c=je(t),a=this.outputLen;if(a%4)throw new Error("_sha2: outputLen must be aligned to 32bit");const l=a/4,u=this.get();if(l>u.length)throw new Error("_sha2: outputLen bigger than state");for(let f=0;f<l;f++)c.setUint32(4*f,u[f],s)}digest(){const{buffer:t,outputLen:r}=this;this.digestInto(t);const n=t.slice(0,r);return this.destroy(),n}_cloneInto(t){t||=new this.constructor,t.set(...this.get());const{blockLen:r,buffer:n,length:i,finished:s,destroyed:o,pos:c}=this;return t.destroyed=o,t.finished=s,t.length=i,t.pos=c,i%r&&t.buffer.set(n),t}clone(){return this._cloneInto()}}const ee=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),cr=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),te=new Uint32Array(64);class lr extends ar{constructor(t){super(64,t,8,!1)}get(){const{A:t,B:r,C:n,D:i,E:s,F:o,G:c,H:a}=this;return[t,r,n,i,s,o,c,a]}set(t,r,n,i,s,o,c,a){this.A=t|0,this.B=r|0,this.C=n|0,this.D=i|0,this.E=s|0,this.F=o|0,this.G=c|0,this.H=a|0}process(t,r){for(let f=0;f<16;f++,r+=4)te[f]=t.getUint32(r,!1);for(let f=16;f<64;f++){const g=te[f-15],b=te[f-2],y=z(g,7)^z(g,18)^g>>>3,E=z(b,17)^z(b,19)^b>>>10;te[f]=E+te[f-7]+y+te[f-16]|0}let{A:n,B:i,C:s,D:o,E:c,F:a,G:l,H:u}=this;for(let f=0;f<64;f++){const g=z(c,6)^z(c,11)^z(c,25),b=u+g+sr(c,a,l)+cr[f]+te[f]|0,E=(z(n,2)^z(n,13)^z(n,22))+or(n,i,s)|0;u=l,l=a,a=c,c=o+b|0,o=s,s=i,i=n,n=b+E|0}n=n+this.A|0,i=i+this.B|0,s=s+this.C|0,o=o+this.D|0,c=c+this.E|0,a=a+this.F|0,l=l+this.G|0,u=u+this.H|0,this.set(n,i,s,o,c,a,l,u)}roundClean(){ze(te)}destroy(){this.set(0,0,0,0,0,0,0,0),ze(this.buffer)}}class dr extends lr{A=ee[0]|0;B=ee[1]|0;C=ee[2]|0;D=ee[3]|0;E=ee[4]|0;F=ee[5]|0;G=ee[6]|0;H=ee[7]|0;constructor(){super(32)}}const Ae=Yn(()=>new dr,zn(1));/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const ct=BigInt(0),Qe=BigInt(1);function Rt(e,t=""){if(typeof e!="boolean"){const r=t&&`"${t}" `;throw new Error(r+"expected boolean, got type="+typeof e)}return e}function ur(e){if(typeof e=="bigint"){if(!pr(e))throw new Error("positive bigint expected, got "+e)}else at(e);return e}function Xt(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);return e===""?ct:BigInt("0x"+e)}function lt(e){return Xt(_(e))}function Jt(e){return Xt(_(fr(M(e)).reverse()))}function dt(e,t){at(t),e=ur(e);const r=X(e.toString(16).padStart(t*2,"0"));if(r.length!==t)throw new Error("number too large");return r}function Qt(e,t){return dt(e,t).reverse()}function fr(e){return Uint8Array.from(e)}function hr(e){return Uint8Array.from(e,(t,r)=>{const n=t.charCodeAt(0);if(t.length!==1||n>127)throw new Error(`string contains non-ASCII character "${e[r]}" with code ${n} at position ${r}`);return n})}const pr=e=>typeof e=="bigint"&&ct<=e;function gr(e){let t;for(t=0;e>ct;e>>=Qe,t+=1);return t}const en=e=>(Qe<<BigInt(e))-Qe;function tn(e,t={},r={}){if(!e||typeof e!="object")throw new Error("expected valid options object");function n(s,o,c){const a=e[s];if(c&&a===void 0)return;const l=typeof a;if(l!==o||a===null)throw new Error(`param "${s}" is invalid: expected ${o}, got ${l}`)}const i=(s,o)=>Object.entries(s).forEach(([c,a])=>n(c,a,o));i(t,!1),i(r,!0)}function $t(e){const t=new WeakMap;return(r,...n)=>{const i=t.get(r);if(i!==void 0)return i;const s=e(r,...n);return t.set(r,s),s}}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const j=BigInt(0),H=BigInt(1),se=BigInt(2),nn=BigInt(3),rn=BigInt(4),sn=BigInt(5),br=BigInt(7),on=BigInt(8),mr=BigInt(9),an=BigInt(16);function K(e,t){const r=e%t;return r>=j?r:t+r}function Z(e,t,r){let n=e;for(;t-- >j;)n*=n,n%=r;return n}function Tt(e,t){if(e===j)throw new Error("invert: expected non-zero number");if(t<=j)throw new Error("invert: expected positive modulus, got "+t);let r=K(e,t),n=t,i=j,s=H;for(;r!==j;){const c=n/r,a=n%r,l=i-s*c;n=r,r=a,i=s,s=l}if(n!==H)throw new Error("invert: does not exist");return K(i,t)}function ut(e,t,r){if(!e.eql(e.sqr(t),r))throw new Error("Cannot find square root")}function cn(e,t){const r=(e.ORDER+H)/rn,n=e.pow(t,r);return ut(e,n,t),n}function yr(e,t){const r=(e.ORDER-sn)/on,n=e.mul(t,se),i=e.pow(n,r),s=e.mul(t,i),o=e.mul(e.mul(s,se),i),c=e.mul(s,e.sub(o,e.ONE));return ut(e,c,t),c}function wr(e){const t=Le(e),r=ln(e),n=r(t,t.neg(t.ONE)),i=r(t,n),s=r(t,t.neg(n)),o=(e+br)/an;return(c,a)=>{let l=c.pow(a,o),u=c.mul(l,n);const f=c.mul(l,i),g=c.mul(l,s),b=c.eql(c.sqr(u),a),y=c.eql(c.sqr(f),a);l=c.cmov(l,u,b),u=c.cmov(g,f,y);const E=c.eql(c.sqr(u),a),N=c.cmov(l,u,E);return ut(c,N,a),N}}function ln(e){if(e<nn)throw new Error("sqrt is not defined for small field");let t=e-H,r=0;for(;t%se===j;)t/=se,r++;let n=se;const i=Le(e);for(;Bt(i,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(r===1)return cn;let s=i.pow(n,t);const o=(t+H)/se;return function(a,l){if(a.is0(l))return l;if(Bt(a,l)!==1)throw new Error("Cannot find square root");let u=r,f=a.mul(a.ONE,s),g=a.pow(l,t),b=a.pow(l,o);for(;!a.eql(g,a.ONE);){if(a.is0(g))return a.ZERO;let y=1,E=a.sqr(g);for(;!a.eql(E,a.ONE);)if(y++,E=a.sqr(E),y===u)throw new Error("Cannot find square root");const N=H<<BigInt(u-y-1),L=a.pow(f,N);u=y,f=a.sqr(L),g=a.mul(g,f),b=a.mul(b,L)}return b}}function vr(e){return e%rn===nn?cn:e%on===sn?yr:e%an===mr?wr(e):ln(e)}const Er=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function xr(e){const t={ORDER:"bigint",BYTES:"number",BITS:"number"},r=Er.reduce((n,i)=>(n[i]="function",n),t);return tn(e,r),e}function kr(e,t,r){if(r<j)throw new Error("invalid exponent, negatives unsupported");if(r===j)return e.ONE;if(r===H)return t;let n=e.ONE,i=t;for(;r>j;)r&H&&(n=e.mul(n,i)),i=e.sqr(i),r>>=H;return n}function dn(e,t,r=!1){const n=new Array(t.length).fill(r?e.ZERO:void 0),i=t.reduce((o,c,a)=>e.is0(c)?o:(n[a]=o,e.mul(o,c)),e.ONE),s=e.inv(i);return t.reduceRight((o,c,a)=>e.is0(c)?o:(n[a]=e.mul(o,n[a]),e.mul(o,c)),s),n}function Bt(e,t){const r=(e.ORDER-H)/se,n=e.pow(t,r),i=e.eql(n,e.ONE),s=e.eql(n,e.ZERO),o=e.eql(n,e.neg(e.ONE));if(!i&&!s&&!o)throw new Error("invalid Legendre symbol result");return i?1:s?0:-1}function Sr(e,t){t!==void 0&&at(t);const r=t!==void 0?t:e.toString(2).length,n=Math.ceil(r/8);return{nBitLength:r,nByteLength:n}}class Rr{ORDER;BITS;BYTES;isLE;ZERO=j;ONE=H;_lengths;_sqrt;_mod;constructor(t,r={}){if(t<=j)throw new Error("invalid field: expected ORDER > 0, got "+t);let n;this.isLE=!1,r!=null&&typeof r=="object"&&(typeof r.BITS=="number"&&(n=r.BITS),typeof r.sqrt=="function"&&(this.sqrt=r.sqrt),typeof r.isLE=="boolean"&&(this.isLE=r.isLE),r.allowedLengths&&(this._lengths=r.allowedLengths?.slice()),typeof r.modFromBytes=="boolean"&&(this._mod=r.modFromBytes));const{nBitLength:i,nByteLength:s}=Sr(t,n);if(s>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=t,this.BITS=i,this.BYTES=s,this._sqrt=void 0,Object.preventExtensions(this)}create(t){return K(t,this.ORDER)}isValid(t){if(typeof t!="bigint")throw new Error("invalid field element: expected bigint, got "+typeof t);return j<=t&&t<this.ORDER}is0(t){return t===j}isValidNot0(t){return!this.is0(t)&&this.isValid(t)}isOdd(t){return(t&H)===H}neg(t){return K(-t,this.ORDER)}eql(t,r){return t===r}sqr(t){return K(t*t,this.ORDER)}add(t,r){return K(t+r,this.ORDER)}sub(t,r){return K(t-r,this.ORDER)}mul(t,r){return K(t*r,this.ORDER)}pow(t,r){return kr(this,t,r)}div(t,r){return K(t*Tt(r,this.ORDER),this.ORDER)}sqrN(t){return t*t}addN(t,r){return t+r}subN(t,r){return t-r}mulN(t,r){return t*r}inv(t){return Tt(t,this.ORDER)}sqrt(t){return this._sqrt||(this._sqrt=vr(this.ORDER)),this._sqrt(this,t)}toBytes(t){return this.isLE?Qt(t,this.BYTES):dt(t,this.BYTES)}fromBytes(t,r=!1){M(t);const{_lengths:n,BYTES:i,isLE:s,ORDER:o,_mod:c}=this;if(n){if(!n.includes(t.length)||t.length>i)throw new Error("Field.fromBytes: expected "+n+" bytes, got "+t.length);const l=new Uint8Array(i);l.set(t,s?0:l.length-t.length),t=l}if(t.length!==i)throw new Error("Field.fromBytes: expected "+i+" bytes, got "+t.length);let a=s?Jt(t):lt(t);if(c&&(a=K(a,o)),!r&&!this.isValid(a))throw new Error("invalid field element: outside of range 0..ORDER");return a}invertBatch(t){return dn(this,t)}cmov(t,r,n){return n?r:t}}function Le(e,t={}){return new Rr(e,t)}function un(e){if(typeof e!="bigint")throw new Error("field order must be bigint");const t=e.toString(2).length;return Math.ceil(t/8)}function $r(e){const t=un(e);return t+Math.ceil(t/2)}function Tr(e,t,r=!1){M(e);const n=e.length,i=un(t),s=$r(t);if(n<16||n<s||n>1024)throw new Error("expected "+s+"-1024 bytes of input, got "+n);const o=r?Jt(e):lt(e),c=K(o,t-H)+H;return r?Qt(c,i):dt(c,i)}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const le=BigInt(0),oe=BigInt(1);function Oe(e,t){const r=t.negate();return e?r:t}function It(e,t){const r=dn(e.Fp,t.map(n=>n.Z));return t.map((n,i)=>e.fromAffine(n.toAffine(r[i])))}function fn(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw new Error("invalid window size, expected [1.."+t+"], got W="+e)}function De(e,t){fn(e,t);const r=Math.ceil(t/e)+1,n=2**(e-1),i=2**e,s=en(e),o=BigInt(e);return{windows:r,windowSize:n,mask:s,maxNumber:i,shiftBy:o}}function At(e,t,r){const{windowSize:n,mask:i,maxNumber:s,shiftBy:o}=r;let c=Number(e&i),a=e>>o;c>n&&(c-=s,a+=oe);const l=t*n,u=l+Math.abs(c)-1,f=c===0,g=c<0,b=t%2!==0;return{nextN:a,offset:u,isZero:f,isNeg:g,isNegF:b,offsetF:l}}const Ze=new WeakMap,hn=new WeakMap;function We(e){return hn.get(e)||1}function Ot(e){if(e!==le)throw new Error("invalid wNAF")}class Br{BASE;ZERO;Fn;bits;constructor(t,r){this.BASE=t.BASE,this.ZERO=t.ZERO,this.Fn=t.Fn,this.bits=r}_unsafeLadder(t,r,n=this.ZERO){let i=t;for(;r>le;)r&oe&&(n=n.add(i)),i=i.double(),r>>=oe;return n}precomputeWindow(t,r){const{windows:n,windowSize:i}=De(r,this.bits),s=[];let o=t,c=o;for(let a=0;a<n;a++){c=o,s.push(c);for(let l=1;l<i;l++)c=c.add(o),s.push(c);o=c.double()}return s}wNAF(t,r,n){if(!this.Fn.isValid(n))throw new Error("invalid scalar");let i=this.ZERO,s=this.BASE;const o=De(t,this.bits);for(let c=0;c<o.windows;c++){const{nextN:a,offset:l,isZero:u,isNeg:f,isNegF:g,offsetF:b}=At(n,c,o);n=a,u?s=s.add(Oe(g,r[b])):i=i.add(Oe(f,r[l]))}return Ot(n),{p:i,f:s}}wNAFUnsafe(t,r,n,i=this.ZERO){const s=De(t,this.bits);for(let o=0;o<s.windows&&n!==le;o++){const{nextN:c,offset:a,isZero:l,isNeg:u}=At(n,o,s);if(n=c,!l){const f=r[a];i=i.add(u?f.negate():f)}}return Ot(n),i}getPrecomputes(t,r,n){let i=Ze.get(r);return i||(i=this.precomputeWindow(r,t),t!==1&&(typeof n=="function"&&(i=n(i)),Ze.set(r,i))),i}cached(t,r,n){const i=We(t);return this.wNAF(i,this.getPrecomputes(i,t,n),r)}unsafe(t,r,n,i){const s=We(t);return s===1?this._unsafeLadder(t,r,i):this.wNAFUnsafe(s,this.getPrecomputes(s,t,n),r,i)}createCache(t,r){fn(r,this.bits),hn.set(t,r),Ze.delete(t)}hasCache(t){return We(t)!==1}}function Ir(e,t,r,n){let i=t,s=e.ZERO,o=e.ZERO;for(;r>le||n>le;)r&oe&&(s=s.add(i)),n&oe&&(o=o.add(i)),i=i.double(),r>>=oe,n>>=oe;return{p1:s,p2:o}}function Nt(e,t,r){if(t){if(t.ORDER!==e)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return xr(t),t}else return Le(e,{isLE:r})}function Ar(e,t,r={},n){if(n===void 0&&(n=e==="edwards"),!t||typeof t!="object")throw new Error(`expected valid ${e} CURVE object`);for(const a of["p","n","h"]){const l=t[a];if(!(typeof l=="bigint"&&l>le))throw new Error(`CURVE.${a} must be positive bigint`)}const i=Nt(t.p,r.Fp,n),s=Nt(t.n,r.Fn,n),c=["Gx","Gy","a","b"];for(const a of c)if(!i.isValid(t[a]))throw new Error(`CURVE.${a} must be valid field element of CURVE.Fp`);return t=Object.freeze(Object.assign({},t)),{CURVE:t,Fp:i,Fn:s}}function Or(e,t){return function(n){const i=e(n);return{secretKey:i,publicKey:t(i)}}}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const qt=(e,t)=>(e+(e>=0?t:-t)/qr)/t;function Nr(e,t,r){const[[n,i],[s,o]]=t,c=qt(o*e,r),a=qt(-i*e,r);let l=e-c*n-a*s,u=-c*i-a*o;const f=l<he,g=u<he;f&&(l=-l),g&&(u=-u);const b=en(Math.ceil(gr(r)/2))+Te;if(l<he||l>=b||u<he||u>=b)throw new Error("splitScalar (endomorphism): failed, k="+e);return{k1neg:f,k1:l,k2neg:g,k2:u}}const he=BigInt(0),Te=BigInt(1),qr=BigInt(2),Se=BigInt(3),Lr=BigInt(4);function Pr(e,t={}){const r=Ar("weierstrass",e,t),{Fp:n,Fn:i}=r;let s=r.CURVE;const{h:o,n:c}=s;tn(t,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object"});const{endo:a}=t;if(a&&(!n.is0(s.a)||typeof a.beta!="bigint"||!Array.isArray(a.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');const l=Cr(n,i);function u(){if(!n.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function f(T,h,m){const{x:v,y:x}=h.toAffine(),B=n.toBytes(v);if(Rt(m,"isCompressed"),m){u();const R=!n.isOdd(x);return Be(_r(R),B)}else return Be(Uint8Array.of(4),B,n.toBytes(x))}function g(T){M(T,void 0,"Point");const{publicKey:h,publicKeyUncompressed:m}=l,v=T.length,x=T[0],B=T.subarray(1);if(v===h&&(x===2||x===3)){const R=n.fromBytes(B);if(!n.isValid(R))throw new Error("bad point: is not on curve, wrong x");const k=E(R);let w;try{w=n.sqrt(k)}catch(D){const P=D instanceof Error?": "+D.message:"";throw new Error("bad point: is not on curve, sqrt error"+P)}u();const S=n.isOdd(w);return(x&1)===1!==S&&(w=n.neg(w)),{x:R,y:w}}else if(v===m&&x===4){const R=n.BYTES,k=n.fromBytes(B.subarray(0,R)),w=n.fromBytes(B.subarray(R,R*2));if(!N(k,w))throw new Error("bad point: is not on curve");return{x:k,y:w}}else throw new Error(`bad point: got length ${v}, expected compressed=${h} or uncompressed=${m}`)}const b=t.toBytes||f,y=t.fromBytes||g;function E(T){const h=n.sqr(T),m=n.mul(h,T);return n.add(n.add(m,n.mul(T,s.a)),s.b)}function N(T,h){const m=n.sqr(h),v=E(T);return n.eql(m,v)}if(!N(s.Gx,s.Gy))throw new Error("bad curve params: generator point");const L=n.mul(n.pow(s.a,Se),Lr),F=n.mul(n.sqr(s.b),BigInt(27));if(n.is0(n.add(L,F)))throw new Error("bad curve params: a or b");function Q(T,h,m=!1){if(!n.isValid(h)||m&&n.is0(h))throw new Error(`bad point coordinate ${T}`);return h}function we(T){if(!(T instanceof A))throw new Error("Weierstrass Point expected")}function ve(T){if(!a||!a.basises)throw new Error("no endo");return Nr(T,a.basises,i.ORDER)}const Ee=$t((T,h)=>{const{X:m,Y:v,Z:x}=T;if(n.eql(x,n.ONE))return{x:m,y:v};const B=T.is0();h==null&&(h=B?n.ONE:n.inv(x));const R=n.mul(m,h),k=n.mul(v,h),w=n.mul(x,h);if(B)return{x:n.ZERO,y:n.ZERO};if(!n.eql(w,n.ONE))throw new Error("invZ was invalid");return{x:R,y:k}}),xn=$t(T=>{if(T.is0()){if(t.allowInfinityPoint&&!n.is0(T.Y))return;throw new Error("bad point: ZERO")}const{x:h,y:m}=T.toAffine();if(!n.isValid(h)||!n.isValid(m))throw new Error("bad point: x or y not field elements");if(!N(h,m))throw new Error("bad point: equation left != right");if(!T.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});function pt(T,h,m,v,x){return m=new A(n.mul(m.X,T),m.Y,m.Z),h=Oe(v,h),m=Oe(x,m),h.add(m)}class A{static BASE=new A(s.Gx,s.Gy,n.ONE);static ZERO=new A(n.ZERO,n.ONE,n.ZERO);static Fp=n;static Fn=i;X;Y;Z;constructor(h,m,v){this.X=Q("x",h),this.Y=Q("y",m,!0),this.Z=Q("z",v),Object.freeze(this)}static CURVE(){return s}static fromAffine(h){const{x:m,y:v}=h||{};if(!h||!n.isValid(m)||!n.isValid(v))throw new Error("invalid affine point");if(h instanceof A)throw new Error("projective point not allowed");return n.is0(m)&&n.is0(v)?A.ZERO:new A(m,v,n.ONE)}static fromBytes(h){const m=A.fromAffine(y(M(h,void 0,"point")));return m.assertValidity(),m}static fromHex(h){return A.fromBytes(X(h))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(h=8,m=!0){return ue.createCache(this,h),m||this.multiply(Se),this}assertValidity(){xn(this)}hasEvenY(){const{y:h}=this.toAffine();if(!n.isOdd)throw new Error("Field doesn't support isOdd");return!n.isOdd(h)}equals(h){we(h);const{X:m,Y:v,Z:x}=this,{X:B,Y:R,Z:k}=h,w=n.eql(n.mul(m,k),n.mul(B,x)),S=n.eql(n.mul(v,k),n.mul(R,x));return w&&S}negate(){return new A(this.X,n.neg(this.Y),this.Z)}double(){const{a:h,b:m}=s,v=n.mul(m,Se),{X:x,Y:B,Z:R}=this;let k=n.ZERO,w=n.ZERO,S=n.ZERO,$=n.mul(x,x),D=n.mul(B,B),P=n.mul(R,R),I=n.mul(x,B);return I=n.add(I,I),S=n.mul(x,R),S=n.add(S,S),k=n.mul(h,S),w=n.mul(v,P),w=n.add(k,w),k=n.sub(D,w),w=n.add(D,w),w=n.mul(k,w),k=n.mul(I,k),S=n.mul(v,S),P=n.mul(h,P),I=n.sub($,P),I=n.mul(h,I),I=n.add(I,S),S=n.add($,$),$=n.add(S,$),$=n.add($,P),$=n.mul($,I),w=n.add(w,$),P=n.mul(B,R),P=n.add(P,P),$=n.mul(P,I),k=n.sub(k,$),S=n.mul(P,D),S=n.add(S,S),S=n.add(S,S),new A(k,w,S)}add(h){we(h);const{X:m,Y:v,Z:x}=this,{X:B,Y:R,Z:k}=h;let w=n.ZERO,S=n.ZERO,$=n.ZERO;const D=s.a,P=n.mul(s.b,Se);let I=n.mul(m,B),W=n.mul(v,R),V=n.mul(x,k),ae=n.add(m,v),U=n.add(B,R);ae=n.mul(ae,U),U=n.add(I,W),ae=n.sub(ae,U),U=n.add(m,x);let Y=n.add(B,k);return U=n.mul(U,Y),Y=n.add(I,V),U=n.sub(U,Y),Y=n.add(v,x),w=n.add(R,k),Y=n.mul(Y,w),w=n.add(W,V),Y=n.sub(Y,w),$=n.mul(D,U),w=n.mul(P,V),$=n.add(w,$),w=n.sub(W,$),$=n.add(W,$),S=n.mul(w,$),W=n.add(I,I),W=n.add(W,I),V=n.mul(D,V),U=n.mul(P,U),W=n.add(W,V),V=n.sub(I,V),V=n.mul(D,V),U=n.add(U,V),I=n.mul(W,U),S=n.add(S,I),I=n.mul(Y,U),w=n.mul(ae,w),w=n.sub(w,I),I=n.mul(ae,W),$=n.mul(Y,$),$=n.add($,I),new A(w,S,$)}subtract(h){return this.add(h.negate())}is0(){return this.equals(A.ZERO)}multiply(h){const{endo:m}=t;if(!i.isValidNot0(h))throw new Error("invalid scalar: out of range");let v,x;const B=R=>ue.cached(this,R,k=>It(A,k));if(m){const{k1neg:R,k1:k,k2neg:w,k2:S}=ve(h),{p:$,f:D}=B(k),{p:P,f:I}=B(S);x=D.add(I),v=pt(m.beta,$,P,R,w)}else{const{p:R,f:k}=B(h);v=R,x=k}return It(A,[v,x])[0]}multiplyUnsafe(h){const{endo:m}=t,v=this;if(!i.isValid(h))throw new Error("invalid scalar: out of range");if(h===he||v.is0())return A.ZERO;if(h===Te)return v;if(ue.hasCache(this))return this.multiply(h);if(m){const{k1neg:x,k1:B,k2neg:R,k2:k}=ve(h),{p1:w,p2:S}=Ir(A,v,B,k);return pt(m.beta,w,S,x,R)}else return ue.unsafe(v,h)}toAffine(h){return Ee(this,h)}isTorsionFree(){const{isTorsionFree:h}=t;return o===Te?!0:h?h(A,this):ue.unsafe(this,c).is0()}clearCofactor(){const{clearCofactor:h}=t;return o===Te?this:h?h(A,this):this.multiplyUnsafe(o)}isSmallOrder(){return this.multiplyUnsafe(o).is0()}toBytes(h=!0){return Rt(h,"isCompressed"),this.assertValidity(),b(A,this,h)}toHex(h=!0){return _(this.toBytes(h))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}const gt=i.BITS,ue=new Br(A,t.endo?Math.ceil(gt/2):gt);return A.BASE.precompute(8),A}function _r(e){return Uint8Array.of(e?2:3)}function Cr(e,t){return{secretKey:t.BYTES,publicKey:1+e.BYTES,publicKeyUncompressed:1+2*e.BYTES,publicKeyHasPrefix:!0,signature:2*t.BYTES}}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const Pe={p:BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),n:BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),h:BigInt(1),a:BigInt(0),b:BigInt(7),Gx:BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),Gy:BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")},Ur={beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),basises:[[BigInt("0x3086d221a7d46bcde86c90e49284eb15"),-BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),BigInt("0x3086d221a7d46bcde86c90e49284eb15")]]},Hr=BigInt(0),et=BigInt(2);function jr(e){const t=Pe.p,r=BigInt(3),n=BigInt(6),i=BigInt(11),s=BigInt(22),o=BigInt(23),c=BigInt(44),a=BigInt(88),l=e*e*e%t,u=l*l*e%t,f=Z(u,r,t)*u%t,g=Z(f,r,t)*u%t,b=Z(g,et,t)*l%t,y=Z(b,i,t)*b%t,E=Z(y,s,t)*y%t,N=Z(E,c,t)*E%t,L=Z(N,a,t)*N%t,F=Z(L,c,t)*E%t,Q=Z(F,r,t)*u%t,we=Z(Q,o,t)*y%t,ve=Z(we,n,t)*l%t,Ee=Z(ve,et,t);if(!Ne.eql(Ne.sqr(Ee),e))throw new Error("Cannot find square root");return Ee}const Ne=Le(Pe.p,{sqrt:jr}),de=Pr(Pe,{Fp:Ne,endo:Ur}),Lt={};function qe(e,...t){let r=Lt[e];if(r===void 0){const n=Ae(hr(e));r=Be(n,n),Lt[e]=r}return Ae(Be(r,...t))}const ft=e=>e.toBytes(!0).slice(1),ht=e=>e%et===Hr;function tt(e){const{Fn:t,BASE:r}=de,n=t.fromBytes(e),i=r.multiply(n);return{scalar:ht(i.y)?n:t.neg(n),bytes:ft(i)}}function pn(e){const t=Ne;if(!t.isValidNot0(e))throw new Error("invalid x: Fail if x ≥ p");const r=t.create(e*e),n=t.create(r*e+BigInt(7));let i=t.sqrt(n);ht(i)||(i=t.neg(i));const s=de.fromAffine({x:e,y:i});return s.assertValidity(),s}const be=lt;function gn(...e){return de.Fn.create(be(qe("BIP0340/challenge",...e)))}function Pt(e){return tt(e).bytes}function Mr(e,t,r=Wt(32)){const{Fn:n}=de,i=M(e,void 0,"message"),{bytes:s,scalar:o}=tt(t),c=M(r,32,"auxRand"),a=n.toBytes(o^be(qe("BIP0340/aux",c))),l=qe("BIP0340/nonce",a,s,i),{bytes:u,scalar:f}=tt(l),g=gn(u,s,i),b=new Uint8Array(64);if(b.set(u,0),b.set(n.toBytes(n.create(f+g*o)),32),!bn(b,i,s))throw new Error("sign: Invalid signature produced");return b}function bn(e,t,r){const{Fp:n,Fn:i,BASE:s}=de,o=M(e,64,"signature"),c=M(t,void 0,"message"),a=M(r,32,"publicKey");try{const l=pn(be(a)),u=be(o.subarray(0,32));if(!n.isValidNot0(u))return!1;const f=be(o.subarray(32,64));if(!i.isValidNot0(f))return!1;const g=gn(i.toBytes(u),ft(l),c),b=s.multiplyUnsafe(f).add(l.multiplyUnsafe(i.neg(g))),{x:y,y:E}=b.toAffine();return!(b.is0()||!ht(E)||y!==u)}catch{return!1}}const G=(()=>{const r=(n=Wt(48))=>Tr(n,Pe.n);return{keygen:Or(r,Pt),getPublicKey:Pt,sign:Mr,verify:bn,Point:de,utils:{randomSecretKey:r,taggedHash:qe,lift_x:pn,pointToBytes:ft},lengths:{secretKey:32,publicKey:32,publicKeyHasPrefix:!1,signature:64,seed:48}}})();var ie=Symbol("verified"),Dr=e=>e instanceof Object;function Zr(e){if(!Dr(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!e.pubkey.match(/^[a-f0-9]{64}$/)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let r=e.tags[t];if(!Array.isArray(r))return!1;for(let n=0;n<r.length;n++)if(typeof r[n]!="string")return!1}return!0}new TextDecoder("utf-8");var Wr=new TextEncoder;function pe(e){try{e.indexOf("://")===-1&&(e="wss://"+e);let t=new URL(e);return t.protocol==="http:"?t.protocol="ws:":t.protocol==="https:"&&(t.protocol="wss:"),t.pathname=t.pathname.replace(/\/+/g,"/"),t.pathname.endsWith("/")&&(t.pathname=t.pathname.slice(0,-1)),(t.port==="80"&&t.protocol==="ws:"||t.port==="443"&&t.protocol==="wss:")&&(t.port=""),t.searchParams.sort(),t.hash="",t.toString()}catch{throw new Error(`Invalid URL: ${e}`)}}var Vr=class{generateSecretKey(){return G.utils.randomSecretKey()}getPublicKey(t){return _(G.getPublicKey(t))}finalizeEvent(t,r){const n=t;return n.pubkey=_(G.getPublicKey(r)),n.id=Ve(n),n.sig=_(G.sign(X(Ve(n)),r)),n[ie]=!0,n}verifyEvent(t){if(typeof t[ie]=="boolean")return t[ie];try{const r=Ve(t);if(r!==t.id)return t[ie]=!1,!1;const n=G.verify(X(t.sig),X(r),X(t.pubkey));return t[ie]=n,n}catch{return t[ie]=!1,!1}}};function Kr(e){if(!Zr(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function Ve(e){let t=Ae(Wr.encode(Kr(e)));return _(t)}var _e=new Vr;_e.generateSecretKey;_e.getPublicKey;_e.finalizeEvent;var Fr=_e.verifyEvent,Yr=22242;function zr(e,t){if(e.ids&&e.ids.indexOf(t.id)===-1||e.kinds&&e.kinds.indexOf(t.kind)===-1||e.authors&&e.authors.indexOf(t.pubkey)===-1)return!1;for(let r in e)if(r[0]==="#"){let n=r.slice(1),i=e[`#${n}`];if(i&&!t.tags.find(([s,o])=>s===r.slice(1)&&i.indexOf(o)!==-1))return!1}return!(e.since&&t.created_at<e.since||e.until&&t.created_at>e.until)}function Gr(e,t){for(let r=0;r<e.length;r++)if(zr(e[r],t))return!0;return!1}function Xr(e,t){let r=t.length+3,n=e.indexOf(`"${t}":`)+r,i=e.slice(n).indexOf('"')+n+1;return e.slice(i,i+64)}function Jr(e){let t=e.slice(0,22).indexOf('"EVENT"');if(t===-1)return null;let r=e.slice(t+7+1).indexOf('"');if(r===-1)return null;let n=t+7+1+r,i=e.slice(n+1,80).indexOf('"');if(i===-1)return null;let s=n+1+i;return e.slice(n+1,s)}function Qr(e,t){return{kind:Yr,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}var mn=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},yn=class{url;_connected=!1;onclose=null;onnotice=e=>console.debug(`NOTICE from ${this.url}: ${e}`);onauth;baseEoseTimeout=4400;publishTimeout=4400;pingFrequency=29e3;pingTimeout=2e4;resubscribeBackoff=[1e4,1e4,1e4,2e4,2e4,3e4,6e4];openSubs=new Map;enablePing;enableReconnect;idleSince=Date.now();ongoingOperations=0;reconnectTimeoutHandle;pingIntervalHandle;reconnectAttempts=0;skipReconnection=!1;connectionPromise;openCountRequests=new Map;openEventPublishes=new Map;ws;challenge;authPromise;serial=0;verifyEvent;_WebSocket;constructor(e,t){this.url=pe(e),this.verifyEvent=t.verifyEvent,this._WebSocket=t.websocketImplementation||WebSocket,this.enablePing=t.enablePing,this.enableReconnect=t.enableReconnect||!1}static async connect(e,t){const r=new yn(e,t);return await r.connect(t),r}closeAllSubscriptions(e){for(let[t,r]of this.openSubs)r.close(e);this.openSubs.clear();for(let[t,r]of this.openEventPublishes)r.reject(new Error(e));this.openEventPublishes.clear();for(let[t,r]of this.openCountRequests)r.reject(new Error(e));this.openCountRequests.clear()}get connected(){return this._connected}async reconnect(){const e=this.resubscribeBackoff[Math.min(this.reconnectAttempts,this.resubscribeBackoff.length-1)];this.reconnectAttempts++,this.reconnectTimeoutHandle=setTimeout(async()=>{try{await this.connect()}catch{}},e)}handleHardClose(e){this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.enableReconnect&&!this.skipReconnection?this.reconnect():(this.onclose?.(),this.closeAllSubscriptions(e))}async connect(e){let t;return this.connectionPromise?this.connectionPromise:(this.challenge=void 0,this.authPromise=void 0,this.skipReconnection=!1,this.connectionPromise=new Promise((r,n)=>{e?.timeout&&(t=setTimeout(()=>{n("connection timed out"),this.connectionPromise=void 0,this.skipReconnection=!0,this.onclose?.(),this.handleHardClose("relay connection timed out")},e.timeout)),e?.abort&&(e.abort.onabort=n);try{this.ws=new this._WebSocket(this.url)}catch(i){clearTimeout(t),n(i);return}this.ws.onopen=()=>{this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),clearTimeout(t),this._connected=!0;const i=this.reconnectAttempts>0;this.reconnectAttempts=0;for(const s of this.openSubs.values()){if(s.eosed=!1,i)for(let o=0;o<s.filters.length;o++)s.lastEmitted&&(s.filters[o].since=s.lastEmitted+1);s.fire()}this.enablePing&&(this.pingIntervalHandle=setInterval(()=>this.pingpong(),this.pingFrequency)),r()},this.ws.onerror=()=>{clearTimeout(t),n("connection failed"),this.connectionPromise=void 0,this.skipReconnection=!0,this.onclose?.(),this.handleHardClose("relay connection failed")},this.ws.onclose=i=>{clearTimeout(t),n(i.message||"websocket closed"),this.handleHardClose("relay connection closed")},this.ws.onmessage=this._onmessage.bind(this)}),this.connectionPromise)}waitForPingPong(){return new Promise(e=>{this.ws.once("pong",()=>e(!0)),this.ws.ping()})}waitForDummyReq(){return new Promise((e,t)=>{if(!this.connectionPromise)return t(new Error(`no connection to ${this.url}, can't ping`));try{const r=this.subscribe([{ids:["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],limit:0}],{label:"<forced-ping>",oneose:()=>{e(!0),r.close()},onclose(){e(!0)},eoseTimeout:this.pingTimeout+1e3})}catch(r){t(r)}})}async pingpong(){this.ws?.readyState===1&&(await Promise.any([this.ws&&this.ws.ping&&this.ws.once?this.waitForPingPong():this.waitForDummyReq(),new Promise(t=>setTimeout(()=>t(!1),this.pingTimeout))])||this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close())}async send(e){if(!this.connectionPromise)throw new mn(e,this.url);this.connectionPromise.then(()=>{this.ws?.send(e)})}async auth(e){const t=this.challenge;if(!t)throw new Error("can't perform auth, no challenge was received");return this.authPromise?this.authPromise:(this.authPromise=new Promise(async(r,n)=>{try{let i=await e(Qr(this.url,t)),s=setTimeout(()=>{let o=this.openEventPublishes.get(i.id);o&&(o.reject(new Error("auth timed out")),this.openEventPublishes.delete(i.id))},this.publishTimeout);this.openEventPublishes.set(i.id,{resolve:r,reject:n,timeout:s}),this.send('["AUTH",'+JSON.stringify(i)+"]")}catch(i){console.warn("subscribe auth function failed:",i)}}),this.authPromise)}async publish(e){this.idleSince=void 0,this.ongoingOperations++;const t=new Promise((r,n)=>{const i=setTimeout(()=>{const s=this.openEventPublishes.get(e.id);s&&(s.reject(new Error("publish timed out")),this.openEventPublishes.delete(e.id))},this.publishTimeout);this.openEventPublishes.set(e.id,{resolve:r,reject:n,timeout:i})});return this.send('["EVENT",'+JSON.stringify(e)+"]"),this.ongoingOperations--,this.ongoingOperations===0&&(this.idleSince=Date.now()),t}async count(e,t){this.serial++;const r=t?.id||"count:"+this.serial,n=new Promise((i,s)=>{this.openCountRequests.set(r,{resolve:i,reject:s})});return this.send('["COUNT","'+r+'",'+JSON.stringify(e).substring(1)),n}subscribe(e,t){t.label!=="<forced-ping>"&&(this.idleSince=void 0,this.ongoingOperations++);const r=this.prepareSubscription(e,t);return r.fire(),t.abort&&(t.abort.onabort=()=>r.close(String(t.abort.reason||"<aborted>"))),r}prepareSubscription(e,t){this.serial++;const r=t.id||(t.label?t.label+":":"sub:")+this.serial,n=new ei(this,r,e,t);return this.openSubs.set(r,n),n}close(){this.skipReconnection=!0,this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this.closeAllSubscriptions("relay connection closed by us"),this._connected=!1,this.idleSince=void 0,this.onclose?.(),this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close()}_onmessage(e){const t=e.data;if(!t)return;const r=Jr(t);if(r){const n=this.openSubs.get(r);if(!n)return;const i=Xr(t,"id"),s=n.alreadyHaveEvent?.(i);if(n.receivedEvent?.(this,i),s)return}try{let n=JSON.parse(t);switch(n[0]){case"EVENT":{const i=this.openSubs.get(n[1]),s=n[2];this.verifyEvent(s)&&Gr(i.filters,s)?i.onevent(s):i.oninvalidevent?.(s),(!i.lastEmitted||i.lastEmitted<s.created_at)&&(i.lastEmitted=s.created_at);return}case"COUNT":{const i=n[1],s=n[2],o=this.openCountRequests.get(i);o&&(o.resolve(s.count),this.openCountRequests.delete(i));return}case"EOSE":{const i=this.openSubs.get(n[1]);if(!i)return;i.receivedEose();return}case"OK":{const i=n[1],s=n[2],o=n[3],c=this.openEventPublishes.get(i);c&&(clearTimeout(c.timeout),s?c.resolve(o):c.reject(new Error(o)),this.openEventPublishes.delete(i));return}case"CLOSED":{const i=n[1],s=this.openSubs.get(i);if(!s)return;s.closed=!0,s.close(n[2]);return}case"NOTICE":{this.onnotice(n[1]);return}case"AUTH":{this.challenge=n[1],this.onauth&&this.auth(this.onauth);return}default:{this.openSubs.get(n[1])?.oncustom?.(n);return}}}catch(n){try{const[i,s,o]=JSON.parse(t);console.warn(`[nostr] relay ${this.url} error processing message:`,n,o)}catch{console.warn(`[nostr] relay ${this.url} error processing message:`,n)}return}}},ei=class{relay;id;lastEmitted;closed=!1;eosed=!1;filters;alreadyHaveEvent;receivedEvent;onevent;oninvalidevent;oneose;onclose;oncustom;eoseTimeout;eoseTimeoutHandle;constructor(e,t,r,n){if(r.length===0)throw new Error("subscription can't be created with zero filters");this.relay=e,this.filters=r,this.id=t,this.alreadyHaveEvent=n.alreadyHaveEvent,this.receivedEvent=n.receivedEvent,this.eoseTimeout=n.eoseTimeout||e.baseEoseTimeout,this.oneose=n.oneose,this.onclose=n.onclose,this.oninvalidevent=n.oninvalidevent,this.onevent=n.onevent||(i=>{console.warn(`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,i)})}fire(){this.relay.send('["REQ","'+this.id+'",'+JSON.stringify(this.filters).substring(1)),this.eoseTimeoutHandle=setTimeout(this.receivedEose.bind(this),this.eoseTimeout)}receivedEose(){this.eosed||(clearTimeout(this.eoseTimeoutHandle),this.eosed=!0,this.oneose?.())}close(e="closed by caller"){if(!this.closed&&this.relay.connected){try{this.relay.send('["CLOSE",'+JSON.stringify(this.id)+"]")}catch(t){if(!(t instanceof mn))throw t}this.closed=!0}this.relay.openSubs.delete(this.id),this.relay.ongoingOperations--,this.relay.ongoingOperations===0&&(this.relay.idleSince=Date.now()),this.onclose?.(e)}},ti=e=>(e[ie]=!0,!0),ni=class{relays=new Map;seenOn=new Map;trackRelays=!1;verifyEvent;enablePing;enableReconnect;automaticallyAuth;trustedRelayURLs=new Set;onRelayConnectionFailure;onRelayConnectionSuccess;allowConnectingToRelay;maxWaitForConnection;_WebSocket;constructor(e){this.verifyEvent=e.verifyEvent,this._WebSocket=e.websocketImplementation,this.enablePing=e.enablePing,this.enableReconnect=e.enableReconnect||!1,this.automaticallyAuth=e.automaticallyAuth,this.onRelayConnectionFailure=e.onRelayConnectionFailure,this.onRelayConnectionSuccess=e.onRelayConnectionSuccess,this.allowConnectingToRelay=e.allowConnectingToRelay,this.maxWaitForConnection=e.maxWaitForConnection||3e3}async ensureRelay(e,t){e=pe(e);let r=this.relays.get(e);if(r||(r=new yn(e,{verifyEvent:this.trustedRelayURLs.has(e)?ti:this.verifyEvent,websocketImplementation:this._WebSocket,enablePing:this.enablePing,enableReconnect:this.enableReconnect}),r.onclose=()=>{this.relays.delete(e)},this.relays.set(e,r)),this.automaticallyAuth){const n=this.automaticallyAuth(e);n&&(r.onauth=n)}try{await r.connect({timeout:t?.connectionTimeout,abort:t?.abort})}catch(n){throw this.relays.delete(e),n}return r}close(e){e.map(pe).forEach(t=>{this.relays.get(t)?.close(),this.relays.delete(t)})}subscribe(e,t,r){const n=[],i=[];for(let s=0;s<e.length;s++){const o=pe(e[s]);n.find(c=>c.url===o)||i.indexOf(o)===-1&&(i.push(o),n.push({url:o,filter:t}))}return this.subscribeMap(n,r)}subscribeMany(e,t,r){return this.subscribe(e,t,r)}subscribeMap(e,t){const r=new Map;for(const g of e){const{url:b,filter:y}=g;r.has(b)||r.set(b,[]),r.get(b).push(y)}const n=Array.from(r.entries()).map(([g,b])=>({url:g,filters:b}));this.trackRelays&&(t.receivedEvent=(g,b)=>{let y=this.seenOn.get(b);y||(y=new Set,this.seenOn.set(b,y)),y.add(g)});const i=new Set,s=[],o=[];let c=g=>{o[g]||(o[g]=!0,o.filter(b=>b).length===n.length&&(t.oneose?.(),c=()=>{}))};const a=[];let l=(g,b)=>{a[g]||(c(g),a[g]=b,a.filter(y=>y).length===n.length&&(t.onclose?.(a),l=()=>{}))};const u=g=>{if(t.alreadyHaveEvent?.(g))return!0;const b=i.has(g);return i.add(g),b},f=Promise.all(n.map(async({url:g,filters:b},y)=>{if(this.allowConnectingToRelay?.(g,["read",b])===!1){l(y,"connection skipped by allowConnectingToRelay");return}let E;try{E=await this.ensureRelay(g,{connectionTimeout:this.maxWaitForConnection<(t.maxWait||0)?Math.max(t.maxWait*.8,t.maxWait-1e3):this.maxWaitForConnection,abort:t.abort})}catch(L){this.onRelayConnectionFailure?.(g),l(y,L?.message||String(L));return}this.onRelayConnectionSuccess?.(g);let N=E.subscribe(b,{...t,oneose:()=>c(y),onclose:L=>{L.startsWith("auth-required: ")&&t.onauth?E.auth(t.onauth).then(()=>{E.subscribe(b,{...t,oneose:()=>c(y),onclose:F=>{l(y,F)},alreadyHaveEvent:u,eoseTimeout:t.maxWait,abort:t.abort})}).catch(F=>{l(y,`auth was required and attempted, but failed with: ${F}`)}):l(y,L)},alreadyHaveEvent:u,eoseTimeout:t.maxWait,abort:t.abort});s.push(N)}));return{async close(g){await f,s.forEach(b=>{b.close(g)})}}}subscribeEose(e,t,r){let n;return n=this.subscribe(e,t,{...r,oneose(){const i="closed automatically on eose";n?n.close(i):r.onclose?.(e.map(s=>i))}}),n}subscribeManyEose(e,t,r){return this.subscribeEose(e,t,r)}async querySync(e,t,r){return new Promise(async n=>{const i=[];this.subscribeEose(e,t,{...r,onevent(s){i.push(s)},onclose(s){n(i)}})})}async get(e,t,r){t.limit=1;const n=await this.querySync(e,t,r);return n.sort((i,s)=>s.created_at-i.created_at),n[0]||null}publish(e,t,r){return e.map(pe).map(async(n,i,s)=>{if(s.indexOf(n)!==i)return Promise.reject("duplicate url");if(this.allowConnectingToRelay?.(n,["write",t])===!1)return Promise.reject("connection skipped by allowConnectingToRelay");let o;try{o=await this.ensureRelay(n,{connectionTimeout:this.maxWaitForConnection<(r?.maxWait||0)?Math.max(r.maxWait*.8,r.maxWait-1e3):this.maxWaitForConnection,abort:r?.abort})}catch(c){return this.onRelayConnectionFailure?.(n),"connection failure: "+String(c)}return o.publish(t).catch(async c=>{if(c instanceof Error&&c.message.startsWith("auth-required: ")&&r?.onauth)return await o.auth(r.onauth),o.publish(t);throw c}).then(c=>{if(this.trackRelays){let a=this.seenOn.get(t.id);a||(a=new Set,this.seenOn.set(t.id,a)),a.add(o)}return c})})}listConnectionStatus(){const e=new Map;return this.relays.forEach((t,r)=>e.set(r,t.connected)),e}destroy(){this.relays.forEach(e=>e.close()),this.relays=new Map}pruneIdleRelays(e=1e4){const t=[];for(const[r,n]of this.relays)n.idleSince&&Date.now()-n.idleSince>=e&&(this.relays.delete(r),t.push(r),n.close());return t}},wn;try{wn=WebSocket}catch{}var ri=class extends ni{constructor(e){super({verifyEvent:Fr,websocketImplementation:wn,maxWaitForConnection:3e3,...e})}},ce=Symbol("verified"),ii=e=>e instanceof Object;function si(e){if(!ii(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!e.pubkey.match(/^[a-f0-9]{64}$/)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let r=e.tags[t];if(!Array.isArray(r))return!1;for(let n=0;n<r.length;n++)if(typeof r[n]!="string")return!1}return!0}new TextDecoder("utf-8");var oi=new TextEncoder,ai=class{generateSecretKey(){return G.utils.randomSecretKey()}getPublicKey(e){return _(G.getPublicKey(e))}finalizeEvent(e,t){const r=e;return r.pubkey=_(G.getPublicKey(t)),r.id=Ke(r),r.sig=_(G.sign(X(Ke(r)),t)),r[ce]=!0,r}verifyEvent(e){if(typeof e[ce]=="boolean")return e[ce];try{const t=Ke(e);if(t!==e.id)return e[ce]=!1,!1;const r=G.verify(X(e.sig),X(t),X(e.pubkey));return e[ce]=r,r}catch{return e[ce]=!1,!1}}};function ci(e){if(!si(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function Ke(e){let t=Ae(oi.encode(ci(e)));return _(t)}var Ce=new ai;Ce.generateSecretKey;Ce.getPublicKey;Ce.finalizeEvent;var li=Ce.verifyEvent;const di=8e3;function ui(e){return typeof e=="number"&&st.includes(e)}function fi(e){try{const t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function hi(e){const t=[];for(const r of e??[])try{const n=new URL(r);if(n.protocol!=="ws:"&&n.protocol!=="wss:")continue;t.push(n.href)}catch{}return[...new Set(t)]}function pi(e){const t=rr(e.trim());if(t.type!=="nevent"&&t.type!=="naddr")throw new Error("Enter a NIP-19 nevent or naddr for a NIP-5D napplet manifest event");const r=hi(t.data.relays);if(r.length===0)throw new Error("The pointer does not include relay hints; include at least one relay in the nevent/naddr");if(t.type==="nevent"){if(t.data.kind!==void 0&&!ui(t.data.kind))throw new Error(`nevent points at kind ${t.data.kind}, not a NIP-5D napplet manifest kind`);return{type:"nevent",relays:r,filter:{ids:[t.data.id],kinds:t.data.kind===void 0?[...st]:[t.data.kind],authors:t.data.author?[t.data.author]:void 0,limit:1}}}if(t.data.kind!==ge)throw new Error(`naddr kind ${t.data.kind} is not the named napplet kind ${ge}`);return{type:"naddr",relays:r,filter:{kinds:[ge],authors:[t.data.pubkey],"#d":[t.data.identifier],limit:1}}}function gi(e){return{id:e.id,pubkey:e.pubkey,kind:e.kind,tags:e.tags}}async function vn(e){const t=typeof e=="string"?new TextEncoder().encode(e):e,r=new Uint8Array(t.byteLength);r.set(t);const n=await crypto.subtle.digest("SHA-256",r.buffer);return[...new Uint8Array(n)].map(i=>i.toString(16).padStart(2,"0")).join("")}function bi(e){return e.tags.filter(t=>t[0]==="path"&&typeof t[1]=="string"&&typeof t[2]=="string")}async function mi(e){const t=bi(e).map(r=>`${r[2]} ${r[1]}
|
|
77
|
-
`).sort().join("");return vn(t)}async function yi(e){const t=await mi(e);for(const r of e.tags.filter(n=>n[0]==="x"))if(r[2]!==t)throw new Error(`Manifest x tag does not match recomputed aggregate hash ${t}`)}function wi(e){return e.tags.find(t=>t[0]==="path"&&t[1]==="/index.html")}function vi(e){const t=[];for(const r of e.tags)if(!(r[0]!=="server"||!r[1]))try{const n=new URL(r[1]);(n.protocol==="http:"||n.protocol==="https:")&&t.push(n.href)}catch{}return[...new Set(t)]}function Ei(e,t){const r=e.endsWith("/")?e:`${e}/`;return new URL(t,r).href}async function xi(e,t=fetch){const n=wi(e)?.[2];if(!n)throw new Error("Manifest does not include a /index.html path hash");const i=vi(e);if(i.length===0)throw new Error("Manifest does not include any usable Blossom server hints");const s=[];for(const o of i){const c=Ei(o,n);try{const a=await t(c,{mode:"cors"});if(!a.ok){s.push(`${c}: HTTP ${a.status}`);continue}const l=new Uint8Array(await a.arrayBuffer()),u=await vn(l);if(u!==n){s.push(`${c}: sha256 ${u} did not match manifest ${n}`);continue}return new TextDecoder().decode(l)}catch(a){s.push(`${c}: ${a instanceof Error?a.message:String(a)}`)}}throw new Error(`Unable to fetch verified /index.html from Blossom servers: ${s.join("; ")}`)}async function ki(e,t){try{const n=await(await t(e,{mode:"cors"})).text();return{source:"url",input:e,label:e,bootUrl:e,html:n,fetched:!0,manifestEvent:null}}catch{return{source:"url",input:e,label:e,bootUrl:e,html:"",fetched:!1,manifestEvent:null}}}async function Si(e,t){const r=pi(e),n=!t.pool,i=t.pool??new ri;try{const s=await i.get(r.relays,{...r.filter},{maxWait:t.maxRelayWaitMs??di});if(!s)throw new Error("No matching napplet manifest event was found on the pointer relay hints");if(!li(s))throw new Error("Resolved manifest event signature is invalid");const o=gi(s),c=ot(o);if(!c.ok)throw new Error(`Resolved event is not a valid NIP-5D napplet manifest: ${c.errors[0]?.message}`);await yi(o);const a=await xi(o,t.fetcher??fetch),l=(t.createObjectUrl??URL.createObjectURL)(new Blob([a],{type:"text/html;charset=utf-8"})),u=()=>(t.revokeObjectUrl??URL.revokeObjectURL)(l);return{source:"nostr",input:e,label:o.id??e,bootUrl:l,html:a,fetched:!0,manifestEvent:o,revoke:u}}finally{n&&i.destroy()}}async function Ri(e,t={}){const r=e.trim();if(!r)throw new Error("Enter a NIP-19 nevent/naddr, or an HTTP URL for local dev");return fi(r)?ki(r,t.fetcher??fetch):Si(r,t)}const $i=/\bwindow\s*\.\s*nostr\b|\bglobalThis\s*\.\s*nostr\b/,Ti="/__conformance__/events",nt=new URLSearchParams(location.search),En=nt.get("live")==="1";function ne(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const re=document.getElementById("app");function Bi(){return re.innerHTML=`
|
|
78
|
-
<header class="masthead">
|
|
79
|
-
<h1>napplet conformance ${En?'<span class="live-badge" id="live-badge">● live</span>':""}</h1>
|
|
80
|
-
<p>Load a napplet by <code>nevent</code> or <code>naddr</code> and run NAP protocol conformance live. Same engine as <code>napplet-conformance</code> CI.</p>
|
|
81
|
-
</header>
|
|
82
|
-
<form id="run-form" class="runbar">
|
|
83
|
-
<input id="target" type="text" placeholder="naddr1… or nevent1… for a NIP-5D napplet manifest" autocomplete="off" spellcheck="false" />
|
|
84
|
-
<button id="run" type="submit">Run conformance</button>
|
|
85
|
-
<button id="rerun" type="button" class="secondary" hidden>Re-run</button>
|
|
86
|
-
</form>
|
|
87
|
-
<p id="status" class="status" role="status"></p>
|
|
88
|
-
<section id="output" class="output"></section>
|
|
89
|
-
`,{targetInput:re.querySelector("#target"),runButton:re.querySelector("#run"),rerunButton:re.querySelector("#rerun"),liveBadge:re.querySelector("#live-badge")??document.createElement("span"),status:re.querySelector("#status"),output:re.querySelector("#output")}}const C=Bi();let ye="",rt=0;function Re(e,t="info"){C.status.textContent=e,C.status.dataset.kind=t}function Fe(e){return String(e).padStart(2,"0")}function Ii(e){const t=new Date(e);return`${Fe(t.getHours())}:${Fe(t.getMinutes())}:${Fe(t.getSeconds())}`}function Ai(e){const t=e.ok?"conformant":"non-conformant",n=[...new Set(e.checks.map(o=>o.area))].map(o=>{const c=e.checks.filter(a=>a.area===o).map(a=>{const l=a.severity==="warning"&&a.status==="fail"?' <span class="tag warn">warning</span>':"",u=a.detail?`<span class="detail">${ne(a.detail)}</span>`:"";return`<li class="check ${a.status}"><span class="badge ${a.status}">${a.status}</span><span class="id">${ne(a.id)}</span>${l}${u}</li>`}).join("");return`<div class="area"><h3>${ne(o)}</h3><ul>${c}</ul></div>`}).join(""),i=e.summary,s=rt>1?`<span class="run-stamp">run #${rt} · ${Ii(e.finishedAt)}</span>`:"";return`
|
|
90
|
-
<div class="verdict ${t}">
|
|
91
|
-
<span class="result">${e.ok?"CONFORMANT":"NON-CONFORMANT"}</span>
|
|
92
|
-
<span class="counts">${i.passed} passed · ${i.failed} failed · ${i.skipped} skipped${i.warnings?` · ${i.warnings} warning(s)`:""}</span>
|
|
93
|
-
${s}
|
|
94
|
-
</div>
|
|
95
|
-
<div class="checks">${n}</div>
|
|
96
|
-
`}function Oi(e){return e.length===0?'<p class="empty">No envelopes were emitted.</p>':`<ul class="envlog">${e.map(r=>{const n=r.verdict.ok?"ok":"bad",i=r.verdict.ok?"":`<div class="errs">${r.verdict.errors.map(s=>ne(`${s.code}: ${s.message}`)).join("<br>")}</div>`;return`<li class="env ${n}"><code>${ne(JSON.stringify(r.envelope))}</code>${i}</li>`}).join("")}</ul>`}function Ni(e){const t=(r,n)=>`<tr><th>${ne(r)}</th><td>${n?ne(String(n)):"<em>—</em>"}</td></tr>`;if(e.manifestEvent){const r=e.manifestEvent,n=ot(r),i=r.tags.find(c=>c[0]==="d")?.[1],s=r.tags.find(c=>c[0]==="path"&&c[1]==="/index.html"),o=r.tags.filter(c=>c[0]==="server").map(c=>c[1]).filter(Boolean);return`
|
|
97
|
-
<table class="manifest">
|
|
98
|
-
${t("event",r.id)}
|
|
99
|
-
${t("kind",r.kind)}
|
|
100
|
-
${t("d",i)}
|
|
101
|
-
${t("name",Mt(r))}
|
|
102
|
-
${t("requires",n.requires.join(", "))}
|
|
103
|
-
${t("/index.html",s?.[2])}
|
|
104
|
-
${t("servers",o.join(", "))}
|
|
105
|
-
</table>
|
|
106
|
-
${n.errors.length?`<div class="errs">${n.errors.map(c=>ne(`${c.code}: ${c.message}`)).join("<br>")}</div>`:""}
|
|
107
|
-
`}return e.fetched?'<p class="empty">Local URL mode booted raw HTML. It does not include a signed NIP-5D manifest event, so manifest-event checks are skipped.</p>':`<p class="empty">Couldn't fetch the local URL HTML, likely because of CORS. Use a NIP-19 <code>nevent</code>/<code>naddr</code> for authoritative manifest checks, or use the CLI for local URL runs.</p>`}function qi(e,t,r){C.output.innerHTML=`
|
|
108
|
-
${Ai(e)}
|
|
109
|
-
<div class="panels">
|
|
110
|
-
<section class="panel"><h2>Emitted envelopes (${t.length})</h2>${Oi(t)}</section>
|
|
111
|
-
<section class="panel"><h2>Manifest</h2>${Ni(r)}</section>
|
|
112
|
-
</div>
|
|
113
|
-
`}async function Ue(e){ye=e,C.runButton.disabled=!0,C.rerunButton.disabled=!0;let t=null;try{Re(`Resolving ${e} …`),t=await Ri(e);const r=$i.test(t.html)?["window.nostr"]:[];Re("Booting napplet in a sandboxed iframe …");const n=await Un({url:t.bootUrl,readyTimeoutMs:5e3,settleMs:800,runDegraded:!0}),i=Nn({manifestHtml:t.html,manifestEvent:t.manifestEvent,boot:n,forbiddenGlobals:r}),s=Wn(i);rt+=1,Re(s.ok?"Done — conformant.":"Done — non-conformant.",s.ok?"info":"error"),qi(s,n.emitted,t),C.rerunButton.hidden=!1}catch(r){Re(`Error: ${r instanceof Error?r.message:String(r)}`,"error")}finally{t?.revoke?.(),C.runButton.disabled=!1,C.rerunButton.disabled=!1}}function Li(){if(!En||typeof EventSource>"u")return;let e=!1;const t=new EventSource(Ti);t.addEventListener("rerun",()=>{!ye||e||(e=!0,setTimeout(()=>{e=!1,Ue(ye)},50))}),t.addEventListener("open",()=>{C.liveBadge&&(C.liveBadge.dataset.state="connected")}),t.addEventListener("error",()=>{C.liveBadge&&(C.liveBadge.dataset.state="disconnected")})}C.runButton.parentElement.addEventListener("submit",e=>{e.preventDefault();const t=C.targetInput.value.trim();if(t){const r=new URL(location.href);r.searchParams.set("target",t),r.searchParams.delete("url"),history.replaceState(null,"",r),Ue(t)}});C.rerunButton.addEventListener("click",()=>{ye&&Ue(ye)});Li();const Ye=nt.get("target")??nt.get("url");Ye&&(C.targetInput.value=Ye,Ue(Ye));
|