@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,212 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { sha256Hex, stableStringify } = require('../stable-id.js');
|
|
4
|
+
|
|
5
|
+
const JAVASCRIPT_APPLICATION_PLAN_VERSION = 'pulse.javascript-application-plan.v1';
|
|
6
|
+
const JAVASCRIPT_APPLICATION_LOADER_VERSION = 'pulse.javascript-application-loader.v1';
|
|
7
|
+
const JAVASCRIPT_TARGET_DESCRIPTOR_VERSION = 'pulse.javascript-target-descriptor.v2';
|
|
8
|
+
const JAVASCRIPT_RUNTIME_CLASS = 'javascript';
|
|
9
|
+
|
|
10
|
+
function deepFreeze(value) {
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
for (const entry of value) deepFreeze(entry);
|
|
13
|
+
return Object.freeze(value);
|
|
14
|
+
}
|
|
15
|
+
if (value && typeof value === 'object') {
|
|
16
|
+
for (const entry of Object.values(value)) deepFreeze(entry);
|
|
17
|
+
return Object.freeze(value);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function requireString(label, value) {
|
|
23
|
+
if (typeof value !== 'string' || value.length === 0) throw new TypeError(`${label} must be a non-empty string.`);
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function normalizeSource(source) {
|
|
28
|
+
if (!source) return null;
|
|
29
|
+
return Object.freeze({
|
|
30
|
+
file: requireString('JavaScript application source file', source.file),
|
|
31
|
+
line: Number.isInteger(source.line) && source.line > 0 ? source.line : 1,
|
|
32
|
+
column: Number.isInteger(source.column) && source.column > 0 ? source.column : 1
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizeModule(module, index) {
|
|
37
|
+
if (!module || typeof module !== 'object') throw new TypeError(`JavaScript application module ${index} must be an object.`);
|
|
38
|
+
return Object.freeze({
|
|
39
|
+
id: requireString(`JavaScript application module ${index} id`, module.id),
|
|
40
|
+
kind: requireString(`JavaScript application module ${index} kind`, module.kind),
|
|
41
|
+
format: requireString(`JavaScript application module ${index} format`, module.format),
|
|
42
|
+
runtime: module.runtime === true,
|
|
43
|
+
path: module.path == null ? null : requireString(`JavaScript application module ${index} path`, module.path),
|
|
44
|
+
packageName: module.packageName == null ? null : requireString(`JavaScript application module ${index} packageName`, module.packageName),
|
|
45
|
+
packageSubpath: module.packageSubpath == null ? null : String(module.packageSubpath),
|
|
46
|
+
packageContract: module.packageContract == null ? null : String(module.packageContract),
|
|
47
|
+
externalSpecifier: module.externalSpecifier == null ? null : String(module.externalSpecifier),
|
|
48
|
+
contentHash: requireString(`JavaScript application module ${index} contentHash`, module.contentHash)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function normalizeEdge(edge, index) {
|
|
53
|
+
if (!edge || typeof edge !== 'object') throw new TypeError(`JavaScript application edge ${index} must be an object.`);
|
|
54
|
+
return Object.freeze({
|
|
55
|
+
id: requireString(`JavaScript application edge ${index} id`, edge.id),
|
|
56
|
+
kind: requireString(`JavaScript application edge ${index} kind`, edge.kind),
|
|
57
|
+
from: requireString(`JavaScript application edge ${index} from`, edge.from),
|
|
58
|
+
to: requireString(`JavaScript application edge ${index} to`, edge.to),
|
|
59
|
+
specifier: requireString(`JavaScript application edge ${index} specifier`, edge.specifier),
|
|
60
|
+
resolutionKind: requireString(`JavaScript application edge ${index} resolutionKind`, edge.resolutionKind),
|
|
61
|
+
runtime: edge.runtime === true,
|
|
62
|
+
packageContract: edge.packageContract == null ? null : String(edge.packageContract),
|
|
63
|
+
source: normalizeSource(edge.source)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
function normalizeBlocker(blocker, index) {
|
|
69
|
+
if (!blocker || typeof blocker !== 'object') throw new TypeError(`JavaScript application blocker ${index} must be an object.`);
|
|
70
|
+
return Object.freeze({
|
|
71
|
+
code: requireString(`JavaScript application blocker ${index} code`, blocker.code),
|
|
72
|
+
kind: requireString(`JavaScript application blocker ${index} kind`, blocker.kind),
|
|
73
|
+
message: requireString(`JavaScript application blocker ${index} message`, blocker.message),
|
|
74
|
+
moduleId: blocker.moduleId == null ? null : String(blocker.moduleId),
|
|
75
|
+
packageName: blocker.packageName == null ? null : String(blocker.packageName),
|
|
76
|
+
packageSubpath: blocker.packageSubpath == null ? null : String(blocker.packageSubpath),
|
|
77
|
+
contractId: blocker.contractId == null ? null : String(blocker.contractId),
|
|
78
|
+
source: normalizeSource(blocker.source)
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalizePackage(entry, index) {
|
|
83
|
+
if (!entry || typeof entry !== 'object') throw new TypeError(`JavaScript application package ${index} must be an object.`);
|
|
84
|
+
const status = requireString(`JavaScript application package ${index} status`, entry.status);
|
|
85
|
+
if (!['supplied-core', 'node-require', 'package-runtime', 'unavailable'].includes(status)) {
|
|
86
|
+
throw new TypeError(`Unsupported JavaScript application package status ${status}.`);
|
|
87
|
+
}
|
|
88
|
+
return Object.freeze({
|
|
89
|
+
moduleId: requireString(`JavaScript application package ${index} moduleId`, entry.moduleId),
|
|
90
|
+
packageName: requireString(`JavaScript application package ${index} packageName`, entry.packageName),
|
|
91
|
+
packageSubpath: entry.packageSubpath == null ? '.' : String(entry.packageSubpath),
|
|
92
|
+
contractId: entry.contractId == null ? null : String(entry.contractId),
|
|
93
|
+
status,
|
|
94
|
+
runtimeEntry: entry.runtimeEntry == null ? null : String(entry.runtimeEntry),
|
|
95
|
+
reasonCode: entry.reasonCode == null ? null : String(entry.reasonCode),
|
|
96
|
+
sources: Object.freeze((entry.sources || []).map(normalizeSource).filter(Boolean))
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function normalizeJavascriptApplicationPlan(input) {
|
|
101
|
+
if (!input || typeof input !== 'object') throw new TypeError('JavaScript application plan input must be an object.');
|
|
102
|
+
const modules = Object.freeze((input.modules || []).map(normalizeModule).sort((a, b) => a.id.localeCompare(b.id)));
|
|
103
|
+
const edges = Object.freeze((input.edges || []).map(normalizeEdge).sort((a, b) => a.id.localeCompare(b.id)));
|
|
104
|
+
const packages = Object.freeze((input.packages || []).map(normalizePackage).sort((a, b) => a.moduleId.localeCompare(b.moduleId)));
|
|
105
|
+
const blockers = Object.freeze((input.blockers || []).map(normalizeBlocker).sort((a, b) => (a.source?.file || '').localeCompare(b.source?.file || '') || (a.source?.line || 0) - (b.source?.line || 0) || a.code.localeCompare(b.code)));
|
|
106
|
+
const moduleIds = new Set(modules.map((entry) => entry.id));
|
|
107
|
+
if (moduleIds.size !== modules.length) throw new TypeError('JavaScript application plan module IDs must be unique.');
|
|
108
|
+
for (const edge of edges) {
|
|
109
|
+
if (!moduleIds.has(edge.from) || !moduleIds.has(edge.to)) throw new TypeError(`JavaScript application edge ${edge.id} references an unknown module.`);
|
|
110
|
+
}
|
|
111
|
+
const entryModuleId = requireString('JavaScript application entry module id', input.entryModuleId);
|
|
112
|
+
if (!moduleIds.has(entryModuleId)) throw new TypeError('JavaScript application entry module must be present in modules.');
|
|
113
|
+
const document = {
|
|
114
|
+
version: JAVASCRIPT_APPLICATION_PLAN_VERSION,
|
|
115
|
+
kind: 'pulse.javascript-application-plan',
|
|
116
|
+
provider: requireString('JavaScript application provider', input.provider),
|
|
117
|
+
target: 'javascript',
|
|
118
|
+
targetId: requireString('JavaScript application target id', input.targetId),
|
|
119
|
+
runtimeClass: JAVASCRIPT_RUNTIME_CLASS,
|
|
120
|
+
sourceApplication: true,
|
|
121
|
+
automaticFallback: false,
|
|
122
|
+
workspace: Object.freeze({
|
|
123
|
+
root: '.',
|
|
124
|
+
entry: requireString('JavaScript application entry path', input.entryPath)
|
|
125
|
+
}),
|
|
126
|
+
graph: Object.freeze({
|
|
127
|
+
version: requireString('JavaScript application graph version', input.graphVersion),
|
|
128
|
+
graphHash: requireString('JavaScript application graph hash', input.graphHash),
|
|
129
|
+
resolverHash: requireString('JavaScript application resolver hash', input.resolverHash),
|
|
130
|
+
entryModuleId,
|
|
131
|
+
modules,
|
|
132
|
+
edges
|
|
133
|
+
}),
|
|
134
|
+
packages,
|
|
135
|
+
loadable: blockers.length === 0,
|
|
136
|
+
blockers,
|
|
137
|
+
packageProduct: input.packageProduct || null,
|
|
138
|
+
nativeEligibility: input.nativeEligibility || null,
|
|
139
|
+
entrySafety: input.entrySafety || null,
|
|
140
|
+
capabilityEnvelope: input.capabilityEnvelope || null,
|
|
141
|
+
policy: Object.freeze({
|
|
142
|
+
graphBackedResolution: true,
|
|
143
|
+
oneModuleCache: true,
|
|
144
|
+
sourceHashVerifiedAtLoad: true,
|
|
145
|
+
applicationDefaultMustBeManaged: true,
|
|
146
|
+
packageSupportCheckedBeforeLoad: true,
|
|
147
|
+
providerLifecycleDeferred: input.providerLifecycleDeferred !== false,
|
|
148
|
+
automaticFallback: false
|
|
149
|
+
})
|
|
150
|
+
};
|
|
151
|
+
const planHash = sha256Hex(stableStringify(document));
|
|
152
|
+
return deepFreeze({ ...document, planHash });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function isJavascriptApplicationPlan(value) {
|
|
156
|
+
return Boolean(value && value.version === JAVASCRIPT_APPLICATION_PLAN_VERSION && value.kind === 'pulse.javascript-application-plan');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function normalizeJavascriptTargetDescriptor(input) {
|
|
160
|
+
if (!input || typeof input !== 'object') throw new TypeError('JavaScript target descriptor input must be an object.');
|
|
161
|
+
const commands = input.commands || {};
|
|
162
|
+
return deepFreeze({
|
|
163
|
+
version: JAVASCRIPT_TARGET_DESCRIPTOR_VERSION,
|
|
164
|
+
provider: requireString('JavaScript target provider', input.provider),
|
|
165
|
+
target: 'javascript',
|
|
166
|
+
targetId: requireString('JavaScript target id', input.targetId),
|
|
167
|
+
runtimeClass: JAVASCRIPT_RUNTIME_CLASS,
|
|
168
|
+
sourceApplication: true,
|
|
169
|
+
automaticFallback: false,
|
|
170
|
+
status: requireString('JavaScript target status', input.status),
|
|
171
|
+
hostBridge: input.hostBridge === true,
|
|
172
|
+
applicationLoader: input.applicationLoader === true,
|
|
173
|
+
requestAdapter: input.requestAdapter === true,
|
|
174
|
+
lifecycle: input.lifecycle === true,
|
|
175
|
+
capabilities: deepFreeze(input.capabilities || {
|
|
176
|
+
version: 'pulse.javascript-capability-envelope.v1',
|
|
177
|
+
provider: input.provider,
|
|
178
|
+
status: input.requestAdapter === true ? 'request-lifecycle-ready' : 'provider-adapters-deferred',
|
|
179
|
+
core: Object.freeze({
|
|
180
|
+
request: input.requestAdapter === true,
|
|
181
|
+
response: input.requestAdapter === true,
|
|
182
|
+
state: true
|
|
183
|
+
}),
|
|
184
|
+
effects: Object.freeze({ fetch: false, config: false, secret: false, kv: false }),
|
|
185
|
+
packages: Object.freeze([])
|
|
186
|
+
}),
|
|
187
|
+
reporting: deepFreeze(input.reporting || {
|
|
188
|
+
supported: true,
|
|
189
|
+
default: 'info',
|
|
190
|
+
levels: ['off', 'error', 'warn', 'info', 'debug']
|
|
191
|
+
}),
|
|
192
|
+
...(input.crypto ? { crypto: deepFreeze(input.crypto) } : {}),
|
|
193
|
+
commands: Object.freeze({
|
|
194
|
+
compile: commands.compile === true,
|
|
195
|
+
inspect: commands.inspect === true,
|
|
196
|
+
doctor: commands.doctor === true,
|
|
197
|
+
build: commands.build === true,
|
|
198
|
+
test: commands.test === true,
|
|
199
|
+
dev: commands.dev === true
|
|
200
|
+
})
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = Object.freeze({
|
|
205
|
+
JAVASCRIPT_APPLICATION_PLAN_VERSION,
|
|
206
|
+
JAVASCRIPT_APPLICATION_LOADER_VERSION,
|
|
207
|
+
JAVASCRIPT_TARGET_DESCRIPTOR_VERSION,
|
|
208
|
+
JAVASCRIPT_RUNTIME_CLASS,
|
|
209
|
+
isJavascriptApplicationPlan,
|
|
210
|
+
normalizeJavascriptApplicationPlan,
|
|
211
|
+
normalizeJavascriptTargetDescriptor
|
|
212
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const JAVASCRIPT_CORE_CAPABILITIES = Object.freeze([
|
|
4
|
+
'error',
|
|
5
|
+
'lifecycle',
|
|
6
|
+
'params',
|
|
7
|
+
'req.header',
|
|
8
|
+
'req.headers',
|
|
9
|
+
'req.method',
|
|
10
|
+
'req.path',
|
|
11
|
+
'req.text',
|
|
12
|
+
'req.url',
|
|
13
|
+
'request.header',
|
|
14
|
+
'request.header.at',
|
|
15
|
+
'request.header.count',
|
|
16
|
+
'request.header.first',
|
|
17
|
+
'request.headers',
|
|
18
|
+
'request.method',
|
|
19
|
+
'request.path',
|
|
20
|
+
'request.text',
|
|
21
|
+
'request.url',
|
|
22
|
+
'response.custom',
|
|
23
|
+
'response.header.append',
|
|
24
|
+
'response.header.delete',
|
|
25
|
+
'response.header.set',
|
|
26
|
+
'response.json',
|
|
27
|
+
'response.response',
|
|
28
|
+
'response.text',
|
|
29
|
+
'route.param',
|
|
30
|
+
'state',
|
|
31
|
+
'state.get',
|
|
32
|
+
'state.set'
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
const javascriptCoreCapabilitySet = new Set(JAVASCRIPT_CORE_CAPABILITIES);
|
|
36
|
+
|
|
37
|
+
function isJavascriptCoreCapability(value) {
|
|
38
|
+
return javascriptCoreCapabilitySet.has(String(value));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = Object.freeze({
|
|
42
|
+
JAVASCRIPT_CORE_CAPABILITIES,
|
|
43
|
+
isJavascriptCoreCapability
|
|
44
|
+
});
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PACKAGE_OWNERSHIP_CONTRACT_VERSION = 'pulse.package-ownership.v1';
|
|
4
|
+
const APPLICATION_IR_ENVELOPE_VERSION = 'pulse.application-ir-envelope.v1';
|
|
5
|
+
|
|
6
|
+
function freezeList(values) {
|
|
7
|
+
return Object.freeze(Array.from(values || []));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function packageOwner(definition) {
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
...definition,
|
|
13
|
+
owns: freezeList(definition.owns),
|
|
14
|
+
mustNotOwn: freezeList(definition.mustNotOwn),
|
|
15
|
+
directRecognizedImports: freezeList(definition.directRecognizedImports)
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const PACKAGE_OWNERSHIP_DEFINITIONS = Object.freeze([
|
|
20
|
+
packageOwner({
|
|
21
|
+
package: '@pulse-compute/runtime',
|
|
22
|
+
layer: 'low-level-application-contract',
|
|
23
|
+
currentStatus: 'public',
|
|
24
|
+
sprint1Status: 'public-vnext-candidate',
|
|
25
|
+
owns: [
|
|
26
|
+
'Router topology and terminal control flow',
|
|
27
|
+
'request, response, context, capability, and handler types',
|
|
28
|
+
'low-level plain-handler and Router authoring',
|
|
29
|
+
'target-neutral application semantics'
|
|
30
|
+
],
|
|
31
|
+
mustNotOwn: [
|
|
32
|
+
'workspace discovery',
|
|
33
|
+
'profile selection',
|
|
34
|
+
'configuration factory normalization',
|
|
35
|
+
'provider lifecycle',
|
|
36
|
+
'compiler internals'
|
|
37
|
+
],
|
|
38
|
+
directRecognizedImports: ['Router'],
|
|
39
|
+
publicationGate: 'already-public'
|
|
40
|
+
}),
|
|
41
|
+
packageOwner({
|
|
42
|
+
package: '@pulse-compute/pulse',
|
|
43
|
+
layer: 'ergonomic-project-wrapper',
|
|
44
|
+
currentStatus: 'private-reserved',
|
|
45
|
+
sprint1Status: 'implementation-candidate-not-yet-released',
|
|
46
|
+
owns: [
|
|
47
|
+
'Pulse application root',
|
|
48
|
+
'defineConfig deferred factory marker',
|
|
49
|
+
'symbolic config scope types',
|
|
50
|
+
'project/profile composition ergonomics',
|
|
51
|
+
'opaque profile composition token'
|
|
52
|
+
],
|
|
53
|
+
mustNotOwn: [
|
|
54
|
+
'a second Router dispatcher',
|
|
55
|
+
'host lifecycle',
|
|
56
|
+
'runtime filesystem discovery',
|
|
57
|
+
'resolved config or secret values',
|
|
58
|
+
'compiler rule registration'
|
|
59
|
+
],
|
|
60
|
+
directRecognizedImports: ['Pulse', 'defineConfig'],
|
|
61
|
+
publicationGate: 'separate-human-authorized-release-change'
|
|
62
|
+
}),
|
|
63
|
+
packageOwner({
|
|
64
|
+
package: '@pulse-compute/cli',
|
|
65
|
+
layer: 'project-tooling',
|
|
66
|
+
currentStatus: 'public',
|
|
67
|
+
sprint1Status: 'public-convergence-candidate',
|
|
68
|
+
owns: [
|
|
69
|
+
'workspace and config discovery',
|
|
70
|
+
'profile selection precedence',
|
|
71
|
+
'project command orchestration',
|
|
72
|
+
'provider lifecycle delegation',
|
|
73
|
+
'inspection and local artifact evidence'
|
|
74
|
+
],
|
|
75
|
+
mustNotOwn: [
|
|
76
|
+
'Router semantics',
|
|
77
|
+
'handler semantic classification',
|
|
78
|
+
'package capability semantics',
|
|
79
|
+
'resolved secret values in artifacts'
|
|
80
|
+
],
|
|
81
|
+
directRecognizedImports: [],
|
|
82
|
+
publicationGate: 'existing-public-package'
|
|
83
|
+
}),
|
|
84
|
+
packageOwner({
|
|
85
|
+
package: '@pulse-compute/wasm-contracts',
|
|
86
|
+
layer: 'internal-shared-contract-authority',
|
|
87
|
+
currentStatus: 'public-implementation-package',
|
|
88
|
+
sprint1Status: 'shared-authority',
|
|
89
|
+
owns: [
|
|
90
|
+
'compiler spine phase vocabulary',
|
|
91
|
+
'handler surface classifications',
|
|
92
|
+
'project/profile plan schema',
|
|
93
|
+
'package ownership declarations',
|
|
94
|
+
'provider-neutral operation contracts'
|
|
95
|
+
],
|
|
96
|
+
mustNotOwn: [
|
|
97
|
+
'TypeScript AST traversal',
|
|
98
|
+
'provider execution',
|
|
99
|
+
'package-specific lowering behavior',
|
|
100
|
+
'public third-party compiler plugins'
|
|
101
|
+
],
|
|
102
|
+
directRecognizedImports: [],
|
|
103
|
+
publicationGate: 'existing-public-package'
|
|
104
|
+
})
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
const IMPLEMENTATION_ROLE_OWNERSHIP = Object.freeze([
|
|
108
|
+
Object.freeze({
|
|
109
|
+
role: 'compiler-orchestration',
|
|
110
|
+
owner: 'pulse.compiler-orchestration',
|
|
111
|
+
owns: Object.freeze([
|
|
112
|
+
'TypeScript source extraction',
|
|
113
|
+
'surface recognition and normalization adapters',
|
|
114
|
+
'contract validation',
|
|
115
|
+
'canonical IR construction',
|
|
116
|
+
'provider-neutral native lowering orchestration'
|
|
117
|
+
]),
|
|
118
|
+
mustNotOwn: Object.freeze([
|
|
119
|
+
'provider runtime behavior',
|
|
120
|
+
'arbitrary package source interpretation',
|
|
121
|
+
'public plugin discovery',
|
|
122
|
+
'alternate Router semantics for Pulse'
|
|
123
|
+
])
|
|
124
|
+
})
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
const PUBLIC_SYMBOL_OWNERSHIP = Object.freeze([
|
|
128
|
+
Object.freeze({ symbol: 'Router', package: '@pulse-compute/runtime', role: 'application-root', importPolicy: 'direct-named-import', aliases: false }),
|
|
129
|
+
Object.freeze({ symbol: 'Pulse', package: '@pulse-compute/pulse', role: 'application-root', importPolicy: 'direct-named-import', aliases: false }),
|
|
130
|
+
Object.freeze({ symbol: 'defineConfig', package: '@pulse-compute/pulse', role: 'config-factory-marker', importPolicy: 'direct-named-import', aliases: false })
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
const APPLICATION_IR_ENVELOPE = Object.freeze({
|
|
134
|
+
version: APPLICATION_IR_ENVELOPE_VERSION,
|
|
135
|
+
kind: 'pulse.application-ir',
|
|
136
|
+
routerField: 'router',
|
|
137
|
+
projectField: 'project',
|
|
138
|
+
router: Object.freeze({
|
|
139
|
+
required: true,
|
|
140
|
+
authority: 'existing-canonical-router-ir',
|
|
141
|
+
semanticsMayDependOnProjectMetadata: false
|
|
142
|
+
}),
|
|
143
|
+
project: Object.freeze({
|
|
144
|
+
requiredFor: Object.freeze(['pulse-root']),
|
|
145
|
+
forbiddenFor: Object.freeze([]),
|
|
146
|
+
contents: Object.freeze([
|
|
147
|
+
'construction-mode',
|
|
148
|
+
'config-plan-hash',
|
|
149
|
+
'selected-profile',
|
|
150
|
+
'strict-policy',
|
|
151
|
+
'symbolic-bindings',
|
|
152
|
+
'package-fragments'
|
|
153
|
+
]),
|
|
154
|
+
resolvedSecretValues: false
|
|
155
|
+
}),
|
|
156
|
+
policies: Object.freeze({
|
|
157
|
+
pulseCreatesSecondRouterIr: false,
|
|
158
|
+
pulseChangesRouterCursorSemantics: false,
|
|
159
|
+
pulseChangesErrorLaneSemantics: false,
|
|
160
|
+
pulseChangesResponseOwnership: false,
|
|
161
|
+
configurationBranchesInsideRouterIr: false
|
|
162
|
+
})
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
function validatePackageOwnership(
|
|
166
|
+
definitions = PACKAGE_OWNERSHIP_DEFINITIONS,
|
|
167
|
+
symbols = PUBLIC_SYMBOL_OWNERSHIP,
|
|
168
|
+
implementationRoles = IMPLEMENTATION_ROLE_OWNERSHIP
|
|
169
|
+
) {
|
|
170
|
+
const packages = new Map();
|
|
171
|
+
for (const definition of definitions) {
|
|
172
|
+
if (!definition || typeof definition.package !== 'string' || definition.package.length === 0) {
|
|
173
|
+
throw new TypeError('Package ownership definition requires a package name.');
|
|
174
|
+
}
|
|
175
|
+
if (packages.has(definition.package)) throw new TypeError(`Duplicate package ownership definition: ${definition.package}`);
|
|
176
|
+
packages.set(definition.package, definition);
|
|
177
|
+
}
|
|
178
|
+
const symbolOwners = new Map();
|
|
179
|
+
for (const entry of symbols) {
|
|
180
|
+
if (!packages.has(entry.package)) throw new TypeError(`Public symbol ${entry.symbol} references unknown package ${entry.package}.`);
|
|
181
|
+
if (symbolOwners.has(entry.symbol)) throw new TypeError(`Public symbol ${entry.symbol} has multiple package owners.`);
|
|
182
|
+
symbolOwners.set(entry.symbol, entry);
|
|
183
|
+
}
|
|
184
|
+
const roles = new Map();
|
|
185
|
+
for (const entry of implementationRoles) {
|
|
186
|
+
if (!entry || typeof entry.role !== 'string' || entry.role.length === 0) {
|
|
187
|
+
throw new TypeError('Implementation-role ownership definition requires a role.');
|
|
188
|
+
}
|
|
189
|
+
if (typeof entry.owner !== 'string' || entry.owner.length === 0) {
|
|
190
|
+
throw new TypeError(`Implementation role ${entry.role} requires an owner.`);
|
|
191
|
+
}
|
|
192
|
+
if (roles.has(entry.role)) throw new TypeError(`Duplicate implementation-role ownership definition: ${entry.role}`);
|
|
193
|
+
roles.set(entry.role, entry);
|
|
194
|
+
}
|
|
195
|
+
return Object.freeze({ packages, symbolOwners, roles });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const DEFAULT_PACKAGE_OWNERSHIP_REGISTRY = validatePackageOwnership();
|
|
199
|
+
|
|
200
|
+
function packageOwnerFor(name) {
|
|
201
|
+
return DEFAULT_PACKAGE_OWNERSHIP_REGISTRY.packages.get(name);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function publicSymbolOwner(symbol) {
|
|
205
|
+
return DEFAULT_PACKAGE_OWNERSHIP_REGISTRY.symbolOwners.get(symbol);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function implementationRoleOwner(role) {
|
|
209
|
+
return DEFAULT_PACKAGE_OWNERSHIP_REGISTRY.roles.get(role);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function defaultPackageOwnershipContract() {
|
|
213
|
+
return Object.freeze({
|
|
214
|
+
version: PACKAGE_OWNERSHIP_CONTRACT_VERSION,
|
|
215
|
+
packages: PACKAGE_OWNERSHIP_DEFINITIONS,
|
|
216
|
+
symbols: PUBLIC_SYMBOL_OWNERSHIP,
|
|
217
|
+
implementationRoles: IMPLEMENTATION_ROLE_OWNERSHIP,
|
|
218
|
+
applicationIr: APPLICATION_IR_ENVELOPE,
|
|
219
|
+
policies: Object.freeze({
|
|
220
|
+
runtimeIsLowLevelEscapeHatch: true,
|
|
221
|
+
pulseSharesRouterIr: true,
|
|
222
|
+
cliOwnsProjectOrchestration: true,
|
|
223
|
+
packageLowerersReceiveCanonicalOperations: true,
|
|
224
|
+
publicCompilerPluginApi: false
|
|
225
|
+
})
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
module.exports = {
|
|
230
|
+
PACKAGE_OWNERSHIP_CONTRACT_VERSION,
|
|
231
|
+
APPLICATION_IR_ENVELOPE_VERSION,
|
|
232
|
+
PACKAGE_OWNERSHIP_DEFINITIONS,
|
|
233
|
+
PUBLIC_SYMBOL_OWNERSHIP,
|
|
234
|
+
IMPLEMENTATION_ROLE_OWNERSHIP,
|
|
235
|
+
APPLICATION_IR_ENVELOPE,
|
|
236
|
+
DEFAULT_PACKAGE_OWNERSHIP_REGISTRY,
|
|
237
|
+
validatePackageOwnership,
|
|
238
|
+
packageOwnerFor,
|
|
239
|
+
publicSymbolOwner,
|
|
240
|
+
implementationRoleOwner,
|
|
241
|
+
defaultPackageOwnershipContract
|
|
242
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { prefixedStableId, stableStringify, sha256Hex } = require('../stable-id.js');
|
|
5
|
+
|
|
6
|
+
const PACKAGE_PRODUCT_PROJECTION_VERSION = 'pulse.package-product-projection.v1';
|
|
7
|
+
const PACKAGE_PRODUCT_BINDING_VERSION = 'pulse.package-product-binding.v1';
|
|
8
|
+
const PACKAGE_FRAGMENT_OWNERSHIP_VERSION = 'pulse.package-fragment-ownership.v1';
|
|
9
|
+
const PACKAGE_BINDING_ROLES = Object.freeze(['authoring', 'helper', 're-export']);
|
|
10
|
+
const PACKAGE_COMPOSITION_STATUSES = Object.freeze(['supported', 'reserved', 'not-realized', 'unsupported']);
|
|
11
|
+
|
|
12
|
+
function isPlainObject(value) {
|
|
13
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
14
|
+
const proto = Object.getPrototypeOf(value);
|
|
15
|
+
return proto === Object.prototype || proto === null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function assertKnownKeys(input, allowed, field) {
|
|
19
|
+
for (const key of Object.keys(input)) if (!allowed.has(key)) throw new TypeError(`${field} contains unsupported field ${key}.`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function string(value, field) {
|
|
23
|
+
if (typeof value !== 'string' || value.trim() === '') throw new TypeError(`${field} must be a non-empty string.`);
|
|
24
|
+
if (value.includes('\0')) throw new TypeError(`${field} must not contain NUL.`);
|
|
25
|
+
return value.trim();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function nullableString(value, field) {
|
|
29
|
+
return value == null ? null : string(value, field);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function bool(value, field) {
|
|
33
|
+
if (typeof value !== 'boolean') throw new TypeError(`${field} must be a boolean.`);
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function strings(values, field) {
|
|
38
|
+
if (values == null) return Object.freeze([]);
|
|
39
|
+
if (!Array.isArray(values)) throw new TypeError(`${field} must be an array.`);
|
|
40
|
+
return Object.freeze([...new Set(values.map((value, index) => string(value, `${field}[${index}]`)))].sort());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function source(input, field) {
|
|
44
|
+
if (!isPlainObject(input)) throw new TypeError(`${field} must be an object.`);
|
|
45
|
+
assertKnownKeys(input, new Set(['file', 'line', 'column']), field);
|
|
46
|
+
return Object.freeze({
|
|
47
|
+
file: string(input.file, `${field}.file`).replace(/\\/g, '/'),
|
|
48
|
+
line: Number(input.line || 1),
|
|
49
|
+
column: Number(input.column || 1)
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function normalizeTarget(input, field) {
|
|
54
|
+
if (!isPlainObject(input)) throw new TypeError(`${field} must be an object.`);
|
|
55
|
+
assertKnownKeys(input, new Set(['version', 'status', 'realization', 'entry', 'lowerableSubpath', 'providerRequirements', 'reasonCode']), field);
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
status: string(input.status, `${field}.status`),
|
|
58
|
+
realization: string(input.realization || 'none', `${field}.realization`),
|
|
59
|
+
entry: nullableString(input.entry, `${field}.entry`),
|
|
60
|
+
lowerableSubpath: nullableString(input.lowerableSubpath, `${field}.lowerableSubpath`),
|
|
61
|
+
providerRequirements: strings(input.providerRequirements, `${field}.providerRequirements`),
|
|
62
|
+
reasonCode: nullableString(input.reasonCode, `${field}.reasonCode`)
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function normalizeContract(input, index) {
|
|
67
|
+
if (!isPlainObject(input)) throw new TypeError(`contracts[${index}] must be an object.`);
|
|
68
|
+
assertKnownKeys(input, new Set([
|
|
69
|
+
'contractId', 'packageName', 'packageVersion', 'metadataHash', 'profileFragment',
|
|
70
|
+
'helperImports', 'reExportImports', 'authoringImport', 'authoringSymbols',
|
|
71
|
+
'compositionStatus', 'compositionHelper', 'compositionReasonCode',
|
|
72
|
+
'nativeTarget', 'javascriptTarget', 'conformanceStatus', 'conformanceFixtureRoots', 'conformanceSemanticCases'
|
|
73
|
+
]), `contracts[${index}]`);
|
|
74
|
+
const compositionStatus = string(input.compositionStatus, `contracts[${index}].compositionStatus`);
|
|
75
|
+
if (!PACKAGE_COMPOSITION_STATUSES.includes(compositionStatus)) throw new TypeError(`Unsupported composition status ${compositionStatus}.`);
|
|
76
|
+
return Object.freeze({
|
|
77
|
+
contractId: string(input.contractId, `contracts[${index}].contractId`),
|
|
78
|
+
packageName: string(input.packageName, `contracts[${index}].packageName`),
|
|
79
|
+
packageVersion: string(input.packageVersion, `contracts[${index}].packageVersion`),
|
|
80
|
+
metadataHash: string(input.metadataHash, `contracts[${index}].metadataHash`),
|
|
81
|
+
profileFragment: string(input.profileFragment, `contracts[${index}].profileFragment`),
|
|
82
|
+
helperImports: strings(input.helperImports, `contracts[${index}].helperImports`),
|
|
83
|
+
reExportImports: strings(input.reExportImports, `contracts[${index}].reExportImports`),
|
|
84
|
+
authoringImport: string(input.authoringImport, `contracts[${index}].authoringImport`),
|
|
85
|
+
authoringSymbols: strings(input.authoringSymbols, `contracts[${index}].authoringSymbols`),
|
|
86
|
+
compositionStatus,
|
|
87
|
+
compositionHelper: nullableString(input.compositionHelper, `contracts[${index}].compositionHelper`),
|
|
88
|
+
compositionReasonCode: nullableString(input.compositionReasonCode, `contracts[${index}].compositionReasonCode`),
|
|
89
|
+
nativeTarget: normalizeTarget(input.nativeTarget, `contracts[${index}].nativeTarget`),
|
|
90
|
+
javascriptTarget: normalizeTarget(input.javascriptTarget, `contracts[${index}].javascriptTarget`),
|
|
91
|
+
conformanceStatus: string(input.conformanceStatus, `contracts[${index}].conformanceStatus`),
|
|
92
|
+
conformanceFixtureRoots: strings(input.conformanceFixtureRoots, `contracts[${index}].conformanceFixtureRoots`),
|
|
93
|
+
conformanceSemanticCases: strings(input.conformanceSemanticCases, `contracts[${index}].conformanceSemanticCases`)
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function normalizeBinding(input, index) {
|
|
98
|
+
if (!isPlainObject(input)) throw new TypeError(`bindings[${index}] must be an object.`);
|
|
99
|
+
assertKnownKeys(input, new Set([
|
|
100
|
+
'moduleId', 'localName', 'exportName', 'importedName', 'packageModuleId', 'packageName',
|
|
101
|
+
'contractId', 'role', 'source', 'via', 'direct', 'used'
|
|
102
|
+
]), `bindings[${index}]`);
|
|
103
|
+
const role = string(input.role, `bindings[${index}].role`);
|
|
104
|
+
if (!PACKAGE_BINDING_ROLES.includes(role)) throw new TypeError(`Unsupported package product binding role ${role}.`);
|
|
105
|
+
const semantic = Object.freeze({
|
|
106
|
+
version: PACKAGE_PRODUCT_BINDING_VERSION,
|
|
107
|
+
moduleId: string(input.moduleId, `bindings[${index}].moduleId`),
|
|
108
|
+
localName: nullableString(input.localName, `bindings[${index}].localName`),
|
|
109
|
+
exportName: nullableString(input.exportName, `bindings[${index}].exportName`),
|
|
110
|
+
importedName: string(input.importedName, `bindings[${index}].importedName`),
|
|
111
|
+
packageModuleId: string(input.packageModuleId, `bindings[${index}].packageModuleId`),
|
|
112
|
+
packageName: string(input.packageName, `bindings[${index}].packageName`),
|
|
113
|
+
contractId: string(input.contractId, `bindings[${index}].contractId`),
|
|
114
|
+
role,
|
|
115
|
+
source: source(input.source, `bindings[${index}].source`),
|
|
116
|
+
via: string(input.via, `bindings[${index}].via`),
|
|
117
|
+
direct: bool(input.direct, `bindings[${index}].direct`),
|
|
118
|
+
used: bool(input.used, `bindings[${index}].used`)
|
|
119
|
+
});
|
|
120
|
+
return Object.freeze({ ...semantic, id: prefixedStableId('pkgproduct', semantic, { length: 32 }) });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function normalizeFragment(input, index) {
|
|
124
|
+
if (!isPlainObject(input)) throw new TypeError(`fragments[${index}] must be an object.`);
|
|
125
|
+
assertKnownKeys(input, new Set(['key', 'contractId', 'packageName', 'present', 'selected']), `fragments[${index}]`);
|
|
126
|
+
return Object.freeze({
|
|
127
|
+
version: PACKAGE_FRAGMENT_OWNERSHIP_VERSION,
|
|
128
|
+
key: string(input.key, `fragments[${index}].key`),
|
|
129
|
+
contractId: nullableString(input.contractId, `fragments[${index}].contractId`),
|
|
130
|
+
packageName: nullableString(input.packageName, `fragments[${index}].packageName`),
|
|
131
|
+
present: bool(input.present, `fragments[${index}].present`),
|
|
132
|
+
selected: bool(input.selected, `fragments[${index}].selected`)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function normalizePackageProductProjection(input) {
|
|
137
|
+
if (!isPlainObject(input)) throw new TypeError('Package product projection must be an object.');
|
|
138
|
+
assertKnownKeys(input, new Set(['graphHash', 'contracts', 'bindings', 'fragments', 'selectedContracts', 'composedContracts']), 'Package product projection');
|
|
139
|
+
const contracts = Object.freeze([...(input.contracts || [])].map(normalizeContract)
|
|
140
|
+
.sort((a, b) => a.contractId.localeCompare(b.contractId)));
|
|
141
|
+
const bindings = Object.freeze([...(input.bindings || [])].map(normalizeBinding)
|
|
142
|
+
.sort((a, b) => a.moduleId.localeCompare(b.moduleId) || (a.localName || a.exportName || '').localeCompare(b.localName || b.exportName || '') || a.id.localeCompare(b.id)));
|
|
143
|
+
const fragments = Object.freeze([...(input.fragments || [])].map(normalizeFragment)
|
|
144
|
+
.sort((a, b) => a.key.localeCompare(b.key)));
|
|
145
|
+
const semantic = Object.freeze({
|
|
146
|
+
version: PACKAGE_PRODUCT_PROJECTION_VERSION,
|
|
147
|
+
graphHash: string(input.graphHash, 'graphHash'),
|
|
148
|
+
contracts,
|
|
149
|
+
bindings,
|
|
150
|
+
fragments,
|
|
151
|
+
selectedContracts: strings(input.selectedContracts, 'selectedContracts'),
|
|
152
|
+
composedContracts: strings(input.composedContracts, 'composedContracts'),
|
|
153
|
+
policy: Object.freeze({
|
|
154
|
+
graphOwnsAttribution: true,
|
|
155
|
+
productMetadataExecutesCode: false,
|
|
156
|
+
helperOwnershipUnique: true,
|
|
157
|
+
profileFragmentOwnershipUnique: true,
|
|
158
|
+
nativeLoweringTrustSeparate: true,
|
|
159
|
+
automaticFallback: false
|
|
160
|
+
})
|
|
161
|
+
});
|
|
162
|
+
return Object.freeze({ ...semantic, projectionHash: sha256Hex(stableStringify(semantic)) });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
module.exports = Object.freeze({
|
|
166
|
+
PACKAGE_PRODUCT_PROJECTION_VERSION,
|
|
167
|
+
PACKAGE_PRODUCT_BINDING_VERSION,
|
|
168
|
+
PACKAGE_FRAGMENT_OWNERSHIP_VERSION,
|
|
169
|
+
PACKAGE_BINDING_ROLES,
|
|
170
|
+
normalizePackageProductProjection
|
|
171
|
+
});
|