@pulse-compute/provider-node 0.0.0 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +61 -1
  2. package/package.json +62 -6
  3. package/src/capabilities.js +65 -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/config/s3.js +20 -0
  16. package/src/events/reference-adapter.js +145 -0
  17. package/src/index.js +57 -0
  18. package/src/javascript/assets-adapter.js +68 -0
  19. package/src/javascript/bindings-adapter.js +90 -0
  20. package/src/javascript/fetch-adapter.js +187 -0
  21. package/src/javascript/grip-broadcast.js +243 -0
  22. package/src/javascript/jwt-verifier.js +137 -0
  23. package/src/javascript/lifecycle.js +69 -0
  24. package/src/javascript/node-adapter.js +284 -0
  25. package/src/javascript/package-effects.js +84 -0
  26. package/src/javascript/runtime-host.js +170 -0
  27. package/src/javascript/s3.js +21 -0
  28. package/src/javascript/source-package.js +439 -0
  29. package/src/javascript/support.js +205 -0
  30. package/src/javascript/target-support-policy.js +136 -0
  31. package/src/javascript/target.js +37 -0
  32. package/src/javascript/test-runtime.js +112 -0
  33. package/src/native/target.js +78 -0
  34. package/src/runtime/assets-provider.js +776 -0
  35. package/src/runtime/canonical-api-runtime.js +604 -0
  36. package/src/runtime/compiled-wasm-node-adapter-kv.js +15 -0
  37. package/src/runtime/conditional-kv.js +93 -0
  38. package/src/runtime/index.js +18 -0
  39. package/src/runtime/jwt-verifier.js +264 -0
  40. package/src/runtime/route-handler-effects.js +757 -0
  41. package/src/runtime/s3-reader.js +131 -0
  42. package/src/toolchain.js +269 -0
@@ -0,0 +1,136 @@
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 (['s3.head', 's3.getText', 's3.putText'].includes(capability)) return decision(capability, 'eligible', 'node-s3-bounded-origin-transport', 'provider-node');
14
+ if (isJavascriptCoreCapability(capability)) {
15
+ return decision(capability, 'eligible', 'node-router-context-parity', 'provider-node');
16
+ }
17
+ if (capability === 'logging' || capability === 'log' || capability.startsWith('log.')) {
18
+ return decision(capability, 'eligible', 'javascript-logging-runtime', 'runtime');
19
+ }
20
+ if (capability === 'request.json' || capability === 'req.json' || capability.startsWith('request.body') || capability.startsWith('req.body')) {
21
+ return decision(capability, 'eligible', 'javascript-request-body-realization', 'runtime');
22
+ }
23
+ if (
24
+ capability === 'fetch'
25
+ || capability.startsWith('fetch.')
26
+ || capability === 'backend-fetch'
27
+ || capability === 'body'
28
+ || capability === 'headers'
29
+ || capability === 'json'
30
+ || capability === 'opaque.pass-through'
31
+ || capability === 'result'
32
+ || capability.startsWith('result.')
33
+ ) {
34
+ return decision(capability, 'eligible', 'javascript-fetch-projection-realization', 'runtime');
35
+ }
36
+ if (capability === 'clock' || capability === 'timer') {
37
+ return decision(capability, 'pending', 'javascript-clock-timer-realization-pending', 'runtime');
38
+ }
39
+ if (capability === 'time.wall-clock') {
40
+ return decision(capability, 'eligible', 'node-provider-wall-clock-authority', 'provider-node');
41
+ }
42
+ if (
43
+ capability === 'jwt.verify'
44
+ || capability === 'jwt.verify.hs256'
45
+ || capability === 'jwt.verify.es256'
46
+ ) {
47
+ return decision(capability, 'eligible', 'node-javascript-jwt-crypto-runtime-builtin', 'provider-node');
48
+ }
49
+ if (capability.startsWith('jwt.verify.')) {
50
+ return decision(capability, 'blocked', 'jwt-crypto-realization-unavailable', 'crypto');
51
+ }
52
+ if (capability === 'config.get' || capability === 'secret.get' || capability === 'kv' || capability.startsWith('kv.')) {
53
+ return options.bindingsRedaction === true
54
+ ? decision(capability, 'eligible', 'javascript-binding-redaction-implemented', 'provider-node')
55
+ : decision(capability, 'pending', 'javascript-binding-effect-pending', 'provider-node');
56
+ }
57
+ if (capability === 'assets' || capability.startsWith('assets.')) {
58
+ return decision(capability, 'eligible', 'assets-javascript-realization', 'assets');
59
+ }
60
+ if (capability.startsWith('schema.')) {
61
+ return decision(capability, 'eligible', 'javascript-schema-validation-policy', 'schema-json');
62
+ }
63
+ if (capability === 'event.ingress') {
64
+ return decision(capability, 'eligible', 'node-event-reference-ingress', 'provider-node');
65
+ }
66
+ if (capability === 'event.emit') {
67
+ return decision(capability, 'eligible', 'node-event-reference-acceptance', 'provider-node');
68
+ }
69
+ if (capability === 'broadcaster' || capability === 'channel' || capability === 'grip' || capability.startsWith('grip.')) {
70
+ return options.gripRealized === true
71
+ ? decision(capability, 'eligible', 'grip-realization-implemented', 'grip')
72
+ : decision(capability, 'pending', 'grip-javascript-readiness-pending', 'grip');
73
+ }
74
+ return decision(capability, 'blocked', 'unknown-javascript-capability-fail-closed', 'compiler');
75
+ }
76
+
77
+ function classifyNodeJavascriptProviderRequirement(id, compilerCapabilities, options = {}) {
78
+ const requirement = String(id);
79
+ if (['s3.head', 's3.getText', 's3.putText'].includes(requirement)) return decision(requirement, 'eligible', 'node-s3-bounded-origin-transport', 'provider-node');
80
+ if (requirement === 'request') {
81
+ const bodyRequired = compilerCapabilities.some((entry) => entry === 'request.json' || entry.startsWith('request.body'));
82
+ return bodyRequired
83
+ ? decision(requirement, 'eligible', 'javascript-request-body-realization', 'runtime')
84
+ : decision(requirement, 'eligible', 'node-request-adapter-and-body-text', 'provider-node');
85
+ }
86
+ if (['response.json', 'response.text', 'response.custom'].includes(requirement)) {
87
+ return decision(requirement, 'eligible', 'node-response-ownership', 'provider-node');
88
+ }
89
+ if (requirement === 'fetch' || requirement === 'opaque.pass-through' || ['body', 'headers', 'result'].includes(requirement)) {
90
+ return decision(requirement, 'eligible', 'javascript-fetch-projection-realization', 'runtime');
91
+ }
92
+ if (['config.get', 'secret.get', 'kv.get', 'kv.put', 'kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap'].includes(requirement)) {
93
+ return options.bindingsRedaction === true
94
+ ? decision(requirement, 'eligible', 'javascript-binding-redaction-implemented', 'provider-node')
95
+ : decision(requirement, 'pending', 'javascript-binding-effect-pending', 'provider-node');
96
+ }
97
+ if (requirement === 'assets' || requirement.startsWith('assets.')) {
98
+ return decision(requirement, 'eligible', 'assets-javascript-realization', 'assets');
99
+ }
100
+ if (requirement === 'clock') {
101
+ return decision(requirement, 'pending', 'javascript-clock-timer-realization-pending', 'runtime');
102
+ }
103
+ if (requirement === 'time.wall-clock') {
104
+ return decision(requirement, 'eligible', 'node-provider-wall-clock-authority', 'provider-node');
105
+ }
106
+ if (
107
+ requirement === 'jwt.verify'
108
+ || requirement === 'jwt.verify.hs256'
109
+ || requirement === 'jwt.verify.es256'
110
+ ) {
111
+ return decision(requirement, 'eligible', 'node-javascript-jwt-crypto-runtime-builtin', 'provider-node');
112
+ }
113
+ if (requirement.startsWith('jwt.verify.')) {
114
+ return decision(requirement, 'blocked', 'jwt-crypto-realization-unavailable', 'crypto');
115
+ }
116
+ if (requirement.startsWith('schema.')) {
117
+ return decision(requirement, 'eligible', 'javascript-schema-validation-policy', 'schema-json');
118
+ }
119
+ if (requirement === 'event.ingress') {
120
+ return decision(requirement, 'eligible', 'node-event-reference-ingress', 'provider-node');
121
+ }
122
+ if (requirement === 'event.emit') {
123
+ return decision(requirement, 'eligible', 'node-event-reference-acceptance', 'provider-node');
124
+ }
125
+ if (['broadcaster', 'channel'].includes(requirement) || requirement === 'grip' || requirement.startsWith('grip.')) {
126
+ return options.gripRealized === true
127
+ ? decision(requirement, 'eligible', 'grip-realization-implemented', 'grip')
128
+ : decision(requirement, 'pending', 'grip-javascript-readiness-pending', 'grip');
129
+ }
130
+ return decision(requirement, 'blocked', 'unknown-provider-requirement-fail-closed', 'compiler');
131
+ }
132
+
133
+ module.exports = Object.freeze({
134
+ classifyNodeJavascriptCapability,
135
+ classifyNodeJavascriptProviderRequirement
136
+ });
@@ -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: [...['SHA-256', 'HMAC-SHA256'].map((algorithm) => ({ algorithm, realization: 'runtime-builtin', implemented: true, status: 'implemented-o3' })), {
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,112 @@
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
+ s3: options.s3 || options.bindings && options.bindings.s3,
56
+ kv: testCase.kv || {},
57
+ application: options.application,
58
+ requestHeaders: adapted.headerPairs,
59
+ maxEffects: options.maxEffects,
60
+ maxRequestBodyBytes: options.maxRequestBodyBytes ?? options.maxBodyBytes ?? testCase.maxBodyBytes,
61
+ maxFetchBodyBytes: options.maxFetchBodyBytes ?? testCase.maxBodyBytes,
62
+ maxStructuredBodyBytes: options.maxStructuredBodyBytes,
63
+ maxBindingNameBytes: options.maxBindingNameBytes,
64
+ maxBindingValueBytes: options.maxBindingValueBytes,
65
+ maxKvNamespaceBytes: options.maxKvNamespaceBytes,
66
+ maxKvKeyBytes: options.maxKvKeyBytes,
67
+ maxKvValueBytes: options.maxKvValueBytes,
68
+ maxKvValueDepth: options.maxKvValueDepth,
69
+ maxKvValueEntries: options.maxKvValueEntries,
70
+ schemaCodecs: options.schemaCodecs,
71
+ strict: options.strict === true,
72
+ provider: options.provider || 'node',
73
+ reporting: options.reporting,
74
+ log: options.log,
75
+ onLogObservation: options.onLogObservation,
76
+ onJsonTrace: options.onJsonTrace,
77
+ onEffectObservation: options.onEffectObservation,
78
+ onEffectSummary(summary) {
79
+ effectSummary = summary;
80
+ if (typeof options.onEffectSummary === 'function') options.onEffectSummary(summary);
81
+ }
82
+ });
83
+ const method = String(testCase.request && testCase.request.method || 'GET').toUpperCase();
84
+ const body = method === 'HEAD' ? '' : Buffer.from(await response.arrayBuffer()).toString('utf8');
85
+ return Object.freeze({
86
+ version: NODE_JAVASCRIPT_TEST_RUNTIME_VERSION,
87
+ response: Object.freeze({
88
+ status: response.status,
89
+ kind: responseKind(response),
90
+ bodyClass: runtimeHost.responseBodyClass(response),
91
+ headers: runtimeHost.responseHeaderPairs(response),
92
+ body
93
+ }),
94
+ effectCount: effectSummary ? effectSummary.ownedEffectCount : 0,
95
+ externalEffectCount: effectSummary ? effectSummary.effectCount : 0,
96
+ localEffectCount: effectSummary ? effectSummary.localEffectCount : 0,
97
+ continuations: Object.freeze((effectSummary && effectSummary.groups || []).map((group) => Object.freeze({
98
+ id: group.id,
99
+ kind: 'parallel',
100
+ effectIds: group.effectIds,
101
+ keys: group.keys
102
+ }))),
103
+ resolutionOrder: effectSummary ? effectSummary.resolutionOrder : Object.freeze([])
104
+ });
105
+ }
106
+
107
+ module.exports = Object.freeze({
108
+ NODE_JAVASCRIPT_TEST_RUNTIME_VERSION,
109
+ createTestRequest,
110
+ executeNodeJavascriptTestCase,
111
+ responseKind
112
+ });
@@ -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: [...['SHA-256', 'HMAC-SHA256'].map((algorithm) => ({ algorithm, realization: 'guest-source:pulse-hmac-as', implemented: true, status: 'implemented-o2' })), {
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 });