| 1 | import * as Alchemy from "alchemy"; |
| 2 | import * as Cloudflare from "alchemy/Cloudflare"; |
| 3 | import { Config } from "effect"; |
| 4 | import * as Effect from "effect/Effect"; |
| 5 | import type { Counter as CounterClass } from "./src/worker.ts"; |
| 6 | |
| 7 | export const DB = Cloudflare.D1.Database("DB"); |
| 8 | |
| 9 | export const Bucket = Cloudflare.R2.Bucket("Bucket", { forceDestroy: true }); |
| 10 | |
| 11 | // Queue producer + consumer wiring (both sides exercised by the same worker). |
| 12 | // The Worker sends a message via `env.QUEUE.send(...)` from POST /queue/send, |
| 13 | // then receives and persists it via its `queue(batch)` handler — end-to-end |
| 14 | // regression guard for the Queue, QueueWrite, and Consumer resources. |
| 15 | export const Queue = Cloudflare.Queues.Queue("Queue"); |
| 16 | |
| 17 | export const Counter = Cloudflare.DurableObject<CounterClass>("Counter", { |
| 18 | className: "Counter", |
| 19 | }); |
| 20 | |
| 21 | export type WorkerEnv = Cloudflare.InferEnv<typeof Worker>; |
| 22 | |
| 23 | export const Worker = Cloudflare.Worker("Worker", { |
| 24 | main: "./src/worker.ts", |
| 25 | assets: { |
| 26 | directory: "./public", |
| 27 | }, |
| 28 | env: { |
| 29 | // Self-contained default so the example deploys without external secrets; |
| 30 | // the integ test asserts this value round-trips through env.API_KEY. |
| 31 | API_KEY: Config.Redacted("SOME_API_KEY").pipe( |
| 32 | Config.withDefault("SOME_API_KEY"), |
| 33 | ), |
| 34 | DB, |
| 35 | Bucket, |
| 36 | Queue, |
| 37 | Counter, |
| 38 | }, |
| 39 | }); |
| 40 | |
| 41 | export default Alchemy.Stack( |
| 42 | "CloudflareWorker", |
| 43 | { |
| 44 | providers: Cloudflare.providers(), |
| 45 | state: Cloudflare.state(), |
| 46 | }, |
| 47 | Effect.gen(function* () { |
| 48 | const queue = yield* Queue; |
| 49 | const worker = yield* Worker; |
| 50 | // create a random resource to test redacted storage |
| 51 | yield* Alchemy.Random("Random"); |
| 52 | |
| 53 | // Register the same worker script as a consumer of Queue. The worker's |
| 54 | // `queue(batch)` handler (see src/worker.ts) receives each message batch. |
| 55 | yield* Cloudflare.Queues.Consumer("Consumer", { |
| 56 | queueId: queue.queueId, |
| 57 | scriptName: worker.workerName, |
| 58 | settings: { |
| 59 | batchSize: 10, |
| 60 | maxRetries: 3, |
| 61 | maxWaitTimeMs: 5000, |
| 62 | }, |
| 63 | }); |
| 64 | |
| 65 | return { url: worker.url.as<string>() }; |
| 66 | }), |
| 67 | ); |