@napplet/conformance-cli 0.2.17 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/host-bundle.global.js +261 -105
- package/dist/ui/assets/index-DV1wZ-SF.js +116 -0
- package/dist/ui/index.html +1 -1
- package/package.json +3 -3
- package/dist/ui/assets/index-B_4r_ePr.js +0 -113
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var NappletConformanceHostBundle = (() => {
|
|
3
3
|
// ../core/dist/index.js
|
|
4
|
-
var NAP_DOMAINS = ["relay", "identity", "storage", "inc", "theme", "keys", "media", "notify", "config", "resource", "cvm", "outbox", "upload", "intent", "ble", "webrtc", "link", "count", "lists", "serial", "common", "dm"];
|
|
4
|
+
var NAP_DOMAINS = ["relay", "identity", "storage", "inc", "theme", "keys", "media", "notify", "config", "resource", "cvm", "outbox", "upload", "intent", "ble", "webrtc", "link", "count", "lists", "serial", "fs", "common", "dm"];
|
|
5
5
|
function createDispatch() {
|
|
6
6
|
const handlers = /* @__PURE__ */ new Map();
|
|
7
7
|
function registerNap2(domain, handler) {
|
|
@@ -136,7 +136,7 @@ var NappletConformanceHostBundle = (() => {
|
|
|
136
136
|
// ── resource ─────────────────────────────────────────────────────────────
|
|
137
137
|
"resource.info": { dir: "out", fields: { ...ID } },
|
|
138
138
|
"resource.bytes": { dir: "out", fields: { ...ID, url: "string" } },
|
|
139
|
-
"resource.bytesMany": { dir: "out", fields: { ...ID,
|
|
139
|
+
"resource.bytesMany": { dir: "out", fields: { ...ID, requests: "array" } },
|
|
140
140
|
"resource.cancel": { dir: "out", fields: { ...ID } },
|
|
141
141
|
"resource.info.result": { dir: "in" },
|
|
142
142
|
"resource.info.error": { dir: "in" },
|
|
@@ -185,7 +185,7 @@ var NappletConformanceHostBundle = (() => {
|
|
|
185
185
|
"intent.invoke": { dir: "out", fields: { ...ID, request: "object" } },
|
|
186
186
|
"intent.available": { dir: "out", fields: { ...ID, archetype: "string" } },
|
|
187
187
|
"intent.handlers": { dir: "out", fields: { ...ID } },
|
|
188
|
-
"intent.invoke.result": { dir: "in" },
|
|
188
|
+
"intent.invoke.result": { dir: "in", fields: { ...ID, result: "object" } },
|
|
189
189
|
"intent.available.result": { dir: "in" },
|
|
190
190
|
"intent.handlers.result": { dir: "in" },
|
|
191
191
|
"intent.changed": { dir: "in" },
|
|
@@ -251,6 +251,36 @@ var NappletConformanceHostBundle = (() => {
|
|
|
251
251
|
"serial.write.result": { dir: "in" },
|
|
252
252
|
"serial.close.result": { dir: "in" },
|
|
253
253
|
"serial.event": { dir: "in" },
|
|
254
|
+
// ── fs ───────────────────────────────────────────────────────────────────
|
|
255
|
+
"fs.info": { dir: "out", fields: { ...ID } },
|
|
256
|
+
"fs.pickFile": { dir: "out", fields: { ...ID } },
|
|
257
|
+
"fs.pickFiles": { dir: "out", fields: { ...ID } },
|
|
258
|
+
"fs.pickDirectory": { dir: "out", fields: { ...ID } },
|
|
259
|
+
"fs.pickSaveFile": { dir: "out", fields: { ...ID } },
|
|
260
|
+
"fs.stat": { dir: "out", fields: { ...ID, path: "string" } },
|
|
261
|
+
"fs.list": { dir: "out", fields: { ...ID, path: "string" } },
|
|
262
|
+
"fs.read": { dir: "out", fields: { ...ID, path: "string" } },
|
|
263
|
+
"fs.write": { dir: "out", fields: { ...ID, path: "string", data: "string" } },
|
|
264
|
+
"fs.mkdir": { dir: "out", fields: { ...ID, path: "string" } },
|
|
265
|
+
"fs.remove": { dir: "out", fields: { ...ID, path: "string" } },
|
|
266
|
+
"fs.move": { dir: "out", fields: { ...ID, fromPath: "string", toPath: "string" } },
|
|
267
|
+
"fs.watch": { dir: "out", fields: { ...ID, path: "string" } },
|
|
268
|
+
"fs.unwatch": { dir: "out", fields: { ...ID, watchId: "string" } },
|
|
269
|
+
"fs.info.result": { dir: "in" },
|
|
270
|
+
"fs.pickFile.result": { dir: "in" },
|
|
271
|
+
"fs.pickFiles.result": { dir: "in" },
|
|
272
|
+
"fs.pickDirectory.result": { dir: "in" },
|
|
273
|
+
"fs.pickSaveFile.result": { dir: "in" },
|
|
274
|
+
"fs.stat.result": { dir: "in" },
|
|
275
|
+
"fs.list.result": { dir: "in" },
|
|
276
|
+
"fs.read.result": { dir: "in" },
|
|
277
|
+
"fs.write.result": { dir: "in" },
|
|
278
|
+
"fs.mkdir.result": { dir: "in" },
|
|
279
|
+
"fs.remove.result": { dir: "in" },
|
|
280
|
+
"fs.move.result": { dir: "in" },
|
|
281
|
+
"fs.watch.result": { dir: "in" },
|
|
282
|
+
"fs.unwatch.result": { dir: "in" },
|
|
283
|
+
"fs.changed": { dir: "in" },
|
|
254
284
|
// ── dm ───────────────────────────────────────────────────────────────────
|
|
255
285
|
"dm.status": { dir: "out", fields: { ...ID } },
|
|
256
286
|
"dm.conversations": { dir: "out", fields: { ...ID } },
|
|
@@ -306,6 +336,48 @@ var NappletConformanceHostBundle = (() => {
|
|
|
306
336
|
});
|
|
307
337
|
}
|
|
308
338
|
}
|
|
339
|
+
function validateServerHints(value, field, errors) {
|
|
340
|
+
if (Array.isArray(value) && value.every((server) => typeof server === "string")) return;
|
|
341
|
+
errors.push({
|
|
342
|
+
code: "wrong-type",
|
|
343
|
+
message: `Field "${field}" must be an array of strings`,
|
|
344
|
+
field
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
function validateResourceRequestFields(record, errors) {
|
|
348
|
+
if (record.servers !== void 0) validateServerHints(record.servers, "servers", errors);
|
|
349
|
+
}
|
|
350
|
+
function validateResourceBytesManyRequests(requests, errors) {
|
|
351
|
+
if (!Array.isArray(requests)) return;
|
|
352
|
+
if (requests.length === 0) {
|
|
353
|
+
errors.push({
|
|
354
|
+
code: "invalid-resource-request",
|
|
355
|
+
message: 'Field "requests" must contain at least one resource request',
|
|
356
|
+
field: "requests"
|
|
357
|
+
});
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
for (const [index, request] of requests.entries()) {
|
|
361
|
+
const field = `requests[${index}]`;
|
|
362
|
+
if (typeof request !== "object" || request === null || Array.isArray(request)) {
|
|
363
|
+
errors.push({
|
|
364
|
+
code: "invalid-resource-request",
|
|
365
|
+
message: `Field "${field}" must be a resource request object`,
|
|
366
|
+
field
|
|
367
|
+
});
|
|
368
|
+
continue;
|
|
369
|
+
}
|
|
370
|
+
const entry = request;
|
|
371
|
+
if (typeof entry.url !== "string") {
|
|
372
|
+
errors.push({
|
|
373
|
+
code: entry.url === void 0 ? "missing-field" : "wrong-type",
|
|
374
|
+
message: `Field "${field}.url" must be a string`,
|
|
375
|
+
field: `${field}.url`
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
if (entry.servers !== void 0) validateServerHints(entry.servers, `${field}.servers`, errors);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
309
381
|
function validateEnvelope(message) {
|
|
310
382
|
const errors = [];
|
|
311
383
|
if (typeof message !== "object" || message === null || Array.isArray(message)) {
|
|
@@ -366,6 +438,12 @@ var NappletConformanceHostBundle = (() => {
|
|
|
366
438
|
if (type === "intent.invoke") {
|
|
367
439
|
validateIntentInvokeRequest(record.request, errors);
|
|
368
440
|
}
|
|
441
|
+
if (type === "resource.bytes") {
|
|
442
|
+
validateResourceRequestFields(record, errors);
|
|
443
|
+
}
|
|
444
|
+
if (type === "resource.bytesMany") {
|
|
445
|
+
validateResourceBytesManyRequests(record.requests, errors);
|
|
446
|
+
}
|
|
369
447
|
return { ok: errors.length === 0, type, domain, direction: "out", errors };
|
|
370
448
|
}
|
|
371
449
|
var NAPPLET_KIND_SNAPSHOT = 5129;
|
|
@@ -464,6 +542,9 @@ var NappletConformanceHostBundle = (() => {
|
|
|
464
542
|
var REFERENCE_HANDLER = "reference-handler";
|
|
465
543
|
var REFERENCE_SUBSCRIBER = "reference-subscriber";
|
|
466
544
|
var REFERENCE_CONVENTION = "napplet:note/open";
|
|
545
|
+
function pickResult(type, id, entry) {
|
|
546
|
+
return ok({ type, id, result: { entries: [entry] } });
|
|
547
|
+
}
|
|
467
548
|
var ok = (v) => [v];
|
|
468
549
|
var none = () => [];
|
|
469
550
|
function dataUrlToBlob(url) {
|
|
@@ -554,10 +635,11 @@ var NappletConformanceHostBundle = (() => {
|
|
|
554
635
|
"resource.bytesMany": (e) => ok({
|
|
555
636
|
type: "resource.bytesMany.result",
|
|
556
637
|
id: e.id,
|
|
557
|
-
items: Array.isArray(e.
|
|
638
|
+
items: Array.isArray(e.requests) ? e.requests.map((request) => {
|
|
639
|
+
const url = typeof request === "object" && request !== null && !Array.isArray(request) ? request.url : void 0;
|
|
558
640
|
const decoded = dataUrlToBlob(url);
|
|
559
641
|
return {
|
|
560
|
-
url,
|
|
642
|
+
url: typeof url === "string" ? url : "",
|
|
561
643
|
ok: true,
|
|
562
644
|
blob: decoded?.blob ?? new Blob([]),
|
|
563
645
|
mime: decoded?.mime ?? "application/octet-stream"
|
|
@@ -571,7 +653,8 @@ var NappletConformanceHostBundle = (() => {
|
|
|
571
653
|
schemes: [
|
|
572
654
|
{ scheme: "data", enabled: true },
|
|
573
655
|
{ scheme: "https", enabled: true }
|
|
574
|
-
]
|
|
656
|
+
],
|
|
657
|
+
maxServers: 8
|
|
575
658
|
}
|
|
576
659
|
}),
|
|
577
660
|
"resource.cancel": none,
|
|
@@ -648,120 +731,190 @@ var NappletConformanceHostBundle = (() => {
|
|
|
648
731
|
// serial
|
|
649
732
|
"serial.open": (e) => ok({ type: "serial.open.result", id: e.id, session: { id: `serial-${String(e.id)}`, state: "open" } }),
|
|
650
733
|
"serial.write": (e) => ok({ type: "serial.write.result", id: e.id }),
|
|
651
|
-
"serial.close": (e) => ok({ type: "serial.close.result", id: e.id })
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
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 };
|
|
734
|
+
"serial.close": (e) => ok({ type: "serial.close.result", id: e.id }),
|
|
735
|
+
// fs -- virtual paths and curated labels only; never a host path, username,
|
|
736
|
+
// device name, volume, or storage-provider string (NAP-FS info() disclosure rules)
|
|
737
|
+
"fs.info": (e) => ok({
|
|
738
|
+
type: "fs.info.result",
|
|
739
|
+
id: e.id,
|
|
740
|
+
info: {
|
|
741
|
+
roots: [{ path: "/shared", name: "Shared files", permissions: ["read", "list", "write", "create", "delete", "watch"] }],
|
|
742
|
+
limits: { maxReadBytes: 1048576, maxWriteBytes: 1048576, maxWatchCount: 16 }
|
|
711
743
|
}
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
744
|
+
}),
|
|
745
|
+
"fs.pickFile": (e) => pickResult("fs.pickFile.result", e.id, {
|
|
746
|
+
path: "/picked/file.txt",
|
|
747
|
+
kind: "file",
|
|
748
|
+
name: "file.txt",
|
|
749
|
+
permissions: ["read"]
|
|
750
|
+
}),
|
|
751
|
+
"fs.pickFiles": (e) => pickResult("fs.pickFiles.result", e.id, {
|
|
752
|
+
path: "/picked/file.txt",
|
|
753
|
+
kind: "file",
|
|
754
|
+
name: "file.txt",
|
|
755
|
+
permissions: ["read"]
|
|
756
|
+
}),
|
|
757
|
+
"fs.pickDirectory": (e) => pickResult("fs.pickDirectory.result", e.id, {
|
|
758
|
+
path: "/picked",
|
|
759
|
+
kind: "directory",
|
|
760
|
+
name: "picked",
|
|
761
|
+
permissions: ["read", "list"]
|
|
762
|
+
}),
|
|
763
|
+
"fs.pickSaveFile": (e) => pickResult("fs.pickSaveFile.result", e.id, {
|
|
764
|
+
path: "/picked/export.json",
|
|
765
|
+
kind: "file",
|
|
766
|
+
name: "export.json",
|
|
767
|
+
permissions: ["write", "create"]
|
|
768
|
+
}),
|
|
769
|
+
"fs.stat": (e) => ok({
|
|
770
|
+
type: "fs.stat.result",
|
|
771
|
+
id: e.id,
|
|
772
|
+
metadata: { path: e.path, kind: "file", size: 0 }
|
|
773
|
+
}),
|
|
774
|
+
"fs.list": (e) => ok({ type: "fs.list.result", id: e.id, entries: [] }),
|
|
775
|
+
"fs.read": (e) => ok({
|
|
776
|
+
type: "fs.read.result",
|
|
777
|
+
id: e.id,
|
|
778
|
+
result: { data: "", offset: 0, bytesRead: 0, eof: true, size: 0 }
|
|
779
|
+
}),
|
|
780
|
+
"fs.write": (e) => ok({
|
|
781
|
+
type: "fs.write.result",
|
|
782
|
+
id: e.id,
|
|
783
|
+
result: { bytesWritten: 0, size: 0 }
|
|
784
|
+
}),
|
|
785
|
+
"fs.mkdir": (e) => ok({ type: "fs.mkdir.result", id: e.id }),
|
|
786
|
+
"fs.remove": (e) => ok({ type: "fs.remove.result", id: e.id }),
|
|
787
|
+
"fs.move": (e) => ok({ type: "fs.move.result", id: e.id }),
|
|
788
|
+
"fs.watch": (e) => ok({ type: "fs.watch.result", id: e.id, watchId: `watch-${String(e.id)}` }),
|
|
789
|
+
"fs.unwatch": (e) => ok({ type: "fs.unwatch.result", id: e.id })
|
|
790
|
+
};
|
|
791
|
+
function createReferenceHandler(options) {
|
|
792
|
+
return (endpoint, envelope) => {
|
|
793
|
+
const type = getEnvelopeType(envelope);
|
|
726
794
|
const verdict = validateEnvelope(envelope);
|
|
727
|
-
records.push({ envelope, verdict, timestamp: now() });
|
|
795
|
+
options.records.push({ envelope, verdict, timestamp: options.now() });
|
|
728
796
|
if (!type || !verdict.ok) return [];
|
|
729
797
|
const env = envelope;
|
|
730
|
-
if (type === "intent.invoke") return
|
|
798
|
+
if (type === "intent.invoke") return options.intents.handleInvoke(endpoint, env);
|
|
731
799
|
if (type === "intent.available") {
|
|
732
|
-
return ok({ type: "intent.available.result", id: env.id, availability:
|
|
800
|
+
return ok({ type: "intent.available.result", id: env.id, availability: options.intents.availability(env.archetype) });
|
|
733
801
|
}
|
|
734
802
|
if (type === "intent.handlers") {
|
|
735
|
-
return ok({ type: "intent.handlers.result", id: env.id, handlers: [
|
|
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 [];
|
|
803
|
+
return ok({ type: "intent.handlers.result", id: env.id, handlers: [options.intents.availability("note")] });
|
|
748
804
|
}
|
|
805
|
+
if (type === "inc.emit") return handleIncEmit(endpoint, env, options.queueDelivery);
|
|
749
806
|
const responder = RESPONDERS[type];
|
|
750
807
|
return responder ? responder(env) : [];
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
function getEnvelopeType(envelope) {
|
|
811
|
+
if (!envelope || typeof envelope !== "object") return void 0;
|
|
812
|
+
const type = envelope.type;
|
|
813
|
+
return typeof type === "string" ? type : void 0;
|
|
814
|
+
}
|
|
815
|
+
function handleIncEmit(endpoint, env, queueDelivery) {
|
|
816
|
+
if (env.topic !== REFERENCE_CONVENTION) return [];
|
|
817
|
+
const event = {
|
|
818
|
+
type: "inc.event",
|
|
819
|
+
topic: env.topic,
|
|
820
|
+
sender: endpoint.dTag
|
|
821
|
+
};
|
|
822
|
+
if ("payload" in env) event.payload = env.payload;
|
|
823
|
+
queueDelivery(REFERENCE_SUBSCRIBER, event);
|
|
824
|
+
return [];
|
|
825
|
+
}
|
|
826
|
+
function unavailableIntent(id, archetype, action, error) {
|
|
827
|
+
return ok({
|
|
828
|
+
type: "intent.invoke.result",
|
|
829
|
+
id,
|
|
830
|
+
result: { ok: false, archetype, action, handled: false, error }
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
function createIntentHandlers() {
|
|
834
|
+
return { handleInvoke, availability };
|
|
835
|
+
}
|
|
836
|
+
function handleInvoke(_endpoint, env) {
|
|
837
|
+
const request = env.request;
|
|
838
|
+
if (typeof request !== "object" || request === null || Array.isArray(request)) {
|
|
839
|
+
return unavailableIntent(env.id, "", "open", "invalid intent request");
|
|
840
|
+
}
|
|
841
|
+
const intent = request;
|
|
842
|
+
const archetype = typeof intent.archetype === "string" ? intent.archetype : "";
|
|
843
|
+
const action = typeof intent.action === "string" ? intent.action : "open";
|
|
844
|
+
if (!archetype) {
|
|
845
|
+
return unavailableIntent(env.id, archetype, action, "intent request requires an archetype");
|
|
751
846
|
}
|
|
752
|
-
|
|
753
|
-
|
|
847
|
+
if (archetype !== "note") return unavailableIntent(env.id, archetype, action, "no handler");
|
|
848
|
+
if (intent.convention !== void 0 && intent.convention !== REFERENCE_CONVENTION) {
|
|
849
|
+
return unavailableIntent(env.id, archetype, action, "unsupported convention");
|
|
850
|
+
}
|
|
851
|
+
return ok({
|
|
852
|
+
type: "intent.invoke.result",
|
|
853
|
+
id: env.id,
|
|
854
|
+
result: {
|
|
855
|
+
ok: true,
|
|
856
|
+
archetype,
|
|
857
|
+
action,
|
|
858
|
+
handled: true,
|
|
859
|
+
handler: REFERENCE_HANDLER,
|
|
860
|
+
windowId: "reference-window",
|
|
861
|
+
convention: typeof intent.convention === "string" ? intent.convention : REFERENCE_CONVENTION
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
function availability(archetype) {
|
|
866
|
+
if (archetype !== "note") {
|
|
867
|
+
return { archetype, available: false, candidates: [], hasDefault: false };
|
|
754
868
|
}
|
|
869
|
+
return {
|
|
870
|
+
archetype,
|
|
871
|
+
available: true,
|
|
872
|
+
candidates: [{
|
|
873
|
+
dTag: REFERENCE_HANDLER,
|
|
874
|
+
actions: ["open"],
|
|
875
|
+
conventions: [REFERENCE_CONVENTION],
|
|
876
|
+
isDefault: true
|
|
877
|
+
}],
|
|
878
|
+
hasDefault: true
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
function createReferenceShell(options = {}) {
|
|
882
|
+
const records = [];
|
|
883
|
+
const deliveries = createDeliveryQueue();
|
|
884
|
+
const handleFrom = createReferenceHandler({
|
|
885
|
+
now: options.now ?? Date.now,
|
|
886
|
+
records,
|
|
887
|
+
queueDelivery: deliveries.queue,
|
|
888
|
+
intents: createIntentHandlers()
|
|
889
|
+
});
|
|
755
890
|
return {
|
|
756
891
|
get records() {
|
|
757
892
|
return records;
|
|
758
893
|
},
|
|
759
|
-
handle,
|
|
894
|
+
handle: (envelope) => handleFrom(REFERENCE_ENDPOINT, envelope),
|
|
760
895
|
handleFrom,
|
|
761
|
-
takeDeliveries,
|
|
896
|
+
takeDeliveries: deliveries.take,
|
|
762
897
|
reset() {
|
|
763
898
|
records.length = 0;
|
|
764
|
-
|
|
899
|
+
deliveries.clear();
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
function createDeliveryQueue() {
|
|
904
|
+
const queues = /* @__PURE__ */ new Map();
|
|
905
|
+
return {
|
|
906
|
+
queue(target, delivery) {
|
|
907
|
+
const queue = queues.get(target);
|
|
908
|
+
if (queue) queue.push(delivery);
|
|
909
|
+
else queues.set(target, [delivery]);
|
|
910
|
+
},
|
|
911
|
+
take(target) {
|
|
912
|
+
const queue = queues.get(target) ?? [];
|
|
913
|
+
queues.delete(target);
|
|
914
|
+
return queue;
|
|
915
|
+
},
|
|
916
|
+
clear() {
|
|
917
|
+
queues.clear();
|
|
765
918
|
}
|
|
766
919
|
};
|
|
767
920
|
}
|
|
@@ -814,11 +967,14 @@ var NappletConformanceHostBundle = (() => {
|
|
|
814
967
|
napplet.resource.info = () =>
|
|
815
968
|
request({ type: 'resource.info' }, 'resource.info.result', 'resource.info.error')
|
|
816
969
|
.then((msg) => msg.info);
|
|
817
|
-
napplet.resource.bytes = (url) =>
|
|
818
|
-
|
|
970
|
+
napplet.resource.bytes = (url, options) => {
|
|
971
|
+
const message = { type: 'resource.bytes', url: String(url) };
|
|
972
|
+
if (options && options.servers !== undefined) message.servers = options.servers;
|
|
973
|
+
return request(message, 'resource.bytes.result', 'resource.bytes.error')
|
|
819
974
|
.then((msg) => msg.blob);
|
|
820
|
-
|
|
821
|
-
|
|
975
|
+
};
|
|
976
|
+
napplet.resource.bytesMany = (requests) =>
|
|
977
|
+
request({ type: 'resource.bytesMany', requests: Array.from(requests || []) }, 'resource.bytesMany.result', 'resource.bytesMany.error')
|
|
822
978
|
.then((msg) => msg.items);
|
|
823
979
|
napplet.resource.bytesAsObjectURL = (url) => {
|
|
824
980
|
const handle = { url: '', revoke: () => {} };
|
|
@@ -0,0 +1,116 @@
|
|
|
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 at=["relay","identity","storage","inc","theme","keys","media","notify","config","resource","cvm","outbox","upload","intent","ble","webrtc","link","count","lists","serial","fs","common","dm"],l={id:"string"},An={"relay.subscribe":{dir:"out",fields:{...l,subId:"string",filters:"array"}},"relay.close":{dir:"out",fields:{...l,subId:"string"}},"relay.publish":{dir:"out",fields:{...l,event:"object"}},"relay.publishEncrypted":{dir:"out",fields:{...l,event:"object",recipient:"string"}},"relay.query":{dir:"out",fields:{...l,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:{...l}},"identity.getRelays":{dir:"out",fields:{...l}},"identity.getProfile":{dir:"out",fields:{...l}},"identity.getFollows":{dir:"out",fields:{...l}},"identity.getList":{dir:"out",fields:{...l,listType:"string"}},"identity.getZaps":{dir:"out",fields:{...l}},"identity.getMutes":{dir:"out",fields:{...l}},"identity.getBlocked":{dir:"out",fields:{...l}},"identity.getBadges":{dir:"out",fields:{...l}},"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:{...l,key:"string"}},"storage.set":{dir:"out",fields:{...l,key:"string",value:"string"}},"storage.remove":{dir:"out",fields:{...l,key:"string"}},"storage.keys":{dir:"out",fields:{...l}},"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:{...l,topic:"string"}},"inc.unsubscribe":{dir:"out",fields:{topic:"string"}},"inc.channel.open":{dir:"out",fields:{...l,target:"string"}},"inc.channel.emit":{dir:"out",fields:{channelId:"string"}},"inc.channel.broadcast":{dir:"out"},"inc.channel.list":{dir:"out",fields:{...l}},"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:{...l}},"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:{...l,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:{...l,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:{...l,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:{...l}},"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:{...l,schema:"object"}},"config.get":{dir:"out",fields:{...l}},"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:{...l}},"resource.bytes":{dir:"out",fields:{...l,url:"string"}},"resource.bytesMany":{dir:"out",fields:{...l,requests:"array"}},"resource.cancel":{dir:"out",fields:{...l}},"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:{...l}},"cvm.request":{dir:"out",fields:{...l,server:"object",message:"object"}},"cvm.close":{dir:"out",fields:{...l,server:"object"}},"cvm.registry.list":{dir:"out",fields:{...l}},"cvm.registry.has":{dir:"out",fields:{...l,family:"string"}},"cvm.registry.describe":{dir:"out",fields:{...l,family:"string"}},"cvm.registry.call":{dir:"out",fields:{...l,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:{...l,eventId:"string"}},"outbox.query":{dir:"out",fields:{...l,filters:"present"}},"outbox.subscribe":{dir:"out",fields:{...l,subId:"string",filters:"present"}},"outbox.close":{dir:"out",fields:{...l,subId:"string"}},"outbox.publish":{dir:"out",fields:{...l,event:"object"}},"outbox.resolveRelays":{dir:"out",fields:{...l,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:{...l}},"upload.upload":{dir:"out",fields:{...l,request:"object"}},"upload.status":{dir:"out",fields:{...l,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:{...l,request:"object"}},"intent.available":{dir:"out",fields:{...l,archetype:"string"}},"intent.handlers":{dir:"out",fields:{...l}},"intent.invoke.result":{dir:"in",fields:{...l,result:"object"}},"intent.available.result":{dir:"in"},"intent.handlers.result":{dir:"in"},"intent.changed":{dir:"in"},"ble.open":{dir:"out",fields:{...l,request:"object"}},"ble.services":{dir:"out",fields:{...l,sessionId:"string"}},"ble.read":{dir:"out",fields:{...l,sessionId:"string",target:"object"}},"ble.write":{dir:"out",fields:{...l,sessionId:"string",target:"object",data:"array"}},"ble.subscribe":{dir:"out",fields:{...l,sessionId:"string",target:"object"}},"ble.unsubscribe":{dir:"out",fields:{...l,sessionId:"string",target:"object"}},"ble.close":{dir:"out",fields:{...l,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:{...l,input:"object"}},"common.decodeNip19":{dir:"out",fields:{...l,value:"string"}},"common.getProfile":{dir:"out",fields:{...l,target:"string"}},"common.follows":{dir:"out",fields:{...l}},"common.follow":{dir:"out",fields:{...l,pubkeys:"array"}},"common.unfollow":{dir:"out",fields:{...l,pubkeys:"array"}},"common.react":{dir:"out",fields:{...l,targetEventId:"string",reaction:"string"}},"common.report":{dir:"out",fields:{...l,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:{...l,request:"object"}},"webrtc.send":{dir:"out",fields:{...l,sessionId:"string",payload:"present"}},"webrtc.close":{dir:"out",fields:{...l,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:{...l,url:"string"}},"link.open.result":{dir:"in"},"count.query":{dir:"out",fields:{...l,filters:"array"}},"count.query.result":{dir:"in"},"lists.supported":{dir:"out",fields:{...l}},"lists.add":{dir:"out",fields:{...l,list:"object",items:"array"}},"lists.remove":{dir:"out",fields:{...l,list:"object",items:"array"}},"lists.supported.result":{dir:"in"},"lists.add.result":{dir:"in"},"lists.remove.result":{dir:"in"},"serial.open":{dir:"out",fields:{...l,request:"object"}},"serial.write":{dir:"out",fields:{...l,sessionId:"string",data:"array"}},"serial.close":{dir:"out",fields:{...l,sessionId:"string"}},"serial.open.result":{dir:"in"},"serial.write.result":{dir:"in"},"serial.close.result":{dir:"in"},"serial.event":{dir:"in"},"fs.info":{dir:"out",fields:{...l}},"fs.pickFile":{dir:"out",fields:{...l}},"fs.pickFiles":{dir:"out",fields:{...l}},"fs.pickDirectory":{dir:"out",fields:{...l}},"fs.pickSaveFile":{dir:"out",fields:{...l}},"fs.stat":{dir:"out",fields:{...l,path:"string"}},"fs.list":{dir:"out",fields:{...l,path:"string"}},"fs.read":{dir:"out",fields:{...l,path:"string"}},"fs.write":{dir:"out",fields:{...l,path:"string",data:"string"}},"fs.mkdir":{dir:"out",fields:{...l,path:"string"}},"fs.remove":{dir:"out",fields:{...l,path:"string"}},"fs.move":{dir:"out",fields:{...l,fromPath:"string",toPath:"string"}},"fs.watch":{dir:"out",fields:{...l,path:"string"}},"fs.unwatch":{dir:"out",fields:{...l,watchId:"string"}},"fs.info.result":{dir:"in"},"fs.pickFile.result":{dir:"in"},"fs.pickFiles.result":{dir:"in"},"fs.pickDirectory.result":{dir:"in"},"fs.pickSaveFile.result":{dir:"in"},"fs.stat.result":{dir:"in"},"fs.list.result":{dir:"in"},"fs.read.result":{dir:"in"},"fs.write.result":{dir:"in"},"fs.mkdir.result":{dir:"in"},"fs.remove.result":{dir:"in"},"fs.move.result":{dir:"in"},"fs.watch.result":{dir:"in"},"fs.unwatch.result":{dir:"in"},"fs.changed":{dir:"in"},"dm.status":{dir:"out",fields:{...l}},"dm.conversations":{dir:"out",fields:{...l}},"dm.messages":{dir:"out",fields:{...l,conversationId:"string"}},"dm.send":{dir:"out",fields:{...l,recipients:"array",content:"string"}},"dm.subscribe":{dir:"out",fields:{...l}},"dm.unsubscribe":{dir:"out",fields:{...l,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 Ht(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 Tn(e,t){return t==="present"?e!=null:Ht(e)===t}function Bn(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 jt(e,t,r){Array.isArray(e)&&e.every(n=>typeof n=="string")||r.push({code:"wrong-type",message:`Field "${t}" must be an array of strings`,field:t})}function On(e,t){e.servers!==void 0&&jt(e.servers,"servers",t)}function qn(e,t){if(Array.isArray(e)){if(e.length===0){t.push({code:"invalid-resource-request",message:'Field "requests" must contain at least one resource request',field:"requests"});return}for(const[r,n]of e.entries()){const i=`requests[${r}]`;if(typeof n!="object"||n===null||Array.isArray(n)){t.push({code:"invalid-resource-request",message:`Field "${i}" must be a resource request object`,field:i});continue}const s=n;typeof s.url!="string"&&t.push({code:s.url===void 0?"missing-field":"wrong-type",message:`Field "${i}.url" must be a string`,field:`${i}.url`}),s.servers!==void 0&&jt(s.servers,`${i}.servers`,t)}}}function Nn(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(!at.includes(s))return{ok:!1,type:n,domain:s,errors:[{code:"unknown-domain",message:`"${s}" is not a known NAP domain`}]};const c=An[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,d]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}Tn(r[a],d)||t.push({code:"wrong-type",message:`Field "${a}" should be ${d} but is ${Ht(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"&&Bn(r.request,t),n==="resource.bytes"&&On(r,t),n==="resource.bytesMany"&&qn(r.requests,t),{ok:t.length===0,type:n,domain:s,direction:"out",errors:t}}var Dt=5129,Mt=15129,ge=35129,ct=[Dt,Mt,ge];function Ft(e,t){return e.tags.find(r=>r[0]===t)}function Ln(e){return ct.includes(e)}function Pn(e){return typeof e=="string"&&/^[0-9a-f]{64}$/i.test(e)}function Wt(e){return Ft(e,"d")?.[1]?.trim()||void 0}function _n(e){return e.tags.filter(t=>t[0]==="requires").map(t=>t[1]?.trim()??"").filter(Boolean)}function Zt(e){return Wt(e)??Ft(e,"title")?.[1]??e.id}function lt(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=Wt(e),i=_n(e);Ln(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===Mt||e.kind===Dt)&&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?Pn(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}at.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),Cn={dTag:"reference-source"},Un="https://reference.invalid/blob",Vt="reference-handler",Hn="reference-subscriber",Be="napplet:note/open";function ke(e,t,r){return u({type:e,id:t,result:{entries:[r]}})}var u=e=>[e],N=()=>[];function wt(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,d=>d.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 jn={"relay.subscribe":e=>u({type:"relay.eose",subId:e.subId}),"relay.close":N,"relay.publish":e=>u({type:"relay.publish.result",id:e.id,ok:!0,event:e.event}),"relay.publishEncrypted":e=>u({type:"relay.publishEncrypted.result",id:e.id,ok:!0,event:e.event}),"relay.query":e=>u({type:"relay.query.result",id:e.id,events:[]}),"identity.getPublicKey":e=>u({type:"identity.getPublicKey.result",id:e.id,pubkey:xe}),"identity.getRelays":e=>u({type:"identity.getRelays.result",id:e.id,relays:{}}),"identity.getProfile":e=>u({type:"identity.getProfile.result",id:e.id,profile:null}),"identity.getFollows":e=>u({type:"identity.getFollows.result",id:e.id,pubkeys:[]}),"identity.getList":e=>u({type:"identity.getList.result",id:e.id,entries:[]}),"identity.getZaps":e=>u({type:"identity.getZaps.result",id:e.id,zaps:[]}),"identity.getMutes":e=>u({type:"identity.getMutes.result",id:e.id,pubkeys:[]}),"identity.getBlocked":e=>u({type:"identity.getBlocked.result",id:e.id,pubkeys:[]}),"identity.getBadges":e=>u({type:"identity.getBadges.result",id:e.id,badges:[]}),"storage.get":e=>u({type:"storage.get.result",id:e.id,value:null}),"storage.set":e=>u({type:"storage.set.result",id:e.id}),"storage.remove":e=>u({type:"storage.remove.result",id:e.id}),"storage.keys":e=>u({type:"storage.keys.result",id:e.id,keys:[]}),"inc.emit":N,"inc.subscribe":e=>u({type:"inc.subscribe.result",id:e.id}),"inc.unsubscribe":N,"inc.channel.open":e=>u({type:"inc.channel.open.result",id:e.id,channelId:`chan-${String(e.id)}`,peer:"reference-peer"}),"inc.channel.emit":N,"inc.channel.broadcast":N,"inc.channel.list":e=>u({type:"inc.channel.list.result",id:e.id,channels:[]}),"inc.channel.close":N,"theme.get":e=>u({type:"theme.get.result",id:e.id,theme:{colors:{},mode:"dark"}}),"keys.forward":N,"keys.registerAction":e=>u({type:"keys.registerAction.result",id:e.id,actionId:`action-${String(e.id)}`}),"keys.unregisterAction":N,"media.session.create":e=>u({type:"media.session.create.result",id:e.id,sessionId:`session-${String(e.id)}`,owner:e.owner}),"media.session.update":N,"media.session.destroy":N,"media.state":N,"media.capabilities":N,"notify.send":e=>u({type:"notify.send.result",id:e.id,notificationId:`notif-${String(e.id)}`}),"notify.dismiss":N,"notify.badge":N,"notify.channel.register":N,"notify.permission.request":e=>u({type:"notify.permission.result",id:e.id,granted:!0}),"config.registerSchema":e=>u({type:"config.registerSchema.result",id:e.id,ok:!0}),"config.get":e=>u({type:"config.values",id:e.id,values:{}}),"config.subscribe":()=>u({type:"config.values",values:{}}),"config.unsubscribe":N,"config.openSettings":N,"resource.bytes":e=>{const t=wt(e.url);return u(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=>u({type:"resource.bytesMany.result",id:e.id,items:Array.isArray(e.requests)?e.requests.map(t=>{const r=typeof t=="object"&&t!==null&&!Array.isArray(t)?t.url:void 0,n=wt(r);return{url:typeof r=="string"?r:"",ok:!0,blob:n?.blob??new Blob([]),mime:n?.mime??"application/octet-stream"}}):[]}),"resource.info":e=>u({type:"resource.info.result",id:e.id,info:{schemes:[{scheme:"data",enabled:!0},{scheme:"https",enabled:!0}],maxServers:8}}),"resource.cancel":N,"cvm.discover":e=>u({type:"cvm.discover.result",id:e.id,servers:[]}),"cvm.request":e=>u({type:"cvm.request.result",id:e.id,message:{}}),"cvm.close":e=>u({type:"cvm.close.result",id:e.id}),"outbox.getEvent":e=>u({type:"outbox.getEvent.result",id:e.id}),"outbox.query":e=>u({type:"outbox.query.result",id:e.id,events:[]}),"outbox.subscribe":e=>u({type:"outbox.closed",subId:e.subId,reason:"reference shell complete"}),"outbox.close":N,"outbox.publish":e=>u({type:"outbox.publish.result",id:e.id,ok:!0}),"outbox.resolveRelays":e=>u({type:"outbox.resolveRelays.result",id:e.id,plan:{}}),"upload.info":e=>u({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=>u({type:"upload.upload.result",id:e.id,result:{url:Un}}),"upload.status":e=>u({type:"upload.status.result",id:e.id,status:{}}),"ble.open":e=>u({type:"ble.open.result",id:e.id,session:{id:"ble-reference",state:"open",device:{id:"reference-device",name:"Reference BLE"}}}),"ble.services":e=>u({type:"ble.services.result",id:e.id,services:[]}),"ble.read":e=>u({type:"ble.read.result",id:e.id,data:[]}),"ble.write":e=>u({type:"ble.write.result",id:e.id}),"ble.subscribe":e=>u({type:"ble.subscribe.result",id:e.id}),"ble.unsubscribe":e=>u({type:"ble.unsubscribe.result",id:e.id}),"ble.close":e=>u({type:"ble.close.result",id:e.id}),"common.encodeNip19":e=>u({type:"common.encodeNip19.result",id:e.id,ok:!0,value:"npub1reference",nip19Type:"npub"}),"common.decodeNip19":e=>u({type:"common.decodeNip19.result",id:e.id,ok:!0,nip19Type:"npub",hex:xe}),"common.getProfile":e=>u({type:"common.getProfile.result",id:e.id,ok:!0,pubkey:xe,profile:null}),"common.follows":e=>u({type:"common.follows.result",id:e.id,ok:!0,pubkeys:[]}),"common.follow":e=>u({type:"common.follow.result",id:e.id,ok:!0}),"common.unfollow":e=>u({type:"common.unfollow.result",id:e.id,ok:!0}),"common.react":e=>u({type:"common.react.result",id:e.id,ok:!0,eventId:"0".repeat(64)}),"common.report":e=>u({type:"common.report.result",id:e.id,ok:!0,eventId:"1".repeat(64)}),"webrtc.open":e=>u({type:"webrtc.open.result",id:e.id,session:{id:"webrtc-reference",scope:{type:"direct",pubkey:xe},channel:"default",state:"connecting"}}),"webrtc.send":e=>u({type:"webrtc.send.result",id:e.id}),"webrtc.close":e=>u({type:"webrtc.close.result",id:e.id}),"link.open":e=>u({type:"link.open.result",id:e.id,status:"opened"}),"count.query":e=>u({type:"count.query.result",id:e.id,ok:!0,count:0}),"lists.supported":e=>u({type:"lists.supported.result",id:e.id,lists:[]}),"lists.add":e=>u({type:"lists.add.result",id:e.id,ok:!0,added:0,skipped:0}),"lists.remove":e=>u({type:"lists.remove.result",id:e.id,ok:!0,removed:0,skipped:0}),"serial.open":e=>u({type:"serial.open.result",id:e.id,session:{id:`serial-${String(e.id)}`,state:"open"}}),"serial.write":e=>u({type:"serial.write.result",id:e.id}),"serial.close":e=>u({type:"serial.close.result",id:e.id}),"fs.info":e=>u({type:"fs.info.result",id:e.id,info:{roots:[{path:"/shared",name:"Shared files",permissions:["read","list","write","create","delete","watch"]}],limits:{maxReadBytes:1048576,maxWriteBytes:1048576,maxWatchCount:16}}}),"fs.pickFile":e=>ke("fs.pickFile.result",e.id,{path:"/picked/file.txt",kind:"file",name:"file.txt",permissions:["read"]}),"fs.pickFiles":e=>ke("fs.pickFiles.result",e.id,{path:"/picked/file.txt",kind:"file",name:"file.txt",permissions:["read"]}),"fs.pickDirectory":e=>ke("fs.pickDirectory.result",e.id,{path:"/picked",kind:"directory",name:"picked",permissions:["read","list"]}),"fs.pickSaveFile":e=>ke("fs.pickSaveFile.result",e.id,{path:"/picked/export.json",kind:"file",name:"export.json",permissions:["write","create"]}),"fs.stat":e=>u({type:"fs.stat.result",id:e.id,metadata:{path:e.path,kind:"file",size:0}}),"fs.list":e=>u({type:"fs.list.result",id:e.id,entries:[]}),"fs.read":e=>u({type:"fs.read.result",id:e.id,result:{data:"",offset:0,bytesRead:0,eof:!0,size:0}}),"fs.write":e=>u({type:"fs.write.result",id:e.id,result:{bytesWritten:0,size:0}}),"fs.mkdir":e=>u({type:"fs.mkdir.result",id:e.id}),"fs.remove":e=>u({type:"fs.remove.result",id:e.id}),"fs.move":e=>u({type:"fs.move.result",id:e.id}),"fs.watch":e=>u({type:"fs.watch.result",id:e.id,watchId:`watch-${String(e.id)}`}),"fs.unwatch":e=>u({type:"fs.unwatch.result",id:e.id})};function Dn(e){return(t,r)=>{const n=Mn(r),i=Nn(r);if(e.records.push({envelope:r,verdict:i,timestamp:e.now()}),!n||!i.ok)return[];const s=r;if(n==="intent.invoke")return e.intents.handleInvoke(t,s);if(n==="intent.available")return u({type:"intent.available.result",id:s.id,availability:e.intents.availability(s.archetype)});if(n==="intent.handlers")return u({type:"intent.handlers.result",id:s.id,handlers:[e.intents.availability("note")]});if(n==="inc.emit")return Fn(t,s,e.queueDelivery);const o=jn[n];return o?o(s):[]}}function Mn(e){if(!e||typeof e!="object")return;const t=e.type;return typeof t=="string"?t:void 0}function Fn(e,t,r){if(t.topic!==Be)return[];const n={type:"inc.event",topic:t.topic,sender:e.dTag};return"payload"in t&&(n.payload=t.payload),r(Hn,n),[]}function Se(e,t,r,n){return u({type:"intent.invoke.result",id:e,result:{ok:!1,archetype:t,action:r,handled:!1,error:n}})}function Wn(){return{handleInvoke:Zn,availability:Vn}}function Zn(e,t){const r=t.request;if(typeof r!="object"||r===null||Array.isArray(r))return Se(t.id,"","open","invalid intent request");const n=r,i=typeof n.archetype=="string"?n.archetype:"",s=typeof n.action=="string"?n.action:"open";return i?i!=="note"?Se(t.id,i,s,"no handler"):n.convention!==void 0&&n.convention!==Be?Se(t.id,i,s,"unsupported convention"):u({type:"intent.invoke.result",id:t.id,result:{ok:!0,archetype:i,action:s,handled:!0,handler:Vt,windowId:"reference-window",convention:typeof n.convention=="string"?n.convention:Be}}):Se(t.id,i,s,"intent request requires an archetype")}function Vn(e){return e!=="note"?{archetype:e,available:!1,candidates:[],hasDefault:!1}:{archetype:e,available:!0,candidates:[{dTag:Vt,actions:["open"],conventions:[Be],isDefault:!0}],hasDefault:!0}}function Kn(e={}){const t=[],r=Yn(),n=Dn({now:e.now??Date.now,records:t,queueDelivery:r.queue,intents:Wn()});return{get records(){return t},handle:i=>n(Cn,i),handleFrom:n,takeDeliveries:r.take,reset(){t.length=0,r.clear()}}}function Yn(){const e=new Map;return{queue(t,r){const n=e.get(t);n?n.push(r):e.set(t,[r])},take(t){const r=e.get(t)??[];return e.delete(t),r},clear(){e.clear()}}}function zn(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 Kt="__nappletConformance.error";function vt(e){return new Promise(t=>setTimeout(t,e))}function Gn(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(/</g,"<").replace(/>/g,">")}function Xn(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, options) => {
|
|
43
|
+
const message = { type: 'resource.bytes', url: String(url) };
|
|
44
|
+
if (options && options.servers !== undefined) message.servers = options.servers;
|
|
45
|
+
return request(message, 'resource.bytes.result', 'resource.bytes.error')
|
|
46
|
+
.then((msg) => msg.blob);
|
|
47
|
+
};
|
|
48
|
+
napplet.resource.bytesMany = (requests) =>
|
|
49
|
+
request({ type: 'resource.bytesMany', requests: Array.from(requests || []) }, 'resource.bytesMany.result', 'resource.bytesMany.error')
|
|
50
|
+
.then((msg) => msg.items);
|
|
51
|
+
napplet.resource.bytesAsObjectURL = (url) => {
|
|
52
|
+
const handle = { url: '', revoke: () => {} };
|
|
53
|
+
let objectUrl = '';
|
|
54
|
+
let revoked = false;
|
|
55
|
+
const ready = napplet.resource.bytes(url).then((blob) => {
|
|
56
|
+
if (revoked) return;
|
|
57
|
+
objectUrl = URL.createObjectURL(blob);
|
|
58
|
+
handle.url = objectUrl;
|
|
59
|
+
return objectUrl;
|
|
60
|
+
});
|
|
61
|
+
handle.revoke = () => {
|
|
62
|
+
if (revoked) return;
|
|
63
|
+
revoked = true;
|
|
64
|
+
if (objectUrl) URL.revokeObjectURL(objectUrl);
|
|
65
|
+
};
|
|
66
|
+
Object.defineProperty(handle, 'ready', { value: ready, enumerable: false });
|
|
67
|
+
return handle;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
window.napplet = napplet;
|
|
71
|
+
const report = (reason) => {
|
|
72
|
+
try {
|
|
73
|
+
window.parent.postMessage({ type: '${Kt}', reason: String(reason && reason.message || reason) }, '*');
|
|
74
|
+
} catch {}
|
|
75
|
+
};
|
|
76
|
+
window.addEventListener('error', (event) => report(event.error || event.message));
|
|
77
|
+
window.addEventListener('unhandledrejection', (event) => report(event.reason));
|
|
78
|
+
})();
|
|
79
|
+
`}function Jn(e,t,r){const n=`<base href="${Gn(t)}">`,i=`<script>${Xn(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 Qn(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 er(e){if(e==="about:blank")return"<!doctype html><html><head></head><body></body></html>";const t=Qn(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 Et(e,t,r,n){const i=Kn(),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=f=>{if(f.source!==s.contentWindow)return;const h=f.data;if(h&&typeof h=="object"&&h.type===Kt){o=`napplet boot error: ${String(h.reason??"unknown error")}`;return}const g=i.handle(f.data),y=f.source;for(const b of g)y?.postMessage(b,"*")};let a=!1;const d=new Promise(f=>{s.addEventListener("load",()=>{a=!0,f()},{once:!0})});n.addEventListener("message",c),(r.body??r.documentElement).appendChild(s);try{const f=await er(t.url);s.srcdoc=Jn(f,t.url,e)}catch(f){o=f instanceof Error?f.message:String(f)}if(!o){const f=Symbol("timeout");await Promise.race([d.then(()=>"loaded"),vt(t.readyTimeoutMs).then(()=>f)])===f||!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 vt(t.settleMs)}n.removeEventListener("message",c);try{s.remove()}catch{}return{installedGlobal:o===null,bootError:o,emitted:[...i.records]}}async function tr(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 Et(at,n,t,r);let s=null;{const o=await Et([],n,t,r);s={bootError:o.bootError,emitted:o.emitted}}return{installedGlobal:i.installedGlobal,bootError:i.bootError,emitted:i.emitted,degraded:s}}var nr=e=>({status:"pass",detail:e}),rr=(e,t)=>({status:"fail",detail:e,diagnostics:t}),ir=e=>({status:"skip",detail:e}),O={pass:nr,fail:rr,skip:ir};function sr(e,t){return lt(e.manifestEvent).errors.filter(r=>t.includes(r.code))}function Me(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=sr(n,r);return i.length?O.fail(i[0].message,i):O.pass()}}}var or=[Me("manifest/event-kind","Resolved event is a NIP-5D napplet manifest",["invalid-napplet-kind","missing-d-tag","unexpected-d-tag"]),Me("manifest/index-html","Manifest declares a hashed /index.html",["missing-index-html","invalid-index-html-hash"]),Me("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 ar(e,t={}){const r=t.now??(()=>Date.now()),n=t.checks??or,i=r(),s=n.map(a=>{const d=a.run(e);return{id:a.id,area:a.area,severity:a.severity,title:a.title,status:d.status,detail:d.detail,diagnostics:d.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 cr(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function dt(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=cr(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 xt(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 lr(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 Je(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function Fe(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function z(e,t){return e<<32-t|e>>>t}const Yt=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",dr=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function _(e){if(D(e),Yt)return e.toHex();let t="";for(let r=0;r<e.length;r++)t+=dr[e[r]];return t}const J={_0:48,_9:57,A:65,F:70,a:97,f:102};function kt(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(Yt)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=kt(e.charCodeAt(s)),c=kt(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 Oe(...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 ur(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 zt(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 fr=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 Gt(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Xt(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 hr(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 Jt(e){if(!Number.isSafeInteger(e))throw new Error(`invalid integer: ${e}`)}function Qe(e){if(!Array.isArray(e))throw new Error("array expected")}function Qt(e,t){if(!Xt(!0,t))throw new Error(`${e}: array of strings expected`)}function en(e,t){if(!Xt(!1,t))throw new Error(`${e}: array of numbers expected`)}function pr(...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 gr(e){const t=typeof e=="string"?e.split(""):e,r=t.length;Qt("alphabet",t);const n=new Map(t.map((i,s)=>[i,s]));return{encode:i=>(Qe(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=>(Qe(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 yr(e=""){return me("join",e),{encode:t=>(Qt("join.decode",t),t.join(e)),decode:t=>(me("join.decode",t),t.split(e))}}const tn=(e,t)=>t===0?e:tn(t,e%t),qe=(e,t)=>e+(t-tn(e,t)),Ae=(()=>{let e=[];for(let t=0;t<40;t++)e.push(2**t);return e})();function et(e,t,r,n){if(Qe(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(qe(t,r)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${r} carryBits=${qe(t,r)}`);let i=0,s=0;const o=Ae[t],c=Ae[r]-1,a=[];for(const d of e){if(Jt(d),d>=o)throw new Error(`convertRadix2: invalid data word=${d} from=${t}`);if(i=i<<t|d,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 f=Ae[s];if(f===void 0)throw new Error("invalid carry");i&=f-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 mr(e,t=!1){if(Jt(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(qe(8,e)>32||qe(e,8)>32)throw new Error("radix2: carry overflow");return{encode:r=>{if(!Gt(r))throw new Error("radix2.encode input should be Uint8Array");return et(Array.from(r),8,e,!t)},decode:r=>(en("radix2.decode",r),Uint8Array.from(et(r,e,8,t)))}}function St(e){return hr(e),function(...t){try{return e.apply(null,t)}catch{}}}const tt=pr(gr("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),yr("")),Rt=[996825010,642813549,513874426,1027748829,705979059];function fe(e){const t=e>>25;let r=(e&33554431)<<5;for(let n=0;n<Rt.length;n++)(t>>n&1)===1&&(r^=Rt[n]);return r}function $t(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,tt.encode(et([i%Ae[30]],30,5,!1))}function br(e){const t=e==="bech32"?1:734539939,r=mr(5),n=r.decode,i=r.encode,s=St(n);function o(h,g,y=90){me("bech32.encode prefix",h),Gt(g)&&(g=Array.from(g)),en("bech32.encode",g);const b=h.length;if(b===0)throw new TypeError(`Invalid prefix length ${b}`);const E=b+7+g.length;if(y!==!1&&E>y)throw new TypeError(`Length ${E} exceeds limit ${y}`);const q=h.toLowerCase(),L=$t(q,g,t);return`${q}1${tt.encode(g)}${L}`}function c(h,g=90){me("bech32.decode input",h);const y=h.length;if(y<8||g!==!1&&y>g)throw new TypeError(`invalid string length: ${y} (${h}). Expected (8..${g})`);const b=h.toLowerCase();if(h!==b&&h!==h.toUpperCase())throw new Error("String must be lowercase or uppercase");const E=b.lastIndexOf("1");if(E===0||E===-1)throw new Error('Letter "1" must be present between prefix and data only');const q=b.slice(0,E),L=b.slice(E+1);if(L.length<6)throw new Error("Data must be at least 6 characters long");const K=tt.decode(L).slice(0,-6),Q=$t(q,K,t);if(!L.endsWith(Q))throw new Error(`Invalid checksum in ${h}: expected "${Q}"`);return{prefix:q,words:K}}const a=St(c);function d(h){const{prefix:g,words:y}=c(h,!1);return{prefix:g,words:y,bytes:n(y)}}function f(h,g){return o(h,i(g))}return{encode:o,decode:c,encodeFromBytes:f,decodeToBytes:d,decodeUnsafe:a,fromWords:n,fromWordsUnsafe:s,toWords:i}}const It=br("bech32");var Re=new TextDecoder("utf-8");new TextEncoder;var wr=5e3;function vr(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),Er(e)}catch{return{type:"invalid",data:null}}}function Er(e){let{prefix:t,words:r}=It.decode(e,wr),n=new Uint8Array(It.fromWords(r));switch(t){case"nprofile":{let i=We(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=>Re.decode(s)):[]}}}case"nevent":{let i=We(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=>Re.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=We(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:Re.decode(i[0][0]),pubkey:_(i[2][0]),kind:parseInt(_(i[3][0]),16),relays:i[1]?i[1].map(s=>Re.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 We(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 xr(e,t,r){return e&t^~e&r}function kr(e,t,r){return e&t^e&r^t&r}class Sr{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=Fe(this.buffer)}update(t){xt(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=Fe(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){xt(this),lr(t,this),this.finished=!0;const{buffer:r,view:n,blockLen:i,isLE:s}=this;let{pos:o}=this;r[o++]=128,Je(this.buffer.subarray(o)),this.padOffset>i-o&&(this.process(n,0),o=0);for(let h=o;h<i;h++)r[h]=0;n.setBigUint64(i-8,BigInt(this.length*8),s),this.process(n,0);const c=Fe(t),a=this.outputLen;if(a%4)throw new Error("_sha2: outputLen must be aligned to 32bit");const d=a/4,f=this.get();if(d>f.length)throw new Error("_sha2: outputLen bigger than state");for(let h=0;h<d;h++)c.setUint32(4*h,f[h],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]),Rr=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 $r extends Sr{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 h=0;h<16;h++,r+=4)te[h]=t.getUint32(r,!1);for(let h=16;h<64;h++){const g=te[h-15],y=te[h-2],b=z(g,7)^z(g,18)^g>>>3,E=z(y,17)^z(y,19)^y>>>10;te[h]=E+te[h-7]+b+te[h-16]|0}let{A:n,B:i,C:s,D:o,E:c,F:a,G:d,H:f}=this;for(let h=0;h<64;h++){const g=z(c,6)^z(c,11)^z(c,25),y=f+g+xr(c,a,d)+Rr[h]+te[h]|0,E=(z(n,2)^z(n,13)^z(n,22))+kr(n,i,s)|0;f=d,d=a,a=c,c=o+y|0,o=s,s=i,i=n,n=y+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,d=d+this.G|0,f=f+this.H|0,this.set(n,i,s,o,c,a,d,f)}roundClean(){Je(te)}destroy(){this.set(0,0,0,0,0,0,0,0),Je(this.buffer)}}class Ir extends $r{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 Ne=ur(()=>new Ir,fr(1));/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const ut=BigInt(0),nt=BigInt(1);function At(e,t=""){if(typeof e!="boolean"){const r=t&&`"${t}" `;throw new Error(r+"expected boolean, got type="+typeof e)}return e}function Ar(e){if(typeof e=="bigint"){if(!Or(e))throw new Error("positive bigint expected, got "+e)}else dt(e);return e}function nn(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);return e===""?ut:BigInt("0x"+e)}function ft(e){return nn(_(e))}function rn(e){return nn(_(Tr(D(e)).reverse()))}function ht(e,t){dt(t),e=Ar(e);const r=X(e.toString(16).padStart(t*2,"0"));if(r.length!==t)throw new Error("number too large");return r}function sn(e,t){return ht(e,t).reverse()}function Tr(e){return Uint8Array.from(e)}function Br(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 Or=e=>typeof e=="bigint"&&ut<=e;function qr(e){let t;for(t=0;e>ut;e>>=nt,t+=1);return t}const on=e=>(nt<<BigInt(e))-nt;function an(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 d=typeof a;if(d!==o||a===null)throw new Error(`param "${s}" is invalid: expected ${o}, got ${d}`)}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),cn=BigInt(3),ln=BigInt(4),dn=BigInt(5),Nr=BigInt(7),un=BigInt(8),Lr=BigInt(9),fn=BigInt(16);function V(e,t){const r=e%t;return r>=j?r:t+r}function F(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=V(e,t),n=t,i=j,s=H;for(;r!==j;){const c=n/r,a=n%r,d=i-s*c;n=r,r=a,i=s,s=d}if(n!==H)throw new Error("invert: does not exist");return V(i,t)}function pt(e,t,r){if(!e.eql(e.sqr(t),r))throw new Error("Cannot find square root")}function hn(e,t){const r=(e.ORDER+H)/ln,n=e.pow(t,r);return pt(e,n,t),n}function Pr(e,t){const r=(e.ORDER-dn)/un,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 pt(e,c,t),c}function _r(e){const t=Ce(e),r=pn(e),n=r(t,t.neg(t.ONE)),i=r(t,n),s=r(t,t.neg(n)),o=(e+Nr)/fn;return(c,a)=>{let d=c.pow(a,o),f=c.mul(d,n);const h=c.mul(d,i),g=c.mul(d,s),y=c.eql(c.sqr(f),a),b=c.eql(c.sqr(h),a);d=c.cmov(d,f,y),f=c.cmov(g,h,b);const E=c.eql(c.sqr(f),a),q=c.cmov(d,f,E);return pt(c,q,a),q}}function pn(e){if(e<cn)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=Ce(e);for(;Ot(i,n)===1;)if(n++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(r===1)return hn;let s=i.pow(n,t);const o=(t+H)/se;return function(a,d){if(a.is0(d))return d;if(Ot(a,d)!==1)throw new Error("Cannot find square root");let f=r,h=a.mul(a.ONE,s),g=a.pow(d,t),y=a.pow(d,o);for(;!a.eql(g,a.ONE);){if(a.is0(g))return a.ZERO;let b=1,E=a.sqr(g);for(;!a.eql(E,a.ONE);)if(b++,E=a.sqr(E),b===f)throw new Error("Cannot find square root");const q=H<<BigInt(f-b-1),L=a.pow(h,q);f=b,h=a.sqr(L),g=a.mul(g,h),y=a.mul(y,L)}return y}}function Cr(e){return e%ln===cn?hn:e%un===dn?Pr:e%fn===Lr?_r(e):pn(e)}const Ur=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Hr(e){const t={ORDER:"bigint",BYTES:"number",BITS:"number"},r=Ur.reduce((n,i)=>(n[i]="function",n),t);return an(e,r),e}function jr(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 gn(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 Ot(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 Dr(e,t){t!==void 0&&dt(t);const r=t!==void 0?t:e.toString(2).length,n=Math.ceil(r/8);return{nBitLength:r,nByteLength:n}}class Mr{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}=Dr(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 V(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 V(-t,this.ORDER)}eql(t,r){return t===r}sqr(t){return V(t*t,this.ORDER)}add(t,r){return V(t+r,this.ORDER)}sub(t,r){return V(t-r,this.ORDER)}mul(t,r){return V(t*r,this.ORDER)}pow(t,r){return jr(this,t,r)}div(t,r){return V(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=Cr(this.ORDER)),this._sqrt(this,t)}toBytes(t){return this.isLE?sn(t,this.BYTES):ht(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 d=new Uint8Array(i);d.set(t,s?0:d.length-t.length),t=d}if(t.length!==i)throw new Error("Field.fromBytes: expected "+i+" bytes, got "+t.length);let a=s?rn(t):ft(t);if(c&&(a=V(a,o)),!r&&!this.isValid(a))throw new Error("invalid field element: outside of range 0..ORDER");return a}invertBatch(t){return gn(this,t)}cmov(t,r,n){return n?r:t}}function Ce(e,t={}){return new Mr(e,t)}function yn(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 Fr(e){const t=yn(e);return t+Math.ceil(t/2)}function Wr(e,t,r=!1){D(e);const n=e.length,i=yn(t),s=Fr(t);if(n<16||n<s||n>1024)throw new Error("expected "+s+"-1024 bytes of input, got "+n);const o=r?rn(e):ft(e),c=V(o,t-H)+H;return r?sn(c,i):ht(c,i)}/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */const le=BigInt(0),oe=BigInt(1);function Le(e,t){const r=t.negate();return e?r:t}function qt(e,t){const r=gn(e.Fp,t.map(n=>n.Z));return t.map((n,i)=>e.fromAffine(n.toAffine(r[i])))}function mn(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){mn(e,t);const r=Math.ceil(t/e)+1,n=2**(e-1),i=2**e,s=on(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 d=t*n,f=d+Math.abs(c)-1,h=c===0,g=c<0,y=t%2!==0;return{nextN:a,offset:f,isZero:h,isNeg:g,isNegF:y,offsetF:d}}const Ve=new WeakMap,bn=new WeakMap;function Ke(e){return bn.get(e)||1}function Lt(e){if(e!==le)throw new Error("invalid wNAF")}class Zr{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 d=1;d<i;d++)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:d,isZero:f,isNeg:h,isNegF:g,offsetF:y}=Nt(n,c,o);n=a,f?s=s.add(Le(g,r[y])):i=i.add(Le(h,r[d]))}return Lt(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:d,isNeg:f}=Nt(n,o,s);if(n=c,!d){const h=r[a];i=i.add(f?h.negate():h)}}return Lt(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=Ke(t);return this.wNAF(i,this.getPrecomputes(i,t,n),r)}unsafe(t,r,n,i){const s=Ke(t);return s===1?this._unsafeLadder(t,r,i):this.wNAFUnsafe(s,this.getPrecomputes(s,t,n),r,i)}createCache(t,r){mn(r,this.bits),bn.set(t,r),Ve.delete(t)}hasCache(t){return Ke(t)!==1}}function Vr(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 Pt(e,t,r){if(t){if(t.ORDER!==e)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Hr(t),t}else return Ce(e,{isLE:r})}function Kr(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 d=t[a];if(!(typeof d=="bigint"&&d>le))throw new Error(`CURVE.${a} must be positive bigint`)}const i=Pt(t.p,r.Fp,n),s=Pt(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 Yr(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 _t=(e,t)=>(e+(e>=0?t:-t)/Gr)/t;function zr(e,t,r){const[[n,i],[s,o]]=t,c=_t(o*e,r),a=_t(-i*e,r);let d=e-c*n-a*s,f=-c*i-a*o;const h=d<he,g=f<he;h&&(d=-d),g&&(f=-f);const y=on(Math.ceil(qr(r)/2))+Te;if(d<he||d>=y||f<he||f>=y)throw new Error("splitScalar (endomorphism): failed, k="+e);return{k1neg:h,k1:d,k2neg:g,k2:f}}const he=BigInt(0),Te=BigInt(1),Gr=BigInt(2),$e=BigInt(3),Xr=BigInt(4);function Jr(e,t={}){const r=Kr("weierstrass",e,t),{Fp:n,Fn:i}=r;let s=r.CURVE;const{h:o,n:c}=s;an(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 d=ei(n,i);function f(){if(!n.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function h(I,p,m){const{x:v,y:x}=p.toAffine(),A=n.toBytes(v);if(At(m,"isCompressed"),m){f();const R=!n.isOdd(x);return Oe(Qr(R),A)}else return Oe(Uint8Array.of(4),A,n.toBytes(x))}function g(I){D(I,void 0,"Point");const{publicKey:p,publicKeyUncompressed:m}=d,v=I.length,x=I[0],A=I.subarray(1);if(v===p&&(x===2||x===3)){const R=n.fromBytes(A);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(M){const P=M instanceof Error?": "+M.message:"";throw new Error("bad point: is not on curve, sqrt error"+P)}f();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(A.subarray(0,R)),w=n.fromBytes(A.subarray(R,R*2));if(!q(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=${p} or uncompressed=${m}`)}const y=t.toBytes||h,b=t.fromBytes||g;function E(I){const p=n.sqr(I),m=n.mul(p,I);return n.add(n.add(m,n.mul(I,s.a)),s.b)}function q(I,p){const m=n.sqr(p),v=E(I);return n.eql(m,v)}if(!q(s.Gx,s.Gy))throw new Error("bad curve params: generator point");const L=n.mul(n.pow(s.a,$e),Xr),K=n.mul(n.sqr(s.b),BigInt(27));if(n.is0(n.add(L,K)))throw new Error("bad curve params: a or b");function Q(I,p,m=!1){if(!n.isValid(p)||m&&n.is0(p))throw new Error(`bad point coordinate ${I}`);return p}function we(I){if(!(I instanceof B))throw new Error("Weierstrass Point expected")}function ve(I){if(!a||!a.basises)throw new Error("no endo");return zr(I,a.basises,i.ORDER)}const Ee=Tt((I,p)=>{const{X:m,Y:v,Z:x}=I;if(n.eql(x,n.ONE))return{x:m,y:v};const A=I.is0();p==null&&(p=A?n.ONE:n.inv(x));const R=n.mul(m,p),k=n.mul(v,p),w=n.mul(x,p);if(A)return{x:n.ZERO,y:n.ZERO};if(!n.eql(w,n.ONE))throw new Error("invZ was invalid");return{x:R,y:k}}),In=Tt(I=>{if(I.is0()){if(t.allowInfinityPoint&&!n.is0(I.Y))return;throw new Error("bad point: ZERO")}const{x:p,y:m}=I.toAffine();if(!n.isValid(p)||!n.isValid(m))throw new Error("bad point: x or y not field elements");if(!q(p,m))throw new Error("bad point: equation left != right");if(!I.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});function mt(I,p,m,v,x){return m=new B(n.mul(m.X,I),m.Y,m.Z),p=Le(v,p),m=Le(x,m),p.add(m)}class B{static BASE=new B(s.Gx,s.Gy,n.ONE);static ZERO=new B(n.ZERO,n.ONE,n.ZERO);static Fp=n;static Fn=i;X;Y;Z;constructor(p,m,v){this.X=Q("x",p),this.Y=Q("y",m,!0),this.Z=Q("z",v),Object.freeze(this)}static CURVE(){return s}static fromAffine(p){const{x:m,y:v}=p||{};if(!p||!n.isValid(m)||!n.isValid(v))throw new Error("invalid affine point");if(p instanceof B)throw new Error("projective point not allowed");return n.is0(m)&&n.is0(v)?B.ZERO:new B(m,v,n.ONE)}static fromBytes(p){const m=B.fromAffine(b(D(p,void 0,"point")));return m.assertValidity(),m}static fromHex(p){return B.fromBytes(X(p))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(p=8,m=!0){return ue.createCache(this,p),m||this.multiply($e),this}assertValidity(){In(this)}hasEvenY(){const{y:p}=this.toAffine();if(!n.isOdd)throw new Error("Field doesn't support isOdd");return!n.isOdd(p)}equals(p){we(p);const{X:m,Y:v,Z:x}=this,{X:A,Y:R,Z:k}=p,w=n.eql(n.mul(m,k),n.mul(A,x)),S=n.eql(n.mul(v,k),n.mul(R,x));return w&&S}negate(){return new B(this.X,n.neg(this.Y),this.Z)}double(){const{a:p,b:m}=s,v=n.mul(m,$e),{X:x,Y:A,Z:R}=this;let k=n.ZERO,w=n.ZERO,S=n.ZERO,$=n.mul(x,x),M=n.mul(A,A),P=n.mul(R,R),T=n.mul(x,A);return T=n.add(T,T),S=n.mul(x,R),S=n.add(S,S),k=n.mul(p,S),w=n.mul(v,P),w=n.add(k,w),k=n.sub(M,w),w=n.add(M,w),w=n.mul(k,w),k=n.mul(T,k),S=n.mul(v,S),P=n.mul(p,P),T=n.sub($,P),T=n.mul(p,T),T=n.add(T,S),S=n.add($,$),$=n.add(S,$),$=n.add($,P),$=n.mul($,T),w=n.add(w,$),P=n.mul(A,R),P=n.add(P,P),$=n.mul(P,T),k=n.sub(k,$),S=n.mul(P,M),S=n.add(S,S),S=n.add(S,S),new B(k,w,S)}add(p){we(p);const{X:m,Y:v,Z:x}=this,{X:A,Y:R,Z:k}=p;let w=n.ZERO,S=n.ZERO,$=n.ZERO;const M=s.a,P=n.mul(s.b,$e);let T=n.mul(m,A),W=n.mul(v,R),Z=n.mul(x,k),ae=n.add(m,v),U=n.add(A,R);ae=n.mul(ae,U),U=n.add(T,W),ae=n.sub(ae,U),U=n.add(m,x);let Y=n.add(A,k);return U=n.mul(U,Y),Y=n.add(T,Z),U=n.sub(U,Y),Y=n.add(v,x),w=n.add(R,k),Y=n.mul(Y,w),w=n.add(W,Z),Y=n.sub(Y,w),$=n.mul(M,U),w=n.mul(P,Z),$=n.add(w,$),w=n.sub(W,$),$=n.add(W,$),S=n.mul(w,$),W=n.add(T,T),W=n.add(W,T),Z=n.mul(M,Z),U=n.mul(P,U),W=n.add(W,Z),Z=n.sub(T,Z),Z=n.mul(M,Z),U=n.add(U,Z),T=n.mul(W,U),S=n.add(S,T),T=n.mul(Y,U),w=n.mul(ae,w),w=n.sub(w,T),T=n.mul(ae,W),$=n.mul(Y,$),$=n.add($,T),new B(w,S,$)}subtract(p){return this.add(p.negate())}is0(){return this.equals(B.ZERO)}multiply(p){const{endo:m}=t;if(!i.isValidNot0(p))throw new Error("invalid scalar: out of range");let v,x;const A=R=>ue.cached(this,R,k=>qt(B,k));if(m){const{k1neg:R,k1:k,k2neg:w,k2:S}=ve(p),{p:$,f:M}=A(k),{p:P,f:T}=A(S);x=M.add(T),v=mt(m.beta,$,P,R,w)}else{const{p:R,f:k}=A(p);v=R,x=k}return qt(B,[v,x])[0]}multiplyUnsafe(p){const{endo:m}=t,v=this;if(!i.isValid(p))throw new Error("invalid scalar: out of range");if(p===he||v.is0())return B.ZERO;if(p===Te)return v;if(ue.hasCache(this))return this.multiply(p);if(m){const{k1neg:x,k1:A,k2neg:R,k2:k}=ve(p),{p1:w,p2:S}=Vr(B,v,A,k);return mt(m.beta,w,S,x,R)}else return ue.unsafe(v,p)}toAffine(p){return Ee(this,p)}isTorsionFree(){const{isTorsionFree:p}=t;return o===Te?!0:p?p(B,this):ue.unsafe(this,c).is0()}clearCofactor(){const{clearCofactor:p}=t;return o===Te?this:p?p(B,this):this.multiplyUnsafe(o)}isSmallOrder(){return this.multiplyUnsafe(o).is0()}toBytes(p=!0){return At(p,"isCompressed"),this.assertValidity(),y(B,this,p)}toHex(p=!0){return _(this.toBytes(p))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}}const bt=i.BITS,ue=new Zr(B,t.endo?Math.ceil(bt/2):bt);return B.BASE.precompute(8),B}function Qr(e){return Uint8Array.of(e?2:3)}function ei(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 Ue={p:BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),n:BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),h:BigInt(1),a:BigInt(0),b:BigInt(7),Gx:BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),Gy:BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")},ti={beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),basises:[[BigInt("0x3086d221a7d46bcde86c90e49284eb15"),-BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),BigInt("0x3086d221a7d46bcde86c90e49284eb15")]]},ni=BigInt(0),rt=BigInt(2);function ri(e){const t=Ue.p,r=BigInt(3),n=BigInt(6),i=BigInt(11),s=BigInt(22),o=BigInt(23),c=BigInt(44),a=BigInt(88),d=e*e*e%t,f=d*d*e%t,h=F(f,r,t)*f%t,g=F(h,r,t)*f%t,y=F(g,rt,t)*d%t,b=F(y,i,t)*y%t,E=F(b,s,t)*b%t,q=F(E,c,t)*E%t,L=F(q,a,t)*q%t,K=F(L,c,t)*E%t,Q=F(K,r,t)*f%t,we=F(Q,o,t)*b%t,ve=F(we,n,t)*d%t,Ee=F(ve,rt,t);if(!Pe.eql(Pe.sqr(Ee),e))throw new Error("Cannot find square root");return Ee}const Pe=Ce(Ue.p,{sqrt:ri}),de=Jr(Ue,{Fp:Pe,endo:ti}),Ct={};function _e(e,...t){let r=Ct[e];if(r===void 0){const n=Ne(Br(e));r=Oe(n,n),Ct[e]=r}return Ne(Oe(r,...t))}const gt=e=>e.toBytes(!0).slice(1),yt=e=>e%rt===ni;function it(e){const{Fn:t,BASE:r}=de,n=t.fromBytes(e),i=r.multiply(n);return{scalar:yt(i.y)?n:t.neg(n),bytes:gt(i)}}function wn(e){const t=Pe;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);yt(i)||(i=t.neg(i));const s=de.fromAffine({x:e,y:i});return s.assertValidity(),s}const ye=ft;function vn(...e){return de.Fn.create(ye(_e("BIP0340/challenge",...e)))}function Ut(e){return it(e).bytes}function ii(e,t,r=zt(32)){const{Fn:n}=de,i=D(e,void 0,"message"),{bytes:s,scalar:o}=it(t),c=D(r,32,"auxRand"),a=n.toBytes(o^ye(_e("BIP0340/aux",c))),d=_e("BIP0340/nonce",a,s,i),{bytes:f,scalar:h}=it(d),g=vn(f,s,i),y=new Uint8Array(64);if(y.set(f,0),y.set(n.toBytes(n.create(h+g*o)),32),!En(y,i,s))throw new Error("sign: Invalid signature produced");return y}function En(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 d=wn(ye(a)),f=ye(o.subarray(0,32));if(!n.isValidNot0(f))return!1;const h=ye(o.subarray(32,64));if(!i.isValidNot0(h))return!1;const g=vn(i.toBytes(f),gt(d),c),y=s.multiplyUnsafe(h).add(d.multiplyUnsafe(i.neg(g))),{x:b,y:E}=y.toAffine();return!(y.is0()||!yt(E)||b!==f)}catch{return!1}}const G=(()=>{const r=(n=zt(48))=>Wr(n,Ue.n);return{keygen:Yr(r,Ut),getPublicKey:Ut,sign:ii,verify:En,Point:de,utils:{randomSecretKey:r,taggedHash:_e,lift_x:wn,pointToBytes:gt},lengths:{secretKey:32,publicKey:32,publicKeyHasPrefix:!1,signature:64,seed:48}}})();var ie=Symbol("verified"),si=e=>e instanceof Object;function oi(e){if(!si(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 ai=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 ci=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=Ye(n),n.sig=_(G.sign(X(Ye(n)),r)),n[ie]=!0,n}verifyEvent(t){if(typeof t[ie]=="boolean")return t[ie];try{const r=Ye(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 li(e){if(!oi(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 Ye(e){let t=Ne(ai.encode(li(e)));return _(t)}var He=new ci;He.generateSecretKey;He.getPublicKey;He.finalizeEvent;var di=He.verifyEvent,ui=22242;function fi(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 hi(e,t){for(let r=0;r<e.length;r++)if(fi(e[r],t))return!0;return!1}function pi(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 gi(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 yi(e,t){return{kind:ui,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}var xn=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},kn=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 kn(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 xn(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(yi(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 mi(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=gi(t);if(r){const n=this.openSubs.get(r);if(!n)return;const i=pi(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)&&hi(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}}},mi=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 xn))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)}},bi=e=>(e[ie]=!0,!0),wi=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 kn(e,{verifyEvent:this.trustedRelayURLs.has(e)?bi: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:y,filter:b}=g;r.has(y)||r.set(y,[]),r.get(y).push(b)}const n=Array.from(r.entries()).map(([g,y])=>({url:g,filters:y}));this.trackRelays&&(t.receivedEvent=(g,y)=>{let b=this.seenOn.get(y);b||(b=new Set,this.seenOn.set(y,b)),b.add(g)});const i=new Set,s=[],o=[];let c=g=>{o[g]||(o[g]=!0,o.filter(y=>y).length===n.length&&(t.oneose?.(),c=()=>{}))};const a=[];let d=(g,y)=>{a[g]||(c(g),a[g]=y,a.filter(b=>b).length===n.length&&(t.onclose?.(a),d=()=>{}))};const f=g=>{if(t.alreadyHaveEvent?.(g))return!0;const y=i.has(g);return i.add(g),y},h=Promise.all(n.map(async({url:g,filters:y},b)=>{if(this.allowConnectingToRelay?.(g,["read",y])===!1){d(b,"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),d(b,L?.message||String(L));return}this.onRelayConnectionSuccess?.(g);let q=E.subscribe(y,{...t,oneose:()=>c(b),onclose:L=>{L.startsWith("auth-required: ")&&t.onauth?E.auth(t.onauth).then(()=>{E.subscribe(y,{...t,oneose:()=>c(b),onclose:K=>{d(b,K)},alreadyHaveEvent:f,eoseTimeout:t.maxWait,abort:t.abort})}).catch(K=>{d(b,`auth was required and attempted, but failed with: ${K}`)}):d(b,L)},alreadyHaveEvent:f,eoseTimeout:t.maxWait,abort:t.abort});s.push(q)}));return{async close(g){await h,s.forEach(y=>{y.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}},Sn;try{Sn=WebSocket}catch{}var vi=class extends wi{constructor(e){super({verifyEvent:di,websocketImplementation:Sn,maxWaitForConnection:3e3,...e})}},ce=Symbol("verified"),Ei=e=>e instanceof Object;function xi(e){if(!Ei(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 ki=new TextEncoder,Si=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=ze(r),r.sig=_(G.sign(X(ze(r)),t)),r[ce]=!0,r}verifyEvent(e){if(typeof e[ce]=="boolean")return e[ce];try{const t=ze(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 Ri(e){if(!xi(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 ze(e){let t=Ne(ki.encode(Ri(e)));return _(t)}var je=new Si;je.generateSecretKey;je.getPublicKey;je.finalizeEvent;var $i=je.verifyEvent;const Ii=8e3;function Ai(e){return typeof e=="number"&&ct.includes(e)}function Ti(e){try{const t=new URL(e);return t.protocol==="http:"||t.protocol==="https:"}catch{return!1}}function Bi(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 Oi(e){const t=vr(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=Bi(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&&!Ai(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?[...ct]:[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 qi(e){return{id:e.id,pubkey:e.pubkey,kind:e.kind,tags:e.tags}}async function Rn(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 Ni(e){return e.tags.filter(t=>t[0]==="path"&&typeof t[1]=="string"&&typeof t[2]=="string")}async function Li(e){const t=Ni(e).map(r=>`${r[2]} ${r[1]}
|
|
80
|
+
`).sort().join("");return Rn(t)}async function Pi(e){const t=await Li(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 _i(e){return e.tags.find(t=>t[0]==="path"&&t[1]==="/index.html")}function Ci(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 Ui(e,t){const r=e.endsWith("/")?e:`${e}/`;return new URL(t,r).href}async function Hi(e,t=fetch){const n=_i(e)?.[2];if(!n)throw new Error("Manifest does not include a /index.html path hash");const i=Ci(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=Ui(o,n);try{const a=await t(c,{mode:"cors"});if(!a.ok){s.push(`${c}: HTTP ${a.status}`);continue}const d=new Uint8Array(await a.arrayBuffer()),f=await Rn(d);if(f!==n){s.push(`${c}: sha256 ${f} did not match manifest ${n}`);continue}return new TextDecoder().decode(d)}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 ji(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 Di(e,t){const r=Oi(e),n=!t.pool,i=t.pool??new vi;try{const s=await i.get(r.relays,{...r.filter},{maxWait:t.maxRelayWaitMs??Ii});if(!s)throw new Error("No matching napplet manifest event was found on the pointer relay hints");if(!$i(s))throw new Error("Resolved manifest event signature is invalid");const o=qi(s),c=lt(o);if(!c.ok)throw new Error(`Resolved event is not a valid NIP-5D napplet manifest: ${c.errors[0]?.message}`);await Pi(o);const a=await Hi(o,t.fetcher??fetch),d=(t.createObjectUrl??URL.createObjectURL)(new Blob([a],{type:"text/html;charset=utf-8"})),f=()=>(t.revokeObjectUrl??URL.revokeObjectURL)(d);return{source:"nostr",input:e,label:o.id??e,bootUrl:d,html:a,fetched:!0,manifestEvent:o,revoke:f}}finally{n&&i.destroy()}}async function Mi(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 Ti(r)?ji(r,t.fetcher??fetch):Di(r,t)}const Fi=/\bwindow\s*\.\s*nostr\b|\bglobalThis\s*\.\s*nostr\b/,Wi="/__conformance__/events",st=new URLSearchParams(location.search),$n=st.get("live")==="1";function ne(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}const re=document.getElementById("app");function Zi(){return re.innerHTML=`
|
|
81
|
+
<header class="masthead">
|
|
82
|
+
<h1>napplet conformance ${$n?'<span class="live-badge" id="live-badge">● live</span>':""}</h1>
|
|
83
|
+
<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>
|
|
84
|
+
</header>
|
|
85
|
+
<form id="run-form" class="runbar">
|
|
86
|
+
<input id="target" type="text" placeholder="naddr1… or nevent1… for a NIP-5D napplet manifest" autocomplete="off" spellcheck="false" />
|
|
87
|
+
<button id="run" type="submit">Run conformance</button>
|
|
88
|
+
<button id="rerun" type="button" class="secondary" hidden>Re-run</button>
|
|
89
|
+
</form>
|
|
90
|
+
<p id="status" class="status" role="status"></p>
|
|
91
|
+
<section id="output" class="output"></section>
|
|
92
|
+
`,{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=Zi();let be="",ot=0;function Ie(e,t="info"){C.status.textContent=e,C.status.dataset.kind=t}function Ge(e){return String(e).padStart(2,"0")}function Vi(e){const t=new Date(e);return`${Ge(t.getHours())}:${Ge(t.getMinutes())}:${Ge(t.getSeconds())}`}function Ki(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 d=a.severity==="warning"&&a.status==="fail"?' <span class="tag warn">warning</span>':"",f=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>${d}${f}</li>`}).join("");return`<div class="area"><h3>${ne(o)}</h3><ul>${c}</ul></div>`}).join(""),i=e.summary,s=ot>1?`<span class="run-stamp">run #${ot} · ${Vi(e.finishedAt)}</span>`:"";return`
|
|
93
|
+
<div class="verdict ${t}">
|
|
94
|
+
<span class="result">${e.ok?"CONFORMANT":"NON-CONFORMANT"}</span>
|
|
95
|
+
<span class="counts">${i.passed} passed · ${i.failed} failed · ${i.skipped} skipped${i.warnings?` · ${i.warnings} warning(s)`:""}</span>
|
|
96
|
+
${s}
|
|
97
|
+
</div>
|
|
98
|
+
<div class="checks">${n}</div>
|
|
99
|
+
`}function Yi(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 zi(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=lt(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`
|
|
100
|
+
<table class="manifest">
|
|
101
|
+
${t("event",r.id)}
|
|
102
|
+
${t("kind",r.kind)}
|
|
103
|
+
${t("d",i)}
|
|
104
|
+
${t("name",Zt(r))}
|
|
105
|
+
${t("requires",n.requires.join(", "))}
|
|
106
|
+
${t("/index.html",s?.[2])}
|
|
107
|
+
${t("servers",o.join(", "))}
|
|
108
|
+
</table>
|
|
109
|
+
${n.errors.length?`<div class="errs">${n.errors.map(c=>ne(`${c.code}: ${c.message}`)).join("<br>")}</div>`:""}
|
|
110
|
+
`}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 Gi(e,t,r){C.output.innerHTML=`
|
|
111
|
+
${Ki(e)}
|
|
112
|
+
<div class="panels">
|
|
113
|
+
<section class="panel"><h2>Emitted envelopes (${t.length})</h2>${Yi(t)}</section>
|
|
114
|
+
<section class="panel"><h2>Manifest</h2>${zi(r)}</section>
|
|
115
|
+
</div>
|
|
116
|
+
`}async function De(e){be=e,C.runButton.disabled=!0,C.rerunButton.disabled=!0;let t=null;try{Ie(`Resolving ${e} …`),t=await Mi(e);const r=Fi.test(t.html)?["window.nostr"]:[];Ie("Booting napplet in a sandboxed iframe …");const n=await tr({url:t.bootUrl,readyTimeoutMs:5e3,settleMs:800,runDegraded:!0}),i=zn({manifestHtml:t.html,manifestEvent:t.manifestEvent,boot:n,forbiddenGlobals:r}),s=ar(i);ot+=1,Ie(s.ok?"Done — conformant.":"Done — non-conformant.",s.ok?"info":"error"),Gi(s,n.emitted,t),C.rerunButton.hidden=!1}catch(r){Ie(`Error: ${r instanceof Error?r.message:String(r)}`,"error")}finally{t?.revoke?.(),C.runButton.disabled=!1,C.rerunButton.disabled=!1}}function Xi(){if(!$n||typeof EventSource>"u")return;let e=!1;const t=new EventSource(Wi);t.addEventListener("rerun",()=>{!be||e||(e=!0,setTimeout(()=>{e=!1,De(be)},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),De(t)}});C.rerunButton.addEventListener("click",()=>{be&&De(be)});Xi();const Xe=st.get("target")??st.get("url");Xe&&(C.targetInput.value=Xe,De(Xe));
|
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-DV1wZ-SF.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.19",
|
|
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.17.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.18"
|
|
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 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));
|