alchemy 2.0.0-beta.82 → 2.0.0-beta.83

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.
Files changed (72) hide show
  1. package/lib/Cloudflare/Containers/Container.d.ts +128 -40
  2. package/lib/Cloudflare/Containers/Container.d.ts.map +1 -1
  3. package/lib/Cloudflare/Containers/Container.js +124 -24
  4. package/lib/Cloudflare/Containers/Container.js.map +1 -1
  5. package/lib/Cloudflare/Containers/ContainerApplication.d.ts +59 -50
  6. package/lib/Cloudflare/Containers/ContainerApplication.d.ts.map +1 -1
  7. package/lib/Cloudflare/Containers/ContainerApplication.js.map +1 -1
  8. package/lib/Cloudflare/Containers/ContainerClient.d.ts +20 -7
  9. package/lib/Cloudflare/Containers/ContainerClient.d.ts.map +1 -1
  10. package/lib/Cloudflare/Containers/ContainerClient.js +22 -5
  11. package/lib/Cloudflare/Containers/ContainerClient.js.map +1 -1
  12. package/lib/Cloudflare/Containers/ContainerConfiguration.d.ts +132 -13
  13. package/lib/Cloudflare/Containers/ContainerConfiguration.d.ts.map +1 -1
  14. package/lib/Cloudflare/Containers/ContainerConfiguration.js +219 -35
  15. package/lib/Cloudflare/Containers/ContainerConfiguration.js.map +1 -1
  16. package/lib/Cloudflare/Containers/ContainerPlatform.d.ts +1 -1
  17. package/lib/Cloudflare/Containers/ContainerPlatform.d.ts.map +1 -1
  18. package/lib/Cloudflare/Containers/ContainerPlatform.js +21 -2
  19. package/lib/Cloudflare/Containers/ContainerPlatform.js.map +1 -1
  20. package/lib/Cloudflare/Containers/ContainerProvider.d.ts.map +1 -1
  21. package/lib/Cloudflare/Containers/ContainerProvider.js +74 -177
  22. package/lib/Cloudflare/Containers/ContainerProvider.js.map +1 -1
  23. package/lib/Cloudflare/Containers/DurableObjectApplication.d.ts +84 -0
  24. package/lib/Cloudflare/Containers/DurableObjectApplication.d.ts.map +1 -0
  25. package/lib/Cloudflare/Containers/DurableObjectApplication.js +249 -0
  26. package/lib/Cloudflare/Containers/DurableObjectApplication.js.map +1 -0
  27. package/lib/Cloudflare/Containers/LocalContainerProvider.d.ts.map +1 -1
  28. package/lib/Cloudflare/Containers/LocalContainerProvider.js +20 -41
  29. package/lib/Cloudflare/Containers/LocalContainerProvider.js.map +1 -1
  30. package/lib/Cloudflare/Containers/index.d.ts +2 -1
  31. package/lib/Cloudflare/Containers/index.d.ts.map +1 -1
  32. package/lib/Cloudflare/Containers/index.js +2 -1
  33. package/lib/Cloudflare/Containers/index.js.map +1 -1
  34. package/lib/Cloudflare/Providers.d.ts.map +1 -1
  35. package/lib/Cloudflare/Providers.js +2 -1
  36. package/lib/Cloudflare/Providers.js.map +1 -1
  37. package/lib/Cloudflare/StateStore/Api.d.ts +3 -0
  38. package/lib/Cloudflare/Workers/DurableObject.d.ts +75 -1
  39. package/lib/Cloudflare/Workers/DurableObject.d.ts.map +1 -1
  40. package/lib/Cloudflare/Workers/DurableObject.js +50 -0
  41. package/lib/Cloudflare/Workers/DurableObject.js.map +1 -1
  42. package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
  43. package/lib/Cloudflare/Workers/LocalWorkerProvider.js +29 -23
  44. package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
  45. package/lib/Cloudflare/Workers/Worker.d.ts +2 -0
  46. package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
  47. package/lib/Cloudflare/Workers/Worker.js.map +1 -1
  48. package/lib/Cloudflare/Workers/WorkerAsyncBindings.d.ts.map +1 -1
  49. package/lib/Cloudflare/Workers/WorkerAsyncBindings.js +67 -4
  50. package/lib/Cloudflare/Workers/WorkerAsyncBindings.js.map +1 -1
  51. package/lib/Cloudflare/Workers/WorkerBinding.d.ts +6 -0
  52. package/lib/Cloudflare/Workers/WorkerBinding.d.ts.map +1 -1
  53. package/lib/Cloudflare/Workers/WorkerProvider.d.ts.map +1 -1
  54. package/lib/Cloudflare/Workers/WorkerProvider.js +54 -8
  55. package/lib/Cloudflare/Workers/WorkerProvider.js.map +1 -1
  56. package/lib/State/HttpStateApi.d.ts +13 -13
  57. package/package.json +6 -6
  58. package/src/Cloudflare/Containers/Container.ts +126 -56
  59. package/src/Cloudflare/Containers/ContainerApplication.ts +60 -53
  60. package/src/Cloudflare/Containers/ContainerClient.ts +47 -13
  61. package/src/Cloudflare/Containers/ContainerConfiguration.ts +316 -44
  62. package/src/Cloudflare/Containers/ContainerPlatform.ts +27 -3
  63. package/src/Cloudflare/Containers/ContainerProvider.ts +96 -256
  64. package/src/Cloudflare/Containers/DurableObjectApplication.ts +382 -0
  65. package/src/Cloudflare/Containers/LocalContainerProvider.ts +20 -48
  66. package/src/Cloudflare/Containers/index.ts +10 -0
  67. package/src/Cloudflare/Providers.ts +2 -0
  68. package/src/Cloudflare/Workers/DurableObject.ts +77 -1
  69. package/src/Cloudflare/Workers/LocalWorkerProvider.ts +32 -21
  70. package/src/Cloudflare/Workers/Worker.ts +2 -0
  71. package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +95 -4
  72. package/src/Cloudflare/Workers/WorkerProvider.ts +78 -13
@@ -27,7 +27,6 @@ import { CloudflareLogs, type TelemetryFilter } from "../Logs.ts";
27
27
  import type {
28
28
  AnyContainerApplicationProps,
29
29
  ContainerApplication,
30
- DevContainerImage,
31
30
  DurableObjectContainerProps,
32
31
  } from "./ContainerApplication.ts";
33
32
  import {
@@ -41,15 +40,15 @@ import {
41
40
  } from "./ContainerBundle.ts";
42
41
  import {
43
42
  ContainerConfigurationError,
44
- isDurableObjectContainer,
45
43
  durableObjectPlaceholder,
46
- namedImageHash,
47
- durableObjectSettingsPatch,
44
+ hasImageSource,
45
+ isDurableObjectContainer,
48
46
  validateContainerConfiguration,
49
47
  } from "./ContainerConfiguration.ts";
50
48
  import { waitForContainerImage } from "./ContainerImagePreparation.ts";
51
49
  import { ContainerPlatform } from "./ContainerPlatform.ts";
52
50
  import { retryContainerPublication } from "./ContainerPublication.ts";
51
+ import { retryNamespacePropagation } from "./DurableObjectApplication.ts";
53
52
 
54
53
  /**
55
54
  * The image source resolved from a {@link ContainerApplicationProps}. Selects
@@ -126,6 +125,9 @@ class ContainerRegistryError extends Schema.TaggedError<ContainerRegistryError>(
126
125
  },
127
126
  ) {}
128
127
 
128
+ /** The explicit application name. Durable Object-managed Containers have none. */
129
+ const nameOf = (props: AnyContainerApplicationProps | undefined) => props?.name;
130
+
129
131
  const digestFromImageRef = (imageRef: string) => {
130
132
  const separator = imageRef.lastIndexOf("@");
131
133
  if (separator === -1) return undefined;
@@ -766,29 +768,11 @@ export const LiveContainerProvider = () =>
766
768
  });
767
769
 
768
770
  // ---------------------------------------------------------------
769
- // Durable Object-managed applications (schedulingPolicy:
770
- // "durable_object"). These have no deployment image or rollout: the
771
- // Durable Object picks one of the named `images` at `start()` time.
771
+ // Durable Object-managed Containers (schedulingPolicy:
772
+ // "durable_object"). A Container publishes one image; the application
773
+ // belongs to the Durable Object class (see DurableObjectApplication).
772
774
  // ---------------------------------------------------------------
773
775
 
774
- /** Resolve the build inputs and content hash of every named image. */
775
- const computeNamedImages = Effect.fn(function* (
776
- id: string,
777
- props: DurableObjectContainerProps,
778
- ) {
779
- return yield* Effect.forEach(
780
- Object.entries(props.images ?? {}),
781
- Effect.fn(function* ([name, source]) {
782
- const imageId = `${id}-${name}`;
783
- const image = yield* computeImage(imageId, source, {});
784
- return { name, imageId, source, ...image };
785
- }),
786
- );
787
- });
788
-
789
- const hashesByName = (images: { name: string; imageHash: string }[]) =>
790
- Object.fromEntries(images.map((image) => [image.name, image.imageHash]));
791
-
792
776
  /**
793
777
  * Cloudflare must prepare an image before a Worker upload may reference
794
778
  * it. Preparation is per image reference, so remember the ones that are
@@ -813,198 +797,98 @@ export const LiveContainerProvider = () =>
813
797
  preparedImages.add(image);
814
798
  });
815
799
 
800
+ /** The build inputs and content hash of a Durable Object Container's image. */
801
+ const computeDurableObjectImage = (id: string, props: DurableObjectContainerProps) =>
802
+ hasImageSource(props) ? computeImage(id, props, {}) : Effect.succeed(undefined);
803
+
816
804
  /**
817
- * Publish every named image to Cloudflare's registry and wait until each
818
- * one is prepared. An image whose content hash is unchanged keeps its
819
- * previously published reference.
805
+ * Publish the Container's image to Cloudflare's registry and wait until
806
+ * it is prepared. An unchanged content hash keeps the previously
807
+ * published reference.
820
808
  */
821
- const publishNamedImages = Effect.fn(function* (
822
- id: string,
823
- props: DurableObjectContainerProps,
824
- output: ContainerApplication["Attributes"] | undefined,
825
- session: ScopedPlanStatusSession,
826
- ) {
827
- const images: Record<string, string> = {};
828
- const devImages: Record<string, DevContainerImage> = {};
829
- const hashes: Record<string, string> = {};
830
-
831
- for (const image of yield* computeNamedImages(id, props)) {
832
- const previousRef = output?.images?.[image.name];
833
- const unchanged = output?.hash?.images?.[image.name] === image.imageHash;
834
-
835
- let imageRef: string;
836
- if (previousRef !== undefined && unchanged) {
837
- imageRef = previousRef;
838
- } else {
839
- const published = yield* buildAndPushImage(
840
- image.imageId,
841
- image.source,
842
- image.build,
843
- image.imageRef,
844
- image.imageHash,
845
- undefined,
846
- session,
847
- // The registry tag keyed by image inputs is the durable publication checkpoint.
848
- // Reuse it after an interrupted preparation, including mirrored images.
849
- true,
850
- );
851
- imageRef = published.imageRef;
852
- }
853
- yield* waitForImagePrepared(imageRef, image.name, props.imagePreparationTimeout, session);
854
-
855
- images[image.name] = imageRef;
856
- devImages[image.name] = image.dev;
857
- hashes[image.name] = image.imageHash;
858
- }
859
-
860
- return {
861
- images,
862
- devImages,
863
- hash: yield* namedImageHash(hashes),
864
- };
865
- });
866
-
867
- const diffDurableObjectApplication = Effect.fn(function* ({
809
+ const reconcileDurableObjectContainer = Effect.fn(function* ({
868
810
  id,
869
811
  news,
870
812
  name,
871
- oldName,
872
- accountId,
873
813
  output,
874
- newBindings,
814
+ session,
875
815
  }: {
876
816
  id: string;
877
817
  news: DurableObjectContainerProps;
878
818
  name: string;
879
- oldName: string;
880
- accountId: string;
881
819
  output: ContainerApplication["Attributes"] | undefined;
882
- newBindings: ResourceBinding<ContainerApplication["Binding"]>[];
820
+ session: ScopedPlanStatusSession;
883
821
  }) {
884
- // A namespace holds exactly one application, so a replacement could
885
- // never be created next to the old one. Refuse instead.
886
- const movedAccount =
887
- output !== undefined && output.accountId !== accountId && isLiveId(output.applicationId);
888
- if (name !== oldName || movedAccount) {
889
- return yield* new ContainerConfigurationError({
890
- message:
891
- "A Durable Object-managed container cannot change its application name or account in place. Declare a new application and Durable Object namespace.",
892
- });
893
- }
894
- const deployedNamespace = output?.durableObjects?.namespaceId;
895
- const namespace = yield* getDurableObjects(newBindings);
896
- if (
897
- deployedNamespace !== undefined &&
898
- namespace !== undefined &&
899
- deployedNamespace !== namespace.namespaceId
900
- ) {
901
- return yield* new ContainerConfigurationError({
902
- message:
903
- "A container application cannot move to a different Durable Object namespace. Declare a new application for the new namespace.",
904
- });
905
- }
906
-
907
- // Precreate only reserves a name; reconcile creates the application
908
- // once the Worker has created its namespace.
909
- if (!output?.applicationId || !isLiveId(output.applicationId)) {
910
- return { action: "update" as const, stables: ["accountId"] };
911
- }
912
-
913
- // Image content (a Dockerfile, a context file) can change without any
914
- // prop changing, so compare content hashes as well.
915
- const hashes = hashesByName(yield* computeNamedImages(id, news));
916
- if (output.images === undefined || !deepEqual(hashes, output.hash?.images)) {
917
- return { action: "update" } as const;
822
+ const { accountId } = yield* yield* CloudflareEnvironment;
823
+ const attributes = durableObjectPlaceholder({
824
+ // The application is owned by the Durable Object class.
825
+ applicationId: "",
826
+ applicationName: name,
827
+ accountId,
828
+ createdAt: output?.createdAt ?? "",
829
+ observability: news.observability,
830
+ });
831
+ const image = yield* computeDurableObjectImage(id, news);
832
+ if (image === undefined) return attributes;
833
+
834
+ let imageRef: string;
835
+ let digest: string | undefined;
836
+ if (output?.image !== undefined && output.hash?.image === image.imageHash) {
837
+ imageRef = output.image;
838
+ digest = output.hash.digest;
839
+ } else {
840
+ const published = yield* buildAndPushImage(
841
+ id,
842
+ news,
843
+ image.build,
844
+ image.imageRef,
845
+ image.imageHash,
846
+ undefined,
847
+ session,
848
+ // The registry tag keyed by image inputs is the durable publication checkpoint.
849
+ // Reuse it after an interrupted preparation, including mirrored images.
850
+ true,
851
+ );
852
+ imageRef = published.imageRef;
853
+ digest = published.digest;
918
854
  }
919
- return undefined;
855
+ yield* waitForImagePrepared(imageRef, id, news.imagePreparationTimeout, session);
856
+ return {
857
+ ...attributes,
858
+ image: imageRef,
859
+ dev: image.dev,
860
+ hash: { image: image.imageHash, digest },
861
+ } satisfies ContainerApplication["Attributes"];
920
862
  });
921
863
 
922
- const reconcileDurableObjectApplication = Effect.fn(function* ({
864
+ const diffDurableObjectContainer = Effect.fn(function* ({
923
865
  id,
924
866
  news,
925
- olds,
926
- name,
927
- durableObjects,
928
867
  output,
929
- session,
930
868
  }: {
931
869
  id: string;
932
870
  news: DurableObjectContainerProps;
933
- olds: AnyContainerApplicationProps | undefined;
934
- name: string;
935
- durableObjects: { namespaceId: string } | undefined;
936
871
  output: ContainerApplication["Attributes"] | undefined;
937
- session: ScopedPlanStatusSession;
938
872
  }) {
939
- if (!durableObjects) {
940
- return yield* new ContainerConfigurationError({
941
- message: `Container application '${name}' requires a resolved Durable Object namespace. Reconcile its Worker first.`,
942
- });
943
- }
944
- const { accountId } = yield* yield* CloudflareEnvironment;
945
- // The application's id is the id of the namespace it serves.
946
- const applicationId = durableObjects.namespaceId;
947
- const getApplication = Containers.getContainerApplication({
948
- accountId,
949
- applicationId,
950
- });
951
- const assertMatchesDeclaration = (
952
- application: Containers.GetContainerApplicationResponse,
953
- ) => {
954
- const matches =
955
- application.id === applicationId &&
956
- application.name === name &&
957
- application.schedulingPolicy === "durable_object" &&
958
- application.durableObjects?.namespaceId === applicationId;
959
- if (matches) return Effect.void;
960
- return Effect.fail(
961
- new ContainerConfigurationError({
962
- message: `The application for Durable Object namespace '${applicationId}' does not match '${name}'. Its name, namespace, and scheduling policy must match before updating it.`,
963
- }),
964
- );
965
- };
966
-
967
- // 1. Observe
968
- let application = yield* getApplication.pipe(
969
- Effect.catchTag("ContainerApplicationNotFound", () => Effect.succeed(undefined)),
970
- );
971
- if (application) yield* assertMatchesDeclaration(application);
972
-
973
- // 2. Publish images. The Worker upload that follows references them.
974
- const published = yield* publishNamedImages(id, news, output, session);
975
-
976
- const configuration: Containers.DurableObjectContainerConfiguration = {
977
- ...(news.ssh !== undefined ? { wranglerSsh: news.ssh } : {}),
978
- ...(news.authorizedKeys !== undefined ? { authorizedKeys: news.authorizedKeys } : {}),
979
- };
980
-
981
- // 3. Ensure the application exists
982
- if (!application) {
983
- yield* session.note(`Creating container application ${name}...`);
984
- application = yield* retryNamespacePropagation(
985
- Containers.createDurableObjectContainerApplication({
986
- accountId,
987
- name,
988
- schedulingPolicy: "durable_object",
989
- durableObjects,
990
- configuration,
991
- observability: news.observability,
992
- }),
993
- ).pipe(Effect.catchTag("DurableObjectAlreadyHasApplication", () => getApplication));
994
- yield* assertMatchesDeclaration(application);
873
+ if (output === undefined) return undefined;
874
+ // State written before one Container meant one image recorded the
875
+ // Container as the application itself. The application now belongs to
876
+ // the Durable Object class; drop the identity so deleting this
877
+ // Container never deletes the class's application.
878
+ if (output.applicationId !== "") {
879
+ return { action: "update" as const, stables: ["accountId"] };
995
880
  }
996
-
997
- // 4. Sync declared settings and reset settings removed from prior props.
998
- const patch = durableObjectSettingsPatch(news, olds, application);
999
- if (patch.configuration !== undefined || patch.observability !== undefined) {
1000
- application = yield* Containers.updateContainerApplication({
1001
- accountId,
1002
- applicationId,
1003
- ...patch,
1004
- });
881
+ // Image content (a Dockerfile, a context file) can change without any
882
+ // prop changing, so compare content hashes as well.
883
+ const image = yield* computeDurableObjectImage(id, news);
884
+ if (
885
+ image?.imageHash !== output.hash?.image ||
886
+ (image !== undefined && output.image === undefined) ||
887
+ !deepEqual(image?.dev, output.dev)
888
+ ) {
889
+ return { action: "update" } as const;
1005
890
  }
1006
-
1007
- return { ...toAttributes(application), ...published };
891
+ return undefined;
1008
892
  });
1009
893
 
1010
894
  const maybeCreateRollout = Effect.fn(function* ({
@@ -1325,22 +1209,15 @@ export const LiveContainerProvider = () =>
1325
1209
  if (!isResolved(newBindings)) return;
1326
1210
  const { accountId } = yield* yield* CloudflareEnvironment;
1327
1211
 
1328
- const oldName = output?.applicationName ?? (yield* createApplicationName(id, olds.name));
1212
+ const oldName =
1213
+ output?.applicationName ?? (yield* createApplicationName(id, nameOf(olds)));
1329
1214
  // Auto-generated names are engine-owned: the deployed name stays
1330
1215
  // authoritative even if the generator would name this id differently
1331
1216
  // today. Only an explicit user-provided name can force a replace.
1332
- const name = news.name ?? oldName;
1217
+ const name = nameOf(news) ?? oldName;
1333
1218
 
1334
1219
  if (isDurableObjectContainer(news)) {
1335
- return yield* diffDurableObjectApplication({
1336
- id,
1337
- news,
1338
- name,
1339
- oldName,
1340
- accountId,
1341
- output,
1342
- newBindings,
1343
- });
1220
+ return yield* diffDurableObjectContainer({ id, news, output });
1344
1221
  }
1345
1222
 
1346
1223
  if ((output?.accountId ?? accountId) !== accountId || name !== oldName) {
@@ -1392,24 +1269,18 @@ export const LiveContainerProvider = () =>
1392
1269
  }),
1393
1270
  precreate: Effect.fn(function* ({ id, news = {}, session }) {
1394
1271
  yield* validateContainerConfiguration(news);
1395
- const name = yield* createApplicationName(id, news.name);
1272
+ const name = yield* createApplicationName(id, nameOf(news));
1396
1273
  yield* Effect.logInfo(`Cloudflare Container precreate: starting ${name}`);
1397
1274
 
1398
1275
  const { accountId } = yield* yield* CloudflareEnvironment;
1399
1276
  if (isDurableObjectContainer(news)) {
1400
- // The application needs the Worker's namespace id, which does not
1401
- // exist yet; reconcile creates it. Publish the images now so the
1402
- // Worker's first upload can already reference them.
1403
- return {
1404
- ...durableObjectPlaceholder({
1405
- applicationId: "",
1406
- applicationName: name,
1407
- accountId,
1408
- createdAt: "",
1409
- observability: news.observability,
1410
- }),
1411
- ...(yield* publishNamedImages(id, news, undefined, session)),
1412
- } satisfies ContainerApplication["Attributes"];
1277
+ return yield* reconcileDurableObjectContainer({
1278
+ id,
1279
+ news,
1280
+ name,
1281
+ output: undefined,
1282
+ session,
1283
+ });
1413
1284
  }
1414
1285
  const env = makeContainerEnv(news, accountId);
1415
1286
  const { build, imageRef, imageHash, dev } = yield* computeImage(id, news, env);
@@ -1458,24 +1329,16 @@ export const LiveContainerProvider = () =>
1458
1329
  dev,
1459
1330
  };
1460
1331
  }),
1461
- reconcile: Effect.fn(function* ({ id, news = {}, olds, bindings, output, session }) {
1332
+ reconcile: Effect.fn(function* ({ id, news = {}, bindings, output, session }) {
1462
1333
  yield* validateContainerConfiguration(news, output?.schedulingPolicy);
1463
1334
  // Prefer the deployed name: regenerating would target a different
1464
1335
  // resource if the generator's output for this id ever drifts.
1465
- const name = output?.applicationName ?? (yield* createApplicationName(id, news.name));
1336
+ const name = output?.applicationName ?? (yield* createApplicationName(id, nameOf(news)));
1466
1337
  yield* Effect.logInfo(`Cloudflare Container reconcile: starting ${name}`);
1467
- const durableObjects = yield* getDurableObjects(bindings);
1468
1338
  if (isDurableObjectContainer(news)) {
1469
- return yield* reconcileDurableObjectApplication({
1470
- id,
1471
- news,
1472
- olds,
1473
- name,
1474
- durableObjects,
1475
- output,
1476
- session,
1477
- });
1339
+ return yield* reconcileDurableObjectContainer({ id, news, name, output, session });
1478
1340
  }
1341
+ const durableObjects = yield* getDurableObjects(bindings);
1479
1342
  const hasUnresolvedAttachment =
1480
1343
  durableObjects === undefined &&
1481
1344
  bindings.some((binding) => binding.data.durableObjects !== undefined);
@@ -1701,8 +1564,7 @@ export const LiveContainerProvider = () =>
1701
1564
  // API can't return — preserve the persisted one so a refresh
1702
1565
  // doesn't wipe it (which would break a later `alchemy dev`).
1703
1566
  dev: output?.dev,
1704
- images: output?.images,
1705
- devImages: output?.devImages,
1567
+ image: output?.image,
1706
1568
  };
1707
1569
  });
1708
1570
 
@@ -1723,8 +1585,7 @@ export const LiveContainerProvider = () =>
1723
1585
  ...toAttributes(app),
1724
1586
  hash: output.hash,
1725
1587
  dev: output.dev,
1726
- images: output.images,
1727
- devImages: output.devImages,
1588
+ image: output.image,
1728
1589
  })),
1729
1590
  Effect.catchTag("ContainerApplicationNotFound", () =>
1730
1591
  readByName(output.applicationName),
@@ -1734,12 +1595,12 @@ export const LiveContainerProvider = () =>
1734
1595
  return attrs;
1735
1596
  }
1736
1597
 
1737
- const name = yield* createApplicationName(id, olds?.name);
1598
+ const name = yield* createApplicationName(id, nameOf(olds));
1738
1599
  attrs = yield* readByName(name);
1739
1600
  if (!attrs) return undefined;
1740
1601
  // Generated names identify this instance by its random suffix.
1741
1602
  // Explicit names alone do not establish ownership.
1742
- return olds?.name === undefined ? attrs : Unowned(attrs);
1603
+ return nameOf(olds) === undefined ? attrs : Unowned(attrs);
1743
1604
  }),
1744
1605
  list: () =>
1745
1606
  Effect.gen(function* () {
@@ -1831,27 +1692,6 @@ const isContainerApplicationNotFound = (
1831
1692
  "_tag" in error &&
1832
1693
  error._tag === "ContainerApplicationNotFound";
1833
1694
 
1834
- /**
1835
- * Right after a Worker upload creates a Durable Object namespace, the
1836
- * containers API can report the namespace missing for a few seconds before it
1837
- * sees it. Retry creates that attach to it, bounded at ~30s.
1838
- */
1839
- const retryNamespacePropagation = <A, E extends { readonly _tag: string }, R>(
1840
- effect: Effect.Effect<A, E, R>,
1841
- ) =>
1842
- effect.pipe(
1843
- Effect.tapError((error) =>
1844
- error._tag === "DurableObjectNamespaceNotFound"
1845
- ? Effect.logDebug("Cloudflare Container create: namespace not visible yet, retrying")
1846
- : Effect.void,
1847
- ),
1848
- Effect.retry({
1849
- while: (error) => error._tag === "DurableObjectNamespaceNotFound",
1850
- schedule: Schedule.spaced("2 seconds"),
1851
- times: 15,
1852
- }),
1853
- );
1854
-
1855
1695
  export const retryForContainerApplicationReadiness = <A, E, R>(
1856
1696
  operation: string,
1857
1697
  applicationId: string,