@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,241 @@
1
+ 'use strict';
2
+
3
+ const { sha256Hex, stableStringify } = require('../stable-id.js');
4
+ const { SCHEMA_ID_PATTERN, RESPONSE_CASE_ID_PATTERN } = require('./registry.js');
5
+
6
+ const JSON_SEMANTIC_TRACE_VERSION = 'pulse.json-semantic-trace.v1';
7
+ const JSON_TRACE_EVENT_KINDS = Object.freeze([
8
+ 'json.decode.request',
9
+ 'json.decode.fetch',
10
+ 'json.encode.response',
11
+ 'json.encode.fetch',
12
+ 'json.decode.error',
13
+ 'json.encode.error'
14
+ ]);
15
+ const JSON_BOUNDARIES = Object.freeze(['request', 'fetch-response', 'application-response', 'fetch-request']);
16
+ const JSON_BODY_OWNERSHIP = Object.freeze([
17
+ 'request-snapshot',
18
+ 'fetched-response-snapshot',
19
+ 'application-owned',
20
+ 'host-owned-opaque'
21
+ ]);
22
+ const JSON_EVENT_BOUNDARIES = Object.freeze({
23
+ 'json.decode.request': Object.freeze(['request']),
24
+ 'json.decode.fetch': Object.freeze(['fetch-response']),
25
+ 'json.encode.response': Object.freeze(['application-response']),
26
+ 'json.encode.fetch': Object.freeze(['fetch-request']),
27
+ 'json.decode.error': Object.freeze(['request', 'fetch-response']),
28
+ 'json.encode.error': Object.freeze(['application-response', 'fetch-request'])
29
+ });
30
+
31
+ function traceError(code, message, details = {}) {
32
+ const error = new TypeError(message);
33
+ error.code = code;
34
+ error.details = Object.freeze({ ...details });
35
+ return error;
36
+ }
37
+
38
+ function normalizeText(value) {
39
+ return String(value).normalize('NFC');
40
+ }
41
+
42
+ function plainObject(value) {
43
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
44
+ const proto = Object.getPrototypeOf(value);
45
+ return proto === Object.prototype || proto === null;
46
+ }
47
+
48
+ function normalizeSemanticValue(value, options = {}, path = '') {
49
+ const redacted = typeof options.redact === 'function' ? options.redact(value, path) : value;
50
+ if (redacted !== value) return normalizeSemanticValue(redacted, { ...options, redact: undefined }, path);
51
+ if (value === null || typeof value === 'boolean') return value;
52
+ if (typeof value === 'string') return normalizeText(value);
53
+ if (typeof value === 'number') {
54
+ if (!Number.isFinite(value)) {
55
+ throw traceError('PULSE_JSON_TRACE_NUMBER_NONFINITE', 'Semantic trace values must contain only finite RFC JSON numbers.', {
56
+ path,
57
+ value: String(value)
58
+ });
59
+ }
60
+ return Object.is(value, -0) ? 0 : value;
61
+ }
62
+ if (Array.isArray(value)) {
63
+ return Object.freeze(value.map((entry, index) => normalizeSemanticValue(entry, options, `${path}/${index}`)));
64
+ }
65
+ if (plainObject(value)) {
66
+ const out = {};
67
+ const normalizedKeys = new Set();
68
+ for (const key of Object.keys(value).sort()) {
69
+ const normalizedKey = normalizeText(key);
70
+ if (normalizedKeys.has(normalizedKey)) {
71
+ throw traceError(
72
+ 'PULSE_JSON_TRACE_KEY_NORMALIZATION_COLLISION',
73
+ `Semantic trace object keys collide after NFC normalization at ${path || '/'}.`,
74
+ { path, key: normalizedKey }
75
+ );
76
+ }
77
+ normalizedKeys.add(normalizedKey);
78
+ const pointerKey = normalizedKey.replace(/~/g, '~0').replace(/\//g, '~1');
79
+ out[normalizedKey] = normalizeSemanticValue(value[key], options, `${path}/${pointerKey}`);
80
+ }
81
+ return Object.freeze(out);
82
+ }
83
+ throw traceError('PULSE_JSON_TRACE_VALUE_UNSUPPORTED', `Semantic trace values cannot contain ${typeof value}.`, {
84
+ path,
85
+ valueType: typeof value
86
+ });
87
+ }
88
+
89
+ function semanticValueDigest(value, options = {}) {
90
+ return sha256Hex(stableStringify(normalizeSemanticValue(value, options)));
91
+ }
92
+
93
+ function normalizeHeaderPairs(input) {
94
+ const entries = input == null
95
+ ? []
96
+ : (Array.isArray(input) ? input : Object.entries(input));
97
+ return Object.freeze(entries.map((entry, index) => {
98
+ if (!Array.isArray(entry) || entry.length < 2) {
99
+ throw traceError('PULSE_JSON_TRACE_HEADERS_INVALID', `headers[${index}] must be a name/value pair.`, { index });
100
+ }
101
+ return Object.freeze([
102
+ normalizeText(entry[0]).trim().toLowerCase(),
103
+ normalizeText(entry[1]).trim().replace(/[ \t]+/g, ' ')
104
+ ]);
105
+ }).sort((left, right) => left[0].localeCompare(right[0]) || left[1].localeCompare(right[1])));
106
+ }
107
+
108
+ function normalizeJsonPointer(input) {
109
+ if (input === undefined || input === null || input === '') return null;
110
+ if (Array.isArray(input)) {
111
+ return `/${input.map((segment) => normalizeText(segment).replace(/~/g, '~0').replace(/\//g, '~1')).join('/')}`;
112
+ }
113
+ const value = normalizeText(input);
114
+ if (!value.startsWith('/') || /~(?![01])/u.test(value)) {
115
+ throw traceError('PULSE_JSON_TRACE_POINTER_INVALID', 'errorPath must be a valid JSON Pointer.', { errorPath: value });
116
+ }
117
+ return value;
118
+ }
119
+
120
+ function optionalId(value, pattern, field, code) {
121
+ if (value === undefined || value === null) return null;
122
+ const id = normalizeText(value).trim();
123
+ if (!pattern.test(id)) throw traceError(code, `${field} must be a stable dotted identifier.`, { field, id });
124
+ return id;
125
+ }
126
+
127
+ function normalizeJsonTraceEvent(input) {
128
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
129
+ throw traceError('PULSE_JSON_TRACE_EVENT_REQUIRED', 'JSON semantic trace event must be an object.');
130
+ }
131
+ const kind = normalizeText(input.kind || '');
132
+ if (!JSON_TRACE_EVENT_KINDS.includes(kind)) {
133
+ throw traceError('PULSE_JSON_TRACE_EVENT_KIND_INVALID', `Unsupported JSON trace event kind ${kind}.`, { kind });
134
+ }
135
+ const boundary = normalizeText(input.boundary || '');
136
+ if (!JSON_BOUNDARIES.includes(boundary)) {
137
+ throw traceError('PULSE_JSON_TRACE_BOUNDARY_INVALID', `Unsupported JSON trace boundary ${boundary}.`, { boundary });
138
+ }
139
+ if (!JSON_EVENT_BOUNDARIES[kind].includes(boundary)) {
140
+ throw traceError(
141
+ 'PULSE_JSON_TRACE_EVENT_BOUNDARY_MISMATCH',
142
+ `${kind} cannot be emitted for the ${boundary} boundary.`,
143
+ { kind, boundary, allowed: JSON_EVENT_BOUNDARIES[kind] }
144
+ );
145
+ }
146
+ const bodyOwnership = normalizeText(input.bodyOwnership || '');
147
+ if (!JSON_BODY_OWNERSHIP.includes(bodyOwnership)) {
148
+ throw traceError('PULSE_JSON_TRACE_BODY_OWNERSHIP_INVALID', `Unsupported JSON body ownership ${bodyOwnership}.`, {
149
+ bodyOwnership
150
+ });
151
+ }
152
+ const operationId = normalizeText(input.operationId || '').trim();
153
+ if (!/^[A-Za-z][A-Za-z0-9_.:-]*$/.test(operationId)) {
154
+ throw traceError('PULSE_JSON_TRACE_OPERATION_ID_INVALID', 'operationId must be deterministic and identifier-safe.', { operationId });
155
+ }
156
+ const status = input.status === undefined || input.status === null ? null : Number(input.status);
157
+ if (status !== null && (!Number.isSafeInteger(status) || status < 100 || status > 599)) {
158
+ throw traceError('PULSE_JSON_TRACE_STATUS_INVALID', 'status must be null or an integer from 100 through 599.', { status });
159
+ }
160
+ const schemaId = optionalId(input.schemaId, SCHEMA_ID_PATTERN, 'schemaId', 'PULSE_SCHEMA_ID_INVALID');
161
+ const responseCaseId = optionalId(input.responseCaseId, RESPONSE_CASE_ID_PATTERN, 'responseCaseId', 'PULSE_RESPONSE_CASE_ID_INVALID');
162
+ const contentType = input.contentType === undefined || input.contentType === null
163
+ ? null
164
+ : normalizeText(input.contentType).trim().toLowerCase().replace(/[ \t]+/g, ' ');
165
+ const event = {
166
+ version: JSON_SEMANTIC_TRACE_VERSION,
167
+ kind,
168
+ boundary,
169
+ schemaId,
170
+ responseCaseId,
171
+ operationId,
172
+ status,
173
+ contentType,
174
+ headers: normalizeHeaderPairs(input.headers),
175
+ bodyOwnership,
176
+ valueDigest: input.valueDigest === undefined || input.valueDigest === null
177
+ ? null
178
+ : normalizeText(input.valueDigest).toLowerCase(),
179
+ errorCode: input.errorCode === undefined || input.errorCode === null ? null : normalizeText(input.errorCode),
180
+ errorPath: normalizeJsonPointer(input.errorPath),
181
+ expected: input.expected === undefined || input.expected === null ? null : normalizeText(input.expected),
182
+ actualKind: input.actualKind === undefined || input.actualKind === null ? null : normalizeText(input.actualKind),
183
+ target: input.target === undefined || input.target === null ? null : normalizeText(input.target),
184
+ provider: input.provider === undefined || input.provider === null ? null : normalizeText(input.provider),
185
+ effectId: input.effectId === undefined || input.effectId === null ? null : normalizeText(input.effectId),
186
+ groupId: input.groupId === undefined || input.groupId === null ? null : normalizeText(input.groupId)
187
+ };
188
+ if (event.valueDigest !== null && !/^[0-9a-f]{64}$/.test(event.valueDigest)) {
189
+ throw traceError('PULSE_JSON_TRACE_DIGEST_INVALID', 'valueDigest must be a lowercase SHA-256 hex digest.', {
190
+ valueDigest: event.valueDigest
191
+ });
192
+ }
193
+ const isError = kind.endsWith('.error');
194
+ if (isError && !event.errorCode) {
195
+ throw traceError('PULSE_JSON_TRACE_ERROR_CODE_REQUIRED', `${kind} requires errorCode.`, { kind });
196
+ }
197
+ if (!isError && event.errorCode) {
198
+ throw traceError('PULSE_JSON_TRACE_ERROR_CODE_UNEXPECTED', `${kind} cannot carry errorCode.`, { kind });
199
+ }
200
+ return Object.freeze({
201
+ ...event,
202
+ eventDigest: sha256Hex(stableStringify(event))
203
+ });
204
+ }
205
+
206
+ function operationIdentity(input) {
207
+ const semantic = normalizeSemanticValue(input);
208
+ return `jsonop:${sha256Hex(stableStringify(semantic)).slice(0, 24)}`;
209
+ }
210
+
211
+ function defaultJsonSemanticTraceContract() {
212
+ return Object.freeze({
213
+ version: JSON_SEMANTIC_TRACE_VERSION,
214
+ eventKinds: JSON_TRACE_EVENT_KINDS,
215
+ boundaries: JSON_BOUNDARIES,
216
+ eventBoundaries: JSON_EVENT_BOUNDARIES,
217
+ bodyOwnership: JSON_BODY_OWNERSHIP,
218
+ digest: 'sha256(canonical-redacted-semantic-value)',
219
+ stringNormalization: 'NFC',
220
+ numberNormalization: 'finite; negative-zero becomes zero',
221
+ headerNormalization: 'lowercase-name; collapsed-ows-value; sorted-pairs',
222
+ errorPath: 'RFC-6901 JSON Pointer',
223
+ parity: 'semantic-not-byte',
224
+ rawSensitiveValuesAllowed: false
225
+ });
226
+ }
227
+
228
+ module.exports = Object.freeze({
229
+ JSON_SEMANTIC_TRACE_VERSION,
230
+ JSON_TRACE_EVENT_KINDS,
231
+ JSON_BOUNDARIES,
232
+ JSON_BODY_OWNERSHIP,
233
+ JSON_EVENT_BOUNDARIES,
234
+ normalizeSemanticValue,
235
+ semanticValueDigest,
236
+ normalizeHeaderPairs,
237
+ normalizeJsonPointer,
238
+ normalizeJsonTraceEvent,
239
+ operationIdentity,
240
+ defaultJsonSemanticTraceContract
241
+ });
@@ -0,0 +1,65 @@
1
+ 'use strict';
2
+
3
+ const SCHEMA_JSON_SIDECAR_VERSION = 'pulsewasm.schema-json-sidecar.v2';
4
+ const SCHEMA_JSON_PLAN_VERSION = 'pulsewasm.schema-json-plan.v2';
5
+ const SCHEMA_JSON_REPORT_VERSION = 'pulsewasm.schema-json-parser-report.v2';
6
+ const SCHEMA_JSON_SMOKE_VERSION = 'pulsewasm.schema-json-smoke.v2';
7
+ const SCHEMA_JSON_REGISTRY_VERSION = 'pulsewasm.schema-json-registry.v1';
8
+ const SCHEMA_JSON_ABI_VERSION = 'pulsewasm.schema-json-sidecar-abi.v1';
9
+ const SCHEMA_JSON_BODY_POLICY_VERSION = 'pulsewasm.schema-json-body-policy.v1';
10
+ const SCHEMA_JSON_PHASE = '12B.1';
11
+ const PHASE = SCHEMA_JSON_PHASE;
12
+
13
+ const SUPPORTED_TYPES = new Set(['string', 'i32', 'u32', 'f64', 'bool', 'boolean', 'number']);
14
+ const RESERVED_TYPES = new Set(['any', 'unknown', 'object', 'Object', 'Record<string, unknown>', 'array', 'Array']);
15
+ const CONTENT_TYPE_POLICIES = new Set(['accept-json-or-missing', 'require-json']);
16
+ const RESERVED_CONTENT_TYPE_POLICIES = new Set(['ignore-content-type']);
17
+ const DEFAULT_SCHEMA_JSON_NAMESPACE = 'app';
18
+ const DEFAULT_SCHEMA_JSON_MAX_BYTES = 1_048_576;
19
+ const DEFAULT_SCHEMA_JSON_CONTENT_TYPE_POLICY = 'accept-json-or-missing';
20
+
21
+ function lowerFieldType(type) {
22
+ if (type === 'boolean') return 'bool';
23
+ if (type === 'number') return 'f64';
24
+ return type;
25
+ }
26
+
27
+ function isSupportedFieldType(type) {
28
+ return SUPPORTED_TYPES.has(String(type));
29
+ }
30
+
31
+ function isReservedFieldType(type) {
32
+ return RESERVED_TYPES.has(String(type));
33
+ }
34
+
35
+ function isSupportedContentTypePolicy(policy) {
36
+ return CONTENT_TYPE_POLICIES.has(String(policy));
37
+ }
38
+
39
+ function isReservedContentTypePolicy(policy) {
40
+ return RESERVED_CONTENT_TYPE_POLICIES.has(String(policy));
41
+ }
42
+
43
+ module.exports = {
44
+ SCHEMA_JSON_SIDECAR_VERSION,
45
+ SCHEMA_JSON_PLAN_VERSION,
46
+ SCHEMA_JSON_REPORT_VERSION,
47
+ SCHEMA_JSON_SMOKE_VERSION,
48
+ SCHEMA_JSON_REGISTRY_VERSION,
49
+ SCHEMA_JSON_ABI_VERSION,
50
+ SCHEMA_JSON_BODY_POLICY_VERSION,
51
+ SCHEMA_JSON_PHASE,
52
+ PHASE,
53
+ SUPPORTED_TYPES,
54
+ RESERVED_TYPES,
55
+ CONTENT_TYPE_POLICIES,
56
+ RESERVED_CONTENT_TYPE_POLICIES,
57
+ DEFAULT_SCHEMA_JSON_NAMESPACE,
58
+ DEFAULT_SCHEMA_JSON_MAX_BYTES,
59
+ DEFAULT_SCHEMA_JSON_CONTENT_TYPE_POLICY,
60
+ lowerFieldType,
61
+ isSupportedFieldType,
62
+ isReservedFieldType,
63
+ isSupportedContentTypePolicy,
64
+ isReservedContentTypePolicy
65
+ };
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ const SCHEMA_JSON_SIDECAR_VERSION = 'pulsewasm.schema-json-sidecar.v3';
4
+ const SCHEMA_JSON_PLAN_VERSION = 'pulsewasm.schema-json-plan.v3';
5
+ const SCHEMA_JSON_REPORT_VERSION = 'pulsewasm.schema-json-parser-report.v3';
6
+ const SCHEMA_JSON_SMOKE_VERSION = 'pulsewasm.schema-json-smoke.v3';
7
+ const SCHEMA_JSON_REGISTRY_VERSION = 'pulsewasm.schema-json-registry.v2';
8
+ const SCHEMA_JSON_ABI_VERSION = 'pulsewasm.schema-json-sidecar-abi.v2';
9
+ const SCHEMA_JSON_BODY_POLICY_VERSION = 'pulsewasm.schema-json-body-policy.v1';
10
+ const SCHEMA_JSON_PHASE = '14';
11
+ const PHASE = SCHEMA_JSON_PHASE;
12
+
13
+ const SCALAR_ALIASES = new Map([
14
+ ['boolean', 'bool'],
15
+ ['number', 'f64']
16
+ ]);
17
+ const SCALAR_TYPES = new Set(['string', 'bool', 'boolean', 'i32', 'u32', 'f64', 'number']);
18
+ const RESERVED_SCALAR_TYPES = new Set(['any', 'unknown', 'object', 'Object', 'Record<string, unknown>', 'array', 'Array']);
19
+ const CONTENT_TYPE_POLICIES = new Set(['accept-json-or-missing', 'require-json']);
20
+ const RESERVED_CONTENT_TYPE_POLICIES = new Set(['ignore-content-type']);
21
+ const DEFAULT_SCHEMA_JSON_NAMESPACE = 'app';
22
+ const DEFAULT_SCHEMA_JSON_CONTENT_TYPE_POLICY = 'accept-json-or-missing';
23
+
24
+ function isPlainObject(value) {
25
+ return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
26
+ }
27
+
28
+ function plainObject(value) {
29
+ return isPlainObject(value) ? value : {};
30
+ }
31
+
32
+ function jsonConfig(config) {
33
+ const runtime = plainObject(config && config.runtime);
34
+ const payload = plainObject(runtime.payload);
35
+ return plainObject(payload.json || (config && config.json));
36
+ }
37
+
38
+ function lowerScalar(type) {
39
+ return SCALAR_ALIASES.get(type) || type;
40
+ }
41
+
42
+ function normalizeScalarType(type) {
43
+ const raw = String(type || '');
44
+ return lowerScalar(raw);
45
+ }
46
+
47
+ function isSupportedScalarType(type) {
48
+ const raw = String(type || '');
49
+ const lowered = lowerScalar(raw);
50
+ return SCALAR_TYPES.has(raw) || SCALAR_TYPES.has(lowered);
51
+ }
52
+
53
+ function isReservedScalarType(type) {
54
+ return RESERVED_SCALAR_TYPES.has(String(type || ''));
55
+ }
56
+
57
+ function isSupportedContentTypePolicy(policy) {
58
+ return CONTENT_TYPE_POLICIES.has(String(policy));
59
+ }
60
+
61
+ function descriptorNeedsV2(value) {
62
+ if (Array.isArray(value)) return true;
63
+ if (!value || typeof value !== 'object') return false;
64
+ if (Object.prototype.hasOwnProperty.call(value, 'fields')) return true;
65
+ if (Object.prototype.hasOwnProperty.call(value, 'enum')) return true;
66
+ if (Object.prototype.hasOwnProperty.call(value, 'required')) return true;
67
+ if (Object.prototype.hasOwnProperty.call(value, 'nullable')) return true;
68
+ if (value.type === 'object') return true;
69
+ if (Array.isArray(value.type)) return true;
70
+ if (isPlainObject(value.type)) return true;
71
+ return false;
72
+ }
73
+
74
+ function configArtifact(config) {
75
+ return config && typeof config === 'object' && config.artifact ? config.artifact : config;
76
+ }
77
+
78
+ function shouldUseSchemaJsonV2(config) {
79
+ const json = jsonConfig(configArtifact(config));
80
+ if ((json.schemaVersion || '') === 'v2') return true;
81
+ const schemas = Array.isArray(json.schemas) ? json.schemas : [];
82
+ return schemas.some((schema) => descriptorNeedsV2(schema.fields) || Object.values(plainObject(schema.fields)).some((field) => descriptorNeedsV2(field)));
83
+ }
84
+
85
+ module.exports = {
86
+ SCHEMA_JSON_SIDECAR_VERSION,
87
+ SCHEMA_JSON_PLAN_VERSION,
88
+ SCHEMA_JSON_REPORT_VERSION,
89
+ SCHEMA_JSON_SMOKE_VERSION,
90
+ SCHEMA_JSON_REGISTRY_VERSION,
91
+ SCHEMA_JSON_ABI_VERSION,
92
+ SCHEMA_JSON_BODY_POLICY_VERSION,
93
+ SCHEMA_JSON_PHASE,
94
+ PHASE,
95
+ SCALAR_ALIASES,
96
+ SCALAR_TYPES,
97
+ RESERVED_SCALAR_TYPES,
98
+ CONTENT_TYPE_POLICIES,
99
+ RESERVED_CONTENT_TYPE_POLICIES,
100
+ DEFAULT_SCHEMA_JSON_NAMESPACE,
101
+ DEFAULT_SCHEMA_JSON_CONTENT_TYPE_POLICY,
102
+ lowerScalar,
103
+ normalizeScalarType,
104
+ isSupportedScalarType,
105
+ isReservedScalarType,
106
+ isSupportedContentTypePolicy,
107
+ configArtifact,
108
+ descriptorNeedsV2,
109
+ shouldUseSchemaJsonV2
110
+ };
package/src/sha256.js ADDED
@@ -0,0 +1,104 @@
1
+ 'use strict';
2
+
3
+ // Synchronous, platform-neutral SHA-256 for deterministic contract identities.
4
+ // Contract code is shared by Node tooling and provider JavaScript closures, so
5
+ // it cannot depend on a Node builtin or an asynchronous host crypto surface.
6
+ const K = Object.freeze([
7
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
8
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
9
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
10
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
11
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
12
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
13
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
14
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
15
+ ]);
16
+
17
+ function rotateRight(value, amount) {
18
+ return (value >>> amount) | (value << (32 - amount));
19
+ }
20
+
21
+ function inputBytes(value) {
22
+ if (typeof value === 'string') return new TextEncoder().encode(value);
23
+ if (value instanceof Uint8Array) return value;
24
+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
25
+ if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
26
+ return new TextEncoder().encode(String(value));
27
+ }
28
+
29
+ function sha256Bytes(input) {
30
+ const bytes = inputBytes(input);
31
+ const paddedLength = Math.ceil((bytes.byteLength + 9) / 64) * 64;
32
+ const message = new Uint8Array(paddedLength);
33
+ message.set(bytes);
34
+ message[bytes.byteLength] = 0x80;
35
+ const bitLength = BigInt(bytes.byteLength) * 8n;
36
+ for (let index = 0; index < 8; index += 1) {
37
+ message[paddedLength - 1 - index] = Number((bitLength >> BigInt(index * 8)) & 0xffn);
38
+ }
39
+
40
+ const state = new Uint32Array([
41
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
42
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
43
+ ]);
44
+ const words = new Uint32Array(64);
45
+ for (let offset = 0; offset < message.byteLength; offset += 64) {
46
+ for (let index = 0; index < 16; index += 1) {
47
+ const position = offset + index * 4;
48
+ words[index] = (
49
+ (message[position] << 24)
50
+ | (message[position + 1] << 16)
51
+ | (message[position + 2] << 8)
52
+ | message[position + 3]
53
+ ) >>> 0;
54
+ }
55
+ for (let index = 16; index < 64; index += 1) {
56
+ const left = words[index - 15];
57
+ const right = words[index - 2];
58
+ const s0 = rotateRight(left, 7) ^ rotateRight(left, 18) ^ (left >>> 3);
59
+ const s1 = rotateRight(right, 17) ^ rotateRight(right, 19) ^ (right >>> 10);
60
+ words[index] = (words[index - 16] + s0 + words[index - 7] + s1) >>> 0;
61
+ }
62
+
63
+ let [a, b, c, d, e, f, g, h] = state;
64
+ for (let index = 0; index < 64; index += 1) {
65
+ const sum1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
66
+ const choice = (e & f) ^ (~e & g);
67
+ const temporary1 = (h + sum1 + choice + K[index] + words[index]) >>> 0;
68
+ const sum0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
69
+ const majority = (a & b) ^ (a & c) ^ (b & c);
70
+ const temporary2 = (sum0 + majority) >>> 0;
71
+ h = g;
72
+ g = f;
73
+ f = e;
74
+ e = (d + temporary1) >>> 0;
75
+ d = c;
76
+ c = b;
77
+ b = a;
78
+ a = (temporary1 + temporary2) >>> 0;
79
+ }
80
+ state[0] = (state[0] + a) >>> 0;
81
+ state[1] = (state[1] + b) >>> 0;
82
+ state[2] = (state[2] + c) >>> 0;
83
+ state[3] = (state[3] + d) >>> 0;
84
+ state[4] = (state[4] + e) >>> 0;
85
+ state[5] = (state[5] + f) >>> 0;
86
+ state[6] = (state[6] + g) >>> 0;
87
+ state[7] = (state[7] + h) >>> 0;
88
+ }
89
+
90
+ const digest = new Uint8Array(32);
91
+ for (let index = 0; index < state.length; index += 1) {
92
+ digest[index * 4] = state[index] >>> 24;
93
+ digest[index * 4 + 1] = state[index] >>> 16;
94
+ digest[index * 4 + 2] = state[index] >>> 8;
95
+ digest[index * 4 + 3] = state[index];
96
+ }
97
+ return digest;
98
+ }
99
+
100
+ function sha256Hex(input) {
101
+ return Array.from(sha256Bytes(input), (byte) => byte.toString(16).padStart(2, '0')).join('');
102
+ }
103
+
104
+ module.exports = Object.freeze({ sha256Bytes, sha256Hex });