@moinulmoin/eden 0.2.2 → 0.4.1
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 +8 -0
- package/README.md +3 -3
- package/dist/eve-control-plane.d.ts +7 -0
- package/dist/eve-control-plane.js +235 -0
- package/dist/eve-packaging.d.ts +1 -1
- package/dist/eve-packaging.js +16 -3
- package/dist/eve-runtime-config.d.ts +1 -1
- package/dist/eve-runtime-config.js +3 -1
- package/dist/eve-runtime-image.d.ts +8 -0
- package/dist/eve-runtime-image.js +57 -39
- package/dist/index.d.ts +1 -1
- package/package.json +2 -2
package/NOTICE
CHANGED
|
@@ -9,3 +9,11 @@ Eden's generated Worker host bundle includes software from
|
|
|
9
9
|
`@cloudflare/containers`, distributed under MIT OR Apache-2.0. Eden
|
|
10
10
|
redistributes that bundled software under the Apache-2.0 option included in
|
|
11
11
|
LICENSE.
|
|
12
|
+
|
|
13
|
+
Workflow SDK
|
|
14
|
+
@workflow/world-postgres, version 5.0.0-beta.47
|
|
15
|
+
https://github.com/vercel/workflow
|
|
16
|
+
|
|
17
|
+
Eden's Cloudflare World storage implementation
|
|
18
|
+
(`@moinulmoin/eden-world-cloudflare`) is adapted from the Workflow SDK
|
|
19
|
+
PostgreSQL World, distributed under the Apache License, Version 2.0.
|
package/README.md
CHANGED
|
@@ -12,15 +12,15 @@ If you already have an Eve project, start with `eden deploy`.
|
|
|
12
12
|
Use any one of these package managers:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npm install --global @moinulmoin/eden@0.
|
|
15
|
+
npm install --global @moinulmoin/eden@0.4.1
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
pnpm add --global @moinulmoin/eden@0.
|
|
19
|
+
pnpm add --global @moinulmoin/eden@0.4.1
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
```sh
|
|
23
|
-
bun add --global @moinulmoin/eden@0.
|
|
23
|
+
bun add --global @moinulmoin/eden@0.4.1
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Then confirm the CLI is available:
|
|
@@ -31,12 +31,18 @@ export interface EveDeploymentMetadata {
|
|
|
31
31
|
readonly runtimeVariableNames: readonly string[];
|
|
32
32
|
readonly evidenceRetained: true;
|
|
33
33
|
}
|
|
34
|
+
export interface EvePreflightWarning {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
readonly message: string;
|
|
37
|
+
readonly remediation?: string;
|
|
38
|
+
}
|
|
34
39
|
export interface EvePreflightResult {
|
|
35
40
|
readonly command: "eve preflight" | "eve deploy";
|
|
36
41
|
readonly ok: boolean;
|
|
37
42
|
readonly environment: EveCliEnvironment;
|
|
38
43
|
readonly name: string;
|
|
39
44
|
readonly checks: readonly EvePreflightCheck[];
|
|
45
|
+
readonly warnings: readonly EvePreflightWarning[];
|
|
40
46
|
readonly candidate: EvePreflightCandidate | null;
|
|
41
47
|
readonly deployment?: EveDeploymentMetadata;
|
|
42
48
|
}
|
|
@@ -77,6 +83,7 @@ export interface EvePreflightRuntimeRunnerRequest {
|
|
|
77
83
|
readonly publicOrigin?: string;
|
|
78
84
|
readonly runtimeInjection?: EveRuntimeInjection;
|
|
79
85
|
readonly retainImage?: boolean;
|
|
86
|
+
readonly workflowWorld?: string;
|
|
80
87
|
}
|
|
81
88
|
export type EvePreflightRuntimeRunner = (request: EvePreflightRuntimeRunnerRequest) => EvePreflightRuntimeEvidence | Promise<EvePreflightRuntimeEvidence>;
|
|
82
89
|
export type EveRuntimeImageDiscardRunner = (request: EveRuntimeImageDiscardRequest) => boolean | Promise<boolean>;
|
|
@@ -75,6 +75,172 @@ function blockedAfterFailure(id, message) {
|
|
|
75
75
|
function allChecksClear(checks) {
|
|
76
76
|
return checks.every((value) => value.status === "passed" || value.status === "skipped");
|
|
77
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Path, inside the built snapshot, of the manifest `eve build` writes with the
|
|
80
|
+
* resolved agent configuration. `config.experimental.workflow.world` is the
|
|
81
|
+
* field Eve itself resolves at build time; absent/`local`/
|
|
82
|
+
* `@workflow/world-local` mean Eve's container-local default World.
|
|
83
|
+
*/
|
|
84
|
+
const EVE_COMPILED_MANIFEST_PATH = ".output/.eve/compile/compiled-agent-manifest.json";
|
|
85
|
+
async function readCompiledWorldSpecifier(candidate) {
|
|
86
|
+
try {
|
|
87
|
+
const manifest = JSON.parse(await readFile(join(candidate.snapshotRoot, EVE_COMPILED_MANIFEST_PATH), "utf8"));
|
|
88
|
+
const world = manifest?.config?.experimental?.workflow?.world;
|
|
89
|
+
return typeof world === "string" ? world : undefined;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Reads authored schedules out of the compiled manifest `eve build` writes.
|
|
97
|
+
* Root `schedules` covers file and extension-mounted schedules; declared
|
|
98
|
+
* subagents cannot carry schedules, so only the root array is consulted.
|
|
99
|
+
*/
|
|
100
|
+
async function readCompiledSchedules(candidate) {
|
|
101
|
+
try {
|
|
102
|
+
const manifest = JSON.parse(await readFile(join(candidate.snapshotRoot, EVE_COMPILED_MANIFEST_PATH), "utf8"));
|
|
103
|
+
const schedules = manifest?.schedules;
|
|
104
|
+
if (!Array.isArray(schedules))
|
|
105
|
+
return [];
|
|
106
|
+
return schedules.flatMap((schedule) => typeof schedule.name === "string" && typeof schedule.cron === "string"
|
|
107
|
+
? [{ name: schedule.name, cron: schedule.cron }]
|
|
108
|
+
: []);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Mirrors Eve's own `assertWorkflowWorldCompatibility`
|
|
116
|
+
* (dist/src/internal/workflow/world-compatibility.js): Eve derives the
|
|
117
|
+
* expected Workflow line from its installed manifest's `@workflow/core`
|
|
118
|
+
* dependency, reads the selected World's manifest for a `@workflow/core` or
|
|
119
|
+
* `@workflow/world` dependency, and fails only on a definite line mismatch —
|
|
120
|
+
* different major, or both prerelease tags present and different.
|
|
121
|
+
*/
|
|
122
|
+
function parseWorkflowVersionLine(range) {
|
|
123
|
+
const match = /(\d+)\.(?:\d+|x|\*)(?:\.(?:\d+|x|\*))?(?:-([0-9A-Za-z.-]+))?/u.exec(range.trim());
|
|
124
|
+
if (match === null)
|
|
125
|
+
return undefined;
|
|
126
|
+
const major = Number(match[1]);
|
|
127
|
+
if (!Number.isInteger(major))
|
|
128
|
+
return undefined;
|
|
129
|
+
return {
|
|
130
|
+
major,
|
|
131
|
+
...(match[2] === undefined
|
|
132
|
+
? {}
|
|
133
|
+
: { prereleaseTag: match[2].split(".")[0] }),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
async function readInstalledManifest(snapshotRoot, packageName) {
|
|
137
|
+
try {
|
|
138
|
+
return JSON.parse(await readFile(join(snapshotRoot, "node_modules", packageName, "package.json"), "utf8"));
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Fails deploy/preflight when a known durable World would trip Eve's runtime
|
|
146
|
+
* World-compatibility rejection. Unreadable manifests
|
|
147
|
+
* mirror Eve's own behavior (skip); Eve is the runtime authority.
|
|
148
|
+
*/
|
|
149
|
+
async function checkEveWorldPairing(candidate, world) {
|
|
150
|
+
if (world !== "@workflow/world-postgres" &&
|
|
151
|
+
world !== "@moinulmoin/eden-world-cloudflare")
|
|
152
|
+
return undefined;
|
|
153
|
+
const eveManifest = await readInstalledManifest(candidate.snapshotRoot, "eve");
|
|
154
|
+
const expectedRange = eveManifest === undefined
|
|
155
|
+
? undefined
|
|
156
|
+
: [
|
|
157
|
+
eveManifest.devDependencies,
|
|
158
|
+
eveManifest.dependencies,
|
|
159
|
+
eveManifest.peerDependencies,
|
|
160
|
+
]
|
|
161
|
+
.map((deps) => deps?.["@workflow/core"])
|
|
162
|
+
.find((value) => typeof value === "string" && value.trim().length > 0);
|
|
163
|
+
if (expectedRange === undefined)
|
|
164
|
+
return undefined;
|
|
165
|
+
const worldManifest = await readInstalledManifest(candidate.snapshotRoot, world);
|
|
166
|
+
const declared = worldManifest === undefined
|
|
167
|
+
? undefined
|
|
168
|
+
: ["@workflow/core", "@workflow/world"]
|
|
169
|
+
.map((name) => ({
|
|
170
|
+
packageName: name,
|
|
171
|
+
range: worldManifest.dependencies?.[name] ??
|
|
172
|
+
worldManifest.peerDependencies?.[name],
|
|
173
|
+
}))
|
|
174
|
+
.find((entry) => typeof entry.range === "string" && entry.range.trim().length > 0);
|
|
175
|
+
if (declared === undefined)
|
|
176
|
+
return undefined;
|
|
177
|
+
const declaredLine = parseWorkflowVersionLine(declared.range);
|
|
178
|
+
const expectedLine = parseWorkflowVersionLine(expectedRange);
|
|
179
|
+
if (declaredLine === undefined || expectedLine === undefined) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
const mismatch = declaredLine.major !== expectedLine.major ||
|
|
183
|
+
(declaredLine.prereleaseTag !== undefined &&
|
|
184
|
+
expectedLine.prereleaseTag !== undefined &&
|
|
185
|
+
declaredLine.prereleaseTag !== expectedLine.prereleaseTag);
|
|
186
|
+
if (mismatch) {
|
|
187
|
+
return check("EVE_WORLD_PAIRING", "failed", `The installed ${world} targets ${declared.packageName} ${declared.range}, but the project's Eve bundles @workflow/core ${expectedRange}; Eve rejects this World at runtime.`, `Install the ${world} release whose ${declared.packageName} dependency matches the Eve-bundled @workflow/core ${expectedRange} line; see docs/deploy.md.`);
|
|
188
|
+
}
|
|
189
|
+
return check("EVE_WORLD_PAIRING", "passed", `The installed ${world} ${declared.packageName} dependency ${declared.range} pairs with the Eve-bundled @workflow/core ${expectedRange}.`);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Returns a generic reason when the URL targets a transaction-mode pooler.
|
|
193
|
+
* Never returns URL content; only a safe classification of the host/port.
|
|
194
|
+
*/
|
|
195
|
+
function pooledPostgresReason(connectionString) {
|
|
196
|
+
if (connectionString === undefined)
|
|
197
|
+
return undefined;
|
|
198
|
+
let url;
|
|
199
|
+
try {
|
|
200
|
+
url = new URL(connectionString);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
if (url.hostname.includes("-pooler")) {
|
|
206
|
+
return "a transaction-mode pooler host";
|
|
207
|
+
}
|
|
208
|
+
if (url.port === "6543") {
|
|
209
|
+
return "a transaction-mode pooler port";
|
|
210
|
+
}
|
|
211
|
+
return undefined;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Non-blocking World warnings. The container wipes its disk on sleep, so the
|
|
215
|
+
* default local World loses pending approvals and sessions; and a pooled
|
|
216
|
+
* Postgres URL breaks the World streamer, which relies on LISTEN/NOTIFY.
|
|
217
|
+
*/
|
|
218
|
+
async function collectEveWorldWarnings(candidate, runtimeConfig) {
|
|
219
|
+
const warnings = [];
|
|
220
|
+
if (candidate !== undefined) {
|
|
221
|
+
const world = await readCompiledWorldSpecifier(candidate);
|
|
222
|
+
if (world === undefined ||
|
|
223
|
+
world === "local" ||
|
|
224
|
+
world === "@workflow/world-local") {
|
|
225
|
+
warnings.push({
|
|
226
|
+
id: "EVE_WORLD_LOCAL",
|
|
227
|
+
message: "This project uses Eve's default local Workflow World; workflow state lives on the container disk and is lost when the container sleeps.",
|
|
228
|
+
remediation: "Configure a durable Workflow World such as @workflow/world-postgres; see docs/deploy.md#durable-state-postgres-world.",
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (runtimeConfig !== undefined) {
|
|
233
|
+
const pooledReason = runtimeConfig.withProtectedValues((values) => pooledPostgresReason(values.WORKFLOW_POSTGRES_URL ?? values.DATABASE_URL));
|
|
234
|
+
if (pooledReason !== undefined) {
|
|
235
|
+
warnings.push({
|
|
236
|
+
id: "EVE_WORLD_POSTGRES_POOLED",
|
|
237
|
+
message: `The configured Postgres connection uses ${pooledReason}; transaction-mode poolers accept LISTEN but never deliver notifications, so live session streaming hangs.`,
|
|
238
|
+
remediation: "Use the direct, unpooled Postgres URL for WORKFLOW_POSTGRES_URL (on Neon, the unpooled host without -pooler); see docs/deploy.md#durable-state-postgres-world.",
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return warnings;
|
|
243
|
+
}
|
|
78
244
|
/** True when the caller asked for the human progress/summary output. */
|
|
79
245
|
function humanOutput(options) {
|
|
80
246
|
return options.outputFormat === "human";
|
|
@@ -113,6 +279,12 @@ function formatEveElapsed(startedAt) {
|
|
|
113
279
|
*/
|
|
114
280
|
function humanEveResultLines(result, startedAt, eveVersion) {
|
|
115
281
|
const lines = [...eveCheckLines(result.checks)];
|
|
282
|
+
for (const warning of result.warnings) {
|
|
283
|
+
lines.push(`! ${warning.id} — ${safeText(warning.message)}`);
|
|
284
|
+
if (warning.remediation !== undefined) {
|
|
285
|
+
lines.push(` → ${safeText(warning.remediation)}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
116
288
|
const elapsed = formatEveElapsed(startedAt);
|
|
117
289
|
const commandLabel = result.command === "eve deploy" ? "deploy" : "preflight";
|
|
118
290
|
if (result.ok) {
|
|
@@ -497,6 +669,9 @@ async function defaultRuntimeRunner(request) {
|
|
|
497
669
|
...(request.runtimeInjection === undefined
|
|
498
670
|
? {}
|
|
499
671
|
: { runtimeInjection: request.runtimeInjection }),
|
|
672
|
+
...(request.workflowWorld === undefined
|
|
673
|
+
? {}
|
|
674
|
+
: { workflowWorld: request.workflowWorld }),
|
|
500
675
|
retainImage: request.retainImage ?? false,
|
|
501
676
|
};
|
|
502
677
|
result = await buildEveRuntimeImage(imageRequest);
|
|
@@ -1242,6 +1417,13 @@ async function runEveDeployment(request, options, collected) {
|
|
|
1242
1417
|
...(identity.runtimeRevisionHandle === undefined
|
|
1243
1418
|
? {}
|
|
1244
1419
|
: { runtimeRevisionHandle: identity.runtimeRevisionHandle }),
|
|
1420
|
+
schedules: collected.schedules ?? [],
|
|
1421
|
+
...(collected.workflowWorld === undefined
|
|
1422
|
+
? {}
|
|
1423
|
+
: { workflowWorld: collected.workflowWorld }),
|
|
1424
|
+
...(process.env.EDEN_EVE_CONTAINER_SLEEP_AFTER === undefined
|
|
1425
|
+
? {}
|
|
1426
|
+
: { containerSleepAfter: process.env.EDEN_EVE_CONTAINER_SLEEP_AFTER }),
|
|
1245
1427
|
});
|
|
1246
1428
|
}
|
|
1247
1429
|
catch (error) {
|
|
@@ -1495,6 +1677,7 @@ async function runEveDeployment(request, options, collected) {
|
|
|
1495
1677
|
}
|
|
1496
1678
|
async function collectEvePreflight(request, options) {
|
|
1497
1679
|
let runtimeConfig;
|
|
1680
|
+
const warnings = [];
|
|
1498
1681
|
const checks = [];
|
|
1499
1682
|
if (request.envFile !== undefined) {
|
|
1500
1683
|
eveProgress(options, "validating environment file");
|
|
@@ -1509,6 +1692,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1509
1692
|
else {
|
|
1510
1693
|
runtimeConfig = await options.runtimeConfigLoader(request.envFile, request.cwd);
|
|
1511
1694
|
checks.push(check("VAL-SEC-001", "passed", "The explicit environment file passed the deployment-safety opaque UTF-8 KEY=VALUE grammar."), check("VAL-SEC-002", "passed", "The explicit environment file contains no reserved Eve host-variable collision."));
|
|
1695
|
+
warnings.push(...(await collectEveWorldWarnings(undefined, runtimeConfig)));
|
|
1512
1696
|
}
|
|
1513
1697
|
}
|
|
1514
1698
|
catch (error) {
|
|
@@ -1522,6 +1706,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1522
1706
|
environment: request.environment,
|
|
1523
1707
|
name: request.name,
|
|
1524
1708
|
checks,
|
|
1709
|
+
warnings,
|
|
1525
1710
|
candidate: null,
|
|
1526
1711
|
},
|
|
1527
1712
|
runtimeConfig,
|
|
@@ -1615,12 +1800,52 @@ async function collectEvePreflight(request, options) {
|
|
|
1615
1800
|
environment: request.environment,
|
|
1616
1801
|
name: request.name,
|
|
1617
1802
|
checks,
|
|
1803
|
+
warnings,
|
|
1618
1804
|
candidate: null,
|
|
1619
1805
|
},
|
|
1620
1806
|
runtimeConfig,
|
|
1621
1807
|
};
|
|
1622
1808
|
}
|
|
1623
1809
|
const candidate = packaging.candidate;
|
|
1810
|
+
const workflowWorld = await readCompiledWorldSpecifier(candidate);
|
|
1811
|
+
if (workflowWorld === "@moinulmoin/eden-world-cloudflare") {
|
|
1812
|
+
checks.push(check("EVE-WORLD", "passed", "world: Cloudflare Durable Object"));
|
|
1813
|
+
}
|
|
1814
|
+
warnings.push(...(await collectEveWorldWarnings(candidate, undefined)));
|
|
1815
|
+
const schedules = await readCompiledSchedules(candidate);
|
|
1816
|
+
// The runtime package is imported lazily so `eden` commands that never
|
|
1817
|
+
// reach deploy checks stay fast; the module specifier is fixed.
|
|
1818
|
+
const { parseEveScheduleCron } = await import("@moinulmoin/eden-runtime-cloudflare");
|
|
1819
|
+
const expressible = schedules.filter((schedule) => parseEveScheduleCron(schedule.cron) !== undefined);
|
|
1820
|
+
const unexpressible = schedules.filter((schedule) => parseEveScheduleCron(schedule.cron) === undefined);
|
|
1821
|
+
if (unexpressible.length > 0) {
|
|
1822
|
+
warnings.push({
|
|
1823
|
+
id: "EVE_SCHEDULE_UNSUPPORTED",
|
|
1824
|
+
message: `Schedule ${unexpressible.map((schedule) => schedule.name).join(", ")} uses a cron expression Cloudflare wake triggers cannot evaluate, so it only fires while the Container is already awake.`,
|
|
1825
|
+
remediation: "Use a standard 5-field cron expression (minute hour day-of-month month day-of-week) for schedules that must fire while the Container sleeps.",
|
|
1826
|
+
});
|
|
1827
|
+
}
|
|
1828
|
+
if (expressible.length > 0) {
|
|
1829
|
+
checks.push(check("EVE-SCHEDULES", "passed", `schedules: ${expressible.length} (wake via Cloudflare Cron)`));
|
|
1830
|
+
}
|
|
1831
|
+
const worldPairing = await checkEveWorldPairing(candidate, workflowWorld);
|
|
1832
|
+
if (worldPairing !== undefined)
|
|
1833
|
+
checks.push(worldPairing);
|
|
1834
|
+
if (!allChecksClear(checks)) {
|
|
1835
|
+
await discardPackagingImage();
|
|
1836
|
+
return {
|
|
1837
|
+
result: {
|
|
1838
|
+
command: request.command === "deploy" ? "eve deploy" : "eve preflight",
|
|
1839
|
+
ok: false,
|
|
1840
|
+
environment: request.environment,
|
|
1841
|
+
name: request.name,
|
|
1842
|
+
checks,
|
|
1843
|
+
warnings,
|
|
1844
|
+
candidate: candidateMetadata(candidate, undefined),
|
|
1845
|
+
},
|
|
1846
|
+
runtimeConfig,
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1624
1849
|
let cloudflare;
|
|
1625
1850
|
let publicOrigin;
|
|
1626
1851
|
if (request.command === "deploy") {
|
|
@@ -1643,6 +1868,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1643
1868
|
environment: request.environment,
|
|
1644
1869
|
name: request.name,
|
|
1645
1870
|
checks,
|
|
1871
|
+
warnings,
|
|
1646
1872
|
candidate: candidateMetadata(candidate, undefined),
|
|
1647
1873
|
},
|
|
1648
1874
|
runtimeConfig,
|
|
@@ -1662,6 +1888,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1662
1888
|
environment: request.environment,
|
|
1663
1889
|
name: request.name,
|
|
1664
1890
|
checks,
|
|
1891
|
+
warnings,
|
|
1665
1892
|
candidate: candidateMetadata(candidate, undefined),
|
|
1666
1893
|
},
|
|
1667
1894
|
runtimeConfig,
|
|
@@ -1714,6 +1941,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1714
1941
|
...(publicOrigin === undefined ? {} : { publicOrigin }),
|
|
1715
1942
|
retainImage: request.command === "deploy",
|
|
1716
1943
|
...(runtimeInjection === undefined ? {} : { runtimeInjection }),
|
|
1944
|
+
...(workflowWorld === undefined ? {} : { workflowWorld }),
|
|
1717
1945
|
});
|
|
1718
1946
|
checks.push(...runtimeEvidence.checks);
|
|
1719
1947
|
const requiredRuntimeChecks = [
|
|
@@ -1766,6 +1994,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1766
1994
|
environment: request.environment,
|
|
1767
1995
|
name: request.name,
|
|
1768
1996
|
checks,
|
|
1997
|
+
warnings,
|
|
1769
1998
|
candidate: candidateResult,
|
|
1770
1999
|
},
|
|
1771
2000
|
runtimeConfig,
|
|
@@ -1791,6 +2020,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1791
2020
|
environment: request.environment,
|
|
1792
2021
|
name: request.name,
|
|
1793
2022
|
checks,
|
|
2023
|
+
warnings,
|
|
1794
2024
|
candidate: candidateResult,
|
|
1795
2025
|
},
|
|
1796
2026
|
runtimeConfig,
|
|
@@ -1806,6 +2036,7 @@ async function collectEvePreflight(request, options) {
|
|
|
1806
2036
|
environment: request.environment,
|
|
1807
2037
|
name: request.name,
|
|
1808
2038
|
checks,
|
|
2039
|
+
warnings,
|
|
1809
2040
|
candidate: candidateResult,
|
|
1810
2041
|
},
|
|
1811
2042
|
runtimeConfig,
|
|
@@ -1814,7 +2045,11 @@ async function collectEvePreflight(request, options) {
|
|
|
1814
2045
|
? {}
|
|
1815
2046
|
: { projectId: packaging.project.projectId }),
|
|
1816
2047
|
...(runtimeEvidence === undefined ? {} : { runtimeEvidence }),
|
|
2048
|
+
// Only expressible schedules are wired into wake triggers; the rest were
|
|
2049
|
+
// reported as EVE_SCHEDULE_UNSUPPORTED and fire only while awake.
|
|
2050
|
+
schedules: expressible,
|
|
1817
2051
|
cloudflare,
|
|
2052
|
+
...(workflowWorld === undefined ? {} : { workflowWorld }),
|
|
1818
2053
|
};
|
|
1819
2054
|
}
|
|
1820
2055
|
export async function runEveControlPlane(request, options = {}) {
|
package/dist/eve-packaging.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { EveRuntimeInputIdentity } from "./eve-runtime-config.js";
|
|
2
|
-
export type EvePackagingCode = "ROOT_INVALID" | "UNSUPPORTED_TOOLCHAIN" | "DEPENDENCY_AMBIGUITY" | "SOURCE_RACE" | "EVE_BUILD_FAILED" | "UNSUPPORTED_EVE_OUTPUT" | "RUNTIME_CLOSURE_INCOMPLETE" | "SECRET_EXCLUSION_FAILED" | "DOCKER_PLATFORM_BLOCKED" | "UNSUPPORTED_HOST_REQUIREMENT" | "EVE_HEALTH_FAILED" | "CLEANUP_UNVERIFIED" | "PACKAGE_VERIFICATION_FAILED";
|
|
2
|
+
export type EvePackagingCode = "ROOT_INVALID" | "UNSUPPORTED_TOOLCHAIN" | "DEPENDENCY_AMBIGUITY" | "SOURCE_RACE" | "EVE_BUILD_FAILED" | "UNSUPPORTED_EVE_OUTPUT" | "RUNTIME_CLOSURE_INCOMPLETE" | "SECRET_EXCLUSION_FAILED" | "DOCKER_PLATFORM_BLOCKED" | "UNSUPPORTED_HOST_REQUIREMENT" | "EVE_HEALTH_FAILED" | "WORLD_MIGRATION_FAILED" | "CLEANUP_UNVERIFIED" | "PACKAGE_VERIFICATION_FAILED";
|
|
3
3
|
export interface EveRuntimeConfigExclusion {
|
|
4
4
|
/**
|
|
5
5
|
* This path is opaque. The packaging worker only uses its lexical identity
|
package/dist/eve-packaging.js
CHANGED
|
@@ -16,6 +16,17 @@ export class EvePackagingError extends Error {
|
|
|
16
16
|
this.remediation = options.remediation;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
// The Postgres World's `cbor-x` dependency declares `cbor-extract` as an
|
|
20
|
+
// optional native accelerator whose prebuilt binary cannot load in the
|
|
21
|
+
// runtime image. pnpm's CLI cannot exempt a single package from
|
|
22
|
+
// strict-dep-builds, so the Dockerfile passes
|
|
23
|
+
// `--config.strict-dep-builds=false` and then runs
|
|
24
|
+
// IGNORED_BUILDS_GUARD, which restores the strict failure for every ignored
|
|
25
|
+
// build script except cbor-extract. Eden never runs dependency build scripts
|
|
26
|
+
// either way, `--frozen-lockfile` stays honest, cbor-extract's .node binary is
|
|
27
|
+
// exempt from the ldd check, and the runtime stage sets
|
|
28
|
+
// CBOR_NATIVE_ACCELERATION_DISABLED.
|
|
29
|
+
const IGNORED_BUILDS_GUARD = `node -e 'const m=JSON.parse(require("fs").readFileSync("node_modules/.modules.yaml","utf8"));const b=(m.ignoredBuilds||[]).filter((p)=>!p.startsWith("cbor-extract@"));if(b.length){console.error("ERR_PNPM_IGNORED_BUILDS Ignored build scripts: "+b.join(", "));process.exit(1)}'`;
|
|
19
30
|
const INSTALL_COMMAND = [
|
|
20
31
|
"corepack",
|
|
21
32
|
"pnpm",
|
|
@@ -943,7 +954,8 @@ RUN corepack enable \\
|
|
|
943
954
|
&& corepack prepare pnpm@${options.packageManagerVersion} --activate \\
|
|
944
955
|
&& test "$(corepack pnpm --version)" = "${options.packageManagerVersion}" \\
|
|
945
956
|
&& test "$(sha256sum pnpm-lock.yaml | cut -d ' ' -f1)" = "${options.lockfileSha256}" \\
|
|
946
|
-
&& corepack pnpm install --frozen-lockfile --config.node-linker=hoisted
|
|
957
|
+
&& corepack pnpm install --frozen-lockfile --config.node-linker=hoisted --config.strict-dep-builds=false \\
|
|
958
|
+
&& ${IGNORED_BUILDS_GUARD}
|
|
947
959
|
RUN test "$(sha256sum pnpm-lock.yaml | cut -d ' ' -f1)" = "${options.lockfileSha256}"
|
|
948
960
|
COPY . ./
|
|
949
961
|
RUN test -x ./node_modules/.bin/eve \\
|
|
@@ -951,7 +963,8 @@ RUN test -x ./node_modules/.bin/eve \\
|
|
|
951
963
|
|
|
952
964
|
FROM builder AS runtime-deps
|
|
953
965
|
RUN rm -rf node_modules \\
|
|
954
|
-
&& corepack pnpm install --frozen-lockfile --prod --config.node-linker=hoisted \\
|
|
966
|
+
&& corepack pnpm install --frozen-lockfile --prod --config.node-linker=hoisted --config.strict-dep-builds=false \\
|
|
967
|
+
&& ${IGNORED_BUILDS_GUARD} \\
|
|
955
968
|
&& for l in node_modules/.bin/*; do t=$(readlink "$l") || continue; case "$t" in /*) ln -sfn "$(realpath --relative-to=node_modules/.bin "$t")" "$l" ;; esac; done
|
|
956
969
|
|
|
957
970
|
FROM --platform=linux/amd64 ${image} AS runtime
|
|
@@ -1339,7 +1352,7 @@ function classifyPnpmInstallFailure(stderr) {
|
|
|
1339
1352
|
return new EvePackagingError({
|
|
1340
1353
|
code: "DEPENDENCY_AMBIGUITY",
|
|
1341
1354
|
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.",
|
|
1355
|
+
reason: "The isolated pinned pnpm install refused dependency build scripts that the project pnpm policy neither allows nor ignores (the known-optional cbor-extract addon is already exempted by Eden).",
|
|
1343
1356
|
remediation: "Name the dependency under allowBuilds or ignoredBuiltDependencies in the project pnpm-workspace.yaml and retry.",
|
|
1344
1357
|
});
|
|
1345
1358
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const EVE_RESERVED_HOST_VARIABLES: readonly ["HOST", "NITRO_HOST", "PORT", "NITRO_PORT", "NODE_ENV", "NODE_EXTRA_CA_CERTS", "WORKFLOW_LOCAL_BASE_URL", "EDEN_EVE_DEPLOYMENT_ID", "EDEN_EVE_GENERATION_ID"];
|
|
1
|
+
export declare const EVE_RESERVED_HOST_VARIABLES: readonly ["HOST", "NITRO_HOST", "PORT", "NITRO_PORT", "NODE_ENV", "NODE_EXTRA_CA_CERTS", "WORKFLOW_LOCAL_BASE_URL", "EDEN_WORLD_URL", "EDEN_EVE_DEPLOYMENT_ID", "EDEN_EVE_GENERATION_ID"];
|
|
2
2
|
export type EveReservedHostVariable = (typeof EVE_RESERVED_HOST_VARIABLES)[number];
|
|
3
3
|
export declare const EVE_START_COMMAND: readonly ["./node_modules/.bin/eve", "start", "--host", "0.0.0.0", "--port", "8080"];
|
|
4
4
|
type EveRuntimeValueMap = Readonly<Record<string, string>>;
|
|
@@ -9,6 +9,7 @@ export const EVE_RESERVED_HOST_VARIABLES = Object.freeze([
|
|
|
9
9
|
"NODE_ENV",
|
|
10
10
|
"NODE_EXTRA_CA_CERTS",
|
|
11
11
|
"WORKFLOW_LOCAL_BASE_URL",
|
|
12
|
+
"EDEN_WORLD_URL",
|
|
12
13
|
"EDEN_EVE_DEPLOYMENT_ID",
|
|
13
14
|
"EDEN_EVE_GENERATION_ID",
|
|
14
15
|
]);
|
|
@@ -275,7 +276,8 @@ export class EveRuntimeConfig {
|
|
|
275
276
|
createStartEnvironment(hostEnvironment) {
|
|
276
277
|
this.assertUsable();
|
|
277
278
|
for (const name of Object.keys(hostEnvironment)) {
|
|
278
|
-
if (!EVE_RESERVED_HOST_VARIABLES.includes(name)
|
|
279
|
+
if (!EVE_RESERVED_HOST_VARIABLES.includes(name) &&
|
|
280
|
+
name !== "CBOR_NATIVE_ACCELERATION_DISABLED") {
|
|
279
281
|
throw new EveRuntimeConfigError({
|
|
280
282
|
code: "EVE_RUNTIME_INJECTION_INVALID",
|
|
281
283
|
message: `The Eve start environment contains a non-host variable ${name}.`,
|
|
@@ -86,6 +86,14 @@ export interface EveRuntimeImageRequest {
|
|
|
86
86
|
readonly hostRequirements?: EveHostRequirements;
|
|
87
87
|
readonly publicOrigin?: string;
|
|
88
88
|
readonly runtimeInjection?: EveRuntimeInjection;
|
|
89
|
+
/**
|
|
90
|
+
* The Workflow World specifier resolved by `eve build`
|
|
91
|
+
* (`config.experimental.workflow.world`). When it selects a known durable
|
|
92
|
+
* World with a one-time schema setup, Eden runs that setup inside the boot
|
|
93
|
+
* probe — idempotently, before health — so the deployed container finds the
|
|
94
|
+
* schema already present.
|
|
95
|
+
*/
|
|
96
|
+
readonly workflowWorld?: string;
|
|
89
97
|
/**
|
|
90
98
|
* Preflight must remove its disposable runtime image after health proof.
|
|
91
99
|
* Deploy may retain the exact image for the publication handoff.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash, } from "node:crypto";
|
|
2
|
-
import { execFile,
|
|
2
|
+
import { execFile, } 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";
|
|
@@ -448,7 +448,8 @@ ENV HOST=0.0.0.0 \\
|
|
|
448
448
|
NITRO_HOST=0.0.0.0 \\
|
|
449
449
|
PORT=8080 \\
|
|
450
450
|
NITRO_PORT=8080 \\
|
|
451
|
-
NODE_ENV=production
|
|
451
|
+
NODE_ENV=production \
|
|
452
|
+
CBOR_NATIVE_ACCELERATION_DISABLED=true
|
|
452
453
|
COPY --from=candidate /candidate/.output /workspace/.output
|
|
453
454
|
COPY --from=candidate /candidate/node_modules /workspace/node_modules
|
|
454
455
|
${sourceCopyLines}
|
|
@@ -541,48 +542,34 @@ function safeDockerEnvironment() {
|
|
|
541
542
|
DOCKER_CONTEXT: process.env.DOCKER_CONTEXT,
|
|
542
543
|
};
|
|
543
544
|
}
|
|
545
|
+
/**
|
|
546
|
+
* Runs the Docker CLI. `environment` values reach the CLI process only, so
|
|
547
|
+
* `--env NAME` arguments (names, never values) can forward runtime secrets
|
|
548
|
+
* into a container without them touching argv, logs, or files. `--env-file
|
|
549
|
+
* /dev/stdin` is not used: on Linux, Node's spawned stdin is a socket that
|
|
550
|
+
* `/dev/stdin` cannot open.
|
|
551
|
+
*/
|
|
544
552
|
async function docker(state, args, options = {}) {
|
|
545
553
|
return execFileAsync(state.command, [...args], {
|
|
546
|
-
env: state.env,
|
|
554
|
+
env: { ...state.env, ...options.environment },
|
|
547
555
|
cwd: state.generationRoot,
|
|
548
556
|
maxBuffer: options.maxBuffer ?? 4 * 1024 * 1024,
|
|
549
557
|
});
|
|
550
558
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
const child = spawn(state.command, [...args], {
|
|
554
|
-
cwd: state.generationRoot,
|
|
555
|
-
env: state.env,
|
|
556
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
557
|
-
});
|
|
558
|
-
let stdout = "";
|
|
559
|
-
let stderr = "";
|
|
560
|
-
child.stdout.on("data", (chunk) => {
|
|
561
|
-
stdout += chunk.toString();
|
|
562
|
-
});
|
|
563
|
-
child.stderr.on("data", (chunk) => {
|
|
564
|
-
stderr += chunk.toString();
|
|
565
|
-
});
|
|
566
|
-
child.once("error", rejectResult);
|
|
567
|
-
child.once("close", (code) => {
|
|
568
|
-
if (code === 0) {
|
|
569
|
-
resolveResult({ stdout, stderr });
|
|
570
|
-
}
|
|
571
|
-
else {
|
|
572
|
-
const error = new Error(stderr || "The Docker operation failed.");
|
|
573
|
-
Object.assign(error, { stdout, stderr, code });
|
|
574
|
-
rejectResult(error);
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
child.stdin.end(input);
|
|
578
|
-
});
|
|
579
|
-
}
|
|
559
|
+
/** Names that must keep the local Docker CLI's own values. */
|
|
560
|
+
const DOCKER_CLI_OWNED_VARIABLES = ["PATH", "HOME", "DOCKER_HOST", "DOCKER_CONTEXT"];
|
|
580
561
|
function runtimeContainerEnvironment(request) {
|
|
581
562
|
return {
|
|
582
563
|
...HOST_ENVIRONMENT,
|
|
583
564
|
...(request.publicOrigin === undefined
|
|
584
565
|
? {}
|
|
585
566
|
: { WORKFLOW_LOCAL_BASE_URL: request.publicOrigin }),
|
|
567
|
+
...(request.workflowWorld === "@moinulmoin/eden-world-cloudflare"
|
|
568
|
+
? {
|
|
569
|
+
EDEN_WORLD_URL: `${request.publicOrigin ?? "http://localhost:8080"}/__eden/world/rpc`,
|
|
570
|
+
CBOR_NATIVE_ACCELERATION_DISABLED: "true",
|
|
571
|
+
}
|
|
572
|
+
: {}),
|
|
586
573
|
};
|
|
587
574
|
}
|
|
588
575
|
function validateHealthPort(port) {
|
|
@@ -936,6 +923,12 @@ export async function buildEveRuntimeImage(request) {
|
|
|
936
923
|
hostEnvironment: runtimeContainerEnvironment(request),
|
|
937
924
|
run: (startRequest) => startRequest.env,
|
|
938
925
|
});
|
|
926
|
+
if (request.runtimeInjection !== undefined) {
|
|
927
|
+
const collision = Object.keys(runtimeEnvironment).find((name) => DOCKER_CLI_OWNED_VARIABLES.includes(name));
|
|
928
|
+
if (collision !== undefined) {
|
|
929
|
+
throw packagingError("DOCKER_PLATFORM_BLOCKED", "runtime variable name", `The runtime variable ${collision} would replace the local Docker CLI's own ${collision}.`, `Rename ${collision} in --env-file; ${DOCKER_CLI_OWNED_VARIABLES.join(", ")} are reserved for the local Docker CLI.`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
939
932
|
const bootArgs = [
|
|
940
933
|
"run",
|
|
941
934
|
"--detach",
|
|
@@ -950,14 +943,12 @@ export async function buildEveRuntimeImage(request) {
|
|
|
950
943
|
"--env",
|
|
951
944
|
`${name}=${value}`,
|
|
952
945
|
])
|
|
953
|
-
: ["--env
|
|
946
|
+
: Object.keys(runtimeEnvironment).flatMap((name) => ["--env", name])),
|
|
954
947
|
state.imageId,
|
|
955
948
|
];
|
|
956
|
-
const boot = request.runtimeInjection === undefined
|
|
957
|
-
?
|
|
958
|
-
:
|
|
959
|
-
.map(([name, value]) => `${name}=${value}`)
|
|
960
|
-
.join("\n")}\n`);
|
|
949
|
+
const boot = await docker(state, bootArgs, request.runtimeInjection === undefined
|
|
950
|
+
? {}
|
|
951
|
+
: { environment: runtimeEnvironment });
|
|
961
952
|
state.containerId = boot.stdout.trim();
|
|
962
953
|
bootContainerId = state.containerId;
|
|
963
954
|
if (state.containerId.length === 0) {
|
|
@@ -984,8 +975,35 @@ export async function buildEveRuntimeImage(request) {
|
|
|
984
975
|
state.containerId,
|
|
985
976
|
"sh",
|
|
986
977
|
"-ceu",
|
|
987
|
-
"set -o noglob; status=0; for module in $(find /workspace/node_modules -type f -name '*.node'); do if ldd \"$module\" 2>&1 | grep -q 'not found'; then echo \"unloadable native module: $module\" >&2; status=1; fi; done; exit $status",
|
|
978
|
+
"set -o noglob; status=0; for module in $(find /workspace/node_modules -type f -name '*.node' -not -path '*cbor-extract*'); do if ldd \"$module\" 2>&1 | grep -q 'not found'; then echo \"unloadable native module: $module\" >&2; status=1; fi; done; exit $status",
|
|
988
979
|
]);
|
|
980
|
+
if (request.workflowWorld === "@workflow/world-postgres") {
|
|
981
|
+
// The Postgres World ships an idempotent setup binary (drizzle
|
|
982
|
+
// `migrate()` plus graphile-worker `workerUtils.migrate()`; both skip
|
|
983
|
+
// already-applied work) that must run once per database before Eve
|
|
984
|
+
// consumes the schema. Running it inside the disposable boot
|
|
985
|
+
// container, before health and publish, exercises the exact deployed
|
|
986
|
+
// node_modules against the env-file URL. `docker exec` inherits the
|
|
987
|
+
// environment the container booted with, so the URL never appears in
|
|
988
|
+
// argv, logs, or the image.
|
|
989
|
+
try {
|
|
990
|
+
await docker(state, [
|
|
991
|
+
"exec",
|
|
992
|
+
state.containerId,
|
|
993
|
+
"./node_modules/.bin/bootstrap",
|
|
994
|
+
]);
|
|
995
|
+
await docker(state, [
|
|
996
|
+
"exec",
|
|
997
|
+
state.containerId,
|
|
998
|
+
"sh",
|
|
999
|
+
"-ceu",
|
|
1000
|
+
"cd node_modules/@workflow/world-postgres && node -e \"const {encode,decode}=require('cbor-x');if(decode(encode({ok:true})).ok!==true)process.exit(1)\"",
|
|
1001
|
+
]);
|
|
1002
|
+
}
|
|
1003
|
+
catch {
|
|
1004
|
+
throw packagingError("WORLD_MIGRATION_FAILED", "@workflow/world-postgres setup", "The Postgres World schema migration or cbor-x codec check failed inside the disposable Eve container.", "Confirm WORKFLOW_POSTGRES_URL in --env-file is the direct, unpooled database URL reachable from this machine, then retry; the migration is idempotent.");
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
989
1007
|
await pollEveHealth(healthPort, timeoutMs, pollIntervalMs, request.fetchHealth ?? fetch);
|
|
990
1008
|
await docker(state, [
|
|
991
1009
|
"exec",
|
package/dist/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export type { EveCliCommand, EveCliEnvironment, EveCliExecutionRequest, EveCliHe
|
|
|
10
10
|
export type { EveNodeImage, EvePackagingCheck, EvePackagingCode, EveProjectBuilder, EveProjectBuilderRequest, EveProjectBuilderResult, EveProjectBuildCandidate, EveProjectFile, EveProjectImage, EveProjectInputManifest, EveProjectOutput, EveProjectPackagingResult, EveProjectRuntime, EveProjectSnapshot, EveProjectSnapshotOptions, EveProjectToolchain, EveRuntimeConfigExclusion, } from "./eve-packaging.js";
|
|
11
11
|
export type { EveHostRequirements, EveRuntimeClosure, EveRuntimeClosureFile, EveRuntimeCleanup, EveRuntimeImage, EveRuntimeImageDiscardRequest, EveRuntimeImageMetadata, EveRuntimeImageRequest, EveRuntimeImageResult, EveRuntimeNativeModule, EveRuntimeStatus, } from "./eve-runtime-image.js";
|
|
12
12
|
export { DEFAULT_EVE_HOST_REQUIREMENTS, DEFAULT_EVE_NODE_IMAGE, runEveControlPlane, runEveDestroy, } from "./eve-control-plane.js";
|
|
13
|
-
export type { EveCloudflareReadRequest, EveCloudflareReadResult, EveCloudflareReadRunner, EveCloudflareTargetState, EveContainerDeleteRunner, EveDeploymentCompensationRequest, EveDeploymentCompensationRunner, EveDeploymentHealthRequest, EveDeploymentHealthResult, EveDeploymentHealthRunner, EveDeploymentIdentity, EveDeploymentIdentityProof, EveDeploymentMetadata, EveDeploymentPublicationRequest, EveDeploymentPublicationResult, EveDeploymentPublicationRunner, EveDeploymentStatus, EveDestroyCloudflareReadRequest, EveDestroyCloudflareReadRunner, EveDestroyOutcome, EveDestroyTargetRead, EveImagePublicationRequest, EveImagePublicationResult, EveImagePublicationRunner, EvePreflightCandidate,
|
|
13
|
+
export type { EveCloudflareReadRequest, EveCloudflareReadResult, EveCloudflareReadRunner, EveCloudflareTargetState, EveContainerDeleteRunner, EveDeploymentCompensationRequest, EveDeploymentCompensationRunner, EveDeploymentHealthRequest, EveDeploymentHealthResult, EveDeploymentHealthRunner, EveDeploymentIdentity, EveDeploymentIdentityProof, EveDeploymentMetadata, EveDeploymentPublicationRequest, EveDeploymentPublicationResult, EveDeploymentPublicationRunner, EveDeploymentStatus, EveDestroyCloudflareReadRequest, EveDestroyCloudflareReadRunner, EveDestroyOutcome, EveDestroyTargetRead, EveImagePublicationRequest, EveImagePublicationResult, EveImagePublicationRunner, EvePreflightCandidate, EvePreflightResult, EvePreflightRuntimeEvidence, EvePreflightWarning, EvePreflightRuntimeRunner, EvePreflightRuntimeRunnerRequest, EveRuntimeConfigLoader, EveRuntimeImageDiscardRunner, EveWorkerDeleteRunner, } from "./eve-control-plane.js";
|
|
14
14
|
export declare const EDEN_CLI_COMMANDS: readonly ["preflight", "deploy", "destroy"];
|
|
15
15
|
export type EdenCliCommand = (typeof EDEN_CLI_COMMANDS)[number];
|
|
16
16
|
export interface EdenCliRunOptions {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moinulmoin/eden",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Deploy existing Eve projects to your own Cloudflare account.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"NOTICE"
|
|
32
32
|
],
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@moinulmoin/eden-runtime-cloudflare": "0.
|
|
34
|
+
"@moinulmoin/eden-runtime-cloudflare": "0.4.1",
|
|
35
35
|
"wrangler": "4.120.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|