@pulse-compute/wasm-contracts 0.0.0 → 1.0.0-beta.2

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 (97) hide show
  1. package/README.md +35 -2
  2. package/package.json +124 -6
  3. package/src/assets/contracts.js +296 -0
  4. package/src/config/provider-resolution.js +54 -0
  5. package/src/config/runtime-provider-kv.js +73 -0
  6. package/src/config/symbolic-refs.js +192 -0
  7. package/src/crypto/contracts.js +647 -0
  8. package/src/definitions/config-schema.js +30 -0
  9. package/src/definitions/handler-roles.js +66 -0
  10. package/src/definitions/path-grammar.js +11 -0
  11. package/src/definitions/router-api.js +149 -0
  12. package/src/diagnostics/codes.js +42 -0
  13. package/src/diagnostics/reporter.js +20 -0
  14. package/src/diagnostics.js +139 -0
  15. package/src/dispatch-table.js +23 -0
  16. package/src/entities/catalog.d.ts +7 -0
  17. package/src/entities/catalog.js +87 -0
  18. package/src/entities/contracts.d.ts +95 -0
  19. package/src/entities/contracts.js +122 -0
  20. package/src/entities/json-rpc.d.ts +27 -0
  21. package/src/entities/json-rpc.js +69 -0
  22. package/src/entities/runtime.d.ts +67 -0
  23. package/src/entities/runtime.js +288 -0
  24. package/src/events/contracts.js +456 -0
  25. package/src/execution-plan.js +42 -0
  26. package/src/grip/contracts.js +106 -0
  27. package/src/handler/backend-json-request-body.js +58 -0
  28. package/src/handler/beta-lifecycle-golden.js +97 -0
  29. package/src/handler/canonical-native-plan.js +143 -0
  30. package/src/handler/canonical-native-runtime.js +168 -0
  31. package/src/handler/canonical-runtime.js +13 -0
  32. package/src/handler/context.js +131 -0
  33. package/src/handler/ctx-contract.js +71 -0
  34. package/src/handler/doctor-readiness-aggregator.js +67 -0
  35. package/src/handler/effects.js +446 -0
  36. package/src/handler/io-lifecycle.js +134 -0
  37. package/src/handler/lifecycle-authoring-alignment.js +56 -0
  38. package/src/handler/lifecycle-readiness-aggregate.js +93 -0
  39. package/src/handler/reference-node-lifecycle-golden.js +73 -0
  40. package/src/handler/request-json-body.js +147 -0
  41. package/src/handler/runtime-api.js +471 -0
  42. package/src/handler/schema-decode-result.js +135 -0
  43. package/src/handler/schema-response-codec.js +141 -0
  44. package/src/handler/surface-contract.js +601 -0
  45. package/src/handler/types-contract.js +51 -0
  46. package/src/handler-table.js +28 -0
  47. package/src/host/backend-capabilities.js +24 -0
  48. package/src/host/capabilities.js +273 -0
  49. package/src/host/channel-broadcaster.js +60 -0
  50. package/src/host/json-body.js +80 -0
  51. package/src/host/request-result-headers.js +38 -0
  52. package/src/host/streaming-passthrough.js +90 -0
  53. package/src/host/wasm-host-abi.js +154 -0
  54. package/src/index.js +75 -0
  55. package/src/jwt/contracts.js +427 -0
  56. package/src/library/api-surface.js +99 -0
  57. package/src/library/contracts.js +273 -0
  58. package/src/library/manifest.js +317 -0
  59. package/src/library/second-package-owned-lowering.js +39 -0
  60. package/src/library/sidecars.js +147 -0
  61. package/src/logging.js +89 -0
  62. package/src/package/package-contract.js +975 -0
  63. package/src/package/package-contract.schema.json +303 -0
  64. package/src/package/runtime-pulse-live.js +100 -0
  65. package/src/path-table.js +12 -0
  66. package/src/path.js +275 -0
  67. package/src/project/config-factory.js +48 -0
  68. package/src/project/config-plan.js +409 -0
  69. package/src/project/config-runtime.js +46 -0
  70. package/src/project/javascript-application.js +212 -0
  71. package/src/project/javascript-core-capabilities.js +44 -0
  72. package/src/project/native-optimization.js +9 -0
  73. package/src/project/package-ownership.js +242 -0
  74. package/src/project/package-product-projection.js +171 -0
  75. package/src/project/reachable-graph-identity.js +219 -0
  76. package/src/project/reachable-graph-projections.js +279 -0
  77. package/src/project/reachable-graph-resolver.js +303 -0
  78. package/src/project/reachable-graph-v2.js +430 -0
  79. package/src/project/reachable-graph-v2.schema.json +285 -0
  80. package/src/project/reachable-graph.js +199 -0
  81. package/src/project/reachable-graph.schema.json +222 -0
  82. package/src/project/target-support-evidence.js +559 -0
  83. package/src/provider/canonical-provider.js +239 -0
  84. package/src/provider/final-wasm-policy.js +87 -0
  85. package/src/provider/toolchain.js +771 -0
  86. package/src/route-plan.js +43 -0
  87. package/src/s3/contracts.js +12 -0
  88. package/src/schema-json/compile.js +63 -0
  89. package/src/schema-json/contracts.js +10 -0
  90. package/src/schema-json/generic-parser.js +62 -0
  91. package/src/schema-json/registry.js +359 -0
  92. package/src/schema-json/semantic-trace.js +241 -0
  93. package/src/schema-json/v1.js +65 -0
  94. package/src/schema-json/v2.js +110 -0
  95. package/src/sha256.js +104 -0
  96. package/src/spine.js +381 -0
  97. package/src/stable-id.js +142 -0
@@ -0,0 +1,975 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ CANONICAL_PACKAGE_EFFECT_VERSION
5
+ } = require('../handler/canonical-runtime.js');
6
+
7
+ const PACKAGE_CONTRACT_VERSION = 'pulse.package-contract.v1';
8
+ const PACKAGE_REALIZATION_ARTIFACT_SET_VERSION = 'pulse.package-realization-artifact-set.v1';
9
+ const PACKAGE_CONTRACT_KIND = 'pulse.package-contract';
10
+ const PACKAGE_TARGET_SUPPORT_VERSION = 'pulse.package-target-support.v1';
11
+ const PACKAGE_COMPOSITION_VERSION = 'pulse.package-composition.v1';
12
+ const PACKAGE_CONFORMANCE_VERSION = 'pulse.package-conformance.v1';
13
+ const PACKAGE_CONTRACT_CATALOG_VERSION = 'pulse.package-contract-catalog.v2';
14
+ const PACKAGE_CONTRACT_DISCOVERY_VERSION = 'pulse.package-contract-discovery.v1';
15
+ const PACKAGE_PRODUCT_METADATA_PACKAGE_POLICY = 'any-static-npm-package';
16
+ const PACKAGE_NATIVE_LOWERING_TRUST_POLICY = 'first-party-only';
17
+ const PROFILE_TOKEN_POLICY = 'opaque-direct-use';
18
+ const CANONICAL_PACKAGE_OPERATION_VERSION = 'pulse.canonical-package-operation.v1';
19
+ const PACKAGE_LOWERING_BUNDLE_VERSION = 'pulse.package-lowering-bundle.v1';
20
+ const PACKAGE_INTRINSIC_VERSION = 'pulse.package-intrinsic.v1';
21
+ const PACKAGE_CRYPTO_REQUIREMENT_VERSION = 'pulse.package-crypto-requirement.v1';
22
+ const PROVIDER_REQUIREMENT_RECORD_VERSION = 'pulse.provider-requirement-record.v1';
23
+ const GUEST_UNIT_CONTRIBUTION_VERSION = 'pulse.guest-unit-contribution.v1';
24
+ const PACKAGE_BUILDER_INVOCATION_VERSION = 'pulse.package-builder-invocation.v1';
25
+ const PACKAGE_BUILDER_RESULT_VERSION = 'pulse.package-builder-result.v1';
26
+ const PACKAGE_INSPECTION_ARTIFACT_VERSION = 'pulse.package-inspection-artifact.v1';
27
+ const CANONICAL_PACKAGE_INSPECTION_VERSION = 'pulse.canonical-package-inspection.v1';
28
+ const PACKAGE_MANAGED_HANDLER_DESCRIPTOR_VERSION = 'pulse.managed-handler-descriptor.v1';
29
+
30
+ const PACKAGE_BUILDER_INVOCATION_FIELDS = Object.freeze([
31
+ 'version',
32
+ 'cwd',
33
+ 'workspaceRoot',
34
+ 'sourcePath',
35
+ 'sourceText',
36
+ 'sourceFile',
37
+ 'typescript',
38
+ 'manifest',
39
+ 'libraryContracts',
40
+ 'packageCompilerBuilder',
41
+ 'generatedBy',
42
+ 'routePlan',
43
+ 'schemaBundle'
44
+ ]);
45
+ const PACKAGE_BUILDER_RAW_RESULT_FIELDS = Object.freeze([
46
+ 'artifact',
47
+ 'entries',
48
+ 'canonicalEffects',
49
+ 'canonicalIntrinsics',
50
+ 'schemaReferences',
51
+ 'cryptoRequirements',
52
+ 'keyArtifacts',
53
+ 'realizationArtifacts',
54
+ 'inspectionArtifacts',
55
+ 'managedHandlers',
56
+ 'guestUnits',
57
+ 'resultAdapters',
58
+ 'diagnostics',
59
+ 'warnings',
60
+ 'unsupported',
61
+ 'payloadModes',
62
+ 'manifest',
63
+ 'packageCompilerBuilder',
64
+ 'dependencies',
65
+ 'hasErrors'
66
+ ]);
67
+ const CANONICAL_PACKAGE_EFFECT_FIELDS = Object.freeze([
68
+ 'version',
69
+ 'contractId',
70
+ 'package',
71
+ 'import',
72
+ 'kind',
73
+ 'providerKind',
74
+ 'operation',
75
+ 'capability',
76
+ 'result',
77
+ 'placement',
78
+ 'range',
79
+ 'resource',
80
+ 'payload',
81
+ 'runtimeInputs',
82
+ 'providerRequirements',
83
+ 'schemaReferences',
84
+ 'redaction',
85
+ 'clock',
86
+ 'loc'
87
+ ]);
88
+ const CANONICAL_PACKAGE_OPERATION_FIELDS = Object.freeze([
89
+ 'version',
90
+ 'id',
91
+ 'order',
92
+ 'contractId',
93
+ 'package',
94
+ 'lowerableSubpath',
95
+ 'kind',
96
+ 'providerKind',
97
+ 'operation',
98
+ 'capability',
99
+ 'result',
100
+ 'placement',
101
+ 'range',
102
+ 'resource',
103
+ 'payload',
104
+ 'runtimeInputs',
105
+ 'source',
106
+ 'hostCapabilities',
107
+ 'providerRequirements',
108
+ 'schemaReferences',
109
+ 'canonicalEffect'
110
+ ]);
111
+ const PROVIDER_REQUIREMENT_RECORD_FIELDS = Object.freeze([
112
+ 'version',
113
+ 'authorityVersion',
114
+ 'planVersion',
115
+ 'planHash',
116
+ 'providerNeutral',
117
+ 'capabilities',
118
+ 'providerKinds',
119
+ 'operations',
120
+ 'packageEffects',
121
+ 'packages',
122
+ 'packageOperationIds',
123
+ 'hostCapabilities',
124
+ 'policy'
125
+ ]);
126
+ const GUEST_UNIT_CONTRIBUTION_FIELDS = Object.freeze([
127
+ 'version',
128
+ 'id',
129
+ 'manifest',
130
+ 'owner',
131
+ 'packageVersion',
132
+ 'origin'
133
+ ]);
134
+
135
+ const TARGET_STATUSES = Object.freeze(['supported', 'provider-dependent', 'not-realized', 'unsupported']);
136
+ const REALIZATION_KINDS = Object.freeze(['canonical-package-lowering', 'javascript-package-runtime', 'provider-runtime', 'none']);
137
+ const COMPOSITION_STATUSES = Object.freeze(['supported', 'reserved', 'not-realized', 'unsupported']);
138
+ const CONFORMANCE_STATUSES = Object.freeze(['native-contract-only', 'target-overlap', 'not-realized']);
139
+
140
+ function isPlainObject(value) {
141
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
142
+ const prototype = Object.getPrototypeOf(value);
143
+ return prototype === Object.prototype || prototype === null;
144
+ }
145
+
146
+ function assertKnownKeys(value, allowed, field) {
147
+ const unknown = Object.keys(value).filter((key) => !allowed.includes(key)).sort();
148
+ if (unknown.length > 0) throw new TypeError(`${field} contains unsupported field${unknown.length === 1 ? '' : 's'}: ${unknown.join(', ')}.`);
149
+ }
150
+
151
+ function ownDataProperties(value, field) {
152
+ const symbols = Object.getOwnPropertySymbols(value);
153
+ if (symbols.length > 0) throw new TypeError(`${field} must not contain symbol fields.`);
154
+ for (const key of Object.keys(value)) {
155
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
156
+ if (!descriptor || !descriptor.enumerable || !Object.prototype.hasOwnProperty.call(descriptor, 'value')) {
157
+ throw new TypeError(`${field}.${key} must be an enumerable data property.`);
158
+ }
159
+ }
160
+ }
161
+
162
+ function nonEmptyString(value, field) {
163
+ if (typeof value !== 'string' || value.trim().length === 0) throw new TypeError(`${field} must be a non-empty string.`);
164
+ return value.trim();
165
+ }
166
+
167
+ function optionalString(value, field) {
168
+ if (value == null) return null;
169
+ return nonEmptyString(value, field);
170
+ }
171
+
172
+ function sortedUnique(values, field) {
173
+ if (!Array.isArray(values)) throw new TypeError(`${field} must be an array.`);
174
+ const normalized = values.map((value, index) => nonEmptyString(value, `${field}[${index}]`));
175
+ return Object.freeze([...new Set(normalized)].sort());
176
+ }
177
+
178
+ function immutableData(value, field, seen = new Set()) {
179
+ if (value === null || value === undefined || typeof value === 'string' || typeof value === 'boolean') return value;
180
+ if (typeof value === 'number') {
181
+ if (!Number.isFinite(value)) throw new TypeError(`${field} must contain only finite numbers.`);
182
+ return value;
183
+ }
184
+ if (typeof value !== 'object') throw new TypeError(`${field} must contain only immutable data values.`);
185
+ if (seen.has(value)) throw new TypeError(`${field} must not contain cycles.`);
186
+ seen.add(value);
187
+ let normalized;
188
+ if (Array.isArray(value)) {
189
+ normalized = value.map((entry, index) => immutableData(entry, `${field}[${index}]`, seen));
190
+ } else {
191
+ if (!isPlainObject(value)) throw new TypeError(`${field} must contain only ordinary objects.`);
192
+ ownDataProperties(value, field);
193
+ normalized = Object.fromEntries(Object.keys(value)
194
+ .sort()
195
+ .map((key) => [key, immutableData(value[key], `${field}.${key}`, seen)]));
196
+ }
197
+ seen.delete(value);
198
+ return deepFreeze(normalized);
199
+ }
200
+
201
+ function optionalImmutableData(value, field) {
202
+ return value == null ? null : immutableData(value, field);
203
+ }
204
+
205
+ function assertSortedUnique(values, field) {
206
+ const normalized = sortedUnique(values, field);
207
+ if (normalized.length !== values.length || normalized.some((value, index) => value !== values[index])) {
208
+ throw new TypeError(`${field} must be sorted and contain no duplicates.`);
209
+ }
210
+ return normalized;
211
+ }
212
+
213
+ function packageName(value, field) {
214
+ const normalized = nonEmptyString(value, field);
215
+ if (!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(normalized)) throw new TypeError(`${field} must be a valid npm package name.`);
216
+ return normalized;
217
+ }
218
+
219
+ function contractId(value, field) {
220
+ const normalized = nonEmptyString(value, field);
221
+ if (!/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/.test(normalized)) throw new TypeError(`${field} must be a stable dotted contract identity.`);
222
+ return normalized;
223
+ }
224
+
225
+ function fragmentKey(value, field) {
226
+ const normalized = nonEmptyString(value, field);
227
+ if (!/^[a-z][a-z0-9-]*$/.test(normalized)) throw new TypeError(`${field} must be a lowercase profile-fragment key.`);
228
+ return normalized;
229
+ }
230
+
231
+ function packageSpecifier(value, field) {
232
+ const normalized = nonEmptyString(value, field);
233
+ if (!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*(?:\/[A-Za-z0-9._-]+)*$/.test(normalized)) {
234
+ throw new TypeError(`${field} must be a package root or subpath.`);
235
+ }
236
+ return normalized;
237
+ }
238
+
239
+ function packageRelativePath(value, field) {
240
+ const normalized = nonEmptyString(value, field).replace(/\\/g, '/');
241
+ if (normalized.startsWith('/') || normalized === '..' || normalized.startsWith('../') || normalized.includes('/../')) {
242
+ throw new TypeError(`${field} must remain package-relative.`);
243
+ }
244
+ return normalized.startsWith('./') ? normalized : `./${normalized}`;
245
+ }
246
+
247
+ function normalizePackageBuilderAuthority(authority = {}) {
248
+ if (!isPlainObject(authority)) throw new TypeError('Package builder authority must be an object.');
249
+ assertKnownKeys(authority, ['contractId', 'npmPackage', 'lowerableSubpath', 'hostCapabilities'], 'package builder authority');
250
+ return deepFreeze({
251
+ contractId: contractId(authority.contractId, 'package builder authority.contractId'),
252
+ npmPackage: packageName(authority.npmPackage, 'package builder authority.npmPackage'),
253
+ lowerableSubpath: packageSpecifier(authority.lowerableSubpath, 'package builder authority.lowerableSubpath')
254
+ });
255
+ }
256
+
257
+ function normalizePackageCompilerBuilder(input, authority) {
258
+ if (!isPlainObject(input)) throw new TypeError('packageCompilerBuilder must be an object.');
259
+ assertKnownKeys(input, ['owner', 'entry', 'export', 'trust'], 'packageCompilerBuilder');
260
+ ownDataProperties(input, 'packageCompilerBuilder');
261
+ const normalized = {
262
+ owner: packageName(input.owner, 'packageCompilerBuilder.owner'),
263
+ entry: nonEmptyString(input.entry, 'packageCompilerBuilder.entry').replace(/\\/g, '/'),
264
+ export: nonEmptyString(input.export, 'packageCompilerBuilder.export'),
265
+ trust: nonEmptyString(input.trust, 'packageCompilerBuilder.trust')
266
+ };
267
+ if (normalized.owner !== authority.npmPackage) throw new TypeError('packageCompilerBuilder.owner must equal the manifest npmPackage.');
268
+ if (normalized.trust !== 'first-party') throw new TypeError('packageCompilerBuilder.trust must be first-party.');
269
+ return deepFreeze(normalized);
270
+ }
271
+
272
+ function normalizePackageBuilderInvocation(input, authorityInput = {}) {
273
+ if (!isPlainObject(input)) throw new TypeError('Package builder invocation must be an object.');
274
+ assertKnownKeys(input, PACKAGE_BUILDER_INVOCATION_FIELDS, 'package builder invocation');
275
+ ownDataProperties(input, 'package builder invocation');
276
+ if (input.version !== PACKAGE_BUILDER_INVOCATION_VERSION) {
277
+ throw new TypeError(`Package builder invocation must use ${PACKAGE_BUILDER_INVOCATION_VERSION}.`);
278
+ }
279
+ const authority = normalizePackageBuilderAuthority(authorityInput);
280
+ if (!isPlainObject(input.manifest)) throw new TypeError('package builder invocation.manifest must be an object.');
281
+ if (
282
+ input.manifest.contractId !== authority.contractId
283
+ || input.manifest.npmPackage !== authority.npmPackage
284
+ || input.manifest.lowerableSubpath !== authority.lowerableSubpath
285
+ ) {
286
+ throw new TypeError('Package builder invocation manifest identity must equal its selected authority.');
287
+ }
288
+ if (input.sourceFile != null && typeof input.sourceFile !== 'object') {
289
+ throw new TypeError('package builder invocation.sourceFile must be a compiler-owned source file or null.');
290
+ }
291
+ if (input.typescript != null && typeof input.typescript !== 'object') {
292
+ throw new TypeError('package builder invocation.typescript must be the compiler-owned TypeScript API or null.');
293
+ }
294
+ const sourcePath = nonEmptyString(input.sourcePath, 'package builder invocation.sourcePath').replace(/\\/g, '/');
295
+ const sourceText = typeof input.sourceText === 'string'
296
+ ? input.sourceText
297
+ : (() => { throw new TypeError('package builder invocation.sourceText must be a string.'); })();
298
+ const libraryContracts = immutableData(input.libraryContracts || [], 'package builder invocation.libraryContracts');
299
+ if (!Array.isArray(libraryContracts)) throw new TypeError('package builder invocation.libraryContracts must be an array.');
300
+ return Object.freeze({
301
+ version: PACKAGE_BUILDER_INVOCATION_VERSION,
302
+ cwd: nonEmptyString(input.cwd, 'package builder invocation.cwd').replace(/\\/g, '/'),
303
+ workspaceRoot: input.workspaceRoot == null
304
+ ? null
305
+ : nonEmptyString(input.workspaceRoot, 'package builder invocation.workspaceRoot').replace(/\\/g, '/'),
306
+ sourcePath,
307
+ sourceText,
308
+ // TypeScript owns these syntax objects. The exact invocation envelope is
309
+ // immutable; builders receive no Program, language service, cache, CLI
310
+ // configuration, provider descriptor, or runtime object.
311
+ sourceFile: input.sourceFile || null,
312
+ typescript: input.typescript || null,
313
+ manifest: immutableData(input.manifest, 'package builder invocation.manifest'),
314
+ libraryContracts,
315
+ packageCompilerBuilder: normalizePackageCompilerBuilder(input.packageCompilerBuilder, authority),
316
+ generatedBy: nonEmptyString(input.generatedBy, 'package builder invocation.generatedBy'),
317
+ routePlan: optionalImmutableData(input.routePlan, 'package builder invocation.routePlan'),
318
+ schemaBundle: optionalImmutableData(input.schemaBundle, 'package builder invocation.schemaBundle')
319
+ });
320
+ }
321
+
322
+ function sourceOrder(value) {
323
+ const range = value && value.range;
324
+ return range && Number.isSafeInteger(range.start) ? range.start : Number.MAX_SAFE_INTEGER;
325
+ }
326
+
327
+ function assertSourceOrdered(values, field) {
328
+ let previous = -1;
329
+ for (const [index, value] of values.entries()) {
330
+ const current = sourceOrder(value);
331
+ if (current < previous) throw new TypeError(`${field} must remain in deterministic source order.`);
332
+ previous = current;
333
+ if (!isPlainObject(value)) throw new TypeError(`${field}[${index}] must be an object.`);
334
+ }
335
+ }
336
+
337
+ function artifactPackageIdentity(artifact) {
338
+ const packageValue = artifact.package === undefined ? artifact.npmPackage : artifact.package;
339
+ return packageValue === undefined ? '' : String(packageValue);
340
+ }
341
+
342
+ function assertNoForbiddenBoundaryFields(value, field) {
343
+ const forbidden = new Set([
344
+ 'targetDescriptor',
345
+ 'packageTarget',
346
+ 'providerDriver',
347
+ 'runtimeObject',
348
+ 'rawCliConfig',
349
+ 'compilerCache',
350
+ 'program',
351
+ 'languageService',
352
+ 'typeChecker',
353
+ 'resolvedSecret',
354
+ 'resolvedSecrets',
355
+ 'secretValue',
356
+ 'secretValues'
357
+ ]);
358
+ if (!value || typeof value !== 'object') return;
359
+ if (Array.isArray(value)) {
360
+ value.forEach((entry, index) => assertNoForbiddenBoundaryFields(entry, `${field}[${index}]`));
361
+ return;
362
+ }
363
+ for (const key of Object.keys(value)) {
364
+ if (forbidden.has(key)) throw new TypeError(`${field} must not contain compiler, provider, runtime, or resolved-secret field ${key}.`);
365
+ assertNoForbiddenBoundaryFields(value[key], `${field}.${key}`);
366
+ }
367
+ }
368
+
369
+ function normalizePackageBuilderResult(input, authorityInput = {}) {
370
+ if (!isPlainObject(input)) throw new TypeError('Package builder result must be an object.');
371
+ assertKnownKeys(input, PACKAGE_BUILDER_RAW_RESULT_FIELDS, 'package builder result');
372
+ ownDataProperties(input, 'package builder result');
373
+ const authority = normalizePackageBuilderAuthority(authorityInput);
374
+ if (!isPlainObject(input.artifact)) throw new TypeError('package builder result.artifact must be an object.');
375
+ if (
376
+ input.artifact.contractId !== authority.contractId
377
+ || artifactPackageIdentity(input.artifact) !== authority.npmPackage
378
+ || (
379
+ input.artifact.lowerableSubpath !== undefined
380
+ && input.artifact.lowerableSubpath !== authority.lowerableSubpath
381
+ )
382
+ ) {
383
+ throw new TypeError('Package builder result artifact identity must equal its selected authority.');
384
+ }
385
+ if (typeof input.artifact.version !== 'string' || input.artifact.version.length === 0) {
386
+ throw new TypeError('package builder result.artifact.version must be a non-empty package-owned identity.');
387
+ }
388
+ if (!['ok', 'error'].includes(String(input.artifact.status || ''))) {
389
+ throw new TypeError('package builder result.artifact.status must be ok or error.');
390
+ }
391
+ assertNoForbiddenBoundaryFields(input.artifact, 'package builder result.artifact');
392
+ const array = (name) => {
393
+ const value = input[name] == null ? [] : input[name];
394
+ if (!Array.isArray(value)) throw new TypeError(`package builder result.${name} must be an array.`);
395
+ const normalized = immutableData(value, `package builder result.${name}`);
396
+ assertNoForbiddenBoundaryFields(normalized, `package builder result.${name}`);
397
+ return normalized;
398
+ };
399
+ const canonicalEffects = Object.freeze(array('canonicalEffects')
400
+ .map((entry) => normalizeCanonicalPackageEffect(entry, authority)));
401
+ const canonicalIntrinsics = array('canonicalIntrinsics');
402
+ assertSourceOrdered(canonicalEffects, 'package builder result.canonicalEffects');
403
+ assertSourceOrdered(canonicalIntrinsics, 'package builder result.canonicalIntrinsics');
404
+ const diagnostics = array('diagnostics');
405
+ const warnings = array('warnings');
406
+ const hasErrors = input.hasErrors === undefined
407
+ ? diagnostics.some((entry) => String(entry && entry.severity || 'error') === 'error')
408
+ : input.hasErrors;
409
+ if (typeof hasErrors !== 'boolean') throw new TypeError('package builder result.hasErrors must be a boolean.');
410
+ if (hasErrors !== diagnostics.some((entry) => String(entry && entry.severity || 'error') === 'error')) {
411
+ throw new TypeError('package builder result.hasErrors must equal its normalized diagnostic error state.');
412
+ }
413
+ return deepFreeze({
414
+ version: PACKAGE_BUILDER_RESULT_VERSION,
415
+ contractId: authority.contractId,
416
+ npmPackage: authority.npmPackage,
417
+ lowerableSubpath: authority.lowerableSubpath,
418
+ artifact: immutableData(input.artifact, 'package builder result.artifact'),
419
+ contributions: {
420
+ canonicalEffects,
421
+ canonicalIntrinsics,
422
+ resultAdapters: array('resultAdapters'),
423
+ schemaReferences: array('schemaReferences'),
424
+ cryptoRequirements: array('cryptoRequirements'),
425
+ realizationArtifacts: array('realizationArtifacts'),
426
+ inspectionArtifacts: array('inspectionArtifacts'),
427
+ managedHandlers: array('managedHandlers'),
428
+ guestUnits: Object.freeze(array('guestUnits').map(normalizeCanonicalGuestUnitContribution))
429
+ },
430
+ diagnostics,
431
+ warnings,
432
+ hasErrors
433
+ });
434
+ }
435
+
436
+ function normalizeCanonicalRuntimeInputs(values) {
437
+ if (values == null) return Object.freeze([]);
438
+ if (!Array.isArray(values)) throw new TypeError('canonical package effect.runtimeInputs must be an array.');
439
+ const names = new Set();
440
+ return Object.freeze(values.map((input, index) => {
441
+ if (!isPlainObject(input)) throw new TypeError(`canonical package effect.runtimeInputs[${index}] must be an object.`);
442
+ assertKnownKeys(input, ['name', 'argumentIndex', 'source'], `canonical package effect.runtimeInputs[${index}]`);
443
+ ownDataProperties(input, `canonical package effect.runtimeInputs[${index}]`);
444
+ const normalized = {
445
+ name: nonEmptyString(input.name, `canonical package effect.runtimeInputs[${index}].name`),
446
+ argumentIndex: input.argumentIndex,
447
+ source: nonEmptyString(input.source, `canonical package effect.runtimeInputs[${index}].source`)
448
+ };
449
+ if (names.has(normalized.name)) throw new TypeError('canonical package effect.runtimeInputs names must be unique.');
450
+ if (!Number.isSafeInteger(normalized.argumentIndex) || normalized.argumentIndex < 0) {
451
+ throw new TypeError('canonical package effect.runtimeInputs argument indexes must be non-negative integers.');
452
+ }
453
+ if (normalized.source !== 'package-call-argument') {
454
+ throw new TypeError('canonical package effect.runtimeInputs source must be package-call-argument.');
455
+ }
456
+ names.add(normalized.name);
457
+ return deepFreeze(normalized);
458
+ }));
459
+ }
460
+
461
+ function normalizeCanonicalPackageEffect(input, authorityInput = {}) {
462
+ if (!isPlainObject(input)) throw new TypeError('Canonical package effect must be an object.');
463
+ assertKnownKeys(input, CANONICAL_PACKAGE_EFFECT_FIELDS, 'canonical package effect');
464
+ ownDataProperties(input, 'canonical package effect');
465
+ if (input.version !== CANONICAL_PACKAGE_EFFECT_VERSION) {
466
+ throw new TypeError(`Canonical package effect must use ${CANONICAL_PACKAGE_EFFECT_VERSION}.`);
467
+ }
468
+ const authority = normalizePackageBuilderAuthority(authorityInput);
469
+ if (
470
+ input.contractId !== authority.contractId
471
+ || input.package !== authority.npmPackage
472
+ || input.import !== authority.lowerableSubpath
473
+ ) {
474
+ throw new TypeError('Canonical package effect identity must equal its manifest authority.');
475
+ }
476
+ for (const field of ['kind', 'providerKind', 'operation', 'capability', 'result', 'placement']) {
477
+ nonEmptyString(input[field], `canonical package effect.${field}`);
478
+ }
479
+ if (
480
+ !isPlainObject(input.range)
481
+ || !Number.isSafeInteger(input.range.start)
482
+ || !Number.isSafeInteger(input.range.end)
483
+ || input.range.start < 0
484
+ || input.range.end < input.range.start
485
+ ) {
486
+ throw new TypeError('canonical package effect.range must contain a bounded start and end.');
487
+ }
488
+ const providerRequirements = sortedUnique(input.providerRequirements || [], 'canonical package effect.providerRequirements');
489
+ return deepFreeze({
490
+ ...immutableData(input, 'canonical package effect'),
491
+ runtimeInputs: normalizeCanonicalRuntimeInputs(input.runtimeInputs),
492
+ providerRequirements
493
+ });
494
+ }
495
+
496
+ function createCanonicalPackageOperation(effectInput, authorityInput = {}, order) {
497
+ if (!Number.isSafeInteger(order) || order < 1) throw new TypeError('Canonical package operation order must be a positive integer.');
498
+ const authority = normalizePackageBuilderAuthority(authorityInput);
499
+ const effect = normalizeCanonicalPackageEffect(effectInput, authority);
500
+ const hostCapabilities = sortedUnique(authorityInput.hostCapabilities || [], 'canonical package operation.hostCapabilities');
501
+ return deepFreeze({
502
+ version: CANONICAL_PACKAGE_OPERATION_VERSION,
503
+ id: `${authority.contractId}:${order}:${effect.kind}`,
504
+ order,
505
+ contractId: authority.contractId,
506
+ package: authority.npmPackage,
507
+ lowerableSubpath: authority.lowerableSubpath,
508
+ kind: effect.kind,
509
+ providerKind: effect.providerKind,
510
+ operation: effect.operation,
511
+ capability: effect.capability,
512
+ result: effect.result,
513
+ placement: effect.placement,
514
+ range: effect.range,
515
+ resource: effect.resource,
516
+ payload: effect.payload,
517
+ runtimeInputs: effect.runtimeInputs,
518
+ source: effect.loc,
519
+ hostCapabilities,
520
+ providerRequirements: effect.providerRequirements,
521
+ schemaReferences: Object.freeze((effect.schemaReferences || []).map((entry, index) => immutableData(entry, `canonical package effect.schemaReferences[${index}]`))),
522
+ canonicalEffect: effect
523
+ });
524
+ }
525
+
526
+ function normalizeCanonicalPackageOperation(input, authorityInput) {
527
+ if (!isPlainObject(input)) throw new TypeError('Canonical package operation must be an object.');
528
+ assertKnownKeys(input, CANONICAL_PACKAGE_OPERATION_FIELDS, 'canonical package operation');
529
+ ownDataProperties(input, 'canonical package operation');
530
+ if (input.version !== CANONICAL_PACKAGE_OPERATION_VERSION) {
531
+ throw new TypeError(`Canonical package operation must use ${CANONICAL_PACKAGE_OPERATION_VERSION}.`);
532
+ }
533
+ const authority = normalizePackageBuilderAuthority(authorityInput || {
534
+ contractId: input.contractId,
535
+ npmPackage: input.package,
536
+ lowerableSubpath: input.lowerableSubpath
537
+ });
538
+ const effect = normalizeCanonicalPackageEffect(input.canonicalEffect, authority);
539
+ const expected = createCanonicalPackageOperation(effect, {
540
+ ...authority,
541
+ hostCapabilities: input.hostCapabilities
542
+ }, input.order);
543
+ const actual = immutableData(input, 'canonical package operation');
544
+ const canonicalExpected = immutableData(expected, 'canonical package operation expected');
545
+ if (JSON.stringify(actual) !== JSON.stringify(canonicalExpected)) {
546
+ throw new TypeError('Canonical package operation fields must exactly match its owned effect and deterministic identity.');
547
+ }
548
+ return expected;
549
+ }
550
+
551
+ function normalizePackageLoweringBundle(input) {
552
+ if (!isPlainObject(input)) throw new TypeError('Package lowering bundle must be an object.');
553
+ assertKnownKeys(input, [
554
+ 'inputVersion',
555
+ 'operations',
556
+ 'packages',
557
+ 'schemaReferences',
558
+ 'realizationArtifacts',
559
+ 'guestUnits',
560
+ 'cryptoRequirements'
561
+ ], 'package lowering bundle input');
562
+ ownDataProperties(input, 'package lowering bundle input');
563
+ const operations = (input.operations || []).map((operation) => normalizeCanonicalPackageOperation(operation));
564
+ for (const [index, operation] of operations.entries()) {
565
+ if (operation.order !== index + 1) throw new TypeError('Canonical package operations must be contiguous and source ordered.');
566
+ }
567
+ const packages = immutableData(input.packages || [], 'package lowering bundle.packages')
568
+ .slice()
569
+ .sort((left, right) => String(left.contractId || '').localeCompare(String(right.contractId || '')));
570
+ const byId = (name) => immutableData(input[name] || [], `package lowering bundle.${name}`)
571
+ .slice()
572
+ .sort((left, right) => String(left.id || '').localeCompare(String(right.id || '')));
573
+ const cryptoRequirements = immutableData(input.cryptoRequirements || [], 'package lowering bundle.cryptoRequirements')
574
+ .slice()
575
+ .sort((left, right) => String(left.requestedBy || '').localeCompare(String(right.requestedBy || ''))
576
+ || String(left.semanticOwner || '').localeCompare(String(right.semanticOwner || '')));
577
+ return deepFreeze({
578
+ version: PACKAGE_LOWERING_BUNDLE_VERSION,
579
+ inputVersion: nonEmptyString(input.inputVersion, 'package lowering bundle.inputVersion'),
580
+ operationVersion: CANONICAL_PACKAGE_OPERATION_VERSION,
581
+ operations,
582
+ packages,
583
+ effects: operations.map((operation) => operation.canonicalEffect),
584
+ requiredHostCapabilities: sortedUnique(operations.flatMap((operation) => operation.hostCapabilities), 'package lowering bundle.requiredHostCapabilities'),
585
+ requiredProviderCapabilities: sortedUnique(operations.flatMap((operation) => operation.providerRequirements), 'package lowering bundle.requiredProviderCapabilities'),
586
+ schemaReferences: immutableData(input.schemaReferences || [], 'package lowering bundle.schemaReferences'),
587
+ realizationArtifacts: byId('realizationArtifacts'),
588
+ guestUnits: byId('guestUnits'),
589
+ cryptoRequirements,
590
+ policy: {
591
+ sourceAstAccepted: false,
592
+ sourceTextAccepted: false,
593
+ canonicalOperationsOnly: true,
594
+ publicPluginApi: false,
595
+ dynamicRegistration: false
596
+ }
597
+ });
598
+ }
599
+
600
+ function normalizeProviderRequirementRecord(input) {
601
+ if (!isPlainObject(input)) throw new TypeError('Provider requirement record must be an object.');
602
+ assertKnownKeys(input, PROVIDER_REQUIREMENT_RECORD_FIELDS, 'provider requirement record');
603
+ ownDataProperties(input, 'provider requirement record');
604
+ if (input.version !== PROVIDER_REQUIREMENT_RECORD_VERSION) {
605
+ throw new TypeError(`Provider requirement record must use ${PROVIDER_REQUIREMENT_RECORD_VERSION}.`);
606
+ }
607
+ if (input.providerNeutral !== true) throw new TypeError('Provider requirement record must remain provider-neutral.');
608
+ const policy = input.policy;
609
+ if (!isPlainObject(policy)) throw new TypeError('provider requirement record.policy must be an object.');
610
+ const expectedPolicy = {
611
+ providerSelected: false,
612
+ providerNeutralPlanRequired: true,
613
+ sourceAstAccepted: false,
614
+ sourceTextAccepted: false,
615
+ canonicalPlanOnly: true,
616
+ packageLoweringBundleOnly: true
617
+ };
618
+ assertKnownKeys(policy, Object.keys(expectedPolicy), 'provider requirement record.policy');
619
+ for (const [key, expected] of Object.entries(expectedPolicy)) {
620
+ if (policy[key] !== expected) throw new TypeError(`provider requirement record.policy.${key} must be ${expected}.`);
621
+ }
622
+ return deepFreeze({
623
+ version: PROVIDER_REQUIREMENT_RECORD_VERSION,
624
+ authorityVersion: nonEmptyString(input.authorityVersion, 'provider requirement record.authorityVersion'),
625
+ planVersion: nonEmptyString(input.planVersion, 'provider requirement record.planVersion'),
626
+ planHash: nonEmptyString(input.planHash, 'provider requirement record.planHash'),
627
+ providerNeutral: true,
628
+ capabilities: assertSortedUnique(input.capabilities || [], 'provider requirement record.capabilities'),
629
+ providerKinds: assertSortedUnique(input.providerKinds || [], 'provider requirement record.providerKinds'),
630
+ operations: immutableData(input.operations || [], 'provider requirement record.operations'),
631
+ packageEffects: immutableData(input.packageEffects || [], 'provider requirement record.packageEffects'),
632
+ packages: immutableData(input.packages || [], 'provider requirement record.packages')
633
+ .slice()
634
+ .sort((left, right) => String(left.contractId || '').localeCompare(String(right.contractId || ''))
635
+ || String(left.package || '').localeCompare(String(right.package || ''))),
636
+ packageOperationIds: immutableData(input.packageOperationIds || [], 'provider requirement record.packageOperationIds'),
637
+ hostCapabilities: assertSortedUnique(input.hostCapabilities || [], 'provider requirement record.hostCapabilities'),
638
+ policy: expectedPolicy
639
+ });
640
+ }
641
+
642
+ function normalizeGuestUnitContribution(input, authority = {}) {
643
+ if (!isPlainObject(input)) throw new TypeError('Guest-unit contribution must be an object.');
644
+ assertKnownKeys(input, ['version', 'id', 'manifest'], 'guest-unit contribution');
645
+ if (input.version !== GUEST_UNIT_CONTRIBUTION_VERSION) {
646
+ throw new TypeError(`Guest-unit contribution must use ${GUEST_UNIT_CONTRIBUTION_VERSION}.`);
647
+ }
648
+ const id = contractId(input.id, 'guest-unit contribution.id');
649
+ const owner = packageName(authority.owner, 'guest-unit contribution authority.owner');
650
+ const packageVersion = nonEmptyString(authority.packageVersion, 'guest-unit contribution authority.packageVersion');
651
+ if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(packageVersion)) {
652
+ throw new TypeError('guest-unit contribution authority.packageVersion must be an exact semantic version.');
653
+ }
654
+ return deepFreeze({
655
+ version: GUEST_UNIT_CONTRIBUTION_VERSION,
656
+ id,
657
+ manifest: packageRelativePath(input.manifest, 'guest-unit contribution.manifest'),
658
+ owner,
659
+ packageVersion,
660
+ origin: 'package-prebuilt'
661
+ });
662
+ }
663
+
664
+ function normalizeCanonicalGuestUnitContribution(input) {
665
+ if (!isPlainObject(input)) throw new TypeError('Canonical guest-unit contribution must be an object.');
666
+ assertKnownKeys(input, GUEST_UNIT_CONTRIBUTION_FIELDS, 'canonical guest-unit contribution');
667
+ ownDataProperties(input, 'canonical guest-unit contribution');
668
+ if (input.origin !== 'package-prebuilt') {
669
+ throw new TypeError('canonical guest-unit contribution.origin must be package-prebuilt.');
670
+ }
671
+ const normalized = normalizeGuestUnitContribution({
672
+ version: input.version,
673
+ id: input.id,
674
+ manifest: input.manifest
675
+ }, {
676
+ owner: input.owner,
677
+ packageVersion: input.packageVersion
678
+ });
679
+ for (const field of GUEST_UNIT_CONTRIBUTION_FIELDS) {
680
+ if (input[field] !== normalized[field]) {
681
+ throw new TypeError(`Canonical guest-unit contribution.${field} must match its normalized value.`);
682
+ }
683
+ }
684
+ return normalized;
685
+ }
686
+
687
+ function clone(value) {
688
+ if (Array.isArray(value)) return value.map(clone);
689
+ if (!value || typeof value !== 'object') return value;
690
+ return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, clone(child)]));
691
+ }
692
+
693
+ function deepFreeze(value) {
694
+ if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
695
+ for (const child of Object.values(value)) deepFreeze(child);
696
+ return Object.freeze(value);
697
+ }
698
+
699
+ function normalizeTarget(name, input = {}) {
700
+ if (!isPlainObject(input)) throw new TypeError(`targets.${name} must be an object.`);
701
+ assertKnownKeys(input, ['version', 'status', 'realization', 'entry', 'lowerableSubpath', 'providerRequirements', 'reasonCode'], `targets.${name}`);
702
+ if (input.version != null && input.version !== PACKAGE_TARGET_SUPPORT_VERSION) throw new TypeError(`targets.${name}.version must be ${PACKAGE_TARGET_SUPPORT_VERSION}.`);
703
+ const status = nonEmptyString(input.status, `targets.${name}.status`);
704
+ if (!TARGET_STATUSES.includes(status)) throw new TypeError(`targets.${name}.status must be one of ${TARGET_STATUSES.join(', ')}.`);
705
+ const realization = nonEmptyString(input.realization || 'none', `targets.${name}.realization`);
706
+ if (!REALIZATION_KINDS.includes(realization)) throw new TypeError(`targets.${name}.realization must be one of ${REALIZATION_KINDS.join(', ')}.`);
707
+ const reasonCode = optionalString(input.reasonCode, `targets.${name}.reasonCode`);
708
+ const entry = input.entry == null ? null : packageRelativePath(input.entry, `targets.${name}.entry`);
709
+ const lowerableSubpath = input.lowerableSubpath == null ? null : packageSpecifier(input.lowerableSubpath, `targets.${name}.lowerableSubpath`);
710
+ const providerRequirements = sortedUnique(input.providerRequirements || [], `targets.${name}.providerRequirements`);
711
+
712
+ if (['not-realized', 'unsupported'].includes(status) && !reasonCode) throw new TypeError(`targets.${name}.reasonCode is required when status is ${status}.`);
713
+ if (status === 'supported' && realization === 'none') throw new TypeError(`targets.${name}.realization cannot be none when the target is supported.`);
714
+ if (status === 'not-realized' && (realization !== 'none' || entry || lowerableSubpath || providerRequirements.length > 0)) {
715
+ throw new TypeError(`targets.${name} not-realized must use realization none without entry, lowerableSubpath, or provider requirements.`);
716
+ }
717
+ if (name === 'native' && status === 'supported' && realization !== 'canonical-package-lowering') {
718
+ throw new TypeError('A supported native target must use canonical-package-lowering.');
719
+ }
720
+ if (name === 'javascript' && status === 'supported' && (realization !== 'javascript-package-runtime' || !entry)) {
721
+ throw new TypeError('A supported JavaScript target must use javascript-package-runtime and declare entry.');
722
+ }
723
+
724
+ return deepFreeze({
725
+ version: PACKAGE_TARGET_SUPPORT_VERSION,
726
+ status,
727
+ realization,
728
+ entry,
729
+ lowerableSubpath,
730
+ providerRequirements,
731
+ reasonCode
732
+ });
733
+ }
734
+
735
+ function normalizePackageContract(input) {
736
+ if (!isPlainObject(input)) throw new TypeError('Pulse package contract must be an object.');
737
+ assertKnownKeys(input, ['version', 'kind', 'contractId', 'npmPackage', 'description', 'authoring', 'ownership', 'composition', 'targets', 'lowering', 'conformance', 'docs', 'policy'], 'package contract');
738
+ if (input.version !== PACKAGE_CONTRACT_VERSION) throw new TypeError(`Package contract must use ${PACKAGE_CONTRACT_VERSION}.`);
739
+ if (input.kind !== PACKAGE_CONTRACT_KIND) throw new TypeError(`Package contract kind must be ${PACKAGE_CONTRACT_KIND}.`);
740
+
741
+ const normalizedPackage = packageName(input.npmPackage, 'npmPackage');
742
+ const authoring = isPlainObject(input.authoring) ? input.authoring : {};
743
+ const ownership = isPlainObject(input.ownership) ? input.ownership : {};
744
+ const composition = isPlainObject(input.composition) ? input.composition : {};
745
+ const lowering = isPlainObject(input.lowering) ? input.lowering : {};
746
+ const conformance = isPlainObject(input.conformance) ? input.conformance : {};
747
+ const docs = isPlainObject(input.docs) ? input.docs : {};
748
+ const expectedPolicy = Object.freeze({
749
+ externalCompilerPlugin: false,
750
+ arbitraryCompilerAccess: false,
751
+ resolvedProfileValues: false,
752
+ resolvedSecretValues: false,
753
+ targetFallback: false,
754
+ packageOwnsProfileFragment: true,
755
+ graphOwnsHelperAttribution: true,
756
+ loweringConsumesCanonicalOperationsOnly: true
757
+ });
758
+ if (input.policy != null) {
759
+ if (!isPlainObject(input.policy)) throw new TypeError('policy must be an object.');
760
+ assertKnownKeys(input.policy, Object.keys(expectedPolicy), 'policy');
761
+ for (const [key, expected] of Object.entries(expectedPolicy)) {
762
+ if (input.policy[key] !== undefined && input.policy[key] !== expected) throw new TypeError(`policy.${key} is compiler-owned and must be ${expected}.`);
763
+ }
764
+ }
765
+ assertKnownKeys(authoring, ['namespace', 'import', 'symbols'], 'authoring');
766
+ assertKnownKeys(ownership, ['profileFragment', 'helperImports', 'reExportImports'], 'ownership');
767
+ assertKnownKeys(composition, ['version', 'status', 'helperSymbol', 'profileToken', 'reasonCode'], 'composition');
768
+ if (composition.version != null && composition.version !== PACKAGE_COMPOSITION_VERSION) throw new TypeError(`composition.version must be ${PACKAGE_COMPOSITION_VERSION}.`);
769
+ assertKnownKeys(lowering, ['manifest', 'trust', 'canonicalOperationVersion', 'bundleVersion', 'providerRequirementVersion'], 'lowering');
770
+ assertKnownKeys(conformance, ['version', 'status', 'fixtureRoots', 'semanticCases'], 'conformance');
771
+ if (conformance.version != null && conformance.version !== PACKAGE_CONFORMANCE_VERSION) throw new TypeError(`conformance.version must be ${PACKAGE_CONFORMANCE_VERSION}.`);
772
+ assertKnownKeys(docs, ['readme', 'contract'], 'docs');
773
+
774
+ const authoringImport = packageSpecifier(authoring.import, 'authoring.import');
775
+ if (authoringImport !== normalizedPackage && !authoringImport.startsWith(`${normalizedPackage}/`)) {
776
+ throw new TypeError('authoring.import must be owned by npmPackage.');
777
+ }
778
+
779
+ const compositionStatus = nonEmptyString(composition.status || 'not-realized', 'composition.status');
780
+ if (!COMPOSITION_STATUSES.includes(compositionStatus)) throw new TypeError(`composition.status must be one of ${COMPOSITION_STATUSES.join(', ')}.`);
781
+ const helperSymbol = optionalString(composition.helperSymbol, 'composition.helperSymbol');
782
+ const compositionReason = optionalString(composition.reasonCode, 'composition.reasonCode');
783
+ if (compositionStatus === 'supported' && !helperSymbol) throw new TypeError('composition.helperSymbol is required when composition.status is supported.');
784
+ if (['reserved', 'not-realized', 'unsupported'].includes(compositionStatus) && !compositionReason) {
785
+ throw new TypeError(`composition.reasonCode is required when composition.status is ${compositionStatus}.`);
786
+ }
787
+ const profileToken = composition.profileToken === undefined ? PROFILE_TOKEN_POLICY : nonEmptyString(composition.profileToken, 'composition.profileToken');
788
+ if (profileToken !== PROFILE_TOKEN_POLICY) throw new TypeError(`composition.profileToken must be ${PROFILE_TOKEN_POLICY}.`);
789
+
790
+ const conformanceStatus = nonEmptyString(conformance.status || 'not-realized', 'conformance.status');
791
+ if (!CONFORMANCE_STATUSES.includes(conformanceStatus)) throw new TypeError(`conformance.status must be one of ${CONFORMANCE_STATUSES.join(', ')}.`);
792
+ const fixtureRoots = sortedUnique(conformance.fixtureRoots || [], 'conformance.fixtureRoots').map((value) => packageRelativePath(value, 'conformance.fixtureRoots'));
793
+ const semanticCases = sortedUnique(conformance.semanticCases || [], 'conformance.semanticCases');
794
+ if (conformanceStatus !== 'not-realized' && (fixtureRoots.length === 0 || semanticCases.length === 0)) {
795
+ throw new TypeError(`conformance ${conformanceStatus} requires fixtureRoots and semanticCases.`);
796
+ }
797
+
798
+ const helperImports = sortedUnique(ownership.helperImports || [], 'ownership.helperImports').map((value) => packageSpecifier(value, 'ownership.helperImports'));
799
+ const reExportImports = sortedUnique(ownership.reExportImports || [], 'ownership.reExportImports').map((value) => packageSpecifier(value, 'ownership.reExportImports'));
800
+ for (const specifier of helperImports) {
801
+ if (specifier !== normalizedPackage && !specifier.startsWith(`${normalizedPackage}/`)) throw new TypeError(`Helper import ${specifier} is not owned by ${normalizedPackage}.`);
802
+ }
803
+
804
+ const normalized = {
805
+ version: PACKAGE_CONTRACT_VERSION,
806
+ kind: PACKAGE_CONTRACT_KIND,
807
+ contractId: contractId(input.contractId, 'contractId'),
808
+ npmPackage: normalizedPackage,
809
+ description: optionalString(input.description, 'description'),
810
+ authoring: {
811
+ namespace: nonEmptyString(authoring.namespace, 'authoring.namespace'),
812
+ import: authoringImport,
813
+ symbols: sortedUnique(authoring.symbols || [], 'authoring.symbols')
814
+ },
815
+ ownership: {
816
+ profileFragment: fragmentKey(ownership.profileFragment, 'ownership.profileFragment'),
817
+ helperImports: Object.freeze(helperImports),
818
+ reExportImports: Object.freeze(reExportImports)
819
+ },
820
+ composition: {
821
+ version: PACKAGE_COMPOSITION_VERSION,
822
+ status: compositionStatus,
823
+ helperSymbol,
824
+ profileToken,
825
+ reasonCode: compositionReason
826
+ },
827
+ targets: {
828
+ native: normalizeTarget('native', input.targets && input.targets.native),
829
+ javascript: normalizeTarget('javascript', input.targets && input.targets.javascript)
830
+ },
831
+ lowering: {
832
+ manifest: lowering.manifest == null ? null : packageRelativePath(lowering.manifest, 'lowering.manifest'),
833
+ trust: optionalString(lowering.trust, 'lowering.trust'),
834
+ canonicalOperationVersion: optionalString(lowering.canonicalOperationVersion, 'lowering.canonicalOperationVersion'),
835
+ bundleVersion: optionalString(lowering.bundleVersion, 'lowering.bundleVersion'),
836
+ providerRequirementVersion: optionalString(lowering.providerRequirementVersion, 'lowering.providerRequirementVersion')
837
+ },
838
+ conformance: {
839
+ version: PACKAGE_CONFORMANCE_VERSION,
840
+ status: conformanceStatus,
841
+ fixtureRoots: Object.freeze(fixtureRoots),
842
+ semanticCases
843
+ },
844
+ docs: {
845
+ readme: docs.readme == null ? null : packageRelativePath(docs.readme, 'docs.readme'),
846
+ contract: docs.contract == null ? null : packageRelativePath(docs.contract, 'docs.contract')
847
+ },
848
+ policy: expectedPolicy
849
+ };
850
+
851
+ if (normalized.targets.native.status === 'supported') {
852
+ if (!normalized.targets.native.lowerableSubpath || !normalized.lowering.manifest) throw new TypeError('A supported native package contract requires lowerableSubpath and lowering.manifest.');
853
+ if (normalized.lowering.trust !== 'first-party') throw new TypeError('The current native package-lowering contract requires lowering.trust first-party.');
854
+ if (normalized.lowering.canonicalOperationVersion !== CANONICAL_PACKAGE_OPERATION_VERSION
855
+ || normalized.lowering.bundleVersion !== PACKAGE_LOWERING_BUNDLE_VERSION
856
+ || normalized.lowering.providerRequirementVersion !== PROVIDER_REQUIREMENT_RECORD_VERSION) {
857
+ throw new TypeError('Native package metadata must identify the sealed canonical operation, lowering bundle, and provider-requirement versions.');
858
+ }
859
+ }
860
+ return deepFreeze(normalized);
861
+ }
862
+
863
+ function validatePackageContractCatalog(contracts) {
864
+ const normalized = (contracts || []).map(normalizePackageContract).sort((a, b) => a.contractId.localeCompare(b.contractId));
865
+ const contractIds = new Set();
866
+ const packages = new Set();
867
+ const fragments = new Set();
868
+ const helperImports = new Map();
869
+ for (const contract of normalized) {
870
+ if (contractIds.has(contract.contractId)) throw new TypeError(`Duplicate package contractId ${contract.contractId}.`);
871
+ if (packages.has(contract.npmPackage)) throw new TypeError(`Package ${contract.npmPackage} declares more than one Pulse package contract.`);
872
+ if (fragments.has(contract.ownership.profileFragment)) throw new TypeError(`Profile fragment ${contract.ownership.profileFragment} is owned by more than one package.`);
873
+ contractIds.add(contract.contractId);
874
+ packages.add(contract.npmPackage);
875
+ fragments.add(contract.ownership.profileFragment);
876
+ for (const specifier of [...contract.ownership.helperImports, ...contract.ownership.reExportImports]) {
877
+ const current = helperImports.get(specifier);
878
+ if (current && current !== contract.contractId) throw new TypeError(`Helper import ${specifier} is owned by both ${current} and ${contract.contractId}.`);
879
+ helperImports.set(specifier, contract.contractId);
880
+ }
881
+ }
882
+ return deepFreeze({
883
+ version: PACKAGE_CONTRACT_CATALOG_VERSION,
884
+ contracts: normalized,
885
+ profileFragments: Object.freeze([...fragments].sort()),
886
+ helperImports: Object.freeze([...helperImports.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([specifier, id]) => Object.freeze({ specifier, contractId: id }))),
887
+ policy: Object.freeze({
888
+ graphOwnershipRequired: true,
889
+ profileFragmentsUnique: true,
890
+ helperOwnershipUnique: true,
891
+ externalCompilerPluginApi: false,
892
+ packageContractExecutesCompilerCode: false,
893
+ loweringManifestSeparate: true
894
+ })
895
+ });
896
+ }
897
+
898
+ function defaultPackageContractDefinition() {
899
+ return deepFreeze({
900
+ version: PACKAGE_CONTRACT_VERSION,
901
+ targetSupportVersion: PACKAGE_TARGET_SUPPORT_VERSION,
902
+ compositionVersion: PACKAGE_COMPOSITION_VERSION,
903
+ conformanceVersion: PACKAGE_CONFORMANCE_VERSION,
904
+ catalogVersion: PACKAGE_CONTRACT_CATALOG_VERSION,
905
+ cryptoRequirementVersion: PACKAGE_CRYPTO_REQUIREMENT_VERSION,
906
+ builderInvocationVersion: PACKAGE_BUILDER_INVOCATION_VERSION,
907
+ builderResultVersion: PACKAGE_BUILDER_RESULT_VERSION,
908
+ inspectionArtifactVersion: PACKAGE_INSPECTION_ARTIFACT_VERSION,
909
+ canonicalInspectionVersion: CANONICAL_PACKAGE_INSPECTION_VERSION,
910
+ managedHandlerDescriptorVersion: PACKAGE_MANAGED_HANDLER_DESCRIPTOR_VERSION,
911
+ targetStatuses: TARGET_STATUSES,
912
+ realizationKinds: REALIZATION_KINDS,
913
+ compositionStatuses: COMPOSITION_STATUSES,
914
+ conformanceStatuses: CONFORMANCE_STATUSES,
915
+ policies: {
916
+ productMetadataSeparateFromTrustedLowerer: true,
917
+ staticDataOnly: true,
918
+ profileTokenOpaque: true,
919
+ graphOwnsAttribution: true,
920
+ packageLowererReceivesCanonicalOperationsOnly: true,
921
+ javascriptSupportMustBeExplicit: true,
922
+ unsupportedModesMustBeExplicit: true,
923
+ automaticFallback: false,
924
+ publicCompilerPluginApi: false
925
+ }
926
+ });
927
+ }
928
+
929
+ module.exports = Object.freeze({
930
+ PACKAGE_CONTRACT_VERSION,
931
+ PACKAGE_REALIZATION_ARTIFACT_SET_VERSION,
932
+ PACKAGE_CONTRACT_KIND,
933
+ PACKAGE_TARGET_SUPPORT_VERSION,
934
+ PACKAGE_COMPOSITION_VERSION,
935
+ PACKAGE_CONFORMANCE_VERSION,
936
+ PACKAGE_CONTRACT_CATALOG_VERSION,
937
+ PACKAGE_CONTRACT_DISCOVERY_VERSION,
938
+ PACKAGE_PRODUCT_METADATA_PACKAGE_POLICY,
939
+ PACKAGE_NATIVE_LOWERING_TRUST_POLICY,
940
+ PROFILE_TOKEN_POLICY,
941
+ CANONICAL_PACKAGE_OPERATION_VERSION,
942
+ PACKAGE_LOWERING_BUNDLE_VERSION,
943
+ PACKAGE_INTRINSIC_VERSION,
944
+ PACKAGE_CRYPTO_REQUIREMENT_VERSION,
945
+ PROVIDER_REQUIREMENT_RECORD_VERSION,
946
+ GUEST_UNIT_CONTRIBUTION_VERSION,
947
+ PACKAGE_BUILDER_INVOCATION_VERSION,
948
+ PACKAGE_BUILDER_RESULT_VERSION,
949
+ PACKAGE_INSPECTION_ARTIFACT_VERSION,
950
+ CANONICAL_PACKAGE_INSPECTION_VERSION,
951
+ PACKAGE_MANAGED_HANDLER_DESCRIPTOR_VERSION,
952
+ PACKAGE_BUILDER_INVOCATION_FIELDS,
953
+ PACKAGE_BUILDER_RAW_RESULT_FIELDS,
954
+ CANONICAL_PACKAGE_EFFECT_FIELDS,
955
+ CANONICAL_PACKAGE_OPERATION_FIELDS,
956
+ PROVIDER_REQUIREMENT_RECORD_FIELDS,
957
+ GUEST_UNIT_CONTRIBUTION_FIELDS,
958
+ TARGET_STATUSES,
959
+ REALIZATION_KINDS,
960
+ COMPOSITION_STATUSES,
961
+ CONFORMANCE_STATUSES,
962
+ normalizePackageContract,
963
+ normalizePackageBuilderInvocation,
964
+ normalizePackageBuilderResult,
965
+ normalizeCanonicalPackageEffect,
966
+ createCanonicalPackageOperation,
967
+ normalizeCanonicalPackageOperation,
968
+ normalizePackageLoweringBundle,
969
+ normalizeProviderRequirementRecord,
970
+ normalizeGuestUnitContribution,
971
+ normalizeCanonicalGuestUnitContribution,
972
+ validatePackageContractCatalog,
973
+ defaultPackageContractDefinition,
974
+ clone
975
+ });