openyida 2026.7.18 → 2026.7.21

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 (200) hide show
  1. package/README.md +37 -2
  2. package/bin/yida.js +113 -18
  3. package/docs/capabilities.md +202 -0
  4. package/lib/agent-center/agent-center.js +2 -3
  5. package/lib/app/app-list.js +3 -4
  6. package/lib/app/build-page.js +13 -6
  7. package/lib/app/check-page.js +16 -6
  8. package/lib/app/compile.js +17 -7
  9. package/lib/app/create-app.js +14 -2
  10. package/lib/app/create-form/api-path.js +25 -0
  11. package/lib/app/create-form/args.js +13 -0
  12. package/lib/app/create-form/commands.js +4 -0
  13. package/lib/app/create-form/definition-reader.js +23 -23
  14. package/lib/app/create-form/field-normalizers.js +26 -7
  15. package/lib/app/create-form/schema-patch.js +4 -1
  16. package/lib/app/create-form.js +155 -68
  17. package/lib/app/create-page.js +47 -10
  18. package/lib/app/generate-page.js +20 -1
  19. package/lib/app/get-form-config.js +2 -1
  20. package/lib/app/get-schema.js +67 -15
  21. package/lib/app/import-app.js +94 -42
  22. package/lib/app/list-forms.js +4 -8
  23. package/lib/app/page-ir.js +140 -0
  24. package/lib/app/publish.js +289 -556
  25. package/lib/app/schema-field-resolution.js +370 -0
  26. package/lib/app/services/app-reader.js +85 -0
  27. package/lib/app/services/app-service.js +235 -0
  28. package/lib/app/services/canvas-page-compiler.js +91 -0
  29. package/lib/app/services/canvas-page-schema-builder.js +149 -0
  30. package/lib/app/services/field-bindings.js +68 -0
  31. package/lib/app/services/form-compiler.js +1922 -0
  32. package/lib/app/services/form-mode-service.js +182 -0
  33. package/lib/app/services/form-schema-patcher.js +333 -0
  34. package/lib/app/services/form-schema-reader.js +59 -0
  35. package/lib/app/services/form-service.js +379 -0
  36. package/lib/app/services/form-validation.js +562 -0
  37. package/lib/app/services/native-page-compiler.js +92 -0
  38. package/lib/app/services/native-page-schema-builder.js +428 -0
  39. package/lib/app/services/page-resource-service.js +185 -0
  40. package/lib/app/update-app.js +22 -9
  41. package/lib/app/update-form-config.js +4 -2
  42. package/lib/asset/asset-cmd.js +19 -6
  43. package/lib/auth/oauth-loopback.js +376 -15
  44. package/lib/auth/token-auth.js +34 -3
  45. package/lib/auth/token-store.js +22 -4
  46. package/lib/basic-info/basic-info.js +2 -1
  47. package/lib/bridge/bridge.js +43 -18
  48. package/lib/core/agent-capabilities.js +5 -3
  49. package/lib/core/command-errors.js +38 -0
  50. package/lib/core/command-manifest.js +59 -1
  51. package/lib/core/copy.js +12 -0
  52. package/lib/core/doctor.js +15 -4
  53. package/lib/core/env-cmd.js +1 -1
  54. package/lib/core/env.js +7 -6
  55. package/lib/core/i18n.js +66 -8
  56. package/lib/core/legacy-schema-guard.js +408 -0
  57. package/lib/core/locales/en.js +38 -46
  58. package/lib/core/locales/zh.js +30 -46
  59. package/lib/core/sample.js +12 -2
  60. package/lib/core/utils.js +334 -66
  61. package/lib/core/yida-client.js +108 -5
  62. package/lib/corp-efficiency/corp-efficiency.js +2 -2
  63. package/lib/corp-manager/corp-manager.js +3 -3
  64. package/lib/formula/evaluate.js +11 -68
  65. package/lib/formula/field-refs.js +83 -0
  66. package/lib/i18n-management/i18n-management.js +2 -3
  67. package/lib/process/configure-process.js +44 -1992
  68. package/lib/process/create-process.js +54 -87
  69. package/lib/process/preview-process.js +20 -8
  70. package/lib/process/services/process-compiler.js +2056 -0
  71. package/lib/process/services/process-reader.js +232 -0
  72. package/lib/process/services/process-resource-service.js +571 -0
  73. package/lib/process/services/process-service.js +122 -0
  74. package/lib/process/services/process-stage-checkpoint.js +246 -0
  75. package/lib/report/append.js +7 -26
  76. package/lib/report/http.js +31 -5
  77. package/lib/report/index.js +10 -2
  78. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
  79. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
  80. package/lib/samples/yida-canvas-custom-page/dashboard-starter.canvas.jsx +5 -2
  81. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
  82. package/lib/samples/yida-canvas-custom-page/portal-shell-home.canvas.jsx +2 -2
  83. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +206 -10
  84. package/lib/samples/yida-custom-page/data-management.oyd.jsx +14 -3
  85. package/lib/samples/yida-custom-page/design-tokens.js +2 -2
  86. package/lib/samples/yida-custom-page/detail-profile.oyd.jsx +1 -1
  87. package/lib/samples/yida-custom-page/portal-shell-home.oyd.jsx +7 -2
  88. package/lib/samples/yida-custom-page/split-pane-detail.oyd.jsx +2 -1
  89. package/lib/schema/adapters/app-adapter.js +210 -0
  90. package/lib/schema/adapters/form-adapter.js +1362 -0
  91. package/lib/schema/adapters/keys.js +19 -0
  92. package/lib/schema/adapters/page-adapter.js +566 -0
  93. package/lib/schema/adapters/process-adapter.js +519 -0
  94. package/lib/schema/applier.js +1878 -0
  95. package/lib/schema/apply-store.js +1083 -0
  96. package/lib/schema/command.js +645 -0
  97. package/lib/schema/dependency-graph.js +83 -0
  98. package/lib/schema/errors.js +481 -0
  99. package/lib/schema/hash.js +9 -0
  100. package/lib/schema/manifest-limits.js +177 -0
  101. package/lib/schema/manifest-loader.js +309 -0
  102. package/lib/schema/manifest-schema-v1.json +193 -0
  103. package/lib/schema/normalize-manifest.js +281 -0
  104. package/lib/schema/page-canvas-foundation.js +447 -0
  105. package/lib/schema/page-data-source-builder.js +561 -0
  106. package/lib/schema/page-foundation.js +556 -0
  107. package/lib/schema/page-source-loader.js +314 -0
  108. package/lib/schema/planner.js +691 -0
  109. package/lib/schema/remote-dispatch-boundary.js +39 -0
  110. package/lib/schema/remote-missing.js +21 -0
  111. package/lib/schema/remote-reader.js +189 -0
  112. package/lib/schema/resource-registry.js +157 -0
  113. package/lib/schema/server-revision.js +71 -0
  114. package/lib/schema/sort.js +28 -0
  115. package/lib/schema/state-store.js +589 -0
  116. package/package.json +10 -8
  117. package/scripts/check-release-risks.js +254 -0
  118. package/scripts/generate-command-docs.js +6 -1
  119. package/scripts/i18n-baseline.json +11 -11
  120. package/scripts/postinstall.js +8 -12
  121. package/scripts/validate-ci.sh +15 -11
  122. package/scripts/validate-i18n.js +30 -9
  123. package/scripts/validate-package-size.js +5 -2
  124. package/scripts/validate-skills.js +4 -0
  125. package/scripts/validate-structure.js +15 -0
  126. package/yida-skills/SKILL.md +117 -30
  127. package/yida-skills/references/schema-as-code-phase1.md +99 -0
  128. package/yida-skills/references/setup-and-env.md +59 -59
  129. package/yida-skills/references/task-retrospective.md +6 -6
  130. package/yida-skills/skills/yida-app/SKILL.md +78 -17
  131. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
  132. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
  133. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +15 -0
  134. package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
  135. package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
  136. package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
  137. package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
  138. package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
  139. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  140. package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
  141. package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
  142. package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
  143. package/yida-skills/skills/yida-integration/SKILL.md +7 -1
  144. package/yida-skills/skills/yida-login/SKILL.md +50 -99
  145. package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
  146. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
  147. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
  148. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
  149. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
  150. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
  151. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
  152. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
  153. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
  154. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
  155. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
  156. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
  157. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
  158. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
  159. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
  160. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
  161. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
  162. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
  163. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
  164. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
  165. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
  166. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
  167. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
  168. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
  169. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
  170. package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
  171. package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
  172. package/yida-skills/skills/yida-report/SKILL.md +9 -235
  173. package/yida-skills/skills/yida-report/references/schema-builder-details.md +239 -0
  174. package/yida-skills/skills/yida-skill-evaluator/SKILL.md +170 -0
  175. package/yida-skills/skills-index.json +238 -54
  176. package/lib/core/locales/ar.js +0 -834
  177. package/lib/core/locales/de.js +0 -834
  178. package/lib/core/locales/es.js +0 -834
  179. package/lib/core/locales/fr.js +0 -834
  180. package/lib/core/locales/hi.js +0 -834
  181. package/lib/core/locales/ja.js +0 -1227
  182. package/lib/core/locales/ko.js +0 -836
  183. package/lib/core/locales/pt.js +0 -834
  184. package/lib/core/locales/vi.js +0 -834
  185. package/lib/core/locales/zh-HK.js +0 -1263
  186. package/project/pages/src/demo-birthday-game.oyd.jsx +0 -832
  187. package/project/pages/src/demo-chip-insight.oyd.jsx +0 -983
  188. package/project/pages/src/demo-compat-smoke.oyd.jsx +0 -58
  189. package/project/pages/src/demo-crm-batch-entry.oyd.jsx +0 -805
  190. package/project/pages/src/demo-crm-dashboard.oyd.jsx +0 -677
  191. package/project/pages/src/demo-future-vision-2026.oyd.jsx +0 -1102
  192. package/project/pages/src/demo-ppt.oyd.jsx +0 -1192
  193. package/project/pages/src/demo-salary-calculator.oyd.jsx +0 -904
  194. package/project/pages/src/openyida-knowledge-doc.oyd.jsx +0 -1714
  195. package/yida-skills/skills/large-file-write/SKILL.md +0 -93
  196. package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
  197. package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
  198. package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
  199. package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
  200. package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
@@ -0,0 +1,561 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('crypto');
4
+ const { isDeepStrictEqual } = require('util');
5
+ const { schemaError } = require('./errors');
6
+ const { hashStable } = require('./state-store');
7
+ const {
8
+ buildDefaultPageDataSource,
9
+ buildNativePageSchemaContent,
10
+ extractPageDataSource,
11
+ mergePageDataSource,
12
+ } = require('../app/services/native-page-schema-builder');
13
+ const {
14
+ buildCanvasPageSchemaContent,
15
+ } = require('../app/services/canvas-page-schema-builder');
16
+ const {
17
+ NATIVE_PAGE_PROFILE,
18
+ isCompiledNativePage,
19
+ } = require('../app/services/native-page-compiler');
20
+ const {
21
+ CANVAS_PAGE_PROFILE,
22
+ isCompiledCanvasPage,
23
+ } = require('../app/services/canvas-page-compiler');
24
+ const {
25
+ projectCanvasPageSchema,
26
+ } = require('./page-canvas-foundation');
27
+ const {
28
+ computeNativePageShellFingerprint,
29
+ createNativePageShellProfile,
30
+ projectNativePageSchema,
31
+ } = require('./page-foundation');
32
+
33
+ const DISPLAY_FORM_TYPE = 'display';
34
+ const INITIAL_PROFILE_CONTRACT_VERSION = 1;
35
+ const HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
36
+ const PROFILE_ID_PATTERN = /^[a-z][a-z0-9._-]{0,63}$/;
37
+ const INITIAL_PROFILES = new WeakSet();
38
+ const INITIAL_ROOT_KEYS = Object.freeze(['gmtModified', 'i18nData', 'pages', 'status']);
39
+ const INITIAL_PAGE_KEYS = Object.freeze(['componentsTree']);
40
+ const INITIAL_TREE_KEYS = Object.freeze(['dataSource']);
41
+ const INITIAL_DATA_SOURCE_KEYS = Object.freeze([
42
+ 'globalConfig',
43
+ 'list',
44
+ 'offline',
45
+ 'online',
46
+ 'sync',
47
+ ]);
48
+
49
+ function createDataSourceOnlyShellProfile(input = {}) {
50
+ const profileId = normalizeProfileId(input.profileId);
51
+ const fingerprint = normalizeHash(
52
+ input.fingerprint,
53
+ 'SCHEMA_PAGE_FOUNDATION_INITIAL_PROFILE_INVALID'
54
+ );
55
+ const profile = Object.freeze({
56
+ contractVersion: INITIAL_PROFILE_CONTRACT_VERSION,
57
+ fingerprint,
58
+ profileId,
59
+ });
60
+ INITIAL_PROFILES.add(profile);
61
+ return profile;
62
+ }
63
+
64
+ function computeDataSourceOnlyShellFingerprint(schemaInput) {
65
+ const schema = normalizeSchema(schemaInput);
66
+ inspectDataSourceOnlyShell(schema, 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID');
67
+ return hashStable(normalizeInitialFingerprint(schema));
68
+ }
69
+
70
+ function projectDataSourceOnlyShell(input = {}) {
71
+ const observedIdentity = normalizeObservedIdentity(input);
72
+ const shellProfile = requireInitialProfile(input.shellProfile);
73
+ const schema = normalizeSchema(input.schema);
74
+ const structure = inspectDataSourceOnlyShell(schema, 'SCHEMA_PAGE_FOUNDATION_CONFLICT');
75
+ const fingerprint = hashStable(normalizeInitialFingerprint(schema));
76
+ if (fingerprint !== shellProfile.fingerprint) {
77
+ foundationError(
78
+ 'SCHEMA_PAGE_FOUNDATION_CONFLICT',
79
+ 'Initial page Schema does not match the approved data-source shell profile.'
80
+ );
81
+ }
82
+ const managed = {
83
+ formType: observedIdentity.formType,
84
+ profile: NATIVE_PAGE_PROFILE,
85
+ title: observedIdentity.title,
86
+ };
87
+ return {
88
+ classification: 'PAGE_CREATED',
89
+ dataSourceHash: hashStable(structure.dataSource),
90
+ managed,
91
+ managedHash: hashStable(managed),
92
+ remoteSchemaHash: hashInitialRemoteSchema(schema),
93
+ };
94
+ }
95
+
96
+ function buildDataSourceOnlyNativePagePatch(input = {}) {
97
+ const compiledPage = requireCompiledPage(input.compiledPage);
98
+ const observedIdentity = normalizeObservedIdentity(input);
99
+ const formUuid = normalizeBinding(input.formUuid);
100
+ const operationId = normalizeHash(
101
+ input.operationId,
102
+ 'SCHEMA_PAGE_FOUNDATION_TRANSITION_INVALID'
103
+ );
104
+ const desiredManaged = buildDesiredManaged(observedIdentity.title, compiledPage);
105
+ if (
106
+ input.expectedManagedHash !== undefined &&
107
+ hashStable(desiredManaged) !== input.expectedManagedHash
108
+ ) {
109
+ foundationError(
110
+ 'SCHEMA_PAGE_FOUNDATION_CONFLICT',
111
+ 'Desired managed page content changed before patch preparation.'
112
+ );
113
+ }
114
+
115
+ const initialSchema = normalizeSchema(input.remoteSchema);
116
+ const initialProjection = projectDataSourceOnlyShell({
117
+ observedFormType: observedIdentity.formType,
118
+ observedTitle: observedIdentity.title,
119
+ schema: initialSchema,
120
+ shellProfile: input.shellProfile,
121
+ });
122
+ if (
123
+ input.expectedInitialRemoteSchemaHash !== undefined &&
124
+ input.expectedInitialRemoteSchemaHash !== initialProjection.remoteSchemaHash
125
+ ) {
126
+ foundationError(
127
+ 'SCHEMA_PAGE_FOUNDATION_CONFLICT',
128
+ 'Initial page Schema changed before the native page patch was prepared.'
129
+ );
130
+ }
131
+
132
+ const initialDataSource = extractInitialDataSource(initialSchema);
133
+ const generators = createDeterministicGenerators({
134
+ compiledHash: compiledPage.compiledHash,
135
+ operationId,
136
+ sourceHash: compiledPage.sourceHash,
137
+ });
138
+ let preparedSchema;
139
+ try {
140
+ preparedSchema = JSON.parse(buildNativePageSchemaContent(
141
+ compiledPage.source,
142
+ compiledPage.compiled,
143
+ formUuid,
144
+ {
145
+ existingDataSource: initialDataSource,
146
+ nextNodeId: generators.nextNodeId,
147
+ nextSuffix: generators.nextSuffix,
148
+ }
149
+ ));
150
+ } catch (error) {
151
+ foundationError(
152
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
153
+ 'Native page Schema could not be prepared.'
154
+ );
155
+ }
156
+
157
+ const preparedDataSource = extractPageDataSource(preparedSchema);
158
+ assertPreparedDataSourceContract(initialDataSource, preparedDataSource, formUuid);
159
+ const savedShellProfile = createNativePageShellProfile({
160
+ fingerprint: computeNativePageShellFingerprint(preparedSchema),
161
+ profileId: 'sac-page-deterministic-native-v1',
162
+ });
163
+ const savedProjection = projectNativePageSchema({
164
+ observedFormType: observedIdentity.formType,
165
+ observedTitle: observedIdentity.title,
166
+ schema: preparedSchema,
167
+ shellProfile: savedShellProfile,
168
+ });
169
+ if (
170
+ savedProjection.classification !== 'SCHEMA_SAVED' ||
171
+ !isDeepStrictEqual(savedProjection.managed, desiredManaged)
172
+ ) {
173
+ foundationError(
174
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
175
+ 'Prepared native page Schema does not match desired managed content.'
176
+ );
177
+ }
178
+
179
+ return deepFreeze({
180
+ initialDataSourceHash: hashStable(initialDataSource),
181
+ initialManagedHash: initialProjection.managedHash,
182
+ initialRemoteSchemaHash: initialProjection.remoteSchemaHash,
183
+ managedHash: savedProjection.managedHash,
184
+ preparedDataSourceHash: hashStable(preparedDataSource),
185
+ preparedRemoteSchemaHash: savedProjection.remoteSchemaHash,
186
+ schema: clonePlain(preparedSchema),
187
+ });
188
+ }
189
+
190
+ function buildDataSourceOnlyCanvasPagePatch(input = {}) {
191
+ const compiledPage = requireCompiledCanvas(input.compiledPage);
192
+ const observedIdentity = normalizeObservedIdentity(input);
193
+ const formUuid = normalizeBinding(input.formUuid);
194
+ const operationId = normalizeHash(
195
+ input.operationId,
196
+ 'SCHEMA_PAGE_FOUNDATION_TRANSITION_INVALID'
197
+ );
198
+ const desiredManaged = buildCanvasDesiredManaged(observedIdentity.title, compiledPage);
199
+ if (
200
+ input.expectedManagedHash !== undefined &&
201
+ hashStable(desiredManaged) !== input.expectedManagedHash
202
+ ) {
203
+ foundationError(
204
+ 'SCHEMA_PAGE_FOUNDATION_CONFLICT',
205
+ 'Desired managed Canvas page content changed before patch preparation.'
206
+ );
207
+ }
208
+
209
+ const initialSchema = normalizeSchema(input.remoteSchema);
210
+ const initialProjection = projectDataSourceOnlyShell({
211
+ observedFormType: observedIdentity.formType,
212
+ observedTitle: observedIdentity.title,
213
+ schema: initialSchema,
214
+ shellProfile: input.shellProfile,
215
+ });
216
+ if (
217
+ input.expectedInitialRemoteSchemaHash !== undefined &&
218
+ input.expectedInitialRemoteSchemaHash !== initialProjection.remoteSchemaHash
219
+ ) {
220
+ foundationError(
221
+ 'SCHEMA_PAGE_FOUNDATION_CONFLICT',
222
+ 'Initial page Schema changed before the Canvas page patch was prepared.'
223
+ );
224
+ }
225
+
226
+ const generators = createDeterministicGenerators({
227
+ compiledHash: compiledPage.compiledHash,
228
+ operationId,
229
+ sourceHash: compiledPage.sourceHash,
230
+ });
231
+ let preparedSchema;
232
+ try {
233
+ preparedSchema = JSON.parse(buildCanvasPageSchemaContent(
234
+ compiledPage.source,
235
+ compiledPage.runtimeCode,
236
+ compiledPage.importedModules,
237
+ formUuid,
238
+ {
239
+ nextNodeId: generators.nextNodeId,
240
+ nextSuffix: generators.nextSuffix,
241
+ }
242
+ ));
243
+ } catch (error) {
244
+ foundationError(
245
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
246
+ 'Canvas page Schema could not be prepared.'
247
+ );
248
+ }
249
+
250
+ const savedProjection = projectCanvasPageSchema({
251
+ observedFormType: observedIdentity.formType,
252
+ observedTitle: observedIdentity.title,
253
+ schema: preparedSchema,
254
+ });
255
+ if (
256
+ savedProjection.classification !== 'SCHEMA_SAVED' ||
257
+ !isDeepStrictEqual(savedProjection.managed, desiredManaged)
258
+ ) {
259
+ foundationError(
260
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
261
+ 'Prepared Canvas page Schema does not match desired managed content.'
262
+ );
263
+ }
264
+
265
+ return deepFreeze({
266
+ initialManagedHash: initialProjection.managedHash,
267
+ initialRemoteSchemaHash: initialProjection.remoteSchemaHash,
268
+ managedHash: savedProjection.managedHash,
269
+ preparedRemoteSchemaHash: savedProjection.remoteSchemaHash,
270
+ schema: clonePlain(preparedSchema),
271
+ });
272
+ }
273
+
274
+ function inspectDataSourceOnlyShell(schema, code) {
275
+ assertExactKeys(schema, INITIAL_ROOT_KEYS, code);
276
+ if (
277
+ !Number.isFinite(schema.gmtModified) ||
278
+ schema.gmtModified < 0 ||
279
+ !Array.isArray(schema.i18nData) ||
280
+ schema.i18nData.length !== 0 ||
281
+ schema.status !== 'ONLINE' ||
282
+ !Array.isArray(schema.pages) ||
283
+ schema.pages.length !== 1
284
+ ) {
285
+ foundationError(code, 'Initial page Schema root does not match the data-source shell contract.');
286
+ }
287
+ const page = schema.pages[0];
288
+ assertPlainObject(page, code);
289
+ assertExactKeys(page, INITIAL_PAGE_KEYS, code);
290
+ if (!Array.isArray(page.componentsTree) || page.componentsTree.length !== 1) {
291
+ foundationError(code, 'Initial page Schema must contain exactly one data-source tree entry.');
292
+ }
293
+ const root = page.componentsTree[0];
294
+ assertPlainObject(root, code);
295
+ assertExactKeys(root, INITIAL_TREE_KEYS, code);
296
+ const dataSource = root.dataSource;
297
+ assertPlainObject(dataSource, code);
298
+ assertExactKeys(dataSource, INITIAL_DATA_SOURCE_KEYS, code);
299
+ const expectedGlobalConfig = buildDefaultPageDataSource('FORM-FOUNDATION').globalConfig;
300
+ if (
301
+ !Array.isArray(dataSource.offline) ||
302
+ dataSource.offline.length !== 0 ||
303
+ !Array.isArray(dataSource.online) ||
304
+ dataSource.online.length !== 0 ||
305
+ !Array.isArray(dataSource.list) ||
306
+ dataSource.list.length !== 0 ||
307
+ dataSource.sync !== true ||
308
+ !isDeepStrictEqual(dataSource.globalConfig, expectedGlobalConfig)
309
+ ) {
310
+ foundationError(code, 'Initial page data-source shell contains unsupported content.');
311
+ }
312
+ return { dataSource };
313
+ }
314
+
315
+ function normalizeInitialFingerprint(schema) {
316
+ const normalized = clonePlain(schema);
317
+ normalized.gmtModified = '<root-gmtModified>';
318
+ return normalized;
319
+ }
320
+
321
+ function hashInitialRemoteSchema(schema) {
322
+ const normalized = clonePlain(schema);
323
+ delete normalized.gmtModified;
324
+ return hashStable(normalized);
325
+ }
326
+
327
+ function extractInitialDataSource(schema) {
328
+ return clonePlain(schema.pages[0].componentsTree[0].dataSource);
329
+ }
330
+
331
+ function assertPreparedDataSourceContract(initialDataSource, preparedDataSource, formUuid) {
332
+ const expected = mergePageDataSource(
333
+ initialDataSource,
334
+ buildDefaultPageDataSource(formUuid)
335
+ );
336
+ if (!preparedDataSource || !isDeepStrictEqual(preparedDataSource, expected)) {
337
+ foundationError(
338
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
339
+ 'Native page builder produced an unsupported data-source transition.'
340
+ );
341
+ }
342
+ }
343
+
344
+ function createDeterministicGenerators(input) {
345
+ const seed = hashStable(input);
346
+ return {
347
+ nextNodeId: createDeterministicTokenFactory(seed, 'node_oc', 18),
348
+ nextSuffix: createDeterministicTokenFactory(seed, '', 20),
349
+ };
350
+ }
351
+
352
+ function createDeterministicTokenFactory(seed, prefix, length) {
353
+ let counter = 0;
354
+ return function nextToken() {
355
+ counter += 1;
356
+ return prefix + crypto
357
+ .createHash('sha256')
358
+ .update(`${seed}:${prefix}:${counter}`)
359
+ .digest('hex')
360
+ .slice(0, length);
361
+ };
362
+ }
363
+
364
+ function buildDesiredManaged(title, compiledPage) {
365
+ return {
366
+ compiledHash: compiledPage.compiledHash,
367
+ formType: DISPLAY_FORM_TYPE,
368
+ profile: NATIVE_PAGE_PROFILE,
369
+ sourceHash: compiledPage.sourceHash,
370
+ title,
371
+ };
372
+ }
373
+
374
+ function buildCanvasDesiredManaged(title, compiledPage) {
375
+ return {
376
+ compiledHash: compiledPage.compiledHash,
377
+ formType: DISPLAY_FORM_TYPE,
378
+ profile: CANVAS_PAGE_PROFILE,
379
+ sourceHash: compiledPage.sourceHash,
380
+ title,
381
+ };
382
+ }
383
+
384
+ function normalizeObservedIdentity(input) {
385
+ const title = typeof input.observedTitle === 'string' ? input.observedTitle.trim() : '';
386
+ const formType = typeof input.observedFormType === 'string'
387
+ ? input.observedFormType.trim().toLowerCase()
388
+ : '';
389
+ if (
390
+ !title ||
391
+ title.length > 256 ||
392
+ containsUnsafeText(title) ||
393
+ formType !== DISPLAY_FORM_TYPE
394
+ ) {
395
+ foundationError(
396
+ 'SCHEMA_PAGE_FOUNDATION_OBSERVED_IDENTITY_INVALID',
397
+ 'Observed page identity is invalid.'
398
+ );
399
+ }
400
+ return { formType, title };
401
+ }
402
+
403
+ function normalizeSchema(value) {
404
+ let candidate = value;
405
+ if (isPlainObject(candidate) && candidate.success === true) {
406
+ if (!isPlainObject(candidate.content) || Object.keys(candidate.content).length === 0) {
407
+ foundationError(
408
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
409
+ 'Page Schema read returned empty content.'
410
+ );
411
+ }
412
+ candidate = candidate.content;
413
+ } else if (isPlainObject(candidate) && candidate.success === false) {
414
+ foundationError(
415
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
416
+ 'Page Schema read was not successful.'
417
+ );
418
+ }
419
+ if (typeof candidate === 'string') {
420
+ try {
421
+ candidate = JSON.parse(candidate);
422
+ } catch (error) {
423
+ foundationError(
424
+ 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID',
425
+ 'Page Schema content is invalid.'
426
+ );
427
+ }
428
+ }
429
+ assertPlainObject(candidate, 'SCHEMA_PAGE_FOUNDATION_SCHEMA_INVALID');
430
+ return clonePlain(candidate);
431
+ }
432
+
433
+ function requireInitialProfile(value) {
434
+ if (
435
+ !value ||
436
+ typeof value !== 'object' ||
437
+ !INITIAL_PROFILES.has(value) ||
438
+ value.contractVersion !== INITIAL_PROFILE_CONTRACT_VERSION
439
+ ) {
440
+ foundationError(
441
+ 'SCHEMA_PAGE_FOUNDATION_INITIAL_PROFILE_REQUIRED',
442
+ 'An approved data-source-only shell profile is required.'
443
+ );
444
+ }
445
+ return value;
446
+ }
447
+
448
+ function requireCompiledPage(value) {
449
+ if (!isCompiledNativePage(value)) {
450
+ foundationError(
451
+ 'SCHEMA_PAGE_SOURCE_INVALID',
452
+ 'Page builder requires trusted compiled native source.'
453
+ );
454
+ }
455
+ return value;
456
+ }
457
+
458
+ function requireCompiledCanvas(value) {
459
+ if (!isCompiledCanvasPage(value)) {
460
+ foundationError(
461
+ 'SCHEMA_PAGE_SOURCE_INVALID',
462
+ 'Page builder requires trusted compiled Canvas source.'
463
+ );
464
+ }
465
+ return value;
466
+ }
467
+
468
+ function normalizeProfileId(value) {
469
+ const profileId = typeof value === 'string' ? value.trim() : '';
470
+ if (!PROFILE_ID_PATTERN.test(profileId)) {
471
+ foundationError(
472
+ 'SCHEMA_PAGE_FOUNDATION_INITIAL_PROFILE_INVALID',
473
+ 'Data-source shell profile is invalid.'
474
+ );
475
+ }
476
+ return profileId;
477
+ }
478
+
479
+ function normalizeHash(value, code) {
480
+ const hash = typeof value === 'string' ? value.trim() : '';
481
+ if (!HASH_PATTERN.test(hash)) {
482
+ foundationError(code, 'Page foundation hash is invalid.');
483
+ }
484
+ return hash;
485
+ }
486
+
487
+ function normalizeBinding(value) {
488
+ const binding = typeof value === 'string' ? value.trim() : '';
489
+ if (!binding || binding.length > 256 || containsUnsafeText(binding)) {
490
+ foundationError(
491
+ 'SCHEMA_PAGE_FOUNDATION_TRANSITION_INVALID',
492
+ 'Page builder binding is invalid.'
493
+ );
494
+ }
495
+ return binding;
496
+ }
497
+
498
+ function assertExactKeys(value, expected, code) {
499
+ assertPlainObject(value, code);
500
+ const keys = Object.keys(value).sort();
501
+ if (
502
+ keys.length !== expected.length ||
503
+ keys.some((key, index) => key !== expected[index])
504
+ ) {
505
+ foundationError(code, 'Page Schema contains unsupported structure.');
506
+ }
507
+ }
508
+
509
+ function assertPlainObject(value, code) {
510
+ if (!isPlainObject(value)) {
511
+ foundationError(code, 'Page Schema value must be a plain object.');
512
+ }
513
+ }
514
+
515
+ function isPlainObject(value) {
516
+ const prototype = value && typeof value === 'object'
517
+ ? Object.getPrototypeOf(value)
518
+ : undefined;
519
+ return !!(
520
+ value &&
521
+ typeof value === 'object' &&
522
+ !Array.isArray(value) &&
523
+ (prototype === Object.prototype || prototype === null)
524
+ );
525
+ }
526
+
527
+ function containsUnsafeText(value) {
528
+ for (let index = 0; index < value.length; index++) {
529
+ const code = value.charCodeAt(index);
530
+ if ((code < 32 && code !== 9 && code !== 10 && code !== 13) || code === 127) {
531
+ return true;
532
+ }
533
+ }
534
+ return false;
535
+ }
536
+
537
+ function deepFreeze(value) {
538
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) {
539
+ return value;
540
+ }
541
+ for (const child of Object.values(value)) {
542
+ deepFreeze(child);
543
+ }
544
+ return Object.freeze(value);
545
+ }
546
+
547
+ function clonePlain(value) {
548
+ return JSON.parse(JSON.stringify(value));
549
+ }
550
+
551
+ function foundationError(code, message) {
552
+ throw schemaError(code, message);
553
+ }
554
+
555
+ module.exports = Object.freeze({
556
+ buildDataSourceOnlyCanvasPagePatch,
557
+ buildDataSourceOnlyNativePagePatch,
558
+ computeDataSourceOnlyShellFingerprint,
559
+ createDataSourceOnlyShellProfile,
560
+ projectDataSourceOnlyShell,
561
+ });