1import * as Alchemy from "alchemy";
2import * as Cloudflare from "alchemy/Cloudflare";
3import * as Effect from "effect/Effect";
4
5import { Gateway } from "./src/AiGateway.ts";
6import Api from "./src/Api.ts";
7import { Bucket } from "./src/Bucket.ts";
8import SandboxLive from "./src/Sandbox.ts";
9import SecondaryApiLive, { SecondaryApi } from "./src/SecondaryApi.ts";
10import WorkerTagLive, { WorkerTag } from "./src/WorkerTag.ts";
11
12// Demo Action — runs at deploy time when its input (the resolved deployed
13// URL) changes. Logs the new URL and returns a tiny manifest used as the
14// stack output. Re-deploys with no changes skip the body.
15const AnnounceDeploy = Alchemy.Action(
16 "AnnounceDeploy",
17 (input: { url: string; bucket: string }) =>
18 Effect.gen(function* () {
19 yield* Effect.log(`Deployed ${input.url} (bucket: ${input.bucket})`);
20 return { deployedAt: new Date().toISOString(), url: input.url };
21 }),
22);
23
24export default Alchemy.Stack(
25 "CloudflareWorkerExample",
26 {
27 providers: Cloudflare.providers(),
28 state: Cloudflare.state(),
29 },
30 Effect.gen(function* () {
31 const api = yield* Api;
32 const bucket = yield* Bucket;
33 const gateway = yield* Gateway;
34 const workerTag = yield* WorkerTag;
35 // Two Workers binding the same Agent DO triggers the regression where
36 // a single Container DO namespace appears in multiple bindings on the
37 // Sandbox ContainerApplication. See SecondaryApi.ts for details.
38 const secondaryApi = yield* SecondaryApi;
39 // The Queue consumer is wired automatically by
40 // `Cloudflare.Queues.consumeQueueMessages(Queue, handler)` inside src/Api.ts —
41 // no explicit `Cloudflare.Queues.Consumer(...)` is needed here.
42
43 const announcement = yield* AnnounceDeploy({
44 url: api.url.as<string>(),
45 bucket: bucket.bucketName,
46 });
47
48 return {
49 url: api.url.as<string>(),
50 bucket: bucket.bucketName,
51 gatewayId: gateway.gatewayId,
52 workerTagUrl: workerTag.url.as<string>(),
53 secondaryApiUrl: secondaryApi.url.as<string>(),
54 deployedAt: announcement.deployedAt,
55 };
56 }).pipe(Effect.provide([WorkerTagLive, SecondaryApiLive, SandboxLive])),
57);