@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,215 @@
|
|
|
1
|
+
// Provider-owned lifecycle and host ABI. Protocol algorithms are S3-owned.
|
|
2
|
+
@external('fastly_async_io', 'select') declare function __s3_select(handles: usize, count: i32, timeout: i32, done: usize): i32
|
|
3
|
+
@external('fastly_http_req', 'pending_req_poll_v2') declare function __s3_poll(pending: i32, detail: usize, done: usize, response: usize, body: usize): i32
|
|
4
|
+
@external('fastly_http_req', 'cache_override_set') declare function __s3_cache(request: i32, tag: i32, ttl: i32, swr: i32): i32
|
|
5
|
+
@external('fastly_http_req', 'auto_decompress_response_set') declare function __s3_decompress(request: i32, encodings: i32): i32
|
|
6
|
+
@external('fastly_http_req', 'close') declare function __s3_close_req(request: i32): i32
|
|
7
|
+
@external('fastly_http_resp', 'close') declare function __s3_close_resp(response: i32): i32
|
|
8
|
+
@external('fastly_http_body', 'close') declare function __s3_close_body(body: i32): i32
|
|
9
|
+
@external('fastly_http_resp', 'header_names_get') declare function __s3_header_names(response: i32, buffer: usize, size: i32, cursor: i32, end: usize, written: usize): i32
|
|
10
|
+
@external('fastly_http_resp', 'header_values_get') declare function __s3_header_values(response: i32, name: usize, length: i32, buffer: usize, size: i32, cursor: i32, end: usize, written: usize): i32
|
|
11
|
+
|
|
12
|
+
class __PulseS3Binding {
|
|
13
|
+
contentType: string = ''; endpoint: string = ''; bucket: string = ''; region: string = ''; backend: string = '';
|
|
14
|
+
id: string = ''; secret: string = ''; token: string = ''; max: i32 = 32768; timeout: i32 = 10000;
|
|
15
|
+
}
|
|
16
|
+
@lazy const __s3_dispatched = new StaticArray<bool>(PULSE_FASTLY_EFFECT_COUNT)
|
|
17
|
+
@lazy const __s3_sent_bytes = new StaticArray<i32>(PULSE_FASTLY_EFFECT_COUNT)
|
|
18
|
+
@lazy const __s3_digests = new Array<string>(PULSE_FASTLY_EFFECT_COUNT).fill('')
|
|
19
|
+
@lazy const __s3_deadlines = new StaticArray<i64>(PULSE_FASTLY_EFFECT_COUNT)
|
|
20
|
+
function __s3_clock(id: i32): i64 {
|
|
21
|
+
const out = new StaticArray<i64>(1);
|
|
22
|
+
return wasi_snapshot_preview1_clock_time_get(id, 1000000, changetype<usize>(out)) == 0 ? out[0] : -1;
|
|
23
|
+
}
|
|
24
|
+
function __s3_remaining(index: i32): i32 {
|
|
25
|
+
const now = __s3_clock(1);
|
|
26
|
+
if (now < 0) return 0;
|
|
27
|
+
const ns = __s3_deadlines[index] - now;
|
|
28
|
+
return ns <= 0 ? 0 : i32((ns + 999999) / 1000000);
|
|
29
|
+
}
|
|
30
|
+
function __s3_set(object: i32, name: string, value: i32): void { host_value_object_set(object, __pulse_fastly_string_value(name), value) }
|
|
31
|
+
function __s3_result(status: string, reason: string = '', http: i32 = 0): i32 {
|
|
32
|
+
const result = host_value_object(); __s3_set(result, 'status', __pulse_fastly_string_value(status));
|
|
33
|
+
if (reason.length) __s3_set(result, 'reason', __pulse_fastly_string_value(reason));
|
|
34
|
+
if (http > 0) { const value = new __PulseFastlyValue(); value.kind = PULSE_VALUE_NUMBER; value.number = f64(http); __s3_set(result, 'httpStatus', __pulse_fastly_put(value)); }
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function __s3_failure(index: i32, reason: string, http: i32 = 0): i32 {
|
|
38
|
+
return __s3_result(__pulse_fastly_effect_kind(index) == 14 ? (__s3_dispatched[index] ? 'unknown' : 'not-stored') : 'failed', reason, http);
|
|
39
|
+
}
|
|
40
|
+
function __s3_fail(index: i32, reason: string): void { __pulse_fastly_ready_effect(index, __s3_failure(index, reason)) }
|
|
41
|
+
function __s3_secret(store: i32, name: string): string | null {
|
|
42
|
+
const key = __pulse_s3_bytes(name), out = new StaticArray<i32>(1), size = new StaticArray<i32>(1), bytes = new Uint8Array(4096);
|
|
43
|
+
if (fastly_secret_store_get(store, key.dataStart, key.length, changetype<usize>(out)) != 0) return null;
|
|
44
|
+
const status = fastly_secret_store_plaintext(out[0], bytes.dataStart, bytes.length, changetype<usize>(size));
|
|
45
|
+
let result: string | null = null;
|
|
46
|
+
if (status == 0 && size[0] > 0 && size[0] <= bytes.length) {
|
|
47
|
+
const raw = bytes.subarray(0, size[0]);
|
|
48
|
+
if (__pulse_s3_utf8_valid(raw)) result = String.UTF8.decodeUnsafe(raw.dataStart, raw.length, false);
|
|
49
|
+
}
|
|
50
|
+
bytes.fill(0);
|
|
51
|
+
if (result !== null) __pulse_fastly_remember_secret(result);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
function __s3_header(request: i32, name: string, value: string): bool {
|
|
55
|
+
const n = __pulse_s3_bytes(name), v = __pulse_s3_bytes(value);
|
|
56
|
+
return fastly_http_req_header_insert(request, n.dataStart, n.length, v.dataStart, v.length) == 0;
|
|
57
|
+
}
|
|
58
|
+
function __pulse_fastly_s3_begin(index: i32, outer: __PulseFastlyValue): void {
|
|
59
|
+
__s3_dispatched[index] = false; __s3_sent_bytes[index] = 0; __s3_digests[index] = '';
|
|
60
|
+
const put = __pulse_fastly_effect_kind(index) == 14;
|
|
61
|
+
const payload = __pulse_fastly_value(__pulse_fastly_payload_field(outer, 'invocation'));
|
|
62
|
+
const input = __pulse_fastly_value(__pulse_fastly_payload_field(payload, 'key'));
|
|
63
|
+
if (input.kind != PULSE_VALUE_STRING) { __s3_fail(index, 'invalid-key'); return; }
|
|
64
|
+
const encoded = __pulse_s3_key(input.text);
|
|
65
|
+
if (encoded === null) { __s3_fail(index, 'invalid-key'); return; }
|
|
66
|
+
// Package effect payloads and signed paths must not enter provider logs.
|
|
67
|
+
__pulse_fastly_remember_secret(input.text);
|
|
68
|
+
const binding = __pulse_fastly_s3_binding(index), start = __s3_clock(1);
|
|
69
|
+
if (start < 0) { __s3_fail(index, 'configuration'); return; }
|
|
70
|
+
__s3_deadlines[index] = start + i64(binding.timeout) * 1000000;
|
|
71
|
+
let data = new Uint8Array(0);
|
|
72
|
+
if (put) {
|
|
73
|
+
const text = __pulse_fastly_value(__pulse_fastly_payload_field(payload, 'text'));
|
|
74
|
+
if (text.kind != PULSE_VALUE_STRING || !__pulse_s3_scalar(text.text)) { __s3_fail(index, 'invalid-text'); return; }
|
|
75
|
+
data = __pulse_s3_bytes(text.text);
|
|
76
|
+
if (data.length > binding.max) { __s3_fail(index, 'too-large'); return; }
|
|
77
|
+
__pulse_fastly_remember_secret(text.text);
|
|
78
|
+
}
|
|
79
|
+
const storeName = __pulse_s3_bytes(__pulse_fastly_secret_store(index)), store = new StaticArray<i32>(1);
|
|
80
|
+
if (fastly_secret_store_open(storeName.dataStart, storeName.length, changetype<usize>(store)) != 0) { __s3_fail(index, 'credentials'); return; }
|
|
81
|
+
const id = __s3_secret(store[0], binding.id), secret = __s3_secret(store[0], binding.secret);
|
|
82
|
+
const token = binding.token.length ? __s3_secret(store[0], binding.token) : '';
|
|
83
|
+
if (__s3_remaining(index) == 0) { __s3_fail(index, 'timeout'); return; }
|
|
84
|
+
if (id === null || secret === null || token === null || !__pulse_s3_credentials(id, secret, token)) { __s3_fail(index, 'credentials'); return; }
|
|
85
|
+
const method = put ? 'PUT' : __pulse_fastly_effect_kind(index) == 12 ? 'HEAD' : 'GET', path = '/' + binding.bucket + '/' + encoded;
|
|
86
|
+
const now = __s3_clock(0);
|
|
87
|
+
if (now < 0 || !__pulse_s3_date(now / 1000000000).length) { __s3_fail(index, 'configuration'); return; }
|
|
88
|
+
const signature = __pulse_s3_sign(method, path, binding.endpoint.slice(8), binding.region, id, secret, token, now / 1000000000, data, binding.contentType);
|
|
89
|
+
__s3_sent_bytes[index] = data.length; __s3_digests[index] = signature.digest;
|
|
90
|
+
__pulse_fastly_remember_secret(signature.digest);
|
|
91
|
+
__pulse_fastly_remember_secret(signature.authorization); __pulse_fastly_remember_secret(binding.endpoint + path);
|
|
92
|
+
if (__s3_remaining(index) == 0) { __s3_fail(index, 'timeout'); return; }
|
|
93
|
+
const request = new StaticArray<i32>(1), body = new StaticArray<i32>(1), pending = new StaticArray<i32>(1);
|
|
94
|
+
if (fastly_http_req_new(changetype<usize>(request)) != 0) { __s3_fail(index, 'transport'); return; }
|
|
95
|
+
const req = request[0], url = __pulse_s3_bytes(binding.endpoint + path), verb = __pulse_s3_bytes(method), backend = __pulse_s3_bytes(binding.backend);
|
|
96
|
+
let ok = fastly_http_req_uri_set(req, url.dataStart, url.length) == 0 && fastly_http_req_method_set(req, verb.dataStart, verb.length) == 0
|
|
97
|
+
&& __s3_cache(req, 1, 0, 0) == 0 && __s3_decompress(req, 0) == 0
|
|
98
|
+
&& __s3_header(req, 'host', binding.endpoint.slice(8)) && __s3_header(req, 'x-amz-date', signature.date)
|
|
99
|
+
&& __s3_header(req, 'x-amz-content-sha256', signature.digest) && __s3_header(req, 'authorization', signature.authorization)
|
|
100
|
+
&& __s3_header(req, 'accept-encoding', 'identity');
|
|
101
|
+
if (ok && put) ok = __s3_header(req, 'content-type', binding.contentType) && __s3_header(req, 'content-length', data.length.toString());
|
|
102
|
+
if (ok && token.length) ok = __s3_header(req, 'x-amz-security-token', token);
|
|
103
|
+
if (!ok || fastly_http_body_new(changetype<usize>(body)) != 0) { __s3_close_req(req); __s3_fail(index, 'transport'); return; }
|
|
104
|
+
let offset = 0; const written = new StaticArray<i32>(1);
|
|
105
|
+
while (offset < data.length) {
|
|
106
|
+
if (__s3_remaining(index) == 0) { __s3_close_req(req); __s3_close_body(body[0]); __s3_fail(index, 'timeout'); return; }
|
|
107
|
+
if (fastly_http_body_write(body[0], data.dataStart + offset, data.length - offset, 0, changetype<usize>(written)) != 0 || written[0] <= 0 || written[0] > data.length - offset) {
|
|
108
|
+
__s3_close_req(req); __s3_close_body(body[0]); __s3_fail(index, 'transport'); return;
|
|
109
|
+
}
|
|
110
|
+
offset += written[0];
|
|
111
|
+
}
|
|
112
|
+
if (__s3_remaining(index) == 0) { __s3_close_req(req); __s3_close_body(body[0]); __s3_fail(index, 'timeout'); return; }
|
|
113
|
+
__s3_dispatched[index] = true;
|
|
114
|
+
if (fastly_http_req_send_async(req, body[0], backend.dataStart, backend.length, changetype<usize>(pending)) != 0) {
|
|
115
|
+
__s3_close_req(req); __s3_close_body(body[0]); __s3_fail(index, 'transport'); return;
|
|
116
|
+
}
|
|
117
|
+
// send_async consumes request/body. Pending handles have no cancel hostcall.
|
|
118
|
+
__pulse_fastly_pending[index] = pending[0]; __pulse_fastly_pending_mode[index] = PULSE_FASTLY_PENDING_ASYNC;
|
|
119
|
+
}
|
|
120
|
+
function __s3_wait_ready(index: i32, handle: i32): i32 {
|
|
121
|
+
const timeout = __s3_remaining(index); if (timeout == 0) return 0;
|
|
122
|
+
const handles = new StaticArray<i32>(1), done = new StaticArray<i32>(1); handles[0] = handle;
|
|
123
|
+
if (__s3_select(changetype<usize>(handles), 1, timeout, changetype<usize>(done)) != 0) return -1;
|
|
124
|
+
return done[0] == -1 || __s3_remaining(index) == 0 ? 0 : 1;
|
|
125
|
+
}
|
|
126
|
+
function __s3_list(buffer: Uint8Array, size: i32): Array<string> | null {
|
|
127
|
+
if (size < 0 || size > buffer.length || (size > 0 && buffer[size - 1] != 0)) return null;
|
|
128
|
+
const result = new Array<string>(); let start = 0;
|
|
129
|
+
for (let i = 0; i < size; i++) if (buffer[i] == 0) {
|
|
130
|
+
const bytes = buffer.subarray(start, i); if (!__pulse_s3_utf8_valid(bytes)) return null;
|
|
131
|
+
result.push(String.UTF8.decodeUnsafe(bytes.dataStart, bytes.length, false)); start = i + 1;
|
|
132
|
+
}
|
|
133
|
+
return result;
|
|
134
|
+
}
|
|
135
|
+
function __s3_read_response(index: i32, response: i32, body: i32, status: i32): i32 {
|
|
136
|
+
const put = __pulse_fastly_effect_kind(index) == 14;
|
|
137
|
+
const rejected = put && status >= 400 && status <= 499 && status != 408;
|
|
138
|
+
if (!put && status == 404) return __s3_result('not-found');
|
|
139
|
+
if (status != 200 && !rejected) return __s3_failure(index, __pulse_s3_status_reason(status), status);
|
|
140
|
+
const buffer = new Uint8Array(16384), end = new StaticArray<i64>(1), size = new StaticArray<i32>(1);
|
|
141
|
+
if (__s3_header_names(response, buffer.dataStart, buffer.length, 0, changetype<usize>(end), changetype<usize>(size)) != 0 || end[0] >= 0) return __s3_failure(index, 'protocol', status);
|
|
142
|
+
const names = __s3_list(buffer, size[0]); if (names === null) return __s3_failure(index, 'protocol', status);
|
|
143
|
+
let total = 0, length: f64 = -1; const seen = new Set<string>();
|
|
144
|
+
const result = __s3_result(put ? 'stored' : 'found');
|
|
145
|
+
for (let i = 0; i < names.length; i++) {
|
|
146
|
+
const rawName = names[i], name = rawName.toLowerCase(), bytes = __pulse_s3_bytes(rawName);
|
|
147
|
+
if (__s3_header_values(response, bytes.dataStart, bytes.length, buffer.dataStart, buffer.length, 0, changetype<usize>(end), changetype<usize>(size)) != 0 || end[0] >= 0) return __s3_failure(index, 'protocol', status);
|
|
148
|
+
const values = __s3_list(buffer, size[0]); if (values === null) return __s3_failure(index, 'protocol', status);
|
|
149
|
+
const selected = name == 'content-length' || name == 'content-type' || name == 'etag' || name == 'content-encoding';
|
|
150
|
+
if (selected && (seen.has(name) || values.length != 1)) return __s3_failure(index, 'protocol', status);
|
|
151
|
+
seen.add(name);
|
|
152
|
+
for (let v = 0; v < values.length; v++) {
|
|
153
|
+
const value = values[v], count = __pulse_s3_bytes(value).length;
|
|
154
|
+
total += bytes.length + count + 4; if (total > 16384) return __s3_failure(index, 'protocol', status);
|
|
155
|
+
if (!selected) continue;
|
|
156
|
+
if (count > 1024 || !__pulse_s3_scalar(value, true)) return __s3_failure(index, 'protocol', status);
|
|
157
|
+
if (name == 'content-encoding' && value.toLowerCase() != 'identity') return __s3_failure(index, 'protocol', status);
|
|
158
|
+
if (name == 'content-length') {
|
|
159
|
+
if (!value.length || (value.length > 1 && value.charCodeAt(0) == 48)) return __s3_failure(index, 'protocol', status);
|
|
160
|
+
length = 0;
|
|
161
|
+
for (let c = 0; c < value.length; c++) { const digit = value.charCodeAt(c) - 48; if (digit < 0 || digit > 9) return __s3_failure(index, 'protocol', status); length = length * 10 + digit; if (length > 9007199254740991) return __s3_failure(index, 'protocol', status); }
|
|
162
|
+
}
|
|
163
|
+
if (name == 'etag') { if (!value.length) return __s3_failure(index, 'protocol', status); __s3_set(result, 'etag', __pulse_fastly_string_value(value)); }
|
|
164
|
+
if (name == 'content-type' && !put) __s3_set(result, 'contentType', __pulse_fastly_string_value(value));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (__s3_remaining(index) == 0) return __s3_failure(index, 'timeout', status);
|
|
168
|
+
const head = __pulse_fastly_effect_kind(index) == 12, binding = __pulse_fastly_s3_binding(index);
|
|
169
|
+
if (head && length < 0) return __s3_failure(index, 'protocol', status);
|
|
170
|
+
if (!head) {
|
|
171
|
+
const maximum = put && !rejected ? 0 : binding.max;
|
|
172
|
+
if (length > maximum) return __s3_failure(index, put ? 'protocol' : 'too-large', status);
|
|
173
|
+
const data = new Uint8Array(maximum + 1); let count = 0;
|
|
174
|
+
while (true) {
|
|
175
|
+
const ready = __s3_wait_ready(index, body);
|
|
176
|
+
if (ready <= 0) return __s3_failure(index, ready == 0 ? 'timeout' : 'transport', status);
|
|
177
|
+
if (fastly_http_body_read(body, data.dataStart + count, data.length - count, changetype<usize>(size)) != 0) return __s3_failure(index, 'protocol', status);
|
|
178
|
+
if (size[0] < 0 || size[0] > data.length - count) return __s3_failure(index, 'protocol', status);
|
|
179
|
+
if (size[0] == 0) break;
|
|
180
|
+
count += size[0]; if (count > maximum) return __s3_failure(index, put ? 'protocol' : 'too-large', status);
|
|
181
|
+
}
|
|
182
|
+
if (length >= 0 && length != count) return __s3_failure(index, 'protocol', status);
|
|
183
|
+
if (put) {
|
|
184
|
+
if (__s3_remaining(index) == 0) return __s3_failure(index, 'timeout', status);
|
|
185
|
+
if (rejected) return __s3_result('not-stored', status == 401 || status == 403 ? 'not-authorized' : status == 429 ? 'throttled' : 'rejected', status);
|
|
186
|
+
const sent = new __PulseFastlyValue(); sent.kind = PULSE_VALUE_NUMBER; sent.number = f64(__s3_sent_bytes[index]);
|
|
187
|
+
__s3_set(result, 'byteLength', __pulse_fastly_put(sent));
|
|
188
|
+
__s3_set(result, 'sha256', __pulse_fastly_string_value(__s3_digests[index]));
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
length = f64(count); const raw = data.subarray(0, count), digest = __pulse_s3_hex(__pulse_s3_sha(raw));
|
|
192
|
+
if (!__pulse_s3_utf8_valid(raw)) return __s3_failure(index, 'invalid-utf8', status);
|
|
193
|
+
__s3_set(result, 'text', __pulse_fastly_string_value(String.UTF8.decodeUnsafe(raw.dataStart, raw.length, false)));
|
|
194
|
+
__s3_set(result, 'sha256', __pulse_fastly_string_value(digest));
|
|
195
|
+
}
|
|
196
|
+
if (__s3_remaining(index) == 0) return __s3_failure(index, 'timeout', status);
|
|
197
|
+
const sizeValue = new __PulseFastlyValue(); sizeValue.kind = PULSE_VALUE_NUMBER; sizeValue.number = length;
|
|
198
|
+
__s3_set(result, 'byteLength', __pulse_fastly_put(sizeValue)); return result;
|
|
199
|
+
}
|
|
200
|
+
function __pulse_fastly_s3_wait(index: i32): i32 {
|
|
201
|
+
if (__pulse_fastly_pending_mode[index] == PULSE_FASTLY_PENDING_READY) return __pulse_fastly_wait_ready(index);
|
|
202
|
+
const pending = __pulse_fastly_pending[index], detail = new StaticArray<i32>(4), done = new StaticArray<i32>(1);
|
|
203
|
+
const response = new StaticArray<i32>(1), body = new StaticArray<i32>(1), code = new StaticArray<i32>(1);
|
|
204
|
+
__pulse_fastly_pending_mode[index] = PULSE_FASTLY_PENDING_NONE; __pulse_fastly_pending[index] = 0;
|
|
205
|
+
while (true) {
|
|
206
|
+
const ready = __s3_wait_ready(index, pending);
|
|
207
|
+
if (ready <= 0) return __s3_failure(index, ready == 0 ? 'timeout' : 'transport');
|
|
208
|
+
if (__s3_poll(pending, changetype<usize>(detail), changetype<usize>(done), changetype<usize>(response), changetype<usize>(body)) != 0) return __s3_failure(index, 'transport');
|
|
209
|
+
if (done[0] != 0) break;
|
|
210
|
+
}
|
|
211
|
+
let result: i32;
|
|
212
|
+
if (fastly_http_resp_status_get(response[0], changetype<usize>(code)) != 0) result = __s3_failure(index, 'protocol');
|
|
213
|
+
else result = __s3_remaining(index) == 0 ? __s3_failure(index, 'timeout', code[0]) : __s3_read_response(index, response[0], body[0], code[0]);
|
|
214
|
+
__s3_close_body(body[0]); __s3_close_resp(response[0]); return result;
|
|
215
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('node:fs');
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { pulseS3AssemblyScriptSource } = require('@pulse-compute/s3/pulsewasm-native');
|
|
5
|
+
const S3_IMPORTS = Object.freeze([
|
|
6
|
+
'fastly_async_io:select', 'fastly_http_req:pending_req_poll_v2', 'fastly_http_req:cache_override_set',
|
|
7
|
+
'fastly_http_req:auto_decompress_response_set', 'fastly_http_req:close', 'fastly_http_resp:close', 'fastly_http_body:close',
|
|
8
|
+
'fastly_http_resp:header_names_get', 'fastly_http_resp:header_values_get', 'fastly_http_resp:status_get',
|
|
9
|
+
'fastly_http_req:new', 'fastly_http_req:method_set', 'fastly_http_req:uri_set', 'fastly_http_req:header_insert', 'fastly_http_req:send_async',
|
|
10
|
+
'fastly_http_body:new', 'fastly_http_body:read', 'fastly_http_body:write', 'fastly_secret_store:open', 'fastly_secret_store:get', 'fastly_secret_store:plaintext',
|
|
11
|
+
'wasi_snapshot_preview1:clock_time_get'
|
|
12
|
+
]);
|
|
13
|
+
function s3NativeSource(plan, bindings) {
|
|
14
|
+
if (!bindings.s3.length) return '';
|
|
15
|
+
const contribution = pulseS3AssemblyScriptSource();
|
|
16
|
+
for (const name of contribution.cryptoRequirements) {
|
|
17
|
+
const selected = plan.crypto && plan.crypto.algorithms.find((entry) => entry.algorithm === name);
|
|
18
|
+
if (!selected || selected.realization !== 'guest-source:pulse-hmac-as' || selected.implementation !== 'pulse-hmac-as.v1'
|
|
19
|
+
|| selected.kind !== 'guest-source' || selected.targetImplemented !== true || selected.automaticFallback !== false) throw new TypeError('Fastly S3 requires its exact selected Native Crypto algorithms.');
|
|
20
|
+
}
|
|
21
|
+
const lines = ['function __pulse_fastly_s3_binding(index: i32): __PulseS3Binding {', 'const value = new __PulseS3Binding();', 'switch (index) {'];
|
|
22
|
+
for (const binding of bindings.s3) {
|
|
23
|
+
lines.push(`case ${binding.index}:`);
|
|
24
|
+
for (const [field, input] of Object.entries({ contentType: 'contentType', endpoint: 'endpoint', bucket: 'bucket', region: 'region', backend: 'backend', id: 'accessKeyIdSecret', secret: 'secretAccessKeySecret', token: 'sessionTokenSecret' })) lines.push(`value.${field} = ${JSON.stringify(binding[input] || '')};`);
|
|
25
|
+
lines.push(`value.max = ${binding.maxTextBytes}; value.timeout = ${binding.timeoutMs}; break;`);
|
|
26
|
+
}
|
|
27
|
+
lines.push('default: unreachable();', '}', 'return value;', '}');
|
|
28
|
+
return [contribution.source, fs.readFileSync(path.join(__dirname, 's3-native.as.ts'), 'utf8'), lines.join('\n')].join('\n');
|
|
29
|
+
}
|
|
30
|
+
module.exports = { S3_IMPORTS, s3NativeSource };
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function loadAssetsContracts() {
|
|
4
|
+
try {
|
|
5
|
+
return require('@pulse-compute/wasm-contracts/assets/contracts');
|
|
6
|
+
} catch (error) {
|
|
7
|
+
if (error && error.code === 'MODULE_NOT_FOUND' && String(error.message).includes('@pulse-compute/wasm-contracts')) {
|
|
8
|
+
return require('../../../../wasm/packages/contracts/src/assets/contracts.js');
|
|
9
|
+
}
|
|
10
|
+
throw error;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function loadDiagnostics() {
|
|
15
|
+
try {
|
|
16
|
+
return require('@pulse-compute/wasm-contracts/diagnostics');
|
|
17
|
+
} catch (error) {
|
|
18
|
+
if (error && error.code === 'MODULE_NOT_FOUND' && String(error.message).includes('@pulse-compute/wasm-contracts')) {
|
|
19
|
+
return require('../../../../wasm/packages/contracts/src/diagnostics.js');
|
|
20
|
+
}
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const assetsContracts = loadAssetsContracts();
|
|
26
|
+
const { PACKAGE_VERSION, normalizeArtifact, normalizeDiagnostic } = loadDiagnostics();
|
|
27
|
+
const { buildFastlyAssetsProviderProof } = require('./assets-provider-proof.js');
|
|
28
|
+
const { buildFastlyAssetsProviderConfig } = require('../runtime/assets-provider.js');
|
|
29
|
+
|
|
30
|
+
const phaseName = 'fastly-assets-package-out-parity-proof';
|
|
31
|
+
|
|
32
|
+
function clone(value) {
|
|
33
|
+
if (Array.isArray(value)) return value.map(clone);
|
|
34
|
+
if (value && typeof value === 'object') return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, clone(entry)]));
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function normalize(input) {
|
|
39
|
+
return input && input.artifact && typeof input.artifact === 'object' ? input.artifact : input;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function makeDiagnostic(code, message, severity = 'error', details) {
|
|
43
|
+
return normalizeDiagnostic({
|
|
44
|
+
phase: phaseName,
|
|
45
|
+
severity,
|
|
46
|
+
code,
|
|
47
|
+
message,
|
|
48
|
+
hint: details && details.hint,
|
|
49
|
+
details,
|
|
50
|
+
loc: { file: '<fastly-assets-package-out-parity-proof>' }
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function check(name, passed, details, failures, diagnostics) {
|
|
55
|
+
const entry = { name, status: passed ? 'ok' : 'error', details: details || {} };
|
|
56
|
+
if (!passed) {
|
|
57
|
+
failures.push(entry);
|
|
58
|
+
diagnostics.push(makeDiagnostic(
|
|
59
|
+
assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_PACKAGE_OUT_PARITY_SMOKE_FAILED,
|
|
60
|
+
`Fastly assets package-out parity check failed: ${name}.`,
|
|
61
|
+
'error',
|
|
62
|
+
{ check: name, details: entry.details }
|
|
63
|
+
));
|
|
64
|
+
}
|
|
65
|
+
return entry;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function checkByName(proof, needle) {
|
|
69
|
+
const checks = proof && proof.smoke && Array.isArray(proof.smoke.checks) ? proof.smoke.checks : [];
|
|
70
|
+
return checks.some((entry) => entry && String(entry.name || '').includes(needle) && entry.status === 'ok');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function summaryFlag(proof, name) {
|
|
74
|
+
return Boolean(proof && proof.summary && proof.summary[name] === true);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function packageOutDiscovered(packageOutProof) {
|
|
78
|
+
return Boolean(packageOutProof && (
|
|
79
|
+
packageOutProof.discoveredFromNodeModules === true ||
|
|
80
|
+
(packageOutProof.discovery && packageOutProof.discovery.discoveredFromNodeModules === true) ||
|
|
81
|
+
(packageOutProof.summary && packageOutProof.summary.discoveredFromNodeModules === true)
|
|
82
|
+
));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function builderLoadedFromPackageOut(packageOutProof) {
|
|
86
|
+
const compilerBuilder = packageOutProof && packageOutProof.discovery && packageOutProof.discovery.compilerBuilder;
|
|
87
|
+
return Boolean(compilerBuilder &&
|
|
88
|
+
compilerBuilder.builderOwner === '@pulse-compute/assets' &&
|
|
89
|
+
String(compilerBuilder.entry || '').includes('node_modules/@pulse-compute/assets/pulsewasm.compiler.cjs'));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function packageOwnedLowerer(plan) {
|
|
93
|
+
const policy = plan && plan.policy || {};
|
|
94
|
+
return Boolean(plan &&
|
|
95
|
+
plan.npmPackage === '@pulse-compute/assets' &&
|
|
96
|
+
plan.lowerableSubpath === '@pulse-compute/assets' &&
|
|
97
|
+
policy.builderOwner === '@pulse-compute/assets' &&
|
|
98
|
+
policy.compilerOwnsPackageMapping === false);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function providerProofOrBuild(options, plan, diagnostics) {
|
|
102
|
+
const provided = normalize(options.fastlyAssetsProviderProof || options.providerProof);
|
|
103
|
+
if (provided) return { artifact: provided, diagnostics: [] };
|
|
104
|
+
if (!plan) return undefined;
|
|
105
|
+
const proof = buildFastlyAssetsProviderProof({
|
|
106
|
+
cwd: options.cwd,
|
|
107
|
+
generatedBy: options.generatedBy || PACKAGE_VERSION,
|
|
108
|
+
assetsLoweringPlan: plan,
|
|
109
|
+
resolvedConfig: options.resolvedConfig,
|
|
110
|
+
fastlyHostcallBinding: options.fastlyHostcallBinding,
|
|
111
|
+
fastlyAdapter: options.fastlyAdapter,
|
|
112
|
+
requestResultHeaders: options.requestResultHeaders,
|
|
113
|
+
streamingPassthrough: options.streamingPassthrough,
|
|
114
|
+
wasmHostAbi: options.wasmHostAbi
|
|
115
|
+
});
|
|
116
|
+
diagnostics.push(...(proof.diagnostics || []));
|
|
117
|
+
return proof;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function buildFastlyAssetsPackageOutParityProof(options = {}) {
|
|
121
|
+
const cwd = options.cwd || process.cwd();
|
|
122
|
+
const generatedBy = options.generatedBy || PACKAGE_VERSION;
|
|
123
|
+
const plan = normalize(options.assetsLoweringPlan || options.plan);
|
|
124
|
+
const sidecarPlan = normalize(options.assetsCompiledWasmSidecarPlan || options.sidecarPlan);
|
|
125
|
+
const packageOutProof = normalize(options.assetsPackageOutDiscoveryProof || options.packageOutDiscoveryProof || options.packageOutProof);
|
|
126
|
+
const nodeCompiledProof = normalize(options.nodeCompiledWasmAssetsLifecycleProof || options.nodeProof);
|
|
127
|
+
const diagnostics = [];
|
|
128
|
+
const failures = [];
|
|
129
|
+
const checks = [];
|
|
130
|
+
|
|
131
|
+
if (!plan) {
|
|
132
|
+
diagnostics.push(makeDiagnostic(
|
|
133
|
+
assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_PACKAGE_OUT_PARITY_PLAN_REQUIRED,
|
|
134
|
+
'Fastly assets package-out parity proof requires assets-lowering-plan.json.',
|
|
135
|
+
'error',
|
|
136
|
+
{ sourceArtifact: assetsContracts.ASSETS_LOWERING_PLAN_VERSION }
|
|
137
|
+
));
|
|
138
|
+
}
|
|
139
|
+
if (!sidecarPlan) {
|
|
140
|
+
diagnostics.push(makeDiagnostic(
|
|
141
|
+
assetsContracts.ASSETS_DIAGNOSTIC_CODES.SIDECAR_FILE_MISSING,
|
|
142
|
+
'Fastly assets package-out parity proof requires assets-compiled-wasm-sidecar-plan.json so compiled-Wasm readiness can be classified honestly.',
|
|
143
|
+
'error',
|
|
144
|
+
{ sourceArtifact: assetsContracts.ASSETS_COMPILED_WASM_SIDECAR_PLAN_ARTIFACT }
|
|
145
|
+
));
|
|
146
|
+
}
|
|
147
|
+
const sidecarPackageOut = sidecarPlan && sidecarPlan.packageOut ? sidecarPlan.packageOut : undefined;
|
|
148
|
+
if (!packageOutProof && !(sidecarPackageOut && sidecarPackageOut.discoveredFromNodeModules === true && sidecarPackageOut.builderLoadedFromNodeModules === true)) {
|
|
149
|
+
diagnostics.push(makeDiagnostic(
|
|
150
|
+
assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_PACKAGE_OUT_PARITY_PLAN_REQUIRED,
|
|
151
|
+
'Fastly assets package-out parity proof requires assets-package-out-discovery-proof.json or sidecar package-out evidence to prove packaged @pulse-compute/assets discovery.',
|
|
152
|
+
'error',
|
|
153
|
+
{ sourceArtifact: assetsContracts.ASSETS_PACKAGE_OUT_DISCOVERY_PROOF_ARTIFACT }
|
|
154
|
+
));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const fastlyProviderProof = providerProofOrBuild(options, plan, diagnostics);
|
|
158
|
+
const providerProofArtifact = fastlyProviderProof && normalize(fastlyProviderProof);
|
|
159
|
+
const providerConfig = options.providerConfig || (providerProofArtifact && providerProofArtifact.providerConfig) || buildFastlyAssetsProviderConfig({ plan, resolvedConfig: options.resolvedConfig });
|
|
160
|
+
|
|
161
|
+
const packageOwnedLoweringConsumed = packageOwnedLowerer(plan);
|
|
162
|
+
const discoveredFromPackagedAssets = packageOutDiscovered(packageOutProof) || Boolean(sidecarPackageOut && sidecarPackageOut.discoveredFromNodeModules === true);
|
|
163
|
+
const packageBuilderLoaded = builderLoadedFromPackageOut(packageOutProof) || Boolean(sidecarPackageOut && sidecarPackageOut.builderLoadedFromNodeModules === true);
|
|
164
|
+
const symbolicStoreConfigValidated = Boolean(providerConfig && providerConfig.provider === 'fastly' && providerConfig.symbolicRefsOnly === true && Array.isArray(providerConfig.stores) && providerConfig.stores.length > 0 && providerConfig.stores.every((store) => String(store.endpointRef || '').startsWith('$config:') && String(store.bucketRef || '').startsWith('$config:') && String(store.keyRef || '').startsWith('$secret:')));
|
|
165
|
+
const getMappingValidated = summaryFlag(providerProofArtifact, 'getTextValidated');
|
|
166
|
+
const headMappingValidated = summaryFlag(providerProofArtifact, 'headValidated');
|
|
167
|
+
const headersValidated = checkByName(providerProofArtifact, 'headers/status pass through') || Boolean(providerProofArtifact && providerProofArtifact.payloadModes && providerProofArtifact.payloadModes.headerPassThrough && providerProofArtifact.payloadModes.headerPassThrough.status === 'implemented-now');
|
|
168
|
+
const cacheControlValidated = checkByName(providerProofArtifact, 'cache-control policy is preserved');
|
|
169
|
+
const notFoundPolicyValidated = summaryFlag(providerProofArtifact, 'notFoundValidated');
|
|
170
|
+
const binaryBodyReserved = summaryFlag(providerProofArtifact, 'binaryReservedValidated') || Boolean(providerProofArtifact && providerProofArtifact.payloadModes && providerProofArtifact.payloadModes.binaryBodyBufferResponse && providerProofArtifact.payloadModes.binaryBodyBufferResponse.status === 'reserved-with-diagnostic');
|
|
171
|
+
const streamProviderProofImplemented = Boolean(providerProofArtifact && providerProofArtifact.payloadModes && providerProofArtifact.payloadModes.streamPassThroughResponse && providerProofArtifact.payloadModes.streamPassThroughResponse.status === 'implemented-fastly-proof');
|
|
172
|
+
const terminalSidecarPlanned = Boolean(sidecarPlan && sidecarPlan.summary && sidecarPlan.summary.terminalAssetResponseEffectPlanned === true);
|
|
173
|
+
const sidecarPackaged = Boolean((sidecarPlan && sidecarPlan.summary && sidecarPlan.summary.packageOutSidecarValidated === true) || (sidecarPackageOut && sidecarPackageOut.discoveredFromNodeModules === true && sidecarPackageOut.sidecarFile));
|
|
174
|
+
const nodeCompiledReferenceImplemented = Boolean(nodeCompiledProof && nodeCompiledProof.compiledWasmLowering === true && nodeCompiledProof.compiledWasmRuntimeBehaviorImplemented === true);
|
|
175
|
+
|
|
176
|
+
checks.push(check('package_owned_lowering_consumed', packageOwnedLoweringConsumed, { package: plan && plan.npmPackage, lowerableSubpath: plan && plan.lowerableSubpath, policy: plan && plan.policy }, failures, diagnostics));
|
|
177
|
+
checks.push(check('packaged_assets_discovered_from_node_modules', discoveredFromPackagedAssets && packageBuilderLoaded, { discoveredFromNodeModules: discoveredFromPackagedAssets, packageBuilderLoaded, compilerBuilder: packageOutProof && packageOutProof.discovery && packageOutProof.discovery.compilerBuilder }, failures, diagnostics));
|
|
178
|
+
checks.push(check('symbolic_fastly_store_config_validated', symbolicStoreConfigValidated, { providerConfig }, failures, diagnostics));
|
|
179
|
+
checks.push(check('get_mapping_validated', getMappingValidated, { summary: providerProofArtifact && providerProofArtifact.summary }, failures, diagnostics));
|
|
180
|
+
checks.push(check('head_mapping_validated', headMappingValidated, { summary: providerProofArtifact && providerProofArtifact.summary }, failures, diagnostics));
|
|
181
|
+
checks.push(check('headers_validated', headersValidated, { headerPassThrough: providerProofArtifact && providerProofArtifact.payloadModes && providerProofArtifact.payloadModes.headerPassThrough }, failures, diagnostics));
|
|
182
|
+
checks.push(check('cache_control_validated', cacheControlValidated, { checks: providerProofArtifact && providerProofArtifact.smoke && providerProofArtifact.smoke.checks }, failures, diagnostics));
|
|
183
|
+
checks.push(check('not_found_policy_validated', notFoundPolicyValidated, { summary: providerProofArtifact && providerProofArtifact.summary }, failures, diagnostics));
|
|
184
|
+
checks.push(check('sidecar_readiness_classified', terminalSidecarPlanned && sidecarPackaged, { terminalAssetResponseEffectPlanned: terminalSidecarPlanned, packageOutSidecarValidated: sidecarPackaged, summary: sidecarPlan && sidecarPlan.summary }, failures, diagnostics));
|
|
185
|
+
checks.push(check('binary_body_reserved', binaryBodyReserved, { binaryBodyBufferResponse: providerProofArtifact && providerProofArtifact.payloadModes && providerProofArtifact.payloadModes.binaryBodyBufferResponse }, failures, diagnostics));
|
|
186
|
+
checks.push(check('no_external_fastly_service_required', Boolean(providerProofArtifact && providerProofArtifact.scope && providerProofArtifact.scope.configSecretRefs === 'symbolic-only') && providerProofArtifact.proofMode === 'direct-fastly-provider-smoke-connected-to-lowering-plan', { proofMode: providerProofArtifact && providerProofArtifact.proofMode, scope: providerProofArtifact && providerProofArtifact.scope }, failures, diagnostics));
|
|
187
|
+
|
|
188
|
+
diagnostics.push(makeDiagnostic(
|
|
189
|
+
assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_ASSETS_COMPILED_WASM_PLAN_ONLY,
|
|
190
|
+
'Fastly compiled-Wasm assets terminal response execution is explicitly plan-only until a provider-owned compiled-Wasm Fastly bridge is wired.',
|
|
191
|
+
'warning',
|
|
192
|
+
{ compiledWasmAssetsReadiness: 'plan-only', nodeReferenceCompiledLifecycleImplemented: nodeCompiledReferenceImplemented }
|
|
193
|
+
));
|
|
194
|
+
|
|
195
|
+
const errorDiagnostics = diagnostics.filter((entry) => (entry.severity || 'error') === 'error');
|
|
196
|
+
const artifact = normalizeArtifact({
|
|
197
|
+
version: assetsContracts.ASSETS_FASTLY_PACKAGE_OUT_PARITY_PROOF_VERSION,
|
|
198
|
+
generatedBy,
|
|
199
|
+
phase: '50',
|
|
200
|
+
artifact: assetsContracts.ASSETS_FASTLY_PACKAGE_OUT_PARITY_PROOF_ARTIFACT,
|
|
201
|
+
contractId: assetsContracts.ASSETS_CONTRACT_ID,
|
|
202
|
+
status: errorDiagnostics.length === 0 ? 'ok' : 'error',
|
|
203
|
+
provider: 'fastly',
|
|
204
|
+
providerPackage: '@pulse-compute/provider-fastly',
|
|
205
|
+
package: '@pulse-compute/assets',
|
|
206
|
+
lowerableSubpath: plan && plan.lowerableSubpath || '@pulse-compute/assets',
|
|
207
|
+
sourceAssetsLoweringPlanVersion: plan && plan.version,
|
|
208
|
+
sourceAssetsCompiledWasmSidecarPlanVersion: sidecarPlan && sidecarPlan.version,
|
|
209
|
+
sourcePackageOutDiscoveryProofVersion: packageOutProof && packageOutProof.version,
|
|
210
|
+
sourceFastlyAssetsProviderProofVersion: providerProofArtifact && providerProofArtifact.version,
|
|
211
|
+
sourceNodeCompiledWasmAssetsLifecycleProofVersion: nodeCompiledProof && nodeCompiledProof.version,
|
|
212
|
+
packageOwnedLoweringConsumed,
|
|
213
|
+
discoveredFromPackagedAssets,
|
|
214
|
+
symbolicStoreConfigValidated,
|
|
215
|
+
getMappingValidated,
|
|
216
|
+
headMappingValidated,
|
|
217
|
+
headersValidated,
|
|
218
|
+
cacheControlValidated,
|
|
219
|
+
notFoundPolicyValidated,
|
|
220
|
+
compiledWasmAssetsReadiness: 'plan-only',
|
|
221
|
+
compiledWasmPlanOnlyDiagnostic: assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_ASSETS_COMPILED_WASM_PLAN_ONLY,
|
|
222
|
+
binaryBodyReserved,
|
|
223
|
+
streamBodyReadiness: streamProviderProofImplemented ? 'provider-proof-implemented-compiled-wasm-plan-only' : 'plan-only',
|
|
224
|
+
noExternalFastlyServiceRequired: true,
|
|
225
|
+
actualNetworkFetch: false,
|
|
226
|
+
policy: {
|
|
227
|
+
compilerOrchestratesOnly: true,
|
|
228
|
+
packageOwnsLoweringSurface: true,
|
|
229
|
+
packageOwnedLowererConsumed: packageOwnedLoweringConsumed,
|
|
230
|
+
providerOwnsFastlyBehavior: true,
|
|
231
|
+
noExternalFastlyServiceRequired: true,
|
|
232
|
+
packageOutFixtureRequired: true,
|
|
233
|
+
monorepoAssetsSourcePathRequired: false,
|
|
234
|
+
compiledWasmAssetsReadiness: 'plan-only',
|
|
235
|
+
directProviderProofFallback: false,
|
|
236
|
+
symbolicStoreConfigOnly: true,
|
|
237
|
+
objectStoreMutationApis: false,
|
|
238
|
+
uploads: false,
|
|
239
|
+
invalidation: false,
|
|
240
|
+
binaryBody: false,
|
|
241
|
+
streamProviderProofImplemented,
|
|
242
|
+
streamCompiledWasmReadiness: 'plan-only'
|
|
243
|
+
},
|
|
244
|
+
packageOut: {
|
|
245
|
+
packagePacked: Boolean(packageOutProof && packageOutProof.checks && packageOutProof.checks.packagePacked),
|
|
246
|
+
discoveredFromNodeModules: discoveredFromPackagedAssets,
|
|
247
|
+
compilerBuilderLoadedFromNodeModules: packageBuilderLoaded,
|
|
248
|
+
packageTarballIncludesManifest: Boolean(packageOutProof && packageOutProof.checks && packageOutProof.checks.packageTarballIncludesManifest),
|
|
249
|
+
packageTarballIncludesCompilerBuilder: Boolean(packageOutProof && packageOutProof.checks && packageOutProof.checks.packageTarballIncludesCompilerBuilder),
|
|
250
|
+
packageTarballIncludesPulseWasmFacade: Boolean(packageOutProof && packageOutProof.checks && packageOutProof.checks.packageTarballIncludesPulseWasmFacade),
|
|
251
|
+
packageTarballIncludesSidecar: Boolean(packageOutProof && packageOutProof.checks && packageOutProof.checks.packageTarballIncludesSidecar),
|
|
252
|
+
monorepoSourcePathRequired: false,
|
|
253
|
+
npmRegistryRequired: false
|
|
254
|
+
},
|
|
255
|
+
fastly: {
|
|
256
|
+
providerConfig: clone(providerConfig),
|
|
257
|
+
providerProof: providerProofArtifact ? {
|
|
258
|
+
version: providerProofArtifact.version,
|
|
259
|
+
status: providerProofArtifact.status,
|
|
260
|
+
proofMode: providerProofArtifact.proofMode,
|
|
261
|
+
summary: clone(providerProofArtifact.summary),
|
|
262
|
+
payloadModes: clone(providerProofArtifact.payloadModes)
|
|
263
|
+
} : undefined,
|
|
264
|
+
symbolicStoreConfig: {
|
|
265
|
+
validated: symbolicStoreConfigValidated,
|
|
266
|
+
configStore: providerConfig && providerConfig.configStore,
|
|
267
|
+
secretStore: providerConfig && providerConfig.secretStore,
|
|
268
|
+
stores: providerConfig && providerConfig.stores
|
|
269
|
+
},
|
|
270
|
+
mapping: {
|
|
271
|
+
get: getMappingValidated,
|
|
272
|
+
head: headMappingValidated,
|
|
273
|
+
headers: headersValidated,
|
|
274
|
+
cacheControl: cacheControlValidated,
|
|
275
|
+
notFound: notFoundPolicyValidated
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
compiledWasm: {
|
|
279
|
+
sidecarDeclared: Boolean(sidecarPlan && sidecarPlan.summary && sidecarPlan.summary.sidecarDeclared),
|
|
280
|
+
sidecarFileExists: Boolean(sidecarPlan && sidecarPlan.summary && sidecarPlan.summary.sidecarFileExists),
|
|
281
|
+
sidecarSymbolsValidated: Boolean(sidecarPlan && sidecarPlan.summary && sidecarPlan.summary.sidecarSymbolsValidated),
|
|
282
|
+
terminalAssetResponseEffectPlanned: terminalSidecarPlanned,
|
|
283
|
+
nodeReferenceImplemented: nodeCompiledReferenceImplemented,
|
|
284
|
+
fastlyReadiness: 'plan-only',
|
|
285
|
+
diagnostic: assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_ASSETS_COMPILED_WASM_PLAN_ONLY,
|
|
286
|
+
asyncAwait: false,
|
|
287
|
+
promises: false,
|
|
288
|
+
asyncify: false
|
|
289
|
+
},
|
|
290
|
+
unsupported: {
|
|
291
|
+
binaryBodyReserved,
|
|
292
|
+
streamBodyReadiness: streamProviderProofImplemented ? 'provider-proof-implemented-compiled-wasm-plan-only' : 'plan-only',
|
|
293
|
+
uploads: false,
|
|
294
|
+
mutationApis: false,
|
|
295
|
+
invalidation: false,
|
|
296
|
+
externalFastlyService: false
|
|
297
|
+
},
|
|
298
|
+
smoke: {
|
|
299
|
+
checks,
|
|
300
|
+
failedChecks: failures
|
|
301
|
+
},
|
|
302
|
+
diagnostics,
|
|
303
|
+
summary: {
|
|
304
|
+
packageOwnedLoweringConsumed,
|
|
305
|
+
discoveredFromPackagedAssets,
|
|
306
|
+
symbolicStoreConfigValidated,
|
|
307
|
+
getMappingValidated,
|
|
308
|
+
headMappingValidated,
|
|
309
|
+
headersValidated,
|
|
310
|
+
cacheControlValidated,
|
|
311
|
+
notFoundPolicyValidated,
|
|
312
|
+
compiledWasmAssetsReadiness: 'plan-only',
|
|
313
|
+
compiledWasmPlanOnlyDiagnostic: assetsContracts.ASSETS_DIAGNOSTIC_CODES.FASTLY_ASSETS_COMPILED_WASM_PLAN_ONLY,
|
|
314
|
+
binaryBodyReserved,
|
|
315
|
+
streamBodyReadiness: streamProviderProofImplemented ? 'provider-proof-implemented-compiled-wasm-plan-only' : 'plan-only',
|
|
316
|
+
noExternalFastlyServiceRequired: true,
|
|
317
|
+
actualNetworkFetch: false,
|
|
318
|
+
checks: checks.length,
|
|
319
|
+
failedChecks: failures.length,
|
|
320
|
+
diagnostics: diagnostics.length,
|
|
321
|
+
warnings: diagnostics.filter((entry) => (entry.severity || 'error') === 'warning').length,
|
|
322
|
+
errors: errorDiagnostics.length
|
|
323
|
+
}
|
|
324
|
+
}, cwd);
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
artifact,
|
|
328
|
+
diagnostics,
|
|
329
|
+
providerProof: fastlyProviderProof,
|
|
330
|
+
failures,
|
|
331
|
+
hasErrors: errorDiagnostics.length > 0
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
module.exports = {
|
|
336
|
+
phaseName,
|
|
337
|
+
buildFastlyAssetsPackageOutParityProof
|
|
338
|
+
};
|