@moinulmoin/eden 0.5.0 → 0.6.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 CHANGED
@@ -1,15 +1,6 @@
1
1
  Eden
2
2
  Copyright 2026 Eden contributors
3
3
 
4
- Cloudflare Containers
5
- @cloudflare/containers, version 0.3.7
6
- https://github.com/cloudflare/containers
7
-
8
- Eden's generated Worker host bundle includes software from
9
- `@cloudflare/containers`, distributed under MIT OR Apache-2.0. Eden
10
- redistributes that bundled software under the Apache-2.0 option included in
11
- LICENSE.
12
-
13
4
  Workflow SDK
14
5
  @workflow/world-postgres, version 5.0.0-beta.47
15
6
  https://github.com/vercel/workflow
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.5.0
15
+ npm install --global @moinulmoin/eden@0.6.0
16
16
  ```
17
17
 
18
18
  ```sh
19
- pnpm add --global @moinulmoin/eden@0.5.0
19
+ pnpm add --global @moinulmoin/eden@0.6.0
20
20
  ```
21
21
 
22
22
  ```sh
23
- bun add --global @moinulmoin/eden@0.5.0
23
+ bun add --global @moinulmoin/eden@0.6.0
24
24
  ```
25
25
 
26
26
  Then confirm the CLI is available:
@@ -39,7 +39,7 @@ Bun can install Eden, but Eden still runs on Node. Do not use `bunx --bun`.
39
39
  - Wrangler authentication:
40
40
 
41
41
  ```sh
42
- npx wrangler@4.120.0 login
42
+ npx wrangler@4.147.0 login
43
43
  ```
44
44
 
45
45
  - Docker or OrbStack with Linux/amd64 container support
@@ -2,7 +2,7 @@ import { type EveCliEnvironment, type EveCliExecutionRequest } from "./eve.js";
2
2
  import { type EveNodeImage, type EveProjectBuildCandidate, type EveProjectBuilder } from "./eve-packaging.js";
3
3
  import { type EveHostRequirements, type EveRuntimeCleanup, type EveRuntimeImageDiscardRequest } from "./eve-runtime-image.js";
4
4
  import { type EveRuntimeConfig, type EveRuntimeInjection, type EveRuntimeProtectedStore } from "./eve-runtime-config.js";
5
- import type { EveHostConfig } from "@moinulmoin/eden-runtime-cloudflare";
5
+ import { type EveHostConfig } from "@moinulmoin/eden-runtime-cloudflare";
6
6
  export declare const DEFAULT_EVE_HOST_REQUIREMENTS: EveHostRequirements;
7
7
  export declare const DEFAULT_EVE_NODE_IMAGE: EveNodeImage;
8
8
  export type EvePreflightCheckStatus = "passed" | "failed" | "blocked" | "skipped";
@@ -87,15 +87,18 @@ export interface EveCloudflareReadResult {
87
87
  /**
88
88
  * Provider-backed facts about the live target, read through the
89
89
  * Cloudflare API (not self-asserted response headers, which any Worker
90
- * can forge): the Container application's configured image and the
91
- * `EDEN_EVE_DEPLOYMENT_ID` plain-text var Eden stamps into every Worker
92
- * it publishes. `settingsReadable` tells the ownership resolver whether
93
- * a missing var is evidence of a foreign Worker or just an unreadable
94
- * settings call.
90
+ * can forge): the Container application's Durable Object namespace and
91
+ * the `EDEN_EVE_DEPLOYMENT_ID` plain-text var Eden stamps into every
92
+ * Worker it publishes. `settingsReadable` tells the ownership resolver
93
+ * whether a missing var is evidence of a foreign Worker or just an
94
+ * unreadable settings call.
95
95
  */
96
96
  readonly providerEvidence?: {
97
- readonly containerImage?: string;
97
+ readonly containerApplicationId?: string;
98
+ readonly containerSchedulingPolicy?: string;
99
+ readonly containerNamespaceId?: string;
98
100
  readonly workerDeploymentId?: string;
101
+ readonly workerContainerNamespaceId?: string;
99
102
  readonly settingsReadable?: boolean;
100
103
  };
101
104
  };
@@ -249,19 +252,20 @@ export interface EvePreflightOptions {
249
252
  readonly destroyCloudflareRead?: EveDestroyCloudflareReadRunner;
250
253
  readonly deleteWorker?: EveWorkerDeleteRunner;
251
254
  readonly deleteContainer?: EveContainerDeleteRunner;
252
- readonly deleteRegistryImage?: EveRegistryImageDeleteRunner;
255
+ readonly deleteRegistryRepository?: EveRegistryRepositoryDeleteRunner;
253
256
  }
254
257
  export interface EveDestroyTargetRead {
255
258
  readonly workerExists: boolean;
256
259
  readonly containerApplicationId?: string;
257
260
  readonly accountId?: string;
258
261
  /**
259
- * Subset of the request's owned registry image tags (`repository:tag`)
260
- * still present in the managed registry. `undefined` means the reader
261
- * could not enumerate the registry; destroy then relies on the exact
262
- * delete outcomes only.
262
+ * Every `repository:tag` ref still present in the managed registry whose
263
+ * repository is one of the request's owned repositories — including the
264
+ * `rootfs-snapshot-*`/`rootfs-set-*` tags container snapshots create.
265
+ * `undefined` means the reader could not enumerate the registry; destroy
266
+ * then relies on the exact delete outcomes only.
263
267
  */
264
- readonly registryImagesPresent?: readonly string[];
268
+ readonly registryTagsPresent?: readonly string[];
265
269
  }
266
270
  export type EveDestroyCloudflareReadRunner = (request: EveDestroyCloudflareReadRequest) => EveDestroyTargetRead | Promise<EveDestroyTargetRead>;
267
271
  export type EveWorkerDeleteRunner = (request: {
@@ -270,15 +274,15 @@ export type EveWorkerDeleteRunner = (request: {
270
274
  export type EveContainerDeleteRunner = (request: {
271
275
  readonly applicationId: string;
272
276
  }) => "deleted" | "absent" | "indeterminate" | Promise<"deleted" | "absent" | "indeterminate">;
273
- export type EveRegistryImageDeleteRunner = (request: {
274
- readonly image: string;
277
+ export type EveRegistryRepositoryDeleteRunner = (request: {
278
+ readonly repository: string;
275
279
  }) => "deleted" | "absent" | "indeterminate" | Promise<"deleted" | "absent" | "indeterminate">;
276
280
  export type EveRuntimeConfigLoader = (path: string, cwd: string) => EveRuntimeConfig | Promise<EveRuntimeConfig>;
277
281
  export interface EveDestroyCloudflareReadRequest {
278
282
  readonly workerName: string;
279
283
  readonly containerApplicationName: string;
280
- /** Exact `repository:tag` image refs recorded for this target. */
281
- readonly registryImages?: readonly string[];
284
+ /** Registry repository names this target provably owns. */
285
+ readonly registryRepositories?: readonly string[];
282
286
  }
283
287
  /**
284
288
  * Container applications in the account that belong to this exact target.
@@ -288,7 +292,6 @@ export interface EveDestroyCloudflareReadRequest {
288
292
  export declare function exactTargetContainerEntries(value: unknown, name: string): readonly {
289
293
  readonly id: string;
290
294
  readonly name: string;
291
- readonly image?: string;
292
295
  }[] | undefined;
293
296
  export declare function runEveControlPlane(request: EveCliExecutionRequest, options?: EvePreflightOptions): Promise<void>;
294
297
  export interface EveDestroyOutcome {
@@ -11,6 +11,7 @@ import { EveCliError, } from "./eve.js";
11
11
  import { buildEveProjectSnapshot, createDockerEveProjectBuilder, revalidateEveProjectCandidateInputs, EvePackagingError, } from "./eve-packaging.js";
12
12
  import { buildEveRuntimeImage, discardEveRuntimeImage, revalidateEveRuntimeCandidate, validateEveHostRequirements, } from "./eve-runtime-image.js";
13
13
  import { EveRuntimeConfigError, prepareEveRuntimeInjection, redactEveRuntimeOutput, } from "./eve-runtime-config.js";
14
+ import { createEveHostConfig, generateEveHostWorkerSource, parseEveScheduleCron, resolveStableWorkersDevOrigin, } from "@moinulmoin/eden-runtime-cloudflare";
14
15
  const execFileAsync = promisify(execFile);
15
16
  const require = createRequire(import.meta.url);
16
17
  const wranglerEntrypoint = require.resolve("wrangler");
@@ -440,21 +441,11 @@ function exactContainerEntries(value, name) {
440
441
  typeof entry.name !== "string") {
441
442
  return undefined;
442
443
  }
443
- const id = entry.id;
444
444
  const entryName = entry.name;
445
445
  if (entryName === name) {
446
- const configuration = entry.configuration;
447
- const image = typeof entry.image === "string"
448
- ? entry.image
449
- : typeof configuration === "object" &&
450
- configuration !== null &&
451
- typeof configuration.image === "string"
452
- ? configuration.image
453
- : undefined;
454
446
  entries.push({
455
- id,
447
+ id: entry.id,
456
448
  name: entryName,
457
- ...(image === undefined ? {} : { image }),
458
449
  });
459
450
  }
460
451
  }
@@ -610,7 +601,7 @@ async function defaultCloudflareRead(request) {
610
601
  }
611
602
  const workerPresent = deploymentEntries.length > 0;
612
603
  const containerPresent = (containerEntries?.length ?? 0) > 0;
613
- const providerEvidence = await readProviderEvidence(request.name, accountId, workerPresent, containerPresent ? containerEntries?.[0]?.image : undefined);
604
+ const providerEvidence = await readProviderEvidence(request.name, accountId, workerPresent, containerPresent ? containerEntries?.[0] : undefined);
614
605
  return {
615
606
  accountAccess,
616
607
  containerAccess,
@@ -634,16 +625,40 @@ async function defaultCloudflareRead(request) {
634
625
  }
635
626
  /**
636
627
  * Reads provider-backed facts about the live target: the Container
637
- * application's configured image (from `wrangler containers list`) and the
638
- * `EDEN_EVE_DEPLOYMENT_ID` plain-text var Eden stamps into every Worker it
639
- * publishes (from the script settings API). Both are provider state — a
640
- * foreign Worker can forge `x-eden-*` response headers but cannot set a var
641
- * Eden recorded at publish time.
628
+ * application's identity from `wrangler containers list` plus `containers
629
+ * info` (scheduling policy and Durable Object namespace), and the
630
+ * `EDEN_EVE_DEPLOYMENT_ID` plain-text var plus the `EVE_CONTAINER` Durable
631
+ * Object namespace Eden stamps into every Worker it publishes (from the
632
+ * script settings API). All are provider state — a foreign Worker can forge
633
+ * `x-eden-*` response headers but cannot set vars or namespaces Eden
634
+ * recorded at publish time. The ownership proof is the Container
635
+ * application's Durable Object namespace matching the Worker's binding
636
+ * namespace.
642
637
  */
643
- async function readProviderEvidence(workerName, accountId, workerPresent, containerImage) {
638
+ async function readProviderEvidence(workerName, accountId, workerPresent, containerEntry) {
644
639
  const evidence = {
645
- ...(containerImage === undefined ? {} : { containerImage }),
640
+ ...(containerEntry === undefined
641
+ ? {}
642
+ : { containerApplicationId: containerEntry.id }),
646
643
  };
644
+ if (containerEntry !== undefined) {
645
+ const info = await readWranglerJson([
646
+ "containers",
647
+ "info",
648
+ containerEntry.id,
649
+ "--json",
650
+ ]);
651
+ if (!info.failed && typeof info.value === "object" && info.value !== null) {
652
+ const infoRecord = info.value;
653
+ if (typeof infoRecord.scheduling_policy === "string") {
654
+ evidence.containerSchedulingPolicy = infoRecord.scheduling_policy;
655
+ }
656
+ const namespaceId = infoRecord.durable_objects?.namespace_id;
657
+ if (typeof namespaceId === "string") {
658
+ evidence.containerNamespaceId = namespaceId;
659
+ }
660
+ }
661
+ }
647
662
  if (workerPresent && accountId !== undefined) {
648
663
  const token = process.env.CLOUDFLARE_API_TOKEN ??
649
664
  (await readWranglerOAuthToken());
@@ -656,10 +671,16 @@ async function readProviderEvidence(workerName, accountId, workerPresent, contai
656
671
  if (response.ok) {
657
672
  evidence.settingsReadable = true;
658
673
  const parsed = (await response.json());
659
- const binding = parsed.result?.bindings?.find((value) => value.type === "plain_text" &&
674
+ const bindings = parsed.result?.bindings ?? [];
675
+ const deploymentBinding = bindings.find((value) => value.type === "plain_text" &&
660
676
  value.name === "EDEN_EVE_DEPLOYMENT_ID");
661
- if (typeof binding?.text === "string") {
662
- evidence.workerDeploymentId = binding.text;
677
+ if (typeof deploymentBinding?.text === "string") {
678
+ evidence.workerDeploymentId = deploymentBinding.text;
679
+ }
680
+ const containerBinding = bindings.find((value) => value.type === "durable_object_namespace" &&
681
+ value.name === "EVE_CONTAINER");
682
+ if (typeof containerBinding?.namespace_id === "string") {
683
+ evidence.workerContainerNamespaceId = containerBinding.namespace_id;
663
684
  }
664
685
  }
665
686
  else if (response.status !== 404) {
@@ -698,19 +719,23 @@ async function resolveEveTargetOwnership(request, result) {
698
719
  }
699
720
  // Remote proof must come from provider state. A foreign Worker can echo
700
721
  // `x-eden-*` response headers, but it cannot plant the plain-text var Eden
701
- // publishes into script settings, nor point the Container application at an
702
- // image digest Eden recorded. The Worker is proven only by its own settings:
703
- // a matching Container image proves the Container, never the Worker, so
704
- // unreadable settings fail closed.
722
+ // publishes into script settings or claim the Durable Object namespace the
723
+ // Worker's EVE_CONTAINER binding resolves to. The Worker is proven only by
724
+ // its own settings: unreadable settings fail closed.
705
725
  const evidence = result.target.providerEvidence;
706
726
  const recordedDeploymentIds = new Set(record.deploymentIds);
707
727
  const workerProven = result.target.observed?.worker !== true ||
708
728
  (evidence?.settingsReadable === true &&
709
729
  evidence.workerDeploymentId !== undefined &&
710
730
  recordedDeploymentIds.has(evidence.workerDeploymentId));
731
+ // The Container proof is the application running the durable_object
732
+ // scheduling policy with a namespace that matches the Worker binding's
733
+ // namespace; anything else fails closed.
711
734
  const containerProven = result.target.observed?.container !== true ||
712
- (evidence?.containerImage !== undefined &&
713
- record.images.includes(evidence.containerImage));
735
+ (evidence?.containerSchedulingPolicy === "durable_object" &&
736
+ evidence.containerNamespaceId !== undefined &&
737
+ evidence.workerContainerNamespaceId !== undefined &&
738
+ evidence.containerNamespaceId === evidence.workerContainerNamespaceId);
714
739
  const remoteProven = evidence !== undefined && workerProven && containerProven;
715
740
  if (!remoteProven) {
716
741
  return {
@@ -763,7 +788,6 @@ async function resolvedCloudflareOrigin(result, workerName) {
763
788
  return undefined;
764
789
  }
765
790
  try {
766
- const { resolveStableWorkersDevOrigin } = await import("@moinulmoin/eden-runtime-cloudflare");
767
791
  const origin = resolveStableWorkersDevOrigin({
768
792
  workerName,
769
793
  workersDevSubdomain: result.workersDevSubdomain,
@@ -1130,8 +1154,6 @@ function defaultPublicationRunner() {
1130
1154
  "--env",
1131
1155
  request.identity.environment,
1132
1156
  "--strict",
1133
- "--containers-rollout",
1134
- "immediate",
1135
1157
  ], dirname(request.wranglerConfigPath));
1136
1158
  if (result.exitCode !== 0) {
1137
1159
  return {
@@ -1490,7 +1512,6 @@ async function runEveDeployment(request, options, collected) {
1490
1512
  }
1491
1513
  let stableWorkersDevOrigin;
1492
1514
  try {
1493
- const { resolveStableWorkersDevOrigin } = await import("@moinulmoin/eden-runtime-cloudflare");
1494
1515
  stableWorkersDevOrigin = resolveStableWorkersDevOrigin({
1495
1516
  workerName: request.name,
1496
1517
  workersDevSubdomain,
@@ -1607,38 +1628,39 @@ async function runEveDeployment(request, options, collected) {
1607
1628
  ? {}
1608
1629
  : { runtimeRevisionHandle: runtimeInjection.protectedHandle }),
1609
1630
  };
1631
+ const baseConfigRequest = {
1632
+ accountId,
1633
+ workerName: identity.workerName,
1634
+ containerApplicationName: identity.containerApplicationName,
1635
+ containerClassName: "EveHostDurableContainer",
1636
+ containerBindingName: "EVE_CONTAINER",
1637
+ stableContainerInstanceName: identity.stableContainerInstanceName,
1638
+ deploymentId: identity.deploymentId,
1639
+ generationId: identity.generationId,
1640
+ stableWorkersDevOrigin: identity.stableWorkersDevOrigin,
1641
+ containerImage: identity.containerImage,
1642
+ runtimeVariableNames: identity.runtimeVariableNames,
1643
+ ...(identity.runtimeRevisionHandle === undefined
1644
+ ? {}
1645
+ : { runtimeRevisionHandle: identity.runtimeRevisionHandle }),
1646
+ schedules: collected.schedules ?? [],
1647
+ ...(collected.workflowWorld === undefined
1648
+ ? {}
1649
+ : { workflowWorld: collected.workflowWorld }),
1650
+ // In-place updates carry the prior Durable Object bindings and
1651
+ // migration history forward verbatim: classes are append-only and are
1652
+ // never silently re-declared or removed.
1653
+ ...(isUpdate && priorDurableObjects !== undefined
1654
+ ? { durableObjects: priorDurableObjects }
1655
+ : {}),
1656
+ ...(process.env.EDEN_EVE_CONTAINER_SLEEP_AFTER === undefined
1657
+ ? {}
1658
+ : { containerSleepAfter: process.env.EDEN_EVE_CONTAINER_SLEEP_AFTER }),
1659
+ };
1610
1660
  let hostConfig;
1611
1661
  try {
1612
- const { createEveHostConfig, } = await import("@moinulmoin/eden-runtime-cloudflare");
1613
1662
  hostConfig = createEveHostConfig({
1614
- accountId,
1615
- workerName: identity.workerName,
1616
- containerApplicationName: identity.containerApplicationName,
1617
- containerClassName: "EveHostContainer",
1618
- containerBindingName: "EVE_CONTAINER",
1619
- stableContainerInstanceName: identity.stableContainerInstanceName,
1620
- deploymentId: identity.deploymentId,
1621
- generationId: identity.generationId,
1622
- stableWorkersDevOrigin: identity.stableWorkersDevOrigin,
1623
- containerImage: identity.containerImage,
1624
- runtimeVariableNames: identity.runtimeVariableNames,
1625
- ...(identity.runtimeRevisionHandle === undefined
1626
- ? {}
1627
- : { runtimeRevisionHandle: identity.runtimeRevisionHandle }),
1628
- schedules: collected.schedules ?? [],
1629
- ...(collected.workflowWorld === undefined
1630
- ? {}
1631
- : { workflowWorld: collected.workflowWorld }),
1632
- // In-place updates carry the prior Durable Object bindings and
1633
- // migration history forward verbatim: classes are append-only, never
1634
- // re-declared, and never deleted (a deleted_classes migration destroys
1635
- // the data).
1636
- ...(isUpdate && priorDurableObjects !== undefined
1637
- ? { durableObjects: priorDurableObjects }
1638
- : {}),
1639
- ...(process.env.EDEN_EVE_CONTAINER_SLEEP_AFTER === undefined
1640
- ? {}
1641
- : { containerSleepAfter: process.env.EDEN_EVE_CONTAINER_SLEEP_AFTER }),
1663
+ ...baseConfigRequest,
1642
1664
  });
1643
1665
  }
1644
1666
  catch (error) {
@@ -1646,7 +1668,6 @@ async function runEveDeployment(request, options, collected) {
1646
1668
  ? error.message
1647
1669
  : "The exact Eve Worker/Container host configuration was invalid.");
1648
1670
  }
1649
- const { generateEveHostWorkerSource } = await import("@moinulmoin/eden-runtime-cloudflare");
1650
1671
  const workerSource = generateEveHostWorkerSource({ config: hostConfig });
1651
1672
  const paths = await writeEveDeploymentArtifacts(candidate, hostConfig, workerSource);
1652
1673
  const publicationRequest = {
@@ -1656,13 +1677,26 @@ async function runEveDeployment(request, options, collected) {
1656
1677
  ...paths,
1657
1678
  ...(runtimeInjection === undefined ? {} : { runtimeInjection }),
1658
1679
  };
1680
+ /** Publishes one wrangler config; returns its terminal result. */
1681
+ const publishOne = async (request) => (options.publish ?? defaultPublicationRunner())(request);
1659
1682
  let publication;
1683
+ const writeFailureRecord = async (status, evidence) => {
1684
+ try {
1685
+ await writeEveDeploymentRecord(candidate, identity, hostConfig, status, {
1686
+ evidence,
1687
+ });
1688
+ }
1689
+ catch (error) {
1690
+ if (error.code !== "EEXIST")
1691
+ throw error;
1692
+ }
1693
+ };
1660
1694
  try {
1661
1695
  eveProgress(options, "publishing Worker and Container application");
1662
- publication = await (options.publish ?? defaultPublicationRunner())(publicationRequest);
1696
+ publication = await publishOne(publicationRequest);
1663
1697
  }
1664
1698
  catch {
1665
- await writeEveDeploymentRecord(candidate, identity, hostConfig, "indeterminate", { evidence: "publication-threw-before-terminal-result" });
1699
+ await writeFailureRecord("indeterminate", "publication-threw-before-terminal-result");
1666
1700
  const deployment = deploymentMetadata(identity, targetKey, "indeterminate", operation, superseded);
1667
1701
  return {
1668
1702
  ...collected.result,
@@ -1671,7 +1705,7 @@ async function runEveDeployment(request, options, collected) {
1671
1705
  };
1672
1706
  }
1673
1707
  if (publication.status === "indeterminate") {
1674
- await writeEveDeploymentRecord(candidate, identity, hostConfig, "indeterminate", { evidence: safeText(publication.reason) });
1708
+ await writeFailureRecord("indeterminate", safeText(publication.reason));
1675
1709
  return {
1676
1710
  ...collected.result,
1677
1711
  ok: false,
@@ -1862,25 +1896,26 @@ async function runEveDeployment(request, options, collected) {
1862
1896
  if (isUpdate) {
1863
1897
  // The superseded generation's registry repository is generation-scoped
1864
1898
  // and no longer referenced once CURRENT promotes this generation; only
1865
- // then is it safe to delete.
1866
- const previousImage = priorIdentity === undefined
1899
+ // then is it safe to delete. Every tag in the repository goes with it —
1900
+ // including the snapshot tags Cloudflare created under it.
1901
+ const previousRepository = priorIdentity === undefined
1867
1902
  ? undefined
1868
- : ownedRegistryImageRef(priorIdentity, request.environment, request.name, accountId);
1869
- if (previousImage !== undefined) {
1870
- eveProgress(options, `deleting superseded registry image ${previousImage}`);
1903
+ : ownedRegistryRepository(priorIdentity, request.environment, request.name, accountId);
1904
+ if (previousRepository !== undefined) {
1905
+ eveProgress(options, `deleting superseded registry repository ${previousRepository}`);
1871
1906
  let deleted = "indeterminate";
1872
1907
  try {
1873
- deleted = await (options.deleteRegistryImage ??
1874
- defaultRegistryImageDelete)({ image: previousImage });
1908
+ deleted = await (options.deleteRegistryRepository ??
1909
+ defaultRegistryRepositoryDelete)({ repository: previousRepository });
1875
1910
  }
1876
1911
  catch {
1877
1912
  deleted = "indeterminate";
1878
1913
  }
1879
1914
  supersededImageCleanup = deleted === "indeterminate"
1880
- ? check("VAL-LIFE-007", "failed", `The update is healthy and promoted, but the superseded registry image ${previousImage} could not be proven deleted.`, `Remove only the recorded image ref ${previousImage}; do not retry or run broad registry cleanup.`)
1915
+ ? check("VAL-LIFE-007", "failed", `The update is healthy and promoted, but the superseded registry repository ${previousRepository} could not be proven deleted.`, `Remove only the recorded repository's tags ${previousRepository}; do not retry or run broad registry cleanup.`)
1881
1916
  : check("VAL-LIFE-007", "passed", deleted === "deleted"
1882
- ? "The superseded generation's registry image was deleted after promotion."
1883
- : "The superseded generation's registry image was already absent.");
1917
+ ? "The superseded generation's registry repository (all tags, including snapshots) was deleted after promotion."
1918
+ : "The superseded generation's registry repository was already absent.");
1884
1919
  }
1885
1920
  }
1886
1921
  let runtimeImageCleanup;
@@ -2058,9 +2093,6 @@ async function collectEvePreflight(request, options) {
2058
2093
  }
2059
2094
  warnings.push(...(await collectEveWorldWarnings(candidate, undefined)));
2060
2095
  const schedules = await readCompiledSchedules(candidate);
2061
- // The runtime package is imported lazily so `eden` commands that never
2062
- // reach deploy checks stay fast; the module specifier is fixed.
2063
- const { parseEveScheduleCron } = await import("@moinulmoin/eden-runtime-cloudflare");
2064
2096
  const expressible = schedules.filter((schedule) => parseEveScheduleCron(schedule.cron) !== undefined);
2065
2097
  const unexpressible = schedules.filter((schedule) => parseEveScheduleCron(schedule.cron) === undefined);
2066
2098
  if (unexpressible.length > 0) {
@@ -2496,7 +2528,6 @@ async function readEveDeploymentRecord(projectRoot, environment, name, accountId
2496
2528
  const entries = await readdir(generationsRoot).catch(() => []);
2497
2529
  const scanned = [];
2498
2530
  const deploymentIds = new Set();
2499
- const images = new Set();
2500
2531
  for (const entry of entries) {
2501
2532
  const generationRoot = join(generationsRoot, entry);
2502
2533
  const recordPath = join(generationRoot, "deployment.json");
@@ -2519,9 +2550,6 @@ async function readEveDeploymentRecord(projectRoot, environment, name, accountId
2519
2550
  const deploymentId = parsed.deploymentId;
2520
2551
  if (deploymentId !== undefined)
2521
2552
  deploymentIds.add(deploymentId);
2522
- if (typeof parsed.identity.containerImage === "string") {
2523
- images.add(parsed.identity.containerImage);
2524
- }
2525
2553
  }
2526
2554
  }
2527
2555
  scanned.sort((left, right) => right.modifiedAt - left.modifiedAt);
@@ -2557,7 +2585,6 @@ async function readEveDeploymentRecord(projectRoot, environment, name, accountId
2557
2585
  identity: live.record.identity,
2558
2586
  status: live.record.status,
2559
2587
  deploymentIds: [...deploymentIds],
2560
- images: [...images],
2561
2588
  worldCloudflare: live.record.worldCloudflare,
2562
2589
  durableObjects: historySource?.record.durableObjects,
2563
2590
  };
@@ -2607,19 +2634,20 @@ async function parseEveDeploymentRecord(recordPath, environment, name) {
2607
2634
  const migrations = [];
2608
2635
  const durableObjectsValid = Array.isArray(rawBindings) &&
2609
2636
  Array.isArray(rawMigrations);
2637
+ const invalidHistory = () => ({
2638
+ recordPath,
2639
+ identity: base.identity,
2640
+ status,
2641
+ deploymentId,
2642
+ worldCloudflare: rawVars?.EDEN_EVE_WORLD_CLOUDFLARE === true,
2643
+ durableObjects: undefined,
2644
+ });
2610
2645
  if (durableObjectsValid) {
2611
2646
  for (const binding of rawBindings) {
2612
2647
  if (typeof binding !== "object" || binding === null ||
2613
2648
  typeof binding.name !== "string" ||
2614
2649
  typeof binding.class_name !== "string") {
2615
- return {
2616
- recordPath,
2617
- identity: base.identity,
2618
- status,
2619
- deploymentId,
2620
- worldCloudflare: rawVars?.EDEN_EVE_WORLD_CLOUDFLARE === true,
2621
- durableObjects: undefined,
2622
- };
2650
+ return invalidHistory();
2623
2651
  }
2624
2652
  bindings.push(binding);
2625
2653
  }
@@ -2627,15 +2655,8 @@ async function parseEveDeploymentRecord(recordPath, environment, name) {
2627
2655
  if (typeof migration !== "object" || migration === null ||
2628
2656
  typeof migration.tag !== "string" ||
2629
2657
  !Array.isArray(migration.new_sqlite_classes) ||
2630
- migration.new_sqlite_classes.some((className) => typeof className !== "string")) {
2631
- return {
2632
- recordPath,
2633
- identity: base.identity,
2634
- status,
2635
- deploymentId,
2636
- worldCloudflare: rawVars?.EDEN_EVE_WORLD_CLOUDFLARE === true,
2637
- durableObjects: undefined,
2638
- };
2658
+ (migration.new_sqlite_classes ?? []).some((className) => typeof className !== "string")) {
2659
+ return invalidHistory();
2639
2660
  }
2640
2661
  migrations.push(migration);
2641
2662
  }
@@ -2670,18 +2691,25 @@ async function defaultDestroyTargetRead(request) {
2670
2691
  (exactDeploymentEntries(deployments.value)?.length ?? 0) > 0;
2671
2692
  const entries = exactContainerEntries(containers.value, request.containerApplicationName);
2672
2693
  const firstContainer = entries === undefined ? undefined : entries[0];
2673
- const ownedImages = request.registryImages;
2674
- let registryImagesPresent;
2675
- if (ownedImages !== undefined && ownedImages.length > 0) {
2694
+ const ownedRepositories = request.registryRepositories;
2695
+ let registryTagsPresent;
2696
+ if (ownedRepositories !== undefined && ownedRepositories.length > 0) {
2676
2697
  const images = await readWranglerJson([
2677
2698
  "containers",
2678
2699
  "images",
2679
2700
  "list",
2680
2701
  "--json",
2681
2702
  ]);
2682
- const present = registryImageNames(images.value);
2683
- if (!images.failed && present !== undefined) {
2684
- registryImagesPresent = ownedImages.filter((image) => present.has(image));
2703
+ const tagsByRepository = registryTagsByRepository(images.value);
2704
+ if (!images.failed && tagsByRepository !== undefined) {
2705
+ const present = [];
2706
+ for (const [repository, tags] of tagsByRepository) {
2707
+ if (!ownedRepositories.includes(repository))
2708
+ continue;
2709
+ for (const tag of tags)
2710
+ present.push(`${repository}:${tag}`);
2711
+ }
2712
+ registryTagsPresent = present;
2685
2713
  }
2686
2714
  }
2687
2715
  return {
@@ -2690,21 +2718,22 @@ async function defaultDestroyTargetRead(request) {
2690
2718
  ? {}
2691
2719
  : { containerApplicationId: firstContainer.id }),
2692
2720
  ...(accountId === undefined ? {} : { accountId }),
2693
- ...(registryImagesPresent === undefined
2721
+ ...(registryTagsPresent === undefined
2694
2722
  ? {}
2695
- : { registryImagesPresent }),
2723
+ : { registryTagsPresent }),
2696
2724
  };
2697
2725
  }
2698
2726
  /**
2699
2727
  * `wrangler containers images list --json` reports `[{name, tags}]` entries
2700
- * with the account prefix already stripped from the repository name. The set
2701
- * carries `repository:tag` refs for the owned tags Eden publishes.
2728
+ * with the account prefix already stripped from the repository name. The map
2729
+ * carries every tag per repository so owned-repository cleanup can delete
2730
+ * snapshot tags alongside the pushed `candidate` tag.
2702
2731
  */
2703
- function registryImageNames(value) {
2732
+ function registryTagsByRepository(value) {
2704
2733
  const collection = jsonCollection(value);
2705
2734
  if (collection === undefined)
2706
2735
  return undefined;
2707
- const names = new Set();
2736
+ const tagsByRepository = new Map();
2708
2737
  for (const entry of collection) {
2709
2738
  if (typeof entry !== "object" || entry === null || !("name" in entry)) {
2710
2739
  return undefined;
@@ -2713,13 +2742,15 @@ function registryImageNames(value) {
2713
2742
  const tags = "tags" in entry ? entry.tags : undefined;
2714
2743
  if (typeof name !== "string" || !Array.isArray(tags))
2715
2744
  return undefined;
2745
+ const validTags = [];
2716
2746
  for (const tag of tags) {
2717
2747
  if (typeof tag !== "string")
2718
2748
  return undefined;
2719
- names.add(`${name}:${tag}`);
2749
+ validTags.push(tag);
2720
2750
  }
2751
+ tagsByRepository.set(name, validTags);
2721
2752
  }
2722
- return names;
2753
+ return tagsByRepository;
2723
2754
  }
2724
2755
  async function defaultWorkerDelete(request) {
2725
2756
  const result = await runWranglerWithInput(["delete", "--name", request.name, "--force"], process.cwd(), "y\n");
@@ -2739,23 +2770,59 @@ async function defaultContainerDelete(request) {
2739
2770
  }
2740
2771
  return "indeterminate";
2741
2772
  }
2742
- async function defaultRegistryImageDelete(request) {
2743
- const result = await runWranglerWithInput(["containers", "images", "delete", request.image, "--skip-confirmation"], process.cwd());
2744
- if (result.exitCode === 0)
2745
- return "deleted";
2746
- if (/(?:does not exist|not found|404)/iu.test(result.stderr)) {
2773
+ /**
2774
+ * Deletes every tag in an owned registry repository — the `candidate` tag
2775
+ * Eden pushed plus any `rootfs-snapshot-*`/`rootfs-set-*` tags container
2776
+ * snapshots created under the source image repository. Deleting only
2777
+ * `candidate` would leave snapshot storage behind, so each tag in the
2778
+ * repository is deleted individually.
2779
+ */
2780
+ async function defaultRegistryRepositoryDelete(request) {
2781
+ const images = await readWranglerJson([
2782
+ "containers",
2783
+ "images",
2784
+ "list",
2785
+ "--json",
2786
+ ]);
2787
+ const collection = jsonCollection(images.value);
2788
+ if (images.failed || collection === undefined)
2789
+ return "indeterminate";
2790
+ const entry = collection.find((candidate) => typeof candidate === "object" &&
2791
+ candidate !== null &&
2792
+ candidate.name === request.repository);
2793
+ if (entry === undefined)
2747
2794
  return "absent";
2795
+ const tags = entry.tags;
2796
+ if (!Array.isArray(tags) || tags.some((tag) => typeof tag !== "string")) {
2797
+ return "indeterminate";
2748
2798
  }
2749
- return "indeterminate";
2799
+ let deletedAny = false;
2800
+ for (const tag of tags) {
2801
+ const result = await runWranglerWithInput([
2802
+ "containers",
2803
+ "images",
2804
+ "delete",
2805
+ `${request.repository}:${tag}`,
2806
+ "--skip-confirmation",
2807
+ ], process.cwd());
2808
+ if (result.exitCode === 0) {
2809
+ deletedAny = true;
2810
+ continue;
2811
+ }
2812
+ if (!/(?:does not exist|not found|404)/iu.test(result.stderr)) {
2813
+ return "indeterminate";
2814
+ }
2815
+ }
2816
+ return deletedAny ? "deleted" : "absent";
2750
2817
  }
2751
2818
  /**
2752
- * The exact `<repository>:${EVE_REGISTRY_IMAGE_TAG}` ref this generation's
2753
- * deployment record proves Eden pushed, or undefined. Ownership holds only
2754
- * when the recorded digest reference points at the repository derived from
2755
- * the same identity that produced it; a digest-bearing reference to any other
2756
- * repository was published outside Eden's push and is never owned here.
2819
+ * The registry repository this generation's deployment record proves Eden
2820
+ * pushed to, or undefined. Ownership holds only when the recorded digest
2821
+ * reference points at the repository derived from the same identity that
2822
+ * produced it; a digest-bearing reference to any other repository was
2823
+ * published outside Eden's push and is never owned here.
2757
2824
  */
2758
- function ownedRegistryImageRef(identity, environment, name, accountId) {
2825
+ function ownedRegistryRepository(identity, environment, name, accountId) {
2759
2826
  if (identity.projectId === undefined ||
2760
2827
  identity.generationId === undefined ||
2761
2828
  identity.containerImage === undefined ||
@@ -2768,14 +2835,14 @@ function ownedRegistryImageRef(identity, environment, name, accountId) {
2768
2835
  imageDigestFromReference(identity.containerImage) === undefined) {
2769
2836
  return undefined;
2770
2837
  }
2771
- return `${repository}:${EVE_REGISTRY_IMAGE_TAG}`;
2838
+ return repository;
2772
2839
  }
2773
2840
  /**
2774
- * The exact image ref an indeterminate deploy attempt provably pushed. The
2775
- * retained attempt evidence names the target's repository; the account and
2776
- * target key must match the verified destroy record.
2841
+ * The registry repository an indeterminate deploy attempt provably pushed.
2842
+ * The retained attempt evidence names the target's repository; the account
2843
+ * and target key must match the verified destroy record.
2777
2844
  */
2778
- async function attemptRegistryImageRef(attemptPath, accountId, targetKey) {
2845
+ async function attemptRegistryRepository(attemptPath, accountId, targetKey) {
2779
2846
  const raw = await readFile(attemptPath, "utf8").catch(() => undefined);
2780
2847
  if (raw === undefined)
2781
2848
  return undefined;
@@ -2795,7 +2862,7 @@ async function attemptRegistryImageRef(attemptPath, accountId, targetKey) {
2795
2862
  (!("targetKey" in parsed) || parsed.targetKey === targetKey) &&
2796
2863
  "accountId" in parsed &&
2797
2864
  parsed.accountId === accountId) {
2798
- return `${parsed.imageRepository}:${EVE_REGISTRY_IMAGE_TAG}`;
2865
+ return parsed.imageRepository;
2799
2866
  }
2800
2867
  if ("imageReference" in parsed &&
2801
2868
  typeof parsed.imageReference === "string" &&
@@ -2805,39 +2872,40 @@ async function attemptRegistryImageRef(attemptPath, accountId, targetKey) {
2805
2872
  if (repository !== undefined &&
2806
2873
  repository.startsWith(expected) &&
2807
2874
  (!("targetKey" in parsed) || parsed.targetKey === targetKey)) {
2808
- return `${repository.slice(`registry.cloudflare.com/${accountId}/`.length)}:${EVE_REGISTRY_IMAGE_TAG}`;
2875
+ return repository.slice(`registry.cloudflare.com/${accountId}/`.length);
2809
2876
  }
2810
2877
  }
2811
2878
  return undefined;
2812
2879
  }
2813
2880
  /**
2814
- * Every registry image tag this exact target provably owns: the recorded
2881
+ * Every registry repository this exact target provably owns: the recorded
2815
2882
  * digest references in matching deployment records plus the repository
2816
2883
  * evidence retained by indeterminate pushes. Never derived by prefix-matching
2817
- * the registry; each ref is computed from the immutable generation records.
2884
+ * the registry; each repository is computed from the immutable generation
2885
+ * records.
2818
2886
  */
2819
- async function collectEveDestroyRegistryImages(projectRoot, environment, name, record) {
2887
+ async function collectEveDestroyRegistryRepositories(projectRoot, environment, name, record) {
2820
2888
  const generationsRoot = join(projectRoot, ".eden", "eve-deploy", "generations");
2821
2889
  const entries = await readdir(generationsRoot).catch(() => []);
2822
- const images = new Set();
2890
+ const repositories = new Set();
2823
2891
  const targetKey = record.projectId === undefined
2824
2892
  ? undefined
2825
2893
  : stableDeploymentKey(record.projectId, record.accountId, environment, name);
2826
2894
  for (const entry of entries) {
2827
2895
  const generationRoot = join(generationsRoot, entry);
2828
2896
  const parsed = await parseEveDestroyRecord(join(generationRoot, "deployment.json"), environment, name);
2829
- const deployedImage = parsed === undefined
2897
+ const deployedRepository = parsed === undefined
2830
2898
  ? undefined
2831
- : ownedRegistryImageRef(parsed.identity, environment, name, record.accountId);
2832
- if (deployedImage !== undefined)
2833
- images.add(deployedImage);
2899
+ : ownedRegistryRepository(parsed.identity, environment, name, record.accountId);
2900
+ if (deployedRepository !== undefined)
2901
+ repositories.add(deployedRepository);
2834
2902
  if (targetKey === undefined)
2835
2903
  continue;
2836
- const attemptImage = await attemptRegistryImageRef(join(generationRoot, "deployment-attempt.json"), record.accountId, targetKey);
2837
- if (attemptImage !== undefined)
2838
- images.add(attemptImage);
2904
+ const attemptRepository = await attemptRegistryRepository(join(generationRoot, "deployment-attempt.json"), record.accountId, targetKey);
2905
+ if (attemptRepository !== undefined)
2906
+ repositories.add(attemptRepository);
2839
2907
  }
2840
- return [...images];
2908
+ return [...repositories];
2841
2909
  }
2842
2910
  export async function runEveDestroy(request, options = {}) {
2843
2911
  const startedAt = Date.now();
@@ -2890,11 +2958,11 @@ async function runEveDestroyLocked(request, options, checks, emit, fail) {
2890
2958
  }
2891
2959
  checks.push(check("VAL-LIFE-006-RECORD", "passed", "The immutable deployment record matched the exact target selectors."));
2892
2960
  eveProgress(options, "verifying the immutable ownership record");
2893
- const ownedRegistryImages = await collectEveDestroyRegistryImages(request.projectRoot, request.environment, request.name, record.identity);
2961
+ const ownedRegistryRepositories = await collectEveDestroyRegistryRepositories(request.projectRoot, request.environment, request.name, record.identity);
2894
2962
  const readTarget = () => Promise.resolve(reader({
2895
2963
  workerName: expectedWorker,
2896
2964
  containerApplicationName: expectedContainer,
2897
- registryImages: ownedRegistryImages,
2965
+ registryRepositories: ownedRegistryRepositories,
2898
2966
  }));
2899
2967
  const reader = options.destroyCloudflareRead ?? defaultDestroyTargetRead;
2900
2968
  eveProgress(options, "reading the exact remote inventory");
@@ -2904,9 +2972,9 @@ async function runEveDestroyLocked(request, options, checks, emit, fail) {
2904
2972
  }
2905
2973
  if (!before.workerExists &&
2906
2974
  before.containerApplicationId === undefined &&
2907
- (ownedRegistryImages.length === 0 ||
2908
- (before.registryImagesPresent !== undefined &&
2909
- before.registryImagesPresent.length === 0))) {
2975
+ (ownedRegistryRepositories.length === 0 ||
2976
+ (before.registryTagsPresent !== undefined &&
2977
+ before.registryTagsPresent.length === 0))) {
2910
2978
  emit({
2911
2979
  ok: true,
2912
2980
  status: "absent",
@@ -2963,17 +3031,22 @@ async function runEveDestroyLocked(request, options, checks, emit, fail) {
2963
3031
  ? "The exact owned Container application was deleted."
2964
3032
  : "The exact Container application was already absent."));
2965
3033
  }
2966
- const imageDeletes = new Map();
2967
- if (ownedRegistryImages.length > 0) {
2968
- const deleteRegistryImage = options.deleteRegistryImage ?? defaultRegistryImageDelete;
2969
- const deletable = before.registryImagesPresent === undefined
2970
- ? ownedRegistryImages
2971
- : ownedRegistryImages.filter((image) => before.registryImagesPresent?.includes(image) === true);
3034
+ const repositoryDeletes = new Map();
3035
+ if (ownedRegistryRepositories.length > 0) {
3036
+ const deleteRegistryRepository = options.deleteRegistryRepository ?? defaultRegistryRepositoryDelete;
3037
+ // Every tag inside an owned repository is deleted (candidate plus
3038
+ // snapshot tags). When the registry could not be enumerated, still
3039
+ // attempt the exact owned repositories; absence verification below
3040
+ // re-reads the registry when it becomes readable.
3041
+ const presentRepositories = new Set((before.registryTagsPresent ?? []).map((ref) => ref.split(":")[0] ?? ""));
3042
+ const deletable = before.registryTagsPresent === undefined
3043
+ ? ownedRegistryRepositories
3044
+ : ownedRegistryRepositories.filter((repository) => presentRepositories.has(repository));
2972
3045
  if (deletable.length > 0) {
2973
- eveProgress(options, `deleting ${deletable.length} registry image${deletable.length === 1 ? "" : "s"}`);
3046
+ eveProgress(options, `deleting ${deletable.length} registry repositor${deletable.length === 1 ? "y" : "ies"}`);
2974
3047
  }
2975
- for (const image of deletable) {
2976
- imageDeletes.set(image, await deleteRegistryImage({ image }));
3048
+ for (const repository of deletable) {
3049
+ repositoryDeletes.set(repository, await deleteRegistryRepository({ repository }));
2977
3050
  }
2978
3051
  }
2979
3052
  eveProgress(options, "verifying the exact target is absent");
@@ -2991,15 +3064,16 @@ async function runEveDestroyLocked(request, options, checks, emit, fail) {
2991
3064
  });
2992
3065
  fail("EVE_DESTROY_ABSENCE_UNPROVEN", "The exact target could not be proven absent after deletion.");
2993
3066
  }
2994
- const retainedImages = ownedRegistryImages.filter((image) => after.registryImagesPresent === undefined
2995
- ? imageDeletes.get(image) === "indeterminate"
2996
- : after.registryImagesPresent.includes(image));
2997
- if (ownedRegistryImages.length > 0) {
2998
- checks.push(retainedImages.length === 0
3067
+ const presentTagsAfter = after.registryTagsPresent ?? [];
3068
+ const retainedRepositories = ownedRegistryRepositories.filter((repository) => presentTagsAfter.some((ref) => ref.startsWith(`${repository}:`)) ||
3069
+ (after.registryTagsPresent === undefined &&
3070
+ repositoryDeletes.get(repository) === "indeterminate"));
3071
+ if (ownedRegistryRepositories.length > 0) {
3072
+ checks.push(retainedRepositories.length === 0
2999
3073
  ? check("VAL-LIFE-006-REGISTRY", "passed", "Every registry image tag recorded for this exact target was deleted or proven absent.")
3000
- : check("VAL-LIFE-006-REGISTRY", "failed", `The exact target's registry image(s) remain after destroy: ${retainedImages.join(", ")}.`, "Retry eden destroy with the same selectors, or remove only the listed image refs with wrangler containers images delete."));
3074
+ : check("VAL-LIFE-006-REGISTRY", "failed", `The exact target's registry image tag(s) remain after destroy: ${retainedRepositories.join(", ")}.`, "Retry eden destroy with the same selectors, or remove only the listed repositories' tags with wrangler containers images delete."));
3001
3075
  }
3002
- if (retainedImages.length > 0) {
3076
+ if (retainedRepositories.length > 0) {
3003
3077
  emit({
3004
3078
  ok: false,
3005
3079
  status: "failed",
@@ -3007,7 +3081,7 @@ async function runEveDestroyLocked(request, options, checks, emit, fail) {
3007
3081
  name: request.name,
3008
3082
  checks,
3009
3083
  });
3010
- fail("EVE_DESTROY_IMAGES_RETAINED", `The exact Worker and Container are absent, but registry image(s) remain: ${retainedImages.join(", ")}.`);
3084
+ fail("EVE_DESTROY_IMAGES_RETAINED", `The exact Worker and Container are absent, but registry image tag(s) remain in: ${retainedRepositories.join(", ")}.`);
3011
3085
  }
3012
3086
  checks.push(check("VAL-LIFE-006", "passed", "Exact absence was verified; clearing this target's CURRENT pointer only."));
3013
3087
  const currentPath = join(request.projectRoot, ".eden", "eve-deploy", "targets", `${request.environment}-${request.name}`, "CURRENT");
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, EvePreflightResult, EvePreflightRuntimeEvidence, EvePreflightWarning, EvePreflightRuntimeRunner, EvePreflightRuntimeRunnerRequest, EveRegistryImageDeleteRunner, EveRuntimeConfigLoader, EveRuntimeImageDiscardRunner, EveWorkerDeleteRunner, } 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, EvePreflightResult, EvePreflightRuntimeEvidence, EvePreflightWarning, EvePreflightRuntimeRunner, EvePreflightRuntimeRunnerRequest, EveRegistryRepositoryDeleteRunner, 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.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Deploy existing Eve projects to your own Cloudflare account.",
5
5
  "keywords": [
6
6
  "ai",
@@ -31,8 +31,8 @@
31
31
  "NOTICE"
32
32
  ],
33
33
  "dependencies": {
34
- "@moinulmoin/eden-runtime-cloudflare": "0.5.0",
35
- "wrangler": "4.120.0"
34
+ "@moinulmoin/eden-runtime-cloudflare": "0.6.0",
35
+ "wrangler": "4.147.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "24.0.0"