@north-light/crouter 0.3.196 → 0.3.198

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 (148) hide show
  1. package/dist/api/client.d.ts +2 -2
  2. package/dist/api/dto/inbox.d.ts +46 -0
  3. package/dist/builtin-memory/00-runtime-base.md +3 -3
  4. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  5. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  6. package/dist/builtin-memory/wedged-child-on-runaway-bash.md +1 -1
  7. package/dist/clients/attach/render/chat-view.d.ts +3 -8
  8. package/dist/clients/attach/render/chat-view.js +3 -24
  9. package/dist/clients/attach/render/markdown-source.js +0 -6
  10. package/dist/clients/attach/render/tool-calls.js +16 -2
  11. package/dist/clients/attach/viewer.js +613 -602
  12. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +2 -2
  13. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +11 -4
  14. package/dist/clients/inbox/controller.js +4 -4
  15. package/dist/clients/inbox/page-adapter.d.ts +2 -1
  16. package/dist/clients/inbox/tui/render.js +46 -25
  17. package/dist/clients/inbox/tui/slots.d.ts +1 -3
  18. package/dist/clients/inbox/tui/slots.js +8 -37
  19. package/dist/clients/inbox/tui/types.d.ts +4 -3
  20. package/dist/commands/__tests__/human.test.js +160 -23
  21. package/dist/commands/canvas-browse.js +1 -1
  22. package/dist/commands/human/doc.js +21 -74
  23. package/dist/commands/human/html.d.ts +2 -0
  24. package/dist/commands/human/html.js +81 -0
  25. package/dist/commands/human/prompts.d.ts +5 -4
  26. package/dist/commands/human/prompts.js +90 -168
  27. package/dist/commands/human/shared.d.ts +5 -6
  28. package/dist/commands/human/shared.js +13 -61
  29. package/dist/commands/human.js +7 -2
  30. package/dist/core/__tests__/daemon-boot.test.js +7 -4
  31. package/dist/core/__tests__/dead-node-policy-table.test.js +20 -36
  32. package/dist/core/__tests__/human-deliver.test.js +28 -37
  33. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +13 -11
  34. package/dist/core/__tests__/seam/dormancy-release.test.js +63 -4
  35. package/dist/core/__tests__/serial/human-deliver-e2e.test.js +3 -13
  36. package/dist/core/canvas/__tests__/attention.test.js +2 -2
  37. package/dist/core/canvas/__tests__/render-remote.test.js +2 -2
  38. package/dist/core/canvas/browse/app.d.ts +1 -1
  39. package/dist/core/canvas/browse/app.js +21 -3
  40. package/dist/core/canvas/browse/render.d.ts +4 -0
  41. package/dist/core/canvas/browse/render.js +5 -1
  42. package/dist/core/canvas/canvas.d.ts +26 -0
  43. package/dist/core/canvas/canvas.js +55 -0
  44. package/dist/core/command.js +6 -11
  45. package/dist/core/config.js +3 -2
  46. package/dist/core/help.d.ts +3 -0
  47. package/dist/core/human/__tests__/html-markdown.test.d.ts +1 -0
  48. package/dist/core/human/__tests__/html-markdown.test.js +52 -0
  49. package/dist/core/human/__tests__/page-catalog.test.d.ts +1 -0
  50. package/dist/core/human/__tests__/page-catalog.test.js +16 -0
  51. package/dist/core/human/__tests__/page-render.test.js +40 -23
  52. package/dist/core/human/__tests__/page-tickets.test.js +48 -27
  53. package/dist/core/human/__tests__/page.test.js +48 -65
  54. package/dist/core/human/__tests__/serial/inbox-core.test.js +5 -15
  55. package/dist/core/human/answer-text.d.ts +3 -0
  56. package/dist/core/human/answer-text.js +98 -0
  57. package/dist/core/human/answer.d.ts +51 -0
  58. package/dist/core/human/answer.js +125 -0
  59. package/dist/core/human/component-docs.d.ts +14 -0
  60. package/dist/core/human/component-docs.js +161 -0
  61. package/dist/core/human/html-markdown.d.ts +3 -0
  62. package/dist/core/human/html-markdown.js +288 -0
  63. package/dist/core/human/page-catalog.d.ts +19 -3
  64. package/dist/core/human/page-catalog.js +73 -16
  65. package/dist/core/human/page-render.d.ts +3 -2
  66. package/dist/core/human/page-render.js +19 -45
  67. package/dist/core/human/page-schema.d.ts +108 -8
  68. package/dist/core/human/page-schema.js +88 -31
  69. package/dist/core/human/page-synth.d.ts +2 -4
  70. package/dist/core/human/page-synth.js +23 -7
  71. package/dist/core/human/page.d.ts +14 -7
  72. package/dist/core/human/page.js +178 -90
  73. package/dist/core/human/review-schema.d.ts +1 -0
  74. package/dist/core/human/review-schema.js +1 -1
  75. package/dist/core/human/scan.d.ts +3 -2
  76. package/dist/core/human/scan.js +7 -8
  77. package/dist/core/human/summary.d.ts +4 -7
  78. package/dist/core/human/summary.js +4 -60
  79. package/dist/core/human/tickets.d.ts +10 -9
  80. package/dist/core/human/tickets.js +5 -3
  81. package/dist/core/human/types.d.ts +4 -0
  82. package/dist/core/keybindings/catalog.d.ts +2 -2
  83. package/dist/core/keybindings/catalog.js +1 -0
  84. package/dist/core/review/realize.js +9 -1
  85. package/dist/core/runtime/boot-root.js +6 -1
  86. package/dist/core/runtime/broker.js +8 -6
  87. package/dist/core/runtime/busy.d.ts +4 -3
  88. package/dist/core/runtime/busy.js +4 -3
  89. package/dist/core/runtime/spawn.js +4 -4
  90. package/dist/core/termrender/display.d.ts +7 -3
  91. package/dist/core/termrender/display.js +45 -9
  92. package/dist/core/termrender/termrender.d.ts +3 -12
  93. package/dist/core/termrender/termrender.js +6 -37
  94. package/dist/core/user-settings.d.ts +17 -2
  95. package/dist/core/user-settings.js +32 -11
  96. package/dist/daemon/api/handlers/human.js +1 -1
  97. package/dist/daemon/api/handlers/inbox.js +22 -7
  98. package/dist/daemon/cron-run.js +16 -2
  99. package/dist/daemon/crtrd.js +1 -1
  100. package/dist/daemon/fleet.d.ts +22 -10
  101. package/dist/daemon/fleet.js +43 -24
  102. package/dist/daemon/human/finish.d.ts +2 -1
  103. package/dist/daemon/human/finish.js +45 -28
  104. package/dist/daemon/human/sweep.js +4 -2
  105. package/dist/daemon/reconcilers/broker-supervision.js +11 -8
  106. package/dist/daemon/reconcilers/dormant-inbox.js +11 -6
  107. package/dist/daemon/reconcilers/live-obligation.d.ts +21 -1
  108. package/dist/daemon/reconcilers/live-obligation.js +30 -2
  109. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -0
  110. package/dist/daemon/reconcilers/storage-maintenance.js +28 -1
  111. package/dist/daemon/review/sweep.js +12 -1
  112. package/dist/pages/bundle.css +1 -1
  113. package/dist/pages/bundle.js +1008 -577
  114. package/dist/pages/comments.d.ts +29 -0
  115. package/dist/pages/comments.js +51 -0
  116. package/dist/pages/controls.d.ts +98 -0
  117. package/dist/pages/controls.js +261 -0
  118. package/dist/pages/elements/cards.d.ts +15 -4
  119. package/dist/pages/elements/cards.js +299 -186
  120. package/dist/pages/elements/chart.d.ts +22 -0
  121. package/dist/pages/elements/chart.js +107 -91
  122. package/dist/pages/elements/options.d.ts +9 -0
  123. package/dist/pages/elements/options.js +268 -155
  124. package/dist/pages/elements/pages.d.ts +6 -0
  125. package/dist/pages/elements/pages.js +60 -38
  126. package/dist/pages/elements/slot.d.ts +5 -0
  127. package/dist/pages/elements/slot.js +17 -10
  128. package/dist/pages/elements/table.d.ts +17 -0
  129. package/dist/pages/elements/table.js +336 -228
  130. package/dist/pages/elements/text.d.ts +9 -3
  131. package/dist/pages/elements/text.js +350 -143
  132. package/dist/pages/host.d.ts +0 -24
  133. package/dist/pages/host.js +0 -17
  134. package/dist/pages/readonly.d.ts +24 -0
  135. package/dist/pages/readonly.js +31 -0
  136. package/dist/pages/responses.d.ts +37 -0
  137. package/dist/pages/responses.js +56 -0
  138. package/dist/pi-extensions/canvas-bash-valve.d.ts +9 -1
  139. package/dist/pi-extensions/canvas-bash-valve.js +12 -8
  140. package/dist/types.d.ts +19 -5
  141. package/dist/types.js +2 -1
  142. package/package.json +1 -1
  143. package/runtime.lock.json +2 -2
  144. package/scripts/install-runtime.mjs +19 -24
  145. package/dist/clients/attach/render/html-markdown.d.ts +0 -13
  146. package/dist/clients/attach/render/html-markdown.js +0 -206
  147. package/dist/core/human/markdown-html.d.ts +0 -8
  148. package/dist/core/human/markdown-html.js +0 -581
@@ -1,61 +1,32 @@
1
- // The default page template: one authored page document → the body-level HTML
2
- // payload the page runtime (`src/pages`) boots against. Both dialects render
3
- // here so an md page and an html page reach the runtime as ONE structure.
1
+ // One authored HTML document → the body-level HTML payload the page runtime
2
+ // (`src/pages`) boots against.
4
3
  //
5
- // What the payload carries: in-document chrome only — the page's own prose and
6
- // its `crtr-*` slot elements, wrapped in the `<crtr-pages>`/`<crtr-page>` pager
7
- // when the page bears a response.
4
+ // What the payload carries: in-document chrome only — the page's own HTML and
5
+ // `crtr-*` slot elements.
8
6
  //
9
7
  // What it deliberately does NOT carry: the runtime bundle's `<script>`/`<link>`
10
8
  // tags (the consuming host injects its own bundle URLs), the page title and
11
9
  // subtitle (host-rendered from the manifest), and any dismiss/save chrome
12
10
  // (host-owned). The payload is a fragment, not a document: the host wraps it.
13
- import { escapeHtmlAttribute, renderMarkdownToHtml } from './markdown-html.js';
14
- import { parsePageSource } from './page.js';
15
- import { isResponseBearingSlot } from './page-schema.js';
11
+ import { embedPageSlotConfigs, parsePageSource } from './page.js';
16
12
  /** Render one page ticket's authored document as the runtime's HTML payload. */
17
13
  export function renderPageHtml(manifest, document, productKinds = []) {
18
- // Re-projects the document AND re-verifies it against the manifest, so the
14
+ if (manifest.dialect !== 'html') {
15
+ throw new Error('legacy md pages render through the terminal inbox only');
16
+ }
17
+ // Re-projects the document and re-verifies it against the manifest, so the
19
18
  // payload can never disagree with the slots the manifest publishes.
20
- const projection = parsePageSource(document, manifest, productKinds);
21
- if (manifest.dialect === 'html')
22
- return renderAuthoredHtml(document);
23
- const body = projection
24
- .map((block) => (block.kind === 'prose' ? renderMarkdownToHtml(block.markdown) : renderSlotElement(manifest.slots[block.slotIndex])))
25
- .filter((part) => part !== '')
26
- .join('\n');
27
- // md is always one step, so the pager renders submit-only chrome — no step
28
- // label is emitted, because `<crtr-page label>` only surfaces at steps > 1.
29
- if (!manifest.slots.some(isResponseBearingSlot))
30
- return body;
31
- return `<crtr-pages>\n<crtr-page>\n${body}\n</crtr-page>\n</crtr-pages>`;
32
- }
33
- /** The pinned slot form the page runtime reads (`src/pages/slot-config.ts`). */
34
- function renderSlotElement(slot) {
35
- const tag = slot.unvalidated === true ? 'crtr-slot' : `crtr-${slot.kind}`;
36
- const attributes = [
37
- ...(slot.unvalidated === true ? [` kind="${escapeHtmlAttribute(slot.kind)}"`] : []),
38
- ...(slot.id === undefined ? [] : [` slot-id="${escapeHtmlAttribute(slot.id)}"`]),
39
- ].join('');
40
- return `<${tag}${attributes}><script type="application/json">${embedJson(slot.config)}</script></${tag}>`;
41
- }
42
- /** Serialize config for a `<script>` text node. Escaping every `<` as `\u003c`
43
- * — legal JSON that parses back identically — makes `</script>`, `<!--`, and
44
- * `<script` unrepresentable in the emitted text, so no config value can end
45
- * the element early. */
46
- function embedJson(config) {
47
- return JSON.stringify(config).replace(/</g, '\\u003c');
19
+ parsePageSource(document, manifest, productKinds);
20
+ return renderAuthoredHtml(embedPageSlotConfigs(document, manifest));
48
21
  }
49
22
  // ---------------------------------------------------------------------------
50
23
  // html dialect — normalized passthrough
51
24
  // ---------------------------------------------------------------------------
52
- /** The authored document's body, with two normalizations and nothing else:
53
- * `<style>` elements from `<head>` are hoisted in front of it (the payload is
54
- * body-level, so authored presentation would otherwise be lost), and every
55
- * `crtr-*` slot element carrying an authored `id` gains the matching
56
- * `slot-id`, which is the attribute the runtime actually reads. Authored
57
- * `<head>` `<link>` and `<script>` elements do not survive — the page runtime
58
- * is the only script a page needs. */
25
+ /** The authored document's body, after stored slot configs replace authored configs,
26
+ * `<style>` elements from `<head>` are hoisted in front of it, and every `crtr-*`
27
+ * slot element carrying an authored `id` gains the matching `slot-id` that the
28
+ * runtime reads. Authored `<head>` `<link>` and `<script>` elements do not survive:
29
+ * the page runtime is the only script a page needs. */
59
30
  function renderAuthoredHtml(document) {
60
31
  const styles = headStyles(document);
61
32
  const body = normalizeSlotIds(bodyInnerHtml(document)).trim();
@@ -99,6 +70,9 @@ function headStyles(document) {
99
70
  return [...head.matchAll(/<style\b[^>]*>[\s\S]*?<\/style>/gi)].map((match) => match[0]);
100
71
  }
101
72
  const PAGER_TAGS = new Set(['crtr-pages', 'crtr-page']);
73
+ function escapeHtmlAttribute(value) {
74
+ return value.replace(/[&<>"]/g, (character) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' })[character]);
75
+ }
102
76
  function normalizeSlotIds(html) {
103
77
  let out = '';
104
78
  let cursor = 0;
@@ -1,4 +1,6 @@
1
1
  import { z } from 'zod';
2
+ import { BUILTIN_PAGE_KINDS } from './page-catalog.js';
3
+ import type { ProductPageComponents } from '../../types.js';
2
4
  export declare const PAGE_SLOT_ID_PATTERN: RegExp;
3
5
  export declare const commentAnchorSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
4
6
  kind: z.ZodLiteral<"whole">;
@@ -52,6 +54,7 @@ export declare const optionSchema: z.ZodObject<{
52
54
  description: z.ZodOptional<z.ZodString>;
53
55
  }, z.core.$strict>;
54
56
  export declare const optionsConfigSchema: z.ZodObject<{
57
+ label: z.ZodOptional<z.ZodString>;
55
58
  options: z.ZodArray<z.ZodObject<{
56
59
  id: z.ZodString;
57
60
  label: z.ZodString;
@@ -96,9 +99,11 @@ export declare const optionsResponseSchema: z.ZodObject<{
96
99
  }, z.core.$strict>;
97
100
  export type OptionsResponse = z.infer<typeof optionsResponseSchema>;
98
101
  export declare const textConfigSchema: z.ZodObject<{
102
+ label: z.ZodOptional<z.ZodString>;
99
103
  initialText: z.ZodString;
100
104
  editable: z.ZodOptional<z.ZodBoolean>;
101
105
  placeholder: z.ZodOptional<z.ZodString>;
106
+ singleLine: z.ZodOptional<z.ZodBoolean>;
102
107
  }, z.core.$strict>;
103
108
  export type TextConfig = z.infer<typeof textConfigSchema>;
104
109
  export declare const textResponseSchema: z.ZodObject<{
@@ -144,7 +149,41 @@ export declare const tableRowSchema: z.ZodObject<{
144
149
  id: z.ZodString;
145
150
  cells: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
146
151
  }, z.core.$strict>;
152
+ export declare const tableRowsSchema: z.ZodArray<z.ZodObject<{
153
+ id: z.ZodString;
154
+ cells: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
155
+ }, z.core.$strict>>;
156
+ /** Stored table config: its data is always embedded. */
147
157
  export declare const tableConfigSchema: z.ZodObject<{
158
+ label: z.ZodOptional<z.ZodString>;
159
+ columns: z.ZodArray<z.ZodObject<{
160
+ id: z.ZodString;
161
+ label: z.ZodString;
162
+ align: z.ZodOptional<z.ZodEnum<{
163
+ right: "right";
164
+ left: "left";
165
+ }>>;
166
+ mono: z.ZodOptional<z.ZodBoolean>;
167
+ }, z.core.$strict>>;
168
+ rows: z.ZodOptional<z.ZodArray<z.ZodObject<{
169
+ id: z.ZodString;
170
+ cells: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
171
+ }, z.core.$strict>>>;
172
+ rowSelect: z.ZodDefault<z.ZodEnum<{
173
+ none: "none";
174
+ single: "single";
175
+ multi: "multi";
176
+ }>>;
177
+ columnSelect: z.ZodDefault<z.ZodEnum<{
178
+ none: "none";
179
+ single: "single";
180
+ multi: "multi";
181
+ }>>;
182
+ }, z.core.$strict>;
183
+ /** Authored table config: `source` is resolved before the manifest is stored. */
184
+ export declare const authoredTableConfigSchema: z.ZodObject<{
185
+ source: z.ZodString;
186
+ label: z.ZodOptional<z.ZodString>;
148
187
  columns: z.ZodArray<z.ZodObject<{
149
188
  id: z.ZodString;
150
189
  label: z.ZodString;
@@ -158,7 +197,6 @@ export declare const tableConfigSchema: z.ZodObject<{
158
197
  id: z.ZodString;
159
198
  cells: z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>;
160
199
  }, z.core.$strict>>>;
161
- source: z.ZodOptional<z.ZodString>;
162
200
  rowSelect: z.ZodDefault<z.ZodEnum<{
163
201
  none: "none";
164
202
  single: "single";
@@ -169,9 +207,9 @@ export declare const tableConfigSchema: z.ZodObject<{
169
207
  single: "single";
170
208
  multi: "multi";
171
209
  }>>;
172
- caption: z.ZodOptional<z.ZodString>;
173
210
  }, z.core.$strict>;
174
211
  export type TableConfig = z.infer<typeof tableConfigSchema>;
212
+ export type AuthoredTableConfig = TableConfig | z.infer<typeof authoredTableConfigSchema>;
175
213
  export declare const tableResponseSchema: z.ZodObject<{
176
214
  selectedRowIds: z.ZodArray<z.ZodString>;
177
215
  selectedColumnIds: z.ZodArray<z.ZodString>;
@@ -208,7 +246,33 @@ export declare const cardSchema: z.ZodObject<{
208
246
  body: z.ZodOptional<z.ZodString>;
209
247
  tag: z.ZodOptional<z.ZodString>;
210
248
  }, z.core.$strict>;
249
+ export declare const cardsSchema: z.ZodArray<z.ZodObject<{
250
+ id: z.ZodString;
251
+ title: z.ZodString;
252
+ subtitle: z.ZodOptional<z.ZodString>;
253
+ body: z.ZodOptional<z.ZodString>;
254
+ tag: z.ZodOptional<z.ZodString>;
255
+ }, z.core.$strict>>;
256
+ /** Stored cards config: its data is always embedded. */
211
257
  export declare const cardsConfigSchema: z.ZodObject<{
258
+ label: z.ZodOptional<z.ZodString>;
259
+ cards: z.ZodOptional<z.ZodArray<z.ZodObject<{
260
+ id: z.ZodString;
261
+ title: z.ZodString;
262
+ subtitle: z.ZodOptional<z.ZodString>;
263
+ body: z.ZodOptional<z.ZodString>;
264
+ tag: z.ZodOptional<z.ZodString>;
265
+ }, z.core.$strict>>>;
266
+ mode: z.ZodEnum<{
267
+ single: "single";
268
+ multi: "multi";
269
+ }>;
270
+ columns: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>]>>;
271
+ }, z.core.$strict>;
272
+ /** Authored cards config: `source` is resolved before the manifest is stored. */
273
+ export declare const authoredCardsConfigSchema: z.ZodObject<{
274
+ source: z.ZodString;
275
+ label: z.ZodOptional<z.ZodString>;
212
276
  cards: z.ZodOptional<z.ZodArray<z.ZodObject<{
213
277
  id: z.ZodString;
214
278
  title: z.ZodString;
@@ -216,7 +280,6 @@ export declare const cardsConfigSchema: z.ZodObject<{
216
280
  body: z.ZodOptional<z.ZodString>;
217
281
  tag: z.ZodOptional<z.ZodString>;
218
282
  }, z.core.$strict>>>;
219
- source: z.ZodOptional<z.ZodString>;
220
283
  mode: z.ZodEnum<{
221
284
  single: "single";
222
285
  multi: "multi";
@@ -224,6 +287,7 @@ export declare const cardsConfigSchema: z.ZodObject<{
224
287
  columns: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<2>, z.ZodLiteral<3>]>>;
225
288
  }, z.core.$strict>;
226
289
  export type CardsConfig = z.infer<typeof cardsConfigSchema>;
290
+ export type AuthoredCardsConfig = CardsConfig | z.infer<typeof authoredCardsConfigSchema>;
227
291
  export declare const cardsResponseSchema: z.ZodObject<{
228
292
  selectedCardIds: z.ZodArray<z.ZodString>;
229
293
  comments: z.ZodArray<z.ZodObject<{
@@ -256,6 +320,8 @@ export declare const chartSeriesSchema: z.ZodObject<{
256
320
  field: z.ZodString;
257
321
  label: z.ZodOptional<z.ZodString>;
258
322
  }, z.core.$strict>;
323
+ export declare const chartDataRowsSchema: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
324
+ /** Stored chart config: its data is always embedded. */
259
325
  export declare const chartConfigSchema: z.ZodObject<{
260
326
  kind: z.ZodEnum<{
261
327
  line: "line";
@@ -268,11 +334,28 @@ export declare const chartConfigSchema: z.ZodObject<{
268
334
  label: z.ZodOptional<z.ZodString>;
269
335
  }, z.core.$strict>>;
270
336
  title: z.ZodOptional<z.ZodString>;
271
- data: z.ZodOptional<z.ZodUnknown>;
272
- source: z.ZodOptional<z.ZodString>;
337
+ data: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
338
+ }, z.core.$strict>;
339
+ /** Authored chart config: `source` is resolved before the manifest is stored. */
340
+ export declare const authoredChartConfigSchema: z.ZodObject<{
341
+ source: z.ZodString;
342
+ kind: z.ZodEnum<{
343
+ line: "line";
344
+ bar: "bar";
345
+ area: "area";
346
+ }>;
347
+ x: z.ZodString;
348
+ y: z.ZodArray<z.ZodObject<{
349
+ field: z.ZodString;
350
+ label: z.ZodOptional<z.ZodString>;
351
+ }, z.core.$strict>>;
352
+ title: z.ZodOptional<z.ZodString>;
353
+ data: z.ZodOptional<z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
273
354
  }, z.core.$strict>;
274
355
  export type ChartConfig = z.infer<typeof chartConfigSchema>;
356
+ export type AuthoredChartConfig = ChartConfig | z.infer<typeof authoredChartConfigSchema>;
275
357
  export type SlotConfig = OptionsConfig | TextConfig | TableConfig | CardsConfig | ChartConfig | Record<string, unknown>;
358
+ export type AuthoredSlotConfig = OptionsConfig | TextConfig | AuthoredTableConfig | AuthoredCardsConfig | AuthoredChartConfig | Record<string, unknown>;
276
359
  export type SlotResponse = OptionsResponse | TextResponse | TableResponse | CardsResponse | Record<string, unknown>;
277
360
  export interface PageSlot {
278
361
  id?: string;
@@ -280,11 +363,18 @@ export interface PageSlot {
280
363
  step: number;
281
364
  config: SlotConfig;
282
365
  unvalidated?: true;
366
+ /** Product registration declares this slot display-only. */
367
+ display?: true;
368
+ }
369
+ /** A page before submit may contain filesystem `source` paths. */
370
+ export interface AuthoredPageSlot extends Omit<PageSlot, 'config'> {
371
+ config: AuthoredSlotConfig;
283
372
  }
284
373
  export interface PageSource {
285
374
  sessionName?: string;
286
375
  askedBy?: string;
287
376
  blockedSince?: string;
377
+ profileName?: string;
288
378
  nodeId?: string;
289
379
  }
290
380
  export interface PageManifest {
@@ -295,14 +385,24 @@ export interface PageManifest {
295
385
  placement: 'inline' | 'panel';
296
386
  document: 'page.md' | 'page.html';
297
387
  steps: number;
388
+ /** Persisted slots never carry a source path. */
298
389
  slots: PageSlot[];
299
390
  source?: PageSource;
300
391
  }
392
+ /** A page before submit may carry filesystem source paths in its built-in slots. */
393
+ export interface AuthoredPageManifest extends Omit<PageManifest, 'slots'> {
394
+ slots: AuthoredPageSlot[];
395
+ }
396
+ export declare const BUILTIN_PAGE_CONFIG_SCHEMAS: Record<(typeof BUILTIN_PAGE_KINDS)[number], z.ZodType>;
397
+ export declare const BUILTIN_PAGE_RESPONSE_SCHEMAS: Partial<Record<(typeof BUILTIN_PAGE_KINDS)[number], z.ZodType>>;
398
+ export declare function issueText(error: z.ZodError): string;
301
399
  /** The canonical response-bearing predicate used by every page consumer. */
302
400
  export declare function isResponseBearingSlot(slot: PageSlot): boolean;
303
- /** Validate and normalize a derived or stored manifest against the resolved product catalog. */
304
- export declare function validatePageManifest(parsed: unknown, productKinds?: string[]): PageManifest;
305
- export declare function createPageManifestSchema(productKinds?: string[]): z.ZodType<PageManifest>;
401
+ /** Validate a persisted manifest. Source paths are rejected: pages render only embedded data. */
402
+ export declare function validatePageManifest(parsed: unknown, productComponents?: ProductPageComponents): PageManifest;
403
+ /** Validate an authored manifest before submit. Source paths are resolved by `snapshotPageSources`. */
404
+ export declare function validateAuthoredPageManifest(parsed: unknown, productComponents?: ProductPageComponents): AuthoredPageManifest;
405
+ export declare function createPageManifestSchema(productComponents?: ProductPageComponents): z.ZodType<PageManifest>;
306
406
  /** Built-in-only manifest schema; product-aware callers use createPageManifestSchema. */
307
407
  export declare const pageManifestSchema: z.ZodType<PageManifest, unknown, z.core.$ZodTypeInternals<PageManifest, unknown>>;
308
408
  export type PageResponses = Record<string, SlotResponse>;
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { BUILTIN_PAGE_KINDS, isRegisteredPageKind } from './page-catalog.js';
2
+ import { BUILTIN_PAGE_KINDS, productPageComponent } from './page-catalog.js';
3
3
  export const PAGE_SLOT_ID_PATTERN = /^[A-Za-z0-9_-]{1,64}$/;
4
4
  const idSchema = z.string().regex(PAGE_SLOT_ID_PATTERN, { error: 'slot id must match /^[A-Za-z0-9_-]{1,64}$/' });
5
5
  const itemIdSchema = z.string().min(1);
@@ -27,6 +27,7 @@ export const commentAnchorSchema = z.discriminatedUnion('kind', [
27
27
  export const commentSchema = z.object({ id: z.string().min(1), anchor: commentAnchorSchema, text: z.string() }).strict();
28
28
  export const optionSchema = z.object({ id: itemIdSchema, label: z.string().min(1), description: z.string().optional() }).strict();
29
29
  export const optionsConfigSchema = z.object({
30
+ label: z.string().optional(),
30
31
  options: z.array(optionSchema).min(1).superRefine((items, ctx) => uniqueIds(items, ctx, 'option')),
31
32
  mode: z.enum(['single', 'multi']),
32
33
  allowFreetext: z.boolean().optional(),
@@ -34,45 +35,67 @@ export const optionsConfigSchema = z.object({
34
35
  freetextPlaceholder: z.string().optional(),
35
36
  }).strict();
36
37
  export const optionsResponseSchema = z.object({ selectedOptionIds: z.array(itemIdSchema), comments: z.array(commentSchema), freetext: z.string().optional() }).strict();
37
- export const textConfigSchema = z.object({ initialText: z.string(), editable: z.boolean().optional(), placeholder: z.string().optional() }).strict();
38
+ // `singleLine` swaps the writing surface for one compact form field — a subject line, a name,
39
+ // a URL. It is an input by definition, so it is always editable and `editable: false` on it is
40
+ // an authoring mistake rather than a read-only one-liner.
41
+ export const textConfigSchema = z.object({ label: z.string().optional(), initialText: z.string(), editable: z.boolean().optional(), placeholder: z.string().optional(), singleLine: z.boolean().optional() }).strict().superRefine((config, ctx) => {
42
+ if (config.singleLine === true && config.editable === false)
43
+ ctx.addIssue({ code: 'custom', path: ['editable'], message: 'single-line text is always editable; drop editable: false' });
44
+ });
38
45
  export const textResponseSchema = z.object({ text: z.string(), edited: z.boolean(), comments: z.array(commentSchema) }).strict();
39
46
  export const tableColumnSchema = z.object({ id: itemIdSchema, label: z.string().min(1), align: z.enum(['left', 'right']).optional(), mono: z.boolean().optional() }).strict();
40
47
  export const tableCellSchema = z.union([z.string(), z.number(), z.boolean(), z.null()]);
41
48
  export const tableRowSchema = z.object({ id: itemIdSchema, cells: z.record(z.string(), tableCellSchema) }).strict();
42
- export const tableConfigSchema = z.object({
49
+ export const tableRowsSchema = z.array(tableRowSchema).superRefine((items, ctx) => uniqueIds(items, ctx, 'row'));
50
+ const tableConfigFields = {
51
+ label: z.string().optional(),
43
52
  columns: z.array(tableColumnSchema).min(1).superRefine((items, ctx) => uniqueIds(items, ctx, 'column')),
44
- rows: z.array(tableRowSchema).superRefine((items, ctx) => uniqueIds(items, ctx, 'row')).optional(),
45
- source: z.string().optional(),
53
+ rows: tableRowsSchema.optional(),
46
54
  rowSelect: selectModeSchema.default('none'),
47
55
  columnSelect: selectModeSchema.default('none'),
48
- caption: z.string().optional(),
49
- }).strict().superRefine((config, ctx) => {
50
- if (config.rows !== undefined && config.source !== undefined)
56
+ };
57
+ /** Stored table config: its data is always embedded. */
58
+ export const tableConfigSchema = z.object(tableConfigFields).strict();
59
+ /** Authored table config: `source` is resolved before the manifest is stored. */
60
+ export const authoredTableConfigSchema = z.object({ ...tableConfigFields, source: z.string() }).strict().superRefine((config, ctx) => {
61
+ if (config.rows !== undefined)
51
62
  ctx.addIssue({ code: 'custom', message: 'table rows and source are mutually exclusive' });
52
63
  });
53
64
  export const tableResponseSchema = z.object({ selectedRowIds: z.array(itemIdSchema), selectedColumnIds: z.array(itemIdSchema), comments: z.array(commentSchema) }).strict();
54
65
  export const cardSchema = z.object({ id: itemIdSchema, title: z.string().min(1), subtitle: z.string().optional(), body: z.string().optional(), tag: z.string().optional() }).strict();
55
- export const cardsConfigSchema = z.object({
56
- cards: z.array(cardSchema).superRefine((items, ctx) => uniqueIds(items, ctx, 'card')).optional(),
57
- source: z.string().optional(),
66
+ export const cardsSchema = z.array(cardSchema).superRefine((items, ctx) => uniqueIds(items, ctx, 'card'));
67
+ const cardsConfigFields = {
68
+ label: z.string().optional(),
69
+ cards: cardsSchema.optional(),
58
70
  mode: z.enum(['single', 'multi']),
59
71
  columns: z.union([z.literal(2), z.literal(3)]).optional(),
60
- }).strict().superRefine((config, ctx) => {
61
- if (config.cards !== undefined && config.source !== undefined)
72
+ };
73
+ /** Stored cards config: its data is always embedded. */
74
+ export const cardsConfigSchema = z.object(cardsConfigFields).strict();
75
+ /** Authored cards config: `source` is resolved before the manifest is stored. */
76
+ export const authoredCardsConfigSchema = z.object({ ...cardsConfigFields, source: z.string() }).strict().superRefine((config, ctx) => {
77
+ if (config.cards !== undefined)
62
78
  ctx.addIssue({ code: 'custom', message: 'cards data and source are mutually exclusive' });
63
79
  });
64
80
  export const cardsResponseSchema = z.object({ selectedCardIds: z.array(itemIdSchema), comments: z.array(commentSchema) }).strict();
65
81
  export const chartSeriesSchema = z.object({ field: z.string().min(1), label: z.string().optional() }).strict();
66
- export const chartConfigSchema = z.object({
82
+ export const chartDataRowsSchema = z.array(z.record(z.string(), z.unknown()));
83
+ const chartConfigFields = {
67
84
  kind: z.enum(['line', 'bar', 'area']),
68
85
  x: z.string().min(1),
69
86
  y: z.array(chartSeriesSchema).min(1),
70
87
  title: z.string().optional(),
71
- data: z.unknown().optional(),
72
- source: z.string().optional(),
73
- }).strict();
74
- const sourceSchema = z.object({ sessionName: z.string().optional(), askedBy: z.string().optional(), blockedSince: z.string().optional(), nodeId: z.string().optional() }).strict();
75
- const rawSlotSchema = z.object({ id: idSchema.optional(), kind: z.string().min(1), step: z.number().int().nonnegative(), config: jsonObjectSchema, unvalidated: z.literal(true).optional() }).strict();
88
+ data: chartDataRowsSchema.optional(),
89
+ };
90
+ /** Stored chart config: its data is always embedded. */
91
+ export const chartConfigSchema = z.object(chartConfigFields).strict();
92
+ /** Authored chart config: `source` is resolved before the manifest is stored. */
93
+ export const authoredChartConfigSchema = z.object({ ...chartConfigFields, source: z.string() }).strict().superRefine((config, ctx) => {
94
+ if (config.data !== undefined)
95
+ ctx.addIssue({ code: 'custom', message: 'chart data and source are mutually exclusive' });
96
+ });
97
+ const sourceSchema = z.object({ sessionName: z.string().optional(), askedBy: z.string().optional(), blockedSince: z.string().optional(), profileName: z.string().optional(), nodeId: z.string().optional() }).strict();
98
+ const rawSlotSchema = z.object({ id: idSchema.optional(), kind: z.string().min(1), step: z.number().int().nonnegative(), config: jsonObjectSchema, unvalidated: z.literal(true).optional(), display: z.literal(true).optional() }).strict();
76
99
  const rawPageManifestSchema = z.object({
77
100
  schema: z.literal('crtr.page/v1'),
78
101
  dialect: z.enum(['md', 'html']),
@@ -84,18 +107,33 @@ const rawPageManifestSchema = z.object({
84
107
  slots: z.array(rawSlotSchema),
85
108
  source: sourceSchema.optional(),
86
109
  }).strict();
87
- const configSchemas = {
110
+ export const BUILTIN_PAGE_CONFIG_SCHEMAS = {
88
111
  options: optionsConfigSchema,
89
112
  text: textConfigSchema,
90
113
  table: tableConfigSchema,
91
114
  cards: cardsConfigSchema,
92
115
  chart: chartConfigSchema,
93
116
  };
94
- function issueText(error) {
117
+ const AUTHORED_PAGE_CONFIG_SCHEMAS = {
118
+ options: optionsConfigSchema,
119
+ text: textConfigSchema,
120
+ table: z.union([tableConfigSchema, authoredTableConfigSchema]),
121
+ cards: z.union([cardsConfigSchema, authoredCardsConfigSchema]),
122
+ chart: z.union([chartConfigSchema, authoredChartConfigSchema]),
123
+ };
124
+ export const BUILTIN_PAGE_RESPONSE_SCHEMAS = {
125
+ options: optionsResponseSchema,
126
+ text: textResponseSchema,
127
+ table: tableResponseSchema,
128
+ cards: cardsResponseSchema,
129
+ };
130
+ export function issueText(error) {
95
131
  return error.issues.map((issue) => `${issue.path.length === 0 ? 'value' : issue.path.join('.')}: ${issue.message}`).join('; ');
96
132
  }
97
133
  /** The canonical response-bearing predicate used by every page consumer. */
98
134
  export function isResponseBearingSlot(slot) {
135
+ if (slot.display === true)
136
+ return false;
99
137
  if (slot.unvalidated === true)
100
138
  return true;
101
139
  if (slot.kind === 'options' || slot.kind === 'text' || slot.kind === 'cards')
@@ -105,8 +143,7 @@ export function isResponseBearingSlot(slot) {
105
143
  const config = slot.config;
106
144
  return (config.rowSelect ?? 'none') !== 'none' || (config.columnSelect ?? 'none') !== 'none';
107
145
  }
108
- /** Validate and normalize a derived or stored manifest against the resolved product catalog. */
109
- export function validatePageManifest(parsed, productKinds = []) {
146
+ function validateManifest(parsed, productComponents, authored) {
110
147
  const manifest = rawPageManifestSchema.parse(parsed);
111
148
  if (manifest.document !== (manifest.dialect === 'md' ? 'page.md' : 'page.html'))
112
149
  throw new Error(`page document "${manifest.document}" does not match ${manifest.dialect} dialect`);
@@ -120,20 +157,32 @@ export function validatePageManifest(parsed, productKinds = []) {
120
157
  if (BUILTIN_PAGE_KINDS.includes(raw.kind)) {
121
158
  if (raw.unvalidated === true)
122
159
  throw new Error(`built-in slot kind "${raw.kind}" cannot be unvalidated`);
123
- const result = configSchemas[raw.kind].safeParse(raw.config);
160
+ if (raw.display === true)
161
+ throw new Error(`built-in slot kind "${raw.kind}" cannot set display: true`);
162
+ const result = (authored ? AUTHORED_PAGE_CONFIG_SCHEMAS : BUILTIN_PAGE_CONFIG_SCHEMAS)[raw.kind].safeParse(raw.config);
124
163
  if (!result.success)
125
164
  throw new Error(`invalid config for slot ${raw.id === undefined ? `#${index}` : `"${raw.id}"`} (${raw.kind}): ${issueText(result.error)}`);
126
165
  slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: result.data };
127
166
  }
128
167
  else {
129
- if (!isRegisteredPageKind(raw.kind, productKinds))
168
+ const component = productPageComponent(raw.kind, productComponents);
169
+ if (component === undefined)
130
170
  throw new Error(`unregistered page slot kind "${raw.kind}" at slot #${index}`);
131
171
  if (raw.unvalidated !== true)
132
172
  throw new Error(`registered product slot kind "${raw.kind}" must set unvalidated: true`);
133
- slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: raw.config, unvalidated: true };
173
+ if (!authored && raw.display !== (component.display === true ? true : undefined))
174
+ throw new Error(component.display === true
175
+ ? `display product slot kind "${raw.kind}" must set display: true`
176
+ : `non-display product slot kind "${raw.kind}" cannot set display: true`);
177
+ if (authored && raw.display === true && component.display !== true)
178
+ throw new Error(`non-display product slot kind "${raw.kind}" cannot set display: true`);
179
+ slot = { ...(raw.id === undefined ? {} : { id: raw.id }), kind: raw.kind, step: raw.step, config: raw.config, unvalidated: true, ...(component.display === true ? { display: true } : {}) };
180
+ }
181
+ if (isResponseBearingSlot(slot) && slot.id === undefined) {
182
+ throw new Error(slot.unvalidated === true
183
+ ? `product slot kind "${slot.kind}" at slot #${index} requires an id="…" attribute on its <crtr-slot> element`
184
+ : `response-bearing slot kind "${slot.kind}" at slot #${index} requires an id="…" attribute on its element`);
134
185
  }
135
- if (isResponseBearingSlot(slot) && slot.id === undefined)
136
- throw new Error(`response-bearing slot kind "${slot.kind}" at slot #${index} requires an id`);
137
186
  if (slot.id !== undefined) {
138
187
  if (seen.has(slot.id))
139
188
  throw new Error(`duplicate slot id "${slot.id}"`);
@@ -143,16 +192,24 @@ export function validatePageManifest(parsed, productKinds = []) {
143
192
  });
144
193
  return { ...manifest, slots };
145
194
  }
146
- export function createPageManifestSchema(productKinds = []) {
195
+ /** Validate a persisted manifest. Source paths are rejected: pages render only embedded data. */
196
+ export function validatePageManifest(parsed, productComponents = []) {
197
+ return validateManifest(parsed, productComponents, false);
198
+ }
199
+ /** Validate an authored manifest before submit. Source paths are resolved by `snapshotPageSources`. */
200
+ export function validateAuthoredPageManifest(parsed, productComponents = []) {
201
+ return validateManifest(parsed, productComponents, true);
202
+ }
203
+ export function createPageManifestSchema(productComponents = []) {
147
204
  return z.custom((value) => {
148
205
  try {
149
- validatePageManifest(value, productKinds);
206
+ validatePageManifest(value, productComponents);
150
207
  return true;
151
208
  }
152
209
  catch {
153
210
  return false;
154
211
  }
155
- }, { error: 'invalid page manifest' }).transform((value) => validatePageManifest(value, productKinds));
212
+ }, { error: 'invalid page manifest' }).transform((value) => validatePageManifest(value, productComponents));
156
213
  }
157
214
  /** Built-in-only manifest schema; product-aware callers use createPageManifestSchema. */
158
215
  export const pageManifestSchema = createPageManifestSchema();
@@ -1,8 +1,6 @@
1
- /** The single response slot every synthesized question page carries. */
2
- export declare const ASK_RESPONSE_SLOT = "```slot:text\n{ \"id\": \"response\", \"initialText\": \"\", \"editable\": true }\n```";
3
- /** Build a page document from title/subtitle/body — the shape crtr synthesizes when no page file is authored. */
1
+ /** Build a complete HTML page from title, subtitle, and body for internal producers. */
4
2
  export declare function synthesizedPageDocument(title: string, subtitle: string, body: string, responseBearing: boolean): string;
5
- /** Materialize a synthesized document into a private temp dir; the caller removes that dir once submitted. */
3
+ /** Materialize an internally generated document into a private temp dir; the caller removes it after submission. */
6
4
  export declare function writeSynthesizedPage(document: string): {
7
5
  dir: string;
8
6
  path: string;
@@ -1,17 +1,33 @@
1
1
  import { join } from 'node:path';
2
2
  import { mkdtempSync, writeFileSync } from 'node:fs';
3
3
  import { tmpdir } from 'node:os';
4
- /** The single response slot every synthesized question page carries. */
5
- export const ASK_RESPONSE_SLOT = '```slot:text\n{ "id": "response", "initialText": "", "editable": true }\n```';
6
- /** Build a page document from title/subtitle/body — the shape crtr synthesizes when no page file is authored. */
4
+ function escapeHtml(value) {
5
+ return value.replace(/[&<>"']/g, (character) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[character]);
6
+ }
7
+ function bodyHtml(body) {
8
+ if (body === '')
9
+ return '';
10
+ return `<p>${escapeHtml(body).replace(/\r?\n/g, '<br>')}</p>`;
11
+ }
12
+ /** Build a complete HTML page from title, subtitle, and body for internal producers. */
7
13
  export function synthesizedPageDocument(title, subtitle, body, responseBearing) {
8
- const slot = responseBearing ? `\n\n${ASK_RESPONSE_SLOT}` : '';
9
- return `---\ntitle: ${title}\nsubtitle: ${subtitle}\n---\n\n${body}${slot}\n`;
14
+ const contents = bodyHtml(body);
15
+ const interactive = responseBearing
16
+ ? `<crtr-pages><crtr-page><crtr-text id="response"><script type="application/json">{"initialText":"","editable":true}</script></crtr-text></crtr-page></crtr-pages>`
17
+ : '';
18
+ return `<!doctype html>
19
+ <html><head>
20
+ <meta name="crtr-page-title" content="${escapeHtml(title)}">
21
+ <meta name="crtr-page-subtitle" content="${escapeHtml(subtitle)}">
22
+ </head><body>
23
+ ${contents}${contents === '' || interactive === '' ? '' : '\n'}${interactive}
24
+ </body></html>
25
+ `;
10
26
  }
11
- /** Materialize a synthesized document into a private temp dir; the caller removes that dir once submitted. */
27
+ /** Materialize an internally generated document into a private temp dir; the caller removes it after submission. */
12
28
  export function writeSynthesizedPage(document) {
13
29
  const dir = mkdtempSync(join(tmpdir(), 'crtr-human-page-'));
14
- const path = join(dir, 'page.md');
30
+ const path = join(dir, 'page.html');
15
31
  writeFileSync(path, document, { encoding: 'utf8', mode: 0o600 });
16
32
  return { dir, path };
17
33
  }
@@ -1,5 +1,8 @@
1
- import { type PageManifest, type PageSource } from './page-schema.js';
1
+ import type { ProductPageComponents } from '../../types.js';
2
+ import { type AuthoredPageManifest, type PageManifest, type PageSource } from './page-schema.js';
3
+ /** Dialects retained in persisted manifests. New page authoring is HTML-only. */
2
4
  export type PageDialect = 'md' | 'html';
5
+ export type AuthoredPageDialect = 'html';
3
6
  export type PageSourceBlock = {
4
7
  kind: 'prose';
5
8
  markdown: string;
@@ -12,11 +15,15 @@ export type PageSourceProjection = PageSourceBlock[];
12
15
  export declare class PageAuthoringError extends Error {
13
16
  constructor(message: string);
14
17
  }
15
- /** Derive the transport manifest from one authored page document. */
16
- export declare function derivePageManifestFromDocument(document: string, dialect: PageDialect, productKinds?: string[], source?: PageSource): PageManifest;
17
- /** Derive the transport manifest from one authored page source file. */
18
- export declare function derivePageManifest(sourceFile: string, dialect: PageDialect, productKinds?: string[], source?: PageSource): PageManifest;
18
+ /** Derive the transport manifest from one authored HTML page document. */
19
+ export declare function derivePageManifestFromDocument(document: string, dialect: AuthoredPageDialect, productComponents?: ProductPageComponents, source?: PageSource): AuthoredPageManifest;
20
+ /** Derive the transport manifest from one authored HTML page source file. */
21
+ export declare function derivePageManifest(sourceFile: string, dialect: AuthoredPageDialect, productComponents?: ProductPageComponents, source?: PageSource): AuthoredPageManifest;
22
+ /** Read source files into their built-in slots, returning a self-contained stored manifest. */
23
+ export declare function snapshotPageSources(manifest: AuthoredPageManifest, productComponents?: ProductPageComponents): PageManifest;
24
+ /** Replace every authored slot config with its stored, self-contained config for runtime rendering. */
25
+ export declare function embedPageSlotConfigs(document: string, manifest: PageManifest): string;
19
26
  /** Read and validate page.json from a ticket directory. */
20
- export declare function parsePage(dir: string, productKinds?: string[]): PageManifest;
27
+ export declare function parsePage(dir: string, productComponents?: ProductPageComponents): PageManifest;
21
28
  /** Project authored source for local rendering and verify its slot references against the manifest. */
22
- export declare function parsePageSource(document: string, manifest: PageManifest, productKinds?: string[]): PageSourceProjection;
29
+ export declare function parsePageSource(document: string, manifest: PageManifest, productComponents?: ProductPageComponents): PageSourceProjection;