@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,134 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ isJavascriptCoreCapability
5
+ } = require('@pulse-compute/wasm-contracts/project/javascript-core-capabilities');
6
+
7
+ function decision(id, status, reasonId, owner, required = true) {
8
+ return Object.freeze({ id, status, required, reasonId, owner });
9
+ }
10
+
11
+ function classifyNodeJavascriptCapability(id, options = {}) {
12
+ const capability = String(id);
13
+ if (isJavascriptCoreCapability(capability)) {
14
+ return decision(capability, 'eligible', 'node-router-context-parity', 'provider-node');
15
+ }
16
+ if (capability === 'logging' || capability === 'log' || capability.startsWith('log.')) {
17
+ return decision(capability, 'eligible', 'javascript-logging-runtime', 'runtime');
18
+ }
19
+ if (capability === 'request.json' || capability === 'req.json' || capability.startsWith('request.body') || capability.startsWith('req.body')) {
20
+ return decision(capability, 'eligible', 'javascript-request-body-realization', 'runtime');
21
+ }
22
+ if (
23
+ capability === 'fetch'
24
+ || capability.startsWith('fetch.')
25
+ || capability === 'backend-fetch'
26
+ || capability === 'body'
27
+ || capability === 'headers'
28
+ || capability === 'json'
29
+ || capability === 'opaque.pass-through'
30
+ || capability === 'result'
31
+ || capability.startsWith('result.')
32
+ ) {
33
+ return decision(capability, 'eligible', 'javascript-fetch-projection-realization', 'runtime');
34
+ }
35
+ if (capability === 'clock' || capability === 'timer') {
36
+ return decision(capability, 'pending', 'javascript-clock-timer-realization-pending', 'runtime');
37
+ }
38
+ if (capability === 'time.wall-clock') {
39
+ return decision(capability, 'eligible', 'node-provider-wall-clock-authority', 'provider-node');
40
+ }
41
+ if (
42
+ capability === 'jwt.verify'
43
+ || capability === 'jwt.verify.hs256'
44
+ || capability === 'jwt.verify.es256'
45
+ ) {
46
+ return decision(capability, 'eligible', 'node-javascript-jwt-crypto-runtime-builtin', 'provider-node');
47
+ }
48
+ if (capability.startsWith('jwt.verify.')) {
49
+ return decision(capability, 'blocked', 'jwt-crypto-realization-unavailable', 'crypto');
50
+ }
51
+ if (capability === 'config.get' || capability === 'secret.get' || capability === 'kv' || capability.startsWith('kv.')) {
52
+ return options.bindingsRedaction === true
53
+ ? decision(capability, 'eligible', 'javascript-binding-redaction-implemented', 'provider-node')
54
+ : decision(capability, 'pending', 'javascript-binding-effect-pending', 'provider-node');
55
+ }
56
+ if (capability === 'assets' || capability.startsWith('assets.')) {
57
+ return decision(capability, 'eligible', 'assets-javascript-realization', 'assets');
58
+ }
59
+ if (capability.startsWith('schema.')) {
60
+ return decision(capability, 'eligible', 'javascript-schema-validation-policy', 'schema-json');
61
+ }
62
+ if (capability === 'event.ingress') {
63
+ return decision(capability, 'eligible', 'node-event-reference-ingress', 'provider-node');
64
+ }
65
+ if (capability === 'event.emit') {
66
+ return decision(capability, 'eligible', 'node-event-reference-acceptance', 'provider-node');
67
+ }
68
+ if (capability === 'broadcaster' || capability === 'channel' || capability === 'grip' || capability.startsWith('grip.')) {
69
+ return options.gripRealized === true
70
+ ? decision(capability, 'eligible', 'grip-realization-implemented', 'grip')
71
+ : decision(capability, 'pending', 'grip-javascript-readiness-pending', 'grip');
72
+ }
73
+ return decision(capability, 'blocked', 'unknown-javascript-capability-fail-closed', 'compiler');
74
+ }
75
+
76
+ function classifyNodeJavascriptProviderRequirement(id, compilerCapabilities, options = {}) {
77
+ const requirement = String(id);
78
+ if (requirement === 'request') {
79
+ const bodyRequired = compilerCapabilities.some((entry) => entry === 'request.json' || entry.startsWith('request.body'));
80
+ return bodyRequired
81
+ ? decision(requirement, 'eligible', 'javascript-request-body-realization', 'runtime')
82
+ : decision(requirement, 'eligible', 'node-request-adapter-and-body-text', 'provider-node');
83
+ }
84
+ if (['response.json', 'response.text', 'response.custom'].includes(requirement)) {
85
+ return decision(requirement, 'eligible', 'node-response-ownership', 'provider-node');
86
+ }
87
+ if (requirement === 'fetch' || requirement === 'opaque.pass-through' || ['body', 'headers', 'result'].includes(requirement)) {
88
+ return decision(requirement, 'eligible', 'javascript-fetch-projection-realization', 'runtime');
89
+ }
90
+ if (['config.get', 'secret.get', 'kv.get', 'kv.put'].includes(requirement)) {
91
+ return options.bindingsRedaction === true
92
+ ? decision(requirement, 'eligible', 'javascript-binding-redaction-implemented', 'provider-node')
93
+ : decision(requirement, 'pending', 'javascript-binding-effect-pending', 'provider-node');
94
+ }
95
+ if (requirement === 'assets' || requirement.startsWith('assets.')) {
96
+ return decision(requirement, 'eligible', 'assets-javascript-realization', 'assets');
97
+ }
98
+ if (requirement === 'clock') {
99
+ return decision(requirement, 'pending', 'javascript-clock-timer-realization-pending', 'runtime');
100
+ }
101
+ if (requirement === 'time.wall-clock') {
102
+ return decision(requirement, 'eligible', 'node-provider-wall-clock-authority', 'provider-node');
103
+ }
104
+ if (
105
+ requirement === 'jwt.verify'
106
+ || requirement === 'jwt.verify.hs256'
107
+ || requirement === 'jwt.verify.es256'
108
+ ) {
109
+ return decision(requirement, 'eligible', 'node-javascript-jwt-crypto-runtime-builtin', 'provider-node');
110
+ }
111
+ if (requirement.startsWith('jwt.verify.')) {
112
+ return decision(requirement, 'blocked', 'jwt-crypto-realization-unavailable', 'crypto');
113
+ }
114
+ if (requirement.startsWith('schema.')) {
115
+ return decision(requirement, 'eligible', 'javascript-schema-validation-policy', 'schema-json');
116
+ }
117
+ if (requirement === 'event.ingress') {
118
+ return decision(requirement, 'eligible', 'node-event-reference-ingress', 'provider-node');
119
+ }
120
+ if (requirement === 'event.emit') {
121
+ return decision(requirement, 'eligible', 'node-event-reference-acceptance', 'provider-node');
122
+ }
123
+ if (['broadcaster', 'channel'].includes(requirement) || requirement === 'grip' || requirement.startsWith('grip.')) {
124
+ return options.gripRealized === true
125
+ ? decision(requirement, 'eligible', 'grip-realization-implemented', 'grip')
126
+ : decision(requirement, 'pending', 'grip-javascript-readiness-pending', 'grip');
127
+ }
128
+ return decision(requirement, 'blocked', 'unknown-provider-requirement-fail-closed', 'compiler');
129
+ }
130
+
131
+ module.exports = Object.freeze({
132
+ classifyNodeJavascriptCapability,
133
+ classifyNodeJavascriptProviderRequirement
134
+ });
@@ -0,0 +1,37 @@
1
+ 'use strict';
2
+
3
+ const { normalizeJavascriptTargetDescriptor } = require('@pulse-compute/wasm-contracts/project/javascript-application');
4
+ const { defineCryptoTargetCapabilities } = require('@pulse-compute/wasm-contracts/crypto/contracts');
5
+
6
+ const NODE_JAVASCRIPT_TARGET_DESCRIPTOR = normalizeJavascriptTargetDescriptor({
7
+ provider: 'node', targetId: 'node-javascript', status: 'source-packaging-ready',
8
+ hostBridge: true, applicationLoader: true, requestAdapter: true, lifecycle: true,
9
+ capabilities: {
10
+ version: 'pulse.javascript-capability-envelope.v1',
11
+ provider: 'node',
12
+ status: 'request-and-event-lifecycle-ready',
13
+ core: { request: true, response: true, state: true, eventIngress: true },
14
+ effects: { fetch: true, config: true, secret: true, kv: true, eventEmit: true },
15
+ events: { ingress: true, emit: true, automaticLoopback: false },
16
+ packages: []
17
+ },
18
+ crypto: defineCryptoTargetCapabilities({
19
+ target: 'javascript',
20
+ algorithms: [{
21
+ algorithm: 'HS256',
22
+ realization: 'runtime-builtin',
23
+ implemented: true,
24
+ status: 'implemented-c2'
25
+ }, {
26
+ algorithm: 'ES256',
27
+ realization: 'runtime-builtin',
28
+ implemented: true,
29
+ status: 'implemented-g3'
30
+ }]
31
+ }),
32
+ commands: { compile: true, inspect: true, doctor: true, build: true, test: true, dev: true }
33
+ });
34
+
35
+ module.exports = Object.freeze({
36
+ NODE_JAVASCRIPT_TARGET_DESCRIPTOR
37
+ });
@@ -0,0 +1,111 @@
1
+ 'use strict';
2
+
3
+ const runtimeHost = require('@pulse-compute/runtime/host');
4
+ const { executeNodeJavascriptApplication } = require('./runtime-host.js');
5
+ const { createNodeJavascriptFixtureFetch } = require('./fetch-adapter.js');
6
+
7
+ const NODE_JAVASCRIPT_TEST_RUNTIME_VERSION = 'pulse.node-javascript-test-runtime.v1';
8
+
9
+ function createTestRequest(input = {}) {
10
+ const method = String(input.method || 'GET').toUpperCase();
11
+ const headerPairs = Object.freeze((input.headers || []).map(([name, value]) => Object.freeze([String(name), String(value)])));
12
+ const headers = new Headers();
13
+ for (const [name, value] of headerPairs) headers.append(name, value);
14
+ const init = { method, headers };
15
+ if (method !== 'GET' && method !== 'HEAD' && input.body !== undefined) {
16
+ init.body = typeof input.body === 'string' || Buffer.isBuffer(input.body) || input.body instanceof Uint8Array
17
+ ? input.body
18
+ : JSON.stringify(input.body);
19
+ }
20
+ return Object.freeze({
21
+ request: new Request(input.url || `http://127.0.0.1${String(input.path || '/')}`, init),
22
+ headerPairs
23
+ });
24
+ }
25
+
26
+ function responseKind(response) {
27
+ const contentType = String(response.headers.get('content-type') || '').toLowerCase();
28
+ if (contentType.includes('application/json') || contentType.includes('+json')) return 'json';
29
+ if (contentType.startsWith('text/')) return 'text';
30
+ return 'response';
31
+ }
32
+
33
+ async function executeNodeJavascriptTestCase(application, testCase, options = {}) {
34
+ const adapted = createTestRequest(testCase.request);
35
+ let effectSummary;
36
+ const fixtureFetch = options.fetchImplementation || createNodeJavascriptFixtureFetch(
37
+ testCase.fetches || {},
38
+ options.networkFetch === true ? globalThis.fetch : undefined
39
+ );
40
+ const gripFixtureFetch = options.gripFetchImplementation || createNodeJavascriptFixtureFetch(
41
+ testCase.fetches || {},
42
+ options.networkFetch === true ? globalThis.fetch : undefined,
43
+ { rawResponse: true }
44
+ );
45
+ const response = await executeNodeJavascriptApplication(application, adapted.request, {
46
+ capabilities: options.capabilities,
47
+ effectAdapter: options.effectAdapter,
48
+ fetchImplementation: fixtureFetch,
49
+ gripFetchImplementation: gripFixtureFetch,
50
+ grip: testCase.grip || options.grip,
51
+ gripBroadcast: options.gripBroadcast,
52
+ jwtCaptureWallClock: options.jwtCaptureWallClock,
53
+ config: testCase.config || {},
54
+ secrets: testCase.secrets || {},
55
+ kv: testCase.kv || {},
56
+ application: options.application,
57
+ requestHeaders: adapted.headerPairs,
58
+ maxEffects: options.maxEffects,
59
+ maxRequestBodyBytes: options.maxRequestBodyBytes ?? options.maxBodyBytes ?? testCase.maxBodyBytes,
60
+ maxFetchBodyBytes: options.maxFetchBodyBytes ?? testCase.maxBodyBytes,
61
+ maxStructuredBodyBytes: options.maxStructuredBodyBytes,
62
+ maxBindingNameBytes: options.maxBindingNameBytes,
63
+ maxBindingValueBytes: options.maxBindingValueBytes,
64
+ maxKvNamespaceBytes: options.maxKvNamespaceBytes,
65
+ maxKvKeyBytes: options.maxKvKeyBytes,
66
+ maxKvValueBytes: options.maxKvValueBytes,
67
+ maxKvValueDepth: options.maxKvValueDepth,
68
+ maxKvValueEntries: options.maxKvValueEntries,
69
+ schemaCodecs: options.schemaCodecs,
70
+ strict: options.strict === true,
71
+ provider: options.provider || 'node',
72
+ reporting: options.reporting,
73
+ log: options.log,
74
+ onLogObservation: options.onLogObservation,
75
+ onJsonTrace: options.onJsonTrace,
76
+ onEffectObservation: options.onEffectObservation,
77
+ onEffectSummary(summary) {
78
+ effectSummary = summary;
79
+ if (typeof options.onEffectSummary === 'function') options.onEffectSummary(summary);
80
+ }
81
+ });
82
+ const method = String(testCase.request && testCase.request.method || 'GET').toUpperCase();
83
+ const body = method === 'HEAD' ? '' : Buffer.from(await response.arrayBuffer()).toString('utf8');
84
+ return Object.freeze({
85
+ version: NODE_JAVASCRIPT_TEST_RUNTIME_VERSION,
86
+ response: Object.freeze({
87
+ status: response.status,
88
+ kind: responseKind(response),
89
+ bodyClass: runtimeHost.responseBodyClass(response),
90
+ headers: runtimeHost.responseHeaderPairs(response),
91
+ body
92
+ }),
93
+ effectCount: effectSummary ? effectSummary.ownedEffectCount : 0,
94
+ externalEffectCount: effectSummary ? effectSummary.effectCount : 0,
95
+ localEffectCount: effectSummary ? effectSummary.localEffectCount : 0,
96
+ continuations: Object.freeze((effectSummary && effectSummary.groups || []).map((group) => Object.freeze({
97
+ id: group.id,
98
+ kind: 'parallel',
99
+ effectIds: group.effectIds,
100
+ keys: group.keys
101
+ }))),
102
+ resolutionOrder: effectSummary ? effectSummary.resolutionOrder : Object.freeze([])
103
+ });
104
+ }
105
+
106
+ module.exports = Object.freeze({
107
+ NODE_JAVASCRIPT_TEST_RUNTIME_VERSION,
108
+ createTestRequest,
109
+ executeNodeJavascriptTestCase,
110
+ responseKind
111
+ });
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+ const { defineFinalWasmPolicy, FINAL_WASM_POLICY_VERSION } = require('@pulse-compute/wasm-contracts/provider/final-wasm-policy');
3
+ const { defineCryptoTargetCapabilities } = require('@pulse-compute/wasm-contracts/crypto/contracts');
4
+ const nativeRuntime = require('@pulse-compute/wasm-contracts/handler/canonical-native-runtime');
5
+ const packageManifest = require('../../package.json');
6
+ const { NODE_NATIVE_TARGET_CAPABILITIES } = require('../capabilities.js');
7
+
8
+ const nodeFinalWasmPolicy = defineFinalWasmPolicy({
9
+ version: FINAL_WASM_POLICY_VERSION,
10
+ descriptorOwner: packageManifest.name,
11
+ toolchainVersion: 'pulse.provider-toolchain.v1',
12
+ descriptorIdentity: 'node-native-host',
13
+ permittedImports: [
14
+ ...nativeRuntime.CANONICAL_NATIVE_IMPORT_NAMES.map((name) => ({ module: 'pulse_host', name, kind: 'function' })),
15
+ ...nativeRuntime.CANONICAL_NATIVE_ALLOWED_ENV_IMPORTS.map((name) => ({ module: 'env', name, kind: 'function' }))
16
+ ],
17
+ requiredExports: nativeRuntime.CANONICAL_NATIVE_EXPORTS.map(([name, second]) => ({
18
+ name,
19
+ kind: second === 'memory' ? 'memory' : 'function'
20
+ }))
21
+ });
22
+
23
+ const NODE_NATIVE_TARGET_DESCRIPTOR = Object.freeze({
24
+ version: 'pulse.provider-target-descriptor.v1',
25
+ id: 'node-native-host',
26
+ provider: 'node',
27
+ mode: 'native',
28
+ runtimeClass: 'native',
29
+ status: 'supported',
30
+ capabilities: NODE_NATIVE_TARGET_CAPABILITIES,
31
+ keyTypes: Object.freeze(['secret', 'jwk', 'jwks']),
32
+ realizations: Object.freeze([
33
+ Object.freeze({
34
+ kind: 'crypto-composed',
35
+ realization: 'guest-source:pulse-hmac-as',
36
+ implementation: 'pulse-hmac-as.v1',
37
+ algorithms: Object.freeze(['HS256']),
38
+ keyTypes: Object.freeze(['secret']),
39
+ implemented: true,
40
+ status: 'implemented-d3',
41
+ semanticOwner: '@pulse-compute/crypto',
42
+ guestUnitRequired: false,
43
+ portable: true,
44
+ automaticFallback: false
45
+ }),
46
+ Object.freeze({
47
+ kind: 'crypto-composed',
48
+ realization: 'guest-linked:pulse-es256-rustcrypto-p256',
49
+ implementation: 'rustcrypto.p256-0.13.2.ecdsa-0.16.9.sha2-0.10.9.v1',
50
+ algorithms: Object.freeze(['ES256']),
51
+ keyTypes: Object.freeze(['jwk', 'jwks']),
52
+ implemented: true,
53
+ status: 'implemented-g3',
54
+ semanticOwner: '@pulse-compute/crypto',
55
+ guestUnitRequired: true,
56
+ portable: true,
57
+ automaticFallback: false
58
+ })
59
+ ]),
60
+ automaticFallback: false,
61
+ crypto: defineCryptoTargetCapabilities({
62
+ target: 'native',
63
+ algorithms: [{
64
+ algorithm: 'HS256',
65
+ realization: 'guest-source:pulse-hmac-as',
66
+ implemented: true,
67
+ status: 'implemented-c3'
68
+ }, {
69
+ algorithm: 'ES256',
70
+ realization: 'guest-linked:pulse-es256-rustcrypto-p256',
71
+ implemented: true,
72
+ status: 'implemented-g3'
73
+ }]
74
+ }),
75
+ finalWasmPolicy: nodeFinalWasmPolicy
76
+ });
77
+
78
+ module.exports = Object.freeze({ NODE_NATIVE_TARGET_DESCRIPTOR });