@kehto/paja 0.17.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +144 -25
- package/dist/browser-host.js +17394 -16749
- package/dist/browser-host.js.map +1 -1
- package/dist/{chunk-ESE55K3Q.js → chunk-GY5ET3PC.js} +146 -55
- package/dist/chunk-GY5ET3PC.js.map +1 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +136 -8
- package/dist/index.js +13 -1
- package/dist/{server-Ia5n1Bqv.d.ts → server-5j5uoy2Z.d.ts} +5 -0
- package/package.json +5 -5
- package/dist/chunk-ESE55K3Q.js.map +0 -1
|
@@ -374,6 +374,7 @@ function createPajaRuntimeHostConfig(options = {}, now = /* @__PURE__ */ new Dat
|
|
|
374
374
|
const base = createPajaHostConfigBase(normalizePajaSimulation(options.simulation));
|
|
375
375
|
return {
|
|
376
376
|
...base,
|
|
377
|
+
...options.csp ? { csp: options.csp } : {},
|
|
377
378
|
target: {
|
|
378
379
|
mode: "runtime-pointer",
|
|
379
380
|
url: "about:blank",
|
|
@@ -524,6 +525,7 @@ function renderPajaHtml(config) {
|
|
|
524
525
|
.tabs { display: flex; align-items: stretch; align-self: flex-end; gap: 4px; min-width: 120px; max-width: min(100%, 760px); overflow-x: auto; scrollbar-width: thin; }
|
|
525
526
|
.tabs:empty { display: none; }
|
|
526
527
|
.tab { min-width: 116px; max-width: 240px; height: 30px; display: grid; grid-template-columns: minmax(0, 1fr) 24px 24px; align-items: center; gap: 2px; border: 1px solid var(--line); border-bottom-color: transparent; background: #151815; color: var(--muted); border-radius: 5px 5px 0 0; padding: 0 2px 0 9px; }
|
|
528
|
+
.tab[data-source="local"] { grid-template-columns: minmax(0, 1fr) 24px; }
|
|
527
529
|
.tab[data-active="true"] { color: var(--text); border-color: var(--accent); border-bottom-color: #151815; background: #20241f; }
|
|
528
530
|
.tab-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; text-align: left; }
|
|
529
531
|
.tab-share, .tab-close { width: 20px; height: 20px; padding: 0; border: 0; background: transparent; color: var(--muted); display: inline-grid; place-items: center; }
|
|
@@ -533,9 +535,21 @@ function renderPajaHtml(config) {
|
|
|
533
535
|
label { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); white-space: nowrap; }
|
|
534
536
|
select, input, textarea { border: 1px solid var(--line); color: var(--text); background: #20241f; min-height: 26px; border-radius: 4px; font: inherit; }
|
|
535
537
|
main { min-height: 0; display: grid; grid-template-columns: var(--paja-console-column) minmax(0, 1fr); }
|
|
536
|
-
.console { min-height: 0; overflow: auto; border-right: 1px solid var(--line); background: #121512; padding:
|
|
537
|
-
.section {
|
|
538
|
+
.console { min-height: 0; overflow: auto; border-right: 1px solid var(--line); background: #121512; padding: 0; display: flex; flex-direction: column; gap: 0; }
|
|
539
|
+
.section { flex-shrink: 0; margin: 0; border-radius: 0; border-bottom: 1px solid var(--line); }
|
|
540
|
+
.section > summary { display: flex; align-items: center; justify-content: space-between; padding: 12px; cursor: pointer; list-style: none; }
|
|
541
|
+
.section > summary::-webkit-details-marker { display: none; }
|
|
542
|
+
.section > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
543
|
+
.section-chevron { transition: transform 120ms; }
|
|
544
|
+
.section[open] > summary .section-chevron { transform: rotate(90deg); }
|
|
545
|
+
.section-body { padding: 0 12px 12px; display: grid; gap: 8px; }
|
|
546
|
+
.resource-servers { display: grid; gap: 8px; }
|
|
547
|
+
.resource-servers > label { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
|
538
548
|
.section-title { color: var(--accent); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0; }
|
|
549
|
+
.resource-servers { min-width: 0; }
|
|
550
|
+
.resource-servers label { white-space: normal; }
|
|
551
|
+
.resource-servers textarea { width: 100%; min-width: 0; padding: 6px; resize: vertical; }
|
|
552
|
+
.resource-servers small, .resource-servers [role="status"] { color: var(--muted); overflow-wrap: anywhere; }
|
|
539
553
|
.switch-grid, .acl-grid { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
540
554
|
.toggle { height: 24px; padding: 0 8px; color: var(--muted); }
|
|
541
555
|
.toggle[data-enabled="true"] { color: var(--text); border-color: #5f724f; background: #24301f; }
|
|
@@ -545,7 +559,7 @@ function renderPajaHtml(config) {
|
|
|
545
559
|
.signer-controls button[data-active="true"] { border-color: var(--accent); color: var(--text); background: #2a2a1d; }
|
|
546
560
|
.signer-controls input { min-width: 0; padding: 0 8px; }
|
|
547
561
|
.signer-consent-clear { width: 100%; margin-top: 6px; }
|
|
548
|
-
.pointer-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }
|
|
562
|
+
.pointer-controls { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 6px; }
|
|
549
563
|
.pointer-status { min-width: 0; color: var(--muted); font-size: 12px; overflow-wrap: anywhere; }
|
|
550
564
|
.log-tools { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 6px; }
|
|
551
565
|
.log-list { min-height: 160px; max-height: 38vh; overflow: auto; border: 1px solid var(--line); border-radius: 4px; background: #0b0d0b; }
|
|
@@ -559,6 +573,7 @@ function renderPajaHtml(config) {
|
|
|
559
573
|
.stage { min-width: 0; min-height: 0; position: relative; background: #050705; }
|
|
560
574
|
.empty-stage { position: absolute; inset: 0; display: grid; place-items: center; color: var(--muted); font-size: 12px; }
|
|
561
575
|
.empty-stage[hidden] { display: none; }
|
|
576
|
+
.stage.drop-active { outline: 2px dashed var(--accent); outline-offset: -6px; }
|
|
562
577
|
.tab-panel { position: absolute; inset: 0; min-width: 0; min-height: 0; }
|
|
563
578
|
.tab-panel[hidden] { display: none; }
|
|
564
579
|
iframe { width: 100%; height: 100%; border: 0; background: white; display: block; }
|
|
@@ -644,28 +659,38 @@ function renderPajaHtml(config) {
|
|
|
644
659
|
<main>
|
|
645
660
|
<aside class="console" id="${PAJA_CONSOLE_PANEL_ID}" aria-label="Paja development controls">
|
|
646
661
|
${renderPointerControls(config)}
|
|
647
|
-
<
|
|
648
|
-
<
|
|
662
|
+
<details class="section" id="paja-section-interfaces" data-paja-section="interfaces" open>
|
|
663
|
+
<summary class="section-title">Interfaces<span class="section-chevron" aria-hidden="true">\u203A</span></summary><div class="section-body">
|
|
649
664
|
<div class="switch-grid" id="interface-toggles"></div>
|
|
650
|
-
</
|
|
651
|
-
<
|
|
652
|
-
<
|
|
665
|
+
</div></details>
|
|
666
|
+
<details class="section" id="paja-section-acl" data-paja-section="acl" open>
|
|
667
|
+
<summary class="section-title">ACL<span class="section-chevron" aria-hidden="true">\u203A</span></summary><div class="section-body">
|
|
653
668
|
<div class="acl-grid" id="acl-controls"></div>
|
|
654
|
-
</
|
|
655
|
-
<
|
|
656
|
-
<
|
|
669
|
+
</div></details>
|
|
670
|
+
<details class="section" id="paja-section-signer" data-paja-section="signer" open>
|
|
671
|
+
<summary class="section-title">Signer<span class="section-chevron" aria-hidden="true">\u203A</span></summary><div class="section-body">
|
|
657
672
|
<div class="signer" id="signer-status">loading</div>
|
|
658
673
|
<div class="signer-controls" id="signer-controls"></div>
|
|
659
674
|
<button type="button" class="signer-consent-clear" id="signer-consent-clear" hidden>Forget remembered approvals</button>
|
|
660
|
-
</
|
|
661
|
-
<
|
|
662
|
-
<
|
|
675
|
+
</div></details>
|
|
676
|
+
<details class="section" id="paja-section-resource-servers" data-paja-section="resource-servers" open>
|
|
677
|
+
<summary class="section-title">Resource servers<span class="section-chevron" aria-hidden="true">\u203A</span></summary><div class="section-body">
|
|
678
|
+
<form class="resource-servers" id="paja-resource-servers-form">
|
|
679
|
+
<label class="section-title" for="paja-resource-servers-input">Resource servers</label>
|
|
680
|
+
<textarea id="paja-resource-servers-input" rows="3" aria-describedby="paja-resource-servers-help paja-resource-servers-status" spellcheck="false"></textarea>
|
|
681
|
+
<small id="paja-resource-servers-help">Extra Blossom lookup servers, one per line. Domains use HTTPS.</small>
|
|
682
|
+
<button type="submit" id="paja-resource-servers-save">Save</button>
|
|
683
|
+
<div id="paja-resource-servers-status" role="status" aria-live="polite"></div>
|
|
684
|
+
</form>
|
|
685
|
+
</div></details>
|
|
686
|
+
<details class="section" id="paja-section-messages" data-paja-section="messages" open>
|
|
687
|
+
<summary class="section-title">Messages<span class="section-chevron" aria-hidden="true">\u203A</span></summary><div class="section-body">
|
|
663
688
|
<div class="log-tools">
|
|
664
689
|
<input id="message-filter" type="search" autocomplete="off" placeholder="filter messages" aria-label="Filter message log">
|
|
665
690
|
<button type="button" id="clear-log">Clear</button>
|
|
666
691
|
</div>
|
|
667
692
|
<div class="log-list" id="message-log" aria-live="polite"></div>
|
|
668
|
-
</
|
|
693
|
+
</div></details>
|
|
669
694
|
</aside>
|
|
670
695
|
${renderStage(config, targetLabel)}
|
|
671
696
|
</main>
|
|
@@ -733,7 +758,7 @@ function renderConfigDialog() {
|
|
|
733
758
|
function renderStage(config, targetLabel) {
|
|
734
759
|
if (config.target.mode === "runtime-pointer") {
|
|
735
760
|
return `<section class="stage" id="napplet-stage" aria-label="Loaded napplet runtimes">
|
|
736
|
-
<div class="empty-stage" id="empty-runtime-stage">Load a napplet pointer to start a runtime tab.</div>
|
|
761
|
+
<div class="empty-stage" id="empty-runtime-stage">Load a napplet pointer or drop an index.html to start a runtime tab.</div>
|
|
737
762
|
</section>`;
|
|
738
763
|
}
|
|
739
764
|
return `<section class="stage" id="napplet-stage">
|
|
@@ -755,14 +780,16 @@ function renderDuplicateDialog() {
|
|
|
755
780
|
function renderPointerControls(config) {
|
|
756
781
|
if (config.target.mode !== "runtime-pointer") return "";
|
|
757
782
|
const value = escapeAttribute(config.target.pointer?.value ?? "");
|
|
758
|
-
return `<
|
|
759
|
-
<
|
|
783
|
+
return `<details class="section" id="runtime-pointer-section" data-paja-section="pointer" open>
|
|
784
|
+
<summary class="section-title">Pointer<span class="section-chevron" aria-hidden="true">\u203A</span></summary><div class="section-body">
|
|
760
785
|
<form class="pointer-controls" id="runtime-pointer-form">
|
|
761
786
|
<input id="runtime-pointer-input" type="text" inputmode="url" autocomplete="off" spellcheck="false" placeholder="naddr or nevent" aria-label="Runtime napplet pointer" value="${value}">
|
|
762
787
|
<button type="submit" id="runtime-pointer-load">Load</button>
|
|
788
|
+
<button type="button" id="runtime-local-open" title="Open a self-contained single-file index.html">Open file\u2026</button>
|
|
789
|
+
<input id="runtime-local-file" type="file" accept=".html,.htm,text/html" aria-label="Local napplet index.html" hidden>
|
|
763
790
|
</form>
|
|
764
791
|
<div class="pointer-status" id="runtime-pointer-status" aria-live="polite">idle</div>
|
|
765
|
-
</
|
|
792
|
+
</div></details>`;
|
|
766
793
|
}
|
|
767
794
|
function getModeLabel(config) {
|
|
768
795
|
if (config.target.mode === "runtime-pointer") return "runtime-pointer";
|
|
@@ -785,6 +812,7 @@ function escapeJsonForHtml(value) {
|
|
|
785
812
|
}
|
|
786
813
|
|
|
787
814
|
// src/runtime-resolver.ts
|
|
815
|
+
import { injectNappletCsp } from "@kehto/shell";
|
|
788
816
|
import { SimplePool } from "nostr-tools/pool";
|
|
789
817
|
import { decode } from "nostr-tools/nip19";
|
|
790
818
|
import {
|
|
@@ -867,7 +895,7 @@ async function resolvePajaPointer(value, options = {}) {
|
|
|
867
895
|
const resolved = await resolveNapplet({
|
|
868
896
|
event,
|
|
869
897
|
cache: await openNappletArtifactCache({ requireStorageEstimate: false }),
|
|
870
|
-
fetchBlob: (
|
|
898
|
+
fetchBlob: (sha256Hex2, servers) => fetchBlob([...servers, ...blossomServers], sha256Hex2, async (url) => {
|
|
871
899
|
const response = await (options.fetcher ?? fetch)(url);
|
|
872
900
|
if (!response.ok) throw new Error(`[paja-runtime] blob ${url}: ${response.status}`);
|
|
873
901
|
return new Uint8Array(await response.arrayBuffer());
|
|
@@ -905,34 +933,7 @@ function resolvePointerBlossomServers(event, configured) {
|
|
|
905
933
|
return servers;
|
|
906
934
|
}
|
|
907
935
|
function injectPajaRuntimeCsp(html, origins) {
|
|
908
|
-
|
|
909
|
-
const connectSrc = grantedOrigins.length > 0 ? `connect-src ${grantedOrigins.join(" ")}` : "connect-src 'none'";
|
|
910
|
-
const value = [
|
|
911
|
-
"default-src 'none'",
|
|
912
|
-
"script-src 'unsafe-inline' 'wasm-unsafe-eval'",
|
|
913
|
-
"style-src 'unsafe-inline'",
|
|
914
|
-
"img-src data: blob:",
|
|
915
|
-
"font-src data:",
|
|
916
|
-
connectSrc,
|
|
917
|
-
"worker-src 'none'",
|
|
918
|
-
"child-src 'none'",
|
|
919
|
-
"frame-src 'none'",
|
|
920
|
-
"media-src 'none'",
|
|
921
|
-
"object-src 'none'",
|
|
922
|
-
"manifest-src 'none'",
|
|
923
|
-
"prefetch-src 'none'",
|
|
924
|
-
"base-uri 'none'",
|
|
925
|
-
"form-action 'none'",
|
|
926
|
-
"frame-ancestors 'self'"
|
|
927
|
-
].join("; ");
|
|
928
|
-
const meta = `<meta http-equiv="Content-Security-Policy" content="${escapeAttribute2(value)}">`;
|
|
929
|
-
if (/<head[^>]*>/i.test(html)) {
|
|
930
|
-
return html.replace(/<head[^>]*>/i, (open) => `${open}${meta}`);
|
|
931
|
-
}
|
|
932
|
-
if (/<html[^>]*>/i.test(html)) {
|
|
933
|
-
return html.replace(/<html[^>]*>/i, (open) => `${open}<head>${meta}</head>`);
|
|
934
|
-
}
|
|
935
|
-
return `${meta}${html}`;
|
|
936
|
+
return injectNappletCsp(html, { connectOrigins: origins });
|
|
936
937
|
}
|
|
937
938
|
async function resolvePointerEvent(pointer, pool, relays, maxWaitMs) {
|
|
938
939
|
const filter = pointer.type === "naddr" ? addressableFilter(pointer) : eventFilter(pointer);
|
|
@@ -1078,9 +1079,6 @@ function normalizeRelayUrl(value) {
|
|
|
1078
1079
|
return void 0;
|
|
1079
1080
|
}
|
|
1080
1081
|
}
|
|
1081
|
-
function escapeAttribute2(value) {
|
|
1082
|
-
return value.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
1083
|
-
}
|
|
1084
1082
|
function formatNappletManifestKinds() {
|
|
1085
1083
|
return PAJA_NAPPLET_MANIFEST_KINDS.join(" / ");
|
|
1086
1084
|
}
|
|
@@ -1211,6 +1209,85 @@ function defaultSleep(ms) {
|
|
|
1211
1209
|
});
|
|
1212
1210
|
}
|
|
1213
1211
|
|
|
1212
|
+
// src/local-target.ts
|
|
1213
|
+
import { computeAggregateHash } from "@kehto/nip/5a";
|
|
1214
|
+
var PAJA_LOCAL_SINGLE_FILE_HINT = "Paja opens self-contained single-file index.html only; relative scripts, styles, and images do not load.";
|
|
1215
|
+
var MAX_DTAG_LENGTH = 128;
|
|
1216
|
+
var MAX_REPORTED_RELATIVE_ASSETS = 8;
|
|
1217
|
+
function isPajaLocalTarget(target) {
|
|
1218
|
+
return typeof target === "object" && target !== null && target.source === "local";
|
|
1219
|
+
}
|
|
1220
|
+
function isPajaLocalHtmlFile(file) {
|
|
1221
|
+
const type = (file.type ?? "").split(";")[0]?.trim().toLowerCase();
|
|
1222
|
+
return type === "text/html" || /\.html?$/i.test(file.name.trim());
|
|
1223
|
+
}
|
|
1224
|
+
async function createPajaLocalTarget(file) {
|
|
1225
|
+
const fileName = file.name.trim() || "index.html";
|
|
1226
|
+
if (!isPajaLocalHtmlFile(file)) {
|
|
1227
|
+
throw new Error(`"${fileName}" is not an HTML file. ${PAJA_LOCAL_SINGLE_FILE_HINT}`);
|
|
1228
|
+
}
|
|
1229
|
+
const bytes = "arrayBuffer" in file ? new Uint8Array(await file.arrayBuffer()) : new TextEncoder().encode(file.text);
|
|
1230
|
+
const indexHtml = new TextDecoder().decode(bytes);
|
|
1231
|
+
if (indexHtml.trim().length === 0) {
|
|
1232
|
+
throw new Error(`"${fileName}" is empty.`);
|
|
1233
|
+
}
|
|
1234
|
+
const sha256 = await sha256Hex(bytes);
|
|
1235
|
+
return Object.freeze({
|
|
1236
|
+
source: "local",
|
|
1237
|
+
fileName,
|
|
1238
|
+
dTag: readNappletIdMeta(indexHtml) ?? localDTag(fileName),
|
|
1239
|
+
aggregateHash: computeAggregateHash([{ path: "/index.html", sha256 }]),
|
|
1240
|
+
sha256,
|
|
1241
|
+
indexHtml,
|
|
1242
|
+
relays: Object.freeze([]),
|
|
1243
|
+
blossomServers: Object.freeze([]),
|
|
1244
|
+
relativeAssets: Object.freeze(findRelativeAssetReferences(indexHtml))
|
|
1245
|
+
});
|
|
1246
|
+
}
|
|
1247
|
+
function readNappletIdMeta(html) {
|
|
1248
|
+
for (const match of html.matchAll(/<meta\b([^>]*)>/gi)) {
|
|
1249
|
+
const attributes = parseAttributes(match[1] ?? "");
|
|
1250
|
+
if (attributes.get("name")?.toLowerCase() !== "napplet-id") continue;
|
|
1251
|
+
const value = attributes.get("content")?.trim();
|
|
1252
|
+
if (value) return value.slice(0, MAX_DTAG_LENGTH);
|
|
1253
|
+
}
|
|
1254
|
+
return void 0;
|
|
1255
|
+
}
|
|
1256
|
+
function findRelativeAssetReferences(html) {
|
|
1257
|
+
const found = /* @__PURE__ */ new Set();
|
|
1258
|
+
for (const match of html.matchAll(/<(?:script|link|img|source|iframe)\b([^>]*)>/gi)) {
|
|
1259
|
+
const attributes = parseAttributes(match[1] ?? "");
|
|
1260
|
+
const reference = attributes.get("src") ?? attributes.get("href");
|
|
1261
|
+
if (reference && isRelativeReference(reference)) found.add(reference.trim());
|
|
1262
|
+
if (found.size >= MAX_REPORTED_RELATIVE_ASSETS) break;
|
|
1263
|
+
}
|
|
1264
|
+
return [...found];
|
|
1265
|
+
}
|
|
1266
|
+
function isRelativeReference(value) {
|
|
1267
|
+
const trimmed = value.trim();
|
|
1268
|
+
if (trimmed.length === 0 || trimmed.startsWith("#")) return false;
|
|
1269
|
+
return !/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(trimmed);
|
|
1270
|
+
}
|
|
1271
|
+
function parseAttributes(source) {
|
|
1272
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
1273
|
+
const pattern = /([^\s=/>"']+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
1274
|
+
for (const match of source.matchAll(pattern)) {
|
|
1275
|
+
const name = match[1]?.toLowerCase();
|
|
1276
|
+
if (!name || attributes.has(name)) continue;
|
|
1277
|
+
attributes.set(name, match[2] ?? match[3] ?? match[4] ?? "");
|
|
1278
|
+
}
|
|
1279
|
+
return attributes;
|
|
1280
|
+
}
|
|
1281
|
+
function localDTag(fileName) {
|
|
1282
|
+
const stem = fileName.replace(/\.[^.]*$/, "");
|
|
1283
|
+
const slug = stem.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
1284
|
+
return `local-${slug || "napplet"}`.slice(0, MAX_DTAG_LENGTH);
|
|
1285
|
+
}
|
|
1286
|
+
async function sha256Hex(bytes) {
|
|
1287
|
+
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
|
1288
|
+
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1214
1291
|
// src/installed-napplet-catalog.ts
|
|
1215
1292
|
import { manifestToIntentCatalogEntry } from "@kehto/services";
|
|
1216
1293
|
function matchesInstalledNappletRecord(record, target) {
|
|
@@ -1227,11 +1304,13 @@ var InstalledNappletCatalog = class {
|
|
|
1227
1304
|
pointer: copyPointer(resolved.pointer),
|
|
1228
1305
|
...resolved.manifest.title === void 0 ? {} : { title: resolved.manifest.title },
|
|
1229
1306
|
requires: [...resolved.manifest.requires],
|
|
1307
|
+
optional: [...resolved.manifest.optional ?? []],
|
|
1230
1308
|
archetypes: resolved.manifest.archetypes.map((archetype) => ({
|
|
1231
1309
|
slug: archetype.slug,
|
|
1232
1310
|
convention: archetype.convention
|
|
1233
1311
|
}))
|
|
1234
1312
|
});
|
|
1313
|
+
if (!record.dTag) return record;
|
|
1235
1314
|
this.records.set(record.dTag, record);
|
|
1236
1315
|
this.notify(record.dTag);
|
|
1237
1316
|
return record;
|
|
@@ -1263,9 +1342,14 @@ var InstalledNappletCatalog = class {
|
|
|
1263
1342
|
if (this.records.get(selected.dTag) !== selected) return null;
|
|
1264
1343
|
return matchesInstalledNappletRecord(selected, target) ? selected : null;
|
|
1265
1344
|
}
|
|
1266
|
-
/**
|
|
1267
|
-
|
|
1268
|
-
|
|
1345
|
+
/**
|
|
1346
|
+
* Return declared handlers whose host environment can receive intent delivery.
|
|
1347
|
+
* @param canReceiveIntent - Resolve intent availability for each verified identity;
|
|
1348
|
+
* without host policy, return declared candidates for the host to filter.
|
|
1349
|
+
* @returns Named intent candidates usable under the supplied host policy.
|
|
1350
|
+
*/
|
|
1351
|
+
intentCatalog(canReceiveIntent = () => true) {
|
|
1352
|
+
return this.installed().filter(canReceiveIntent).map((record) => manifestToIntentCatalogEntry({
|
|
1269
1353
|
dTag: record.dTag,
|
|
1270
1354
|
...record.title === void 0 ? {} : { title: record.title },
|
|
1271
1355
|
archetypes: record.archetypes.map((archetype) => ({
|
|
@@ -1307,6 +1391,7 @@ function freezeRecord(record) {
|
|
|
1307
1391
|
return Object.freeze({
|
|
1308
1392
|
...record,
|
|
1309
1393
|
requires: Object.freeze([...record.requires]),
|
|
1394
|
+
optional: Object.freeze([...record.optional ?? []]),
|
|
1310
1395
|
archetypes: Object.freeze(record.archetypes.map((archetype) => Object.freeze({ ...archetype })))
|
|
1311
1396
|
});
|
|
1312
1397
|
}
|
|
@@ -1629,6 +1714,12 @@ export {
|
|
|
1629
1714
|
getMissingServices,
|
|
1630
1715
|
ReadinessError,
|
|
1631
1716
|
waitForTargetUrl,
|
|
1717
|
+
PAJA_LOCAL_SINGLE_FILE_HINT,
|
|
1718
|
+
isPajaLocalTarget,
|
|
1719
|
+
isPajaLocalHtmlFile,
|
|
1720
|
+
createPajaLocalTarget,
|
|
1721
|
+
readNappletIdMeta,
|
|
1722
|
+
findRelativeAssetReferences,
|
|
1632
1723
|
InstalledNappletCatalog,
|
|
1633
1724
|
BrowserIntentController,
|
|
1634
1725
|
PAJA_TARGET_CORS_HINT,
|
|
@@ -1636,4 +1727,4 @@ export {
|
|
|
1636
1727
|
probeTargetCors,
|
|
1637
1728
|
startPajaServer
|
|
1638
1729
|
};
|
|
1639
|
-
//# sourceMappingURL=chunk-
|
|
1730
|
+
//# sourceMappingURL=chunk-GY5ET3PC.js.map
|