@moinulmoin/eden 0.1.0
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/LICENSE +201 -0
- package/NOTICE +42 -0
- package/README.md +20 -0
- package/dist/eve-control-plane.d.ts +228 -0
- package/dist/eve-control-plane.js +2007 -0
- package/dist/eve-packaging.d.ts +261 -0
- package/dist/eve-packaging.js +2056 -0
- package/dist/eve-runtime-config.d.ts +126 -0
- package/dist/eve-runtime-config.js +446 -0
- package/dist/eve-runtime-image.d.ts +121 -0
- package/dist/eve-runtime-image.js +1134 -0
- package/dist/eve.d.ts +49 -0
- package/dist/eve.js +234 -0
- package/dist/index.d.ts +196 -0
- package/dist/index.js +6840 -0
- package/package.json +56 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export declare const EVE_RESERVED_HOST_VARIABLES: readonly ["HOST", "NITRO_HOST", "PORT", "NITRO_PORT", "NODE_ENV", "WORKFLOW_LOCAL_BASE_URL", "EDEN_EVE_DEPLOYMENT_ID", "EDEN_EVE_GENERATION_ID"];
|
|
2
|
+
export type EveReservedHostVariable = (typeof EVE_RESERVED_HOST_VARIABLES)[number];
|
|
3
|
+
export declare const EVE_START_COMMAND: readonly ["./node_modules/.bin/eve", "start", "--host", "0.0.0.0", "--port", "8080"];
|
|
4
|
+
type EveRuntimeValueMap = Readonly<Record<string, string>>;
|
|
5
|
+
export type EveRuntimeConfigErrorCode = "EVE_ENV_FILE_NOT_FOUND" | "EVE_ENV_FILE_INVALID" | "EVE_ENV_FILE_UNREADABLE" | "EVE_ENV_FILE_ENCODING" | "EVE_ENV_FILE_MALFORMED" | "EVE_ENV_FILE_DUPLICATE" | "EVE_ENV_RESERVED_VARIABLE" | "EVE_ENV_FILE_RACE" | "EVE_RUNTIME_INJECTION_INVALID" | "EVE_RUNTIME_PROTECTED_STORE_UNAVAILABLE" | "EVE_RUNTIME_PROTECTED_UPLOAD_FAILED" | "EVE_RUNTIME_LOCAL_INJECTION_UNSUPPORTED";
|
|
6
|
+
export declare class EveRuntimeConfigError extends Error {
|
|
7
|
+
readonly code: EveRuntimeConfigErrorCode;
|
|
8
|
+
readonly source: string | undefined;
|
|
9
|
+
readonly variableName: string | undefined;
|
|
10
|
+
constructor(options: {
|
|
11
|
+
readonly code: EveRuntimeConfigErrorCode;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
readonly source?: string;
|
|
14
|
+
readonly variableName?: string;
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export interface EveRuntimeInputIdentity {
|
|
18
|
+
readonly token: string;
|
|
19
|
+
readonly byteLength: number;
|
|
20
|
+
readonly digest: string;
|
|
21
|
+
}
|
|
22
|
+
export interface RedactedRuntimeConfigSeam {
|
|
23
|
+
readonly supplied: true;
|
|
24
|
+
readonly inputIdentity: EveRuntimeInputIdentity;
|
|
25
|
+
readonly variableNames: readonly string[];
|
|
26
|
+
readonly reservedHostNames: readonly EveReservedHostVariable[];
|
|
27
|
+
readonly protectedRevision: string;
|
|
28
|
+
readonly redactionHandle: string;
|
|
29
|
+
readonly excludedFromBuildInputs: true;
|
|
30
|
+
}
|
|
31
|
+
interface EveRuntimeFileObservation {
|
|
32
|
+
readonly path: string;
|
|
33
|
+
readonly dev: number;
|
|
34
|
+
readonly ino: number;
|
|
35
|
+
readonly mode: number;
|
|
36
|
+
readonly size: number;
|
|
37
|
+
readonly bytes: Buffer;
|
|
38
|
+
readonly digest: string;
|
|
39
|
+
}
|
|
40
|
+
declare class EveRuntimeRedactionRegistry {
|
|
41
|
+
readonly handle: string;
|
|
42
|
+
private readonly values;
|
|
43
|
+
register(value: string): void;
|
|
44
|
+
redact(value: string): string;
|
|
45
|
+
dispose(): void;
|
|
46
|
+
}
|
|
47
|
+
export declare function redactEveRuntimeOutput(value: string): string;
|
|
48
|
+
export interface EveStartProcessRequest {
|
|
49
|
+
readonly command: "./node_modules/.bin/eve";
|
|
50
|
+
readonly args: readonly [
|
|
51
|
+
"start",
|
|
52
|
+
"--host",
|
|
53
|
+
"0.0.0.0",
|
|
54
|
+
"--port",
|
|
55
|
+
"8080"
|
|
56
|
+
];
|
|
57
|
+
readonly cwd: string;
|
|
58
|
+
/**
|
|
59
|
+
* This is a private startup environment. It is intentionally not inherited
|
|
60
|
+
* from the Eden process and never contains the control-plane environment.
|
|
61
|
+
*/
|
|
62
|
+
readonly env: Readonly<Record<string, string>>;
|
|
63
|
+
}
|
|
64
|
+
export interface EveRuntimeProtectedPutRequest {
|
|
65
|
+
readonly targetId: string;
|
|
66
|
+
readonly revision: string;
|
|
67
|
+
readonly inputIdentity: EveRuntimeInputIdentity;
|
|
68
|
+
readonly variableNames: readonly string[];
|
|
69
|
+
readonly values: EveRuntimeValueMap;
|
|
70
|
+
}
|
|
71
|
+
export interface EveRuntimeProtectedPutResult {
|
|
72
|
+
readonly revision: string;
|
|
73
|
+
readonly handle: string;
|
|
74
|
+
}
|
|
75
|
+
export interface EveRuntimeProtectedStore {
|
|
76
|
+
/**
|
|
77
|
+
* Implementations must use a provider-protected value channel. This method
|
|
78
|
+
* must not serialize values into argv, URLs, source, records, or logs.
|
|
79
|
+
*/
|
|
80
|
+
put(request: EveRuntimeProtectedPutRequest): Promise<EveRuntimeProtectedPutResult>;
|
|
81
|
+
}
|
|
82
|
+
export type EveRuntimeInjectionMode = "preflight" | "deploy";
|
|
83
|
+
export interface EveRuntimeInjection {
|
|
84
|
+
readonly mode: EveRuntimeInjectionMode;
|
|
85
|
+
readonly seam: RedactedRuntimeConfigSeam;
|
|
86
|
+
readonly protectedRevision: string;
|
|
87
|
+
readonly protectedHandle: string | undefined;
|
|
88
|
+
readonly variableNames: readonly string[];
|
|
89
|
+
readonly startCommand: typeof EVE_START_COMMAND;
|
|
90
|
+
runLocal<T>(options: {
|
|
91
|
+
readonly cwd: string;
|
|
92
|
+
readonly hostEnvironment: Readonly<Record<string, string>>;
|
|
93
|
+
readonly run: (request: EveStartProcessRequest) => T | Promise<T>;
|
|
94
|
+
}): Promise<T>;
|
|
95
|
+
}
|
|
96
|
+
export interface EveRuntimeInjectionOptions {
|
|
97
|
+
readonly mode: EveRuntimeInjectionMode;
|
|
98
|
+
readonly targetId?: string;
|
|
99
|
+
readonly protectedStore?: EveRuntimeProtectedStore;
|
|
100
|
+
}
|
|
101
|
+
export declare class EveRuntimeConfig {
|
|
102
|
+
private readonly values;
|
|
103
|
+
private readonly observation;
|
|
104
|
+
private readonly redaction;
|
|
105
|
+
private disposed;
|
|
106
|
+
private readonly safeSeam;
|
|
107
|
+
private constructor();
|
|
108
|
+
static from(observation: EveRuntimeFileObservation, values: EveRuntimeValueMap, redaction: EveRuntimeRedactionRegistry): EveRuntimeConfig;
|
|
109
|
+
get seam(): RedactedRuntimeConfigSeam;
|
|
110
|
+
get inputPath(): string;
|
|
111
|
+
toJSON(): RedactedRuntimeConfigSeam;
|
|
112
|
+
revalidate(): Promise<void>;
|
|
113
|
+
readInputIdentity(): Promise<EveRuntimeInputIdentity>;
|
|
114
|
+
withProtectedValues<T>(callback: (values: EveRuntimeValueMap) => T): T;
|
|
115
|
+
createStartEnvironment(hostEnvironment: Readonly<Record<string, string>>): Readonly<Record<string, string>>;
|
|
116
|
+
dispose(): void;
|
|
117
|
+
private assertUsable;
|
|
118
|
+
}
|
|
119
|
+
export declare function readEveRuntimeConfig(inputPath: string, options?: {
|
|
120
|
+
readonly cwd?: string;
|
|
121
|
+
}): Promise<EveRuntimeConfig>;
|
|
122
|
+
export declare const parseEveRuntimeConfig: typeof readEveRuntimeConfig;
|
|
123
|
+
export declare const loadEveRuntimeConfig: typeof readEveRuntimeConfig;
|
|
124
|
+
export declare function prepareEveRuntimeInjection(config: EveRuntimeConfig, options: EveRuntimeInjectionOptions): Promise<EveRuntimeInjection>;
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=eve-runtime-config.d.ts.map
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { createHash, randomUUID, } from "node:crypto";
|
|
2
|
+
import { lstat, readFile, } from "node:fs/promises";
|
|
3
|
+
import { resolve, } from "node:path";
|
|
4
|
+
export const EVE_RESERVED_HOST_VARIABLES = Object.freeze([
|
|
5
|
+
"HOST",
|
|
6
|
+
"NITRO_HOST",
|
|
7
|
+
"PORT",
|
|
8
|
+
"NITRO_PORT",
|
|
9
|
+
"NODE_ENV",
|
|
10
|
+
"WORKFLOW_LOCAL_BASE_URL",
|
|
11
|
+
"EDEN_EVE_DEPLOYMENT_ID",
|
|
12
|
+
"EDEN_EVE_GENERATION_ID",
|
|
13
|
+
]);
|
|
14
|
+
export const EVE_START_COMMAND = Object.freeze([
|
|
15
|
+
"./node_modules/.bin/eve",
|
|
16
|
+
"start",
|
|
17
|
+
"--host",
|
|
18
|
+
"0.0.0.0",
|
|
19
|
+
"--port",
|
|
20
|
+
"8080",
|
|
21
|
+
]);
|
|
22
|
+
const EVE_ENVIRONMENT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/u;
|
|
23
|
+
const EVE_RUNTIME_METADATA_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
24
|
+
const EVE_ENV_FILE_SOURCE = "--env-file";
|
|
25
|
+
export class EveRuntimeConfigError extends Error {
|
|
26
|
+
code;
|
|
27
|
+
source;
|
|
28
|
+
variableName;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
super(options.message);
|
|
31
|
+
this.name = "EveRuntimeConfigError";
|
|
32
|
+
this.code = options.code;
|
|
33
|
+
this.source = options.source;
|
|
34
|
+
this.variableName = options.variableName;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
function sha256(value) {
|
|
38
|
+
return createHash("sha256").update(value).digest("hex");
|
|
39
|
+
}
|
|
40
|
+
function isMissingError(error) {
|
|
41
|
+
return (typeof error === "object" &&
|
|
42
|
+
error !== null &&
|
|
43
|
+
"code" in error &&
|
|
44
|
+
error.code === "ENOENT");
|
|
45
|
+
}
|
|
46
|
+
function isPermissionError(error) {
|
|
47
|
+
return (typeof error === "object" &&
|
|
48
|
+
error !== null &&
|
|
49
|
+
"code" in error &&
|
|
50
|
+
["EACCES", "EPERM", "EISDIR"].includes(String(error.code)));
|
|
51
|
+
}
|
|
52
|
+
function fileObservationMatches(left, right) {
|
|
53
|
+
return (left.dev === right.dev &&
|
|
54
|
+
left.ino === right.ino &&
|
|
55
|
+
left.mode === right.mode &&
|
|
56
|
+
left.size === right.size &&
|
|
57
|
+
left.digest === right.digest &&
|
|
58
|
+
left.bytes.equals(right.bytes));
|
|
59
|
+
}
|
|
60
|
+
function invalidPathError(reason) {
|
|
61
|
+
return new EveRuntimeConfigError({
|
|
62
|
+
code: "EVE_ENV_FILE_INVALID",
|
|
63
|
+
message: `The explicit Eve environment file is invalid: ${reason}.`,
|
|
64
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async function observeEnvironmentFile(path) {
|
|
68
|
+
const before = await lstat(path).catch((error) => {
|
|
69
|
+
if (isMissingError(error)) {
|
|
70
|
+
throw new EveRuntimeConfigError({
|
|
71
|
+
code: "EVE_ENV_FILE_NOT_FOUND",
|
|
72
|
+
message: "The explicit Eve environment file does not exist.",
|
|
73
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
throw new EveRuntimeConfigError({
|
|
77
|
+
code: "EVE_ENV_FILE_UNREADABLE",
|
|
78
|
+
message: "The explicit Eve environment file could not be inspected safely.",
|
|
79
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
if (!before.isFile() || before.isSymbolicLink()) {
|
|
83
|
+
throw invalidPathError("it must be a regular file and symbolic links are not accepted");
|
|
84
|
+
}
|
|
85
|
+
let bytes;
|
|
86
|
+
try {
|
|
87
|
+
bytes = await readFile(path);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new EveRuntimeConfigError({
|
|
91
|
+
code: isPermissionError(error)
|
|
92
|
+
? "EVE_ENV_FILE_UNREADABLE"
|
|
93
|
+
: "EVE_ENV_FILE_INVALID",
|
|
94
|
+
message: "The explicit Eve environment file could not be read safely.",
|
|
95
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const secondBytes = await readFile(path).catch(() => undefined);
|
|
99
|
+
const after = await lstat(path).catch((error) => {
|
|
100
|
+
if (isMissingError(error))
|
|
101
|
+
return undefined;
|
|
102
|
+
return undefined;
|
|
103
|
+
});
|
|
104
|
+
if (secondBytes === undefined ||
|
|
105
|
+
!bytes.equals(secondBytes) ||
|
|
106
|
+
after === undefined ||
|
|
107
|
+
!after.isFile() ||
|
|
108
|
+
after.isSymbolicLink() ||
|
|
109
|
+
after.dev !== before.dev ||
|
|
110
|
+
after.ino !== before.ino ||
|
|
111
|
+
after.mode !== before.mode ||
|
|
112
|
+
after.size !== before.size) {
|
|
113
|
+
throw new EveRuntimeConfigError({
|
|
114
|
+
code: "EVE_ENV_FILE_RACE",
|
|
115
|
+
message: "The explicit Eve environment file changed while it was being read.",
|
|
116
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
path,
|
|
121
|
+
dev: before.dev,
|
|
122
|
+
ino: before.ino,
|
|
123
|
+
mode: before.mode,
|
|
124
|
+
size: before.size,
|
|
125
|
+
bytes,
|
|
126
|
+
digest: sha256(bytes),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function decodeUtf8(bytes) {
|
|
130
|
+
try {
|
|
131
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
132
|
+
return text.startsWith("\uFEFF") ? text.slice(1) : text;
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
throw new EveRuntimeConfigError({
|
|
136
|
+
code: "EVE_ENV_FILE_ENCODING",
|
|
137
|
+
message: "The explicit Eve environment file must contain valid UTF-8 text.",
|
|
138
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function malformedLine(lineNumber) {
|
|
143
|
+
return new EveRuntimeConfigError({
|
|
144
|
+
code: "EVE_ENV_FILE_MALFORMED",
|
|
145
|
+
message: `The explicit Eve environment file contains a malformed assignment on line ${lineNumber}.`,
|
|
146
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function parseEnvironmentText(text) {
|
|
150
|
+
const values = Object.create(null);
|
|
151
|
+
const lines = text.split("\n");
|
|
152
|
+
for (const [index, rawLine] of lines.entries()) {
|
|
153
|
+
const lineNumber = index + 1;
|
|
154
|
+
const line = rawLine.endsWith("\r")
|
|
155
|
+
? rawLine.slice(0, -1)
|
|
156
|
+
: rawLine;
|
|
157
|
+
const firstNonWhitespace = line.search(/\S/u);
|
|
158
|
+
if (firstNonWhitespace === -1 || line[firstNonWhitespace] === "#") {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
const separator = line.indexOf("=");
|
|
162
|
+
if (separator <= 0) {
|
|
163
|
+
throw malformedLine(lineNumber);
|
|
164
|
+
}
|
|
165
|
+
const name = line.slice(0, separator);
|
|
166
|
+
const value = line.slice(separator + 1);
|
|
167
|
+
if (!EVE_ENVIRONMENT_NAME_PATTERN.test(name)) {
|
|
168
|
+
throw malformedLine(lineNumber);
|
|
169
|
+
}
|
|
170
|
+
if (Object.prototype.hasOwnProperty.call(values, name)) {
|
|
171
|
+
throw new EveRuntimeConfigError({
|
|
172
|
+
code: "EVE_ENV_FILE_DUPLICATE",
|
|
173
|
+
message: `The explicit Eve environment file defines ${name} more than once.`,
|
|
174
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
175
|
+
variableName: name,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
if (EVE_RESERVED_HOST_VARIABLES.includes(name)) {
|
|
179
|
+
throw new EveRuntimeConfigError({
|
|
180
|
+
code: "EVE_ENV_RESERVED_VARIABLE",
|
|
181
|
+
message: `The explicit Eve environment file attempts to override reserved host variable ${name}.`,
|
|
182
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
183
|
+
variableName: name,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
values[name] = value;
|
|
187
|
+
}
|
|
188
|
+
return Object.freeze(values);
|
|
189
|
+
}
|
|
190
|
+
class EveRuntimeRedactionRegistry {
|
|
191
|
+
handle = `eve-runtime-redaction-${randomUUID()}`;
|
|
192
|
+
values = new Set();
|
|
193
|
+
register(value) {
|
|
194
|
+
if (value.length > 0)
|
|
195
|
+
this.values.add(value);
|
|
196
|
+
}
|
|
197
|
+
redact(value) {
|
|
198
|
+
let redacted = value;
|
|
199
|
+
const registered = [...this.values].sort((left, right) => right.length - left.length);
|
|
200
|
+
for (const secret of registered) {
|
|
201
|
+
redacted = redacted.split(secret).join("[redacted]");
|
|
202
|
+
}
|
|
203
|
+
return redacted;
|
|
204
|
+
}
|
|
205
|
+
dispose() {
|
|
206
|
+
this.values.clear();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const activeRedactionRegistries = new Set();
|
|
210
|
+
export function redactEveRuntimeOutput(value) {
|
|
211
|
+
let redacted = value;
|
|
212
|
+
for (const registry of activeRedactionRegistries) {
|
|
213
|
+
redacted = registry.redact(redacted);
|
|
214
|
+
}
|
|
215
|
+
return redacted;
|
|
216
|
+
}
|
|
217
|
+
export class EveRuntimeConfig {
|
|
218
|
+
values;
|
|
219
|
+
observation;
|
|
220
|
+
redaction;
|
|
221
|
+
disposed = false;
|
|
222
|
+
safeSeam;
|
|
223
|
+
constructor(observation, values, redaction) {
|
|
224
|
+
this.observation = observation;
|
|
225
|
+
this.values = values;
|
|
226
|
+
this.redaction = redaction;
|
|
227
|
+
const variableNames = Object.freeze(Object.keys(values).sort());
|
|
228
|
+
const protectedRevision = `eve-runtime-revision-${randomUUID()}`;
|
|
229
|
+
this.safeSeam = Object.freeze({
|
|
230
|
+
supplied: true,
|
|
231
|
+
inputIdentity: Object.freeze({
|
|
232
|
+
token: `eve-runtime-input-${randomUUID()}`,
|
|
233
|
+
byteLength: observation.bytes.byteLength,
|
|
234
|
+
digest: observation.digest,
|
|
235
|
+
}),
|
|
236
|
+
variableNames,
|
|
237
|
+
reservedHostNames: EVE_RESERVED_HOST_VARIABLES,
|
|
238
|
+
protectedRevision,
|
|
239
|
+
redactionHandle: redaction.handle,
|
|
240
|
+
excludedFromBuildInputs: true,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
static from(observation, values, redaction) {
|
|
244
|
+
return new EveRuntimeConfig(observation, values, redaction);
|
|
245
|
+
}
|
|
246
|
+
get seam() {
|
|
247
|
+
return this.safeSeam;
|
|
248
|
+
}
|
|
249
|
+
get inputPath() {
|
|
250
|
+
return this.observation.path;
|
|
251
|
+
}
|
|
252
|
+
toJSON() {
|
|
253
|
+
return this.safeSeam;
|
|
254
|
+
}
|
|
255
|
+
async revalidate() {
|
|
256
|
+
this.assertUsable();
|
|
257
|
+
const latest = await observeEnvironmentFile(this.observation.path);
|
|
258
|
+
if (!fileObservationMatches(this.observation, latest)) {
|
|
259
|
+
throw new EveRuntimeConfigError({
|
|
260
|
+
code: "EVE_ENV_FILE_RACE",
|
|
261
|
+
message: "The explicit Eve environment file changed during Eve validation.",
|
|
262
|
+
source: EVE_ENV_FILE_SOURCE,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
async readInputIdentity() {
|
|
267
|
+
await this.revalidate();
|
|
268
|
+
return this.safeSeam.inputIdentity;
|
|
269
|
+
}
|
|
270
|
+
withProtectedValues(callback) {
|
|
271
|
+
this.assertUsable();
|
|
272
|
+
return callback(this.values);
|
|
273
|
+
}
|
|
274
|
+
createStartEnvironment(hostEnvironment) {
|
|
275
|
+
this.assertUsable();
|
|
276
|
+
for (const name of Object.keys(hostEnvironment)) {
|
|
277
|
+
if (!EVE_RESERVED_HOST_VARIABLES.includes(name)) {
|
|
278
|
+
throw new EveRuntimeConfigError({
|
|
279
|
+
code: "EVE_RUNTIME_INJECTION_INVALID",
|
|
280
|
+
message: `The Eve start environment contains a non-host variable ${name}.`,
|
|
281
|
+
variableName: name,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
const environment = {
|
|
286
|
+
...this.values,
|
|
287
|
+
...hostEnvironment,
|
|
288
|
+
};
|
|
289
|
+
return Object.freeze(environment);
|
|
290
|
+
}
|
|
291
|
+
dispose() {
|
|
292
|
+
if (this.disposed)
|
|
293
|
+
return;
|
|
294
|
+
this.disposed = true;
|
|
295
|
+
this.redaction.dispose();
|
|
296
|
+
activeRedactionRegistries.delete(this.redaction);
|
|
297
|
+
}
|
|
298
|
+
assertUsable() {
|
|
299
|
+
if (this.disposed) {
|
|
300
|
+
throw new EveRuntimeConfigError({
|
|
301
|
+
code: "EVE_RUNTIME_INJECTION_INVALID",
|
|
302
|
+
message: "The Eve runtime configuration has already been released.",
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
export async function readEveRuntimeConfig(inputPath, options = {}) {
|
|
308
|
+
if (inputPath.length === 0) {
|
|
309
|
+
throw new EveRuntimeConfigError({
|
|
310
|
+
code: "EVE_ENV_FILE_INVALID",
|
|
311
|
+
message: "The explicit Eve environment file path must not be empty.",
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
const path = resolve(options.cwd ?? process.cwd(), inputPath);
|
|
315
|
+
const observation = await observeEnvironmentFile(path);
|
|
316
|
+
const values = parseEnvironmentText(decodeUtf8(observation.bytes));
|
|
317
|
+
const redaction = new EveRuntimeRedactionRegistry();
|
|
318
|
+
for (const value of Object.values(values))
|
|
319
|
+
redaction.register(value);
|
|
320
|
+
activeRedactionRegistries.add(redaction);
|
|
321
|
+
return EveRuntimeConfig.from(observation, values, redaction);
|
|
322
|
+
}
|
|
323
|
+
export const parseEveRuntimeConfig = readEveRuntimeConfig;
|
|
324
|
+
export const loadEveRuntimeConfig = readEveRuntimeConfig;
|
|
325
|
+
function validateProtectedPutResult(result) {
|
|
326
|
+
if (typeof result !== "object" ||
|
|
327
|
+
result === null ||
|
|
328
|
+
typeof result.revision !== "string" ||
|
|
329
|
+
typeof result.handle !== "string" ||
|
|
330
|
+
!EVE_RUNTIME_METADATA_PATTERN.test(result.revision) ||
|
|
331
|
+
!EVE_RUNTIME_METADATA_PATTERN.test(result.handle)) {
|
|
332
|
+
throw new EveRuntimeConfigError({
|
|
333
|
+
code: "EVE_RUNTIME_PROTECTED_UPLOAD_FAILED",
|
|
334
|
+
message: "The protected Eve runtime store returned an invalid revision handle.",
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
function assertProtectedMetadataDoesNotContainRuntimeValues(result) {
|
|
339
|
+
if (redactEveRuntimeOutput(result.revision) !== result.revision ||
|
|
340
|
+
redactEveRuntimeOutput(result.handle) !== result.handle) {
|
|
341
|
+
throw new EveRuntimeConfigError({
|
|
342
|
+
code: "EVE_RUNTIME_PROTECTED_UPLOAD_FAILED",
|
|
343
|
+
message: "The protected Eve runtime store returned value-bearing metadata.",
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
function redactRuntimeConfigError(error) {
|
|
348
|
+
return new EveRuntimeConfigError({
|
|
349
|
+
code: error.code,
|
|
350
|
+
message: redactEveRuntimeOutput(error.message),
|
|
351
|
+
...(error.source === undefined
|
|
352
|
+
? {}
|
|
353
|
+
: { source: redactEveRuntimeOutput(error.source) }),
|
|
354
|
+
...(error.variableName === undefined
|
|
355
|
+
? {}
|
|
356
|
+
: { variableName: redactEveRuntimeOutput(error.variableName) }),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
export async function prepareEveRuntimeInjection(config, options) {
|
|
360
|
+
await config.revalidate();
|
|
361
|
+
const variableNames = config.seam.variableNames;
|
|
362
|
+
if (options.mode === "preflight") {
|
|
363
|
+
if (options.protectedStore !== undefined) {
|
|
364
|
+
throw new EveRuntimeConfigError({
|
|
365
|
+
code: "EVE_RUNTIME_PROTECTED_STORE_UNAVAILABLE",
|
|
366
|
+
message: "Preflight runtime configuration must use disposable local injection and cannot use a Cloudflare protected store.",
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
mode: options.mode,
|
|
371
|
+
seam: config.seam,
|
|
372
|
+
protectedRevision: config.seam.protectedRevision,
|
|
373
|
+
protectedHandle: undefined,
|
|
374
|
+
variableNames,
|
|
375
|
+
startCommand: EVE_START_COMMAND,
|
|
376
|
+
async runLocal(runOptions) {
|
|
377
|
+
await config.revalidate();
|
|
378
|
+
const request = {
|
|
379
|
+
command: EVE_START_COMMAND[0],
|
|
380
|
+
args: [
|
|
381
|
+
EVE_START_COMMAND[1],
|
|
382
|
+
EVE_START_COMMAND[2],
|
|
383
|
+
EVE_START_COMMAND[3],
|
|
384
|
+
EVE_START_COMMAND[4],
|
|
385
|
+
EVE_START_COMMAND[5],
|
|
386
|
+
],
|
|
387
|
+
cwd: resolve(runOptions.cwd),
|
|
388
|
+
env: config.createStartEnvironment(runOptions.hostEnvironment),
|
|
389
|
+
};
|
|
390
|
+
return runOptions.run(request);
|
|
391
|
+
},
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (options.targetId === undefined || options.targetId.length === 0) {
|
|
395
|
+
throw new EveRuntimeConfigError({
|
|
396
|
+
code: "EVE_RUNTIME_INJECTION_INVALID",
|
|
397
|
+
message: "Deploy runtime configuration requires an explicit exact target identity.",
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
if (options.protectedStore === undefined) {
|
|
401
|
+
throw new EveRuntimeConfigError({
|
|
402
|
+
code: "EVE_RUNTIME_PROTECTED_STORE_UNAVAILABLE",
|
|
403
|
+
message: "Deploy runtime configuration requires a protected runtime store.",
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
await config.revalidate();
|
|
407
|
+
const revision = config.seam.protectedRevision;
|
|
408
|
+
let stored;
|
|
409
|
+
try {
|
|
410
|
+
stored = await config.withProtectedValues((values) => options.protectedStore?.put({
|
|
411
|
+
targetId: options.targetId,
|
|
412
|
+
revision,
|
|
413
|
+
inputIdentity: config.seam.inputIdentity,
|
|
414
|
+
variableNames,
|
|
415
|
+
values,
|
|
416
|
+
}));
|
|
417
|
+
}
|
|
418
|
+
catch (error) {
|
|
419
|
+
if (error instanceof EveRuntimeConfigError) {
|
|
420
|
+
throw redactRuntimeConfigError(error);
|
|
421
|
+
}
|
|
422
|
+
throw new EveRuntimeConfigError({
|
|
423
|
+
code: "EVE_RUNTIME_PROTECTED_UPLOAD_FAILED",
|
|
424
|
+
message: "The protected Eve runtime configuration upload failed before publication.",
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
validateProtectedPutResult(stored);
|
|
428
|
+
assertProtectedMetadataDoesNotContainRuntimeValues(stored);
|
|
429
|
+
await config.revalidate();
|
|
430
|
+
const protectedRevision = stored.revision;
|
|
431
|
+
return {
|
|
432
|
+
mode: options.mode,
|
|
433
|
+
seam: config.seam,
|
|
434
|
+
protectedRevision,
|
|
435
|
+
protectedHandle: stored.handle,
|
|
436
|
+
variableNames,
|
|
437
|
+
startCommand: EVE_START_COMMAND,
|
|
438
|
+
async runLocal() {
|
|
439
|
+
throw new EveRuntimeConfigError({
|
|
440
|
+
code: "EVE_RUNTIME_LOCAL_INJECTION_UNSUPPORTED",
|
|
441
|
+
message: "Deploy runtime values are available only through the protected Container start seam.",
|
|
442
|
+
});
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
//# sourceMappingURL=eve-runtime-config.js.map
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type EveNodeImage, type EvePackagingCheck, type EvePackagingCode, type EveProjectBuildCandidate, type EveProjectOutput } from "./eve-packaging.js";
|
|
2
|
+
import type { EveRuntimeInjection } from "./eve-runtime-config.js";
|
|
3
|
+
declare const START_COMMAND: readonly ["./node_modules/.bin/eve", "start", "--host", "0.0.0.0", "--port", "8080"];
|
|
4
|
+
declare const HEALTH_PATH: "/eve/v1/health";
|
|
5
|
+
declare const HOST_ENVIRONMENT: {
|
|
6
|
+
readonly HOST: "0.0.0.0";
|
|
7
|
+
readonly NITRO_HOST: "0.0.0.0";
|
|
8
|
+
readonly PORT: "8080";
|
|
9
|
+
readonly NITRO_PORT: "8080";
|
|
10
|
+
readonly NODE_ENV: "production";
|
|
11
|
+
};
|
|
12
|
+
export interface EveHostRequirements {
|
|
13
|
+
readonly architecture: string;
|
|
14
|
+
readonly world: "supported" | "unsupported" | "unknown";
|
|
15
|
+
readonly sandbox: "supported" | "unsupported" | "unknown";
|
|
16
|
+
readonly privileged: boolean;
|
|
17
|
+
readonly devices: "none" | "required" | "unknown";
|
|
18
|
+
readonly kernel: "supported" | "unsupported" | "unknown";
|
|
19
|
+
readonly network: "supported" | "unsupported" | "unknown";
|
|
20
|
+
readonly durableLocalFilesystem: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface EveRuntimeClosureFile {
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly sha256: string;
|
|
25
|
+
readonly byteLength: number;
|
|
26
|
+
readonly symbolicLink: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface EveRuntimeNativeModule {
|
|
29
|
+
readonly path: string;
|
|
30
|
+
readonly sha256: string;
|
|
31
|
+
readonly platform: "linux/amd64";
|
|
32
|
+
}
|
|
33
|
+
export interface EveRuntimeClosure {
|
|
34
|
+
readonly root: "/workspace/node_modules";
|
|
35
|
+
readonly outputDigest: string;
|
|
36
|
+
readonly dependencyDigest: string;
|
|
37
|
+
readonly digest: string;
|
|
38
|
+
readonly files: readonly EveRuntimeClosureFile[];
|
|
39
|
+
readonly nativeModules: readonly EveRuntimeNativeModule[];
|
|
40
|
+
readonly eveStartClosureRetained: true;
|
|
41
|
+
readonly builderOnlyMaterialExcluded: true;
|
|
42
|
+
}
|
|
43
|
+
export interface EveRuntimeImage extends EveRuntimeImageMetadata {
|
|
44
|
+
readonly runtimeClosure: EveRuntimeClosure;
|
|
45
|
+
}
|
|
46
|
+
export interface EveRuntimeImageMetadata {
|
|
47
|
+
readonly dockerfilePath: string;
|
|
48
|
+
readonly runtimeContextPath: string;
|
|
49
|
+
readonly platform: "linux/amd64";
|
|
50
|
+
readonly builderImage: string;
|
|
51
|
+
readonly runtimeImage: string;
|
|
52
|
+
readonly imageId: string;
|
|
53
|
+
readonly imageReference: string;
|
|
54
|
+
readonly imageDigest: string;
|
|
55
|
+
readonly launchCommand: typeof START_COMMAND;
|
|
56
|
+
readonly workingDirectory: "/workspace";
|
|
57
|
+
readonly hostEnvironment: typeof HOST_ENVIRONMENT;
|
|
58
|
+
readonly publicOrigin?: string;
|
|
59
|
+
readonly generatedOutput: EveProjectOutput;
|
|
60
|
+
}
|
|
61
|
+
export interface EveRuntimeStatus {
|
|
62
|
+
readonly listenHost: "0.0.0.0";
|
|
63
|
+
readonly listenPort: 8080;
|
|
64
|
+
readonly healthMethod: "GET";
|
|
65
|
+
readonly healthPath: typeof HEALTH_PATH;
|
|
66
|
+
readonly healthStatus: "ready";
|
|
67
|
+
readonly healthVerified: true;
|
|
68
|
+
readonly healthVerifiedAt: string;
|
|
69
|
+
readonly durableLocalFilesystemClaim: false;
|
|
70
|
+
}
|
|
71
|
+
export interface EveRuntimeCleanup {
|
|
72
|
+
readonly bootContainerId: string | null;
|
|
73
|
+
readonly bootContainerRemoved: boolean;
|
|
74
|
+
readonly imageIdentity: "exact" | "indeterminate";
|
|
75
|
+
readonly imageRetained: boolean;
|
|
76
|
+
readonly verified: boolean;
|
|
77
|
+
}
|
|
78
|
+
export interface EveRuntimeImageRequest {
|
|
79
|
+
readonly candidate: EveProjectBuildCandidate;
|
|
80
|
+
readonly nodeImage: EveNodeImage;
|
|
81
|
+
readonly dockerCommand?: string;
|
|
82
|
+
readonly healthPort: number;
|
|
83
|
+
readonly healthTimeoutMs?: number;
|
|
84
|
+
readonly healthPollIntervalMs?: number;
|
|
85
|
+
readonly fetchHealth?: (url: string, init?: RequestInit) => Promise<Response>;
|
|
86
|
+
readonly hostRequirements?: EveHostRequirements;
|
|
87
|
+
readonly publicOrigin?: string;
|
|
88
|
+
readonly runtimeInjection?: EveRuntimeInjection;
|
|
89
|
+
/**
|
|
90
|
+
* Preflight must remove its disposable runtime image after health proof.
|
|
91
|
+
* Deploy may retain the exact image for the publication handoff.
|
|
92
|
+
*/
|
|
93
|
+
readonly retainImage?: boolean;
|
|
94
|
+
}
|
|
95
|
+
export interface EveRuntimeImageResult {
|
|
96
|
+
readonly schemaVersion: 1;
|
|
97
|
+
readonly worker: "eve-packaging-worker";
|
|
98
|
+
readonly operation: "runtime-image";
|
|
99
|
+
readonly status: "ready" | "blocked";
|
|
100
|
+
readonly returnCode: EvePackagingCode | "EVE_PACKAGE_READY";
|
|
101
|
+
readonly deployable: boolean;
|
|
102
|
+
readonly candidate: EveProjectBuildCandidate;
|
|
103
|
+
readonly image: EveRuntimeImage | null;
|
|
104
|
+
readonly runtime: EveRuntimeStatus | null;
|
|
105
|
+
readonly cleanup: EveRuntimeCleanup;
|
|
106
|
+
readonly checks: readonly EvePackagingCheck[];
|
|
107
|
+
readonly candidateImageId: string | null;
|
|
108
|
+
readonly candidateImageRetainedLocally: boolean;
|
|
109
|
+
readonly writtenPaths: readonly string[];
|
|
110
|
+
readonly error: {
|
|
111
|
+
readonly code: EvePackagingCode;
|
|
112
|
+
readonly subject: string;
|
|
113
|
+
readonly reason: string;
|
|
114
|
+
readonly remediation: string;
|
|
115
|
+
} | null;
|
|
116
|
+
}
|
|
117
|
+
export declare function validateEveHostRequirements(requirements: EveHostRequirements): void;
|
|
118
|
+
export declare function revalidateEveRuntimeCandidate(candidate: EveProjectBuildCandidate): Promise<EveRuntimeClosure>;
|
|
119
|
+
export declare function buildEveRuntimeImage(request: EveRuntimeImageRequest): Promise<EveRuntimeImageResult>;
|
|
120
|
+
export {};
|
|
121
|
+
//# sourceMappingURL=eve-runtime-image.d.ts.map
|