@toon-protocol/views 0.2.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/dist/a2ui/A2UIRenderer.d.ts +47 -0
- package/dist/a2ui/A2UIRenderer.d.ts.map +1 -0
- package/dist/a2ui/A2UIRenderer.js +106 -0
- package/dist/a2ui/A2UIRenderer.js.map +1 -0
- package/dist/a2ui/binding.d.ts +46 -0
- package/dist/a2ui/binding.d.ts.map +1 -0
- package/dist/a2ui/binding.js +111 -0
- package/dist/a2ui/binding.js.map +1 -0
- package/dist/a2ui/index.d.ts +17 -0
- package/dist/a2ui/index.d.ts.map +1 -0
- package/dist/a2ui/index.js +17 -0
- package/dist/a2ui/index.js.map +1 -0
- package/dist/a2ui/types.d.ts +101 -0
- package/dist/a2ui/types.d.ts.map +1 -0
- package/dist/a2ui/types.js +64 -0
- package/dist/a2ui/types.js.map +1 -0
- package/dist/a2ui/validate.d.ts +55 -0
- package/dist/a2ui/validate.d.ts.map +1 -0
- package/dist/a2ui/validate.js +117 -0
- package/dist/a2ui/validate.js.map +1 -0
- package/dist/app/index.html +246 -0
- package/dist/app-bridge/ext-apps-bridge.d.ts +16 -0
- package/dist/app-bridge/ext-apps-bridge.d.ts.map +1 -0
- package/dist/app-bridge/ext-apps-bridge.js +66 -0
- package/dist/app-bridge/ext-apps-bridge.js.map +1 -0
- package/dist/app-bridge/types.d.ts +41 -0
- package/dist/app-bridge/types.d.ts.map +1 -0
- package/dist/app-bridge/types.js +10 -0
- package/dist/app-bridge/types.js.map +1 -0
- package/dist/app-entry.d.ts +13 -0
- package/dist/app-entry.d.ts.map +1 -0
- package/dist/app-entry.js +45 -0
- package/dist/app-entry.js.map +1 -0
- package/dist/atoms/defi.d.ts +3 -0
- package/dist/atoms/defi.d.ts.map +1 -0
- package/dist/atoms/defi.js +80 -0
- package/dist/atoms/defi.js.map +1 -0
- package/dist/atoms/fallback.d.ts +4 -0
- package/dist/atoms/fallback.d.ts.map +1 -0
- package/dist/atoms/fallback.js +15 -0
- package/dist/atoms/fallback.js.map +1 -0
- package/dist/atoms/forge.d.ts +3 -0
- package/dist/atoms/forge.d.ts.map +1 -0
- package/dist/atoms/forge.js +50 -0
- package/dist/atoms/forge.js.map +1 -0
- package/dist/atoms/interactive.d.ts +3 -0
- package/dist/atoms/interactive.d.ts.map +1 -0
- package/dist/atoms/interactive.js +99 -0
- package/dist/atoms/interactive.js.map +1 -0
- package/dist/atoms/layout.d.ts +3 -0
- package/dist/atoms/layout.d.ts.map +1 -0
- package/dist/atoms/layout.js +22 -0
- package/dist/atoms/layout.js.map +1 -0
- package/dist/atoms/media.d.ts +3 -0
- package/dist/atoms/media.d.ts.map +1 -0
- package/dist/atoms/media.js +92 -0
- package/dist/atoms/media.js.map +1 -0
- package/dist/atoms/onboard.d.ts +3 -0
- package/dist/atoms/onboard.d.ts.map +1 -0
- package/dist/atoms/onboard.js +26 -0
- package/dist/atoms/onboard.js.map +1 -0
- package/dist/atoms/registry.d.ts +35 -0
- package/dist/atoms/registry.d.ts.map +1 -0
- package/dist/atoms/registry.js +77 -0
- package/dist/atoms/registry.js.map +1 -0
- package/dist/atoms/social.d.ts +3 -0
- package/dist/atoms/social.d.ts.map +1 -0
- package/dist/atoms/social.js +52 -0
- package/dist/atoms/social.js.map +1 -0
- package/dist/atoms/types.d.ts +72 -0
- package/dist/atoms/types.d.ts.map +1 -0
- package/dist/atoms/types.js +11 -0
- package/dist/atoms/types.js.map +1 -0
- package/dist/catalog.d.ts +27 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +121 -0
- package/dist/catalog.js.map +1 -0
- package/dist/components/mono-id.d.ts +16 -0
- package/dist/components/mono-id.d.ts.map +1 -0
- package/dist/components/mono-id.js +18 -0
- package/dist/components/mono-id.js.map +1 -0
- package/dist/components/ui/avatar.d.ts +12 -0
- package/dist/components/ui/avatar.d.ts.map +1 -0
- package/dist/components/ui/avatar.js +25 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.d.ts +10 -0
- package/dist/components/ui/badge.d.ts.map +1 -0
- package/dist/components/ui/badge.js +26 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/button.d.ts.map +1 -0
- package/dist/components/ui/button.js +37 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/input.d.ts +4 -0
- package/dist/components/ui/input.d.ts.map +1 -0
- package/dist/components/ui/input.js +8 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/separator.d.ts +5 -0
- package/dist/components/ui/separator.d.ts.map +1 -0
- package/dist/components/ui/separator.js +9 -0
- package/dist/components/ui/separator.js.map +1 -0
- package/dist/components/ui/textarea.d.ts +4 -0
- package/dist/components/ui/textarea.d.ts.map +1 -0
- package/dist/components/ui/textarea.js +8 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/examples.d.ts +39 -0
- package/dist/examples.d.ts.map +1 -0
- package/dist/examples.js +168 -0
- package/dist/examples.js.map +1 -0
- package/dist/filters.d.ts +40 -0
- package/dist/filters.d.ts.map +1 -0
- package/dist/filters.js +84 -0
- package/dist/filters.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cn.d.ts +4 -0
- package/dist/lib/cn.d.ts.map +1 -0
- package/dist/lib/cn.js +7 -0
- package/dist/lib/cn.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +7 -0
- package/dist/main.js.map +1 -0
- package/dist/mcp-ui/ConsentPrompt.d.ts +41 -0
- package/dist/mcp-ui/ConsentPrompt.d.ts.map +1 -0
- package/dist/mcp-ui/ConsentPrompt.js +45 -0
- package/dist/mcp-ui/ConsentPrompt.js.map +1 -0
- package/dist/mcp-ui/SandboxedAppRenderer.d.ts +54 -0
- package/dist/mcp-ui/SandboxedAppRenderer.d.ts.map +1 -0
- package/dist/mcp-ui/SandboxedAppRenderer.js +74 -0
- package/dist/mcp-ui/SandboxedAppRenderer.js.map +1 -0
- package/dist/mcp-ui/index.d.ts +18 -0
- package/dist/mcp-ui/index.d.ts.map +1 -0
- package/dist/mcp-ui/index.js +18 -0
- package/dist/mcp-ui/index.js.map +1 -0
- package/dist/mcp-ui/sandbox.d.ts +62 -0
- package/dist/mcp-ui/sandbox.d.ts.map +1 -0
- package/dist/mcp-ui/sandbox.js +78 -0
- package/dist/mcp-ui/sandbox.js.map +1 -0
- package/dist/parsers/media.d.ts +68 -0
- package/dist/parsers/media.d.ts.map +1 -0
- package/dist/parsers/media.js +124 -0
- package/dist/parsers/media.js.map +1 -0
- package/dist/parsers/nip34.d.ts +75 -0
- package/dist/parsers/nip34.d.ts.map +1 -0
- package/dist/parsers/nip34.js +142 -0
- package/dist/parsers/nip34.js.map +1 -0
- package/dist/parsers/social.d.ts +89 -0
- package/dist/parsers/social.d.ts.map +1 -0
- package/dist/parsers/social.js +136 -0
- package/dist/parsers/social.js.map +1 -0
- package/dist/render/node-shims/node-builtins.d.ts +30 -0
- package/dist/render/node-shims/node-builtins.d.ts.map +1 -0
- package/dist/render/node-shims/node-builtins.js +38 -0
- package/dist/render/node-shims/node-builtins.js.map +1 -0
- package/dist/render/resolve.d.ts +72 -0
- package/dist/render/resolve.d.ts.map +1 -0
- package/dist/render/resolve.js +115 -0
- package/dist/render/resolve.js.map +1 -0
- package/dist/runtime.d.ts +17 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +218 -0
- package/dist/runtime.js.map +1 -0
- package/dist/server/apps-server.d.ts +32 -0
- package/dist/server/apps-server.d.ts.map +1 -0
- package/dist/server/apps-server.js +163 -0
- package/dist/server/apps-server.js.map +1 -0
- package/dist/server/backend.d.ts +148 -0
- package/dist/server/backend.d.ts.map +1 -0
- package/dist/server/backend.js +11 -0
- package/dist/server/backend.js.map +1 -0
- package/dist/server/daemon-backend.d.ts +113 -0
- package/dist/server/daemon-backend.d.ts.map +1 -0
- package/dist/server/daemon-backend.js +79 -0
- package/dist/server/daemon-backend.js.map +1 -0
- package/dist/server/daemon-main.d.ts +25 -0
- package/dist/server/daemon-main.d.ts.map +1 -0
- package/dist/server/daemon-main.js +165 -0
- package/dist/server/daemon-main.js.map +1 -0
- package/dist/server/fake-backend.d.ts +53 -0
- package/dist/server/fake-backend.d.ts.map +1 -0
- package/dist/server/fake-backend.js +157 -0
- package/dist/server/fake-backend.js.map +1 -0
- package/dist/server/fake-main.d.ts +15 -0
- package/dist/server/fake-main.d.ts.map +1 -0
- package/dist/server/fake-main.js +39 -0
- package/dist/server/fake-main.js.map +1 -0
- package/dist/spec.d.ts +67 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +221 -0
- package/dist/spec.js.map +1 -0
- package/dist/tool-names.d.ts +27 -0
- package/dist/tool-names.d.ts.map +1 -0
- package/dist/tool-names.js +32 -0
- package/dist/tool-names.js.map +1 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser shim for the Node builtins (`child_process`, `fs/promises`, `os`,
|
|
3
|
+
* `path`, `crypto`) that `@toon-protocol/core`'s root entry top-level-imports for
|
|
4
|
+
* its Node-only devnet `preset` helper. Aliased in by `vite.config.ts` for the
|
|
5
|
+
* MCP-app bundle only.
|
|
6
|
+
*
|
|
7
|
+
* The render trust gradient uses only core's PURE `ui` coordinate helpers; the
|
|
8
|
+
* devnet-preset code that needs these builtins is dead in the iframe. Vite's
|
|
9
|
+
* default `__vite-browser-external` stub does not export the *named* bindings
|
|
10
|
+
* core imports (`execFile`, `mkdtemp`, `tmpdir`, …), which fails the build at
|
|
11
|
+
* link time. This shim exports every name core references so the (dead) imports
|
|
12
|
+
* resolve; any actual call throws — none happens in the browser.
|
|
13
|
+
*/
|
|
14
|
+
function unavailable(name) {
|
|
15
|
+
throw new Error(`Node builtin "${name}" is not available in the browser bundle`);
|
|
16
|
+
}
|
|
17
|
+
// child_process
|
|
18
|
+
export const execFile = () => unavailable('child_process.execFile');
|
|
19
|
+
// fs/promises
|
|
20
|
+
export const readFile = () => unavailable('fs/promises.readFile');
|
|
21
|
+
export const writeFile = () => unavailable('fs/promises.writeFile');
|
|
22
|
+
export const mkdtemp = () => unavailable('fs/promises.mkdtemp');
|
|
23
|
+
export const cp = () => unavailable('fs/promises.cp');
|
|
24
|
+
export const rm = () => unavailable('fs/promises.rm');
|
|
25
|
+
// os
|
|
26
|
+
export const tmpdir = () => unavailable('os.tmpdir');
|
|
27
|
+
// crypto
|
|
28
|
+
export const createHash = () => unavailable('crypto.createHash');
|
|
29
|
+
// path — default import in core; provide the members it could reference.
|
|
30
|
+
const pathShim = {
|
|
31
|
+
join: () => unavailable('path.join'),
|
|
32
|
+
resolve: () => unavailable('path.resolve'),
|
|
33
|
+
dirname: () => unavailable('path.dirname'),
|
|
34
|
+
basename: () => unavailable('path.basename'),
|
|
35
|
+
sep: '/',
|
|
36
|
+
};
|
|
37
|
+
export default pathShim;
|
|
38
|
+
//# sourceMappingURL=node-builtins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-builtins.js","sourceRoot":"","sources":["../../../src/render/node-shims/node-builtins.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,0CAA0C,CAAC,CAAC;AACnF,CAAC;AAED,gBAAgB;AAChB,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,wBAAwB,CAAC,CAAC;AAE3E,cAAc;AACd,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,sBAAsB,CAAC,CAAC;AACzE,MAAM,CAAC,MAAM,SAAS,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,uBAAuB,CAAC,CAAC;AAC3E,MAAM,CAAC,MAAM,OAAO,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC;AACvE,MAAM,CAAC,MAAM,EAAE,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;AAC7D,MAAM,CAAC,MAAM,EAAE,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;AAE7D,KAAK;AACL,MAAM,CAAC,MAAM,MAAM,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;AAE5D,SAAS;AACT,MAAM,CAAC,MAAM,UAAU,GAAG,GAAU,EAAE,CAAC,WAAW,CAAC,mBAAmB,CAAC,CAAC;AAExE,yEAAyE;AACzE,MAAM,QAAQ,GAAG;IACf,IAAI,EAAE,GAAU,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC;IAC3C,OAAO,EAAE,GAAU,EAAE,CAAC,WAAW,CAAC,cAAc,CAAC;IACjD,OAAO,EAAE,GAAU,EAAE,CAAC,WAAW,CAAC,cAAc,CAAC;IACjD,QAAQ,EAAE,GAAU,EAAE,CAAC,WAAW,CAAC,eAAe,CAAC;IACnD,GAAG,EAAE,GAAG;CACT,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live render-trust-gradient resolution for incoming events.
|
|
3
|
+
*
|
|
4
|
+
* This is the host-wiring half of the NIP-on-TOON render gradient (toon-meta#58):
|
|
5
|
+
* `@toon-protocol/client` owns the pure dispatch + swap-defense; this module
|
|
6
|
+
* fetches the renderer over the app's {@link ViewBridge} (the app has no direct
|
|
7
|
+
* relay access) and drives {@link guardedRenderDispatch} so every incoming event
|
|
8
|
+
* is routed through the gradient instead of unconditionally rendered native.
|
|
9
|
+
*
|
|
10
|
+
* Flow per event:
|
|
11
|
+
* 1. {@link resolveUiCoordinate} parses the event's `ui` tag → a renderer
|
|
12
|
+
* coordinate `31036:<event-author>:<targetKind>` (or `null` if no `ui` tag).
|
|
13
|
+
* 2. If a coordinate exists, fetch candidate `kind:31036` renderers via the
|
|
14
|
+
* bridge: `toon_query { kinds: [31036], '#d': [targetKind], authors: [author] }`.
|
|
15
|
+
* The query is a relay round-trip, so resolution is async (loading state).
|
|
16
|
+
* 3. {@link guardedRenderDispatch} runs the swap-defense guard over the raw
|
|
17
|
+
* candidates (author-binding + signature re-verify + anti-swap pinning) and
|
|
18
|
+
* returns the {@link RenderDecision} — native / a2ui / mcp-ui / generative.
|
|
19
|
+
*
|
|
20
|
+
* Known kinds short-circuit to branch 1 (native) without any bridge round-trip,
|
|
21
|
+
* keeping the common feed path fast: a kind with a registered atom never needs a
|
|
22
|
+
* renderer fetch.
|
|
23
|
+
*
|
|
24
|
+
* NOTE on coordinate forms: the query filter is built from
|
|
25
|
+
* {@link resolveUiCoordinate}, which accepts BOTH the bare target-kind `ui` tag
|
|
26
|
+
* (`["ui","42"]`) and the full `31036:<pubkey>:<kind>` coordinate. The
|
|
27
|
+
* swap-defense guard inside {@link guardedRenderDispatch}, however, is authored
|
|
28
|
+
* against the FULL coordinate (core's `getUiCoordinate`) and fails closed
|
|
29
|
+
* (→ generative) on a bare-only `ui` tag. So branches 2/3 light up for events
|
|
30
|
+
* carrying the full coordinate (the canonical renderer-aware form); a bare-only
|
|
31
|
+
* `ui` tag still resolves a query but the guard routes it to the safe generative
|
|
32
|
+
* branch. This mirrors the guard being the security-authoritative gate.
|
|
33
|
+
*/
|
|
34
|
+
import { type DispatchGuardInfo, type KindRegistry, type RenderDecision, type RendererPinStore } from '@toon-protocol/client/render';
|
|
35
|
+
import { type NostrEvent } from '../types.js';
|
|
36
|
+
import { type ViewBridge } from '../app-bridge/types.js';
|
|
37
|
+
import { type Atom } from '../atoms/types.js';
|
|
38
|
+
/**
|
|
39
|
+
* Build the `toon_query` filter that fetches the candidate `kind:31036`
|
|
40
|
+
* renderers for an event's `ui` coordinate. Returns `undefined` when the event
|
|
41
|
+
* carries no usable `ui` tag (nothing to resolve — branch 4 territory).
|
|
42
|
+
*
|
|
43
|
+
* The filter is author-bound to the event author (the authoritative renderer
|
|
44
|
+
* author, per toon#36) and pinned to the target kind via the `#d` tag, mirroring
|
|
45
|
+
* the coordinate the swap-defense guard re-derives — so the relay returns only
|
|
46
|
+
* the revisions that can legitimately win.
|
|
47
|
+
*/
|
|
48
|
+
export declare function rendererQueryFilter(event: NostrEvent): {
|
|
49
|
+
kinds: number[];
|
|
50
|
+
authors: string[];
|
|
51
|
+
'#d': string[];
|
|
52
|
+
} | undefined;
|
|
53
|
+
/** The outcome of {@link useRenderDecision}. */
|
|
54
|
+
export interface RenderResolution {
|
|
55
|
+
/** The dispatch decision, or `null` while a renderer fetch is in flight. */
|
|
56
|
+
decision: RenderDecision<Atom> | null;
|
|
57
|
+
/** Set when the swap-defense guard refused a renderer (the gradient fell back). */
|
|
58
|
+
guard?: DispatchGuardInfo;
|
|
59
|
+
/** `true` while the renderer query round-trip is in flight. */
|
|
60
|
+
loading: boolean;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve an event to a {@link RenderDecision} through the render trust gradient.
|
|
64
|
+
*
|
|
65
|
+
* Known kinds resolve synchronously to branch 1 (native) — no bridge call. For
|
|
66
|
+
* an unknown kind with a `ui` coordinate, the candidate renderers are fetched
|
|
67
|
+
* over the bridge and the guarded dispatch picks the branch once they arrive;
|
|
68
|
+
* until then `loading` is `true` and `decision` is `null`. Unknown kinds with no
|
|
69
|
+
* `ui` tag resolve immediately to branch 4 (generative).
|
|
70
|
+
*/
|
|
71
|
+
export declare function useRenderDecision(event: NostrEvent, bridge: ViewBridge, registry: KindRegistry<Atom>, pins: RendererPinStore): RenderResolution;
|
|
72
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/render/resolve.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAGH,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EAEtB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAG9C;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,UAAU,GAChB;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAQpE;AAED,gDAAgD;AAChD,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,QAAQ,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACtC,mFAAmF;IACnF,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,+DAA+D;IAC/D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,YAAY,CAAC,IAAI,CAAC,EAC5B,IAAI,EAAE,gBAAgB,GACrB,gBAAgB,CAkDlB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Live render-trust-gradient resolution for incoming events.
|
|
3
|
+
*
|
|
4
|
+
* This is the host-wiring half of the NIP-on-TOON render gradient (toon-meta#58):
|
|
5
|
+
* `@toon-protocol/client` owns the pure dispatch + swap-defense; this module
|
|
6
|
+
* fetches the renderer over the app's {@link ViewBridge} (the app has no direct
|
|
7
|
+
* relay access) and drives {@link guardedRenderDispatch} so every incoming event
|
|
8
|
+
* is routed through the gradient instead of unconditionally rendered native.
|
|
9
|
+
*
|
|
10
|
+
* Flow per event:
|
|
11
|
+
* 1. {@link resolveUiCoordinate} parses the event's `ui` tag → a renderer
|
|
12
|
+
* coordinate `31036:<event-author>:<targetKind>` (or `null` if no `ui` tag).
|
|
13
|
+
* 2. If a coordinate exists, fetch candidate `kind:31036` renderers via the
|
|
14
|
+
* bridge: `toon_query { kinds: [31036], '#d': [targetKind], authors: [author] }`.
|
|
15
|
+
* The query is a relay round-trip, so resolution is async (loading state).
|
|
16
|
+
* 3. {@link guardedRenderDispatch} runs the swap-defense guard over the raw
|
|
17
|
+
* candidates (author-binding + signature re-verify + anti-swap pinning) and
|
|
18
|
+
* returns the {@link RenderDecision} — native / a2ui / mcp-ui / generative.
|
|
19
|
+
*
|
|
20
|
+
* Known kinds short-circuit to branch 1 (native) without any bridge round-trip,
|
|
21
|
+
* keeping the common feed path fast: a kind with a registered atom never needs a
|
|
22
|
+
* renderer fetch.
|
|
23
|
+
*
|
|
24
|
+
* NOTE on coordinate forms: the query filter is built from
|
|
25
|
+
* {@link resolveUiCoordinate}, which accepts BOTH the bare target-kind `ui` tag
|
|
26
|
+
* (`["ui","42"]`) and the full `31036:<pubkey>:<kind>` coordinate. The
|
|
27
|
+
* swap-defense guard inside {@link guardedRenderDispatch}, however, is authored
|
|
28
|
+
* against the FULL coordinate (core's `getUiCoordinate`) and fails closed
|
|
29
|
+
* (→ generative) on a bare-only `ui` tag. So branches 2/3 light up for events
|
|
30
|
+
* carrying the full coordinate (the canonical renderer-aware form); a bare-only
|
|
31
|
+
* `ui` tag still resolves a query but the guard routes it to the safe generative
|
|
32
|
+
* branch. This mirrors the guard being the security-authoritative gate.
|
|
33
|
+
*/
|
|
34
|
+
import { useEffect, useState } from 'react';
|
|
35
|
+
import { guardedRenderDispatch, resolveUiCoordinate, UI_RENDERER_KIND, } from '@toon-protocol/client/render';
|
|
36
|
+
import {} from '../types.js';
|
|
37
|
+
import {} from '../app-bridge/types.js';
|
|
38
|
+
import {} from '../atoms/types.js';
|
|
39
|
+
import { QUERY_TOOL } from '../tool-names.js';
|
|
40
|
+
/**
|
|
41
|
+
* Build the `toon_query` filter that fetches the candidate `kind:31036`
|
|
42
|
+
* renderers for an event's `ui` coordinate. Returns `undefined` when the event
|
|
43
|
+
* carries no usable `ui` tag (nothing to resolve — branch 4 territory).
|
|
44
|
+
*
|
|
45
|
+
* The filter is author-bound to the event author (the authoritative renderer
|
|
46
|
+
* author, per toon#36) and pinned to the target kind via the `#d` tag, mirroring
|
|
47
|
+
* the coordinate the swap-defense guard re-derives — so the relay returns only
|
|
48
|
+
* the revisions that can legitimately win.
|
|
49
|
+
*/
|
|
50
|
+
export function rendererQueryFilter(event) {
|
|
51
|
+
const coord = resolveUiCoordinate(event);
|
|
52
|
+
if (!coord)
|
|
53
|
+
return undefined;
|
|
54
|
+
return {
|
|
55
|
+
kinds: [UI_RENDERER_KIND],
|
|
56
|
+
authors: [coord.pubkey],
|
|
57
|
+
'#d': [String(coord.targetKind)],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Resolve an event to a {@link RenderDecision} through the render trust gradient.
|
|
62
|
+
*
|
|
63
|
+
* Known kinds resolve synchronously to branch 1 (native) — no bridge call. For
|
|
64
|
+
* an unknown kind with a `ui` coordinate, the candidate renderers are fetched
|
|
65
|
+
* over the bridge and the guarded dispatch picks the branch once they arrive;
|
|
66
|
+
* until then `loading` is `true` and `decision` is `null`. Unknown kinds with no
|
|
67
|
+
* `ui` tag resolve immediately to branch 4 (generative).
|
|
68
|
+
*/
|
|
69
|
+
export function useRenderDecision(event, bridge, registry, pins) {
|
|
70
|
+
const [resolution, setResolution] = useState(() => {
|
|
71
|
+
// Known kind, or no `ui` tag → no fetch needed; decide synchronously so the
|
|
72
|
+
// common path renders on the first frame with no loading flash.
|
|
73
|
+
if (registry.has(event.kind) || rendererQueryFilter(event) === undefined) {
|
|
74
|
+
const { decision, guard } = guardedRenderDispatch({ event }, registry, pins);
|
|
75
|
+
return { decision, ...(guard ? { guard } : {}), loading: false };
|
|
76
|
+
}
|
|
77
|
+
return { decision: null, loading: true };
|
|
78
|
+
});
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
const filter = rendererQueryFilter(event);
|
|
81
|
+
// Known kind or no coordinate: already decided synchronously above; nothing
|
|
82
|
+
// to fetch. (Re-assert in case the event prop changed between renders.)
|
|
83
|
+
if (registry.has(event.kind) || filter === undefined) {
|
|
84
|
+
const { decision, guard } = guardedRenderDispatch({ event }, registry, pins);
|
|
85
|
+
setResolution({ decision, ...(guard ? { guard } : {}), loading: false });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
let cancelled = false;
|
|
89
|
+
setResolution({ decision: null, loading: true });
|
|
90
|
+
void bridge
|
|
91
|
+
.callTool(QUERY_TOOL, { filter })
|
|
92
|
+
.then((res) => {
|
|
93
|
+
if (cancelled)
|
|
94
|
+
return;
|
|
95
|
+
const candidates = res.events ?? [];
|
|
96
|
+
const { decision, guard } = guardedRenderDispatch({ event, candidates }, registry, pins);
|
|
97
|
+
setResolution({ decision, ...(guard ? { guard } : {}), loading: false });
|
|
98
|
+
})
|
|
99
|
+
.catch(() => {
|
|
100
|
+
if (cancelled)
|
|
101
|
+
return;
|
|
102
|
+
// A failed renderer fetch must never render nothing — fall back to the
|
|
103
|
+
// gradient's safe branch (generative for the unknown kind) with no
|
|
104
|
+
// candidates, exactly as if the relay returned an empty set.
|
|
105
|
+
const { decision, guard } = guardedRenderDispatch({ event }, registry, pins);
|
|
106
|
+
setResolution({ decision, ...(guard ? { guard } : {}), loading: false });
|
|
107
|
+
});
|
|
108
|
+
return () => {
|
|
109
|
+
cancelled = true;
|
|
110
|
+
};
|
|
111
|
+
// `event.id` keys the event; bridge/registry/pins are stable for a session.
|
|
112
|
+
}, [event.id, bridge, registry, pins]);
|
|
113
|
+
return resolution;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/render/resolve.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ViewSpec composition runtime.
|
|
3
|
+
*
|
|
4
|
+
* Interprets a (model-authored, validated) ViewSpec into a React tree using the
|
|
5
|
+
* atom registry. Data binds resolve via the {@link ViewBridge} (free reads);
|
|
6
|
+
* write actions are wired to the bridge. Unknown atom ids / invalid specs
|
|
7
|
+
* degrade to the generic fallback — never crash, never `eval`.
|
|
8
|
+
*/
|
|
9
|
+
import { type ReactNode } from 'react';
|
|
10
|
+
import { type ViewBridge } from './app-bridge/types.js';
|
|
11
|
+
export { QUERY_TOOL, WRITE_TOOLS } from './tool-names.js';
|
|
12
|
+
/** Top-level: validate an untrusted ViewSpec then render it, or show the error. */
|
|
13
|
+
export declare function ViewSpecRenderer({ spec, bridge, }: {
|
|
14
|
+
spec: unknown;
|
|
15
|
+
bridge: ViewBridge;
|
|
16
|
+
}): ReactNode;
|
|
17
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAgC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASrE,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAqCxD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAqP1D,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,MAAM,GACP,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;CACpB,GAAG,SAAS,CAOZ"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* ViewSpec composition runtime.
|
|
4
|
+
*
|
|
5
|
+
* Interprets a (model-authored, validated) ViewSpec into a React tree using the
|
|
6
|
+
* atom registry. Data binds resolve via the {@link ViewBridge} (free reads);
|
|
7
|
+
* write actions are wired to the bridge. Unknown atom ids / invalid specs
|
|
8
|
+
* degrade to the generic fallback — never crash, never `eval`.
|
|
9
|
+
*/
|
|
10
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
11
|
+
import { extractUiResource, GenerativeFallbackRenderer, RendererPinStore, } from '@toon-protocol/client/render';
|
|
12
|
+
import {} from './types.js';
|
|
13
|
+
import {} from './app-bridge/types.js';
|
|
14
|
+
import { validateViewSpec, } from './spec.js';
|
|
15
|
+
import { ATOMS, ATOM_IDS, buildKindRegistry, fallbackAtomFor, } from './atoms/registry.js';
|
|
16
|
+
import {} from './atoms/types.js';
|
|
17
|
+
import { useRenderDecision } from './render/resolve.js';
|
|
18
|
+
import { A2UIRenderer } from './a2ui/A2UIRenderer.js';
|
|
19
|
+
import { SandboxedAppRenderer } from './mcp-ui/SandboxedAppRenderer.js';
|
|
20
|
+
import { DEFAULT_MCP_UI_SANDBOX_URL } from './mcp-ui/sandbox.js';
|
|
21
|
+
import { QUERY_TOOL, STATUS_TOOL, WRITE_TOOLS } from './tool-names.js';
|
|
22
|
+
/**
|
|
23
|
+
* Session-scoped render-gradient state. Built once per bundle load:
|
|
24
|
+
* - the branch-1 native {@link KindRegistry} of atoms, and
|
|
25
|
+
* - the anti-swap {@link RendererPinStore} that pins each coordinate's chosen
|
|
26
|
+
* renderer for the life of the session (the swap-defense's V4 guard).
|
|
27
|
+
* Both are stable across renders so `guardedRenderDispatch` sees a consistent
|
|
28
|
+
* registry/pin store and the swap-defense pins persist.
|
|
29
|
+
*/
|
|
30
|
+
const KIND_REGISTRY = buildKindRegistry();
|
|
31
|
+
const RENDERER_PINS = new RendererPinStore();
|
|
32
|
+
/**
|
|
33
|
+
* The branch-4 generative fallback. Uses the deterministic generator (no model
|
|
34
|
+
* is wired in the app yet — the injected-generator seam stays available) and
|
|
35
|
+
* publish-back stays OFF (no `publish` option). See toon-meta#58.
|
|
36
|
+
*/
|
|
37
|
+
const GENERATIVE_FALLBACK = new GenerativeFallbackRenderer();
|
|
38
|
+
// Re-export so existing importers (and tests) can keep importing from the runtime.
|
|
39
|
+
export { QUERY_TOOL, WRITE_TOOLS } from './tool-names.js';
|
|
40
|
+
function useBind(bind, bridge) {
|
|
41
|
+
const [events, setEvents] = useState([]);
|
|
42
|
+
const bindKey = bind ? JSON.stringify(bind) : '';
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
const filter = bind?.query ?? (bind?.eventId ? { ids: [bind.eventId] } : undefined);
|
|
45
|
+
if (!filter) {
|
|
46
|
+
setEvents([]);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
let cancelled = false;
|
|
50
|
+
void bridge.callTool(QUERY_TOOL, { filter }).then((res) => {
|
|
51
|
+
if (!cancelled && res.events)
|
|
52
|
+
setEvents(res.events);
|
|
53
|
+
});
|
|
54
|
+
return () => {
|
|
55
|
+
cancelled = true;
|
|
56
|
+
};
|
|
57
|
+
// bindKey captures the (serialized) bind; bridge is stable for a session.
|
|
58
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
59
|
+
}, [bindKey, bridge]);
|
|
60
|
+
return events;
|
|
61
|
+
}
|
|
62
|
+
function buildActions(node, bridge) {
|
|
63
|
+
const actions = {};
|
|
64
|
+
for (const [name, ref] of Object.entries(node.actions ?? {})) {
|
|
65
|
+
actions[name] = async (runtimeArgs) => {
|
|
66
|
+
const args = { ...(ref.args ?? {}), ...(runtimeArgs ?? {}) };
|
|
67
|
+
if (ref.spendy) {
|
|
68
|
+
const label = ref.confirmLabel ?? 'This action spends to publish. Continue?';
|
|
69
|
+
// Fallback is browser-only; auto-approves in Worker/SSR environments where window is absent.
|
|
70
|
+
const confirmFn = bridge.confirm ??
|
|
71
|
+
((msg) => Promise.resolve(typeof window !== 'undefined' ? !!window.confirm(msg) : true));
|
|
72
|
+
const ok = await confirmFn(label);
|
|
73
|
+
if (!ok) {
|
|
74
|
+
bridge.notifyModel(`Action "${name}" cancelled.`);
|
|
75
|
+
return { ok: false, error: 'cancelled' };
|
|
76
|
+
}
|
|
77
|
+
args['spendy'] = true;
|
|
78
|
+
}
|
|
79
|
+
const res = await bridge.callTool(ref.tool, args);
|
|
80
|
+
bridge.notifyModel(res.ok ? `Action "${name}" completed.` : `Action "${name}" failed: ${res.error ?? 'unknown'}`);
|
|
81
|
+
// Surface the real published id so atoms can render an accurate receipt.
|
|
82
|
+
// The publish/upload tools return `{ eventId, … }` as `structuredContent`,
|
|
83
|
+
// which the bridge carries on `ToolOutcome.data`.
|
|
84
|
+
const eventId = res.data && typeof res.data === 'object' && 'eventId' in res.data
|
|
85
|
+
? String(res.data.eventId)
|
|
86
|
+
: undefined;
|
|
87
|
+
return {
|
|
88
|
+
ok: res.ok,
|
|
89
|
+
...(eventId ? { eventId } : {}),
|
|
90
|
+
...(res.data !== undefined ? { data: res.data } : {}),
|
|
91
|
+
...(res.error ? { error: res.error } : {}),
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return actions;
|
|
96
|
+
}
|
|
97
|
+
/** Render an event with a resolved branch-1 native atom (full trust). */
|
|
98
|
+
function NativeEvent({ atom, event, bridge }) {
|
|
99
|
+
const Component = atom.Component;
|
|
100
|
+
return (_jsx(Component, { events: [event], props: {}, actions: {}, renderEvent: (e) => _jsx(EventAtom, { event: e, bridge: bridge }, e.id), children: null }));
|
|
101
|
+
}
|
|
102
|
+
/** Branch 4 — generative fallback (low trust). Renders the deterministic HTML. */
|
|
103
|
+
function GenerativeEvent({ event }) {
|
|
104
|
+
const [result, setResult] = useState(null);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
let cancelled = false;
|
|
107
|
+
void GENERATIVE_FALLBACK.render(event).then((r) => {
|
|
108
|
+
if (!cancelled)
|
|
109
|
+
setResult(r);
|
|
110
|
+
});
|
|
111
|
+
return () => {
|
|
112
|
+
cancelled = true;
|
|
113
|
+
};
|
|
114
|
+
}, [event]);
|
|
115
|
+
if (!result) {
|
|
116
|
+
return _jsx("div", { className: "p-2 text-xs text-muted-foreground", children: "Rendering\u2026" });
|
|
117
|
+
}
|
|
118
|
+
// The deterministic generator emits trusted, host-built HTML (no widget code);
|
|
119
|
+
// it is safe to render directly. (A model-backed generator would route through
|
|
120
|
+
// the sandbox like branch 3 — not wired in the app yet.)
|
|
121
|
+
return (_jsx("div", { "data-branch": "generative", "data-trust": result.trust, dangerouslySetInnerHTML: { __html: result.rendered.html } }));
|
|
122
|
+
}
|
|
123
|
+
/** Adapt the app bridge into the branch-3 `onPerform` (authorized tool runner). */
|
|
124
|
+
function bridgePerformTool(bridge) {
|
|
125
|
+
return async (toolName, args) => {
|
|
126
|
+
const res = await bridge.callTool(toolName, args);
|
|
127
|
+
return {
|
|
128
|
+
...(res.error ? { isError: true } : {}),
|
|
129
|
+
content: [{ type: 'text', text: res.error ?? 'ok' }],
|
|
130
|
+
...(res.data !== undefined ? { structuredContent: res.data } : {}),
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Render a single incoming event through the NIP-on-TOON render trust gradient
|
|
136
|
+
* (feeds / kindAuto). Branch 1 (known kind) renders the native atom; branches
|
|
137
|
+
* 2/3/4 render through the resolved `kind:31036` renderer (A2UI / sandboxed
|
|
138
|
+
* mcp-ui) or the generative fallback — guarded by the swap-defense + consent.
|
|
139
|
+
*/
|
|
140
|
+
function EventAtom({ event, bridge }) {
|
|
141
|
+
const { decision, loading } = useRenderDecision(event, bridge, KIND_REGISTRY, RENDERER_PINS);
|
|
142
|
+
const performTool = useMemo(() => bridgePerformTool(bridge), [bridge]);
|
|
143
|
+
if (loading || decision === null) {
|
|
144
|
+
return _jsx("div", { className: "p-2 text-xs text-muted-foreground", children: "Resolving renderer\u2026" });
|
|
145
|
+
}
|
|
146
|
+
switch (decision.branch) {
|
|
147
|
+
case 'native':
|
|
148
|
+
return _jsx(NativeEvent, { atom: decision.component, event: event, bridge: bridge });
|
|
149
|
+
case 'a2ui':
|
|
150
|
+
// Branch 2: medium trust. On a gate refusal the renderer signals fallback;
|
|
151
|
+
// drop to the generative branch (per the gate's signal) so a refused A2UI
|
|
152
|
+
// surface still renders something safe rather than nothing.
|
|
153
|
+
return (_jsx(A2UIBranch, { renderer: decision.renderer, event: event }));
|
|
154
|
+
case 'mcp-ui':
|
|
155
|
+
// Branch 3: low trust, sandboxed iframe + host-rendered consent prompt.
|
|
156
|
+
return _jsx(McpUiBranch, { renderer: decision.renderer, event: event, performTool: performTool });
|
|
157
|
+
case 'generative':
|
|
158
|
+
// Branch 4: low trust, generative fallback (deterministic; no model wired).
|
|
159
|
+
return _jsx(GenerativeEvent, { event: event });
|
|
160
|
+
default:
|
|
161
|
+
return _jsx(GenerativeEvent, { event: event });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/** Branch 2 wrapper: render A2UI, falling back to generative on a gate refusal. */
|
|
165
|
+
function A2UIBranch({ renderer, event }) {
|
|
166
|
+
const [refused, setRefused] = useState(false);
|
|
167
|
+
if (refused)
|
|
168
|
+
return _jsx(GenerativeEvent, { event: event });
|
|
169
|
+
return _jsx(A2UIRenderer, { renderer: renderer, event: event, onFallback: () => setRefused(true) });
|
|
170
|
+
}
|
|
171
|
+
/** Branch 3 wrapper: extract the widget resource and render it sandboxed. */
|
|
172
|
+
function McpUiBranch({ renderer, event, performTool, }) {
|
|
173
|
+
const resource = useMemo(() => extractUiResource(renderer), [renderer]);
|
|
174
|
+
// A renderer that doesn't yield a usable widget resource falls back to branch 4.
|
|
175
|
+
if (!resource)
|
|
176
|
+
return _jsx(GenerativeEvent, { event: event });
|
|
177
|
+
return (_jsx(SandboxedAppRenderer, { resource: resource, sandboxUrl: new URL(DEFAULT_MCP_UI_SANDBOX_URL), onPerform: performTool }));
|
|
178
|
+
}
|
|
179
|
+
/** Read the live pay-to-write status (`toon_status`) for the fee-confirm UX. */
|
|
180
|
+
function buildReadStatus(bridge) {
|
|
181
|
+
return async () => {
|
|
182
|
+
const res = await bridge.callTool(STATUS_TOOL, {});
|
|
183
|
+
const data = (res.data ?? {});
|
|
184
|
+
// Throw so the atom catches it as statusError=true and disables Confirm — never
|
|
185
|
+
// silently show '0' for a non-zero charge.
|
|
186
|
+
if (typeof data.feePerEvent !== 'string' || !data.feePerEvent) {
|
|
187
|
+
throw new Error('fee unavailable');
|
|
188
|
+
}
|
|
189
|
+
return {
|
|
190
|
+
feePerEvent: data.feePerEvent,
|
|
191
|
+
settlementChain: typeof data.settlementChain === 'string' ? data.settlementChain : 'unknown',
|
|
192
|
+
...(typeof data.asset === 'string' ? { asset: data.asset } : {}),
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function NodeView({ node, bridge }) {
|
|
197
|
+
const atom = ATOMS.get(node.atom) ?? fallbackAtomFor();
|
|
198
|
+
const events = useBind(node.bind, bridge);
|
|
199
|
+
const actions = useMemo(() => buildActions(node, bridge), [node, bridge]);
|
|
200
|
+
const readStatus = useMemo(() => buildReadStatus(bridge), [bridge]);
|
|
201
|
+
if (node.bind?.kindAuto) {
|
|
202
|
+
return _jsx(_Fragment, { children: events.map((e) => _jsx(EventAtom, { event: e, bridge: bridge }, e.id)) });
|
|
203
|
+
}
|
|
204
|
+
const Component = atom.Component;
|
|
205
|
+
return (_jsx(Component, { events: events, props: node.props ?? {}, actions: actions, readStatus: readStatus, renderEvent: (e) => _jsx(EventAtom, { event: e, bridge: bridge }, e.id), children: node.children?.map((child, i) => _jsx(NodeView, { node: child, bridge: bridge }, i)) }));
|
|
206
|
+
}
|
|
207
|
+
/** Renders an invalid spec's errors without leaking internals to the user. */
|
|
208
|
+
function InvalidSpec({ errors }) {
|
|
209
|
+
return (_jsxs("div", { className: "rounded-md border border-destructive/40 bg-destructive/5 p-3 text-sm", children: [_jsx("div", { className: "font-medium", children: "This view could not be rendered." }), _jsx("ul", { className: "mt-1 list-disc pl-5 text-xs text-muted-foreground", children: errors.slice(0, 5).map((e, i) => (_jsx("li", { children: e }, i))) })] }));
|
|
210
|
+
}
|
|
211
|
+
/** Top-level: validate an untrusted ViewSpec then render it, or show the error. */
|
|
212
|
+
export function ViewSpecRenderer({ spec, bridge, }) {
|
|
213
|
+
const result = useMemo(() => validateViewSpec(spec, { allowedAtoms: ATOM_IDS, allowedTools: WRITE_TOOLS }), [spec]);
|
|
214
|
+
if (!result.ok)
|
|
215
|
+
return _jsx(InvalidSpec, { errors: result.errors });
|
|
216
|
+
return _jsx(NodeView, { node: result.spec.root, bridge: bridge });
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registers the TOON apps surface on an MCP server: the single `ui://toon/app`
|
|
3
|
+
* UI resource plus the tools the agent uses to drive a generative user journey.
|
|
4
|
+
*
|
|
5
|
+
* The journey loop:
|
|
6
|
+
* 1. agent → `toon_atoms` (discover the atom vocabulary)
|
|
7
|
+
* 2. agent → `toon_render(spec)` (compose a ViewSpec; rides back as the tool
|
|
8
|
+
* result, and the tool's `_meta.ui.resourceUri` makes the host render the
|
|
9
|
+
* app bundle with it)
|
|
10
|
+
* 3. iframe → `toon_query(filter)` (free reads, fed into atoms)
|
|
11
|
+
* 4. iframe → `toon_publish_unsigned` / `toon_upload_media` (writes)
|
|
12
|
+
* 5. iframe → updateModelContext → agent composes the next ViewSpec
|
|
13
|
+
*
|
|
14
|
+
* ViewSpecs are model-authored → validated here (server side) before they are
|
|
15
|
+
* echoed back, in addition to the iframe runtime's own validation.
|
|
16
|
+
*/
|
|
17
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
18
|
+
import { type AppBackend } from './backend.js';
|
|
19
|
+
export interface RegisterToonAppsOptions {
|
|
20
|
+
/** Read/write backend (fake for the demo; real daemon later). */
|
|
21
|
+
backend: AppBackend;
|
|
22
|
+
/** The self-contained app bundle HTML (served as the `ui://toon/app` resource). */
|
|
23
|
+
appHtml: string;
|
|
24
|
+
/** Domains to allow in the iframe CSP (Arweave gateway, relay origin, …). */
|
|
25
|
+
cspDomains?: {
|
|
26
|
+
connect?: string[];
|
|
27
|
+
resource?: string[];
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/** Register the `ui://toon/app` resource + the generative-UI tools. */
|
|
31
|
+
export declare function registerToonApps(server: McpServer, opts: RegisterToonAppsOptions): void;
|
|
32
|
+
//# sourceMappingURL=apps-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apps-server.d.ts","sourceRoot":"","sources":["../../src/server/apps-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAuBzE,OAAO,EAAE,KAAK,UAAU,EAAoB,MAAM,cAAc,CAAC;AAEjE,MAAM,WAAW,uBAAuB;IACtC,iEAAiE;IACjE,OAAO,EAAE,UAAU,CAAC;IACpB,mFAAmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,UAAU,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAC1D;AAaD,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAkMvF"}
|