@moinulmoin/eden 0.1.5 → 0.2.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/NOTICE +0 -31
- package/README.md +37 -109
- package/dist/eve-control-plane.d.ts +19 -0
- package/dist/eve-control-plane.js +345 -23
- package/dist/eve-packaging.d.ts +7 -0
- package/dist/eve-packaging.js +144 -14
- package/dist/eve-runtime-image.js +15 -13
- package/dist/eve.d.ts +17 -2
- package/dist/eve.js +60 -26
- package/dist/index.d.ts +4 -166
- package/dist/index.js +48 -6700
- package/package.json +3 -5
package/dist/eve-packaging.js
CHANGED
|
@@ -34,6 +34,7 @@ const START_COMMAND = [
|
|
|
34
34
|
const EVE_ENTRYPOINT = ".output/server/index.mjs";
|
|
35
35
|
const EVE_EXCLUDED_DIRECTORY_NAMES = new Set([
|
|
36
36
|
".eden",
|
|
37
|
+
".eve",
|
|
37
38
|
".git",
|
|
38
39
|
".hg",
|
|
39
40
|
".next",
|
|
@@ -98,7 +99,8 @@ function isPathExcluded(relativePath, runtimeEnvRelativePath) {
|
|
|
98
99
|
if (excludedDirectory !== undefined) {
|
|
99
100
|
return {
|
|
100
101
|
excluded: true,
|
|
101
|
-
category: excludedDirectory === ".eden" ||
|
|
102
|
+
category: excludedDirectory === ".eden" ||
|
|
103
|
+
excludedDirectory === ".eve" || excludedDirectory === ".git"
|
|
102
104
|
? "generated-state"
|
|
103
105
|
: excludedDirectory === "node_modules"
|
|
104
106
|
? "node_modules"
|
|
@@ -886,6 +888,34 @@ async function writeJson(path, value) {
|
|
|
886
888
|
mode: 0o600,
|
|
887
889
|
});
|
|
888
890
|
}
|
|
891
|
+
const EVE_GENERATED_SNAPSHOT_ROOTS = {
|
|
892
|
+
".dockerignore": true,
|
|
893
|
+
".output": true,
|
|
894
|
+
"node_modules": true,
|
|
895
|
+
};
|
|
896
|
+
/**
|
|
897
|
+
* The authored Eve project source the runtime stage must carry so `eve start`
|
|
898
|
+
* can resolve the project context (agent/, agents/ workspaces, flat layouts,
|
|
899
|
+
* and the manifest). Returns validated top-level snapshot entries with every
|
|
900
|
+
* capture-time exclusion still applied; generated roots are never source.
|
|
901
|
+
*/
|
|
902
|
+
export async function eveSnapshotSourceEntries(snapshotRoot) {
|
|
903
|
+
const entries = await readdir(snapshotRoot, { withFileTypes: true });
|
|
904
|
+
const names = [];
|
|
905
|
+
for (const entry of entries) {
|
|
906
|
+
if (!entry.isFile() && !entry.isDirectory())
|
|
907
|
+
continue;
|
|
908
|
+
if (entry.isSymbolicLink())
|
|
909
|
+
continue;
|
|
910
|
+
if (EVE_GENERATED_SNAPSHOT_ROOTS[entry.name] === true)
|
|
911
|
+
continue;
|
|
912
|
+
if (isPathExcluded(entry.name, undefined).excluded)
|
|
913
|
+
continue;
|
|
914
|
+
names.push(entry.name);
|
|
915
|
+
}
|
|
916
|
+
names.sort((left, right) => left.localeCompare(right));
|
|
917
|
+
return names;
|
|
918
|
+
}
|
|
889
919
|
async function writeDockerBuildFiles(options) {
|
|
890
920
|
if (!/^sha256:[0-9a-f]{64}$/u.test(options.nodeImage.digest) ||
|
|
891
921
|
!/^node:24\.17\.0(?:-[a-z0-9][a-z0-9._-]*)?$/u.test(options.nodeImage.reference)) {
|
|
@@ -897,10 +927,18 @@ async function writeDockerBuildFiles(options) {
|
|
|
897
927
|
});
|
|
898
928
|
}
|
|
899
929
|
const image = `${options.nodeImage.reference}@${options.nodeImage.digest}`;
|
|
930
|
+
const installSources = ["package.json", "pnpm-lock.yaml"];
|
|
931
|
+
if ((await lstat(join(options.snapshotRoot, "pnpm-workspace.yaml"))
|
|
932
|
+
.catch(() => undefined))?.isFile() === true) {
|
|
933
|
+
installSources.push("pnpm-workspace.yaml");
|
|
934
|
+
}
|
|
935
|
+
const runtimeSourceCopies = (await eveSnapshotSourceEntries(options.snapshotRoot))
|
|
936
|
+
.map((name) => `COPY --from=builder ${JSON.stringify([`/workspace/${name}`, `/app/${name}`])}`)
|
|
937
|
+
.join("\n");
|
|
900
938
|
const dockerfile = `# syntax=docker/dockerfile:1
|
|
901
939
|
FROM --platform=linux/amd64 ${image} AS builder
|
|
902
940
|
WORKDIR /workspace
|
|
903
|
-
COPY
|
|
941
|
+
COPY ${JSON.stringify([...installSources, "./"])}
|
|
904
942
|
RUN corepack enable \\
|
|
905
943
|
&& corepack prepare pnpm@${options.packageManagerVersion} --activate \\
|
|
906
944
|
&& test "$(corepack pnpm --version)" = "${options.packageManagerVersion}" \\
|
|
@@ -924,6 +962,7 @@ ENV HOST=0.0.0.0 \\
|
|
|
924
962
|
NITRO_PORT=8080 \\
|
|
925
963
|
NODE_ENV=production
|
|
926
964
|
COPY --from=builder /workspace/.output /app/.output
|
|
965
|
+
${runtimeSourceCopies}
|
|
927
966
|
COPY --from=runtime-deps /workspace/node_modules /app/node_modules
|
|
928
967
|
EXPOSE 8080
|
|
929
968
|
ENTRYPOINT ["./node_modules/.bin/eve", "start", "--host", "0.0.0.0", "--port", "8080"]
|
|
@@ -1257,6 +1296,80 @@ function safeError(error) {
|
|
|
1257
1296
|
remediation: error.remediation,
|
|
1258
1297
|
};
|
|
1259
1298
|
}
|
|
1299
|
+
/**
|
|
1300
|
+
* The reported BuildKit step decides the classification: an echoed
|
|
1301
|
+
* `RUN corepack pnpm install --frozen-lockfile` line from an earlier cached
|
|
1302
|
+
* step must not relabel a failing `eve build` step as a pnpm install failure.
|
|
1303
|
+
*/
|
|
1304
|
+
function failingDockerStepCommand(stderr) {
|
|
1305
|
+
let command;
|
|
1306
|
+
let position = -1;
|
|
1307
|
+
for (const pattern of [
|
|
1308
|
+
/process "([^"]+)" did not complete/gu,
|
|
1309
|
+
/executor failed running \[([^\]]+)\]/gu,
|
|
1310
|
+
/The command '([^']+)' returned a non-zero code/gu,
|
|
1311
|
+
]) {
|
|
1312
|
+
for (const match of stderr.matchAll(pattern)) {
|
|
1313
|
+
if (match.index >= position) {
|
|
1314
|
+
position = match.index;
|
|
1315
|
+
command = match[1];
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
return command;
|
|
1320
|
+
}
|
|
1321
|
+
function classifyPnpmInstallFailure(stderr) {
|
|
1322
|
+
if (/ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION/u.test(stderr)) {
|
|
1323
|
+
return new EvePackagingError({
|
|
1324
|
+
code: "DEPENDENCY_AMBIGUITY",
|
|
1325
|
+
subject: "ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION",
|
|
1326
|
+
reason: "The isolated pinned pnpm install rejected a dependency that is newer than the project's minimumReleaseAge policy.",
|
|
1327
|
+
remediation: "Wait until the release ages past the minimumReleaseAge cutoff, or name the exact pin in minimumReleaseAgeExclude inside the project pnpm-workspace.yaml.",
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
if (/ERR_PNPM_(?:OUTDATED_LOCKFILE|LOCKFILE_MISSING_DEPENDENCY)/u.test(stderr)) {
|
|
1331
|
+
return new EvePackagingError({
|
|
1332
|
+
code: "DEPENDENCY_AMBIGUITY",
|
|
1333
|
+
subject: "frozen pnpm install",
|
|
1334
|
+
reason: "The isolated pinned pnpm install could not complete without changing or bypassing the lockfile.",
|
|
1335
|
+
remediation: "Regenerate pnpm-lock.yaml with the declared pnpm version and retry without relaxing frozen mode.",
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
if (/ERR_PNPM_IGNORED_BUILDS/u.test(stderr)) {
|
|
1339
|
+
return new EvePackagingError({
|
|
1340
|
+
code: "DEPENDENCY_AMBIGUITY",
|
|
1341
|
+
subject: "ERR_PNPM_IGNORED_BUILDS",
|
|
1342
|
+
reason: "The isolated pinned pnpm install refused dependency build scripts that the project pnpm policy neither allows nor ignores.",
|
|
1343
|
+
remediation: "Name the dependency under allowBuilds or ignoredBuiltDependencies in the project pnpm-workspace.yaml and retry.",
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
const pnpmErrorCode = /ERR_PNPM_[A-Z0-9_]+/u.exec(stderr)?.[0];
|
|
1347
|
+
if (pnpmErrorCode !== undefined) {
|
|
1348
|
+
return new EvePackagingError({
|
|
1349
|
+
code: "DEPENDENCY_AMBIGUITY",
|
|
1350
|
+
subject: pnpmErrorCode,
|
|
1351
|
+
reason: `The isolated pinned pnpm install failed with ${pnpmErrorCode}.`,
|
|
1352
|
+
remediation: "Fix the pnpm failure reported by the isolated build without relaxing the frozen lockfile or the declared pnpm pin, then retry.",
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
return undefined;
|
|
1356
|
+
}
|
|
1357
|
+
function classifyEveBuildFailure(stderr) {
|
|
1358
|
+
if (/\bjust-bash\b/u.test(stderr)) {
|
|
1359
|
+
return new EvePackagingError({
|
|
1360
|
+
code: "EVE_BUILD_FAILED",
|
|
1361
|
+
subject: "eve build",
|
|
1362
|
+
reason: "The project-local Eve build failed inside the isolated Linux/amd64 builder because Eve's default sandbox needs just-bash where no Docker daemon or /dev/kvm exists.",
|
|
1363
|
+
remediation: "Declare just-bash as a production dependency of the Eve project, regenerate pnpm-lock.yaml, and retry.",
|
|
1364
|
+
});
|
|
1365
|
+
}
|
|
1366
|
+
return new EvePackagingError({
|
|
1367
|
+
code: "EVE_BUILD_FAILED",
|
|
1368
|
+
subject: "eve build",
|
|
1369
|
+
reason: "The project-local Eve build failed inside the isolated Linux/amd64 builder.",
|
|
1370
|
+
remediation: "Fix the project-local Eve build and retry without changing the authored project during packaging.",
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1260
1373
|
function classifyDockerBuildFailure(error) {
|
|
1261
1374
|
const stderr = typeof error === "object" &&
|
|
1262
1375
|
error !== null &&
|
|
@@ -1264,13 +1377,38 @@ function classifyDockerBuildFailure(error) {
|
|
|
1264
1377
|
typeof error.stderr === "string"
|
|
1265
1378
|
? error.stderr
|
|
1266
1379
|
: "";
|
|
1267
|
-
|
|
1268
|
-
|
|
1380
|
+
const step = failingDockerStepCommand(stderr);
|
|
1381
|
+
if (step !== undefined) {
|
|
1382
|
+
if (/\beve\b/u.test(step) && /\bbuild\b/u.test(step)) {
|
|
1383
|
+
return classifyEveBuildFailure(stderr);
|
|
1384
|
+
}
|
|
1385
|
+
if (/pnpm|corepack/u.test(step)) {
|
|
1386
|
+
const pnpmFailure = classifyPnpmInstallFailure(stderr);
|
|
1387
|
+
if (pnpmFailure !== undefined)
|
|
1388
|
+
return pnpmFailure;
|
|
1389
|
+
return new EvePackagingError({
|
|
1390
|
+
code: "DEPENDENCY_AMBIGUITY",
|
|
1391
|
+
subject: "frozen pnpm install",
|
|
1392
|
+
reason: "The isolated pinned pnpm toolchain or install step did not complete inside the builder.",
|
|
1393
|
+
remediation: "Keep the declared exact pnpm version and the frozen lockfile; fix the reported toolchain or install failure and retry.",
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
const pnpmFailure = classifyPnpmInstallFailure(stderr);
|
|
1398
|
+
if (pnpmFailure !== undefined)
|
|
1399
|
+
return pnpmFailure;
|
|
1400
|
+
if (/\bjust-bash\b|Cannot find package/u.test(stderr)) {
|
|
1401
|
+
return classifyEveBuildFailure(stderr);
|
|
1402
|
+
}
|
|
1403
|
+
if (/eve build/u.test(stderr)) {
|
|
1404
|
+
return classifyEveBuildFailure(stderr);
|
|
1405
|
+
}
|
|
1406
|
+
if (/frozen-lockfile|pnpm --version/u.test(stderr)) {
|
|
1269
1407
|
return new EvePackagingError({
|
|
1270
1408
|
code: "DEPENDENCY_AMBIGUITY",
|
|
1271
1409
|
subject: "frozen pnpm install",
|
|
1272
|
-
reason: "The isolated pinned pnpm install
|
|
1273
|
-
remediation: "
|
|
1410
|
+
reason: "The isolated pinned pnpm toolchain or install step did not complete inside the builder.",
|
|
1411
|
+
remediation: "Keep the declared exact pnpm version and the frozen lockfile; fix the reported toolchain or install failure and retry.",
|
|
1274
1412
|
});
|
|
1275
1413
|
}
|
|
1276
1414
|
if (/node_modules\/\.bin\/eve|test -x/u.test(stderr)) {
|
|
@@ -1281,14 +1419,6 @@ function classifyDockerBuildFailure(error) {
|
|
|
1281
1419
|
remediation: "Declare Eve as a project dependency and retry with the frozen lockfile.",
|
|
1282
1420
|
});
|
|
1283
1421
|
}
|
|
1284
|
-
if (/eve build/u.test(stderr)) {
|
|
1285
|
-
return new EvePackagingError({
|
|
1286
|
-
code: "EVE_BUILD_FAILED",
|
|
1287
|
-
subject: "eve build",
|
|
1288
|
-
reason: "The project-local Eve build failed inside the isolated Linux/amd64 builder.",
|
|
1289
|
-
remediation: "Fix the project-local Eve build and retry without changing the authored project during packaging.",
|
|
1290
|
-
});
|
|
1291
|
-
}
|
|
1292
1422
|
return new EvePackagingError({
|
|
1293
1423
|
code: "DOCKER_PLATFORM_BLOCKED",
|
|
1294
1424
|
subject: "Docker/OrbStack",
|
|
@@ -3,7 +3,7 @@ import { execFile, spawn, } from "node:child_process";
|
|
|
3
3
|
import { cp, lstat, mkdir, readFile, readlink, readdir, realpath, rm, symlink, writeFile, } from "node:fs/promises";
|
|
4
4
|
import { dirname, join, relative, resolve, } from "node:path";
|
|
5
5
|
import { promisify, } from "node:util";
|
|
6
|
-
import { EvePackagingError, } from "./eve-packaging.js";
|
|
6
|
+
import { EvePackagingError, eveSnapshotSourceEntries, } from "./eve-packaging.js";
|
|
7
7
|
const execFileAsync = promisify(execFile);
|
|
8
8
|
const START_COMMAND = [
|
|
9
9
|
"./node_modules/.bin/eve",
|
|
@@ -239,7 +239,6 @@ async function captureRuntimeTree(root, snapshotRoot, label) {
|
|
|
239
239
|
}
|
|
240
240
|
};
|
|
241
241
|
await visit(canonicalRoot);
|
|
242
|
-
files.sort((left, right) => left.path.localeCompare(right.path));
|
|
243
242
|
nativeModules.sort((left, right) => left.path.localeCompare(right.path));
|
|
244
243
|
return {
|
|
245
244
|
files,
|
|
@@ -421,8 +420,10 @@ async function writeRuntimeContext(candidate, nodeImage, closure) {
|
|
|
421
420
|
try {
|
|
422
421
|
await cp(join(candidate.snapshotRoot, ".output"), join(runtimeContextPath, ".output"), { recursive: true });
|
|
423
422
|
await cp(join(candidate.snapshotRoot, "node_modules"), join(runtimeContextPath, "node_modules"), { recursive: true });
|
|
424
|
-
await
|
|
425
|
-
|
|
423
|
+
const sourceEntries = await eveSnapshotSourceEntries(candidate.snapshotRoot);
|
|
424
|
+
for (const entry of sourceEntries) {
|
|
425
|
+
await cp(join(candidate.snapshotRoot, entry), join(runtimeContextPath, entry), { recursive: true });
|
|
426
|
+
}
|
|
426
427
|
await rewriteContextLinks(join(candidate.snapshotRoot, "node_modules"), join(runtimeContextPath, "node_modules"));
|
|
427
428
|
await rewriteContextLinks(join(candidate.snapshotRoot, ".output"), join(runtimeContextPath, ".output"));
|
|
428
429
|
const copiedOutput = await captureRuntimeTree(join(runtimeContextPath, ".output"), runtimeContextPath, "output");
|
|
@@ -431,13 +432,15 @@ async function writeRuntimeContext(candidate, nodeImage, closure) {
|
|
|
431
432
|
copiedDependencies.digest !== closure.dependencyDigest) {
|
|
432
433
|
throw packagingError("SOURCE_RACE", "runtime context", "The copied runtime context does not match the validated immutable closure.", "Discard the mixed-generation runtime context and rebuild from a quiescent candidate.");
|
|
433
434
|
}
|
|
435
|
+
const sourceCopyLines = sourceEntries
|
|
436
|
+
.map((entry) => `COPY --from=candidate ${JSON.stringify([`/candidate/${entry}`, `/workspace/${entry}`])}`)
|
|
437
|
+
.join("\n");
|
|
434
438
|
const dockerfile = `# syntax=docker/dockerfile:1
|
|
435
439
|
FROM --platform=linux/amd64 ${imageReference(nodeImage)} AS candidate
|
|
436
|
-
WORKDIR /
|
|
437
|
-
COPY .output /
|
|
438
|
-
COPY node_modules /
|
|
439
|
-
COPY
|
|
440
|
-
COPY package.json /workspace/package.json
|
|
440
|
+
WORKDIR /candidate
|
|
441
|
+
COPY .output /candidate/.output
|
|
442
|
+
COPY node_modules /candidate/node_modules
|
|
443
|
+
${sourceEntries.map((entry) => `COPY ${JSON.stringify([entry, `/candidate/${entry}`])}`).join("\n")}
|
|
441
444
|
|
|
442
445
|
FROM --platform=linux/amd64 ${imageReference(nodeImage)} AS runtime
|
|
443
446
|
WORKDIR /workspace
|
|
@@ -446,10 +449,9 @@ ENV HOST=0.0.0.0 \\
|
|
|
446
449
|
PORT=8080 \\
|
|
447
450
|
NITRO_PORT=8080 \\
|
|
448
451
|
NODE_ENV=production
|
|
449
|
-
COPY --from=candidate /
|
|
450
|
-
COPY --from=candidate /
|
|
451
|
-
|
|
452
|
-
COPY --from=candidate /workspace/package.json /workspace/package.json
|
|
452
|
+
COPY --from=candidate /candidate/.output /workspace/.output
|
|
453
|
+
COPY --from=candidate /candidate/node_modules /workspace/node_modules
|
|
454
|
+
${sourceCopyLines}
|
|
453
455
|
EXPOSE 8080
|
|
454
456
|
ENTRYPOINT ["./node_modules/.bin/eve", "start", "--host", "0.0.0.0", "--port", "8080"]
|
|
455
457
|
`;
|
package/dist/eve.d.ts
CHANGED
|
@@ -6,8 +6,14 @@ export interface EveCliInvocation {
|
|
|
6
6
|
readonly command: EveCliCommand;
|
|
7
7
|
readonly projectRoot: string;
|
|
8
8
|
readonly environment: EveCliEnvironment;
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Absent only on preflight/deploy preview invocations; index.ts derives a
|
|
11
|
+
* deterministic Worker name from the project before execution.
|
|
12
|
+
*/
|
|
13
|
+
readonly name?: string;
|
|
10
14
|
readonly envFile?: string;
|
|
15
|
+
/** When true the command prints the machine-readable result object. */
|
|
16
|
+
readonly json?: boolean;
|
|
11
17
|
}
|
|
12
18
|
export interface EveCliHelp {
|
|
13
19
|
readonly kind: "help";
|
|
@@ -25,6 +31,8 @@ export interface EveCliExecutionRequest {
|
|
|
25
31
|
* layer is the only owner allowed to open or parse its contents.
|
|
26
32
|
*/
|
|
27
33
|
readonly envFile?: string;
|
|
34
|
+
/** When true the command prints the machine-readable result object. */
|
|
35
|
+
readonly json?: boolean;
|
|
28
36
|
}
|
|
29
37
|
export type EveCliRunner = (request: EveCliExecutionRequest) => void | Promise<void>;
|
|
30
38
|
export interface EveCliDiagnostic {
|
|
@@ -43,7 +51,14 @@ export declare class EveCliError extends Error {
|
|
|
43
51
|
readonly diagnostics?: readonly EveCliDiagnostic[];
|
|
44
52
|
});
|
|
45
53
|
}
|
|
46
|
-
export declare const EVE_USAGE = "Usage: eden <preflight|deploy|destroy> [options]\n\nEden Deploy commands:\n preflight Build and inspect a local Eve candidate without remote mutation\n deploy Deploy the selected Eve project to the exact named target\n destroy Remove the exact owned Eve target\n\
|
|
54
|
+
export declare const EVE_USAGE = "Usage: eden <preflight|deploy|destroy> [options]\n\nEden Deploy commands:\n preflight Build and inspect a local Eve candidate without remote mutation\n deploy Deploy the selected Eve project to the exact named target\n destroy Remove the exact owned Eve target\n\nWithout flags, preflight and deploy use the current directory, the preview\nenvironment, and a Worker name derived from the project's package.json name.\n--env accepts only preview or production; production and destroy always\nrequire an explicit --name. --env-file is accepted only by preflight and deploy.\nAll three commands print a human summary by default; --json prints the\nmachine-readable result object for scripts and CI.\n\nOptions:\n --help Show this help\n";
|
|
47
55
|
export declare function eveHelpText(scope: EveCliHelp["scope"]): string;
|
|
48
56
|
export declare function parseEveArguments(args: readonly string[]): ParsedEveInvocation;
|
|
57
|
+
/**
|
|
58
|
+
* Derive a stable, collision-safe Cloudflare Worker name from a raw package
|
|
59
|
+
* name. The sanitized slug is combined with a short digest of the raw name so
|
|
60
|
+
* distinct package names that collide after sanitization stay distinct. The
|
|
61
|
+
* result is deterministic across runs and always satisfies EVE_NAME_PATTERN.
|
|
62
|
+
*/
|
|
63
|
+
export declare function deriveEveTargetName(rawPackageName: string): string;
|
|
49
64
|
//# sourceMappingURL=eve.d.ts.map
|
package/dist/eve.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
export const EVE_CLI_COMMANDS = [
|
|
2
3
|
"preflight",
|
|
3
4
|
"deploy",
|
|
@@ -23,45 +24,50 @@ Eden Deploy commands:
|
|
|
23
24
|
deploy Deploy the selected Eve project to the exact named target
|
|
24
25
|
destroy Remove the exact owned Eve target
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
--env
|
|
29
|
-
|
|
27
|
+
Without flags, preflight and deploy use the current directory, the preview
|
|
28
|
+
environment, and a Worker name derived from the project's package.json name.
|
|
29
|
+
--env accepts only preview or production; production and destroy always
|
|
30
|
+
require an explicit --name. --env-file is accepted only by preflight and deploy.
|
|
31
|
+
All three commands print a human summary by default; --json prints the
|
|
32
|
+
machine-readable result object for scripts and CI.
|
|
30
33
|
|
|
31
34
|
Options:
|
|
32
35
|
--help Show this help
|
|
33
36
|
`;
|
|
34
37
|
const EVE_COMMAND_USAGE = {
|
|
35
|
-
preflight: `Usage: eden preflight --project <path> --env <preview|production> --name <name> [--env-file <path>]
|
|
38
|
+
preflight: `Usage: eden preflight [--project <path>] [--env <preview|production>] [--name <name>] [--env-file <path>] [--json]
|
|
36
39
|
|
|
37
40
|
Build and inspect an immutable local Eve candidate. Preflight is read-only toward remote resources.
|
|
38
41
|
|
|
39
42
|
Options:
|
|
40
|
-
--project <path>
|
|
41
|
-
--env <environment>
|
|
42
|
-
--name <name>
|
|
43
|
+
--project <path> Eve project root (default: current directory)
|
|
44
|
+
--env <environment> preview or production target (default: preview)
|
|
45
|
+
--name <name> Exact target name (default: derived from the project's package.json; required for production)
|
|
43
46
|
--env-file <path> Optional opaque runtime environment file
|
|
47
|
+
--json Print the machine-readable result object (default: human summary)
|
|
44
48
|
--help Show this help
|
|
45
49
|
`,
|
|
46
|
-
deploy: `Usage: eden deploy --project <path> --env <preview|production> --name <name> [--env-file <path>]
|
|
50
|
+
deploy: `Usage: eden deploy [--project <path>] [--env <preview|production>] [--name <name>] [--env-file <path>] [--json]
|
|
47
51
|
|
|
48
52
|
Deploy the selected Eve project to one exact target after host checks pass.
|
|
49
53
|
|
|
50
54
|
Options:
|
|
51
|
-
--project <path>
|
|
52
|
-
--env <environment>
|
|
53
|
-
--name <name>
|
|
55
|
+
--project <path> Eve project root (default: current directory)
|
|
56
|
+
--env <environment> preview or production target (default: preview)
|
|
57
|
+
--name <name> Exact target name (default: derived from the project's package.json; required for production)
|
|
54
58
|
--env-file <path> Optional opaque runtime environment file
|
|
59
|
+
--json Print the machine-readable result object (default: human summary)
|
|
55
60
|
--help Show this help
|
|
56
61
|
`,
|
|
57
|
-
destroy: `Usage: eden destroy --project <path> --env <preview|production> --
|
|
62
|
+
destroy: `Usage: eden destroy --name <name> [--project <path>] [--env <preview|production>] [--json]
|
|
58
63
|
|
|
59
64
|
Destroy only the exact owned Eve target after ownership verification.
|
|
60
65
|
|
|
61
66
|
Options:
|
|
62
|
-
--project <path> Required canonical Eve project root
|
|
63
|
-
--env <environment> Required preview or production target
|
|
64
67
|
--name <name> Required exact target name
|
|
68
|
+
--project <path> Eve project root (default: current directory)
|
|
69
|
+
--env <environment> preview or production target (default: preview)
|
|
70
|
+
--json Print the machine-readable result object (default: human summary)
|
|
65
71
|
--help Show this help
|
|
66
72
|
`,
|
|
67
73
|
};
|
|
@@ -126,6 +132,7 @@ export function parseEveArguments(args) {
|
|
|
126
132
|
let name;
|
|
127
133
|
let envFile;
|
|
128
134
|
let help = false;
|
|
135
|
+
let json = false;
|
|
129
136
|
for (let index = 1; index < args.length; index += 1) {
|
|
130
137
|
const argument = args[index];
|
|
131
138
|
if (argument === undefined) {
|
|
@@ -205,6 +212,10 @@ export function parseEveArguments(args) {
|
|
|
205
212
|
envFile = parseEnvFileValue(argument.slice("--env-file=".length));
|
|
206
213
|
continue;
|
|
207
214
|
}
|
|
215
|
+
if (argument === "--json") {
|
|
216
|
+
json = true;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
208
219
|
if (argument.startsWith("-")) {
|
|
209
220
|
throw eveError("EVE_OPTION_UNKNOWN", "The Eve command contains an unknown option.");
|
|
210
221
|
}
|
|
@@ -213,22 +224,45 @@ export function parseEveArguments(args) {
|
|
|
213
224
|
if (help) {
|
|
214
225
|
return { kind: "help", scope: command };
|
|
215
226
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
throw eveError("
|
|
221
|
-
}
|
|
222
|
-
if (name === undefined) {
|
|
223
|
-
throw eveError("EVE_NAME_REQUIRED", "The --name option is required for every Eve command.");
|
|
227
|
+
const resolvedEnvironment = environment ?? "preview";
|
|
228
|
+
const resolvedProjectRoot = projectRoot ?? ".";
|
|
229
|
+
if (name === undefined &&
|
|
230
|
+
(command === "destroy" || resolvedEnvironment === "production")) {
|
|
231
|
+
throw eveError("EVE_NAME_REQUIRED", "An explicit --name is required for destroy and for production targets.");
|
|
224
232
|
}
|
|
225
233
|
return {
|
|
226
234
|
kind: "invocation",
|
|
227
235
|
command,
|
|
228
|
-
projectRoot,
|
|
229
|
-
environment,
|
|
230
|
-
name,
|
|
236
|
+
projectRoot: resolvedProjectRoot,
|
|
237
|
+
environment: resolvedEnvironment,
|
|
238
|
+
...(name === undefined ? {} : { name }),
|
|
231
239
|
...(envFile === undefined ? {} : { envFile }),
|
|
240
|
+
...(json ? { json: true } : {}),
|
|
232
241
|
};
|
|
233
242
|
}
|
|
243
|
+
const WORKER_NAME_LIMIT = 63;
|
|
244
|
+
/**
|
|
245
|
+
* Derive a stable, collision-safe Cloudflare Worker name from a raw package
|
|
246
|
+
* name. The sanitized slug is combined with a short digest of the raw name so
|
|
247
|
+
* distinct package names that collide after sanitization stay distinct. The
|
|
248
|
+
* result is deterministic across runs and always satisfies EVE_NAME_PATTERN.
|
|
249
|
+
*/
|
|
250
|
+
export function deriveEveTargetName(rawPackageName) {
|
|
251
|
+
const slug = rawPackageName
|
|
252
|
+
.toLowerCase()
|
|
253
|
+
.replace(/[^a-z0-9-]+/gu, "-")
|
|
254
|
+
.replace(/-{2,}/gu, "-")
|
|
255
|
+
.replace(/^-+|-+$/gu, "");
|
|
256
|
+
if (slug.length === 0) {
|
|
257
|
+
throw eveError("EVE_NAME_DERIVATION_FAILED", "A target name could not be derived from the project package.json; pass an explicit --name.");
|
|
258
|
+
}
|
|
259
|
+
const digest = createHash("sha256")
|
|
260
|
+
.update(rawPackageName, "utf8")
|
|
261
|
+
.digest("hex")
|
|
262
|
+
.slice(0, 8);
|
|
263
|
+
const stem = slug
|
|
264
|
+
.slice(0, WORKER_NAME_LIMIT - digest.length - 1)
|
|
265
|
+
.replace(/-+$/u, "");
|
|
266
|
+
return `${stem}-${digest}`;
|
|
267
|
+
}
|
|
234
268
|
//# sourceMappingURL=eve.js.map
|