openyida 2026.7.19 → 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 (139) hide show
  1. package/README.md +14 -0
  2. package/bin/yida.js +107 -18
  3. package/lib/app/create-app.js +12 -1
  4. package/lib/app/create-form/args.js +13 -0
  5. package/lib/app/create-form.js +154 -67
  6. package/lib/app/create-page.js +45 -9
  7. package/lib/app/get-schema.js +65 -14
  8. package/lib/app/import-app.js +92 -41
  9. package/lib/app/publish.js +289 -556
  10. package/lib/app/schema-field-resolution.js +370 -0
  11. package/lib/app/services/app-reader.js +85 -0
  12. package/lib/app/services/app-service.js +235 -0
  13. package/lib/app/services/canvas-page-compiler.js +91 -0
  14. package/lib/app/services/canvas-page-schema-builder.js +149 -0
  15. package/lib/app/services/field-bindings.js +68 -0
  16. package/lib/app/services/form-compiler.js +1922 -0
  17. package/lib/app/services/form-mode-service.js +182 -0
  18. package/lib/app/services/form-schema-patcher.js +333 -0
  19. package/lib/app/services/form-schema-reader.js +59 -0
  20. package/lib/app/services/form-service.js +379 -0
  21. package/lib/app/services/form-validation.js +562 -0
  22. package/lib/app/services/native-page-compiler.js +92 -0
  23. package/lib/app/services/native-page-schema-builder.js +428 -0
  24. package/lib/app/services/page-resource-service.js +185 -0
  25. package/lib/app/update-app.js +18 -6
  26. package/lib/auth/token-auth.js +34 -3
  27. package/lib/auth/token-store.js +22 -4
  28. package/lib/bridge/bridge.js +37 -5
  29. package/lib/core/agent-capabilities.js +5 -3
  30. package/lib/core/command-manifest.js +40 -0
  31. package/lib/core/doctor.js +15 -4
  32. package/lib/core/env-cmd.js +1 -1
  33. package/lib/core/env.js +7 -6
  34. package/lib/core/legacy-schema-guard.js +408 -0
  35. package/lib/core/locales/en.js +8 -46
  36. package/lib/core/locales/zh.js +8 -46
  37. package/lib/core/sample.js +1 -1
  38. package/lib/core/utils.js +334 -66
  39. package/lib/core/yida-client.js +104 -3
  40. package/lib/formula/evaluate.js +8 -66
  41. package/lib/formula/field-refs.js +83 -0
  42. package/lib/process/configure-process.js +44 -1992
  43. package/lib/process/create-process.js +54 -87
  44. package/lib/process/services/process-compiler.js +2056 -0
  45. package/lib/process/services/process-reader.js +232 -0
  46. package/lib/process/services/process-resource-service.js +571 -0
  47. package/lib/process/services/process-service.js +122 -0
  48. package/lib/process/services/process-stage-checkpoint.js +246 -0
  49. package/lib/report/append.js +7 -26
  50. package/lib/report/http.js +31 -5
  51. package/lib/report/index.js +10 -2
  52. package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
  53. package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
  54. package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
  55. package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +204 -8
  56. package/lib/schema/adapters/app-adapter.js +210 -0
  57. package/lib/schema/adapters/form-adapter.js +1362 -0
  58. package/lib/schema/adapters/keys.js +19 -0
  59. package/lib/schema/adapters/page-adapter.js +566 -0
  60. package/lib/schema/adapters/process-adapter.js +519 -0
  61. package/lib/schema/applier.js +1878 -0
  62. package/lib/schema/apply-store.js +1083 -0
  63. package/lib/schema/command.js +645 -0
  64. package/lib/schema/dependency-graph.js +83 -0
  65. package/lib/schema/errors.js +481 -0
  66. package/lib/schema/hash.js +9 -0
  67. package/lib/schema/manifest-limits.js +177 -0
  68. package/lib/schema/manifest-loader.js +309 -0
  69. package/lib/schema/manifest-schema-v1.json +193 -0
  70. package/lib/schema/normalize-manifest.js +281 -0
  71. package/lib/schema/page-canvas-foundation.js +447 -0
  72. package/lib/schema/page-data-source-builder.js +561 -0
  73. package/lib/schema/page-foundation.js +556 -0
  74. package/lib/schema/page-source-loader.js +314 -0
  75. package/lib/schema/planner.js +691 -0
  76. package/lib/schema/remote-dispatch-boundary.js +39 -0
  77. package/lib/schema/remote-missing.js +21 -0
  78. package/lib/schema/remote-reader.js +189 -0
  79. package/lib/schema/resource-registry.js +157 -0
  80. package/lib/schema/server-revision.js +71 -0
  81. package/lib/schema/sort.js +28 -0
  82. package/lib/schema/state-store.js +589 -0
  83. package/package.json +2 -2
  84. package/scripts/postinstall.js +8 -12
  85. package/scripts/validate-package-size.js +1 -1
  86. package/yida-skills/SKILL.md +114 -29
  87. package/yida-skills/references/schema-as-code-phase1.md +99 -0
  88. package/yida-skills/references/setup-and-env.md +59 -59
  89. package/yida-skills/references/task-retrospective.md +6 -6
  90. package/yida-skills/skills/yida-app/SKILL.md +60 -14
  91. package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
  92. package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
  93. package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +7 -1
  94. package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
  95. package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
  96. package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
  97. package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
  98. package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
  99. package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
  100. package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
  101. package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
  102. package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
  103. package/yida-skills/skills/yida-integration/SKILL.md +7 -1
  104. package/yida-skills/skills/yida-login/SKILL.md +50 -99
  105. package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
  106. package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
  107. package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
  108. package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
  109. package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
  110. package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
  111. package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
  112. package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
  113. package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
  114. package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
  115. package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
  116. package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
  117. package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
  118. package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
  119. package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
  120. package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
  121. package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
  122. package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
  123. package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
  124. package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
  125. package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
  126. package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
  127. package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
  128. package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
  129. package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
  130. package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
  131. package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
  132. package/yida-skills/skills/yida-report/SKILL.md +7 -1
  133. package/yida-skills/skills-index.json +14 -46
  134. package/yida-skills/skills/large-file-write/SKILL.md +0 -93
  135. package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
  136. package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
  137. package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
  138. package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
  139. package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
@@ -0,0 +1,83 @@
1
+ 'use strict';
2
+
3
+ const { schemaError } = require('./errors');
4
+ const { sortStrings } = require('./sort');
5
+
6
+ function resourceId(resource) {
7
+ return `${resource.resourceType}:${resource.key}`;
8
+ }
9
+
10
+ function validateDependencyGraph(resources) {
11
+ const byId = new Map(resources.map(resource => [resourceId(resource), resource]));
12
+ const edges = new Map();
13
+
14
+ for (const resource of resources) {
15
+ const id = resourceId(resource);
16
+ const dependencies = sortStrings(resource.dependsOn || []);
17
+ edges.set(id, dependencies);
18
+ for (const target of dependencies) {
19
+ if (!byId.has(target)) {
20
+ const source = firstDependencySource(resource, target);
21
+ const code = source && source.kind === 'reference'
22
+ ? 'SCHEMA_REFERENCE_NOT_FOUND'
23
+ : 'SCHEMA_DEPENDENCY_NOT_FOUND';
24
+ throw schemaError(code, 'Resource dependency target does not exist.', {
25
+ path: source && source.path,
26
+ details: {
27
+ resource: id,
28
+ target,
29
+ },
30
+ });
31
+ }
32
+ }
33
+ }
34
+
35
+ detectCycle(edges);
36
+ }
37
+
38
+ function firstDependencySource(resource, target) {
39
+ const sources = resource.dependencySources && resource.dependencySources[target];
40
+ return Array.isArray(sources) && sources.length > 0 ? sources[0] : undefined;
41
+ }
42
+
43
+ function detectCycle(edges) {
44
+ const visiting = new Set();
45
+ const visited = new Set();
46
+ const stack = [];
47
+
48
+ function visit(id) {
49
+ if (visited.has(id)) {
50
+ return;
51
+ }
52
+ if (visiting.has(id)) {
53
+ const start = stack.indexOf(id);
54
+ const cycle = stack.slice(start).concat(id);
55
+ throw schemaError('SCHEMA_DEPENDENCY_CYCLE', 'Manifest resource dependencies must not contain cycles.', {
56
+ details: { cycle },
57
+ });
58
+ }
59
+
60
+ visiting.add(id);
61
+ stack.push(id);
62
+ for (const target of edges.get(id) || []) {
63
+ visit(target);
64
+ }
65
+ stack.pop();
66
+ visiting.delete(id);
67
+ visited.add(id);
68
+ }
69
+
70
+ for (const id of sortStrings(edges.keys())) {
71
+ visit(id);
72
+ }
73
+ }
74
+
75
+ function countDependencies(resources) {
76
+ return resources.reduce((total, resource) => total + (resource.dependsOn || []).length, 0);
77
+ }
78
+
79
+ module.exports = {
80
+ countDependencies,
81
+ resourceId,
82
+ validateDependencyGraph,
83
+ };
@@ -0,0 +1,481 @@
1
+ 'use strict';
2
+
3
+ const VALIDATION_KIND = 'openyida_schema_validation';
4
+ const PLAN_KIND = 'openyida_schema_plan';
5
+ const APPLY_KIND = 'openyida_schema_apply';
6
+ const CONTRACT_VERSION = 1;
7
+ const TRUSTED_SCHEMA_ERROR = Symbol('openyida.schema.trustedError');
8
+
9
+ const PLAN_RESOURCE_TYPES = new Set([
10
+ 'app',
11
+ 'automation',
12
+ 'form',
13
+ 'page',
14
+ 'process',
15
+ 'report',
16
+ ]);
17
+
18
+ const PLAN_MANIFEST_PATH_CODES = new Set([
19
+ 'SCHEMA_DUPLICATE_KEY',
20
+ 'SCHEMA_FIELD_PROPERTY_INVALID',
21
+ 'SCHEMA_FIELD_TYPE_UNSUPPORTED',
22
+ 'SCHEMA_FORM_FIELDS_REQUIRED',
23
+ 'SCHEMA_INVALID_ARGUMENTS',
24
+ 'SCHEMA_INVALID_KEY',
25
+ 'SCHEMA_INVALID_KIND',
26
+ 'SCHEMA_INVALID_REFERENCE',
27
+ 'SCHEMA_MANIFEST_LIMIT_INVALID',
28
+ 'SCHEMA_MANIFEST_SCHEMA_INVALID',
29
+ 'SCHEMA_MANIFEST_COLLECTION_LIMIT_EXCEEDED',
30
+ 'SCHEMA_MANIFEST_DEPTH_LIMIT_EXCEEDED',
31
+ 'SCHEMA_MANIFEST_NODE_LIMIT_EXCEEDED',
32
+ 'SCHEMA_MANIFEST_PATH_UNSAFE',
33
+ 'SCHEMA_MANIFEST_STRING_LIMIT_EXCEEDED',
34
+ 'SCHEMA_MANIFEST_STRUCTURE_UNSUPPORTED',
35
+ 'SCHEMA_MANIFEST_TOO_LARGE',
36
+ 'SCHEMA_PROCESS_FORM_MODE_REQUIRED',
37
+ 'SCHEMA_PROCESS_NODE_PROPERTY_INVALID',
38
+ 'SCHEMA_PROCESS_NODE_TYPE_UNSUPPORTED',
39
+ 'SCHEMA_REFERENCE_NOT_FOUND',
40
+ 'SCHEMA_RESOURCE_TYPE_UNSUPPORTED',
41
+ 'SCHEMA_UNKNOWN_PROPERTY',
42
+ 'SCHEMA_UNSUPPORTED_VERSION',
43
+ ]);
44
+
45
+ const PLAN_SAFE_MESSAGES = Object.freeze({
46
+ SCHEMA_DEPENDENCY_CYCLE: 'Schema plan failed because the manifest dependency graph contains a cycle.',
47
+ SCHEMA_DEPENDENCY_NOT_FOUND: 'Schema plan failed because a dependency target does not exist.',
48
+ SCHEMA_DUPLICATE_KEY: 'Schema plan failed because a semantic key is duplicated.',
49
+ SCHEMA_FIELD_PROPERTY_INVALID: 'Schema plan failed because a field property is invalid.',
50
+ SCHEMA_FIELD_TYPE_UNSUPPORTED: 'Schema plan failed because a field type is unsupported.',
51
+ SCHEMA_FORBIDDEN_FIELD: 'Schema plan failed because the manifest contains a forbidden field.',
52
+ SCHEMA_FORM_FIELDS_REQUIRED: 'Schema plan failed because a form has no fields.',
53
+ SCHEMA_INVALID_ARGUMENTS: 'Schema plan arguments are invalid.',
54
+ SCHEMA_INVALID_KIND: 'Schema plan failed because the manifest kind is invalid.',
55
+ SCHEMA_INVALID_KEY: 'Schema plan failed because a semantic key is invalid.',
56
+ SCHEMA_INVALID_REFERENCE: 'Schema plan failed because a resource reference is invalid.',
57
+ SCHEMA_MANIFEST_LOAD_FAILED: 'Schema plan failed because the manifest could not be read.',
58
+ SCHEMA_MANIFEST_LIMIT_INVALID: 'Schema plan failed because the manifest input limit configuration is invalid.',
59
+ SCHEMA_MANIFEST_PARSE_FAILED: 'Schema plan failed because the manifest JSON is invalid.',
60
+ SCHEMA_MANIFEST_PATH_UNSAFE: 'Schema plan failed because the manifest path is outside the workspace trust root.',
61
+ SCHEMA_MANIFEST_COLLECTION_LIMIT_EXCEEDED: 'Schema plan failed because the manifest JSON collection limit was exceeded.',
62
+ SCHEMA_MANIFEST_DEPTH_LIMIT_EXCEEDED: 'Schema plan failed because the manifest JSON depth limit was exceeded.',
63
+ SCHEMA_MANIFEST_NODE_LIMIT_EXCEEDED: 'Schema plan failed because the manifest JSON node limit was exceeded.',
64
+ SCHEMA_MANIFEST_SCHEMA_INVALID: 'Schema plan failed because the manifest schema is invalid.',
65
+ SCHEMA_MANIFEST_STRING_LIMIT_EXCEEDED: 'Schema plan failed because the manifest JSON string limit was exceeded.',
66
+ SCHEMA_MANIFEST_STRUCTURE_UNSUPPORTED: 'Schema plan failed because the manifest JSON structure is unsupported.',
67
+ SCHEMA_MANIFEST_TOO_LARGE: 'Schema plan failed because the manifest file is too large.',
68
+ SCHEMA_OBSERVED_BINDING_MISSING: 'Schema plan failed because an observed binding is missing.',
69
+ SCHEMA_OBSERVED_REFERENCE_AMBIGUOUS: 'Schema plan failed because an observed reference is ambiguous.',
70
+ SCHEMA_OBSERVED_REFERENCE_MISSING: 'Schema plan failed because an observed reference is missing.',
71
+ SCHEMA_OBSERVED_STRUCTURE_MISMATCH: 'Schema plan failed because observed structure does not match managed state.',
72
+ SCHEMA_PLAN_STATE_INTEGRITY_FAILED: 'Schema plan failed because state integrity verification failed.',
73
+ SCHEMA_PROCESS_FORM_MODE_REQUIRED: 'Schema plan failed because a process form does not declare process mode.',
74
+ SCHEMA_PROCESS_COMPILE_FAILED: 'Schema plan failed because a process resource could not be compiled.',
75
+ SCHEMA_PROCESS_NODE_PROPERTY_INVALID: 'Schema plan failed because a process node property is invalid.',
76
+ SCHEMA_PROCESS_NODE_TYPE_UNSUPPORTED: 'Schema plan failed because a process node type is unsupported.',
77
+ SCHEMA_REFERENCE_NOT_FOUND: 'Schema plan failed because a referenced resource does not exist.',
78
+ SCHEMA_REMOTE_PROJECT_FAILED: 'Schema plan failed because remote observed projection failed.',
79
+ SCHEMA_REMOTE_READ_FAILED: 'Schema plan failed because remote observed read failed.',
80
+ SCHEMA_REMOTE_RESOURCE_MISSING: 'Schema plan detected that a bound remote resource is missing.',
81
+ SCHEMA_RESOURCE_TYPE_UNSUPPORTED: 'Schema plan failed because a resource type is unsupported.',
82
+ SCHEMA_STATE_ADAPTER_VERSION_UNSUPPORTED: 'Schema plan failed because state adapterVersion is unsupported.',
83
+ SCHEMA_STATE_ENVIRONMENT_MISMATCH: 'Schema plan failed because state belongs to a different environment.',
84
+ SCHEMA_STATE_ENVIRONMENT_REQUIRED: 'Schema plan requires environment identity.',
85
+ SCHEMA_STATE_FORBIDDEN_FIELD: 'Schema plan failed because state contains forbidden data.',
86
+ SCHEMA_STATE_INVALID: 'Schema plan failed because state is invalid.',
87
+ SCHEMA_STATE_READ_FAILED: 'Schema plan failed because state could not be read.',
88
+ SCHEMA_STATE_RESOURCE_BINDING_MISSING: 'Schema plan failed because state bindings are missing.',
89
+ SCHEMA_STATE_VERSION_UNSUPPORTED: 'Schema plan failed because state contractVersion is unsupported.',
90
+ SCHEMA_STATE_WRITE_FAILED: 'Schema plan failed because state could not be written.',
91
+ SCHEMA_UNKNOWN_PROPERTY: 'Schema plan failed because an unknown property was found.',
92
+ SCHEMA_UNSUPPORTED_VERSION: 'Schema plan failed because manifest schemaVersion is unsupported.',
93
+ });
94
+
95
+ const APPLY_SAFE_MESSAGES = Object.freeze({
96
+ SCHEMA_APPLY_BLOCKED: 'Schema apply is blocked by a non-executable plan change.',
97
+ SCHEMA_APPLY_DESTRUCTIVE_CHANGE_UNSUPPORTED: 'Schema apply does not support this destructive managed change.',
98
+ SCHEMA_APPLY_JIT_CONFLICT: 'Schema apply stopped because the resource changed after planning.',
99
+ SCHEMA_APPLY_JOURNAL_INVALID: 'Schema apply recovery journal is invalid.',
100
+ SCHEMA_APPLY_JOURNAL_READ_FAILED: 'Schema apply recovery journal could not be read.',
101
+ SCHEMA_APPLY_JOURNAL_WRITE_FAILED: 'Schema apply recovery journal could not be checkpointed.',
102
+ SCHEMA_APPLY_LOCKED: 'Schema apply is already running for this state.',
103
+ SCHEMA_APPLY_LOCK_FAILED: 'Schema apply could not acquire its state lock.',
104
+ SCHEMA_APPLY_LOCK_RELEASE_FAILED: 'Schema apply could not release its state lock.',
105
+ SCHEMA_APPLY_PATH_UNSAFE: 'Schema apply state path is outside the allowed workspace boundary.',
106
+ SCHEMA_APPLY_PLAN_STALE: 'Schema apply stopped because the reviewed plan is stale.',
107
+ SCHEMA_APPLY_VERIFY_FAILED: 'Schema apply post-write verification did not match desired state.',
108
+ SCHEMA_INVALID_ARGUMENTS: 'Schema apply arguments are invalid.',
109
+ SCHEMA_MANIFEST_LOAD_FAILED: 'Schema apply failed because the manifest could not be read.',
110
+ SCHEMA_MANIFEST_LIMIT_INVALID: 'Schema apply failed because the manifest input limit configuration is invalid.',
111
+ SCHEMA_MANIFEST_PARSE_FAILED: 'Schema apply failed because the manifest JSON is invalid.',
112
+ SCHEMA_MANIFEST_PATH_UNSAFE: 'Schema apply failed because the manifest path is outside the workspace trust root.',
113
+ SCHEMA_MANIFEST_COLLECTION_LIMIT_EXCEEDED: 'Schema apply failed because the manifest JSON collection limit was exceeded.',
114
+ SCHEMA_MANIFEST_DEPTH_LIMIT_EXCEEDED: 'Schema apply failed because the manifest JSON depth limit was exceeded.',
115
+ SCHEMA_MANIFEST_NODE_LIMIT_EXCEEDED: 'Schema apply failed because the manifest JSON node limit was exceeded.',
116
+ SCHEMA_MANIFEST_STRING_LIMIT_EXCEEDED: 'Schema apply failed because the manifest JSON string limit was exceeded.',
117
+ SCHEMA_MANIFEST_STRUCTURE_UNSUPPORTED: 'Schema apply failed because the manifest JSON structure is unsupported.',
118
+ SCHEMA_MANIFEST_TOO_LARGE: 'Schema apply failed because the manifest file is too large.',
119
+ SCHEMA_PROCESS_COMPILE_FAILED: 'Schema apply failed because a process resource could not be compiled.',
120
+ SCHEMA_REMOTE_PROJECT_FAILED: 'Schema apply failed because remote observed projection failed.',
121
+ SCHEMA_REMOTE_READ_FAILED: 'Schema apply failed because remote observed read failed.',
122
+ SCHEMA_RECONCILIATION_REQUIRED: 'Schema apply stopped because remote reconciliation is required.',
123
+ SCHEMA_RESOURCE_TYPE_UNSUPPORTED: 'Schema apply failed because a resource type is unsupported.',
124
+ SCHEMA_STATE_ADAPTER_VERSION_UNSUPPORTED: 'Schema apply failed because state adapterVersion is unsupported.',
125
+ SCHEMA_STATE_ENVIRONMENT_MISMATCH: 'Schema apply failed because state belongs to a different environment.',
126
+ SCHEMA_STATE_ENVIRONMENT_REQUIRED: 'Schema apply requires environment identity.',
127
+ SCHEMA_STATE_INVALID: 'Schema apply failed because state is invalid.',
128
+ SCHEMA_STATE_READ_FAILED: 'Schema apply failed because state could not be read.',
129
+ SCHEMA_STATE_RESOURCE_BINDING_MISSING: 'Schema apply failed because required state bindings are missing.',
130
+ SCHEMA_STATE_VERSION_UNSUPPORTED: 'Schema apply failed because state contractVersion is unsupported.',
131
+ SCHEMA_STATE_WRITE_FAILED: 'Schema apply could not checkpoint state.',
132
+ });
133
+
134
+ const PLAN_DETAIL_PROJECTORS = Object.freeze({
135
+ SCHEMA_APPLY_BLOCKED: details => projectPlanDetailObject(details, {
136
+ key: projectSemanticKey,
137
+ operation: projectOperation,
138
+ resourceType: projectResourceType,
139
+ }),
140
+ SCHEMA_APPLY_DESTRUCTIVE_CHANGE_UNSUPPORTED: details => projectPlanDetailObject(details, {
141
+ key: projectSemanticKey,
142
+ operation: projectOperation,
143
+ resourceType: projectResourceType,
144
+ semanticPath: projectSemanticPath,
145
+ }),
146
+ SCHEMA_APPLY_JIT_CONFLICT: details => projectPlanDetailObject(details, {
147
+ key: projectSemanticKey,
148
+ operation: projectOperation,
149
+ resourceType: projectResourceType,
150
+ }),
151
+ SCHEMA_APPLY_VERIFY_FAILED: details => projectPlanDetailObject(details, {
152
+ key: projectSemanticKey,
153
+ resourceType: projectResourceType,
154
+ }),
155
+ SCHEMA_FIELD_PROPERTY_INVALID: details => projectPlanDetailObject(details, {
156
+ property: projectSafeName,
157
+ semanticPath: projectSemanticPath,
158
+ }),
159
+ SCHEMA_FIELD_TYPE_UNSUPPORTED: details => projectPlanDetailObject(details, {
160
+ semanticPath: projectSemanticPath,
161
+ }),
162
+ SCHEMA_INVALID_REFERENCE: details => projectPlanDetailObject(details, {
163
+ resourceType: projectResourceType,
164
+ semanticPath: projectSemanticPath,
165
+ }),
166
+ SCHEMA_OBSERVED_BINDING_MISSING: details => projectPlanDetailObject(details, {
167
+ resourceType: projectResourceType,
168
+ semanticPath: projectSemanticPath,
169
+ }),
170
+ SCHEMA_OBSERVED_REFERENCE_AMBIGUOUS: details => projectPlanDetailObject(details, {
171
+ semanticPath: projectSemanticPath,
172
+ }),
173
+ SCHEMA_OBSERVED_REFERENCE_MISSING: details => projectPlanDetailObject(details, {
174
+ semanticPath: projectSemanticPath,
175
+ }),
176
+ SCHEMA_OBSERVED_STRUCTURE_MISMATCH: details => projectPlanDetailObject(details, {
177
+ actualParentBound: projectBoolean,
178
+ expectedParentBound: projectBoolean,
179
+ semanticPath: projectSemanticPath,
180
+ }),
181
+ SCHEMA_PLAN_STATE_INTEGRITY_FAILED: details => projectPlanDetailObject(details, {
182
+ key: projectSemanticKey,
183
+ resourceType: projectResourceType,
184
+ }),
185
+ SCHEMA_PROCESS_COMPILE_FAILED: details => projectPlanDetailObject(details, {
186
+ key: projectSemanticKey,
187
+ resourceType: projectResourceType,
188
+ }),
189
+ SCHEMA_REMOTE_PROJECT_FAILED: details => projectPlanDetailObject(details, {
190
+ key: projectSemanticKey,
191
+ resourceType: projectResourceType,
192
+ }),
193
+ SCHEMA_REMOTE_READ_FAILED: details => projectPlanDetailObject(details, {
194
+ key: projectSemanticKey,
195
+ resourceType: projectResourceType,
196
+ }),
197
+ SCHEMA_REMOTE_RESOURCE_MISSING: details => projectPlanDetailObject(details, {
198
+ key: projectSemanticKey,
199
+ resourceType: projectResourceType,
200
+ }),
201
+ SCHEMA_RESOURCE_TYPE_UNSUPPORTED: details => projectPlanDetailObject(details, {
202
+ resourceType: projectResourceType,
203
+ section: projectSafeName,
204
+ }),
205
+ SCHEMA_STATE_ADAPTER_VERSION_UNSUPPORTED: details => projectPlanDetailObject(details, {
206
+ adapterVersion: projectAdapterVersion,
207
+ key: projectSemanticKey,
208
+ resourceType: projectResourceType,
209
+ stateAdapterVersion: projectAdapterVersion,
210
+ }),
211
+ SCHEMA_STATE_RESOURCE_BINDING_MISSING: details => projectPlanDetailObject(details, {
212
+ key: projectSemanticKey,
213
+ resourceType: projectResourceType,
214
+ }),
215
+ SCHEMA_UNKNOWN_PROPERTY: details => projectPlanDetailObject(details, {
216
+ property: projectSafeName,
217
+ }),
218
+ });
219
+
220
+ class SchemaValidationError extends Error {
221
+ constructor(code, message, options = {}) {
222
+ super(message);
223
+ this.name = 'SchemaValidationError';
224
+ this.code = code;
225
+ this.path = options.path;
226
+ this.details = sanitizeDetails(options.details);
227
+ this.exitCode = options.exitCode || 1;
228
+ this[TRUSTED_SCHEMA_ERROR] = options.trusted !== false;
229
+ }
230
+ }
231
+
232
+ function sanitizeDetails(value) {
233
+ if (value === undefined) {
234
+ return undefined;
235
+ }
236
+ if (value === null || typeof value !== 'object') {
237
+ return value;
238
+ }
239
+ if (Array.isArray(value)) {
240
+ return value.map(item => sanitizeDetails(item));
241
+ }
242
+
243
+ const result = {};
244
+ for (const [key, child] of Object.entries(value)) {
245
+ if (child === undefined) {
246
+ continue;
247
+ }
248
+ if (isSensitiveDetailKey(key)) {
249
+ result[key] = '[REDACTED]';
250
+ } else {
251
+ result[key] = sanitizeDetails(child);
252
+ }
253
+ }
254
+ return result;
255
+ }
256
+
257
+ function isSensitiveDetailKey(key) {
258
+ return /cookie|token|secret|authorization|credential|header|csrf|schema|internalPath/i.test(String(key));
259
+ }
260
+
261
+ function schemaError(code, message, options = {}) {
262
+ return new SchemaValidationError(code, message, options);
263
+ }
264
+
265
+ function normalizeError(error) {
266
+ if (error instanceof SchemaValidationError) {
267
+ return error;
268
+ }
269
+ if (error && error.code && String(error.code).startsWith('SCHEMA_')) {
270
+ return new SchemaValidationError(error.code, error.message || 'Schema validation failed', {
271
+ path: error.path,
272
+ details: error.details,
273
+ trusted: false,
274
+ });
275
+ }
276
+ return new SchemaValidationError(
277
+ 'SCHEMA_INTERNAL_ERROR',
278
+ 'Schema validation failed because of an internal error.'
279
+ );
280
+ }
281
+
282
+ function toFailurePayload(error, kind = VALIDATION_KIND, options = {}) {
283
+ const normalized = normalizeError(error);
284
+ const usePlanSanitizer = options.plan === true || kind === PLAN_KIND;
285
+ const trustedPlanError = usePlanSanitizer && isTrustedSchemaError(normalized);
286
+ const details = usePlanSanitizer
287
+ ? trustedPlanError ? projectPlanDetails(normalized.code, normalized.details) : undefined
288
+ : normalized.details;
289
+ const path = usePlanSanitizer
290
+ ? trustedPlanError ? projectPlanPath(normalized.code, normalized.path) : undefined
291
+ : normalized.path;
292
+ const payload = {
293
+ kind,
294
+ contractVersion: CONTRACT_VERSION,
295
+ success: false,
296
+ error: {
297
+ code: normalized.code,
298
+ message: usePlanSanitizer
299
+ ? projectSafeErrorMessage(normalized.code, options.safeMessages, options.safeFallback)
300
+ : normalized.message,
301
+ },
302
+ };
303
+ if (path) {
304
+ payload.error.path = path;
305
+ }
306
+ if (details !== undefined) {
307
+ payload.error.details = details;
308
+ }
309
+ return payload;
310
+ }
311
+
312
+ function toPlanFailurePayload(error) {
313
+ return toFailurePayload(error, PLAN_KIND, {
314
+ plan: true,
315
+ safeMessages: PLAN_SAFE_MESSAGES,
316
+ safeFallback: 'Schema plan failed.',
317
+ });
318
+ }
319
+
320
+ function toApplyFailurePayload(error) {
321
+ return toFailurePayload(error, APPLY_KIND, {
322
+ plan: true,
323
+ safeMessages: APPLY_SAFE_MESSAGES,
324
+ safeFallback: 'Schema apply failed.',
325
+ });
326
+ }
327
+
328
+ function toSuccessPayload(result) {
329
+ return {
330
+ kind: VALIDATION_KIND,
331
+ contractVersion: CONTRACT_VERSION,
332
+ success: true,
333
+ manifestHash: result.manifestHash,
334
+ counts: {
335
+ resources: result.counts.resources,
336
+ dependencies: result.counts.dependencies,
337
+ },
338
+ };
339
+ }
340
+
341
+ function projectSafeErrorMessage(code, safeMessages, fallback) {
342
+ return safeMessages && safeMessages[code] || fallback || 'Schema operation failed.';
343
+ }
344
+
345
+ function projectPlanDetails(code, details) {
346
+ const projector = PLAN_DETAIL_PROJECTORS[code];
347
+ return projector ? projector(details) : undefined;
348
+ }
349
+
350
+ function projectPlanDetailObject(details, projectors) {
351
+ if (!details || typeof details !== 'object' || Array.isArray(details)) {
352
+ return undefined;
353
+ }
354
+ const result = {};
355
+ for (const [key, projector] of Object.entries(projectors)) {
356
+ const projected = projector(details[key]);
357
+ if (projected !== undefined) {
358
+ result[key] = projected;
359
+ }
360
+ }
361
+ return Object.keys(result).length > 0 ? result : undefined;
362
+ }
363
+
364
+ function projectPlanPath(code, path) {
365
+ if (!PLAN_MANIFEST_PATH_CODES.has(code) || !isSafeManifestPointer(path)) {
366
+ return undefined;
367
+ }
368
+ return path;
369
+ }
370
+
371
+ function projectAdapterVersion(value) {
372
+ return Number.isInteger(value) && value >= 0 ? value : undefined;
373
+ }
374
+
375
+ function projectBoolean(value) {
376
+ return typeof value === 'boolean' ? value : undefined;
377
+ }
378
+
379
+ function projectOperation(value) {
380
+ return ['conflict', 'create', 'orphan', 'remove', 'replace_type', 'stateRepair', 'unmanaged', 'update'].includes(value)
381
+ ? value
382
+ : undefined;
383
+ }
384
+
385
+ function projectResourceType(value) {
386
+ if (typeof value !== 'string' || !PLAN_RESOURCE_TYPES.has(value)) {
387
+ return undefined;
388
+ }
389
+ return value;
390
+ }
391
+
392
+ function projectSafeName(value) {
393
+ if (typeof value !== 'string' || !/^[A-Za-z_][A-Za-z0-9_-]*$/.test(value)) {
394
+ return undefined;
395
+ }
396
+ return hasSensitiveSemanticToken(value) ? undefined : value;
397
+ }
398
+
399
+ function projectSemanticKey(value) {
400
+ if (typeof value !== 'string' || !/^[A-Za-z][A-Za-z0-9_]*$/.test(value)) {
401
+ return undefined;
402
+ }
403
+ if (hasSensitiveSemanticToken(value) || looksLikeRemoteIdentifier(value)) {
404
+ return undefined;
405
+ }
406
+ return value;
407
+ }
408
+
409
+ function projectSemanticPath(value) {
410
+ if (typeof value !== 'string') {
411
+ return undefined;
412
+ }
413
+ const segments = value.split('.');
414
+ if (segments.length === 0 || segments.some(segment => projectSemanticKey(segment) === undefined)) {
415
+ return undefined;
416
+ }
417
+ return value;
418
+ }
419
+
420
+ function isSafeManifestPointer(path) {
421
+ if (!path || typeof path !== 'string' || !path.startsWith('/')) {
422
+ return false;
423
+ }
424
+ const segments = path.split('/').slice(1).map(unescapePointerSegment);
425
+ if (!['app', 'forms', 'kind', 'processes', 'schemaVersion'].includes(segments[0])) {
426
+ return false;
427
+ }
428
+ return segments.every(segment => (
429
+ segment === '' ||
430
+ /^[A-Za-z0-9_~.-]+$/.test(segment) &&
431
+ !hasSensitiveSemanticToken(segment) &&
432
+ !looksLikeRemoteIdentifier(segment)
433
+ ));
434
+ }
435
+
436
+ function hasSensitiveSemanticToken(value) {
437
+ const normalized = String(value).replace(/[-_\s]/g, '').toLowerCase();
438
+ return (
439
+ normalized.includes('apikey') ||
440
+ normalized.includes('authorization') ||
441
+ normalized.includes('cookie') ||
442
+ normalized.includes('credential') ||
443
+ normalized.includes('csrf') ||
444
+ normalized.includes('fieldid') ||
445
+ normalized.includes('formuuid') ||
446
+ normalized.includes('header') ||
447
+ normalized.includes('internalpath') ||
448
+ normalized.includes('password') ||
449
+ normalized.includes('secret') ||
450
+ normalized.includes('token')
451
+ );
452
+ }
453
+
454
+ function looksLikeRemoteIdentifier(value) {
455
+ return (
456
+ /^(APP|FORM|PROC|TPROC|LPROC)_[A-Za-z0-9_-]+$/.test(value) ||
457
+ /^[a-z]+Field_[A-Za-z0-9_.-]+$/.test(value)
458
+ );
459
+ }
460
+
461
+ function isTrustedSchemaError(error) {
462
+ return error instanceof SchemaValidationError && error[TRUSTED_SCHEMA_ERROR] === true;
463
+ }
464
+
465
+ function unescapePointerSegment(segment) {
466
+ return String(segment).replace(/~1/g, '/').replace(/~0/g, '~');
467
+ }
468
+
469
+ module.exports = {
470
+ APPLY_KIND,
471
+ CONTRACT_VERSION,
472
+ PLAN_KIND,
473
+ VALIDATION_KIND,
474
+ SchemaValidationError,
475
+ isTrustedSchemaError,
476
+ schemaError,
477
+ toApplyFailurePayload,
478
+ toPlanFailurePayload,
479
+ toFailurePayload,
480
+ toSuccessPayload,
481
+ };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ function isSha256(value) {
4
+ return typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value);
5
+ }
6
+
7
+ module.exports = {
8
+ isSha256,
9
+ };