@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.
- package/README.md +53 -1
- package/dist/config-schema.json +77 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/index.js.map +1 -0
- package/package.json +88 -5
- package/src/build/canonical-target.js +436 -0
- package/src/build/entities-native.js +564 -0
- package/src/build/fixed-memory-runtime.as.ts +148 -0
- package/src/build/kv-native.as.ts +229 -0
- package/src/build/kv-native.js +20 -0
- package/src/build/native-http-effects.js +871 -0
- package/src/build/native-http-shell.js +703 -0
- package/src/build/native-platform-capabilities.js +2196 -0
- package/src/build/s3-native.as.ts +215 -0
- package/src/build/s3-native.js +30 -0
- package/src/compiler/assets-package-out-parity-proof.js +338 -0
- package/src/compiler/assets-provider-proof.js +499 -0
- package/src/compiler/config-provider-resolution.js +573 -0
- package/src/compiler/fastly-adapter.js +564 -0
- package/src/compiler/fastly-command-entry.js +390 -0
- package/src/compiler/fastly-config-secret-serve.js +323 -0
- package/src/compiler/fastly-hostcall-binding.js +598 -0
- package/src/compiler/fastly-readiness.js +477 -0
- package/src/compiler/index.js +40 -0
- package/src/compiler/lifecycle-parity-contract.js +70 -0
- package/src/compiler/lifecycle-parity-proof.js +260 -0
- package/src/compiler/route-handler-effect-proof.js +255 -0
- package/src/compiler/runtime-provider-kv.js +237 -0
- package/src/compiler/runtime-provider-shape.js +109 -0
- package/src/config-api.js +63 -0
- package/src/config-schema.d.ts +13 -0
- package/src/config-schema.js +27 -0
- package/src/config-schema.json +77 -0
- package/src/index.js +3 -0
- package/src/index.ts +118 -0
- package/src/javascript/assets-adapter.js +122 -0
- package/src/javascript/bindings-adapter.js +237 -0
- package/src/javascript/errors.js +26 -0
- package/src/javascript/fetch-adapter.js +93 -0
- package/src/javascript/grip-broadcast.js +261 -0
- package/src/javascript/jwt-verifier.js +137 -0
- package/src/javascript/lifecycle.js +55 -0
- package/src/javascript/local-loader.js +138 -0
- package/src/javascript/logging.js +26 -0
- package/src/javascript/package-effects.js +68 -0
- package/src/javascript/runtime-host.js +108 -0
- package/src/javascript/sha256.js +128 -0
- package/src/javascript/source-package.js +776 -0
- package/src/javascript/support.js +142 -0
- package/src/javascript/target-support-policy.js +264 -0
- package/src/javascript/target.js +73 -0
- package/src/javascript/test-runtime.js +407 -0
- package/src/provider-contract.js +79 -0
- package/src/runtime/assets-provider.js +464 -0
- package/src/runtime/canonical-api-runtime.js +601 -0
- package/src/runtime/index.js +28 -0
- package/src/runtime/provider-primitives-contract.js +272 -0
- package/src/runtime/provider-primitives.js +82 -0
- package/src/runtime/route-handler-effects.js +507 -0
- package/src/testing/conditional-kv-host.js +109 -0
- package/src/testing/fastly-cli.js +538 -0
- package/src/testing/native-http-effects-host.js +390 -0
- package/src/testing/native-http-shell-host.js +190 -0
- package/src/testing/native-platform-capabilities-host.js +676 -0
- package/src/toolchain/config.js +131 -0
- package/src/toolchain/index.js +345 -0
- package/src/toolchain/s3.js +26 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
normalizeTargetSupportDeclaration
|
|
5
|
+
} = require('@pulse-compute/wasm-contracts/project/target-support-evidence');
|
|
6
|
+
const { FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR } = require('./target.js');
|
|
7
|
+
|
|
8
|
+
function evidence(artifact, version, cases) {
|
|
9
|
+
return Object.freeze({
|
|
10
|
+
artifact,
|
|
11
|
+
version,
|
|
12
|
+
sha256: null,
|
|
13
|
+
status: 'passed',
|
|
14
|
+
cases,
|
|
15
|
+
matched: cases,
|
|
16
|
+
mismatches: 0
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function gate(id, status, reasonId, owner, summary, evidenceReference = null) {
|
|
21
|
+
return Object.freeze({ id, status, reasonId, owner, summary, evidence: evidenceReference });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const FASTLY_JAVASCRIPT_SOURCE_PACKAGE_EVIDENCE = evidence(
|
|
25
|
+
'wasm/test/provider/assert-fastly-javascript-packaging.cjs',
|
|
26
|
+
'pulse.fastly-javascript-source-package-evidence.v1',
|
|
27
|
+
14
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const FASTLY_JAVASCRIPT_RUNTIME_EVIDENCE = evidence(
|
|
31
|
+
'wasm/test/provider/assert-fastly-javascript-runtime.cjs',
|
|
32
|
+
'pulse.fastly-javascript-runtime-evidence.v1',
|
|
33
|
+
27
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const FASTLY_JAVASCRIPT_TOOLING_EVIDENCE = evidence(
|
|
37
|
+
'wasm/test/provider/assert-fastly-javascript-tooling.cjs',
|
|
38
|
+
'pulse.fastly-javascript-tooling-evidence.v1',
|
|
39
|
+
6
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const FASTLY_JAVASCRIPT_FOUR_MODE_EVIDENCE = evidence(
|
|
43
|
+
'wasm/test/contracts/assert-four-mode-conformance.cjs',
|
|
44
|
+
'pulse.four-mode-conformance.v1',
|
|
45
|
+
24
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const FASTLY_JAVASCRIPT_RELEASE_CANDIDATE_EVIDENCE = evidence(
|
|
49
|
+
'scripts/offline-release-candidates.cjs',
|
|
50
|
+
'pulse.offline-deployment-candidates.v1',
|
|
51
|
+
2
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const GATES = Object.freeze([
|
|
55
|
+
gate(
|
|
56
|
+
'build-source-packaging',
|
|
57
|
+
'satisfied',
|
|
58
|
+
'fastly-javascript-source-packaging',
|
|
59
|
+
'provider-fastly',
|
|
60
|
+
'Fastly JavaScript builds emit deterministic source closures with exact downstream toolchain pins and no Pulse Native artifact.',
|
|
61
|
+
FASTLY_JAVASCRIPT_SOURCE_PACKAGE_EVIDENCE
|
|
62
|
+
),
|
|
63
|
+
gate(
|
|
64
|
+
'provider-request-runtime',
|
|
65
|
+
'satisfied',
|
|
66
|
+
'fastly-javascript-request-runtime',
|
|
67
|
+
'provider-fastly',
|
|
68
|
+
'Fastly FetchEvent requests execute through the shared Router/context runtime with request-contained provider failures and cleanup.',
|
|
69
|
+
FASTLY_JAVASCRIPT_RUNTIME_EVIDENCE
|
|
70
|
+
),
|
|
71
|
+
gate(
|
|
72
|
+
'provider-capabilities-packages-redaction',
|
|
73
|
+
'satisfied',
|
|
74
|
+
'fastly-javascript-capabilities',
|
|
75
|
+
'provider-fastly',
|
|
76
|
+
'Fetch, Config Store, Secret Store, KV Store, Assets, GRIP broadcast, logging, and request-owned redaction have provider adapters.',
|
|
77
|
+
FASTLY_JAVASCRIPT_RUNTIME_EVIDENCE
|
|
78
|
+
),
|
|
79
|
+
gate(
|
|
80
|
+
'representative-local-tooling',
|
|
81
|
+
'satisfied',
|
|
82
|
+
'fastly-javascript-representative-tooling',
|
|
83
|
+
'provider-fastly',
|
|
84
|
+
'Representative pulse test and pulse dev use explicit provider emulation, while deterministic build output forms a structurally deployable Fastly JavaScript candidate.',
|
|
85
|
+
FASTLY_JAVASCRIPT_TOOLING_EVIDENCE
|
|
86
|
+
),
|
|
87
|
+
gate(
|
|
88
|
+
'four-mode-conformance',
|
|
89
|
+
'satisfied',
|
|
90
|
+
'fastly-javascript-four-mode-conformance',
|
|
91
|
+
'conformance',
|
|
92
|
+
'Node Native, Node JavaScript, Fastly Native, and Fastly JavaScript agree across normalized semantic traces with target-integrity and negative-control evidence.',
|
|
93
|
+
FASTLY_JAVASCRIPT_FOUR_MODE_EVIDENCE
|
|
94
|
+
),
|
|
95
|
+
gate(
|
|
96
|
+
'offline-deployment-candidates',
|
|
97
|
+
'satisfied',
|
|
98
|
+
'fastly-javascript-offline-deployment-candidate',
|
|
99
|
+
'release',
|
|
100
|
+
'Two clean source-package builds agree byte-for-byte and the pinned downstream Fastly compiler emits a structurally deployable JavaScript runtime candidate without deployment or publication.',
|
|
101
|
+
FASTLY_JAVASCRIPT_RELEASE_CANDIDATE_EVIDENCE
|
|
102
|
+
)
|
|
103
|
+
]);
|
|
104
|
+
|
|
105
|
+
const COMMANDS = Object.freeze([
|
|
106
|
+
['build', true, 'eligible', 'build-implemented', 'provider-fastly'],
|
|
107
|
+
['compile', true, 'eligible', 'compile-implemented', 'compiler'],
|
|
108
|
+
['dev', true, 'eligible', 'fastly-javascript-dev-implemented', 'provider-fastly'],
|
|
109
|
+
['doctor', true, 'eligible', 'doctor-implemented', 'cli'],
|
|
110
|
+
['inspect', true, 'eligible', 'inspect-implemented', 'cli'],
|
|
111
|
+
['test', true, 'eligible', 'fastly-javascript-test-implemented', 'provider-fastly']
|
|
112
|
+
].map(([id, implemented, status, reasonId, owner]) => Object.freeze({
|
|
113
|
+
id,
|
|
114
|
+
implemented,
|
|
115
|
+
status,
|
|
116
|
+
reasonId,
|
|
117
|
+
owner
|
|
118
|
+
})));
|
|
119
|
+
|
|
120
|
+
const FASTLY_JAVASCRIPT_TARGET_SUPPORT_DECLARATION = normalizeTargetSupportDeclaration({
|
|
121
|
+
provider: 'fastly',
|
|
122
|
+
target: 'javascript',
|
|
123
|
+
targetId: FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR.targetId,
|
|
124
|
+
runtimeClass: FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR.runtimeClass,
|
|
125
|
+
definition: 'full-target-support',
|
|
126
|
+
coreExecutionReady: true,
|
|
127
|
+
fullTargetSupportReady: true,
|
|
128
|
+
generalAvailable: true,
|
|
129
|
+
automaticFallback: false,
|
|
130
|
+
parity: FASTLY_JAVASCRIPT_FOUR_MODE_EVIDENCE,
|
|
131
|
+
commands: COMMANDS,
|
|
132
|
+
gates: GATES
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
module.exports = Object.freeze({
|
|
136
|
+
FASTLY_JAVASCRIPT_SOURCE_PACKAGE_EVIDENCE,
|
|
137
|
+
FASTLY_JAVASCRIPT_RUNTIME_EVIDENCE,
|
|
138
|
+
FASTLY_JAVASCRIPT_TOOLING_EVIDENCE,
|
|
139
|
+
FASTLY_JAVASCRIPT_FOUR_MODE_EVIDENCE,
|
|
140
|
+
FASTLY_JAVASCRIPT_RELEASE_CANDIDATE_EVIDENCE,
|
|
141
|
+
FASTLY_JAVASCRIPT_TARGET_SUPPORT_DECLARATION
|
|
142
|
+
});
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
isJavascriptCoreCapability
|
|
5
|
+
} = require('@pulse-compute/wasm-contracts/project/javascript-core-capabilities');
|
|
6
|
+
|
|
7
|
+
function decision(id, status, reasonId, owner, required = true) {
|
|
8
|
+
return Object.freeze({ id, status, required, reasonId, owner });
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function blockedRestriction(id, restriction) {
|
|
12
|
+
return restriction
|
|
13
|
+
? decision(id, 'blocked', restriction.reasonId, restriction.owner)
|
|
14
|
+
: null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function classifyFastlyJavascriptCapability(id, restrictions = {}) {
|
|
18
|
+
const capability = String(id);
|
|
19
|
+
if (['kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap'].includes(capability)) return decision(capability, 'blocked', 'fastly-conditional-kv-incomplete', 'provider-fastly');
|
|
20
|
+
if (['s3.head', 's3.getText', 's3.putText'].includes(capability)) return decision(capability, 'blocked', 'fastly-javascript-s3-raw-headers-unavailable', 'provider-fastly');
|
|
21
|
+
if (isJavascriptCoreCapability(capability)) {
|
|
22
|
+
return decision(capability, 'eligible', 'fastly-request-router-runtime', 'provider-fastly');
|
|
23
|
+
}
|
|
24
|
+
if (
|
|
25
|
+
capability === 'request.json'
|
|
26
|
+
|| capability === 'req.json'
|
|
27
|
+
|| capability.startsWith('request.body')
|
|
28
|
+
|| capability.startsWith('req.body')
|
|
29
|
+
|| capability.startsWith('schema.')
|
|
30
|
+
) {
|
|
31
|
+
return decision(capability, 'eligible', 'fastly-shared-schema-boundaries', 'runtime');
|
|
32
|
+
}
|
|
33
|
+
if (capability === 'fetch' || capability.startsWith('fetch.') || capability === 'backend-fetch') {
|
|
34
|
+
return blockedRestriction(capability, restrictions.fetch)
|
|
35
|
+
|| decision(capability, 'eligible', 'fastly-fetch-adapter', 'provider-fastly');
|
|
36
|
+
}
|
|
37
|
+
if (capability === 'config' || capability === 'config.get') {
|
|
38
|
+
return blockedRestriction(capability, restrictions.config)
|
|
39
|
+
|| decision(capability, 'eligible', 'fastly-config-store-adapter', 'provider-fastly');
|
|
40
|
+
}
|
|
41
|
+
if (capability === 'secret' || capability === 'secret.get') {
|
|
42
|
+
return blockedRestriction(capability, restrictions.secret)
|
|
43
|
+
|| decision(capability, 'eligible', 'fastly-secret-store-adapter', 'provider-fastly');
|
|
44
|
+
}
|
|
45
|
+
if (capability === 'kv' || capability.startsWith('kv.')) {
|
|
46
|
+
return blockedRestriction(capability, restrictions.kv)
|
|
47
|
+
|| decision(capability, 'eligible', 'fastly-kv-store-adapter', 'provider-fastly');
|
|
48
|
+
}
|
|
49
|
+
if (capability === 'assets' || capability.startsWith('assets.')) {
|
|
50
|
+
return blockedRestriction(capability, restrictions.assets)
|
|
51
|
+
|| decision(capability, 'eligible', 'fastly-assets-kv-adapter', 'provider-fastly');
|
|
52
|
+
}
|
|
53
|
+
if (
|
|
54
|
+
capability === 'broadcaster'
|
|
55
|
+
|| capability === 'channel'
|
|
56
|
+
|| capability === 'grip'
|
|
57
|
+
|| capability.startsWith('grip.')
|
|
58
|
+
) {
|
|
59
|
+
return blockedRestriction(capability, restrictions.grip)
|
|
60
|
+
|| decision(capability, 'eligible', 'fastly-grip-broadcast-adapter', 'provider-fastly');
|
|
61
|
+
}
|
|
62
|
+
if (
|
|
63
|
+
capability === 'body'
|
|
64
|
+
|| capability === 'headers'
|
|
65
|
+
|| capability === 'json'
|
|
66
|
+
|| capability === 'opaque.pass-through'
|
|
67
|
+
|| capability === 'result'
|
|
68
|
+
|| capability.startsWith('result.')
|
|
69
|
+
|| capability === 'parallel'
|
|
70
|
+
|| capability.startsWith('parallel.')
|
|
71
|
+
|| capability === 'logging'
|
|
72
|
+
|| capability === 'log'
|
|
73
|
+
|| capability.startsWith('log.')
|
|
74
|
+
) {
|
|
75
|
+
return decision(capability, 'eligible', 'fastly-shared-javascript-runtime', 'runtime');
|
|
76
|
+
}
|
|
77
|
+
if (capability === 'clock' || capability === 'timer') {
|
|
78
|
+
return decision(capability, 'pending', 'fastly-javascript-clock-timer-pending', 'runtime');
|
|
79
|
+
}
|
|
80
|
+
if (capability === 'time.wall-clock') {
|
|
81
|
+
return decision(capability, 'eligible', 'fastly-javascript-provider-wall-clock-authority', 'provider-fastly');
|
|
82
|
+
}
|
|
83
|
+
if (
|
|
84
|
+
capability === 'jwt.verify'
|
|
85
|
+
|| capability === 'jwt.verify.hs256'
|
|
86
|
+
|| capability === 'jwt.verify.es256'
|
|
87
|
+
) {
|
|
88
|
+
return blockedRestriction(capability, restrictions.jwt)
|
|
89
|
+
|| decision(capability, 'eligible', 'fastly-javascript-jwt-crypto-runtime-builtin', 'provider-fastly');
|
|
90
|
+
}
|
|
91
|
+
if (capability.startsWith('jwt.verify.')) {
|
|
92
|
+
return decision(capability, 'blocked', 'jwt-crypto-realization-unavailable', 'crypto');
|
|
93
|
+
}
|
|
94
|
+
if (capability === 'event.ingress') {
|
|
95
|
+
return decision(capability, 'blocked', 'fastly-event-ingress-unavailable', 'provider-fastly');
|
|
96
|
+
}
|
|
97
|
+
if (capability === 'event.emit') {
|
|
98
|
+
return decision(capability, 'blocked', 'fastly-event-emit-unavailable', 'provider-fastly');
|
|
99
|
+
}
|
|
100
|
+
return decision(capability, 'blocked', 'unknown-fastly-javascript-capability-fail-closed', 'compiler');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function classifyFastlyJavascriptProviderRequirement(id, restrictions = {}) {
|
|
104
|
+
const requirement = String(id);
|
|
105
|
+
if (['kv.getVersioned', 'kv.insertIfAbsent', 'kv.compareAndSwap'].includes(requirement)) return decision(requirement, 'blocked', 'fastly-conditional-kv-incomplete', 'provider-fastly');
|
|
106
|
+
if (['s3.head', 's3.getText', 's3.putText'].includes(requirement)) return decision(requirement, 'blocked', 'fastly-javascript-s3-raw-headers-unavailable', 'provider-fastly');
|
|
107
|
+
if (requirement === 'request' || ['response.json', 'response.text', 'response.custom'].includes(requirement)) {
|
|
108
|
+
return decision(requirement, 'eligible', 'fastly-request-response-lifecycle', 'provider-fastly');
|
|
109
|
+
}
|
|
110
|
+
if (requirement === 'fetch' || requirement === 'opaque.pass-through' || ['body', 'headers', 'result'].includes(requirement)) {
|
|
111
|
+
return blockedRestriction(requirement, restrictions.fetch)
|
|
112
|
+
|| decision(requirement, 'eligible', 'fastly-fetch-adapter', 'provider-fastly');
|
|
113
|
+
}
|
|
114
|
+
if (requirement === 'config.get') {
|
|
115
|
+
return blockedRestriction(requirement, restrictions.config)
|
|
116
|
+
|| decision(requirement, 'eligible', 'fastly-config-store-adapter', 'provider-fastly');
|
|
117
|
+
}
|
|
118
|
+
if (requirement === 'secret.get') {
|
|
119
|
+
return blockedRestriction(requirement, restrictions.secret)
|
|
120
|
+
|| decision(requirement, 'eligible', 'fastly-secret-store-adapter', 'provider-fastly');
|
|
121
|
+
}
|
|
122
|
+
if (requirement === 'kv' || requirement === 'kv.get' || requirement === 'kv.put') {
|
|
123
|
+
return blockedRestriction(requirement, restrictions.kv)
|
|
124
|
+
|| decision(requirement, 'eligible', 'fastly-kv-store-adapter', 'provider-fastly');
|
|
125
|
+
}
|
|
126
|
+
if (requirement === 'assets' || requirement.startsWith('assets.')) {
|
|
127
|
+
return blockedRestriction(requirement, restrictions.assets)
|
|
128
|
+
|| decision(requirement, 'eligible', 'fastly-assets-kv-adapter', 'provider-fastly');
|
|
129
|
+
}
|
|
130
|
+
if (
|
|
131
|
+
['broadcaster', 'channel'].includes(requirement)
|
|
132
|
+
|| requirement === 'grip'
|
|
133
|
+
|| requirement.startsWith('grip.')
|
|
134
|
+
) {
|
|
135
|
+
return blockedRestriction(requirement, restrictions.grip)
|
|
136
|
+
|| decision(requirement, 'eligible', 'fastly-grip-broadcast-adapter', 'provider-fastly');
|
|
137
|
+
}
|
|
138
|
+
if (requirement.startsWith('schema.')) {
|
|
139
|
+
return decision(requirement, 'eligible', 'fastly-shared-schema-boundaries', 'runtime');
|
|
140
|
+
}
|
|
141
|
+
if (requirement === 'clock') {
|
|
142
|
+
return decision(requirement, 'pending', 'fastly-javascript-clock-timer-pending', 'runtime');
|
|
143
|
+
}
|
|
144
|
+
if (requirement === 'time.wall-clock') {
|
|
145
|
+
return decision(requirement, 'eligible', 'fastly-javascript-provider-wall-clock-authority', 'provider-fastly');
|
|
146
|
+
}
|
|
147
|
+
if (
|
|
148
|
+
requirement === 'jwt.verify'
|
|
149
|
+
|| requirement === 'jwt.verify.hs256'
|
|
150
|
+
|| requirement === 'jwt.verify.es256'
|
|
151
|
+
) {
|
|
152
|
+
return blockedRestriction(requirement, restrictions.jwt)
|
|
153
|
+
|| decision(requirement, 'eligible', 'fastly-javascript-jwt-crypto-runtime-builtin', 'provider-fastly');
|
|
154
|
+
}
|
|
155
|
+
if (requirement.startsWith('jwt.verify.')) {
|
|
156
|
+
return decision(requirement, 'blocked', 'jwt-crypto-realization-unavailable', 'crypto');
|
|
157
|
+
}
|
|
158
|
+
if (requirement === 'event.ingress') {
|
|
159
|
+
return decision(requirement, 'blocked', 'fastly-event-ingress-unavailable', 'provider-fastly');
|
|
160
|
+
}
|
|
161
|
+
if (requirement === 'event.emit') {
|
|
162
|
+
return decision(requirement, 'blocked', 'fastly-event-emit-unavailable', 'provider-fastly');
|
|
163
|
+
}
|
|
164
|
+
return decision(requirement, 'blocked', 'unknown-fastly-provider-requirement-fail-closed', 'compiler');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function restriction(reasonId, configuration) {
|
|
168
|
+
return Object.freeze({ reasonId, owner: 'provider-fastly', configuration });
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function fastlyJavascriptProjectRestrictions(compiled, project) {
|
|
172
|
+
const bindings = project.providerConfig && project.providerConfig.bindings || {};
|
|
173
|
+
const backends = bindings.backends && typeof bindings.backends === 'object' ? bindings.backends : {};
|
|
174
|
+
const kv = bindings.kv && typeof bindings.kv === 'object' ? bindings.kv : {};
|
|
175
|
+
const sites = compiled.metadata.effectSites || [];
|
|
176
|
+
const fetchSites = sites.filter((entry) => entry.kind === 'fetch');
|
|
177
|
+
const kvSites = sites.filter((entry) => entry.kind === 'kv.get' || entry.kind === 'kv.put');
|
|
178
|
+
const assetSites = sites.filter((entry) => entry.contractId === 'pulse.assets' && entry.operation === 'lookup');
|
|
179
|
+
const gripSites = sites.filter((entry) => entry.contractId === 'pulse.grip' && entry.operation === 'broadcast');
|
|
180
|
+
const configSites = sites.filter((entry) => entry.kind === 'config.get');
|
|
181
|
+
const secretSites = sites.filter((entry) => entry.kind === 'secret.get');
|
|
182
|
+
const jwtSites = sites.filter((entry) => (
|
|
183
|
+
entry.contractId === 'pulse.jwt'
|
|
184
|
+
&& (entry.operation === 'verify' || entry.kind === 'jwt.verify')
|
|
185
|
+
));
|
|
186
|
+
const output = {};
|
|
187
|
+
|
|
188
|
+
if (configSites.length > 0 && !(typeof bindings.configStore === 'string' && bindings.configStore.trim())) {
|
|
189
|
+
output.config = restriction('fastly-config-store-binding-required', 'bindings.configStore');
|
|
190
|
+
}
|
|
191
|
+
const grip = bindings.grip && typeof bindings.grip === 'object' ? bindings.grip : {};
|
|
192
|
+
const gripSecretRequired = gripSites.length > 0 && grip.authentication && grip.authentication.secretRef;
|
|
193
|
+
if ((secretSites.length > 0 || gripSecretRequired) && !(typeof bindings.secretStore === 'string' && bindings.secretStore.trim())) {
|
|
194
|
+
output.secret = restriction('fastly-secret-store-binding-required', 'bindings.secretStore');
|
|
195
|
+
}
|
|
196
|
+
if (jwtSites.length > 0 && !(typeof bindings.secretStore === 'string' && bindings.secretStore.trim())) {
|
|
197
|
+
output.jwt = restriction('fastly-jwt-secret-store-binding-required', 'bindings.secretStore');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
for (const site of fetchSites) {
|
|
201
|
+
const resource = site.resource || {};
|
|
202
|
+
if (resource.kind === 'literal') {
|
|
203
|
+
if (!resource.origin) {
|
|
204
|
+
output.fetch = restriction('fastly-fetch-url-invalid', 'ctx.fetch');
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
if (!(typeof backends[resource.origin] === 'string' && backends[resource.origin].trim()) && bindings.dynamicBackends !== true) {
|
|
208
|
+
output.fetch = restriction('fastly-fetch-backend-binding-required', `bindings.backends.${resource.origin}`);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
} else if (resource.kind === 'dynamic' && bindings.dynamicBackends !== true && Object.keys(backends).length === 0) {
|
|
212
|
+
output.fetch = restriction('fastly-dynamic-fetch-backend-policy-required', 'bindings.backends');
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (const site of kvSites) {
|
|
218
|
+
const resource = site.resource || {};
|
|
219
|
+
if (resource.kind !== 'literal') {
|
|
220
|
+
output.kv = restriction('fastly-dynamic-kv-namespace-unsupported', 'bindings.kv');
|
|
221
|
+
break;
|
|
222
|
+
}
|
|
223
|
+
const namespace = String(resource.value || '');
|
|
224
|
+
if (!(typeof kv[namespace] === 'string' && kv[namespace].trim())) {
|
|
225
|
+
output.kv = restriction('fastly-kv-binding-required', `bindings.kv.${namespace}`);
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
for (const site of assetSites) {
|
|
231
|
+
const store = site.payload && typeof site.payload.store === 'string' ? site.payload.store : '';
|
|
232
|
+
if (!store || !(typeof kv[store] === 'string' && kv[store].trim())) {
|
|
233
|
+
output.assets = restriction('fastly-assets-binding-required', store ? `bindings.kv.${store}` : 'bindings.kv');
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (gripSites.length > 0) {
|
|
239
|
+
const endpointValue = grip.publishEndpoint || grip.publishUrl;
|
|
240
|
+
let endpoint;
|
|
241
|
+
try { endpoint = new URL(String(endpointValue || '')); }
|
|
242
|
+
catch (_) {
|
|
243
|
+
output.grip = restriction('fastly-grip-publish-endpoint-required', 'bindings.grip.publishEndpoint');
|
|
244
|
+
}
|
|
245
|
+
if (endpoint && !['http:', 'https:'].includes(endpoint.protocol)) {
|
|
246
|
+
output.grip = restriction('fastly-grip-publish-endpoint-invalid', 'bindings.grip.publishEndpoint');
|
|
247
|
+
}
|
|
248
|
+
if (endpoint && !output.grip) {
|
|
249
|
+
const mapped = typeof backends[endpoint.origin] === 'string' && backends[endpoint.origin].trim();
|
|
250
|
+
const explicit = typeof grip.publishBackend === 'string' && grip.publishBackend.trim();
|
|
251
|
+
if (!mapped && !explicit && bindings.dynamicBackends !== true) {
|
|
252
|
+
output.grip = restriction('fastly-grip-publish-backend-required', 'bindings.grip.publishBackend');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return Object.freeze(output);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
module.exports = Object.freeze({
|
|
261
|
+
classifyFastlyJavascriptCapability,
|
|
262
|
+
classifyFastlyJavascriptProviderRequirement,
|
|
263
|
+
fastlyJavascriptProjectRestrictions
|
|
264
|
+
});
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { normalizeJavascriptTargetDescriptor } = require('@pulse-compute/wasm-contracts/project/javascript-application');
|
|
4
|
+
const { defineCryptoTargetCapabilities } = require('@pulse-compute/wasm-contracts/crypto/contracts');
|
|
5
|
+
|
|
6
|
+
const FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR = normalizeJavascriptTargetDescriptor({
|
|
7
|
+
provider: 'fastly',
|
|
8
|
+
targetId: 'fastly-javascript',
|
|
9
|
+
status: 'provider-runtime-ready',
|
|
10
|
+
hostBridge: true,
|
|
11
|
+
applicationLoader: true,
|
|
12
|
+
requestAdapter: true,
|
|
13
|
+
lifecycle: true,
|
|
14
|
+
crypto: defineCryptoTargetCapabilities({
|
|
15
|
+
target: 'javascript',
|
|
16
|
+
algorithms: [{
|
|
17
|
+
algorithm: 'HS256',
|
|
18
|
+
realization: 'runtime-builtin',
|
|
19
|
+
implemented: true,
|
|
20
|
+
status: 'implemented-c2'
|
|
21
|
+
}, {
|
|
22
|
+
algorithm: 'ES256',
|
|
23
|
+
realization: 'runtime-builtin',
|
|
24
|
+
implemented: true,
|
|
25
|
+
status: 'implemented-h4'
|
|
26
|
+
}]
|
|
27
|
+
}),
|
|
28
|
+
capabilities: {
|
|
29
|
+
version: 'pulse.javascript-capability-envelope.v1',
|
|
30
|
+
provider: 'fastly',
|
|
31
|
+
status: 'request-lifecycle-ready',
|
|
32
|
+
core: {
|
|
33
|
+
request: true,
|
|
34
|
+
response: true,
|
|
35
|
+
router: true,
|
|
36
|
+
state: true,
|
|
37
|
+
middleware: true,
|
|
38
|
+
schemas: true,
|
|
39
|
+
logging: true
|
|
40
|
+
},
|
|
41
|
+
effects: {
|
|
42
|
+
fetch: true,
|
|
43
|
+
config: true,
|
|
44
|
+
secret: true,
|
|
45
|
+
kv: true,
|
|
46
|
+
parallel: true
|
|
47
|
+
},
|
|
48
|
+
packages: ['pulse.assets', 'pulse.grip', 'pulse.jwt'],
|
|
49
|
+
restrictions: {
|
|
50
|
+
fetch: 'origin-backend-map-or-dynamic-opt-in',
|
|
51
|
+
kv: 'logical-store-map-required',
|
|
52
|
+
assets: 'logical-store-to-kv-map-required',
|
|
53
|
+
grip: 'publish-endpoint-and-backend-or-dynamic-opt-in'
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
reporting: {
|
|
57
|
+
supported: true,
|
|
58
|
+
default: 'info',
|
|
59
|
+
levels: ['off', 'error', 'warn', 'info', 'debug'],
|
|
60
|
+
destination: 'provider-owned',
|
|
61
|
+
betaDefault: 'stdio-log-tail'
|
|
62
|
+
},
|
|
63
|
+
commands: {
|
|
64
|
+
compile: true,
|
|
65
|
+
inspect: true,
|
|
66
|
+
doctor: true,
|
|
67
|
+
build: true,
|
|
68
|
+
test: true,
|
|
69
|
+
dev: true
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
module.exports = Object.freeze({ FASTLY_JAVASCRIPT_TARGET_DESCRIPTOR });
|