@pulse-compute/wasm-contracts 0.0.0 → 1.0.0-beta.1
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.
- package/README.md +34 -2
- package/package.json +123 -6
- package/src/assets/contracts.js +296 -0
- package/src/config/provider-resolution.js +54 -0
- package/src/config/runtime-provider-kv.js +73 -0
- package/src/config/symbolic-refs.js +192 -0
- package/src/crypto/contracts.js +637 -0
- package/src/definitions/config-schema.js +30 -0
- package/src/definitions/handler-roles.js +66 -0
- package/src/definitions/path-grammar.js +11 -0
- package/src/definitions/router-api.js +146 -0
- package/src/diagnostics/codes.js +42 -0
- package/src/diagnostics/reporter.js +20 -0
- package/src/diagnostics.js +139 -0
- package/src/dispatch-table.js +23 -0
- package/src/entities/catalog.d.ts +7 -0
- package/src/entities/catalog.js +87 -0
- package/src/entities/contracts.d.ts +95 -0
- package/src/entities/contracts.js +122 -0
- package/src/entities/json-rpc.d.ts +27 -0
- package/src/entities/json-rpc.js +69 -0
- package/src/entities/runtime.d.ts +67 -0
- package/src/entities/runtime.js +288 -0
- package/src/events/contracts.js +456 -0
- package/src/execution-plan.js +42 -0
- package/src/grip/contracts.js +106 -0
- package/src/handler/backend-json-request-body.js +58 -0
- package/src/handler/beta-lifecycle-golden.js +97 -0
- package/src/handler/canonical-native-plan.js +143 -0
- package/src/handler/canonical-native-runtime.js +168 -0
- package/src/handler/canonical-runtime.js +13 -0
- package/src/handler/context.js +131 -0
- package/src/handler/ctx-contract.js +71 -0
- package/src/handler/doctor-readiness-aggregator.js +67 -0
- package/src/handler/effects.js +446 -0
- package/src/handler/io-lifecycle.js +134 -0
- package/src/handler/lifecycle-authoring-alignment.js +52 -0
- package/src/handler/lifecycle-readiness-aggregate.js +93 -0
- package/src/handler/reference-node-lifecycle-golden.js +73 -0
- package/src/handler/request-json-body.js +147 -0
- package/src/handler/runtime-api.js +471 -0
- package/src/handler/schema-decode-result.js +135 -0
- package/src/handler/schema-response-codec.js +141 -0
- package/src/handler/surface-contract.js +594 -0
- package/src/handler/types-contract.js +51 -0
- package/src/handler-table.js +28 -0
- package/src/host/backend-capabilities.js +24 -0
- package/src/host/capabilities.js +273 -0
- package/src/host/channel-broadcaster.js +60 -0
- package/src/host/json-body.js +80 -0
- package/src/host/request-result-headers.js +38 -0
- package/src/host/streaming-passthrough.js +90 -0
- package/src/host/wasm-host-abi.js +154 -0
- package/src/index.js +75 -0
- package/src/jwt/contracts.js +427 -0
- package/src/library/api-surface.js +99 -0
- package/src/library/contracts.js +273 -0
- package/src/library/manifest.js +317 -0
- package/src/library/second-package-owned-lowering.js +39 -0
- package/src/library/sidecars.js +147 -0
- package/src/logging.js +89 -0
- package/src/package/package-contract.js +975 -0
- package/src/package/package-contract.schema.json +303 -0
- package/src/package/runtime-pulse-live.js +100 -0
- package/src/path-table.js +12 -0
- package/src/path.js +275 -0
- package/src/project/config-factory.js +48 -0
- package/src/project/config-plan.js +409 -0
- package/src/project/config-runtime.js +46 -0
- package/src/project/javascript-application.js +212 -0
- package/src/project/javascript-core-capabilities.js +44 -0
- package/src/project/native-optimization.js +9 -0
- package/src/project/package-ownership.js +242 -0
- package/src/project/package-product-projection.js +171 -0
- package/src/project/reachable-graph-identity.js +219 -0
- package/src/project/reachable-graph-projections.js +279 -0
- package/src/project/reachable-graph-resolver.js +303 -0
- package/src/project/reachable-graph-v2.js +430 -0
- package/src/project/reachable-graph-v2.schema.json +285 -0
- package/src/project/reachable-graph.js +199 -0
- package/src/project/reachable-graph.schema.json +222 -0
- package/src/project/target-support-evidence.js +559 -0
- package/src/provider/canonical-provider.js +235 -0
- package/src/provider/final-wasm-policy.js +87 -0
- package/src/provider/toolchain.js +771 -0
- package/src/route-plan.js +43 -0
- package/src/schema-json/compile.js +63 -0
- package/src/schema-json/contracts.js +10 -0
- package/src/schema-json/generic-parser.js +62 -0
- package/src/schema-json/registry.js +359 -0
- package/src/schema-json/semantic-trace.js +241 -0
- package/src/schema-json/v1.js +65 -0
- package/src/schema-json/v2.js +110 -0
- package/src/sha256.js +104 -0
- package/src/spine.js +381 -0
- package/src/stable-id.js +142 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://pulsecompute.io/contracts/pulse.reachable-graph-manifest.v2.schema.json",
|
|
4
|
+
"title": "Pulse reachable graph manifest v2",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": [
|
|
7
|
+
"version",
|
|
8
|
+
"identityVersion",
|
|
9
|
+
"resolverVersion",
|
|
10
|
+
"handlerReferenceVersion",
|
|
11
|
+
"resolver",
|
|
12
|
+
"entry",
|
|
13
|
+
"modules",
|
|
14
|
+
"edges",
|
|
15
|
+
"handlers",
|
|
16
|
+
"cycles",
|
|
17
|
+
"unsupportedBoundaries",
|
|
18
|
+
"firstUnsupportedBoundary",
|
|
19
|
+
"graphHash"
|
|
20
|
+
],
|
|
21
|
+
"properties": {
|
|
22
|
+
"version": { "const": "pulse.reachable-graph-manifest.v2" },
|
|
23
|
+
"identityVersion": { "const": "pulse.reachable-graph-identity.v1" },
|
|
24
|
+
"resolverVersion": { "const": "pulse.module-resolver.v1" },
|
|
25
|
+
"handlerReferenceVersion": { "const": "pulse.handler-reference.v2" },
|
|
26
|
+
"resolver": { "$ref": "#/$defs/resolver" },
|
|
27
|
+
"entry": { "$ref": "#/$defs/stableId" },
|
|
28
|
+
"modules": {
|
|
29
|
+
"type": "array",
|
|
30
|
+
"items": { "$ref": "#/$defs/module" }
|
|
31
|
+
},
|
|
32
|
+
"edges": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"items": { "$ref": "#/$defs/edge" }
|
|
35
|
+
},
|
|
36
|
+
"handlers": {
|
|
37
|
+
"type": "array",
|
|
38
|
+
"items": { "$ref": "#/$defs/handler" }
|
|
39
|
+
},
|
|
40
|
+
"cycles": {
|
|
41
|
+
"type": "array",
|
|
42
|
+
"items": { "$ref": "#/$defs/cycle" }
|
|
43
|
+
},
|
|
44
|
+
"unsupportedBoundaries": {
|
|
45
|
+
"type": "array",
|
|
46
|
+
"items": { "$ref": "#/$defs/unsupportedBoundary" }
|
|
47
|
+
},
|
|
48
|
+
"firstUnsupportedBoundary": {
|
|
49
|
+
"oneOf": [
|
|
50
|
+
{ "type": "null" },
|
|
51
|
+
{ "$ref": "#/$defs/unsupportedBoundary" }
|
|
52
|
+
]
|
|
53
|
+
},
|
|
54
|
+
"graphHash": { "$ref": "#/$defs/sha256" }
|
|
55
|
+
},
|
|
56
|
+
"$defs": {
|
|
57
|
+
"sha256": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"pattern": "^[0-9a-f]{64}$"
|
|
60
|
+
},
|
|
61
|
+
"stableId": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"pattern": "^[a-z][a-z0-9_]*_[0-9a-f]{32}$"
|
|
64
|
+
},
|
|
65
|
+
"source": {
|
|
66
|
+
"type": "object",
|
|
67
|
+
"required": ["file", "line", "column"],
|
|
68
|
+
"properties": {
|
|
69
|
+
"file": {
|
|
70
|
+
"type": "string",
|
|
71
|
+
"minLength": 1,
|
|
72
|
+
"pattern": "^(?!/)(?![A-Za-z]:/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
|
|
73
|
+
},
|
|
74
|
+
"line": { "type": "integer", "minimum": 1 },
|
|
75
|
+
"column": { "type": "integer", "minimum": 1 }
|
|
76
|
+
},
|
|
77
|
+
"additionalProperties": false
|
|
78
|
+
},
|
|
79
|
+
"alias": {
|
|
80
|
+
"type": "object",
|
|
81
|
+
"required": ["pattern", "wildcard", "prefix", "suffix", "targets"],
|
|
82
|
+
"properties": {
|
|
83
|
+
"pattern": { "type": "string", "minLength": 1 },
|
|
84
|
+
"wildcard": { "type": "boolean" },
|
|
85
|
+
"prefix": { "type": "string" },
|
|
86
|
+
"suffix": { "type": "string" },
|
|
87
|
+
"targets": {
|
|
88
|
+
"type": "array",
|
|
89
|
+
"minItems": 1,
|
|
90
|
+
"items": { "type": "string", "minLength": 1 },
|
|
91
|
+
"uniqueItems": true
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"additionalProperties": false
|
|
95
|
+
},
|
|
96
|
+
"resolver": {
|
|
97
|
+
"type": "object",
|
|
98
|
+
"required": [
|
|
99
|
+
"version",
|
|
100
|
+
"resolverVersion",
|
|
101
|
+
"baseUrl",
|
|
102
|
+
"pathAliases",
|
|
103
|
+
"configFile",
|
|
104
|
+
"configContentHash",
|
|
105
|
+
"resolverHash"
|
|
106
|
+
],
|
|
107
|
+
"properties": {
|
|
108
|
+
"version": { "const": "pulse.module-resolver-input.v1" },
|
|
109
|
+
"resolverVersion": { "const": "pulse.module-resolver.v1" },
|
|
110
|
+
"baseUrl": { "type": "string", "minLength": 1 },
|
|
111
|
+
"pathAliases": {
|
|
112
|
+
"type": "array",
|
|
113
|
+
"items": { "$ref": "#/$defs/alias" }
|
|
114
|
+
},
|
|
115
|
+
"configFile": { "type": ["string", "null"] },
|
|
116
|
+
"configContentHash": {
|
|
117
|
+
"oneOf": [
|
|
118
|
+
{ "type": "null" },
|
|
119
|
+
{ "$ref": "#/$defs/sha256" }
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
"resolverHash": { "$ref": "#/$defs/sha256" }
|
|
123
|
+
},
|
|
124
|
+
"additionalProperties": false
|
|
125
|
+
},
|
|
126
|
+
"module": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"required": [
|
|
129
|
+
"id",
|
|
130
|
+
"kind",
|
|
131
|
+
"owner",
|
|
132
|
+
"canonical",
|
|
133
|
+
"format",
|
|
134
|
+
"runtime",
|
|
135
|
+
"path",
|
|
136
|
+
"packageName",
|
|
137
|
+
"packageVersion",
|
|
138
|
+
"packageSubpath",
|
|
139
|
+
"packageManifestHash",
|
|
140
|
+
"generator",
|
|
141
|
+
"logicalName",
|
|
142
|
+
"externalSpecifier",
|
|
143
|
+
"packageContract",
|
|
144
|
+
"contentHash",
|
|
145
|
+
"exports",
|
|
146
|
+
"reExports",
|
|
147
|
+
"source"
|
|
148
|
+
],
|
|
149
|
+
"properties": {
|
|
150
|
+
"id": { "$ref": "#/$defs/stableId" },
|
|
151
|
+
"kind": { "enum": ["project", "package", "generated", "external"] },
|
|
152
|
+
"owner": { "enum": ["application", "pulse-runtime", "pulse-package", "third-party", "generated", "external"] },
|
|
153
|
+
"canonical": { "type": "string", "minLength": 1 },
|
|
154
|
+
"format": { "enum": ["typescript", "javascript", "json", "declaration", "generated", "external"] },
|
|
155
|
+
"runtime": { "type": "boolean" },
|
|
156
|
+
"path": { "type": ["string", "null"] },
|
|
157
|
+
"packageName": { "type": ["string", "null"] },
|
|
158
|
+
"packageVersion": { "type": ["string", "null"] },
|
|
159
|
+
"packageSubpath": { "type": ["string", "null"] },
|
|
160
|
+
"packageManifestHash": {
|
|
161
|
+
"oneOf": [
|
|
162
|
+
{ "type": "null" },
|
|
163
|
+
{ "$ref": "#/$defs/sha256" }
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
"generator": { "type": ["string", "null"] },
|
|
167
|
+
"logicalName": { "type": ["string", "null"] },
|
|
168
|
+
"externalSpecifier": { "type": ["string", "null"] },
|
|
169
|
+
"packageContract": { "type": ["string", "null"] },
|
|
170
|
+
"contentHash": {
|
|
171
|
+
"oneOf": [
|
|
172
|
+
{ "type": "null" },
|
|
173
|
+
{ "$ref": "#/$defs/sha256" }
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"exports": {
|
|
177
|
+
"type": "array",
|
|
178
|
+
"items": { "type": "string", "minLength": 1 },
|
|
179
|
+
"uniqueItems": true
|
|
180
|
+
},
|
|
181
|
+
"reExports": {
|
|
182
|
+
"type": "array",
|
|
183
|
+
"items": { "type": "string", "minLength": 1 },
|
|
184
|
+
"uniqueItems": true
|
|
185
|
+
},
|
|
186
|
+
"source": {
|
|
187
|
+
"oneOf": [
|
|
188
|
+
{ "type": "null" },
|
|
189
|
+
{ "$ref": "#/$defs/source" }
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"additionalProperties": false
|
|
194
|
+
},
|
|
195
|
+
"edge": {
|
|
196
|
+
"type": "object",
|
|
197
|
+
"required": [
|
|
198
|
+
"id",
|
|
199
|
+
"kind",
|
|
200
|
+
"from",
|
|
201
|
+
"to",
|
|
202
|
+
"specifier",
|
|
203
|
+
"resolutionKind",
|
|
204
|
+
"runtime",
|
|
205
|
+
"importedNames",
|
|
206
|
+
"exportedNames",
|
|
207
|
+
"packageContract",
|
|
208
|
+
"source"
|
|
209
|
+
],
|
|
210
|
+
"properties": {
|
|
211
|
+
"id": { "$ref": "#/$defs/stableId" },
|
|
212
|
+
"kind": { "enum": ["runtime-import", "type-import", "re-export", "package-contract", "lifecycle"] },
|
|
213
|
+
"from": { "$ref": "#/$defs/stableId" },
|
|
214
|
+
"to": { "$ref": "#/$defs/stableId" },
|
|
215
|
+
"specifier": { "type": "string", "minLength": 1 },
|
|
216
|
+
"resolutionKind": { "enum": ["project-relative", "tsconfig-path", "package-root", "package-subpath", "generated", "external"] },
|
|
217
|
+
"runtime": { "type": "boolean" },
|
|
218
|
+
"importedNames": {
|
|
219
|
+
"type": "array",
|
|
220
|
+
"items": { "type": "string", "minLength": 1 },
|
|
221
|
+
"uniqueItems": true
|
|
222
|
+
},
|
|
223
|
+
"exportedNames": {
|
|
224
|
+
"type": "array",
|
|
225
|
+
"items": { "type": "string", "minLength": 1 },
|
|
226
|
+
"uniqueItems": true
|
|
227
|
+
},
|
|
228
|
+
"packageContract": { "type": ["string", "null"] },
|
|
229
|
+
"source": { "$ref": "#/$defs/source" }
|
|
230
|
+
},
|
|
231
|
+
"additionalProperties": false
|
|
232
|
+
},
|
|
233
|
+
"handler": {
|
|
234
|
+
"type": "object",
|
|
235
|
+
"required": ["version", "id", "moduleId", "exportName", "localName", "role", "wrappers", "source"],
|
|
236
|
+
"properties": {
|
|
237
|
+
"version": { "const": "pulse.handler-reference.v2" },
|
|
238
|
+
"id": { "$ref": "#/$defs/stableId" },
|
|
239
|
+
"moduleId": { "$ref": "#/$defs/stableId" },
|
|
240
|
+
"exportName": { "type": ["string", "null"] },
|
|
241
|
+
"localName": { "type": ["string", "null"] },
|
|
242
|
+
"role": { "enum": ["handler", "route", "middleware", "event", "error-middleware", "router"] },
|
|
243
|
+
"wrappers": {
|
|
244
|
+
"type": "array",
|
|
245
|
+
"items": { "enum": ["parentheses", "as-cast", "type-assertion", "satisfies", "non-null"] },
|
|
246
|
+
"uniqueItems": true
|
|
247
|
+
},
|
|
248
|
+
"source": { "$ref": "#/$defs/source" }
|
|
249
|
+
},
|
|
250
|
+
"additionalProperties": false
|
|
251
|
+
},
|
|
252
|
+
"cycle": {
|
|
253
|
+
"type": "object",
|
|
254
|
+
"required": ["id", "modules"],
|
|
255
|
+
"properties": {
|
|
256
|
+
"id": { "$ref": "#/$defs/stableId" },
|
|
257
|
+
"modules": {
|
|
258
|
+
"type": "array",
|
|
259
|
+
"minItems": 1,
|
|
260
|
+
"items": { "$ref": "#/$defs/stableId" },
|
|
261
|
+
"uniqueItems": true
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
"additionalProperties": false
|
|
265
|
+
},
|
|
266
|
+
"unsupportedBoundary": {
|
|
267
|
+
"type": "object",
|
|
268
|
+
"required": ["id", "kind", "from", "specifier", "source"],
|
|
269
|
+
"properties": {
|
|
270
|
+
"id": { "$ref": "#/$defs/stableId" },
|
|
271
|
+
"kind": { "enum": ["dynamic-import", "commonjs-require", "computed-specifier", "loader-hook", "unknown-runtime-side-effect"] },
|
|
272
|
+
"from": {
|
|
273
|
+
"oneOf": [
|
|
274
|
+
{ "type": "null" },
|
|
275
|
+
{ "$ref": "#/$defs/stableId" }
|
|
276
|
+
]
|
|
277
|
+
},
|
|
278
|
+
"specifier": { "type": "string", "minLength": 1 },
|
|
279
|
+
"source": { "$ref": "#/$defs/source" }
|
|
280
|
+
},
|
|
281
|
+
"additionalProperties": false
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
"additionalProperties": false
|
|
285
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { stableStringify, sha256Hex } = require('../stable-id.js');
|
|
4
|
+
const reachableGraphResolver = require('./reachable-graph-resolver.js');
|
|
5
|
+
const reachableGraphIdentity = require('./reachable-graph-identity.js');
|
|
6
|
+
const reachableGraphV2 = require('./reachable-graph-v2.js');
|
|
7
|
+
const reachableGraphProjections = require('./reachable-graph-projections.js');
|
|
8
|
+
function deepFreeze(value) {
|
|
9
|
+
if (!value || typeof value !== 'object' || Object.isFrozen(value)) return value;
|
|
10
|
+
for (const child of Object.values(value)) deepFreeze(child);
|
|
11
|
+
return Object.freeze(value);
|
|
12
|
+
}
|
|
13
|
+
const REACHABLE_GRAPH_MANIFEST_V2_SCHEMA = deepFreeze(require('./reachable-graph-v2.schema.json'));
|
|
14
|
+
|
|
15
|
+
const REACHABLE_GRAPH_CONTRACT_VERSION = 'pulse.reachable-graph-contract.v1';
|
|
16
|
+
const REACHABLE_GRAPH_MANIFEST_VERSION = 'pulse.reachable-graph-manifest.v1';
|
|
17
|
+
const HANDLER_REFERENCE_VERSION = 'pulse.handler-reference.v1';
|
|
18
|
+
const MODULE_KINDS = Object.freeze(['project', 'package', 'generated', 'external']);
|
|
19
|
+
const EDGE_KINDS = Object.freeze(['runtime-import', 'type-import', 're-export', 'package-contract', 'lifecycle']);
|
|
20
|
+
const OWNERSHIP_KINDS = Object.freeze(['application', 'pulse-runtime', 'pulse-package', 'third-party', 'generated', 'external']);
|
|
21
|
+
const HANDLER_ROLES = Object.freeze(['handler', 'route', 'middleware', 'event', 'error-middleware', 'router']);
|
|
22
|
+
const HANDLER_WRAPPERS = Object.freeze(['parentheses', 'as-cast', 'type-assertion', 'satisfies', 'non-null']);
|
|
23
|
+
const UNSUPPORTED_EDGE_KINDS = Object.freeze(['dynamic-import', 'commonjs-require', 'computed-specifier', 'loader-hook', 'unknown-runtime-side-effect']);
|
|
24
|
+
|
|
25
|
+
function isPlainObject(value) {
|
|
26
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
27
|
+
const proto = Object.getPrototypeOf(value);
|
|
28
|
+
return proto === Object.prototype || proto === null;
|
|
29
|
+
}
|
|
30
|
+
function assertString(value, field) {
|
|
31
|
+
if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${field} must be a non-empty string.`);
|
|
32
|
+
return value.trim();
|
|
33
|
+
}
|
|
34
|
+
function assertPositiveInteger(value, field) {
|
|
35
|
+
const number = Number(value);
|
|
36
|
+
if (!Number.isSafeInteger(number) || number < 1) throw new TypeError(`${field} must be a positive safe integer.`);
|
|
37
|
+
return number;
|
|
38
|
+
}
|
|
39
|
+
function strings(input, field) {
|
|
40
|
+
if (input == null) return Object.freeze([]);
|
|
41
|
+
if (!Array.isArray(input)) throw new TypeError(`${field} must be an array.`);
|
|
42
|
+
return Object.freeze(Array.from(new Set(input.map((value, index) => assertString(value, `${field}[${index}]`)))).sort());
|
|
43
|
+
}
|
|
44
|
+
function normalizeSource(input, field) {
|
|
45
|
+
if (!isPlainObject(input)) throw new TypeError(`${field} must be an object.`);
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
file: assertString(input.file, `${field}.file`),
|
|
48
|
+
line: assertPositiveInteger(input.line, `${field}.line`),
|
|
49
|
+
column: assertPositiveInteger(input.column, `${field}.column`)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function normalizeModule(input, index) {
|
|
53
|
+
if (!isPlainObject(input)) throw new TypeError(`modules[${index}] must be an object.`);
|
|
54
|
+
const kind = assertString(input.kind, `modules[${index}].kind`);
|
|
55
|
+
const owner = assertString(input.owner, `modules[${index}].owner`);
|
|
56
|
+
if (!MODULE_KINDS.includes(kind)) throw new TypeError(`Unsupported module kind ${kind}.`);
|
|
57
|
+
if (!OWNERSHIP_KINDS.includes(owner)) throw new TypeError(`Unsupported module owner ${owner}.`);
|
|
58
|
+
return Object.freeze({
|
|
59
|
+
id: assertString(input.id, `modules[${index}].id`),
|
|
60
|
+
kind,
|
|
61
|
+
owner,
|
|
62
|
+
resolved: assertString(input.resolved, `modules[${index}].resolved`),
|
|
63
|
+
packageName: input.packageName == null ? null : assertString(input.packageName, `modules[${index}].packageName`),
|
|
64
|
+
packageContract: input.packageContract == null ? null : assertString(input.packageContract, `modules[${index}].packageContract`),
|
|
65
|
+
contentHash: input.contentHash == null ? null : assertString(input.contentHash, `modules[${index}].contentHash`),
|
|
66
|
+
exports: strings(input.exports, `modules[${index}].exports`),
|
|
67
|
+
reExports: strings(input.reExports, `modules[${index}].reExports`),
|
|
68
|
+
source: input.source == null ? null : normalizeSource(input.source, `modules[${index}].source`)
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function normalizeEdge(input, index, moduleIds) {
|
|
72
|
+
if (!isPlainObject(input)) throw new TypeError(`edges[${index}] must be an object.`);
|
|
73
|
+
const kind = assertString(input.kind, `edges[${index}].kind`);
|
|
74
|
+
if (!EDGE_KINDS.includes(kind)) throw new TypeError(`Unsupported graph edge kind ${kind}.`);
|
|
75
|
+
const from = assertString(input.from, `edges[${index}].from`);
|
|
76
|
+
const to = assertString(input.to, `edges[${index}].to`);
|
|
77
|
+
if (!moduleIds.has(from) || !moduleIds.has(to)) throw new TypeError(`edges[${index}] must reference declared modules.`);
|
|
78
|
+
return Object.freeze({
|
|
79
|
+
id: assertString(input.id, `edges[${index}].id`),
|
|
80
|
+
kind,
|
|
81
|
+
from,
|
|
82
|
+
to,
|
|
83
|
+
specifier: assertString(input.specifier, `edges[${index}].specifier`),
|
|
84
|
+
importedNames: strings(input.importedNames, `edges[${index}].importedNames`),
|
|
85
|
+
exportedNames: strings(input.exportedNames, `edges[${index}].exportedNames`),
|
|
86
|
+
packageContract: input.packageContract == null ? null : assertString(input.packageContract, `edges[${index}].packageContract`),
|
|
87
|
+
source: normalizeSource(input.source, `edges[${index}].source`)
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function normalizeHandlerReference(input, index, moduleIds) {
|
|
91
|
+
if (!isPlainObject(input)) throw new TypeError(`handlers[${index}] must be an object.`);
|
|
92
|
+
const moduleId = assertString(input.moduleId, `handlers[${index}].moduleId`);
|
|
93
|
+
if (!moduleIds.has(moduleId)) throw new TypeError(`handlers[${index}] references unknown module ${moduleId}.`);
|
|
94
|
+
const role = assertString(input.role, `handlers[${index}].role`);
|
|
95
|
+
if (!HANDLER_ROLES.includes(role)) throw new TypeError(`Unsupported handler role ${role}.`);
|
|
96
|
+
const wrappers = strings(input.wrappers, `handlers[${index}].wrappers`);
|
|
97
|
+
for (const wrapper of wrappers) if (!HANDLER_WRAPPERS.includes(wrapper)) throw new TypeError(`Unsupported handler wrapper ${wrapper}.`);
|
|
98
|
+
return Object.freeze({
|
|
99
|
+
version: HANDLER_REFERENCE_VERSION,
|
|
100
|
+
id: assertString(input.id, `handlers[${index}].id`),
|
|
101
|
+
moduleId,
|
|
102
|
+
exportName: input.exportName == null ? null : assertString(input.exportName, `handlers[${index}].exportName`),
|
|
103
|
+
localName: input.localName == null ? null : assertString(input.localName, `handlers[${index}].localName`),
|
|
104
|
+
role,
|
|
105
|
+
wrappers,
|
|
106
|
+
source: normalizeSource(input.source, `handlers[${index}].source`)
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function normalizeCycle(input, index, moduleIds) {
|
|
110
|
+
if (!Array.isArray(input) || input.length === 0) throw new TypeError(`cycles[${index}] must be a non-empty module-ID array.`);
|
|
111
|
+
const ids = Array.from(new Set(input.map((value, moduleIndex) => assertString(value, `cycles[${index}][${moduleIndex}]`)))).sort();
|
|
112
|
+
for (const id of ids) if (!moduleIds.has(id)) throw new TypeError(`cycles[${index}] references unknown module ${id}.`);
|
|
113
|
+
return Object.freeze(ids);
|
|
114
|
+
}
|
|
115
|
+
function normalizeUnsupportedBoundary(input, moduleIds) {
|
|
116
|
+
if (input == null) return null;
|
|
117
|
+
if (!isPlainObject(input)) throw new TypeError('firstUnsupportedBoundary must be null or an object.');
|
|
118
|
+
const kind = assertString(input.kind, 'firstUnsupportedBoundary.kind');
|
|
119
|
+
if (!UNSUPPORTED_EDGE_KINDS.includes(kind)) throw new TypeError(`Unsupported boundary kind ${kind}.`);
|
|
120
|
+
const from = input.from == null ? null : assertString(input.from, 'firstUnsupportedBoundary.from');
|
|
121
|
+
if (from !== null && !moduleIds.has(from)) throw new TypeError(`firstUnsupportedBoundary.from references unknown module ${from}.`);
|
|
122
|
+
return Object.freeze({
|
|
123
|
+
kind,
|
|
124
|
+
specifier: assertString(input.specifier, 'firstUnsupportedBoundary.specifier'),
|
|
125
|
+
from,
|
|
126
|
+
source: normalizeSource(input.source, 'firstUnsupportedBoundary.source')
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function normalizeReachableGraphManifest(input) {
|
|
130
|
+
if (!isPlainObject(input)) throw new TypeError('Reachable graph manifest must be an object.');
|
|
131
|
+
const modules = Object.freeze([...(input.modules || [])].map(normalizeModule).sort((a, b) => a.id.localeCompare(b.id)));
|
|
132
|
+
const moduleIds = new Set(modules.map((entry) => entry.id));
|
|
133
|
+
if (moduleIds.size !== modules.length) throw new TypeError('Reachable graph module IDs must be unique.');
|
|
134
|
+
const entry = assertString(input.entry, 'entry');
|
|
135
|
+
if (!moduleIds.has(entry)) throw new TypeError(`Reachable graph entry references unknown module ${entry}.`);
|
|
136
|
+
const edges = Object.freeze([...(input.edges || [])].map((edge, index) => normalizeEdge(edge, index, moduleIds)).sort((a, b) => a.id.localeCompare(b.id)));
|
|
137
|
+
if (new Set(edges.map((edge) => edge.id)).size !== edges.length) throw new TypeError('Reachable graph edge IDs must be unique.');
|
|
138
|
+
const handlers = Object.freeze([...(input.handlers || [])].map((handler, index) => normalizeHandlerReference(handler, index, moduleIds)).sort((a, b) => a.id.localeCompare(b.id)));
|
|
139
|
+
if (new Set(handlers.map((handler) => handler.id)).size !== handlers.length) throw new TypeError('Reachable graph handler IDs must be unique.');
|
|
140
|
+
const semantic = {
|
|
141
|
+
version: REACHABLE_GRAPH_MANIFEST_VERSION,
|
|
142
|
+
handlerReferenceVersion: HANDLER_REFERENCE_VERSION,
|
|
143
|
+
entry,
|
|
144
|
+
modules,
|
|
145
|
+
edges,
|
|
146
|
+
handlers,
|
|
147
|
+
cycles: Object.freeze([...(input.cycles || [])].map((cycle, index) => normalizeCycle(cycle, index, moduleIds)).sort((a, b) => a.join('\0').localeCompare(b.join('\0')))),
|
|
148
|
+
firstUnsupportedBoundary: normalizeUnsupportedBoundary(input.firstUnsupportedBoundary, moduleIds)
|
|
149
|
+
};
|
|
150
|
+
return Object.freeze({ ...semantic, graphHash: sha256Hex(stableStringify(semantic)) });
|
|
151
|
+
}
|
|
152
|
+
function defaultReachableGraphContract() {
|
|
153
|
+
return Object.freeze({
|
|
154
|
+
version: REACHABLE_GRAPH_CONTRACT_VERSION,
|
|
155
|
+
manifestVersion: REACHABLE_GRAPH_MANIFEST_VERSION,
|
|
156
|
+
handlerReferenceVersion: HANDLER_REFERENCE_VERSION,
|
|
157
|
+
moduleKinds: MODULE_KINDS,
|
|
158
|
+
edgeKinds: EDGE_KINDS,
|
|
159
|
+
ownershipKinds: OWNERSHIP_KINDS,
|
|
160
|
+
handlerRoles: HANDLER_ROLES,
|
|
161
|
+
handlerWrappers: HANDLER_WRAPPERS,
|
|
162
|
+
unsupportedEdgeKinds: UNSUPPORTED_EDGE_KINDS,
|
|
163
|
+
policies: Object.freeze({
|
|
164
|
+
oneAuthoritativeGraph: true,
|
|
165
|
+
staticEsmOnly: true,
|
|
166
|
+
typeOnlyEdgesDoNotCreateRuntimeReachability: true,
|
|
167
|
+
packageUseFromResolvedReachabilityOnly: true,
|
|
168
|
+
packageSubstringDetectionAllowed: false,
|
|
169
|
+
reExportsPreserveOwningPackage: true,
|
|
170
|
+
cyclesReportedAsStronglyConnectedComponents: true,
|
|
171
|
+
sourceLocationsRequired: true,
|
|
172
|
+
lifecycleSideEffectsAreReachabilityFindings: true,
|
|
173
|
+
graphHashRequiredBeforeCache: true,
|
|
174
|
+
dynamicImportImplemented: false,
|
|
175
|
+
arbitraryRequireImplemented: false,
|
|
176
|
+
bundlingImplemented: false,
|
|
177
|
+
cacheImplemented: false
|
|
178
|
+
}),
|
|
179
|
+
consumers: Object.freeze(['native-compiler', 'javascript-build-planner', 'native-eligibility', 'watch-inputs', 'package-contract-selection', 'application-entry-safety'])
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
module.exports = Object.freeze({
|
|
183
|
+
REACHABLE_GRAPH_CONTRACT_VERSION,
|
|
184
|
+
REACHABLE_GRAPH_MANIFEST_VERSION,
|
|
185
|
+
HANDLER_REFERENCE_VERSION,
|
|
186
|
+
MODULE_KINDS,
|
|
187
|
+
EDGE_KINDS,
|
|
188
|
+
OWNERSHIP_KINDS,
|
|
189
|
+
HANDLER_ROLES,
|
|
190
|
+
HANDLER_WRAPPERS,
|
|
191
|
+
UNSUPPORTED_EDGE_KINDS,
|
|
192
|
+
normalizeReachableGraphManifest,
|
|
193
|
+
defaultReachableGraphContract,
|
|
194
|
+
REACHABLE_GRAPH_MANIFEST_V2_SCHEMA,
|
|
195
|
+
...reachableGraphResolver,
|
|
196
|
+
...reachableGraphIdentity,
|
|
197
|
+
...reachableGraphV2,
|
|
198
|
+
...reachableGraphProjections
|
|
199
|
+
});
|