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,281 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('crypto');
4
+ const Ajv = require('ajv');
5
+ const manifestSchemaV1 = require('./manifest-schema-v1.json');
6
+ const { schemaError } = require('./errors');
7
+ const { assertManifestObjectLimits } = require('./manifest-limits');
8
+ const { createDefaultRegistry } = require('./resource-registry');
9
+ const { countDependencies, validateDependencyGraph } = require('./dependency-graph');
10
+ const { compareCodePoints, sortStrings } = require('./sort');
11
+
12
+ const KNOWN_UNSUPPORTED_SECTIONS = Object.freeze({
13
+ automations: 'automation',
14
+ reports: 'report',
15
+ });
16
+
17
+ const FORBIDDEN_KEY_CANONICALS = new Set([
18
+ 'apikey',
19
+ 'apptype',
20
+ 'authorization',
21
+ 'clientsecret',
22
+ 'cookie',
23
+ 'cookies',
24
+ 'credential',
25
+ 'credentials',
26
+ 'constructor',
27
+ 'csrf',
28
+ 'csrftoken',
29
+ 'fieldid',
30
+ 'formuuid',
31
+ 'header',
32
+ 'headers',
33
+ 'internalpath',
34
+ 'internalurl',
35
+ 'nodeid',
36
+ 'password',
37
+ 'proto',
38
+ 'prototype',
39
+ 'processcode',
40
+ 'processid',
41
+ 'processversion',
42
+ 'refreshtoken',
43
+ 'secret',
44
+ 'token',
45
+ ]);
46
+
47
+ let validateManifestV1;
48
+
49
+ function normalizeManifest(manifest, options = {}) {
50
+ assertManifestObjectLimits(manifest, options);
51
+ precheckUnsupportedSections(manifest);
52
+ precheckForbiddenKeys(manifest);
53
+ validateRawManifest(manifest);
54
+
55
+ const registry = options.registry || createDefaultRegistry();
56
+ const appAdapter = registry.get('app');
57
+ const appEntry = {
58
+ key: manifest.app.key,
59
+ definition: manifest.app,
60
+ };
61
+ appAdapter.validate(appEntry);
62
+ const appResource = appAdapter.normalize(appEntry);
63
+
64
+ const context = {
65
+ appKey: manifest.app.key,
66
+ fsImpl: options.fsImpl,
67
+ manifest,
68
+ registry,
69
+ workspaceRoot: options.workspaceRoot || process.cwd(),
70
+ };
71
+ const formAdapter = registry.get('form');
72
+ const formResources = sortStrings(Object.keys(manifest.forms || {})).map(formKey => {
73
+ const entry = {
74
+ key: formKey,
75
+ definition: manifest.forms[formKey],
76
+ };
77
+ formAdapter.validate(entry, context);
78
+ return formAdapter.normalize(entry, context);
79
+ });
80
+
81
+ let processResources = [];
82
+ if (Object.prototype.hasOwnProperty.call(manifest, 'processes')) {
83
+ const processAdapter = registry.get('process');
84
+ processResources = sortStrings(Object.keys(manifest.processes || {})).map(processKey => {
85
+ const entry = {
86
+ key: processKey,
87
+ definition: manifest.processes[processKey],
88
+ };
89
+ processAdapter.validate(entry, context);
90
+ return processAdapter.normalize(entry, context);
91
+ });
92
+ }
93
+
94
+ let pageResources = [];
95
+ if (Object.prototype.hasOwnProperty.call(manifest, 'pages')) {
96
+ const pageAdapter = registry.get('page');
97
+ pageResources = sortStrings(Object.keys(manifest.pages || {})).map(pageKey => {
98
+ const entry = {
99
+ key: pageKey,
100
+ definition: manifest.pages[pageKey],
101
+ };
102
+ pageAdapter.validate(entry, context);
103
+ return pageAdapter.normalize(entry, context);
104
+ });
105
+ }
106
+
107
+ const resources = [appResource, ...formResources, ...processResources, ...pageResources]
108
+ .sort(compareResources);
109
+ validateDependencyGraph(resources);
110
+
111
+ const publicResources = resources.map(toPublicResource);
112
+ const hashInput = {
113
+ contractVersion: 1,
114
+ resources: publicResources,
115
+ };
116
+ const manifestHash = 'sha256:' + crypto
117
+ .createHash('sha256')
118
+ .update(stableStringify(hashInput))
119
+ .digest('hex');
120
+
121
+ return {
122
+ manifestHash,
123
+ normalized: {
124
+ resources: publicResources,
125
+ },
126
+ counts: {
127
+ resources: publicResources.length,
128
+ dependencies: countDependencies(publicResources),
129
+ },
130
+ };
131
+ }
132
+
133
+ function precheckUnsupportedSections(manifest) {
134
+ if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) {
135
+ return;
136
+ }
137
+ for (const section of sortStrings(Object.keys(KNOWN_UNSUPPORTED_SECTIONS))) {
138
+ if (Object.prototype.hasOwnProperty.call(manifest, section)) {
139
+ throw schemaError('SCHEMA_RESOURCE_TYPE_UNSUPPORTED', 'Manifest resource type is not supported in SAC-02.', {
140
+ path: `/${section}`,
141
+ details: {
142
+ section,
143
+ resourceType: KNOWN_UNSUPPORTED_SECTIONS[section],
144
+ },
145
+ });
146
+ }
147
+ }
148
+ }
149
+
150
+ function precheckForbiddenKeys(value, pathSegments = []) {
151
+ if (!value || typeof value !== 'object') {
152
+ return;
153
+ }
154
+ if (Array.isArray(value)) {
155
+ value.forEach((item, index) => precheckForbiddenKeys(item, pathSegments.concat(String(index))));
156
+ return;
157
+ }
158
+
159
+ for (const [key, child] of Object.entries(value)) {
160
+ if (FORBIDDEN_KEY_CANONICALS.has(canonicalizeKey(key))) {
161
+ throw schemaError('SCHEMA_FORBIDDEN_FIELD', 'Manifest must not contain environment IDs or sensitive configuration fields.', {
162
+ path: formatJsonPointer(pathSegments.concat(key)),
163
+ details: { key },
164
+ });
165
+ }
166
+ precheckForbiddenKeys(child, pathSegments.concat(key));
167
+ }
168
+ }
169
+
170
+ function validateRawManifest(manifest) {
171
+ const validate = getValidator();
172
+ if (validate(manifest)) {
173
+ return;
174
+ }
175
+
176
+ const error = (validate.errors || [])[0];
177
+ throw mapAjvError(error);
178
+ }
179
+
180
+ function getValidator() {
181
+ if (!validateManifestV1) {
182
+ const ajv = new Ajv({ allErrors: true, strict: false });
183
+ validateManifestV1 = ajv.compile(manifestSchemaV1);
184
+ }
185
+ return validateManifestV1;
186
+ }
187
+
188
+ function mapAjvError(error) {
189
+ if (!error) {
190
+ return schemaError('SCHEMA_MANIFEST_SCHEMA_INVALID', 'Manifest does not match Manifest v1 schema.');
191
+ }
192
+
193
+ const pointer = error.instancePath || '/';
194
+ if (error.keyword === 'additionalProperties') {
195
+ const property = error.params && error.params.additionalProperty;
196
+ return schemaError('SCHEMA_UNKNOWN_PROPERTY', 'Manifest contains an unknown property.', {
197
+ path: pointer === '/' ? `/${property}` : `${pointer}/${escapePointer(property)}`,
198
+ details: { property },
199
+ });
200
+ }
201
+ if (error.keyword === 'required' && error.params && error.params.missingProperty === 'fields' && /^\/forms\//.test(error.instancePath || '')) {
202
+ return schemaError('SCHEMA_FORM_FIELDS_REQUIRED', 'Manifest forms must contain at least one field.', {
203
+ path: `${error.instancePath}/fields`,
204
+ });
205
+ }
206
+ if (error.keyword === 'minProperties' && /\/fields$/.test(error.instancePath || '')) {
207
+ return schemaError('SCHEMA_FORM_FIELDS_REQUIRED', 'Manifest forms must contain at least one field.', {
208
+ path: error.instancePath,
209
+ });
210
+ }
211
+ if (error.instancePath === '/kind' && error.keyword === 'const') {
212
+ return schemaError('SCHEMA_INVALID_KIND', 'Manifest kind must be "openyida_app_manifest".', {
213
+ path: '/kind',
214
+ });
215
+ }
216
+ if (error.instancePath === '/schemaVersion' && error.keyword === 'const') {
217
+ return schemaError('SCHEMA_UNSUPPORTED_VERSION', 'Manifest schemaVersion must be 1.', {
218
+ path: '/schemaVersion',
219
+ });
220
+ }
221
+
222
+ return schemaError('SCHEMA_MANIFEST_SCHEMA_INVALID', 'Manifest does not match Manifest v1 schema.', {
223
+ path: pointer,
224
+ details: {
225
+ keyword: error.keyword,
226
+ },
227
+ });
228
+ }
229
+
230
+ function toPublicResource(resource) {
231
+ const result = {
232
+ resourceType: resource.resourceType,
233
+ key: resource.key,
234
+ desired: resource.desired,
235
+ dependsOn: [...(resource.dependsOn || [])].sort(),
236
+ };
237
+ if (resource.source !== undefined) {
238
+ result.source = resource.source;
239
+ }
240
+ return result;
241
+ }
242
+
243
+ function compareResources(left, right) {
244
+ const leftId = `${left.resourceType}:${left.key}`;
245
+ const rightId = `${right.resourceType}:${right.key}`;
246
+ return compareCodePoints(leftId, rightId);
247
+ }
248
+
249
+ function stableStringify(value) {
250
+ if (value === null || typeof value !== 'object') {
251
+ return JSON.stringify(value);
252
+ }
253
+ if (Array.isArray(value)) {
254
+ return '[' + value.map(item => stableStringify(item)).join(',') + ']';
255
+ }
256
+ return '{' + Object.keys(value).sort(compareCodePoints).map(key => (
257
+ JSON.stringify(key) + ':' + stableStringify(value[key])
258
+ )).join(',') + '}';
259
+ }
260
+
261
+ function canonicalizeKey(key) {
262
+ return String(key).replace(/[^A-Za-z0-9]/g, '').toLowerCase();
263
+ }
264
+
265
+ function formatJsonPointer(segments) {
266
+ if (!segments || segments.length === 0) {
267
+ return '/';
268
+ }
269
+ return '/' + segments.map(escapePointer).join('/');
270
+ }
271
+
272
+ function escapePointer(value) {
273
+ return String(value).replace(/~/g, '~0').replace(/\//g, '~1');
274
+ }
275
+
276
+ module.exports = {
277
+ KNOWN_UNSUPPORTED_SECTIONS,
278
+ canonicalizeKey,
279
+ normalizeManifest,
280
+ stableStringify,
281
+ };