@kehto/paja 0.16.5 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -59,7 +59,11 @@ warning, when the target would block the sandboxed frame.
59
59
 
60
60
  The console shows supported interfaces with per-domain injection toggles,
61
61
  runtime ACL controls, signer controls, and a filterable message log with visible
62
- error details. In runtime-pointer mode, ACL controls always display and mutate
62
+ error details. It starts expanded and collapses to the left with the chevron
63
+ button in the top bar; the same button brings the whole panel back. Collapsing
64
+ is presentation-only — the target iframe keeps its identity and the loaded
65
+ napplet keeps running — and Paja remembers the choice per browser origin. In
66
+ runtime-pointer mode, ACL controls always display and mutate
63
67
  the active tab's resolver-verified d-tag and aggregate hash; a grant or revoke
64
68
  rerenders that same identity immediately. Paja auto-connects a browser NIP-07 signer when `window.nostr` is
65
69
  available, can connect to a bunker/NIP-46 URI, and only uses the generated local
@@ -213,6 +217,15 @@ identity. A superseded target/source, failed open/readiness, or terminal send is
213
217
  handled by the controller's replacement/retry/terminal policy and produces a
214
218
  canonical failed `IntentResult`.
215
219
 
220
+ Reusing a handler tab activates it and remembers the new active tab. Paja's stage
221
+ shows exactly one tab, so a delivered intent always selects the handler tab:
222
+ `behavior.focus` is a hint, and honoring `false` as "deliver into the hidden
223
+ tab" would report a handled intent whose surface the user never sees. Reuse
224
+ still leaves the caller's tab open, so nothing is replaced. Newly created
225
+ handler tabs behave the same way. Pointer installation logs declared
226
+ archetypes and required domains; Paja warns when archetypes lack `inc`, which
227
+ its current convention delivery policy requires.
228
+
216
229
  `@napplet/shim@0.30.0` supplies no generic shell API. Kehto deliberately keeps
217
230
  its host-owned mandatory `window.napplet.shell` prelude: it installs the live
218
231
  receiver before the one bare `shell.ready`, caches the first `shell.init`, and
@@ -5363,6 +5363,39 @@ function nappletNamespacePrelude(domains) {
5363
5363
  });
5364
5364
  }
5365
5365
 
5366
+ // src/browser-console-panel.ts
5367
+ var PAJA_CONSOLE_PANEL_STORAGE_KEY = "kehto:paja:console:v1";
5368
+ var PAJA_CONSOLE_TOGGLE_ID = "paja-console-toggle";
5369
+ var PAJA_CONSOLE_COLLAPSE_LABEL = "Collapse the Paja development console";
5370
+ var PAJA_CONSOLE_EXPAND_LABEL = "Expand the Paja development console";
5371
+ function installPajaConsolePanel() {
5372
+ const root = document.documentElement;
5373
+ const button2 = document.getElementById(PAJA_CONSOLE_TOGGLE_ID);
5374
+ let collapsed = false;
5375
+ try {
5376
+ collapsed = localStorage.getItem(PAJA_CONSOLE_PANEL_STORAGE_KEY) === "collapsed";
5377
+ } catch {
5378
+ }
5379
+ const apply = () => {
5380
+ root.dataset.pajaConsole = collapsed ? "collapsed" : "expanded";
5381
+ const label = collapsed ? PAJA_CONSOLE_EXPAND_LABEL : PAJA_CONSOLE_COLLAPSE_LABEL;
5382
+ button2?.setAttribute("aria-expanded", String(!collapsed));
5383
+ button2?.setAttribute("aria-label", label);
5384
+ button2?.setAttribute("title", label);
5385
+ };
5386
+ const toggle = () => {
5387
+ collapsed = !collapsed;
5388
+ apply();
5389
+ try {
5390
+ localStorage.setItem(PAJA_CONSOLE_PANEL_STORAGE_KEY, root.dataset.pajaConsole);
5391
+ } catch {
5392
+ }
5393
+ };
5394
+ apply();
5395
+ button2?.addEventListener("click", toggle);
5396
+ return () => button2?.removeEventListener("click", toggle);
5397
+ }
5398
+
5366
5399
  // ../../node_modules/.pnpm/@noble+hashes@2.0.1/node_modules/@noble/hashes/utils.js
5367
5400
  function isBytes(a) {
5368
5401
  return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
@@ -22695,6 +22728,8 @@ function createPajaIntentTargetOptions(getState, getContext, effects = {}) {
22695
22728
  (tab2) => matchesInstalledNappletRecord(record, tab2.resolvedTarget) && isCurrentRuntimeTabGeneration(state, context, tab2)
22696
22729
  );
22697
22730
  if (current && params.behavior?.newWindow !== true && params.behavior?.reuse !== false) {
22731
+ activateRuntimeTab(state, context, current.id);
22732
+ effects.persistTabs?.(state);
22698
22733
  return bindPajaIntentGeneration(current, record, context.runtime);
22699
22734
  }
22700
22735
  const resolved = await resolvePajaPointer(record.pointer.value, pajaPointerResolverOptions(context));
@@ -22757,6 +22792,25 @@ function createPajaIntentTargetOptions(getState, getContext, effects = {}) {
22757
22792
  }
22758
22793
  };
22759
22794
  }
22795
+ function recordInstalledIntentSurface(state, resolvedTarget) {
22796
+ const archetypes = resolvedTarget.manifest.archetypes;
22797
+ const requires = resolvedTarget.manifest.requires;
22798
+ const intentEligible = requires.includes("inc") && archetypes.length > 0;
22799
+ if (archetypes.length > 0 && !intentEligible) {
22800
+ console.warn(
22801
+ '[paja] napplet %s declares archetypes but is NOT intent-eligible: missing "inc" in requires. Add a ["requires","inc"] tag to its manifest to route intents to it.',
22802
+ resolvedTarget.dTag
22803
+ );
22804
+ }
22805
+ appendPajaMessageLog(state, "paja", {
22806
+ type: "paja.pointer.resolved",
22807
+ dTag: resolvedTarget.dTag,
22808
+ aggregateHash: resolvedTarget.aggregateHash,
22809
+ archetypes,
22810
+ requires,
22811
+ intentEligible
22812
+ });
22813
+ }
22760
22814
  function pajaPointerResolverOptions(context) {
22761
22815
  return {
22762
22816
  relays: [
@@ -23530,11 +23584,7 @@ async function loadRuntimePointer(state, context, value, options = {}) {
23530
23584
  runtime.catalog.install(resolvedTarget);
23531
23585
  const pointerStatus = `${resolvedTarget.dTag}:${resolvedTarget.aggregateHash.slice(0, 12)}`;
23532
23586
  setPointerStatus(state, pointerStatus);
23533
- appendPajaMessageLog(state, "paja", {
23534
- type: "paja.pointer.resolved",
23535
- dTag: resolvedTarget.dTag,
23536
- aggregateHash: resolvedTarget.aggregateHash
23537
- });
23587
+ recordInstalledIntentSurface(state, resolvedTarget);
23538
23588
  const duplicate = options.skipDuplicatePrompt ? void 0 : state.tabs.find((tab) => tab.key === resolvedTargetKey(resolvedTarget));
23539
23589
  if (duplicate) {
23540
23590
  const choice = await showDuplicatePointerDialog();
@@ -23681,6 +23731,7 @@ function createPajaBrowserState(context) {
23681
23731
  };
23682
23732
  }
23683
23733
  async function installPajaHost() {
23734
+ const disposeConsolePanel = installPajaConsolePanel();
23684
23735
  const config = await readLatestConfig(readConfig());
23685
23736
  const stage = getStage();
23686
23737
  const frame = config.target.mode === "runtime-pointer" ? null : getFrame();
@@ -23771,6 +23822,7 @@ async function installPajaHost() {
23771
23822
  window.addEventListener("pagehide", () => confirmationController.dispose(), { once: true });
23772
23823
  window.addEventListener("pagehide", () => notifyController?.dispose(), { once: true });
23773
23824
  window.addEventListener("pagehide", () => configController?.dispose(), { once: true });
23825
+ window.addEventListener("pagehide", disposeConsolePanel, { once: true });
23774
23826
  window.__KEHTO_PAJA__ = state;
23775
23827
  window.addEventListener("message", (event) => {
23776
23828
  const source = event.source;