@pulse-compute/wasm-contracts 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 (97) hide show
  1. package/README.md +35 -2
  2. package/package.json +124 -6
  3. package/src/assets/contracts.js +296 -0
  4. package/src/config/provider-resolution.js +54 -0
  5. package/src/config/runtime-provider-kv.js +73 -0
  6. package/src/config/symbolic-refs.js +192 -0
  7. package/src/crypto/contracts.js +647 -0
  8. package/src/definitions/config-schema.js +30 -0
  9. package/src/definitions/handler-roles.js +66 -0
  10. package/src/definitions/path-grammar.js +11 -0
  11. package/src/definitions/router-api.js +149 -0
  12. package/src/diagnostics/codes.js +42 -0
  13. package/src/diagnostics/reporter.js +20 -0
  14. package/src/diagnostics.js +139 -0
  15. package/src/dispatch-table.js +23 -0
  16. package/src/entities/catalog.d.ts +7 -0
  17. package/src/entities/catalog.js +87 -0
  18. package/src/entities/contracts.d.ts +95 -0
  19. package/src/entities/contracts.js +122 -0
  20. package/src/entities/json-rpc.d.ts +27 -0
  21. package/src/entities/json-rpc.js +69 -0
  22. package/src/entities/runtime.d.ts +67 -0
  23. package/src/entities/runtime.js +288 -0
  24. package/src/events/contracts.js +456 -0
  25. package/src/execution-plan.js +42 -0
  26. package/src/grip/contracts.js +106 -0
  27. package/src/handler/backend-json-request-body.js +58 -0
  28. package/src/handler/beta-lifecycle-golden.js +97 -0
  29. package/src/handler/canonical-native-plan.js +143 -0
  30. package/src/handler/canonical-native-runtime.js +168 -0
  31. package/src/handler/canonical-runtime.js +13 -0
  32. package/src/handler/context.js +131 -0
  33. package/src/handler/ctx-contract.js +71 -0
  34. package/src/handler/doctor-readiness-aggregator.js +67 -0
  35. package/src/handler/effects.js +446 -0
  36. package/src/handler/io-lifecycle.js +134 -0
  37. package/src/handler/lifecycle-authoring-alignment.js +56 -0
  38. package/src/handler/lifecycle-readiness-aggregate.js +93 -0
  39. package/src/handler/reference-node-lifecycle-golden.js +73 -0
  40. package/src/handler/request-json-body.js +147 -0
  41. package/src/handler/runtime-api.js +471 -0
  42. package/src/handler/schema-decode-result.js +135 -0
  43. package/src/handler/schema-response-codec.js +141 -0
  44. package/src/handler/surface-contract.js +601 -0
  45. package/src/handler/types-contract.js +51 -0
  46. package/src/handler-table.js +28 -0
  47. package/src/host/backend-capabilities.js +24 -0
  48. package/src/host/capabilities.js +273 -0
  49. package/src/host/channel-broadcaster.js +60 -0
  50. package/src/host/json-body.js +80 -0
  51. package/src/host/request-result-headers.js +38 -0
  52. package/src/host/streaming-passthrough.js +90 -0
  53. package/src/host/wasm-host-abi.js +154 -0
  54. package/src/index.js +75 -0
  55. package/src/jwt/contracts.js +427 -0
  56. package/src/library/api-surface.js +99 -0
  57. package/src/library/contracts.js +273 -0
  58. package/src/library/manifest.js +317 -0
  59. package/src/library/second-package-owned-lowering.js +39 -0
  60. package/src/library/sidecars.js +147 -0
  61. package/src/logging.js +89 -0
  62. package/src/package/package-contract.js +975 -0
  63. package/src/package/package-contract.schema.json +303 -0
  64. package/src/package/runtime-pulse-live.js +100 -0
  65. package/src/path-table.js +12 -0
  66. package/src/path.js +275 -0
  67. package/src/project/config-factory.js +48 -0
  68. package/src/project/config-plan.js +409 -0
  69. package/src/project/config-runtime.js +46 -0
  70. package/src/project/javascript-application.js +212 -0
  71. package/src/project/javascript-core-capabilities.js +44 -0
  72. package/src/project/native-optimization.js +9 -0
  73. package/src/project/package-ownership.js +242 -0
  74. package/src/project/package-product-projection.js +171 -0
  75. package/src/project/reachable-graph-identity.js +219 -0
  76. package/src/project/reachable-graph-projections.js +279 -0
  77. package/src/project/reachable-graph-resolver.js +303 -0
  78. package/src/project/reachable-graph-v2.js +430 -0
  79. package/src/project/reachable-graph-v2.schema.json +285 -0
  80. package/src/project/reachable-graph.js +199 -0
  81. package/src/project/reachable-graph.schema.json +222 -0
  82. package/src/project/target-support-evidence.js +559 -0
  83. package/src/provider/canonical-provider.js +239 -0
  84. package/src/provider/final-wasm-policy.js +87 -0
  85. package/src/provider/toolchain.js +771 -0
  86. package/src/route-plan.js +43 -0
  87. package/src/s3/contracts.js +12 -0
  88. package/src/schema-json/compile.js +63 -0
  89. package/src/schema-json/contracts.js +10 -0
  90. package/src/schema-json/generic-parser.js +62 -0
  91. package/src/schema-json/registry.js +359 -0
  92. package/src/schema-json/semantic-trace.js +241 -0
  93. package/src/schema-json/v1.js +65 -0
  94. package/src/schema-json/v2.js +110 -0
  95. package/src/sha256.js +104 -0
  96. package/src/spine.js +381 -0
  97. package/src/stable-id.js +142 -0
@@ -0,0 +1,154 @@
1
+ 'use strict';
2
+
3
+ const ABI_VERSION = 'pulsewasm.wasm-host-abi.v4';
4
+ const ABI_PHASE = '12D';
5
+
6
+ const METHOD_CODES = Object.freeze({
7
+ UNKNOWN: 0,
8
+ GET: 1,
9
+ POST: 2,
10
+ PUT: 3,
11
+ PATCH: 4,
12
+ DELETE: 5,
13
+ OPTIONS: 6,
14
+ HEAD: 7
15
+ });
16
+
17
+ const RESULT_KINDS = Object.freeze({
18
+ RESULT_NONE: 0,
19
+ RESULT_TEXT: 1,
20
+ RESULT_JSON: 2,
21
+ RESULT_BINARY: 3,
22
+ RESULT_EMPTY: 4,
23
+ RESULT_STREAM: 5
24
+ });
25
+
26
+ const NEXT_OUTCOMES = Object.freeze({
27
+ NEXT_NONE: 0,
28
+ NEXT_NORMAL: 1,
29
+ NEXT_ERROR: 2
30
+ });
31
+
32
+ function fn(name, params, returns = 'void', notes = []) {
33
+ return { name, params, returns, notes };
34
+ }
35
+
36
+ function buildWasmHostAbiExportGroups() {
37
+ const memory = [
38
+ fn('memory', [], 'memory', ['Exported linear memory.']),
39
+ fn('pulse_alloc', [{ name: 'byteLength', type: 'i32' }], 'i32', ['Allocates host-visible memory.']),
40
+ fn('pulse_free', [{ name: 'ptr', type: 'i32' }, { name: 'byteLength', type: 'i32' }], 'void', ['Releases memory previously allocated through pulse_alloc when supported.'])
41
+ ];
42
+
43
+ const lifecycle = [
44
+ fn('pulse_init', [], 'void', ['Initializes runtime globals.']),
45
+ fn('pulse_reset', [], 'void', ['Clears transient dispatch/result/error state.'])
46
+ ];
47
+
48
+ const dispatch = [
49
+ fn('pulse_execute_request', [{ name: 'methodCode', type: 'i32' }, { name: 'pathPtr', type: 'i32' }, { name: 'pathLen', type: 'i32' }], 'i32', ['Executes request routing with a UTF-8 full path.']),
50
+ fn('pulse_execute_connect', [{ name: 'methodCode', type: 'i32' }, { name: 'pathPtr', type: 'i32' }, { name: 'pathLen', type: 'i32' }], 'i32', ['Executes explicit connect lifecycle handlers for the matched scope.']),
51
+ fn('pulse_execute_disconnect', [{ name: 'methodCode', type: 'i32' }, { name: 'pathPtr', type: 'i32' }, { name: 'pathLen', type: 'i32' }], 'i32', ['Executes explicit disconnect lifecycle handlers for the matched scope.'])
52
+ ];
53
+
54
+ const result = [
55
+ fn('pulse_result_status', [], 'i32'),
56
+ fn('pulse_result_kind', [], 'i32'),
57
+ fn('pulse_result_body_ref', [], 'i32'),
58
+ fn('pulse_result_body_ptr', [], 'i32'),
59
+ fn('pulse_result_body_len', [], 'i32'),
60
+ fn('pulse_result_headers_ref', [], 'i32'),
61
+ fn('pulse_result_error_ref', [], 'i32'),
62
+ fn('pulse_result_stream_ref', [], 'i32'),
63
+ fn('pulse_result_response_ref', [], 'i32')
64
+ ];
65
+
66
+ const headers = [
67
+ fn('pulse_request_header_first', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }], 'i32', ['Returns first matching request header StringRef, or 0.']),
68
+ fn('pulse_request_header_count', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }], 'i32'),
69
+ fn('pulse_request_header_at', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }, { name: 'index', type: 'i32' }], 'i32', ['Returns matching request header StringRef by repeated-header index, or 0.']),
70
+ fn('pulse_response_header_set', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }, { name: 'valuePtr', type: 'i32' }, { name: 'valueLen', type: 'i32' }], 'void'),
71
+ fn('pulse_response_header_append', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }, { name: 'valuePtr', type: 'i32' }, { name: 'valueLen', type: 'i32' }], 'void'),
72
+ fn('pulse_response_header_delete', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }], 'void'),
73
+ fn('pulse_result_header_count', [], 'i32'),
74
+ fn('pulse_result_header_name_ptr', [{ name: 'index', type: 'i32' }], 'i32'),
75
+ fn('pulse_result_header_name_len', [{ name: 'index', type: 'i32' }], 'i32'),
76
+ fn('pulse_result_header_value_ptr', [{ name: 'index', type: 'i32' }], 'i32'),
77
+ fn('pulse_result_header_value_len', [{ name: 'index', type: 'i32' }], 'i32'),
78
+ fn('pulse_result_header_mode', [{ name: 'index', type: 'i32' }], 'i32', ['1 = set/override, 2 = append.']),
79
+ fn('pulse_result_header_delete_count', [], 'i32'),
80
+ fn('pulse_result_header_delete_name_ptr', [{ name: 'index', type: 'i32' }], 'i32'),
81
+ fn('pulse_result_header_delete_name_len', [{ name: 'index', type: 'i32' }], 'i32')
82
+ ];
83
+
84
+ const jsonBody = [
85
+ fn('pulse_request_body_text', [{ name: 'ctxRef', type: 'i32' }], 'i32', ['Returns request body text StringRef; body access is explicit and lazy.']),
86
+ fn('pulse_request_body_len', [{ name: 'ctxRef', type: 'i32' }], 'i32'),
87
+ fn('pulse_request_json_parse', [{ name: 'ctxRef', type: 'i32' }], 'i32', ['Returns JsonParseResultRef; parsing errors are explicit, not thrown.']),
88
+ fn('pulse_json_result_ok', [{ name: 'resultRef', type: 'i32' }], 'i32'),
89
+ fn('pulse_json_result_value', [{ name: 'resultRef', type: 'i32' }], 'i32'),
90
+ fn('pulse_json_result_error', [{ name: 'resultRef', type: 'i32' }], 'i32'),
91
+ fn('pulse_json_kind', [{ name: 'valueRef', type: 'i32' }], 'i32'),
92
+ fn('pulse_json_object_has', [{ name: 'valueRef', type: 'i32' }, { name: 'keyPtr', type: 'i32' }, { name: 'keyLen', type: 'i32' }], 'i32'),
93
+ fn('pulse_json_object_get', [{ name: 'valueRef', type: 'i32' }, { name: 'keyPtr', type: 'i32' }, { name: 'keyLen', type: 'i32' }], 'i32'),
94
+ fn('pulse_json_array_len', [{ name: 'valueRef', type: 'i32' }], 'i32'),
95
+ fn('pulse_json_array_get', [{ name: 'valueRef', type: 'i32' }, { name: 'index', type: 'i32' }], 'i32'),
96
+ fn('pulse_json_as_string', [{ name: 'valueRef', type: 'i32' }], 'i32'),
97
+ fn('pulse_json_as_f64', [{ name: 'valueRef', type: 'i32' }], 'f64'),
98
+ fn('pulse_json_as_bool', [{ name: 'valueRef', type: 'i32' }], 'i32'),
99
+ fn('pulse_result_json_text', [{ name: 'ctxRef', type: 'i32' }, { name: 'statusCode', type: 'i32' }, { name: 'jsonPtr', type: 'i32' }, { name: 'jsonLen', type: 'i32' }], 'void', ['Sets RESULT_JSON and Content-Type: application/json.'])
100
+ ];
101
+
102
+ const stringRefs = [
103
+ fn('pulse_string_ptr', [{ name: 'stringRef', type: 'i32' }], 'i32'),
104
+ fn('pulse_string_len', [{ name: 'stringRef', type: 'i32' }], 'i32'),
105
+ fn('pulse_string_is_null', [{ name: 'stringRef', type: 'i32' }], 'i32')
106
+ ];
107
+
108
+ const ctxOps = [
109
+ fn('pulse_ctx_param', [{ name: 'ctxRef', type: 'i32' }, { name: 'namePtr', type: 'i32' }, { name: 'nameLen', type: 'i32' }], 'i32', ['Returns a StringRef, or 0 when missing.']),
110
+ fn('pulse_ctx_state_get', [{ name: 'ctxRef', type: 'i32' }, { name: 'keyPtr', type: 'i32' }, { name: 'keyLen', type: 'i32' }], 'i32', ['Returns a StringRef, or 0 when missing.']),
111
+ fn('pulse_ctx_state_set', [{ name: 'ctxRef', type: 'i32' }, { name: 'keyPtr', type: 'i32' }, { name: 'keyLen', type: 'i32' }, { name: 'valuePtr', type: 'i32' }, { name: 'valueLen', type: 'i32' }], 'void'),
112
+ fn('pulse_result_text', [{ name: 'ctxRef', type: 'i32' }, { name: 'statusCode', type: 'i32' }, { name: 'bodyPtr', type: 'i32' }, { name: 'bodyLen', type: 'i32' }], 'void'),
113
+ fn('pulse_result_empty', [{ name: 'ctxRef', type: 'i32' }, { name: 'statusCode', type: 'i32' }], 'void'),
114
+ fn('pulse_result_stream', [{ name: 'ctxRef', type: 'i32' }, { name: 'statusCode', type: 'i32' }, { name: 'streamRef', type: 'i32' }], 'void', ['Sets RESULT_STREAM from an opaque host-owned stream ref.']),
115
+ fn('pulse_result_from_response', [{ name: 'ctxRef', type: 'i32' }, { name: 'responseRef', type: 'i32' }], 'void', ['Sets RESULT_STREAM from an opaque host-owned response ref; host preserves/merges status, headers, and stream.']),
116
+ fn('pulse_next', [{ name: 'ctxRef', type: 'i32' }], 'void'),
117
+ fn('pulse_next_error', [{ name: 'ctxRef', type: 'i32' }, { name: 'errorRef', type: 'i32' }], 'void')
118
+ ];
119
+
120
+ const errors = [
121
+ fn('pulse_error', [{ name: 'codePtr', type: 'i32' }, { name: 'codeLen', type: 'i32' }, { name: 'messagePtr', type: 'i32' }, { name: 'messageLen', type: 'i32' }, { name: 'statusCode', type: 'i32' }], 'i32'),
122
+ fn('pulse_error_with_cause', [{ name: 'codePtr', type: 'i32' }, { name: 'codeLen', type: 'i32' }, { name: 'messagePtr', type: 'i32' }, { name: 'messageLen', type: 'i32' }, { name: 'statusCode', type: 'i32' }, { name: 'causeRef', type: 'i32' }], 'i32'),
123
+ fn('pulse_error_code_ref', [{ name: 'errorRef', type: 'i32' }], 'i32'),
124
+ fn('pulse_error_message_ref', [{ name: 'errorRef', type: 'i32' }], 'i32'),
125
+ fn('pulse_error_status_code', [{ name: 'errorRef', type: 'i32' }], 'i32'),
126
+ fn('pulse_error_cause_ref', [{ name: 'errorRef', type: 'i32' }], 'i32')
127
+ ];
128
+
129
+ const channel = [
130
+ fn('pulse_channel_count', [{ name: 'channelsRef', type: 'i32' }], 'i32'),
131
+ fn('pulse_channel_ref_at', [{ name: 'channelsRef', type: 'i32' }, { name: 'index', type: 'i32' }], 'i32')
132
+ ];
133
+
134
+ return { memory, lifecycle, dispatch, result, headers, jsonBody, stringRefs, ctxOps, errors, channel };
135
+ }
136
+
137
+ function flattenWasmHostAbiExports(groups) {
138
+ return Object.entries(groups).flatMap(([group, functions]) => functions.map((item) => ({ group, ...item })));
139
+ }
140
+
141
+ function listWasmHostAbiExports() {
142
+ return flattenWasmHostAbiExports(buildWasmHostAbiExportGroups());
143
+ }
144
+
145
+ module.exports = {
146
+ ABI_VERSION,
147
+ ABI_PHASE,
148
+ METHOD_CODES,
149
+ RESULT_KINDS,
150
+ NEXT_OUTCOMES,
151
+ buildWasmHostAbiExportGroups,
152
+ flattenWasmHostAbiExports,
153
+ listWasmHostAbiExports
154
+ };
package/src/index.js ADDED
@@ -0,0 +1,75 @@
1
+ 'use strict';
2
+
3
+ module.exports = {
4
+ handlerSchemaDecodeResult: require('./handler/schema-decode-result.js'),
5
+ handlerSchemaResponseCodec: require('./handler/schema-response-codec.js'),
6
+ diagnostics: require('./diagnostics.js'),
7
+ diagnosticCodes: require('./diagnostics/codes.js'),
8
+ diagnosticReporter: require('./diagnostics/reporter.js'),
9
+ stableId: require('./stable-id.js'),
10
+ logging: require('./logging.js'),
11
+ configSchema: require('./definitions/config-schema.js'),
12
+ handlerRoles: require('./definitions/handler-roles.js'),
13
+ routerApi: require('./definitions/router-api.js'),
14
+ path: require('./path.js'),
15
+ pathGrammar: require('./definitions/path-grammar.js'),
16
+ routePlan: require('./route-plan.js'),
17
+ dispatchTable: require('./dispatch-table.js'),
18
+ executionPlan: require('./execution-plan.js'),
19
+ pathTable: require('./path-table.js'),
20
+ handlerTable: require('./handler-table.js'),
21
+ handlerEffects: require('./handler/effects.js'),
22
+ handlerContext: require('./handler/context.js'),
23
+ handlerIoLifecycle: require('./handler/io-lifecycle.js'),
24
+ requestJsonBody: require('./handler/request-json-body.js'),
25
+ schemaDecodeResult: require('./handler/schema-decode-result.js'),
26
+ schemaResponseCodec: require('./handler/schema-response-codec.js'),
27
+ backendJsonRequestBody: require('./handler/backend-json-request-body.js'),
28
+ referenceNodeLifecycleGolden: require('./handler/reference-node-lifecycle-golden.js'),
29
+ betaLifecycleGolden: require('./handler/beta-lifecycle-golden.js'),
30
+ lifecycleAuthoringAlignment: require('./handler/lifecycle-authoring-alignment.js'),
31
+ lifecycleReadinessAggregate: require('./handler/lifecycle-readiness-aggregate.js'),
32
+ doctorReadinessAggregator: require('./handler/doctor-readiness-aggregator.js'),
33
+ runtimeApi: require('./handler/runtime-api.js'),
34
+ canonicalRuntime: require('./handler/canonical-runtime.js'),
35
+ canonicalNativePlan: require('./handler/canonical-native-plan.js'),
36
+ canonicalNativeRuntime: require('./handler/canonical-native-runtime.js'),
37
+ canonicalProvider: require('./provider/canonical-provider.js'),
38
+ assetsContracts: require('./assets/contracts.js'),
39
+ gripContracts: require('./grip/contracts.js'),
40
+ jwtContracts: require('./jwt/contracts.js'),
41
+ entitiesContracts: require('./entities/contracts.js'),
42
+ entitiesRuntime: require('./entities/runtime.js'),
43
+ entitiesJsonRpc: require('./entities/json-rpc.js'),
44
+ entitiesCatalog: require('./entities/catalog.js'),
45
+ hostCapabilities: require('./host/capabilities.js'),
46
+ hostWasmAbi: require('./host/wasm-host-abi.js'),
47
+ requestResultHeaders: require('./host/request-result-headers.js'),
48
+ channelBroadcaster: require('./host/channel-broadcaster.js'),
49
+ jsonBody: require('./host/json-body.js'),
50
+ streamingPassthrough: require('./host/streaming-passthrough.js'),
51
+ backendCapabilities: require('./host/backend-capabilities.js'),
52
+ libraryContracts: require('./library/contracts.js'),
53
+ libraryManifest: require('./library/manifest.js'),
54
+ secondPackageOwnedLowering: require('./library/second-package-owned-lowering.js'),
55
+ librarySidecars: require('./library/sidecars.js'),
56
+ libraryApiSurface: require('./library/api-surface.js'),
57
+ schemaJsonContracts: require('./schema-json/contracts.js'),
58
+ schemaJsonV1: require('./schema-json/v1.js'),
59
+ schemaJsonV2: require('./schema-json/v2.js'),
60
+ schemaJsonCompile: require('./schema-json/compile.js'),
61
+ schemaJsonGenericParser: require('./schema-json/generic-parser.js'),
62
+ configSymbolicRefs: require('./config/symbolic-refs.js'),
63
+ configProviderResolution: require('./config/provider-resolution.js'),
64
+ runtimeProviderKv: require('./config/runtime-provider-kv.js'),
65
+ compilerSpine: require('./spine.js'),
66
+ handlerSurface: require('./handler/surface-contract.js'),
67
+ ctxContract: require('./handler/ctx-contract.js'),
68
+ handlerTypes: require('./handler/types-contract.js'),
69
+ projectConfigPlan: require('./project/config-plan.js'),
70
+ projectConfigRuntime: require('./project/config-runtime.js'),
71
+ reachableGraph: require('./project/reachable-graph.js'),
72
+ packageOwnership: require('./project/package-ownership.js'),
73
+ packageContract: require('./package/package-contract.js'),
74
+ targetSupportEvidence: require('./project/target-support-evidence.js')
75
+ };
@@ -0,0 +1,427 @@
1
+ 'use strict';
2
+
3
+ const {
4
+ CRYPTO_SEMANTIC_OWNER
5
+ } = require('../crypto/contracts.js');
6
+ const {
7
+ PACKAGE_CRYPTO_REQUIREMENT_VERSION
8
+ } = require('../package/package-contract.js');
9
+
10
+ const JWT_CONTRACT_VERSION = 'pulse.jwt-contract.v1';
11
+ const JWT_CANONICAL_EFFECT_VERSION = 'pulse.canonical-package-effect.v1';
12
+ const JWT_LOWERING_PLAN_VERSION = 'pulse.jwt-lowering-plan.v1';
13
+ const JWT_LOWERING_PLAN_ARTIFACT = 'jwt-lowering-plan.json';
14
+ const JWT_SIDECAR_ABI_VERSION = 'pulse.jwt-sidecar-abi.v1';
15
+ const JWT_CRYPTO_COMPOSITION_VERSION = 'pulse.jwt-crypto-composition.v1';
16
+ const JWT_CONTRACT_ID = 'pulse.jwt';
17
+ const JWT_PACKAGE_NAME = '@pulse-compute/jwt';
18
+
19
+ const JWT_ALGORITHMS = Object.freeze(['HS256', 'RS256', 'ES256', 'EdDSA']);
20
+ const JWT_IMPLEMENTED_ALGORITHMS = Object.freeze(['HS256', 'ES256']);
21
+ const JWT_KEY_TYPES = Object.freeze(['secret', 'jwk', 'jwks']);
22
+ const JWT_IMPLEMENTED_KEY_TYPES = Object.freeze(['secret', 'jwk', 'jwks']);
23
+ const JWT_NATIVE_REALIZATION_KINDS = Object.freeze(['crypto-composed']);
24
+ const JWT_ALGORITHM_CAPABILITIES = Object.freeze({
25
+ HS256: 'jwt.verify.hs256',
26
+ RS256: 'jwt.verify.rs256',
27
+ ES256: 'jwt.verify.es256',
28
+ EdDSA: 'jwt.verify.eddsa'
29
+ });
30
+ const JWT_PACKAGE_INTRINSICS = Object.freeze({
31
+ bearer: Object.freeze({
32
+ name: 'jwt.bearer-request-header',
33
+ nativeIntrinsic: 'request.header',
34
+ compilerName: '__pulse_jwt_bearer_request_header',
35
+ valueKind: 'string-or-undefined',
36
+ argumentIndexes: Object.freeze([]),
37
+ staticArguments: Object.freeze(['authorization'])
38
+ })
39
+ });
40
+ const JWT_DIAGNOSTIC_CODES = Object.freeze({
41
+ ARGUMENT_SHAPE_UNSUPPORTED: 'PULSE_JWT_ARGUMENT_SHAPE_UNSUPPORTED',
42
+ CONTEXT_UNSUPPORTED: 'PULSE_JWT_CONTEXT_UNSUPPORTED',
43
+ TOKEN_SOURCE_UNSUPPORTED: 'PULSE_JWT_TOKEN_SOURCE_UNSUPPORTED',
44
+ BEARER_REQUEST_UNSUPPORTED: 'PULSE_JWT_BEARER_REQUEST_UNSUPPORTED',
45
+ BEARER_PLACEMENT_UNSUPPORTED: 'PULSE_JWT_BEARER_PLACEMENT_UNSUPPORTED',
46
+ PLACEMENT_UNSUPPORTED: 'PULSE_JWT_PLACEMENT_UNSUPPORTED',
47
+ RESULT_ACCESS_UNSUPPORTED: 'PULSE_JWT_RESULT_ACCESS_UNSUPPORTED',
48
+ OPTIONS_LITERAL_REQUIRED: 'PULSE_JWT_OPTIONS_LITERAL_REQUIRED',
49
+ OPTIONS_PROPERTY_UNSUPPORTED: 'PULSE_JWT_OPTIONS_PROPERTY_UNSUPPORTED',
50
+ ALGORITHMS_LITERAL_REQUIRED: 'PULSE_JWT_ALGORITHMS_LITERAL_REQUIRED',
51
+ ALGORITHMS_EMPTY: 'PULSE_JWT_ALGORITHMS_EMPTY',
52
+ ALGORITHM_UNSUPPORTED: 'PULSE_JWT_ALGORITHM_UNSUPPORTED',
53
+ KEY_LITERAL_REQUIRED: 'PULSE_JWT_KEY_LITERAL_REQUIRED',
54
+ KEY_TYPE_UNSUPPORTED: 'PULSE_JWT_KEY_TYPE_UNSUPPORTED',
55
+ KEY_ALGORITHM_MISMATCH: 'PULSE_JWT_KEY_ALGORITHM_MISMATCH',
56
+ JWK_INVALID: 'PULSE_JWT_JWK_INVALID',
57
+ PRIVATE_JWK_UNSUPPORTED: 'PULSE_JWT_PRIVATE_JWK_UNSUPPORTED',
58
+ JWKS_LIMIT_EXCEEDED: 'PULSE_JWT_JWKS_LIMIT_EXCEEDED',
59
+ JWKS_AMBIGUOUS: 'PULSE_JWT_JWKS_AMBIGUOUS',
60
+ POLICY_LITERAL_REQUIRED: 'PULSE_JWT_POLICY_LITERAL_REQUIRED',
61
+ POLICY_LIMIT_EXCEEDED: 'PULSE_JWT_POLICY_LIMIT_EXCEEDED',
62
+ SCHEMA_LITERAL_REQUIRED: 'PULSE_JWT_SCHEMA_LITERAL_REQUIRED',
63
+ SCHEMA_UNKNOWN: 'PULSE_JWT_SCHEMA_UNKNOWN',
64
+ SCHEMA_UNREALIZED: 'PULSE_JWT_SCHEMA_UNREALIZED',
65
+ TARGET_ALGORITHM_UNSUPPORTED: 'PULSE_JWT_TARGET_ALGORITHM_UNSUPPORTED',
66
+ TARGET_KEY_UNSUPPORTED: 'PULSE_JWT_TARGET_KEY_UNSUPPORTED',
67
+ TARGET_CLOCK_UNAVAILABLE: 'PULSE_JWT_TARGET_CLOCK_UNAVAILABLE',
68
+ REALIZATION_UNSUPPORTED: 'PULSE_JWT_REALIZATION_UNSUPPORTED',
69
+ REALIZATION_AMBIGUOUS: 'PULSE_JWT_REALIZATION_AMBIGUOUS',
70
+ FACADE_USE_UNSUPPORTED: 'PULSE_JWT_FACADE_USE_UNSUPPORTED'
71
+ });
72
+ const JWT_RESOURCE_LIMITS = Object.freeze({
73
+ tokenBytes: 16 * 1024,
74
+ protectedHeaderBytes: 4 * 1024,
75
+ claimsBytes: 16 * 1024,
76
+ jwksEntries: 16,
77
+ requiredClaimNames: 32,
78
+ algorithms: 4,
79
+ clockToleranceSeconds: 300,
80
+ jsonDepth: 32
81
+ });
82
+
83
+ const JWT_ES256_KEY_NORMALIZATION_CONTRACT = Object.freeze({
84
+ version: 'pulse.jwt.es256-key-normalization.v1',
85
+ status: 'executable-g3',
86
+ algorithm: 'ES256',
87
+ inlineJwk: Object.freeze({
88
+ requiredMembers: Object.freeze(['kty', 'crv', 'x', 'y']),
89
+ optionalMembers: Object.freeze(['alg', 'use', 'key_ops', 'kid']),
90
+ exactValues: Object.freeze({
91
+ kty: 'EC',
92
+ crv: 'P-256',
93
+ alg: 'absent-or-ES256',
94
+ use: 'absent-or-sig',
95
+ key_ops: 'absent-or-exactly-verify'
96
+ }),
97
+ coordinateEncoding: 'canonical-unpadded-base64url',
98
+ coordinateBytes: 32,
99
+ privateMembersRejected: true,
100
+ unknownMembersRejected: true,
101
+ certificateMembersRejected: true
102
+ }),
103
+ jwks: Object.freeze({
104
+ kind: 'bounded-static-inline',
105
+ entriesMaximum: JWT_RESOURCE_LIMITS.jwksEntries,
106
+ remoteDiscovery: false,
107
+ fetch: false,
108
+ cache: false,
109
+ refresh: false,
110
+ duplicateKid: 'reject-entire-set',
111
+ selection: 'kid-exact-or-single-eligible-key',
112
+ selectedKeyFailure: 'terminal-no-retry'
113
+ }),
114
+ cryptoAdapter: Object.freeze({
115
+ publicKeyType: 'p256-public-key-bytes',
116
+ publicKeyEncoding: 'x-y-big-endian',
117
+ publicKeyBytes: 64,
118
+ signatureEncoding: 'jose-r-s-big-endian',
119
+ signatureBytes: 64,
120
+ derAccepted: false,
121
+ highS: 'accepted-if-otherwise-valid'
122
+ }),
123
+ exactSigningInput: true,
124
+ claimsBeforeAuthenticity: false,
125
+ automaticFallback: false
126
+ });
127
+
128
+ const JWT_VERIFY_OPERATION = Object.freeze({
129
+ version: JWT_CANONICAL_EFFECT_VERSION,
130
+ contractId: JWT_CONTRACT_ID,
131
+ package: JWT_PACKAGE_NAME,
132
+ import: JWT_PACKAGE_NAME,
133
+ kind: 'jwt.verify',
134
+ providerKind: 'jwt',
135
+ operation: 'verify',
136
+ capability: 'jwt.verify',
137
+ result: 'jwt-verification',
138
+ placement: 'variable',
139
+ clock: 'provider-wall-clock'
140
+ });
141
+
142
+ const JWT_EXECUTION_REQUIREMENTS = Object.freeze({
143
+ containment: 'request-owned-effect',
144
+ cancellation: 'request-lifecycle-signal',
145
+ secretResolution: 'provider-owned-named-secret-authority',
146
+ clock: 'one-trusted-provider-wall-clock-capture',
147
+ schemaValidation: 'project-codecs-decode-in-memory',
148
+ resultProjection: 'detached-immutable-jwt-verification',
149
+ redaction: Object.freeze([
150
+ 'token',
151
+ 'signature',
152
+ 'key-material',
153
+ 'complete-claims',
154
+ 'secret-value'
155
+ ])
156
+ });
157
+
158
+ const JWT_NATIVE_LOWERING_CONTRACT = Object.freeze({
159
+ planVersion: JWT_LOWERING_PLAN_VERSION,
160
+ sidecarAbiVersion: JWT_SIDECAR_ABI_VERSION,
161
+ cryptoCompositionVersion: JWT_CRYPTO_COMPOSITION_VERSION,
162
+ operation: 'jwt.verify',
163
+ tokenSource: 'bearer-request-header',
164
+ result: 'jwt-verification',
165
+ targetCapabilities: Object.freeze([
166
+ 'jwt.verify',
167
+ 'jwt.verify.hs256',
168
+ 'secret.get',
169
+ 'time.wall-clock'
170
+ ]),
171
+ realizationKinds: JWT_NATIVE_REALIZATION_KINDS,
172
+ realizationBinding: 'crypto-owned-before-artifact-generation',
173
+ implementationStatus: 'crypto-composed-hs256-es256',
174
+ implementedCapabilities: Object.freeze([
175
+ 'jwt.verify',
176
+ 'jwt.verify.hs256',
177
+ 'jwt.verify.es256',
178
+ 'secret.get',
179
+ 'time.wall-clock'
180
+ ]),
181
+ implementedAlgorithms: JWT_IMPLEMENTED_ALGORITHMS,
182
+ implementedKeyTypes: JWT_IMPLEMENTED_KEY_TYPES,
183
+ realization: 'guest-source:pulse-hmac-as',
184
+ implementation: 'pulse-hmac-as.v1',
185
+ realizations: Object.freeze({
186
+ HS256: Object.freeze({
187
+ realization: 'guest-source:pulse-hmac-as',
188
+ implementation: 'pulse-hmac-as.v1',
189
+ guestUnitRequired: false
190
+ }),
191
+ ES256: Object.freeze({
192
+ realization: 'guest-linked:pulse-es256-rustcrypto-p256',
193
+ implementation: 'rustcrypto.p256-0.13.2.ecdsa-0.16.9.sha2-0.10.9.v1',
194
+ guestUnitRequired: true
195
+ })
196
+ }),
197
+ cryptoSemanticOwner: CRYPTO_SEMANTIC_OWNER,
198
+ portableVerifierImplemented: false,
199
+ hostVerifyImplemented: false,
200
+ guestUnitRequiredForHs256: false,
201
+ guestUnitRequiredForEs256: true,
202
+ automaticFallback: false
203
+ });
204
+
205
+ const JWT_TARGET_REALIZATIONS = Object.freeze({
206
+ node: Object.freeze({
207
+ javascript: Object.freeze({
208
+ status: 'eligible',
209
+ algorithm: 'HS256',
210
+ realization: 'runtime-builtin',
211
+ implementation: 'webcrypto.subtle.hmac-sha-256.v1',
212
+ algorithms: JWT_IMPLEMENTED_ALGORITHMS,
213
+ keyTypes: JWT_IMPLEMENTED_KEY_TYPES,
214
+ clock: 'node-provider-wall-clock',
215
+ automaticFallback: false
216
+ }),
217
+ native: Object.freeze({
218
+ status: 'eligible',
219
+ algorithm: 'HS256',
220
+ realization: 'guest-source:pulse-hmac-as',
221
+ implementation: 'pulse-hmac-as.v1',
222
+ algorithms: JWT_IMPLEMENTED_ALGORITHMS,
223
+ keyTypes: JWT_IMPLEMENTED_KEY_TYPES,
224
+ clock: 'node-provider-wall-clock',
225
+ guestUnitRequired: false,
226
+ automaticFallback: false
227
+ })
228
+ }),
229
+ fastly: Object.freeze({
230
+ javascript: Object.freeze({
231
+ status: 'eligible',
232
+ algorithm: 'HS256',
233
+ realization: 'runtime-builtin',
234
+ implementation: 'webcrypto.subtle.hmac-sha-256.v1',
235
+ algorithms: JWT_IMPLEMENTED_ALGORITHMS,
236
+ keyTypes: JWT_IMPLEMENTED_KEY_TYPES,
237
+ clock: 'fastly-provider-wall-clock',
238
+ automaticFallback: false
239
+ }),
240
+ native: Object.freeze({
241
+ status: 'eligible',
242
+ algorithms: JWT_IMPLEMENTED_ALGORITHMS,
243
+ keyTypes: JWT_IMPLEMENTED_KEY_TYPES,
244
+ realizations: JWT_NATIVE_LOWERING_CONTRACT.realizations,
245
+ guestUnitRequiredForEs256: true,
246
+ automaticFallback: false
247
+ })
248
+ })
249
+ });
250
+
251
+ class PulseJwtContractError extends Error {
252
+ constructor(message, detail) {
253
+ super(message);
254
+ this.name = 'PulseJwtContractError';
255
+ this.code = 'PULSE_JWT_OPERATION_FAILED';
256
+ this.detail = Object.freeze({ category: 'canonical-operation', ...detail });
257
+ }
258
+ }
259
+
260
+ function ordinaryObject(value) {
261
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
262
+ const prototype = Object.getPrototypeOf(value);
263
+ return prototype === Object.prototype || prototype === null;
264
+ }
265
+
266
+ function dataProperty(value, name) {
267
+ const descriptor = Object.getOwnPropertyDescriptor(value, name);
268
+ return descriptor && descriptor.enumerable
269
+ && Object.prototype.hasOwnProperty.call(descriptor, 'value')
270
+ ? descriptor.value
271
+ : undefined;
272
+ }
273
+
274
+ function assertOperationIdentity(effect) {
275
+ if (!ordinaryObject(effect)
276
+ || effect.contractId !== JWT_VERIFY_OPERATION.contractId
277
+ || effect.package !== JWT_VERIFY_OPERATION.package
278
+ || effect.kind !== JWT_VERIFY_OPERATION.kind
279
+ || effect.providerKind !== JWT_VERIFY_OPERATION.providerKind
280
+ || effect.operation !== JWT_VERIFY_OPERATION.operation
281
+ || effect.capability !== JWT_VERIFY_OPERATION.capability
282
+ || effect.result !== JWT_VERIFY_OPERATION.result) {
283
+ throw new PulseJwtContractError(
284
+ 'Pulse JWT provider received an invalid canonical verification operation.',
285
+ { field: 'identity' }
286
+ );
287
+ }
288
+ }
289
+
290
+ function normalizeJwtVerifyEffect(effect) {
291
+ assertOperationIdentity(effect);
292
+ const payload = dataProperty(effect, 'payload');
293
+ if (!ordinaryObject(payload)) {
294
+ throw new PulseJwtContractError(
295
+ 'Pulse JWT verification requires an ordinary operation payload.',
296
+ { field: 'payload' }
297
+ );
298
+ }
299
+ const payloadKeys = Reflect.ownKeys(payload);
300
+ if (payloadKeys.length !== 2 || !payloadKeys.includes('token') || !payloadKeys.includes('options')) {
301
+ throw new PulseJwtContractError(
302
+ 'Pulse JWT verification received an invalid operation payload.',
303
+ { field: 'payload' }
304
+ );
305
+ }
306
+ const token = dataProperty(payload, 'token');
307
+ const options = dataProperty(payload, 'options');
308
+ if (typeof token !== 'string' || !ordinaryObject(options)) {
309
+ throw new PulseJwtContractError(
310
+ 'Pulse JWT verification received an invalid token or options payload.',
311
+ { field: typeof token !== 'string' ? 'token' : 'options' }
312
+ );
313
+ }
314
+ return Object.freeze({ token, options });
315
+ }
316
+
317
+ function jwtVerifyProviderRequirements(options = {}) {
318
+ const requirements = ['jwt.verify', 'time.wall-clock'];
319
+ const algorithms = Array.isArray(options.algorithms) ? options.algorithms : [];
320
+ for (const algorithm of algorithms) {
321
+ const suffix = String(algorithm).toLowerCase();
322
+ if (JWT_ALGORITHMS.includes(String(algorithm)) && !requirements.includes(`jwt.verify.${suffix}`)) {
323
+ requirements.push(`jwt.verify.${suffix}`);
324
+ }
325
+ }
326
+ const key = ordinaryObject(options.key) ? options.key : {};
327
+ if (key.type === 'secret') requirements.push('secret.get');
328
+ if (typeof options.claimsSchema === 'string') requirements.push('schema.decode');
329
+ return Object.freeze(requirements);
330
+ }
331
+
332
+ function jwtAlgorithmCapability(algorithm) {
333
+ return JWT_ALGORITHM_CAPABILITIES[String(algorithm)];
334
+ }
335
+
336
+ function jwtVerifyNativeRequirements(options = {}) {
337
+ const requirements = ['jwt.verify', 'time.wall-clock'];
338
+ const algorithms = Array.isArray(options.algorithms) ? options.algorithms : [];
339
+ for (const algorithm of algorithms) {
340
+ const capability = jwtAlgorithmCapability(algorithm);
341
+ if (capability && !requirements.includes(capability)) requirements.push(capability);
342
+ }
343
+ const key = ordinaryObject(options.key) ? options.key : {};
344
+ if (key.type === 'secret') requirements.push('secret.get');
345
+ if (typeof options.claimsSchema === 'string') requirements.push('schema.decode');
346
+ return Object.freeze(requirements);
347
+ }
348
+
349
+ function jwtCryptoRequirements(algorithms = []) {
350
+ if (!Array.isArray(algorithms)) {
351
+ throw new PulseJwtContractError(
352
+ 'JWT crypto demand requires a static algorithm array.',
353
+ { field: 'algorithms' }
354
+ );
355
+ }
356
+ const normalized = [...new Set(algorithms.map(String))].sort();
357
+ if (normalized.some((algorithm) => !JWT_ALGORITHMS.includes(algorithm))) {
358
+ throw new PulseJwtContractError(
359
+ 'JWT crypto demand contains an unsupported JWT algorithm.',
360
+ { field: 'algorithms' }
361
+ );
362
+ }
363
+ if (normalized.length === 0) return Object.freeze([]);
364
+ return Object.freeze([
365
+ Object.freeze({
366
+ version: PACKAGE_CRYPTO_REQUIREMENT_VERSION,
367
+ requestedBy: JWT_PACKAGE_NAME,
368
+ semanticOwner: CRYPTO_SEMANTIC_OWNER,
369
+ reachable: true,
370
+ algorithms: Object.freeze(normalized)
371
+ })
372
+ ]);
373
+ }
374
+
375
+ function jwtVerifyRedactedProjection(options = {}) {
376
+ const key = ordinaryObject(options.key) ? options.key : {};
377
+ const keyCount = key.type === 'jwks' && Array.isArray(key.keys)
378
+ ? key.keys.length
379
+ : (key.type === 'jwk' || key.type === 'secret' ? 1 : 0);
380
+ return Object.freeze({
381
+ version: JWT_CONTRACT_VERSION,
382
+ contractId: JWT_CONTRACT_ID,
383
+ operation: 'verify',
384
+ algorithms: Object.freeze(Array.isArray(options.algorithms)
385
+ ? options.algorithms.filter((entry) => JWT_ALGORITHMS.includes(String(entry))).map(String)
386
+ : []),
387
+ keyType: JWT_KEY_TYPES.includes(String(key.type)) ? String(key.type) : 'unknown',
388
+ keyCount,
389
+ hasIssuer: options.issuer !== undefined,
390
+ hasAudience: options.audience !== undefined,
391
+ hasSubject: options.subject !== undefined,
392
+ hasClaimsSchema: typeof options.claimsSchema === 'string',
393
+ providerRequirements: jwtVerifyProviderRequirements(options)
394
+ });
395
+ }
396
+
397
+ module.exports = Object.freeze({
398
+ JWT_CONTRACT_VERSION,
399
+ JWT_CANONICAL_EFFECT_VERSION,
400
+ JWT_LOWERING_PLAN_VERSION,
401
+ JWT_LOWERING_PLAN_ARTIFACT,
402
+ JWT_SIDECAR_ABI_VERSION,
403
+ JWT_CRYPTO_COMPOSITION_VERSION,
404
+ JWT_CONTRACT_ID,
405
+ JWT_PACKAGE_NAME,
406
+ JWT_ALGORITHMS,
407
+ JWT_IMPLEMENTED_ALGORITHMS,
408
+ JWT_KEY_TYPES,
409
+ JWT_IMPLEMENTED_KEY_TYPES,
410
+ JWT_NATIVE_REALIZATION_KINDS,
411
+ JWT_ALGORITHM_CAPABILITIES,
412
+ JWT_PACKAGE_INTRINSICS,
413
+ JWT_DIAGNOSTIC_CODES,
414
+ JWT_RESOURCE_LIMITS,
415
+ JWT_ES256_KEY_NORMALIZATION_CONTRACT,
416
+ JWT_VERIFY_OPERATION,
417
+ JWT_EXECUTION_REQUIREMENTS,
418
+ JWT_NATIVE_LOWERING_CONTRACT,
419
+ JWT_TARGET_REALIZATIONS,
420
+ PulseJwtContractError,
421
+ normalizeJwtVerifyEffect,
422
+ jwtVerifyProviderRequirements,
423
+ jwtAlgorithmCapability,
424
+ jwtVerifyNativeRequirements,
425
+ jwtCryptoRequirements,
426
+ jwtVerifyRedactedProjection
427
+ });