@cocoar/vue-page-builder 2.19.0 → 2.20.0-beta.19

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