@cocoar/vue-page-builder 2.19.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/IDP_INTEGRATION.md +350 -0
  2. package/README.md +498 -169
  3. package/dist/BuilderElementCodeDialog-DXGNzleE.js +64 -0
  4. package/dist/BuilderExpressionDialog-yIfwYgXD.js +61 -0
  5. package/dist/BuilderLogicPanel-C9urz5Cd.js +68 -0
  6. package/dist/BuilderPageRootCodeDialog-CQsg_ozW.js +61 -0
  7. package/dist/CoarPageBuilder.vue.d.ts +71 -1
  8. package/dist/CoarPageBuilder.vue.d.ts.map +1 -1
  9. package/dist/CoarPageRenderer.vue.d.ts +36 -1
  10. package/dist/CoarPageRenderer.vue.d.ts.map +1 -1
  11. package/dist/PageNode.vue.d.ts +9 -1
  12. package/dist/PageNode.vue.d.ts.map +1 -1
  13. package/dist/VisualMarkupInspector-CmAOc-CH.js +54 -0
  14. package/dist/_plugin-vue_export-helper-BTgDAbhb.js +8 -0
  15. package/dist/actionValues.d.ts +21 -0
  16. package/dist/actionValues.d.ts.map +1 -0
  17. package/dist/assets/pageScriptRuntime.worker-Cll8Lm_I.js +25 -0
  18. package/dist/builder/BuilderCanvas.vue.d.ts +31 -1
  19. package/dist/builder/BuilderCanvas.vue.d.ts.map +1 -1
  20. package/dist/builder/BuilderCanvasNode.vue.d.ts.map +1 -1
  21. package/dist/builder/BuilderCompositionsPanel.vue.d.ts +3 -0
  22. package/dist/builder/BuilderCompositionsPanel.vue.d.ts.map +1 -0
  23. package/dist/builder/BuilderElementCodeDialog.vue.d.ts +14 -0
  24. package/dist/builder/BuilderElementCodeDialog.vue.d.ts.map +1 -0
  25. package/dist/builder/BuilderExpressionDialog.vue.d.ts +11 -0
  26. package/dist/builder/BuilderExpressionDialog.vue.d.ts.map +1 -0
  27. package/dist/builder/BuilderFxButton.vue.d.ts +28 -0
  28. package/dist/builder/BuilderFxButton.vue.d.ts.map +1 -0
  29. package/dist/builder/BuilderLogicPanel.vue.d.ts +3 -0
  30. package/dist/builder/BuilderLogicPanel.vue.d.ts.map +1 -0
  31. package/dist/builder/BuilderOutline.vue.d.ts.map +1 -1
  32. package/dist/builder/BuilderOutlineNode.vue.d.ts.map +1 -1
  33. package/dist/builder/BuilderPageRootCodeDialog.vue.d.ts +13 -0
  34. package/dist/builder/BuilderPageRootCodeDialog.vue.d.ts.map +1 -0
  35. package/dist/builder/BuilderPalette.vue.d.ts +3 -0
  36. package/dist/builder/BuilderPalette.vue.d.ts.map +1 -0
  37. package/dist/builder/BuilderPropsPanel.vue.d.ts.map +1 -1
  38. package/dist/builder/BuilderTranslationsPanel.vue.d.ts +6 -0
  39. package/dist/builder/BuilderTranslationsPanel.vue.d.ts.map +1 -0
  40. package/dist/builder/boxSides.d.ts +30 -0
  41. package/dist/builder/boxSides.d.ts.map +1 -0
  42. package/dist/builder/builderContext.d.ts +46 -4
  43. package/dist/builder/builderContext.d.ts.map +1 -1
  44. package/dist/builder/expressionAuthoring.d.ts +7 -0
  45. package/dist/builder/expressionAuthoring.d.ts.map +1 -0
  46. package/dist/builder/nodeDefaults.d.ts +10 -5
  47. package/dist/builder/nodeDefaults.d.ts.map +1 -1
  48. package/dist/builder/pageCodeAuthoring.d.ts +11 -0
  49. package/dist/builder/pageCodeAuthoring.d.ts.map +1 -0
  50. package/dist/builder/props/ActionPropsEditor.vue.d.ts +9 -0
  51. package/dist/builder/props/ActionPropsEditor.vue.d.ts.map +1 -0
  52. package/dist/builder/props/BuilderViewportControl.vue.d.ts +23 -0
  53. package/dist/builder/props/BuilderViewportControl.vue.d.ts.map +1 -0
  54. package/dist/builder/props/BuilderZoomControl.vue.d.ts +24 -0
  55. package/dist/builder/props/BuilderZoomControl.vue.d.ts.map +1 -0
  56. package/dist/builder/props/CompoundLengthProperty.vue.d.ts +20 -0
  57. package/dist/builder/props/CompoundLengthProperty.vue.d.ts.map +1 -0
  58. package/dist/builder/props/StyleProps.vue.d.ts +1 -0
  59. package/dist/builder/props/StyleProps.vue.d.ts.map +1 -1
  60. package/dist/builder/schemaMigrateV1.d.ts +7 -0
  61. package/dist/builder/schemaMigrateV1.d.ts.map +1 -1
  62. package/dist/builder/schemaNormalize.d.ts.map +1 -1
  63. package/dist/builder/{useSchemaValidation.d.ts → useAuthoringFindings.d.ts} +8 -8
  64. package/dist/builder/useAuthoringFindings.d.ts.map +1 -0
  65. package/dist/builder/useBuilderDnd.d.ts +8 -1
  66. package/dist/builder/useBuilderDnd.d.ts.map +1 -1
  67. package/dist/builder/useCanvasZoom.d.ts +50 -0
  68. package/dist/builder/useCanvasZoom.d.ts.map +1 -0
  69. package/dist/builder/usePageBuilder.d.ts +2 -0
  70. package/dist/builder/usePageBuilder.d.ts.map +1 -1
  71. package/dist/builder/usePageCompositions.d.ts +71 -0
  72. package/dist/builder/usePageCompositions.d.ts.map +1 -0
  73. package/dist/builderContext-B3rX2dxZ.js +4 -0
  74. package/dist/compositions.d.ts +79 -0
  75. package/dist/compositions.d.ts.map +1 -0
  76. package/dist/conditions.d.ts +8 -0
  77. package/dist/conditions.d.ts.map +1 -0
  78. package/dist/context.d.ts +17 -3
  79. package/dist/context.d.ts.map +1 -1
  80. package/dist/documentValidation.d.ts +12 -0
  81. package/dist/documentValidation.d.ts.map +1 -0
  82. package/dist/elements/builtins.d.ts.map +1 -1
  83. package/dist/elements/button/ButtonInspector.vue.d.ts.map +1 -1
  84. package/dist/elements/button/ButtonRenderer.vue.d.ts.map +1 -1
  85. package/dist/elements/button/index.d.ts +2 -2
  86. package/dist/elements/button/index.d.ts.map +1 -1
  87. package/dist/elements/card/CardInspector.vue.d.ts.map +1 -1
  88. package/dist/elements/card/index.d.ts.map +1 -1
  89. package/dist/elements/checkbox/CheckboxDefaultInput.vue.d.ts.map +1 -1
  90. package/dist/elements/checkbox/CheckboxInspector.vue.d.ts.map +1 -1
  91. package/dist/elements/checkbox/CheckboxRenderer.vue.d.ts.map +1 -1
  92. package/dist/elements/checkbox/index.d.ts.map +1 -1
  93. package/dist/elements/date-input/DateInputDefaultInput.vue.d.ts.map +1 -1
  94. package/dist/elements/date-input/DateInputInspector.vue.d.ts.map +1 -1
  95. package/dist/elements/date-input/index.d.ts.map +1 -1
  96. package/dist/elements/datetime-input/DateTimeInputDefaultInput.vue.d.ts.map +1 -1
  97. package/dist/elements/datetime-input/DateTimeInputInspector.vue.d.ts.map +1 -1
  98. package/dist/elements/datetime-input/index.d.ts.map +1 -1
  99. package/dist/elements/feedback/FeedbackInspector.vue.d.ts +8 -0
  100. package/dist/elements/feedback/FeedbackInspector.vue.d.ts.map +1 -0
  101. package/dist/elements/feedback/FeedbackPreview.vue.d.ts +7 -0
  102. package/dist/elements/feedback/FeedbackPreview.vue.d.ts.map +1 -0
  103. package/dist/elements/{stack/StackInspector.vue.d.ts → feedback/FeedbackRenderer.vue.d.ts} +3 -4
  104. package/dist/elements/feedback/FeedbackRenderer.vue.d.ts.map +1 -0
  105. package/dist/elements/feedback/index.d.ts +6 -0
  106. package/dist/elements/feedback/index.d.ts.map +1 -0
  107. package/dist/elements/heading/HeadingInspector.vue.d.ts.map +1 -1
  108. package/dist/elements/heading/index.d.ts.map +1 -1
  109. package/dist/elements/image/ImageInspector.vue.d.ts.map +1 -1
  110. package/dist/elements/image/index.d.ts.map +1 -1
  111. package/dist/elements/link/LinkInspector.vue.d.ts +1 -1
  112. package/dist/elements/link/LinkInspector.vue.d.ts.map +1 -1
  113. package/dist/elements/link/index.d.ts +1 -2
  114. package/dist/elements/link/index.d.ts.map +1 -1
  115. package/dist/elements/multi-select/MultiSelectDefaultInput.vue.d.ts.map +1 -1
  116. package/dist/elements/multi-select/MultiSelectInspector.vue.d.ts.map +1 -1
  117. package/dist/elements/multi-select/index.d.ts.map +1 -1
  118. package/dist/elements/note/NoteInspector.vue.d.ts.map +1 -1
  119. package/dist/elements/number-input/NumberInputDefaultInput.vue.d.ts.map +1 -1
  120. package/dist/elements/number-input/NumberInputInspector.vue.d.ts.map +1 -1
  121. package/dist/elements/number-input/index.d.ts.map +1 -1
  122. package/dist/elements/otp-input/OtpInputInspector.vue.d.ts.map +1 -1
  123. package/dist/elements/otp-input/index.d.ts.map +1 -1
  124. package/dist/elements/paragraph/index.d.ts.map +1 -1
  125. package/dist/elements/password-input/PasswordInputInspector.vue.d.ts.map +1 -1
  126. package/dist/elements/password-input/index.d.ts.map +1 -1
  127. package/dist/elements/previewUtils.d.ts.map +1 -1
  128. package/dist/elements/radio-group/RadioGroupDefaultInput.vue.d.ts.map +1 -1
  129. package/dist/elements/radio-group/RadioGroupInspector.vue.d.ts.map +1 -1
  130. package/dist/elements/radio-group/index.d.ts.map +1 -1
  131. package/dist/elements/registry.d.ts +265 -2
  132. package/dist/elements/registry.d.ts.map +1 -1
  133. package/dist/elements/repeat/RepeatInspector.vue.d.ts +8 -0
  134. package/dist/elements/repeat/RepeatInspector.vue.d.ts.map +1 -0
  135. package/dist/elements/repeat/RepeatRenderer.vue.d.ts +29 -0
  136. package/dist/elements/repeat/RepeatRenderer.vue.d.ts.map +1 -0
  137. package/dist/elements/repeat/index.d.ts +10 -0
  138. package/dist/elements/repeat/index.d.ts.map +1 -0
  139. package/dist/elements/section/SectionInspector.vue.d.ts.map +1 -1
  140. package/dist/elements/section/index.d.ts.map +1 -1
  141. package/dist/elements/select/SelectDefaultInput.vue.d.ts.map +1 -1
  142. package/dist/elements/select/SelectInspector.vue.d.ts.map +1 -1
  143. package/dist/elements/select/index.d.ts.map +1 -1
  144. package/dist/elements/spacer/SpacerInspector.vue.d.ts.map +1 -1
  145. package/dist/elements/stack/StackRenderer.vue.d.ts.map +1 -1
  146. package/dist/elements/stack/index.d.ts.map +1 -1
  147. package/dist/elements/switch/SwitchDefaultInput.vue.d.ts.map +1 -1
  148. package/dist/elements/switch/SwitchInspector.vue.d.ts.map +1 -1
  149. package/dist/elements/switch/index.d.ts.map +1 -1
  150. package/dist/elements/text-input/TextInputInspector.vue.d.ts.map +1 -1
  151. package/dist/elements/text-input/index.d.ts.map +1 -1
  152. package/dist/elements/usePageElement.d.ts +6 -2
  153. package/dist/elements/usePageElement.d.ts.map +1 -1
  154. package/dist/elements/visual-markup/VisualMarkupInspector.vue.d.ts +10 -0
  155. package/dist/elements/visual-markup/VisualMarkupInspector.vue.d.ts.map +1 -0
  156. package/dist/elements/visual-markup/VisualMarkupPreview.vue.d.ts +7 -0
  157. package/dist/elements/visual-markup/VisualMarkupPreview.vue.d.ts.map +1 -0
  158. package/dist/elements/visual-markup/VisualMarkupRenderer.vue.d.ts +7 -0
  159. package/dist/elements/visual-markup/VisualMarkupRenderer.vue.d.ts.map +1 -0
  160. package/dist/elements/visual-markup/index.d.ts +6 -0
  161. package/dist/elements/visual-markup/index.d.ts.map +1 -0
  162. package/dist/elements/visual-markup/visualDocument.d.ts +13 -0
  163. package/dist/elements/visual-markup/visualDocument.d.ts.map +1 -0
  164. package/dist/expressionAuthoring-7iAyadA3.js +74 -0
  165. package/dist/index.css +1 -1
  166. package/dist/index.d.ts +32 -2
  167. package/dist/index.d.ts.map +1 -1
  168. package/dist/index.js +8571 -3448
  169. package/dist/pageCode-echPQdna.js +455 -0
  170. package/dist/pageCode.d.ts +101 -0
  171. package/dist/pageCode.d.ts.map +1 -0
  172. package/dist/pageCodeAuthoring-C8grEAUf.js +123 -0
  173. package/dist/responsive.d.ts +7 -0
  174. package/dist/responsive.d.ts.map +1 -0
  175. package/dist/runtime/PageRuntimeHost.d.ts +57 -0
  176. package/dist/runtime/PageRuntimeHost.d.ts.map +1 -0
  177. package/dist/runtime/PageScriptRuntime.d.ts +62 -0
  178. package/dist/runtime/PageScriptRuntime.d.ts.map +1 -0
  179. package/dist/runtime/pageScriptRuntime.worker.d.ts +1 -0
  180. package/dist/runtime/pageScriptRuntime.worker.d.ts.map +1 -0
  181. package/dist/runtime/runtimeProtocol.d.ts +150 -0
  182. package/dist/runtime/runtimeProtocol.d.ts.map +1 -0
  183. package/dist/runtime/usePageCodeRuntime.d.ts +32 -0
  184. package/dist/runtime/usePageCodeRuntime.d.ts.map +1 -0
  185. package/dist/runtime-worker.js +240 -0
  186. package/dist/runtimeBindings.d.ts +32 -0
  187. package/dist/runtimeBindings.d.ts.map +1 -0
  188. package/dist/runtimeExpressions.d.ts +16 -0
  189. package/dist/runtimeExpressions.d.ts.map +1 -0
  190. package/dist/runtimeProtocol-Bg1C-O0c.js +36 -0
  191. package/dist/runtimeWorkerEntry.d.ts +2 -0
  192. package/dist/runtimeWorkerEntry.d.ts.map +1 -0
  193. package/dist/schema.d.ts +298 -31
  194. package/dist/schema.d.ts.map +1 -1
  195. package/dist/styleMapping.d.ts +7 -0
  196. package/dist/styleMapping.d.ts.map +1 -1
  197. package/dist/translations.d.ts +8 -0
  198. package/dist/translations.d.ts.map +1 -0
  199. package/dist/visualDocument-DKjWBfpW.js +139 -0
  200. package/package.json +24 -6
  201. package/dist/builder/useSchemaValidation.d.ts.map +0 -1
  202. package/dist/elements/stack/StackInspector.vue.d.ts.map +0 -1
@@ -0,0 +1,350 @@
1
+ # IDP integration guide
2
+
3
+ This guide is the integration contract for Page Builder 2.20. It separates
4
+ tenant-owned data from application-owned authority so an IDP can offer visual
5
+ customization without turning a page document into application code.
6
+
7
+ ## 1. Install the matching package set
8
+
9
+ Install the Page Builder and its Cocoar peers at the same release version. Pinning
10
+ the set prevents an authoring package from being combined accidentally with an
11
+ older renderer, localization or ScriptEditor runtime:
12
+
13
+ ```bash
14
+ pnpm add --save-exact \
15
+ @cocoar/vue-page-builder@2.20.0 \
16
+ @cocoar/vue-ui@2.20.0 \
17
+ @cocoar/vue-localization@2.20.0 \
18
+ @cocoar/vue-script-editor@2.20.0 \
19
+ monaco-editor@^0.55.1
20
+ ```
21
+
22
+ ### Prerelease channels
23
+
24
+ Use the `alpha` channel for feature-branch integration tests without merging the
25
+ implementation into `develop`. Alpha packages are hosted by GitHub Packages
26
+ under the physical `@cocoar-dev` scope. Configure the registry and a GitHub token
27
+ with `read:packages` in the consuming project:
28
+
29
+ ```ini
30
+ # .npmrc
31
+ @cocoar-dev:registry=https://npm.pkg.github.com
32
+ //npm.pkg.github.com/:_authToken=${GITHUB_PACKAGES_TOKEN}
33
+ ```
34
+
35
+ Install them through pnpm aliases so application imports keep the stable
36
+ `@cocoar/*` names:
37
+
38
+ ```bash
39
+ pnpm add --save-exact \
40
+ "@cocoar/vue-page-builder@npm:@cocoar-dev/vue-page-builder@alpha" \
41
+ "@cocoar/vue-ui@npm:@cocoar-dev/vue-ui@alpha" \
42
+ "@cocoar/vue-localization@npm:@cocoar-dev/vue-localization@alpha" \
43
+ "@cocoar/vue-script-editor@npm:@cocoar-dev/vue-script-editor@alpha" \
44
+ monaco-editor
45
+ ```
46
+
47
+ The dependency keys and all source imports remain `@cocoar/*`; only the package
48
+ source in `package.json` points at the temporary GitHub package.
49
+
50
+ The shared `develop` prerelease remains available on the `beta` channel:
51
+
52
+ ```bash
53
+ pnpm add @cocoar/vue-page-builder@beta
54
+ ```
55
+
56
+ Import `@cocoar/vue-page-builder/styles` once in the authoring application and
57
+ the application that renders the authentication views.
58
+
59
+ ### Register all Monaco workers used by the Builder
60
+
61
+ The Page Builder opens Monaco in JavaScript **and JSON** mode. The consuming
62
+ authoring application therefore has to route both language labels to their
63
+ matching Monaco workers before the first Builder mounts:
64
+
65
+ ```ts
66
+ // src/main.ts (Vite)
67
+ import EditorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
68
+ import TsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker';
69
+ import JsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker';
70
+
71
+ self.MonacoEnvironment = {
72
+ getWorker(_workerId, label) {
73
+ if (label === 'typescript' || label === 'javascript') return new TsWorker();
74
+ if (label === 'json') return new JsonWorker();
75
+ return new EditorWorker();
76
+ },
77
+ };
78
+ ```
79
+
80
+ Do not route `json` to the generic `EditorWorker`. The JSON language client then
81
+ requests methods that worker cannot provide and logs errors such as
82
+ `Missing requestHandler or method: doValidation`, `findDocumentColors`, or
83
+ `getFoldingRanges`. Script execution is unaffected, but JSON validation,
84
+ folding and color support are unavailable until the correct worker is used.
85
+
86
+ ### Theme and host style registration
87
+
88
+ Resolve the application/client theme in the IDP and pass stable primitives to
89
+ the generic UI scope. Runtime and Builder preview intentionally share this one
90
+ implementation:
91
+
92
+ ```vue
93
+ <CoarThemeScope :theme="applicationTheme" mode="auto">
94
+ <CoarPageRenderer :schema :config />
95
+ </CoarThemeScope>
96
+
97
+ <CoarPageBuilder
98
+ v-model="schema"
99
+ :config="config"
100
+ :preview-theme="applicationTheme"
101
+ preview-theme-mode="dark"
102
+ />
103
+ ```
104
+
105
+ `previewTheme` is scoped to the embedded renderer; the Builder toolbar,
106
+ Properties panel, dialogs, and Monaco keep the administration theme.
107
+
108
+ ## 2. Persist one versioned document per scope and slot
109
+
110
+ The recommended storage key is:
111
+
112
+ ```text
113
+ tenant / application-or-realm / slot / revision
114
+ ```
115
+
116
+ The first preset release contains these slots:
117
+
118
+ - `login`
119
+ - `password-forgot`
120
+ - `logout`
121
+ - `consent`
122
+
123
+ The host owns the starting document and the `PageConfig` for each slot; the
124
+ package ships neither. Persist the complete `PageNode` JSON, including its `schemaVersion`. Treat saved
125
+ documents as immutable revisions. Draft, published revision, rollback target,
126
+ ETag and audit metadata belong to the IDP record around that JSON rather than to
127
+ the generic page schema.
128
+
129
+ Recommended lifecycle:
130
+
131
+ ```text
132
+ default -> draft -> server validation -> preview -> publish -> rollback/reset
133
+ ```
134
+
135
+ Never overwrite the last published revision while saving a draft. Use an ETag or
136
+ revision number to reject concurrent saves.
137
+
138
+ ## 3. Validate on both boundaries
139
+
140
+ Normalize and validate when loading an old document in the authoring UI:
141
+
142
+ ```ts
143
+ const normalized = normalizePageSchema(storedDocument, config);
144
+ const validation = validatePageDocument(normalized.schema, config);
145
+ ```
146
+
147
+ Repeat equivalent validation in the trusted publish endpoint. Client validation
148
+ is authoring feedback, not authorization. Reject unsupported schema versions,
149
+ disallowed element types, document-limit violations and invalid host-context
150
+ bindings before a revision becomes active. Anything the tenant must not remove
151
+ — a compliance notice on a consent screen — is checked here too: the library
152
+ has no mechanism that could hold it in the browser.
153
+
154
+ Authentication, consent, ticket ownership, redirect validation and field-level
155
+ authorization always remain authoritative on the server.
156
+
157
+ ## 4. Define the application host once
158
+
159
+ `definePageRuntimeHost()` creates an application-owned capability catalogue and
160
+ grant policy. It does not create page state or a Worker by itself. Reuse this
161
+ object for renderer sessions throughout the application.
162
+
163
+ ```ts
164
+ export const idpPageRuntimeHost = definePageRuntimeHost({
165
+ endowments: {
166
+ api: {
167
+ call: withRuntimeEndowmentContext(
168
+ ({ signal, tenantId, pageId }, operation, payload) =>
169
+ idpPageApi.call({
170
+ signal,
171
+ tenantId,
172
+ pageId,
173
+ operation: String(operation),
174
+ payload,
175
+ }),
176
+ ),
177
+ },
178
+ },
179
+ grants: ({ pageId, definition }) => {
180
+ if (!pageId.startsWith('auth:')) return [];
181
+ if (!definition.id.startsWith('element-action:')) return [];
182
+ return ['api'];
183
+ },
184
+ });
185
+ ```
186
+
187
+ Objects not listed in `endowments` cannot be granted. Objects listed but not
188
+ returned by `grants` are not described to that Worker session. Pure compute
189
+ bindings can never receive endowments. Keep the facade narrow: expose named IDP
190
+ operations, not a general-purpose URL fetcher.
191
+
192
+ ## 5. Create one runtime session per rendered page
193
+
194
+ ```ts
195
+ const {
196
+ pageCodeValues,
197
+ onRuntimeChange,
198
+ runPageAction,
199
+ } = usePageCodeRuntime({
200
+ pageId: computed(() => `auth:${slot.value}`),
201
+ tenantId,
202
+ schema,
203
+ context,
204
+ viewport,
205
+ runtimeHost: idpPageRuntimeHost,
206
+ });
207
+ ```
208
+
209
+ ```vue
210
+ <CoarPageRenderer
211
+ :schema="schema"
212
+ :config="config"
213
+ :runtime-context="context"
214
+ :viewport-width="viewport.width"
215
+ :page-code-values="pageCodeValues"
216
+ :actions="hostActions"
217
+ :on-action="runPageAction"
218
+ @runtime-change="onRuntimeChange"
219
+ />
220
+ ```
221
+
222
+ The explicit `actions` map wins for host actions. The dynamic `onAction`
223
+ dispatcher handles internal Page-Code action ids through `runPageAction`. The
224
+ Auth Customization Lab is the executable reference wiring. Each composable
225
+ instance creates an isolated SES Worker session. Pages never share script
226
+ globals or Page State. Unmounting the owning Vue component disposes the session.
227
+
228
+ ## 6. Keep navigation and authentication as host actions
229
+
230
+ Page documents may configure presentation, validation, element actions and
231
+ Page State. They do not create or delete elements at runtime, change an element
232
+ type/name, navigate directly, read cookies, access the DOM or call ambient
233
+ browser APIs.
234
+
235
+ Map stable action ids to trusted application handlers for operations such as:
236
+
237
+ - login submission;
238
+ - forgot-password submission;
239
+ - consent allow/deny;
240
+ - navigation back to login;
241
+ - external provider selection.
242
+
243
+ On errors, keep the renderer mounted and pass field/form errors back to its
244
+ feedback model. Do not discard entered values on HTTP 500, timeout or disconnect.
245
+
246
+ ## 7. Localization
247
+
248
+ The page root owns tenant translations. Elements reference keys through
249
+ translation bindings; the Builder's Translations tab edits the catalogue.
250
+ Runtime lookup order is page translation, host localization store, binding
251
+ fallback, then key. Keep security- or protocol-owned messages in the host
252
+ catalogue when tenants must not replace them.
253
+
254
+ ## 8. Deployment and production boundary
255
+
256
+ Vite does not relocate `import.meta.url` assets while dependency pre-bundling.
257
+ The PageBuilder therefore publishes the Worker runtime as the isolated
258
+ `runtime-worker` subpath. Keep only this small entry out of the optimizer; the
259
+ PageBuilder, UI, Script Editor and their transitive dependencies remain fully
260
+ optimized:
261
+
262
+ ```ts
263
+ // vite.config.ts
264
+ export default defineConfig({
265
+ optimizeDeps: {
266
+ exclude: ['@cocoar/vue-page-builder/runtime-worker'],
267
+ },
268
+ });
269
+ ```
270
+
271
+ Do not exclude the complete `@cocoar/vue-page-builder` package. That would also
272
+ skip optimization of CommonJS dependencies used by its UI/editor peers. The
273
+ consuming production build emits `pageScriptRuntime.worker-<hash>.js` under its
274
+ own configured `base`.
275
+
276
+ Serve that file as a same-origin module Worker and permit it through
277
+ `worker-src 'self'` (the application may keep `blob:` for unrelated Workers). SES uses
278
+ `Compartment.evaluate()` inside the Worker, so the Worker response must not
279
+ inherit an application CSP that forbids dynamic evaluation. Apply the strict
280
+ `script-src 'self'` policy to the HTML response, not indiscriminately to every
281
+ static asset. If the server requires a CSP header on the Worker response, scope
282
+ `script-src 'self' 'unsafe-eval'` to that response only. Do **not** add
283
+ `unsafe-eval` to the IDP document/application CSP.
284
+
285
+ The packed-consumer CI and release gates verify this from tarballs on Linux and
286
+ Windows with `vite --force`, a production build, a neutral non-root
287
+ `/consumer-app/` base and a browser boot under the strict document CSP.
288
+
289
+ ### Decorative visual documents
290
+
291
+ Use the built-in `visual-markup` element only for non-semantic decoration.
292
+ `PageConfig.visualMarkup` is the host-controlled capability boundary for
293
+ approved font data/blob URLs and sanitized CSS custom properties. The page
294
+ author controls the node's allowlisted HTML, inline SVG and local CSS, while
295
+ the renderer supplies an empty iframe sandbox and a restrictive document CSP.
296
+ No JavaScript, form control, navigation or network API is available.
297
+
298
+ Pass the same `PageConfig` to the Builder and Runtime. The Builder's Preview tab
299
+ uses the real renderer; it intentionally does not grant a more permissive
300
+ preview environment. Size the opaque iframe through the outer node style—it
301
+ cannot inspect its content to auto-report height. Invalid or oversized visual
302
+ content is a node-local error: the iframe stays absent while the remaining IDP
303
+ form renders normally. The host's whole-document fallback is reserved for an
304
+ invalid or failed published page, not a rejected decorative node.
305
+
306
+ Before general tenant production rollout, complete the product threat model,
307
+ independent security review, browser/mobile matrix, operational quotas and
308
+ server-side publication checks. A stable library version supplies the technical
309
+ boundary; it does not replace the consuming SaaS product's own security and
310
+ publication review.
311
+
312
+ ### Reusable composition repository
313
+
314
+ Reusable subtrees belong to the authoring workflow, not to the IDP request
315
+ runtime. Supply a host-owned `PageCompositionRepository` to `CoarPageBuilder`.
316
+ The Builder stores exact immutable version tokens, materializes the complete
317
+ subtree in the draft, and preserves instance ids/names while applying an update.
318
+ The host repository should enforce tenant ownership and optimistic concurrency
319
+ through `baseVersion` on `publish`.
320
+
321
+ For a SaaS authoring host, expose definitions separately from pages:
322
+
323
+ - **Pages** embed the Builder with `composition-management="consume"` and may
324
+ drag definitions from the **Compositions** palette group, select another
325
+ immutable version, update to latest or detach pinned instances.
326
+ - **Compositions** edit one standalone definition tree and call repository
327
+ `create()` / `publish()` at the host boundary.
328
+
329
+ Use `@open-composition="openComposition"` on `CoarPageBuilder` to connect the
330
+ Properties action to that separate host area. The event carries the exact
331
+ pinned `{ id, version }`; the host should open that version rather than latest.
332
+ The palette drag payload is editor-only. A successful drop is persisted solely
333
+ as the already-defined materialized nodes plus `composition` and
334
+ `compositionOrigins`; no wrapper or composition element type is introduced.
335
+
336
+ Removing a composition instance from Login therefore changes only Login. It
337
+ does not mutate the definition, Logout, or any other consumer. Publishing a new
338
+ definition version also leaves every page pinned until its author updates it.
339
+
340
+ At the server-side publication boundary:
341
+
342
+ 1. Load the tenant-owned authoring document.
343
+ 2. Run `validatePageCompositionReferences(document, repository)` and reject
344
+ missing versions or cycles.
345
+ 3. Run the normal page-document validation and security checks.
346
+ 4. Store `compilePageCompositions(document)` as the immutable runtime document.
347
+
348
+ The runtime document contains no composition reference and never loads a
349
+ repository. A missing repository therefore affects authoring/update only, not a
350
+ previously materialized draft or an already published IDP page.