@graview/guest 0.1.9 → 0.1.12

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.
Files changed (173) hide show
  1. package/README.md +353 -3
  2. package/client.js +2 -0
  3. package/dist/channel.d.ts +11 -3
  4. package/dist/channel.d.ts.map +1 -1
  5. package/dist/channel.js +5 -1
  6. package/dist/channel.js.map +1 -1
  7. package/dist/cli.d.ts +16 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +75 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/client-script.d.ts +3 -0
  12. package/dist/client-script.d.ts.map +1 -0
  13. package/dist/client-script.js +21 -0
  14. package/dist/client-script.js.map +1 -0
  15. package/dist/client.d.ts +2 -0
  16. package/dist/client.d.ts.map +1 -0
  17. package/dist/client.generated.d.ts +4 -0
  18. package/dist/client.generated.d.ts.map +1 -0
  19. package/dist/client.generated.js +9 -0
  20. package/dist/client.generated.js.map +1 -0
  21. package/dist/client.js +12 -0
  22. package/dist/client.js.map +1 -0
  23. package/dist/headless/describe.d.ts +19 -0
  24. package/dist/headless/describe.d.ts.map +1 -0
  25. package/dist/headless/describe.js +255 -0
  26. package/dist/headless/describe.js.map +1 -0
  27. package/dist/headless/draw.d.ts +17 -0
  28. package/dist/headless/draw.d.ts.map +1 -0
  29. package/dist/headless/draw.js +25 -0
  30. package/dist/headless/draw.js.map +1 -0
  31. package/dist/headless/index.d.ts +99 -0
  32. package/dist/headless/index.d.ts.map +1 -0
  33. package/dist/headless/index.js +143 -0
  34. package/dist/headless/index.js.map +1 -0
  35. package/dist/headless/judge.d.ts +16 -0
  36. package/dist/headless/judge.d.ts.map +1 -0
  37. package/dist/headless/judge.js +52 -0
  38. package/dist/headless/judge.js.map +1 -0
  39. package/dist/headless/node.d.ts +8 -0
  40. package/dist/headless/node.d.ts.map +1 -0
  41. package/dist/headless/node.js +80 -0
  42. package/dist/headless/node.js.map +1 -0
  43. package/dist/headless/protocol.d.ts +75 -0
  44. package/dist/headless/protocol.d.ts.map +1 -0
  45. package/dist/headless/protocol.js +14 -0
  46. package/dist/headless/protocol.js.map +1 -0
  47. package/dist/headless/runtime.d.ts +2 -0
  48. package/dist/headless/runtime.d.ts.map +1 -0
  49. package/dist/headless/runtime.generated.d.ts +2 -0
  50. package/dist/headless/runtime.generated.d.ts.map +1 -0
  51. package/dist/headless/runtime.generated.js +8 -0
  52. package/dist/headless/runtime.generated.js.map +1 -0
  53. package/dist/headless/runtime.js +171 -0
  54. package/dist/headless/runtime.js.map +1 -0
  55. package/dist/headless/tree.d.ts +54 -0
  56. package/dist/headless/tree.d.ts.map +1 -0
  57. package/dist/headless/tree.js +128 -0
  58. package/dist/headless/tree.js.map +1 -0
  59. package/dist/host/css.d.ts +118 -0
  60. package/dist/host/css.d.ts.map +1 -0
  61. package/dist/host/css.js +963 -0
  62. package/dist/host/css.js.map +1 -0
  63. package/dist/host/draw-budget.d.ts +10 -0
  64. package/dist/host/draw-budget.d.ts.map +1 -0
  65. package/dist/host/draw-budget.js +29 -0
  66. package/dist/host/draw-budget.js.map +1 -0
  67. package/dist/host/frame.d.ts +19 -1
  68. package/dist/host/frame.d.ts.map +1 -1
  69. package/dist/host/frame.js +21 -2
  70. package/dist/host/frame.js.map +1 -1
  71. package/dist/host/index.d.ts +4 -3
  72. package/dist/host/index.d.ts.map +1 -1
  73. package/dist/host/index.js +7 -1
  74. package/dist/host/index.js.map +1 -1
  75. package/dist/host/kit.d.ts +6 -2
  76. package/dist/host/kit.d.ts.map +1 -1
  77. package/dist/host/kit.js +12 -5
  78. package/dist/host/kit.js.map +1 -1
  79. package/dist/host/links.d.ts +24 -0
  80. package/dist/host/links.d.ts.map +1 -0
  81. package/dist/host/links.js +35 -0
  82. package/dist/host/links.js.map +1 -0
  83. package/dist/host/manifest.d.ts +50 -0
  84. package/dist/host/manifest.d.ts.map +1 -0
  85. package/dist/host/manifest.js +103 -0
  86. package/dist/host/manifest.js.map +1 -0
  87. package/dist/host/open-draw.d.ts +44 -0
  88. package/dist/host/open-draw.d.ts.map +1 -0
  89. package/dist/host/open-draw.js +108 -0
  90. package/dist/host/open-draw.js.map +1 -0
  91. package/dist/host/open-judge.d.ts +53 -0
  92. package/dist/host/open-judge.d.ts.map +1 -0
  93. package/dist/host/open-judge.js +95 -0
  94. package/dist/host/open-judge.js.map +1 -0
  95. package/dist/host/open-render.d.ts +32 -0
  96. package/dist/host/open-render.d.ts.map +1 -0
  97. package/dist/host/open-render.js +262 -0
  98. package/dist/host/open-render.js.map +1 -0
  99. package/dist/host/press.d.ts +15 -0
  100. package/dist/host/press.d.ts.map +1 -0
  101. package/dist/host/press.js +156 -0
  102. package/dist/host/press.js.map +1 -0
  103. package/dist/host/react.d.ts +15 -2
  104. package/dist/host/react.d.ts.map +1 -1
  105. package/dist/host/react.js +13 -5
  106. package/dist/host/react.js.map +1 -1
  107. package/dist/host/session.d.ts +94 -1
  108. package/dist/host/session.d.ts.map +1 -1
  109. package/dist/host/session.js +103 -14
  110. package/dist/host/session.js.map +1 -1
  111. package/dist/host/theme.d.ts +14 -0
  112. package/dist/host/theme.d.ts.map +1 -0
  113. package/dist/host/theme.js +51 -0
  114. package/dist/host/theme.js.map +1 -0
  115. package/dist/host/view-runtime.generated.d.ts +2 -0
  116. package/dist/host/view-runtime.generated.d.ts.map +1 -0
  117. package/dist/host/view-runtime.generated.js +7 -0
  118. package/dist/host/view-runtime.generated.js.map +1 -0
  119. package/dist/host/view-source.d.ts +10 -0
  120. package/dist/host/view-source.d.ts.map +1 -0
  121. package/dist/host/view-source.js +44 -0
  122. package/dist/host/view-source.js.map +1 -0
  123. package/dist/host/view.d.ts +138 -0
  124. package/dist/host/view.d.ts.map +1 -0
  125. package/dist/host/view.js +381 -0
  126. package/dist/host/view.js.map +1 -0
  127. package/dist/host/views.d.ts +10 -0
  128. package/dist/host/views.d.ts.map +1 -0
  129. package/dist/host/views.js +15 -0
  130. package/dist/host/views.js.map +1 -0
  131. package/dist/host/worker-react.d.ts +57 -0
  132. package/dist/host/worker-react.d.ts.map +1 -0
  133. package/dist/host/worker-react.js +129 -0
  134. package/dist/host/worker-react.js.map +1 -0
  135. package/dist/host/worker-start.d.ts +66 -0
  136. package/dist/host/worker-start.d.ts.map +1 -0
  137. package/dist/host/worker-start.js +188 -0
  138. package/dist/host/worker-start.js.map +1 -0
  139. package/dist/host/worker.d.ts +28 -19
  140. package/dist/host/worker.d.ts.map +1 -1
  141. package/dist/host/worker.js +60 -119
  142. package/dist/host/worker.js.map +1 -1
  143. package/dist/host/writes.d.ts +49 -0
  144. package/dist/host/writes.d.ts.map +1 -0
  145. package/dist/host/writes.js +76 -0
  146. package/dist/host/writes.js.map +1 -0
  147. package/dist/index.d.ts +1 -1
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/open-kit.d.ts +148 -0
  150. package/dist/open-kit.d.ts.map +1 -0
  151. package/dist/open-kit.js +321 -0
  152. package/dist/open-kit.js.map +1 -0
  153. package/dist/protocol.d.ts +109 -3
  154. package/dist/protocol.d.ts.map +1 -1
  155. package/dist/protocol.js +13 -0
  156. package/dist/protocol.js.map +1 -1
  157. package/dist/worker/harden.d.ts +13 -2
  158. package/dist/worker/harden.d.ts.map +1 -1
  159. package/dist/worker/harden.js +10 -4
  160. package/dist/worker/harden.js.map +1 -1
  161. package/dist/worker/natives.d.ts +1 -0
  162. package/dist/worker/natives.d.ts.map +1 -1
  163. package/dist/worker/natives.js +4 -0
  164. package/dist/worker/natives.js.map +1 -1
  165. package/dist/worker/view-global.d.ts +70 -0
  166. package/dist/worker/view-global.d.ts.map +1 -0
  167. package/dist/worker/view-global.js +264 -0
  168. package/dist/worker/view-global.js.map +1 -0
  169. package/dist/worker/view.d.ts +14 -0
  170. package/dist/worker/view.d.ts.map +1 -0
  171. package/dist/worker/view.js +64 -0
  172. package/dist/worker/view.js.map +1 -0
  173. package/package.json +30 -4
package/README.md CHANGED
@@ -57,7 +57,67 @@ entries import nothing of the framework, so a guest bundle carries none of it.
57
57
  `GuestProps` is the plain-data half of `ViewProps` — `node`, `nodes`, the
58
58
  `edges` among them, `label`, `fidelity`, `cardinality`, `mode`, `selected`,
59
59
  `implicated`, `flagged` — and `acts`, the acts the viewer may run. A record
60
- the viewer may not see is in none of them.
60
+ the viewer may not see is in none of them. Every record's `label` is
61
+ filled as the host labels it, and `theme` and `places` are the app's.
62
+
63
+ ### What a frame guest reads, its look, and its place
64
+
65
+ ```ts
66
+ views.register("package", { cardinality: "many", fidelity: "full" },
67
+ guestView({ url, name: "prices", title: "The price sheet", reads: { kinds: ["offer"], edges: ["includes"] } }),
68
+ { title: "The price sheet" });
69
+ views.home(guestView({ url: frontUrl, name: "front", reads: { kinds: ["package"] } }));
70
+ ```
71
+
72
+ A guest is handed what it is drawn over and the edges among those records.
73
+ With `reads` it is also handed every record of the kinds it reads and
74
+ every edge of the edges it reads between the records it holds, as the
75
+ viewer sees them (`readAcross`, the rule a worker view's manifest uses
76
+ too). A guest over packages that reads `offer` and `includes` gets each
77
+ package's offers, and an offer the viewer may not see is in none of it.
78
+ Drawn as the home (`views.home`), a guest is drawn over nothing and sees
79
+ what it reads: it is the routed home's body, and the landing over the scene.
80
+
81
+ Its props carry `theme`, a `GuestTheme`: the scheme, the accent, ground,
82
+ panel, ink, muted ink and edge colours, and the body and mono fonts, read
83
+ off the element the frame is drawn in. The scheme is the app's own (the
84
+ embed's `data-graview-scheme`), not the system's, and the host pushes
85
+ again when the app's toggle changes it. `mountGuestView` takes `reads`,
86
+ `theme` and `places` too.
87
+
88
+ `title` names the frame for assistive technology. Registered with the same
89
+ title, the guest is a place on both faces: listed by `placesOf`, at
90
+ `/places/the-price-sheet` on the routed face and `#view=the-price-sheet` in
91
+ the scene. `props.places` lists the app's places, and
92
+ `guest.navigate({ place: "the-packages" })` goes to one.
93
+
94
+ ### One client, served or inlined
95
+
96
+ `@graview/guest/client.js` is the frame guest's client as one prebuilt
97
+ classic script (2.4 kB). It leaves one global, `GraviewGuest`, and
98
+ `GraviewGuest.connect()` is `connectGuest()`. A host serves it at a path of
99
+ its own, or inlines its text where a frame's policy allows inline script
100
+ alone, as Graview Cloud serves an uploaded view (`script-src
101
+ 'unsafe-inline'`). `GUEST_CLIENT` from `@graview/guest/client` is that
102
+ text, and `GUEST_CLIENT_SHA256` its hash for a policy that names it.
103
+
104
+ ```html
105
+ <main id="app"></main>
106
+ <script>/* GUEST_CLIENT */</script>
107
+ <script>
108
+ const guest = GraviewGuest.connect();
109
+ guest.subscribe((props) => {
110
+ document.body.style.background = props.theme.panel;
111
+ app.replaceChildren(...props.nodes.map((node) => Object.assign(document.createElement("p"), { textContent: node.label })));
112
+ guest.size(document.documentElement.scrollHeight);
113
+ });
114
+ </script>
115
+ ```
116
+
117
+ How to write one, with a worked example, is the `graview-embed` skill.
118
+ `guest-sandbox --transport=client` serves a guest of a few lines under that
119
+ policy and finds it renders, acts, navigates, resizes and follows the
120
+ app's toggle in Chromium, WebKit and Firefox.
61
121
 
62
122
  ## In a worker
63
123
 
@@ -69,7 +129,7 @@ starts from a `blob:` URL, and draws in the host's page from a component kit.
69
129
  import { mountGuestWorker } from "@graview/guest/host/worker";
70
130
 
71
131
  const guest = mountGuestWorker(element, { worker: { script }, view: "recipe-card", store, principal,
72
- onFailure: (reason) => showTheTierOneCard(reason) }); // refused, silent, or budget
132
+ onFailure: (reason, detail) => showTheTierOneCard(reason) }); // start, silent, slow or budget
73
133
 
74
134
  views.register("recipe", { fidelity: "full", cardinality: "one" },
75
135
  guestView({ worker: { script }, name: "recipe-card" }));
@@ -84,7 +144,13 @@ limits. A second ready from the same worker is dropped. Once it is ready,
84
144
  the host sends a heartbeat over the port and the worker's runtime answers
85
145
  it; a worker that goes `limits.silentMs` (5 000 by default) without an
86
146
  answer — a guest spinning in `while (true)` — is terminated, and
87
- the host is told `silent`. A guest that is busy but yields is kept. What the guest draws
147
+ the host is told `silent`. A worker that never says ready — the page
148
+ refused it, it failed before its first line ran, or it was not ready in
149
+ `limits.readyMs` — is `start` (see "What the host page allows"). A guest that is busy but yields is kept. The
150
+ host also counts its own time drawing what the guest sends. Over any one
151
+ second it spends at most `limits.drawMs` (100 by default). Past it, the
152
+ rest of the batch is left undrawn, the worker is terminated, and the host
153
+ is told `slow`. What the guest draws
88
154
  comes over the port as Remote DOM mutation records, and the host draws only
89
155
  the kit (`GUEST_KIT`), with `createKitRenderer`. Both are
90
156
  `@graview/guest/host/worker`, apart from the frame's host, so a page that
@@ -144,3 +210,287 @@ runs guests it did not build checks them, or better, builds them itself.
144
210
 
145
211
  The worker entry carries Remote DOM (`@remote-dom/core` and its polyfill,
146
212
  MIT, pinned); the frame guest and the host do not.
213
+
214
+ ## A worker view on the open kit
215
+
216
+ A view that needs more than the kit's components — a card grid, a chart,
217
+ an animated ring — draws plain HTML, SVG and one stylesheet instead. What
218
+ keeps it safe is what it can reach, not what it can draw: it runs in the
219
+ same hardened classic worker, and the host draws what it says into a
220
+ shadow root inside a region of the host's own — `contain: layout paint
221
+ style`, `isolation: isolate`, `overflow: clip` — keeping only what the open
222
+ kit allows. The view is one plain script with no imports and no build;
223
+ the host puts the view's runtime in front of it.
224
+
225
+ ```ts
226
+ import { mountWorkerView } from "@graview/guest/host/worker";
227
+
228
+ const view = mountWorkerView(element, { manifest, worker: { source }, store, principal,
229
+ onFailure: (reason, detail) => showTheTierOneFace(reason, detail) });
230
+ ```
231
+
232
+ In the worker, the view has one global, `graview`:
233
+
234
+ ```js
235
+ graview.style(`.grid { display: grid; gap: 12px } .card { background: var(--graview-panel) }`);
236
+ graview.onProps((props) => graview.render(graview.html`
237
+ <section class="grid">${props.nodes.map((n) => graview.html`<article class="card"><h3>${n.label}</h3></article>`)}</section>`));
238
+ graview.on("click", ".card", (event) => { /* … */ });
239
+ ```
240
+
241
+ What may be drawn is one declaration, read by both sides: most of HTML's
242
+ sectioning, text, lists, tables, `details`, buttons, fields and `img`;
243
+ SVG's shapes, paths, text, gradients, clip paths, masks, markers and `use`
244
+ of `#id`; and CSS for layout, grid, flex, colour, type, transitions,
245
+ keyframes, media and container queries, with the app's theme tokens
246
+ (`--graview-*`) inherited, light or dark as the app is. The stylesheet,
247
+ every `style` attribute and every SVG paint are read with the CSS Syntax
248
+ tokenizer and parser — escapes decoded, comments gone — and written afresh
249
+ from what was kept: `url()` only as `url(#id)` on a paint, no `@import`,
250
+ `@font-face` or other at-rule but `@media`, `@supports`, `@container` and
251
+ `@keyframes`, only the functions on the list (no `image-set()`, `attr()`,
252
+ `cross-fade()`, `element()` …), `position` only static, relative or
253
+ absolute, and no selector that reaches out of the shadow tree (`:host`,
254
+ `::slotted`). An image is a `data:` image or a `blob:` of the page's own;
255
+ an SVG image in an `img` runs no script and loads nothing. No `<script>`,
256
+ `<iframe>`, `<object>`, `<embed>`, `<link>`, `<meta>`, `<base>`, `<style>`,
257
+ `<form>`, SVG `<image>` or `<foreignObject>`, no `src`, `href`, `srcset`,
258
+ `formaction` or `on*` attribute is drawn; what is not drawn is in
259
+ `refused`, with why. A view never speaks as the app's chrome. `<nav>`,
260
+ `<header>`, `<footer>`, `<aside>` and `<search>` are drawn as `<div>`, and
261
+ `<output>` as `<span>`. Each holds what it held and is marked
262
+ `data-graview-as`, and the view's selectors for those names are read as
263
+ that attribute. A `<section>` is never named, and `role` takes no landmark
264
+ or notice's role. `guest-sandbox --transport=open` serves a page with no
265
+ content security policy, tries every way out, and finds no request leaving
266
+ it in Chromium, WebKit or Firefox.
267
+
268
+ ### A worker view is a place
269
+
270
+ A worker view says what it is and what it may touch in a manifest the host
271
+ enforces:
272
+
273
+ ```ts
274
+ import { registerWorkerView, workerHome } from "@graview/guest/host/views";
275
+
276
+ const packages = {
277
+ manifest: { name: "packages", title: "The packages", attach: "package", cardinality: "many",
278
+ reads: { kinds: ["offer"], edges: ["includes"] }, acts: ["set-standing"] },
279
+ worker: { source },
280
+ author: "Made by Claude for Nick",
281
+ };
282
+ views: (schema, registry) => registerWorkerView(registry, packages), // the embed's views
283
+ pages.surface("home", workerHome(frontPage)); // a view of the home
284
+ ```
285
+
286
+ It is handed the viewer's sight and nothing more, cut to the kind it
287
+ attaches to (the members the face hands it, or every one the viewer sees)
288
+ and the kinds and edges it reads: a record the viewer may not see is in
289
+ none of it, and a kind it did not ask to read is not handed to it however
290
+ visible. Every record's `label` is filled as the host labels it — for a
291
+ frame guest too. A titled view is a named place on the Graview face and
292
+ the pages face, by its title; whatever the registry drew for that kind
293
+ before is drawn if the view fails. With `attach: "home"`,
294
+ `registerWorkerView` makes it the home's own view (FR-81). That is the
295
+ routed home's body and the landing over the scene when it is at home, in
296
+ place of the home the app declared, which is drawn if the view fails.
297
+ `workerHome` makes it the routed face's whole home surface instead. Its props carry the app's look as a
298
+ `GuestTheme` — the scheme, the accent, ground, panel, ink, muted ink and
299
+ edge colours, and the body and mono fonts — read off the region it is
300
+ drawn in, and the host
301
+ pushes again when the app's own toggle changes the scheme, whatever the
302
+ system prefers. `checkManifest` says what in a manifest names a kind, an
303
+ edge or an act the app does not declare, and the host refuses to start
304
+ such a view (`onFailure` hears `manifest`).
305
+
306
+ ### Writes that cannot leak
307
+
308
+ A view runs for every member with that member's sight, and its author is
309
+ not the member, so the danger is a view reading what this viewer may see
310
+ and writing it where somebody else may. An act must be named in the
311
+ manifest. Where the app's sight is total — no sight is declared, or every
312
+ kind is seen whole by everybody (`sightIsTotal`) — an act the view asks for
313
+ from its code applies with its arguments as given. Otherwise it applies
314
+ only from a press the host itself saw:
315
+
316
+ ```html
317
+ <fieldset>
318
+ <input name="summary" placeholder="What it is">
319
+ <button data-act="set-summary" data-record="package:start">Say it</button>
320
+ </fieldset>
321
+ ```
322
+
323
+ A trusted click on an element with `data-act` is judged and applied in the
324
+ click's own handler, before the view hears of it (it hears `pressed`). Its
325
+ arguments come only from the record the element is bound to (`data-record`,
326
+ one the view was shown), the manifest's constants for the act (`{ act,
327
+ as, constants }`), and the fields in the press's `fieldset` the host read
328
+ itself — each one the viewer's: its last change a trusted `input`, and
329
+ nothing the view wrote in it since. A field the view filled is the view's
330
+ until the viewer empties it; a `change` a browser raises when such a field
331
+ loses focus is not typing; a view that says back what a field shows, or
332
+ empties it, takes nothing away. Either way an act is applied as the viewer,
333
+ `via: "view:<name>"`, within the view's allowance, and undoable.
334
+
335
+ ### Links stay in the app
336
+
337
+ A worker view links to a record or a named place of this app, and nowhere
338
+ else. The open kit draws no `href`, so `<a href="https://…">` is text;
339
+ `<a data-record="offer:coaching">` and `<a data-place="the-packages">` are
340
+ made links by the host — focusable, a link to assistive technology — and
341
+ followed by it on a press or Enter, to a record the viewer may see or a
342
+ place the app has. `graview.navigate("offer:coaching")` and
343
+ `graview.navigate({ place: "the-packages" })` are held to the same. The
344
+ props list the app's places (`places`, each with its slug and title). On
345
+ the Graview face a record is focused and chosen and a place is drawn; on
346
+ the pages face each goes to its own address — through `useGoTo` in
347
+ `@graview/react`, which the routed face provides. The kit's `gv-link`
348
+ keeps `links.origins`: it is the kit's one deliberate way out, to the
349
+ origins a host lists, and an open-kit view has none.
350
+
351
+ ### What the host page allows
352
+
353
+ A worker guest, on the kit or the open kit, starts from a `blob:` URL the
354
+ host makes of its script. The page's Content-Security-Policy has to allow
355
+ that, and an open-kit view's stylesheet:
356
+
357
+ ```
358
+ worker-src blob:; style-src 'unsafe-inline'
359
+ ```
360
+
361
+ With no `worker-src`, the browser reads `script-src` instead (and
362
+ `default-src` with neither), so a page that says `script-src 'self'` and
363
+ no `worker-src` refuses every view. Nothing else is needed for the worker:
364
+ it runs none of the page's scripts and has no network to allow. An
365
+ open-kit view's stylesheet is a `<style>` in its region's shadow root, and
366
+ the kit's CSS one in the page's head, hence `style-src 'unsafe-inline'`.
367
+ An image a view draws is a `data:` image or a `blob:` of the page's own,
368
+ so `img-src data: blob:` if views draw images.
369
+
370
+ A page that refuses the worker is told so. Chromium and WebKit throw from
371
+ `new Worker` and Firefox fires `error` on it. Either way `onFailure` hears
372
+ `start` once for each view, with a sentence naming the directive (`it needs
373
+ worker-src blob:`). The plain face is drawn in the view's place, and the
374
+ page's console is told once however many views it refuses. `start` is also
375
+ a worker that failed before it said ready, or was not ready in
376
+ `limits.readyMs` (5 000 by default). Each runtime says ready before a line
377
+ of the view runs, so a worker with no ready never started. `silent` is a
378
+ worker that said ready and then stopped answering. `registerWorkerView`
379
+ takes `onFailure` too, for a host that reports it.
380
+
381
+ A host that will not allow `blob:` serves each view's whole script from
382
+ its own origin under `worker-src 'self'`, and passes `worker: { url }`:
383
+
384
+ ```ts
385
+ import { checkViewSource, viewScript } from "@graview/guest/host/views";
386
+
387
+ // On the server: the runtime, then the view, as the host would have made it.
388
+ if (checkViewSource(source).length === 0) serve(`/views/${name}.js`, await viewScript(source));
389
+ // On the page:
390
+ mountWorkerView(element, { manifest, worker: { url: `/views/${name}.js` }, store, principal });
391
+ ```
392
+
393
+ The server checks the source then, since the page never holds its text,
394
+ and `maxSourceBytes` is the server's to keep. A kit guest takes
395
+ `worker: { url }` the same way. `guest-sandbox --transport=limits` serves
396
+ all three pages in Chromium, WebKit and Firefox: the policy above draws, a
397
+ page without it reports `start` once a view, and the served script draws
398
+ under `worker-src 'self'`.
399
+
400
+ ### Limits, and what is drawn in a view's place
401
+
402
+ The host caps a view's code (`maxSourceBytes`, 256 000 by default), the
403
+ nodes it draws (`maxNodes`, 5 000), the messages it sends (`messages` in
404
+ `messageWindowMs`, 120 a second) and the time it takes over each push of
405
+ what it is shown (`pushMs`, 1 000 ms: the view's listeners as its runtime
406
+ times them, and the wait for the runtime to say it drew, as the host times
407
+ it), beside the heartbeat's `silentMs`, and the page's own time drawing
408
+ what the view sends (`drawMs`, 100 ms of any second). Past any of them the worker is
409
+ terminated, the plain face of what the view was shown — its title and each
410
+ record by its label, drawn by the host — is drawn in the region, and
411
+ `onFailure` hears why: `source`, `nodes`, `flood`, `slow`, `silent`,
412
+ `error` (it threw before it drew), `start` (it never started) or
413
+ `manifest`, with a sentence saying it, once. A host draws its own in its place with `fallback`; the React
414
+ registrations draw whatever the registry drew for the kind before.
415
+
416
+ What is left: work a view schedules with timers between pushes is not
417
+ timed per push. A view that busies its own worker for just under
418
+ `silentMs`, answers the heartbeat, and does it again can hold a core of the
419
+ reader's machine for as long as it is shown. That is the worker's thread,
420
+ not the page's; the page stays responsive.
421
+
422
+ ### A view with no build
423
+
424
+ A view is handed over as its plain source, `{ source }`: one script
425
+ against the `graview` global, with no imports, no bundler and no copy of
426
+ the protocol. The host puts the view's runtime in front of it — Remote
427
+ DOM's polyfill, the hardening, the channel and the global, which the host
428
+ holds as one classic script and fetches only when it first starts a view —
429
+ and runs both as one strict classic worker. A module worker is not an
430
+ option: a `blob:` one is refused in an opaque origin. The hardened worker
431
+ has no `eval`, no function constructor and no `importScripts`, so the one
432
+ way left to load code is `import()`, which is syntax: a source whose text
433
+ says `import` anywhere, even in a string or a comment, is refused before it
434
+ runs (`checkViewSource` says why), and so is one that exports. `{ script }`
435
+ still takes a whole worker script built against `@graview/guest/worker/view`.
436
+ How to write one — the manifest, what may be drawn, the theme's tokens, the
437
+ write rules, links and limits, with a list lens and a home worked through —
438
+ is the `graview-worker-view` skill (`graview skills install`).
439
+
440
+ ### Run a view headless, and say what it drew
441
+
442
+ Before a view is applied, a host can run it once with no network and no
443
+ DOM, against one member's sight, and be told what it drew in the words
444
+ `describePlace` says a place in (`@graview/core/describe`): its headings,
445
+ text, figures and fields, and its lists with each record's title and what
446
+ its row or card says. Or it is told why the view will not do.
447
+
448
+ ```ts
449
+ import { runWorkerViewHeadless } from "@graview/guest/headless";
450
+
451
+ const result = await runWorkerViewHeadless({ manifest, source, store, principal, run });
452
+ if (result.ok) say(result.description.text); // "The packages (/places/the-packages) — as partner …"
453
+ else say(result.reason, result.detail); // "act": It asks for the act "buy", which its manifest does not name.
454
+ ```
455
+
456
+ The reasons are the page's (`source`, `manifest`, `error`, `nodes`,
457
+ `flood`, `slow`, `refused`) and two of a headless run's own: `act`, an act
458
+ asked for from the view's code or bound to a press (`data-act`) that its
459
+ manifest does not name, and `isolate`, the host's isolate could not run it.
460
+ Nothing is applied: an act the view asks for is written down in the
461
+ transcript and answered with a refusal.
462
+
463
+ A view never runs in the host's own context. The host supplies the
464
+ isolate: `run` is handed one script and one JSON string (`HeadlessPayload`),
465
+ loads the script into an isolate of its choosing, calls the global it
466
+ leaves (`graviewHeadless`) with the string, and hands back the string it
467
+ resolves with. Nothing but text crosses. There is no default, and without
468
+ a `run` the helper throws. The script is the headless runtime, then the
469
+ view. It makes the isolate a worker's before the view is read: the same
470
+ `graview` global over a transcript, a console that writes to it, timers
471
+ that never fire, and everything outside the worker's allowlist taken from
472
+ the global. Then the view's top line runs and it is pushed what it is
473
+ shown, once. What it sent is judged again in the host's context, from the
474
+ transcript alone, by the open kit's own renderer drawing into a tree of
475
+ plain objects (`drawTranscript`, `describeDrawing`), so the isolate's word
476
+ is not taken for what the view drew.
477
+
478
+ `nodeIsolate` from `@graview/guest/headless/node` is a `run` for Node: a
479
+ worker thread with a heap ceiling and a context made from nothing (no
480
+ `process`, `require`, `fetch` or timers; no code from strings), with a
481
+ deadline that covers the microtasks the view queues. In workerd, the
482
+ script is one module of a worker of its own with no outbound network, and
483
+ the host's module, loaded first, keeps `Response` to answer with:
484
+
485
+ ```js
486
+ // before.js
487
+ const Made = Response; export const answer = (text) => new Made(text);
488
+ // host.js
489
+ import { answer } from "./before.js"; import "./view.js"; // view.js is payload.script
490
+ const run = globalThis.graviewHeadless;
491
+ export default { async fetch(request) { return answer(await run(await request.text())); } };
492
+ ```
493
+
494
+ `graview view check view.js --app app.js --manifest manifest.json --seed
495
+ seed.json --roles partner` does the same from a terminal, with
496
+ `nodeIsolate`.
package/client.js ADDED
@@ -0,0 +1,2 @@
1
+ /*! @graview/guest/client.js — a frame guest's client (GraviewGuest.connect). Generated from src/client-script.ts. Elastic License 2.0. */
2
+ "use strict";var GraviewGuest=(()=>{var f=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var H=Object.prototype.hasOwnProperty;var k=(o,t)=>{for(var r in t)f(o,r,{get:t[r],enumerable:!0})},M=(o,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of O(t))!H.call(o,a)&&a!==r&&f(o,a,{get:()=>t[a],enumerable:!(i=R(t,a))||i.enumerable});return o};var P=o=>M(f({},"__esModule",{value:!0}),o);var T={};k(T,{connect:()=>w,protocol:()=>y});var y=1;function G(o){let t=o;return typeof o=="object"&&o!==null&&t.graview==="host-hello"&&typeof t.nonce=="string"}function b(o,t={}){let r,i="",a,h=0,u=new Set,g=new Map,m=[],d=n=>{r?r.postMessage({...n,nonce:i}):m.push(n)},x=n=>{let e=n.data;if(!(!e||typeof e!="object")){if(e.type==="props"){a=e.props;for(let s of u)s(e.props)}else e.type==="answer"?(g.get(e.id)?.(e),g.delete(e.id)):e.type==="event"&&typeof e.listener=="number"?t.onEvent?.(e):e.type==="heartbeat"&&typeof e.beat=="number"&&d({type:"heartbeat",beat:e.beat});t.onMessage?.(e)}},p=()=>{},E=n=>{if(r||!o.fromHost(n)||!G(n.data)||n.data.protocol!==1)return;let e=n.ports[0];if(e){r=e,i=n.data.nonce,r.onmessage=x,r.start?.(),p();for(let s of m.splice(0))d(s)}};p=o.listen(E),o.ready({graview:"guest-ready",protocol:1});let c,v={get props(){return a},subscribe(n){return u.add(n),()=>u.delete(n)},act(n,e={}){let s=h+=1;return new Promise(l=>{g.set(s,l),d({type:"act",id:s,name:n,args:e})})},navigate(n){typeof n=="string"?d({type:"navigate",to:n}):n&&typeof n.place=="string"&&d({type:"navigate",place:n.place})},size(n){d({type:"size",height:n})},autoSize(n){let e=n??globalThis.document?.documentElement,s=globalThis.ResizeObserver;if(!e||!s||typeof e.getBoundingClientRect!="function")return()=>{};c?.disconnect();let l=new s(()=>v.size(Math.ceil(e.getBoundingClientRect().height)));return l.observe(e),c=l,()=>l.disconnect()},close(){c?.disconnect(),p(),r?.close(),u.clear()}};return{guest:v,send:d}}function w(o={}){let t=o.window??globalThis;return b({listen(r){return t.addEventListener("message",r),()=>t.removeEventListener("message",r)},fromHost:r=>r.source===t.parent&&(o.hostOrigin===void 0||r.origin===o.hostOrigin),ready:r=>t.parent?.postMessage(r,"*")}).guest}return P(T);})();
package/dist/channel.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { type GuestAnswer, type GuestEvent, type GuestProps, type GuestRequest } from "./protocol.js";
1
+ import { type GuestAnswer, type GuestEvent, type GuestProps, type GuestRequest, type HostMessage } from "./protocol.js";
2
2
  /**
3
3
  * A GUEST'S ONE CHANNEL to the host that started it. It can read what the
4
4
  * host pushed and ask; it cannot reach the store, and an act it asks for
@@ -11,8 +11,14 @@ export interface Guest {
11
11
  subscribe(listener: (props: GuestProps) => void): () => void;
12
12
  /** Ask for an act by name. Resolves with the host's answer; never rejects for a refusal. */
13
13
  act(name: string, args?: Readonly<Record<string, unknown>>): Promise<GuestAnswer>;
14
- /** Ask the host to go to a record. A record the viewer may not see goes nowhere. */
15
- navigate(to: string): void;
14
+ /**
15
+ * Ask the host to go to a record, by its id, or to one of the app's named
16
+ * places (`{ place: slug }`, one `props.places` lists). A record the viewer
17
+ * may not see, and a place the app does not have, go nowhere.
18
+ */
19
+ navigate(to: string | {
20
+ readonly place: string;
21
+ }): void;
16
22
  /** Ask for a height, in CSS pixels. */
17
23
  size(height: number): void;
18
24
  /** Ask for the height of an element whenever it changes. Returns the stop. In a worker, where nothing is laid out, it does nothing. */
@@ -44,6 +50,8 @@ export interface GuestLink {
44
50
  */
45
51
  export declare function openGuest(link: GuestLink, hooks?: {
46
52
  readonly onEvent?: (event: GuestEvent) => void;
53
+ /** Every message from the host, once the channel's own handling of it is done: a runtime's way to hear what is its own (FR-90). */
54
+ readonly onMessage?: (message: HostMessage) => void;
47
55
  }): {
48
56
  readonly guest: Guest;
49
57
  send(request: Unsent): void;
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EAElB,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;IACvC,uDAAuD;IACvD,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC7D,4FAA4F;IAC5F,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClF,oFAAoF;IACpF,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uCAAuC;IACvC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uIAAuI;IACvI,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,IAAI,CAAC;IACxC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,+CAA+C;AAC/C,MAAM,MAAM,MAAM,GAAG,YAAY,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,YAAY,GAAG,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;AAEhH;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,wEAAwE;IACxE,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACzD,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;IACvC,iBAAiB;IACjB,KAAK,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACtF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,GAAE;IAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAA;CAAO,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAwFjK"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,oEAAoE;IACpE,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,CAAC;IACvC,uDAAuD;IACvD,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC7D,4FAA4F;IAC5F,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClF;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACxD,uCAAuC;IACvC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,uIAAuI;IACvI,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,IAAI,CAAC;IACxC,KAAK,IAAI,IAAI,CAAC;CACf;AAED,+CAA+C;AAC/C,MAAM,MAAM,MAAM,GAAG,YAAY,SAAS,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,YAAY,GAAG,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;AAEhH;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,wEAAwE;IACxE,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACzD,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC;IACvC,iBAAiB;IACjB,KAAK,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACtF;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,SAAS,EACf,KAAK,GAAE;IACL,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IAC/C,mIAAmI;IACnI,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;CAChD,GACL;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CA0FxD"}
package/dist/channel.js CHANGED
@@ -38,6 +38,7 @@ export function openGuest(link, hooks = {}) {
38
38
  /* The runtime answers, so only a blocked event loop goes quiet. */
39
39
  send({ type: "heartbeat", beat: message.beat });
40
40
  }
41
+ hooks.onMessage?.(message);
41
42
  };
42
43
  let stop = () => { };
43
44
  const hello = (event) => {
@@ -77,7 +78,10 @@ export function openGuest(link, hooks = {}) {
77
78
  });
78
79
  },
79
80
  navigate(to) {
80
- send({ type: "navigate", to });
81
+ if (typeof to === "string")
82
+ send({ type: "navigate", to });
83
+ else if (to && typeof to.place === "string")
84
+ send({ type: "navigate", place: to.place });
81
85
  },
82
86
  size(height) {
83
87
  send({ type: "size", height });
@@ -1 +1 @@
1
- {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel.js","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `graview view check` — run a worker view once, headless, and say what it
3
+ * drew (FR-95).
4
+ *
5
+ * The view's source, its manifest, the app it is for and, given one, a seed
6
+ * to run it over, seated as one member: it runs in a worker thread's fresh
7
+ * context with no network (`@graview/guest/headless/node`) and the command
8
+ * prints what it drew in the words `graview describe` says a place in, or
9
+ * why it will not do. Exit 0 when it drew, 1 when it will not do.
10
+ *
11
+ * Reached through the `graview` command line, which dispatches here; this
12
+ * package ships no bin of its own.
13
+ */
14
+ export declare const VIEW_USAGE = " graview view check <view.js> --app <app> --manifest <manifest.json>\n [--seed <file>] [--as <id>] [--roles a,b] [--width <px>] [--json]\n run a worker view once, headless, with no network, seated as one\n member (the system, unless --as or --roles say who), and say what it\n drew, or why it will not do\n";
15
+ export declare function view(argv: readonly string[]): Promise<number>;
16
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,UAAU,2VAKtB,CAAC;AASF,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA2CnE"}
package/dist/cli.js ADDED
@@ -0,0 +1,75 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+ import { Store } from "@graview/core";
4
+ import { loadApp } from "@graview/core/cli";
5
+ import { runWorkerViewHeadless } from "./headless/index.js";
6
+ import { nodeIsolate } from "./headless/node.js";
7
+ /**
8
+ * `graview view check` — run a worker view once, headless, and say what it
9
+ * drew (FR-95).
10
+ *
11
+ * The view's source, its manifest, the app it is for and, given one, a seed
12
+ * to run it over, seated as one member: it runs in a worker thread's fresh
13
+ * context with no network (`@graview/guest/headless/node`) and the command
14
+ * prints what it drew in the words `graview describe` says a place in, or
15
+ * why it will not do. Exit 0 when it drew, 1 when it will not do.
16
+ *
17
+ * Reached through the `graview` command line, which dispatches here; this
18
+ * package ships no bin of its own.
19
+ */
20
+ export const VIEW_USAGE = ` graview view check <view.js> --app <app> --manifest <manifest.json>
21
+ [--seed <file>] [--as <id>] [--roles a,b] [--width <px>] [--json]
22
+ run a worker view once, headless, with no network, seated as one
23
+ member (the system, unless --as or --roles say who), and say what it
24
+ drew, or why it will not do
25
+ `;
26
+ function flag(argv, name) {
27
+ const at = argv.indexOf(name);
28
+ return at === -1 ? undefined : argv[at + 1];
29
+ }
30
+ const readJson = (file) => JSON.parse(readFileSync(resolve(process.cwd(), file), "utf8"));
31
+ export async function view(argv) {
32
+ const [command, file] = argv;
33
+ if (command !== "check" || !file || file.startsWith("--")) {
34
+ process.stdout.write(`graview view — a worker view, run where it can reach nothing\n\n${VIEW_USAGE}`);
35
+ return command === undefined || command === "help" || command === "--help" ? 0 : 1;
36
+ }
37
+ const appAt = flag(argv, "--app");
38
+ const manifestAt = flag(argv, "--manifest");
39
+ if (!appAt || !manifestAt) {
40
+ process.stderr.write(`graview view check needs --app and --manifest.\n\n${VIEW_USAGE}`);
41
+ return 1;
42
+ }
43
+ const app = await loadApp(appAt);
44
+ const seedAt = flag(argv, "--seed");
45
+ const store = new Store({
46
+ schema: app.schema,
47
+ mutations: (app.mutations ?? []),
48
+ ...(app.policy ? { policy: app.policy } : {}),
49
+ ...(seedAt ? { snapshot: readJson(seedAt) } : {}),
50
+ });
51
+ const roles = (flag(argv, "--roles") ?? "").split(",").map((role) => role.trim()).filter(Boolean);
52
+ const as = flag(argv, "--as");
53
+ const principal = as || roles.length > 0 ? { kind: "human", id: as ?? "graview-view-check", ...(roles.length > 0 ? { roles } : {}) } : { kind: "system", id: "graview-view-check" };
54
+ const width = flag(argv, "--width");
55
+ const result = await runWorkerViewHeadless({
56
+ store,
57
+ principal,
58
+ manifest: readJson(manifestAt),
59
+ source: readFileSync(resolve(process.cwd(), file), "utf8"),
60
+ run: nodeIsolate(),
61
+ places: (app.views?.places?.() ?? []).map((place) => ({ as: place.as, title: place.title, kind: place.kind })),
62
+ ...(width ? { width: Number(width) } : {}),
63
+ });
64
+ if (argv.includes("--json")) {
65
+ process.stdout.write(`${JSON.stringify(result.ok ? result.description : { reason: result.reason, detail: result.detail }, null, 2)}\n`);
66
+ return result.ok ? 0 : 1;
67
+ }
68
+ if (!result.ok) {
69
+ process.stdout.write(`${file} will not do (${result.reason}): ${result.detail}\n`);
70
+ return 1;
71
+ }
72
+ process.stdout.write(`${result.description.text}\n`);
73
+ return 0;
74
+ }
75
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { connectGuest as connect } from "./guest.js";
2
+ export { GUEST_PROTOCOL as protocol } from "./protocol.js";
3
+ //# sourceMappingURL=client-script.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-script.d.ts","sourceRoot":"","sources":["../src/client-script.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,YAAY,IAAI,OAAO,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,21 @@
1
+ /*
2
+ * THE FRAME GUEST'S CLIENT, AS ONE CLASSIC SCRIPT (FR-88).
3
+ *
4
+ * `connectGuest` is a module, so every frame guest bundled or inlined its
5
+ * own copy. This is the entry `scripts/guest-view-runtime.mjs` bundles into
6
+ * `client.js` at the package's root — `@graview/guest/client.js`, an IIFE
7
+ * that leaves one global, `GraviewGuest`:
8
+ *
9
+ * const guest = GraviewGuest.connect();
10
+ * guest.subscribe((props) => draw(props)); // nodes, edges, acts, theme, places
11
+ * guest.act("add-note", { label: "…" }); // the viewer's act, answered
12
+ * guest.navigate("offer:7"); // or { place: "the-packages" }
13
+ * guest.autoSize(); // or guest.size(px)
14
+ *
15
+ * A host serves it at a fixed path of its own, or inlines its text
16
+ * (`GUEST_CLIENT`, from `@graview/guest/client`) where a frame's policy
17
+ * allows inline script alone.
18
+ */
19
+ export { connectGuest as connect } from "./guest.js";
20
+ export { GUEST_PROTOCOL as protocol } from "./protocol.js";
21
+ //# sourceMappingURL=client-script.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-script.js","sourceRoot":"","sources":["../src/client-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,YAAY,IAAI,OAAO,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { GUEST_CLIENT, GUEST_CLIENT_SHA256 } from "./client.generated.js";
2
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const GUEST_CLIENT: string;
2
+ /** For `script-src 'sha256-…'`. */
3
+ export declare const GUEST_CLIENT_SHA256: string;
4
+ //# sourceMappingURL=client.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.generated.d.ts","sourceRoot":"","sources":["../src/client.generated.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,YAAY,EAAE,MAA+5E,CAAC;AAC37E,mCAAmC;AACnC,eAAO,MAAM,mBAAmB,EAAE,MAA8D,CAAC"}