@pulse-compute/provider-fastly 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 (69) hide show
  1. package/README.md +53 -1
  2. package/dist/config-schema.json +77 -0
  3. package/dist/index.d.ts +61 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +59 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +88 -5
  8. package/src/build/canonical-target.js +436 -0
  9. package/src/build/entities-native.js +564 -0
  10. package/src/build/fixed-memory-runtime.as.ts +148 -0
  11. package/src/build/kv-native.as.ts +229 -0
  12. package/src/build/kv-native.js +20 -0
  13. package/src/build/native-http-effects.js +871 -0
  14. package/src/build/native-http-shell.js +703 -0
  15. package/src/build/native-platform-capabilities.js +2196 -0
  16. package/src/build/s3-native.as.ts +215 -0
  17. package/src/build/s3-native.js +30 -0
  18. package/src/compiler/assets-package-out-parity-proof.js +338 -0
  19. package/src/compiler/assets-provider-proof.js +499 -0
  20. package/src/compiler/config-provider-resolution.js +573 -0
  21. package/src/compiler/fastly-adapter.js +564 -0
  22. package/src/compiler/fastly-command-entry.js +390 -0
  23. package/src/compiler/fastly-config-secret-serve.js +323 -0
  24. package/src/compiler/fastly-hostcall-binding.js +598 -0
  25. package/src/compiler/fastly-readiness.js +477 -0
  26. package/src/compiler/index.js +40 -0
  27. package/src/compiler/lifecycle-parity-contract.js +70 -0
  28. package/src/compiler/lifecycle-parity-proof.js +260 -0
  29. package/src/compiler/route-handler-effect-proof.js +255 -0
  30. package/src/compiler/runtime-provider-kv.js +237 -0
  31. package/src/compiler/runtime-provider-shape.js +109 -0
  32. package/src/config-api.js +63 -0
  33. package/src/config-schema.d.ts +13 -0
  34. package/src/config-schema.js +27 -0
  35. package/src/config-schema.json +77 -0
  36. package/src/index.js +3 -0
  37. package/src/index.ts +118 -0
  38. package/src/javascript/assets-adapter.js +122 -0
  39. package/src/javascript/bindings-adapter.js +237 -0
  40. package/src/javascript/errors.js +26 -0
  41. package/src/javascript/fetch-adapter.js +93 -0
  42. package/src/javascript/grip-broadcast.js +261 -0
  43. package/src/javascript/jwt-verifier.js +137 -0
  44. package/src/javascript/lifecycle.js +55 -0
  45. package/src/javascript/local-loader.js +138 -0
  46. package/src/javascript/logging.js +26 -0
  47. package/src/javascript/package-effects.js +68 -0
  48. package/src/javascript/runtime-host.js +108 -0
  49. package/src/javascript/sha256.js +128 -0
  50. package/src/javascript/source-package.js +776 -0
  51. package/src/javascript/support.js +142 -0
  52. package/src/javascript/target-support-policy.js +264 -0
  53. package/src/javascript/target.js +73 -0
  54. package/src/javascript/test-runtime.js +407 -0
  55. package/src/provider-contract.js +79 -0
  56. package/src/runtime/assets-provider.js +464 -0
  57. package/src/runtime/canonical-api-runtime.js +601 -0
  58. package/src/runtime/index.js +28 -0
  59. package/src/runtime/provider-primitives-contract.js +272 -0
  60. package/src/runtime/provider-primitives.js +82 -0
  61. package/src/runtime/route-handler-effects.js +507 -0
  62. package/src/testing/conditional-kv-host.js +109 -0
  63. package/src/testing/fastly-cli.js +538 -0
  64. package/src/testing/native-http-effects-host.js +390 -0
  65. package/src/testing/native-http-shell-host.js +190 -0
  66. package/src/testing/native-platform-capabilities-host.js +676 -0
  67. package/src/toolchain/config.js +131 -0
  68. package/src/toolchain/index.js +345 -0
  69. package/src/toolchain/s3.js +26 -0
@@ -0,0 +1,131 @@
1
+ 'use strict';
2
+ const { normalizeFastlyS3 } = require('./s3.js');
3
+
4
+ function providerConfigError(code, message, detail) {
5
+ const error = new TypeError(message);
6
+ error.code = code;
7
+ error.detail = Object.freeze({ ...detail });
8
+ return error;
9
+ }
10
+
11
+ function normalizeStringMap(input, code) {
12
+ if (input === undefined) return Object.freeze({});
13
+ if (!input || typeof input !== 'object' || Array.isArray(input)) {
14
+ throw providerConfigError(code, 'Provider binding maps must be objects.', {
15
+ valueType: Array.isArray(input) ? 'array' : typeof input
16
+ });
17
+ }
18
+ return Object.freeze(Object.fromEntries(
19
+ Object.entries(input).map(([key, value]) => [String(key), String(value)])
20
+ ));
21
+ }
22
+
23
+ function normalizeFastlyProviderConfig(value) {
24
+ const input = value && typeof value === 'object' && !Array.isArray(value) ? value : {};
25
+ const bindings = input.bindings && typeof input.bindings === 'object' && !Array.isArray(input.bindings)
26
+ ? input.bindings
27
+ : {};
28
+ const local = input.local && typeof input.local === 'object' && !Array.isArray(input.local)
29
+ ? input.local
30
+ : {};
31
+ const gripInput = bindings.grip && typeof bindings.grip === 'object' && !Array.isArray(bindings.grip)
32
+ ? bindings.grip
33
+ : {};
34
+ return Object.freeze({
35
+ kind: 'fastly',
36
+ version: input.version ? String(input.version) : undefined,
37
+ bindings: Object.freeze({
38
+ configStore: String(bindings.configStore || 'pulse_config'),
39
+ secretStore: String(bindings.secretStore || 'pulse_secrets'),
40
+ kv: normalizeStringMap(bindings.kv, 'PULSE_FASTLY_KV_BINDINGS_INVALID'),
41
+ s3: normalizeFastlyS3(bindings.s3),
42
+ backends: normalizeStringMap(bindings.backends, 'PULSE_FASTLY_BACKEND_BINDINGS_INVALID'),
43
+ grip: Object.freeze({
44
+ fanoutBackend: gripInput.fanoutBackend === undefined ? undefined : String(gripInput.fanoutBackend),
45
+ publishEndpoint: gripInput.publishEndpoint === undefined ? undefined : String(gripInput.publishEndpoint),
46
+ publishUrl: gripInput.publishUrl === undefined ? undefined : String(gripInput.publishUrl),
47
+ publishBackend: gripInput.publishBackend === undefined ? undefined : String(gripInput.publishBackend),
48
+ authentication: gripInput.authentication === undefined ? undefined : Object.freeze({
49
+ scheme: String(gripInput.authentication && gripInput.authentication.scheme || 'bearer').toLowerCase(),
50
+ secretRef: String(gripInput.authentication && gripInput.authentication.secretRef || '')
51
+ }),
52
+ directHold: gripInput.directHold !== false
53
+ }),
54
+ dynamicBackends: bindings.dynamicBackends === true
55
+ }),
56
+ build: Object.freeze({
57
+ name: String(input.build && input.build.name || 'pulse-app'),
58
+ description: String(input.build && input.build.description || 'Pulse application'),
59
+ authors: Object.freeze(Array.isArray(input.build && input.build.authors) ? input.build.authors.map(String) : [])
60
+ }),
61
+ local: Object.freeze({ networkFetch: local.networkFetch === true }),
62
+ providerSpecificUserland: false
63
+ });
64
+ }
65
+
66
+ function fastlyProjectConfigDocument(config) {
67
+ return Object.freeze({
68
+ kind: 'fastly',
69
+ bindings: config.bindings,
70
+ build: config.build,
71
+ local: config.local,
72
+ providerSpecificUserland: false
73
+ });
74
+ }
75
+
76
+ function fastlyInitTemplate(name) {
77
+ return Object.freeze({
78
+ profileFragment: ` fastly: {
79
+ bindings: {
80
+ configStore: 'pulse_config',
81
+ secretStore: 'pulse_secrets',
82
+ kv: { sessions: 'sessions' },
83
+ dynamicBackends: false,
84
+ },
85
+ build: { name: '${name}' },
86
+ },
87
+ `,
88
+ dependencies: Object.freeze({
89
+ '@pulse-compute/provider-fastly': require('../../package.json').version
90
+ })
91
+ });
92
+ }
93
+
94
+ const FASTLY_PROJECT_CONFIG_REFERENCE = Object.freeze({
95
+ sections: Object.freeze([
96
+ Object.freeze({
97
+ id: 'fastly',
98
+ title: 'Fastly provider options',
99
+ description: 'Options passed to fastly(...) from @pulse-compute/provider-fastly.'
100
+ })
101
+ ]),
102
+ fields: Object.freeze([
103
+ Object.freeze({ section: 'fastly', path: 'fastly.bindings.s3', type: 'Readonly<Record<string, S3Binding & { backend: string }>>', default: '`{}`', scope: 'Fastly Native S3', description: 'Maps logical names to fixed HTTPS endpoint, bucket, region, named static backend, accessKeyIdSecret, secretAccessKeySecret, optional sessionTokenSecret, maxTextBytes (1–32768, default 32768) and timeoutMs (1–30000, default 10000).', security: 'Credentials resolve through the configured Secret Store at execution. Dynamic backend authority and guest endpoint overrides are forbidden.' }),
104
+ Object.freeze({ section: 'fastly', path: 'fastly.configStore', type: 'string', default: '`pulse_config`', scope: 'Fastly config capability', description: 'Fastly Config Store resource name.' }),
105
+ Object.freeze({ section: 'fastly', path: 'fastly.secretStore', type: 'string', default: '`pulse_secrets`', scope: 'Fastly secret capability', description: 'Fastly Secret Store resource name.', security: 'The name is build metadata; secret values are never embedded by this option.' }),
106
+ Object.freeze({ section: 'fastly', path: 'fastly.kv', type: 'Readonly<Record<string, string>>', default: '`{}`', scope: 'Fastly KV capability', description: 'Maps logical ctx.kv names to Fastly KV Store resource names.', diagnostics: Object.freeze(['PULSE_FASTLY_KV_BINDINGS_INVALID']) }),
107
+ Object.freeze({ section: 'fastly', path: 'fastly.backends', type: 'Readonly<Record<string, string>>', default: '`{}`', scope: 'Fastly fetch capability', description: 'Maps static absolute origin URLs to named Fastly backends.', security: 'Prefer explicit backends over dynamic origin authority.', diagnostics: Object.freeze(['PULSE_FASTLY_BACKEND_BINDINGS_INVALID', 'PULSE_FASTLY_BACKEND_REQUIRED']) }),
108
+ Object.freeze({ section: 'fastly', path: 'fastly.dynamicBackends', type: 'boolean', default: '`false`', scope: 'Fastly fetch capability', description: 'Allows undeclared outbound origins to use dynamic backends.', security: 'Opt in deliberately because it broadens outbound authority.', diagnostics: Object.freeze(['PULSE_FASTLY_BACKEND_REQUIRED']) }),
109
+ Object.freeze({ section: 'fastly', path: 'fastly.grip', type: 'object', default: 'omitted', scope: 'Fastly GRIP capability', description: 'Provider-owned bindings used by package-owned GRIP compatibility and canonical broadcast effects.' }),
110
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.fanoutBackend', type: 'string', default: 'omitted', scope: 'GRIP hold', description: 'Named Fastly Fanout backend.', diagnostics: Object.freeze(['PULSE_FASTLY_GRIP_FANOUT_BACKEND_REQUIRED']) }),
111
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.publishEndpoint', type: 'string', default: 'omitted', scope: 'GRIP broadcast', description: 'Provider-owned absolute publish/control endpoint; distinct from public gateway and ingress URLs.', diagnostics: Object.freeze(['PULSE_FASTLY_GRIP_PUBLISH_BINDING_REQUIRED']) }),
112
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.publishUrl', type: 'string', default: 'omitted', scope: 'GRIP publish', description: 'Absolute publish endpoint URL.', diagnostics: Object.freeze(['PULSE_FASTLY_GRIP_PUBLISH_BINDING_REQUIRED']) }),
113
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.publishBackend', type: 'string', default: 'omitted', scope: 'GRIP broadcast/publish', description: 'Named backend for the provider publish endpoint.', diagnostics: Object.freeze(['PULSE_FASTLY_GRIP_PUBLISH_BINDING_REQUIRED']) }),
114
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.authentication', type: 'object', default: 'omitted', scope: 'GRIP broadcast authentication', description: 'Authentication metadata containing references only; no credential value is accepted here.', security: 'Store the value in Fastly Secret Store and configure only secretRef.' }),
115
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.authentication.scheme', type: "'bearer'", default: '`bearer`', scope: 'GRIP broadcast authentication', description: 'Provider authentication scheme.', diagnostics: Object.freeze(['PULSE_FASTLY_NATIVE_GRIP_AUTH_SCHEME_UNSUPPORTED']) }),
116
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.authentication.secretRef', type: 'string', default: 'omitted', scope: 'GRIP broadcast authentication', description: 'Named Fastly Secret Store key used for the bearer token.', security: 'The secret value is resolved only at request execution and is redacted from traces.', diagnostics: Object.freeze(['PULSE_FASTLY_NATIVE_GRIP_SECRET_REFERENCE_MISSING']) }),
117
+ Object.freeze({ section: 'fastly', path: 'fastly.grip.directHold', type: 'boolean', default: '`true`', scope: 'GRIP hold', description: 'Enables the direct host-owned hold response realization.' }),
118
+ Object.freeze({ section: 'fastly', path: 'fastly.name', type: 'string', default: '`pulse-app`', scope: 'Fastly package metadata', description: 'Generated Fastly package name.' }),
119
+ Object.freeze({ section: 'fastly', path: 'fastly.description', type: 'string', default: '`Pulse application`', scope: 'Fastly package metadata', description: 'Generated Fastly package description.' }),
120
+ Object.freeze({ section: 'fastly', path: 'fastly.authors', type: 'readonly string[]', default: '`[]`', scope: 'Fastly package metadata', description: 'Generated Fastly package authors.' }),
121
+ Object.freeze({ section: 'fastly', path: 'fastly.local', type: 'object', default: '`{}`', scope: 'local Fastly conformance', description: 'Local-only behavior; it does not alter the deployed target.' }),
122
+ Object.freeze({ section: 'fastly', path: 'fastly.local.networkFetch', type: 'boolean', default: '`false`', scope: 'local Fastly fetch realization', description: 'Allows unmatched local Fastly fetches to use the network.', precedence: '`dev.networkFetch` overrides this value when explicitly set.', security: 'Keep disabled for deterministic tests and offline development.' })
123
+ ])
124
+ });
125
+
126
+ module.exports = Object.freeze({
127
+ normalizeFastlyProviderConfig,
128
+ fastlyProjectConfigDocument,
129
+ fastlyInitTemplate,
130
+ FASTLY_PROJECT_CONFIG_REFERENCE
131
+ });
@@ -0,0 +1,345 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+ const {
5
+ PROVIDER_DRIVER_VERSION,
6
+ PROVIDER_TARGET_RESULT_VERSION,
7
+ PROVIDER_PACKAGING_AUDIT_VERSION,
8
+ defineProviderToolchain,
9
+ defineProviderDriver,
10
+ normalizeProviderTargetResult,
11
+ normalizeProviderJavascriptPackageResult
12
+ } = require('@pulse-compute/wasm-contracts/provider/toolchain');
13
+ const { defineFinalWasmPolicy, FINAL_WASM_POLICY_VERSION } = require('@pulse-compute/wasm-contracts/provider/final-wasm-policy');
14
+ const { defineCryptoTargetCapabilities } = require('@pulse-compute/wasm-contracts/crypto/contracts');
15
+ const nativeRuntime = require('@pulse-compute/wasm-contracts/handler/canonical-native-runtime');
16
+ const fastlyRuntime = require('../runtime/canonical-api-runtime.js');
17
+ const { writeFastlyCanonicalTarget, inspectFastlyCanonicalTarget } = require('../build/canonical-target.js');
18
+ const { FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS } = require('../build/native-platform-capabilities.js');
19
+ const { FASTLY_PROVIDER_DESCRIPTOR, createFastlyLoweringPlan } = require('../provider-contract.js');
20
+ const { FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR } = require('../javascript/target.js');
21
+ const { FASTLY_JAVASCRIPT_TARGET_SUPPORT_DECLARATION } = require('../javascript/support.js');
22
+ const {
23
+ classifyFastlyJavascriptCapability,
24
+ classifyFastlyJavascriptProviderRequirement,
25
+ fastlyJavascriptProjectRestrictions
26
+ } = require('../javascript/target-support-policy.js');
27
+ const fastlyJavascriptTestRuntime = require('../javascript/test-runtime.js');
28
+ const fastlyJavascriptLocalLoader = require('../javascript/local-loader.js');
29
+ const { writeFastlyJavascriptSourcePackage } = require('../javascript/source-package.js');
30
+ const {
31
+ normalizeFastlyProviderConfig,
32
+ fastlyProjectConfigDocument,
33
+ fastlyInitTemplate,
34
+ FASTLY_PROJECT_CONFIG_REFERENCE
35
+ } = require('./config.js');
36
+ const packageManifest = require('../../package.json');
37
+
38
+ const reportingTargetCapability = Object.freeze({
39
+ supported: true,
40
+ default: 'info',
41
+ levels: Object.freeze(['off', 'error', 'warn', 'info', 'debug'])
42
+ });
43
+
44
+ const fastlyFinalWasmPolicy = defineFinalWasmPolicy({
45
+ version: FINAL_WASM_POLICY_VERSION,
46
+ descriptorOwner: packageManifest.name,
47
+ toolchainVersion: 'pulse.provider-toolchain.v1',
48
+ descriptorIdentity: 'fastly-compute-native',
49
+ permittedImports: FASTLY_NATIVE_PLATFORM_CAPABILITIES_IMPORTS
50
+ .map(([module, name]) => ({ module, name, kind: 'function' })),
51
+ requiredExports: nativeRuntime.CANONICAL_NATIVE_EXPORTS.map(([name, second]) => ({
52
+ name,
53
+ kind: second === 'memory' ? 'memory' : 'function'
54
+ }))
55
+ });
56
+
57
+ function adjustPackages(packages, restrictions) {
58
+ return packages.map((entry) => {
59
+ if (!entry.required) return entry;
60
+ const packageRestriction = entry.contractId === 'pulse.assets'
61
+ ? restrictions.assets
62
+ : (entry.contractId === 'pulse.grip' ? restrictions.grip : null);
63
+ if (!packageRestriction) return entry;
64
+ return Object.freeze({
65
+ ...entry,
66
+ status: 'blocked',
67
+ reasonId: packageRestriction.reasonId,
68
+ owner: packageRestriction.owner
69
+ });
70
+ });
71
+ }
72
+
73
+ function createDriver() {
74
+ return defineProviderDriver({
75
+ version: PROVIDER_DRIVER_VERSION,
76
+ id: 'fastly',
77
+ descriptor: FASTLY_PROVIDER_DESCRIPTOR,
78
+ executable: true,
79
+ localExecution: true,
80
+ deployable: true,
81
+ deploymentValidated: false,
82
+ sourcePackage: true,
83
+ compiledWasm: true,
84
+ defaultBuildMode: 'native-provider',
85
+ sourceOnlySupported: false,
86
+ targetSupport: Object.freeze({ javascript: FASTLY_JAVASCRIPT_TARGET_SUPPORT_DECLARATION }),
87
+ normalizeConfig: normalizeFastlyProviderConfig,
88
+ defaultLocalNetworkFetch: false,
89
+ projectConfigDocument: fastlyProjectConfigDocument,
90
+ configReference: FASTLY_PROJECT_CONFIG_REFERENCE,
91
+ initTemplate: fastlyInitTemplate,
92
+ javascript: Object.freeze({
93
+ kind: 'provider-bundled',
94
+ localEmulation: true,
95
+ buildTimeLoader: true,
96
+ localExecutionMode: fastlyJavascriptTestRuntime.FASTLY_JAVASCRIPT_LOCAL_EXECUTION_MODE,
97
+ realityRunner: 'fastly compute serve',
98
+ targetSupportPolicy: Object.freeze({
99
+ providerId: 'fastly',
100
+ declaration: FASTLY_JAVASCRIPT_TARGET_SUPPORT_DECLARATION,
101
+ context: fastlyJavascriptProjectRestrictions,
102
+ classifyCapability: classifyFastlyJavascriptCapability,
103
+ classifyProviderRequirement(id, _compilerCapabilities, restrictions) {
104
+ return classifyFastlyJavascriptProviderRequirement(id, restrictions);
105
+ },
106
+ packageOptions: Object.freeze({
107
+ suppliedCoreOwner: 'runtime',
108
+ packageResolutionReasonId: 'fastly-esbuild-package-resolution-planned',
109
+ packageResolutionOwner: 'provider-fastly',
110
+ packageRuntimeOwner: 'provider-fastly'
111
+ }),
112
+ adjustPackages,
113
+ commandOptions: Object.freeze({ projectScopedBuild: true })
114
+ }),
115
+ loadApplication(plan, options) {
116
+ return fastlyJavascriptLocalLoader.loadFastlyJavascriptLocalApplication(plan, {
117
+ projectRoot: options.projectRoot,
118
+ schemaBundle: options.schemaBundle
119
+ });
120
+ },
121
+ writeSourcePackage(invocation) {
122
+ return normalizeProviderJavascriptPackageResult(writeFastlyJavascriptSourcePackage({
123
+ plan: invocation.applicationPlan,
124
+ projectRoot: invocation.project.root,
125
+ outDir: invocation.project.outDir,
126
+ schemaBundle: invocation.javascript.schemaBundle,
127
+ providerConfig: invocation.providerConfig,
128
+ reporting: invocation.javascript.reporting,
129
+ strict: invocation.javascript.strict,
130
+ maxStructuredBodyBytes: invocation.javascript.maxStructuredBodyBytes,
131
+ targetSupport: invocation.javascript.targetSupport
132
+ }), { provider: 'fastly' });
133
+ },
134
+ describeSourcePackage(sourcePackage, context) {
135
+ return Object.freeze({
136
+ deploymentCandidate: true,
137
+ downstreamJavascriptRuntimeWasm: true,
138
+ application: Object.freeze({
139
+ entry: path.relative(context.outDir, sourcePackage.paths.entry).replace(/\\/g, '/'),
140
+ modules: context.plan.graph.modules.filter((entry) => entry.runtime).length,
141
+ bundledApplication: path.relative(context.outDir, sourcePackage.paths.bundledApplication).replace(/\\/g, '/'),
142
+ deployment: path.basename(sourcePackage.paths.deployment),
143
+ deploymentCandidate: path.basename(sourcePackage.paths.deploymentCandidate),
144
+ fastlyToml: path.basename(sourcePackage.paths.fastlyToml),
145
+ buildConfig: path.basename(sourcePackage.paths.buildConfig),
146
+ bundledInputs: sourcePackage.manifest.summary.bundledInputs
147
+ }),
148
+ files: Object.freeze({
149
+ bundledApplication: sourcePackage.paths.bundledApplication,
150
+ deployment: sourcePackage.paths.deployment,
151
+ deploymentCandidate: sourcePackage.paths.deploymentCandidate,
152
+ fastlyToml: sourcePackage.paths.fastlyToml,
153
+ buildConfig: sourcePackage.paths.buildConfig
154
+ })
155
+ });
156
+ },
157
+ executeTestCase(application, testCase, options) {
158
+ return fastlyJavascriptTestRuntime.executeFastlyJavascriptTestCase(application, testCase, options);
159
+ },
160
+ createLocalEnvironment: fastlyJavascriptTestRuntime.createFastlyJavascriptLocalEnvironment,
161
+ createTestRequest: fastlyJavascriptTestRuntime.createFastlyJavascriptTestRequest,
162
+ executeLocalRequest: fastlyJavascriptTestRuntime.executeFastlyJavascriptLocalRequest
163
+ }),
164
+ targets: Object.freeze({
165
+ native: Object.freeze({
166
+ version: 'pulse.provider-target-descriptor.v1',
167
+ target: 'native',
168
+ targetId: 'fastly-compute-native',
169
+ runtimeClass: 'native',
170
+ status: 'supported',
171
+ capabilities: Object.freeze([
172
+ 's3.head', 's3.getText',
173
+ 'kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap',
174
+ 'jwt.verify',
175
+ 'jwt.verify.hs256',
176
+ 'jwt.verify.es256',
177
+ 'secret.get',
178
+ 'time.wall-clock'
179
+ ]),
180
+ keyTypes: Object.freeze(['secret', 'jwk', 'jwks']),
181
+ realizations: Object.freeze([
182
+ Object.freeze({
183
+ kind: 'crypto-composed',
184
+ realization: 'guest-source:pulse-hmac-as',
185
+ implementation: 'pulse-hmac-as.v1',
186
+ algorithms: Object.freeze(['HS256']),
187
+ keyTypes: Object.freeze(['secret']),
188
+ implemented: true,
189
+ status: 'implemented-e2',
190
+ semanticOwner: '@pulse-compute/crypto',
191
+ guestUnitRequired: false,
192
+ portable: true,
193
+ automaticFallback: false
194
+ }),
195
+ Object.freeze({
196
+ kind: 'crypto-composed',
197
+ realization: 'guest-linked:pulse-es256-rustcrypto-p256',
198
+ implementation: 'rustcrypto.p256-0.13.2.ecdsa-0.16.9.sha2-0.10.9.v1',
199
+ algorithms: Object.freeze(['ES256']),
200
+ keyTypes: Object.freeze(['jwk', 'jwks']),
201
+ implemented: true,
202
+ status: 'implemented-g4',
203
+ semanticOwner: '@pulse-compute/crypto',
204
+ guestUnitRequired: true,
205
+ portable: true,
206
+ automaticFallback: false
207
+ })
208
+ ]),
209
+ jwt: Object.freeze({
210
+ status: 'implemented-e2',
211
+ realization: 'guest-source:pulse-hmac-as',
212
+ implementation: 'pulse-hmac-as.v1',
213
+ packageSource: 'pulse-jwt-as',
214
+ providerAuthorities: Object.freeze([
215
+ 'request',
216
+ 'secret',
217
+ 'wall-clock',
218
+ 'schema',
219
+ 'error-transport'
220
+ ]),
221
+ automaticFallback: false
222
+ }),
223
+ automaticFallback: false,
224
+ crypto: defineCryptoTargetCapabilities({
225
+ target: 'native',
226
+ algorithms: [...['SHA-256', 'HMAC-SHA256'].map((algorithm) => ({ algorithm, realization: 'guest-source:pulse-hmac-as', implemented: true, status: 'implemented-o2' })), {
227
+ algorithm: 'HS256',
228
+ realization: 'guest-source:pulse-hmac-as',
229
+ implemented: true,
230
+ status: 'implemented-c3'
231
+ }, {
232
+ algorithm: 'ES256',
233
+ realization: 'guest-linked:pulse-es256-rustcrypto-p256',
234
+ implemented: true,
235
+ status: 'implemented-g4'
236
+ }]
237
+ }),
238
+ finalWasmPolicy: fastlyFinalWasmPolicy,
239
+ reporting: reportingTargetCapability,
240
+ commands: Object.freeze({ compile: true, inspect: true, doctor: true, build: true, test: true, dev: true })
241
+ }),
242
+ javascript: FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR
243
+ }),
244
+ execute: fastlyRuntime.executeCanonicalProgram,
245
+ createLoweringPlan(metadata, providerConfig = {}) {
246
+ return createFastlyLoweringPlan(metadata, providerConfig.bindings || {});
247
+ },
248
+ inspectRealization(invocation) {
249
+ const realization = inspectFastlyCanonicalTarget({
250
+ plan: invocation.applicationPlan,
251
+ providerPlan: invocation.providerPlan,
252
+ providerConfig: invocation.providerConfig,
253
+ projectRoot: invocation.project.root,
254
+ profile: invocation.project.profile,
255
+ targetDescriptor: invocation.selectedTarget,
256
+ synchronizedPackages: invocation.synchronizedPackages,
257
+ realizationArtifacts: invocation.nativeArtifact.realizationArtifacts,
258
+ guestUnits: invocation.nativeArtifact.guestUnits,
259
+ nativeOptimization: invocation.optimization,
260
+ compileTimeoutMs: invocation.timeoutMs
261
+ });
262
+ const { native, ...publicRealization } = realization;
263
+ return normalizeProviderTargetResult({
264
+ version: PROVIDER_TARGET_RESULT_VERSION,
265
+ action: 'inspect-native',
266
+ provider: 'fastly',
267
+ target: 'native',
268
+ status: 'inspected',
269
+ automaticFallback: false,
270
+ files: Object.freeze({}),
271
+ build: null,
272
+ realization: publicRealization,
273
+ packaging: null
274
+ });
275
+ },
276
+ writeTarget(invocation) {
277
+ const inspected = inspectFastlyCanonicalTarget({
278
+ plan: invocation.applicationPlan,
279
+ providerPlan: invocation.providerPlan,
280
+ providerConfig: invocation.providerConfig,
281
+ projectRoot: invocation.project.root,
282
+ profile: invocation.project.profile,
283
+ targetDescriptor: invocation.selectedTarget,
284
+ synchronizedPackages: invocation.synchronizedPackages,
285
+ realizationArtifacts: invocation.nativeArtifact.realizationArtifacts,
286
+ guestUnits: invocation.nativeArtifact.guestUnits,
287
+ nativeOptimization: invocation.optimization,
288
+ compileTimeoutMs: invocation.timeoutMs
289
+ });
290
+ const providerBuild = writeFastlyCanonicalTarget({
291
+ outDir: invocation.project.outDir,
292
+ plan: invocation.applicationPlan,
293
+ providerPlan: invocation.providerPlan,
294
+ native: inspected.native,
295
+ providerConfig: invocation.providerConfig,
296
+ bindings: invocation.providerConfig.bindings,
297
+ projectRoot: invocation.project.root,
298
+ profile: invocation.project.profile,
299
+ targetDescriptor: invocation.selectedTarget,
300
+ synchronizedPackages: invocation.synchronizedPackages
301
+ });
302
+ const { native, ...publicRealization } = inspected;
303
+ const audit = native.guestLink && native.guestLink.audit;
304
+ return normalizeProviderTargetResult({
305
+ version: PROVIDER_TARGET_RESULT_VERSION,
306
+ action: 'write-native',
307
+ provider: 'fastly',
308
+ target: 'native',
309
+ status: 'built',
310
+ automaticFallback: false,
311
+ files: Object.freeze({
312
+ provider: providerBuild.providerFile,
313
+ providerEntry: providerBuild.entryFile,
314
+ providerBuild: providerBuild.buildFile,
315
+ providerWasm: providerBuild.wasmFile,
316
+ providerWat: providerBuild.watFile,
317
+ providerNativePlan: providerBuild.nativePlanFile,
318
+ providerNativeManifest: providerBuild.nativeManifestFile,
319
+ fastlyToml: providerBuild.fastlyTomlFile,
320
+ providerPackage: providerBuild.packageFile,
321
+ providerSourceEntry: providerBuild.sourceEntryFile
322
+ }),
323
+ build: providerBuild.build,
324
+ realization: publicRealization,
325
+ packaging: audit ? Object.freeze({
326
+ version: PROVIDER_PACKAGING_AUDIT_VERSION,
327
+ artifactSha256: providerBuild.build.wasm.sha256,
328
+ auditedSha256: audit.artifact.sha256,
329
+ authorized: native.guestLink.providerPackaging.authorized === true
330
+ }) : null
331
+ });
332
+ },
333
+ executionOptions(providerConfig = {}, values = {}) {
334
+ return { ...values, bindings: providerConfig.bindings };
335
+ }
336
+ });
337
+ }
338
+
339
+ module.exports = defineProviderToolchain({
340
+ version: 'pulse.provider-toolchain.v1',
341
+ id: 'fastly',
342
+ packageName: packageManifest.name,
343
+ packageVersion: packageManifest.version,
344
+ createDriver
345
+ });
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+ const { normalizeBinding, namePattern } = require('@pulse-compute/s3/provider');
3
+ function normalizeFastlyS3(input = {}) {
4
+ if (!input || typeof input !== 'object' || Array.isArray(input) || ![Object.prototype, null].includes(Object.getPrototypeOf(input))) throw new TypeError('Fastly S3 bindings must be a map.');
5
+ for (const key of Reflect.ownKeys(input)) {
6
+ const field = Object.getOwnPropertyDescriptor(input, key);
7
+ if (typeof key !== 'string' || !field.enumerable || !Object.hasOwn(field, 'value')) throw new TypeError('Fastly S3 bindings require data properties.');
8
+ }
9
+ return Object.freeze(Object.fromEntries(Object.entries(input).map(([name, value]) => {
10
+ if (!namePattern.test(name) || !value || typeof value !== 'object' || ![Object.prototype, null].includes(Object.getPrototypeOf(value))
11
+ || Reflect.ownKeys(value).some((key) => { const field = Object.getOwnPropertyDescriptor(value, key); return typeof key !== 'string' || !field.enumerable || !Object.hasOwn(field, 'value'); })) throw new TypeError('Fastly S3 binding is invalid.');
12
+ const { backend, ...binding } = value;
13
+ if (typeof backend !== 'string' || !namePattern.test(backend)) throw new TypeError('Fastly S3 requires a named static backend.');
14
+ return [name, Object.freeze({ ...normalizeBinding(binding), backend })];
15
+ })));
16
+ }
17
+ function resolveFastlyS3(effects, input) {
18
+ const configured = normalizeFastlyS3(input);
19
+ return Object.freeze(effects.flatMap((effect, index) => {
20
+ if (!['s3.head', 's3.getText', 's3.putText'].includes(effect.kind)) return [];
21
+ const name = effect.resource && effect.resource.binding;
22
+ if (!Object.hasOwn(configured, name)) throw new TypeError('The required Fastly S3 binding is missing.');
23
+ return [Object.freeze({ index, ...configured[name], contentType: effect.operation === 'putText' ? require('@pulse-compute/s3/provider').normalizePutOptions({ contentType: effect.payload && effect.payload.contentType }).contentType : '' })];
24
+ }));
25
+ }
26
+ module.exports = { normalizeFastlyS3, resolveFastlyS3 };