@pulse-compute/provider-node 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.
Files changed (38) hide show
  1. package/README.md +60 -1
  2. package/package.json +61 -6
  3. package/src/capabilities.js +56 -0
  4. package/src/compiler/assets-provider-proof.js +434 -0
  5. package/src/compiler/backend-json-request-body-proof.js +90 -0
  6. package/src/compiler/index.js +38 -0
  7. package/src/compiler/node-adapter.js +452 -0
  8. package/src/compiler/node-compiled-wasm-assets-lifecycle-proof.js +435 -0
  9. package/src/compiler/request-json-body-proof.js +181 -0
  10. package/src/compiler/route-handler-compiled-wasm-bridge.js +323 -0
  11. package/src/compiler/route-handler-effect-proof.js +215 -0
  12. package/src/compiler/route-handler-live-origin-proof.js +372 -0
  13. package/src/compiler/schema-decode-result-proof.js +180 -0
  14. package/src/compiler/schema-response-codec-proof.js +149 -0
  15. package/src/events/reference-adapter.js +145 -0
  16. package/src/index.js +57 -0
  17. package/src/javascript/assets-adapter.js +68 -0
  18. package/src/javascript/bindings-adapter.js +120 -0
  19. package/src/javascript/fetch-adapter.js +187 -0
  20. package/src/javascript/grip-broadcast.js +243 -0
  21. package/src/javascript/jwt-verifier.js +137 -0
  22. package/src/javascript/lifecycle.js +69 -0
  23. package/src/javascript/node-adapter.js +281 -0
  24. package/src/javascript/package-effects.js +78 -0
  25. package/src/javascript/runtime-host.js +165 -0
  26. package/src/javascript/source-package.js +439 -0
  27. package/src/javascript/support.js +205 -0
  28. package/src/javascript/target-support-policy.js +134 -0
  29. package/src/javascript/target.js +37 -0
  30. package/src/javascript/test-runtime.js +111 -0
  31. package/src/native/target.js +78 -0
  32. package/src/runtime/assets-provider.js +776 -0
  33. package/src/runtime/canonical-api-runtime.js +632 -0
  34. package/src/runtime/compiled-wasm-node-adapter-kv.js +15 -0
  35. package/src/runtime/index.js +17 -0
  36. package/src/runtime/jwt-verifier.js +264 -0
  37. package/src/runtime/route-handler-effects.js +757 -0
  38. package/src/toolchain.js +258 -0
@@ -0,0 +1,439 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const path = require('node:path');
6
+ const { builtinModules, createRequire } = require('node:module');
7
+ const ts = require('typescript');
8
+
9
+ const NODE_JAVASCRIPT_SOURCE_PACKAGE_VERSION = 'pulse.node-javascript-source-package.v2';
10
+ const NODE_JAVASCRIPT_SOURCE_PACKAGE_MANIFEST = 'pulse-javascript-source-package.json';
11
+ const BUILTIN_MODULES = new Set([...builtinModules, ...builtinModules.map((name) => `node:${name}`)]);
12
+
13
+ class PulseNodeJavascriptSourcePackageError extends Error {
14
+ constructor(code, message, detail = {}) {
15
+ super(message);
16
+ this.name = 'PulseNodeJavascriptSourcePackageError';
17
+ this.code = code;
18
+ this.detail = Object.freeze({ ...detail });
19
+ }
20
+ }
21
+
22
+ function stableJson(value) {
23
+ return `${JSON.stringify(value, null, 2)}\n`;
24
+ }
25
+
26
+ function sha256(value) {
27
+ return crypto.createHash('sha256').update(value).digest('hex');
28
+ }
29
+
30
+ function slash(value) {
31
+ return String(value).replace(/\\/g, '/');
32
+ }
33
+
34
+ function assertInside(root, candidate, label) {
35
+ const relative = path.relative(path.resolve(root), path.resolve(candidate));
36
+ if (relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))) return;
37
+ throw new PulseNodeJavascriptSourcePackageError(
38
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_PATH_UNSAFE',
39
+ `${label} escapes the JavaScript source package root.`,
40
+ { root: path.resolve(root), candidate: path.resolve(candidate) }
41
+ );
42
+ }
43
+
44
+ function outputModulePath(modulePath) {
45
+ const normalized = slash(modulePath);
46
+ if (normalized.endsWith('.json')) return normalized;
47
+ return normalized.replace(/\.(?:[cm]?[jt]sx?)$/i, '.js');
48
+ }
49
+
50
+ function sourceKind(file) {
51
+ const extension = path.extname(file).toLowerCase();
52
+ if (extension === '.json') return 'json';
53
+ return 'javascript';
54
+ }
55
+
56
+ function transpileModule(source, file) {
57
+ const result = ts.transpileModule(source, {
58
+ fileName: file,
59
+ compilerOptions: {
60
+ target: ts.ScriptTarget.ES2022,
61
+ module: ts.ModuleKind.CommonJS,
62
+ moduleResolution: ts.ModuleResolutionKind.Node10,
63
+ esModuleInterop: true,
64
+ allowJs: true,
65
+ resolveJsonModule: true,
66
+ sourceMap: false,
67
+ inlineSourceMap: false,
68
+ inlineSources: false,
69
+ declaration: false
70
+ },
71
+ reportDiagnostics: true
72
+ });
73
+ const errors = (result.diagnostics || []).filter((entry) => entry.category === ts.DiagnosticCategory.Error);
74
+ if (errors.length > 0) {
75
+ throw new PulseNodeJavascriptSourcePackageError(
76
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_COMPILE_FAILED',
77
+ `JavaScript source packaging could not transpile ${file}.`,
78
+ {
79
+ file,
80
+ diagnostics: errors.map((entry) => Object.freeze({
81
+ code: entry.code,
82
+ message: ts.flattenDiagnosticMessageText(entry.messageText, '\n')
83
+ }))
84
+ }
85
+ );
86
+ }
87
+ return result.outputText;
88
+ }
89
+
90
+ function packageNameFromSpecifier(specifier) {
91
+ const value = String(specifier || '');
92
+ if (!value || value.startsWith('.') || value.startsWith('/') || BUILTIN_MODULES.has(value)) return null;
93
+ if (value.startsWith('@')) {
94
+ const parts = value.split('/');
95
+ return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : null;
96
+ }
97
+ return value.split('/')[0] || null;
98
+ }
99
+
100
+ function projectPackageManifest(projectRoot) {
101
+ const file = path.join(projectRoot, 'package.json');
102
+ if (!fs.existsSync(file)) return null;
103
+ try {
104
+ const value = JSON.parse(fs.readFileSync(file, 'utf8'));
105
+ return value && typeof value === 'object' ? value : null;
106
+ } catch (error) {
107
+ throw new PulseNodeJavascriptSourcePackageError(
108
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_PROJECT_MANIFEST_INVALID',
109
+ `Cannot parse project package manifest ${file}.`,
110
+ { file, cause: error && error.message }
111
+ );
112
+ }
113
+ }
114
+
115
+ function declaredVersion(manifest, name) {
116
+ for (const field of ['dependencies', 'optionalDependencies', 'peerDependencies', 'devDependencies']) {
117
+ const value = manifest && manifest[field] && manifest[field][name];
118
+ if (typeof value === 'string' && value.trim()) return value.trim();
119
+ }
120
+ return null;
121
+ }
122
+
123
+ function packageVersionFromEntry(entry, name) {
124
+ let current = path.dirname(entry);
125
+ const root = path.parse(current).root;
126
+ while (current !== root) {
127
+ const manifestFile = path.join(current, 'package.json');
128
+ if (fs.existsSync(manifestFile)) {
129
+ try {
130
+ const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
131
+ if (manifest && manifest.name === name && typeof manifest.version === 'string') return manifest.version;
132
+ } catch (_) {
133
+ // Continue searching toward the package root.
134
+ }
135
+ }
136
+ current = path.dirname(current);
137
+ }
138
+ return null;
139
+ }
140
+
141
+ function workspacePatterns(manifest) {
142
+ if (!manifest) return [];
143
+ if (Array.isArray(manifest.workspaces)) return manifest.workspaces;
144
+ if (manifest.workspaces && Array.isArray(manifest.workspaces.packages)) return manifest.workspaces.packages;
145
+ return [];
146
+ }
147
+
148
+ function expandWorkspacePattern(root, pattern) {
149
+ const segments = slash(pattern).split('/').filter(Boolean);
150
+ let candidates = [root];
151
+ for (const segment of segments) {
152
+ const next = [];
153
+ for (const candidate of candidates) {
154
+ if (segment === '*') {
155
+ if (!fs.existsSync(candidate) || !fs.statSync(candidate).isDirectory()) continue;
156
+ for (const entry of fs.readdirSync(candidate, { withFileTypes: true })) {
157
+ if (entry.isDirectory() && entry.name !== 'node_modules' && !entry.name.startsWith('.')) {
158
+ next.push(path.join(candidate, entry.name));
159
+ }
160
+ }
161
+ } else if (!segment.includes('*')) {
162
+ next.push(path.join(candidate, segment));
163
+ }
164
+ }
165
+ candidates = next;
166
+ }
167
+ return candidates;
168
+ }
169
+
170
+ function workspacePackageVersion(projectRoot, name) {
171
+ let current = path.resolve(projectRoot);
172
+ const filesystemRoot = path.parse(current).root;
173
+ while (true) {
174
+ const manifestFile = path.join(current, 'package.json');
175
+ if (fs.existsSync(manifestFile)) {
176
+ try {
177
+ const manifest = JSON.parse(fs.readFileSync(manifestFile, 'utf8'));
178
+ const patterns = workspacePatterns(manifest);
179
+ for (const pattern of patterns) {
180
+ for (const candidate of expandWorkspacePattern(current, pattern)) {
181
+ const candidateManifestFile = path.join(candidate, 'package.json');
182
+ if (!fs.existsSync(candidateManifestFile)) continue;
183
+ const candidateManifest = JSON.parse(fs.readFileSync(candidateManifestFile, 'utf8'));
184
+ if (candidateManifest && candidateManifest.name === name && typeof candidateManifest.version === 'string') {
185
+ return candidateManifest.version;
186
+ }
187
+ }
188
+ }
189
+ } catch (_) {
190
+ // Ignore non-workspace or invalid ancestor manifests here; project manifest
191
+ // validation is handled separately by projectPackageManifest().
192
+ }
193
+ }
194
+ if (current === filesystemRoot) break;
195
+ current = path.dirname(current);
196
+ }
197
+ return null;
198
+ }
199
+
200
+ function resolvedPackageVersion(projectRoot, name) {
201
+ const request = createRequire(path.join(projectRoot, 'package.json'));
202
+ try {
203
+ const entry = request.resolve(name);
204
+ const version = packageVersionFromEntry(entry, name);
205
+ if (version) return version;
206
+ } catch (_) {
207
+ // Fall through to workspace discovery for source-tree projects that have not
208
+ // installed package links into the application directory.
209
+ }
210
+ return workspacePackageVersion(projectRoot, name);
211
+ }
212
+
213
+ function normalizeDependencyVersion(projectRoot, manifest, name) {
214
+ const declared = declaredVersion(manifest, name);
215
+ if (declared && !/^(?:workspace:|file:|link:)/.test(declared)) return declared;
216
+ const resolved = resolvedPackageVersion(projectRoot, name);
217
+ if (resolved) return resolved;
218
+ if (declared) return declared;
219
+ throw new PulseNodeJavascriptSourcePackageError(
220
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_DEPENDENCY_VERSION_UNKNOWN',
221
+ `Cannot determine a package version for reachable dependency ${name}.`,
222
+ { projectRoot, packageName: name }
223
+ );
224
+ }
225
+
226
+ function reachableDependencies(plan, projectRoot) {
227
+ const names = new Set();
228
+ for (const module of plan.graph.modules || []) {
229
+ if (!module.runtime) continue;
230
+ if (module.kind === 'package' && module.packageName) names.add(module.packageName);
231
+ if (module.kind === 'external' && module.externalSpecifier) {
232
+ const name = packageNameFromSpecifier(module.externalSpecifier);
233
+ if (name) names.add(name);
234
+ }
235
+ }
236
+ const manifest = projectPackageManifest(projectRoot);
237
+ return Object.freeze(Object.fromEntries([...names].sort().map((name) => [
238
+ name,
239
+ normalizeDependencyVersion(projectRoot, manifest, name)
240
+ ])));
241
+ }
242
+
243
+ function sourcePackageName(projectRoot) {
244
+ const manifest = projectPackageManifest(projectRoot);
245
+ const candidate = manifest && typeof manifest.name === 'string'
246
+ ? manifest.name
247
+ : path.basename(projectRoot);
248
+ const normalized = String(candidate || 'pulse-application')
249
+ .toLowerCase()
250
+ .replace(/^@/, '')
251
+ .replace(/[^a-z0-9._-]+/g, '-')
252
+ .replace(/^-+|-+$/g, '') || 'pulse-application';
253
+ return `pulse-build-${normalized}`;
254
+ }
255
+
256
+ function writeFile(root, relativeFile, content) {
257
+ const file = path.join(root, relativeFile);
258
+ assertInside(root, file, `Output file ${relativeFile}`);
259
+ fs.mkdirSync(path.dirname(file), { recursive: true });
260
+ fs.writeFileSync(file, content);
261
+ const bytes = fs.readFileSync(file);
262
+ return Object.freeze({ file: slash(relativeFile), bytes: bytes.byteLength, sha256: sha256(bytes) });
263
+ }
264
+
265
+ function defaultExportLoader(entryFile) {
266
+ return `'use strict';\n\nconst loaded = require(${JSON.stringify(`./application/${slash(entryFile)}`)});\nconst application = loaded && Object.prototype.hasOwnProperty.call(loaded, 'default') ? loaded.default : loaded;\nmodule.exports = application;\n`;
267
+ }
268
+
269
+ function writeNodeJavascriptSourcePackage(options = {}) {
270
+ const plan = options.plan;
271
+ if (!plan || !plan.graph || plan.loadable !== true) {
272
+ throw new PulseNodeJavascriptSourcePackageError(
273
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_PLAN_UNAVAILABLE',
274
+ 'Node JavaScript source packaging requires a loadable JavaScript application plan.',
275
+ { blockers: plan && plan.blockers || [] }
276
+ );
277
+ }
278
+ const projectRoot = path.resolve(options.projectRoot || '.');
279
+ const outDir = path.resolve(options.outDir || path.join(projectRoot, 'dist'));
280
+ assertInside(projectRoot, outDir, 'JavaScript build output');
281
+ fs.mkdirSync(outDir, { recursive: true });
282
+
283
+ const moduleRecords = [];
284
+ const projectModules = (plan.graph.modules || [])
285
+ .filter((entry) => entry.runtime && entry.kind === 'project' && entry.path)
286
+ .sort((left, right) => left.path.localeCompare(right.path));
287
+ for (const module of projectModules) {
288
+ const sourceFile = path.resolve(projectRoot, module.path);
289
+ assertInside(projectRoot, sourceFile, `Project module ${module.path}`);
290
+ if (!fs.existsSync(sourceFile) || !fs.statSync(sourceFile).isFile()) {
291
+ throw new PulseNodeJavascriptSourcePackageError(
292
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_MODULE_MISSING',
293
+ `JavaScript source package module is missing: ${module.path}.`,
294
+ { module: module.path, sourceFile }
295
+ );
296
+ }
297
+ const sourceBytes = fs.readFileSync(sourceFile);
298
+ const actualHash = sha256(sourceBytes);
299
+ if (actualHash !== module.contentHash) {
300
+ throw new PulseNodeJavascriptSourcePackageError(
301
+ 'PULSE_JAVASCRIPT_SOURCE_PACKAGE_SOURCE_CHANGED',
302
+ `JavaScript source package module changed after planning: ${module.path}.`,
303
+ { module: module.path, expected: module.contentHash, actual: actualHash }
304
+ );
305
+ }
306
+ const outputPath = outputModulePath(module.path);
307
+ const kind = sourceKind(module.path);
308
+ const output = kind === 'json'
309
+ ? sourceBytes
310
+ : Buffer.from(transpileModule(sourceBytes.toString('utf8'), module.path));
311
+ const record = writeFile(outDir, `application/${outputPath}`, output);
312
+ moduleRecords.push(Object.freeze({
313
+ moduleId: module.id,
314
+ source: slash(module.path),
315
+ sourceSha256: module.contentHash,
316
+ output: record.file,
317
+ outputSha256: record.sha256,
318
+ bytes: record.bytes,
319
+ kind
320
+ }));
321
+ }
322
+
323
+ const entryOutput = outputModulePath(plan.workspace.entry);
324
+ const schemaBundle = options.schemaBundle;
325
+ const schemaActive = Boolean(schemaBundle && schemaBundle.active);
326
+ const baseDependencies = reachableDependencies(plan, projectRoot);
327
+ const dependencies = Object.freeze({
328
+ ...baseDependencies,
329
+ ...(schemaActive
330
+ ? {
331
+ '@pulse-compute/wasm-contracts': normalizeDependencyVersion(
332
+ projectRoot,
333
+ projectPackageManifest(projectRoot),
334
+ '@pulse-compute/wasm-contracts'
335
+ )
336
+ }
337
+ : {})
338
+ });
339
+ const packageJson = Object.freeze({
340
+ name: sourcePackageName(projectRoot),
341
+ version: '0.0.0',
342
+ private: true,
343
+ type: 'commonjs',
344
+ main: 'index.cjs',
345
+ dependencies
346
+ });
347
+ const packageRecord = writeFile(outDir, 'package.json', stableJson(packageJson));
348
+ const entryRecord = writeFile(outDir, 'index.cjs', defaultExportLoader(entryOutput));
349
+ const planRecord = writeFile(outDir, 'pulse-javascript-application-plan.json', stableJson(plan));
350
+ const schemaRegistryRecord = schemaActive
351
+ ? writeFile(outDir, 'schema-json-registry.json', stableJson(schemaBundle.registry))
352
+ : undefined;
353
+ const schemaCodecsRecord = schemaActive
354
+ ? writeFile(outDir, 'schema-json-codecs.cjs', schemaBundle.moduleSource)
355
+ : undefined;
356
+
357
+ const manifest = Object.freeze({
358
+ version: NODE_JAVASCRIPT_SOURCE_PACKAGE_VERSION,
359
+ status: 'packaged',
360
+ provider: 'node',
361
+ target: 'javascript',
362
+ targetId: plan.targetId,
363
+ automaticFallback: false,
364
+ project: Object.freeze({
365
+ root: '.',
366
+ entry: slash(plan.workspace.entry),
367
+ packagedEntry: `application/${slash(entryOutput)}`
368
+ }),
369
+ plan: Object.freeze({
370
+ version: plan.version,
371
+ planHash: plan.planHash,
372
+ graphVersion: plan.graph.version,
373
+ graphHash: plan.graph.graphHash,
374
+ resolverHash: plan.graph.resolverHash,
375
+ loadable: plan.loadable,
376
+ blockers: plan.blockers
377
+ }),
378
+ package: Object.freeze({
379
+ manifest: packageRecord.file,
380
+ entry: entryRecord.file,
381
+ applicationPlan: planRecord.file,
382
+ schemaRegistry: schemaRegistryRecord && schemaRegistryRecord.file,
383
+ schemaCodecs: schemaCodecsRecord && schemaCodecsRecord.file,
384
+ dependencies
385
+ }),
386
+ schemas: Object.freeze({
387
+ active: schemaActive,
388
+ registry: schemaRegistryRecord && schemaRegistryRecord.file,
389
+ codecs: schemaCodecsRecord && schemaCodecsRecord.file,
390
+ ids: Object.freeze(schemaActive ? [...schemaBundle.schemaIds] : []),
391
+ responseCaseIds: Object.freeze(schemaActive ? [...schemaBundle.responseCaseIds] : []),
392
+ registryHash: schemaActive ? schemaBundle.registry.registryHash : null,
393
+ codecTableHash: schemaActive ? schemaBundle.codecTableHash : null,
394
+ sourceHash: schemaActive ? schemaBundle.sourceHash : null,
395
+ fullCodecRealization: schemaActive ? schemaBundle.fullCodecRealization === true : false
396
+ }),
397
+ modules: Object.freeze(moduleRecords),
398
+ summary: Object.freeze({
399
+ modules: moduleRecords.length,
400
+ packages: Object.keys(dependencies).length,
401
+ bytes: moduleRecords.reduce((sum, entry) => sum + entry.bytes, 0)
402
+ + packageRecord.bytes
403
+ + entryRecord.bytes
404
+ + planRecord.bytes
405
+ + (schemaRegistryRecord ? schemaRegistryRecord.bytes : 0)
406
+ + (schemaCodecsRecord ? schemaCodecsRecord.bytes : 0)
407
+ })
408
+ });
409
+ const manifestRecord = writeFile(outDir, NODE_JAVASCRIPT_SOURCE_PACKAGE_MANIFEST, stableJson(manifest));
410
+ return Object.freeze({
411
+ version: NODE_JAVASCRIPT_SOURCE_PACKAGE_VERSION,
412
+ outDir,
413
+ entryFile: path.join(outDir, entryRecord.file),
414
+ packageFile: path.join(outDir, packageRecord.file),
415
+ applicationPlanFile: path.join(outDir, planRecord.file),
416
+ schemaRegistryFile: schemaRegistryRecord ? path.join(outDir, schemaRegistryRecord.file) : undefined,
417
+ schemaCodecsFile: schemaCodecsRecord ? path.join(outDir, schemaCodecsRecord.file) : undefined,
418
+ manifestFile: path.join(outDir, manifestRecord.file),
419
+ manifest,
420
+ files: Object.freeze([
421
+ packageRecord,
422
+ entryRecord,
423
+ planRecord,
424
+ ...(schemaRegistryRecord ? [schemaRegistryRecord] : []),
425
+ ...(schemaCodecsRecord ? [schemaCodecsRecord] : []),
426
+ manifestRecord,
427
+ ...moduleRecords.map((entry) => Object.freeze({ file: entry.output, bytes: entry.bytes, sha256: entry.outputSha256 }))
428
+ ])
429
+ });
430
+ }
431
+
432
+ module.exports = Object.freeze({
433
+ NODE_JAVASCRIPT_SOURCE_PACKAGE_VERSION,
434
+ NODE_JAVASCRIPT_SOURCE_PACKAGE_MANIFEST,
435
+ PulseNodeJavascriptSourcePackageError,
436
+ outputModulePath,
437
+ reachableDependencies,
438
+ writeNodeJavascriptSourcePackage
439
+ });
@@ -0,0 +1,205 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ normalizeTargetSupportDeclaration
5
+ } = require('@pulse-compute/wasm-contracts/project/target-support-evidence');
6
+ const { NODE_JAVASCRIPT_TARGET_DESCRIPTOR } = require('./target.js');
7
+
8
+ function evidence(artifact, version, cases) {
9
+ return Object.freeze({
10
+ artifact,
11
+ version,
12
+ sha256: null,
13
+ status: 'passed',
14
+ cases,
15
+ matched: cases,
16
+ mismatches: 0
17
+ });
18
+ }
19
+
20
+ const NODE_JAVASCRIPT_PARITY_EVIDENCE = evidence(
21
+ 'wasm/test/contracts/assert-node-router-context-parity.cjs',
22
+ 'pulse.node-router-context-parity.v1',
23
+ 12
24
+ );
25
+ const NODE_JAVASCRIPT_EFFECT_ADAPTER_EVIDENCE = evidence(
26
+ 'wasm/test/contracts/assert-javascript-effect-adapter.cjs',
27
+ 'pulse.javascript-effect-adapter.v1',
28
+ 13
29
+ );
30
+ const NODE_JAVASCRIPT_FETCH_BODY_EVIDENCE = evidence(
31
+ 'wasm/test/contracts/assert-fetch-projections-request-bodies.cjs',
32
+ 'pulse.fetch-projections-request-bodies.v1',
33
+ 12
34
+ );
35
+ const NODE_JAVASCRIPT_BINDINGS_REDACTION_EVIDENCE = evidence(
36
+ 'wasm/test/contracts/assert-config-secrets-kv-redaction.cjs',
37
+ 'pulse.config-secrets-kv-redaction.v1',
38
+ 10
39
+ );
40
+ const NODE_JAVASCRIPT_ASSETS_EVIDENCE = evidence(
41
+ 'packages/assets/test/javascript-runtime.test.ts',
42
+ 'pulse.assets-javascript-realization.v1',
43
+ 4
44
+ );
45
+ const NODE_JAVASCRIPT_PACKAGE_PARITY_EVIDENCE = evidence(
46
+ 'wasm/test/contracts/assert-package-reachability.cjs',
47
+ 'pulse.package-capability-parity.v1',
48
+ 1
49
+ );
50
+ const NODE_JAVASCRIPT_SCHEMA_CODEC_EVIDENCE = evidence(
51
+ 'wasm/test/contracts/assert-schema-codecs.cjs',
52
+ 'pulse.schema-codecs.v1',
53
+ 4
54
+ );
55
+ const NODE_JAVASCRIPT_CROSS_TARGET_CONFORMANCE_EVIDENCE = evidence(
56
+ 'wasm/test/contracts/assert-node-cross-target-conformance.cjs',
57
+ 'pulse.node-cross-target-conformance.v1',
58
+ 37
59
+ );
60
+ const NODE_JAVASCRIPT_GRIP_EVIDENCE = evidence(
61
+ 'wasm/test/contracts/assert-grip-cross-target-conformance.cjs',
62
+ 'pulse.grip-cross-target-conformance.v1',
63
+ 35
64
+ );
65
+
66
+ function gate(id, reasonId, owner, summary, evidenceReference) {
67
+ return Object.freeze({
68
+ id,
69
+ status: 'satisfied',
70
+ reasonId,
71
+ owner,
72
+ summary,
73
+ evidence: evidenceReference || null
74
+ });
75
+ }
76
+
77
+ const GATES = Object.freeze([
78
+ gate(
79
+ 'core-router-context',
80
+ 'node-router-context-parity',
81
+ 'provider-node',
82
+ 'The graph-backed loader, Node request/response lifecycle, project test/dev lane, and Router/context wire behavior agree across Native and JavaScript.',
83
+ NODE_JAVASCRIPT_PARITY_EVIDENCE
84
+ ),
85
+ gate(
86
+ 'shared-effect-adapter',
87
+ 'javascript-effect-adapter',
88
+ 'runtime',
89
+ 'One request-owned JavaScript effect adapter implements explicit keyed parallel execution without changing implicit Native grouping.',
90
+ NODE_JAVASCRIPT_EFFECT_ADAPTER_EVIDENCE
91
+ ),
92
+ gate(
93
+ 'fetch-projections-request-bodies',
94
+ 'fetch-projections-request-bodies',
95
+ 'runtime',
96
+ 'Fetch normalization, bounded body projections, timeout propagation, and direct response pass-through are implemented.',
97
+ NODE_JAVASCRIPT_FETCH_BODY_EVIDENCE
98
+ ),
99
+ gate(
100
+ 'bindings-redaction',
101
+ 'config-secrets-kv-redaction',
102
+ 'provider-node',
103
+ 'Config, secret, and KV effects share provider-neutral value contracts with request-owned redaction.',
104
+ NODE_JAVASCRIPT_BINDINGS_REDACTION_EVIDENCE
105
+ ),
106
+ gate(
107
+ 'assets-package',
108
+ 'assets-javascript-realization',
109
+ 'assets',
110
+ 'Assets has a request-bound JavaScript realization and provider-owned response handling.',
111
+ NODE_JAVASCRIPT_ASSETS_EVIDENCE
112
+ ),
113
+ gate(
114
+ 'package-capability-parity',
115
+ 'package-capability-parity',
116
+ 'compiler',
117
+ 'Canonical package roots, package effects, and provider requirements agree across supported targets.',
118
+ NODE_JAVASCRIPT_PACKAGE_PARITY_EVIDENCE
119
+ ),
120
+ gate(
121
+ 'build-source-packaging',
122
+ 'node-javascript-source-packaging',
123
+ 'provider-node',
124
+ 'Node JavaScript builds emit deterministic executable source packages with explicit dependencies and no Native fallback.',
125
+ NODE_JAVASCRIPT_PACKAGE_PARITY_EVIDENCE
126
+ ),
127
+ gate(
128
+ 'normalized-semantic-trace',
129
+ 'normalized-semantic-trace',
130
+ 'schema-json',
131
+ 'All schema JSON boundaries emit a normalized redaction-safe semantic trace.',
132
+ NODE_JAVASCRIPT_SCHEMA_CODEC_EVIDENCE
133
+ ),
134
+ gate(
135
+ 'schema-validation-policy',
136
+ 'schema-validation-policy',
137
+ 'schema-json',
138
+ 'The pulse.schema registry drives strict policy and generated JavaScript and Native codecs.',
139
+ NODE_JAVASCRIPT_SCHEMA_CODEC_EVIDENCE
140
+ ),
141
+ gate(
142
+ 'cross-target-conformance',
143
+ 'node-cross-target-conformance',
144
+ 'provider-node',
145
+ 'A shared corpus and drift comparator enforce JavaScript and Native semantic parity.',
146
+ NODE_JAVASCRIPT_CROSS_TARGET_CONFORMANCE_EVIDENCE
147
+ ),
148
+ gate(
149
+ 'grip-readiness',
150
+ 'grip-cross-target-conformance',
151
+ 'grip',
152
+ 'Stateless GRIP framing and provider broadcast agree across JavaScript, Native Node, and Fastly.',
153
+ NODE_JAVASCRIPT_GRIP_EVIDENCE
154
+ ),
155
+ gate(
156
+ 'target-integrity',
157
+ 'javascript-target-integrity',
158
+ 'provider-node',
159
+ 'JavaScript packaging and conformance preserve explicit target identity without Native artifacts or automatic fallback.',
160
+ NODE_JAVASCRIPT_CROSS_TARGET_CONFORMANCE_EVIDENCE
161
+ )
162
+ ]);
163
+
164
+ const COMMANDS = Object.freeze([
165
+ ['build', 'provider-node'],
166
+ ['compile', 'compiler'],
167
+ ['dev', 'provider-node'],
168
+ ['doctor', 'cli'],
169
+ ['inspect', 'cli'],
170
+ ['test', 'provider-node']
171
+ ].map(([id, owner]) => Object.freeze({
172
+ id,
173
+ implemented: true,
174
+ status: 'eligible',
175
+ reasonId: `${id}-implemented`,
176
+ owner
177
+ })));
178
+
179
+ const NODE_JAVASCRIPT_TARGET_SUPPORT_DECLARATION = normalizeTargetSupportDeclaration({
180
+ provider: 'node',
181
+ target: 'javascript',
182
+ targetId: NODE_JAVASCRIPT_TARGET_DESCRIPTOR.targetId,
183
+ runtimeClass: NODE_JAVASCRIPT_TARGET_DESCRIPTOR.runtimeClass,
184
+ definition: 'full-target-support',
185
+ coreExecutionReady: true,
186
+ fullTargetSupportReady: true,
187
+ generalAvailable: true,
188
+ automaticFallback: false,
189
+ parity: NODE_JAVASCRIPT_PARITY_EVIDENCE,
190
+ commands: COMMANDS,
191
+ gates: GATES
192
+ });
193
+
194
+ module.exports = Object.freeze({
195
+ NODE_JAVASCRIPT_PARITY_EVIDENCE,
196
+ NODE_JAVASCRIPT_EFFECT_ADAPTER_EVIDENCE,
197
+ NODE_JAVASCRIPT_FETCH_BODY_EVIDENCE,
198
+ NODE_JAVASCRIPT_BINDINGS_REDACTION_EVIDENCE,
199
+ NODE_JAVASCRIPT_ASSETS_EVIDENCE,
200
+ NODE_JAVASCRIPT_PACKAGE_PARITY_EVIDENCE,
201
+ NODE_JAVASCRIPT_SCHEMA_CODEC_EVIDENCE,
202
+ NODE_JAVASCRIPT_CROSS_TARGET_CONFORMANCE_EVIDENCE,
203
+ NODE_JAVASCRIPT_GRIP_EVIDENCE,
204
+ NODE_JAVASCRIPT_TARGET_SUPPORT_DECLARATION
205
+ });