### Init/Exec Split Example Source: https://v2.alchemy.run/concepts/phases This code demonstrates how to use the init/exec split. The 'init' phase runs once per cold start to resolve infrastructure references and initialize clients. The 'exec' phase runs per request with a pre-configured context. ```typescript Effect.gen(function* () { // Init: runs once per cold start const bucket = yield* Cloudflare.R2Bucket.bind(Bucket); const kv = yield* Cloudflare.KVNamespace.bind(KV); return { // Exec: runs per request fetch: Effect.gen(function* () { const obj = yield* bucket.get("key"); // ... }), }; }); ``` -------------------------------- ### Bun CI Workflow Steps Source: https://v2.alchemy.run/guides/ci Defines the setup, installation, and execution steps for a CI workflow using Bun as the package manager. Includes specific commands for installing dependencies and running Alchemy. ```yaml setup: - name: Setup Bun uses: oven-sh/setup-bun@v2 install: bun install run: bun alchemy destroy: bun alchemy ``` -------------------------------- ### Initialize Project and Install Dependencies Source: https://v2.alchemy.run/tutorial/aws/lambda Sets up a new project directory and installs necessary Alchemy and Effect libraries using Bun. ```bash mkdir my-app && cd my-app && bun init -y bun add alchemy effect @effect/platform-bun ``` -------------------------------- ### Alchemy Login Examples Source: https://v2.alchemy.run/guides/cli Examples demonstrating how to log in with the default profile, a separate profile, or re-configure provider settings. ```sh # Log in with the default profile alchemy login ``` ```sh # Log in to a separate profile alchemy login --profile prod ``` ```sh # Re-configure (e.g. switch from OAuth to API token) and log in alchemy login --configure ``` -------------------------------- ### npm CI Workflow Steps Source: https://v2.alchemy.run/guides/ci Defines the setup, installation, and execution steps for a CI workflow using npm. It specifies Node.js setup, dependency installation with `npm ci`, and running Alchemy commands. ```yaml setup: - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "24" install: npm ci run: npx alchemy destroy: npx alchemy ``` -------------------------------- ### Yarn CI Workflow Steps Source: https://v2.alchemy.run/guides/ci Outlines the CI workflow steps for Yarn, including Node.js setup, global Yarn installation, dependency installation, and running Alchemy commands. This ensures Yarn is properly configured for CI execution. ```yaml setup: - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "24" cache: "yarn" - name: Install yarn run: npm install -g yarn install: yarn install run: yarn dlx alchemy destroy: yarn dlx alchemy ``` -------------------------------- ### Create Basic AI Gateway Source: https://v2.alchemy.run/providers/cloudflare/aigateway Instantiate a basic AI Gateway. This is the simplest way to get started with the AI Gateway. ```typescript const gateway = yield* Cloudflare.AiGateway("Gateway"); ``` -------------------------------- ### Install Alchemy and Dependencies with Bun Source: https://v2.alchemy.run/getting-started Install Alchemy and its associated Effect platform packages using Bun. ```sh bun add alchemy@latest effect@latest @effect/platform-bun@latest @effect/platform-node@latest ``` -------------------------------- ### Install React and Vite dependencies Source: https://v2.alchemy.run/tutorial/cloudflare/vite-spa Install React and its types, along with Vite's React plugin types, using Bun. ```bash bun add react react-dom bun add -d @types/react @types/react-dom @vitejs/plugin-react ``` -------------------------------- ### Alchemy Profile Show Examples Source: https://v2.alchemy.run/guides/cli Examples for showing the default profile or a specific named profile's credentials. ```sh # Show the default profile alchemy profile show ``` ```sh # Show a named profile alchemy profile show --profile prod ``` -------------------------------- ### Deployment Output Example Source: https://v2.alchemy.run/tutorial/cloudflare/vite-spa The deployment process outputs the URL for the Worker and the web application. ```json { url: "https://myapp-worker-dev-you.workers.dev", webUrl: "https://myapp-web-dev-you.workers.dev", } ``` -------------------------------- ### Install Alchemy and Dependencies with Yarn Source: https://v2.alchemy.run/getting-started Install Alchemy and its associated Effect platform packages using Yarn. ```sh yarn add alchemy@latest effect@latest @effect/platform-bun@latest @effect/platform-node@latest ``` -------------------------------- ### Install Alchemy and Dependencies with npm Source: https://v2.alchemy.run/getting-started Install Alchemy and its associated Effect platform packages using npm. ```sh npm install alchemy@latest effect@latest @effect/platform-bun@latest @effect/platform-node@latest ``` -------------------------------- ### Start Alchemy Development Server Source: https://v2.alchemy.run/ Run this command to start the Alchemy development server, enabling hot-reloading for frontend, backend, and infrastructure. ```bash $ alchemy dev ``` -------------------------------- ### Install Alchemy and Dependencies with pnpm Source: https://v2.alchemy.run/getting-started Install Alchemy and its associated Effect platform packages using pnpm. ```sh pnpm add alchemy@latest effect@latest @effect/platform-bun@latest @effect/platform-node@latest ``` -------------------------------- ### Sample Profile Output Source: https://v2.alchemy.run/concepts/profiles This is an example of the output from `alchemy profile show`, displaying provider-specific credentials and configuration details. ```text Profile: default ── AWS ── accessKeyId: ASIA**** secretAccessKey: Pj5T**** region: us-west-2 source: sso - default ── Cloudflare ── accessToken: Xl06**** expires: in 59m 58s 999ms accountId: 123456789... source: oauth ``` -------------------------------- ### Interact with Deployed API via cURL Source: https://v2.alchemy.run/guides/effect-http-api Examples of interacting with the deployed API using cURL for POST and GET requests. Demonstrates creating a task and fetching it by ID. ```sh curl -X POST https://your-worker.workers.dev/ \ -H "Content-Type: application/json" \ -d '{"title": "Write docs"}' # → {"id":"...","title":"Write docs","completed":false} ``` ```sh curl https://your-worker.workers.dev/ # → {"id":"...","title":"Write docs","completed":false} ``` -------------------------------- ### Deploy TanStack Start App with Vite Source: https://v2.alchemy.run/guides/frontends Use Cloudflare.Vite for TanStack Start applications. Enable nodejs_compat for frameworks requiring Node APIs at runtime. ```typescript import * as Cloudflare from "alchemy/Cloudflare"; export const App = Cloudflare.Vite("App", { compatibility: { flags: ["nodejs_compat"] }, }); ``` -------------------------------- ### Bun Test Setup with Cloudflare Providers Source: https://v2.alchemy.run/tutorial/part-3 Configures the test environment with Cloudflare providers and state for Worker-based stacks. This setup is typically done once at the top of a test file. ```typescript import * as Test from "alchemy/Test/Bun"; import * as Cloudflare from "alchemy/Cloudflare"; const { test, deploy, destroy, beforeAll, afterAll } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(), }); ``` -------------------------------- ### Install Alchemy and Effect Dependencies with Bun Source: https://v2.alchemy.run/tutorial/part-1 Installs Alchemy, Effect, and related platform packages using Bun. ```sh bun add alchemy@0.2.0 effect@0.3.10 @effect/platform-bun@0.3.10 @effect/platform-node@0.3.10 ``` -------------------------------- ### Plan Output Example Source: https://v2.alchemy.run/concepts/resource-lifecycle Displays the outcome of a plan operation, indicating resources to be created, updated, or no-ops. This helps visualize changes before applying them. ```text [u]Plan[/u]: [g]1 to create[/g], [y]1 to update[/y] [g]+[/g] [b]Queue[/b] [d](AWS.SQS.Queue)[/d] [y]~[/y] [b]Worker[/b] [d](Cloudflare.Worker)[/d] [d]•[/d] [b]Bucket[/b] [d](Cloudflare.R2Bucket)[/d] ``` -------------------------------- ### Adapter API Comparison (Bun vs Vitest) Source: https://v2.alchemy.run/concepts/testing Illustrates the minimal differences in setup when using Bun or Vitest as the test runner. The core testing API remains consistent. ```diff -import * as Test from "alchemy/Test/Bun"; -import { expect } from "bun:test"; +import * as Test from "alchemy/Test/Vitest"; +import { expect } from "@effect/vitest"; const { test, beforeAll, afterAll, deploy, destroy } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(), }); ``` -------------------------------- ### Start Local Development with `alchemy dev` Source: https://v2.alchemy.run/concepts/local-development Initiates the local development server, deploying infrastructure to the cloud and starting your worker in a local runtime. It then watches for file changes to enable hot reloading. ```sh alchemy dev ``` -------------------------------- ### Install Alchemy and Effect Dependencies with Yarn Source: https://v2.alchemy.run/tutorial/part-1 Installs Alchemy, Effect, and related platform packages using Yarn. ```sh yarn add alchemy@0.2.0 effect@0.3.10 @effect/platform-bun@0.3.10 @effect/platform-node@0.3.10 ``` -------------------------------- ### Install Alchemy and Effect Dependencies with npm Source: https://v2.alchemy.run/tutorial/part-1 Installs Alchemy, Effect, and related platform packages using npm. ```sh npm install alchemy@0.2.0 effect@0.3.10 @effect/platform-bun@0.3.10 @effect/platform-node@0.3.10 ``` -------------------------------- ### Set up Isolated Stack for Testing Source: https://v2.alchemy.run/ Define and manage an isolated cloud stack for testing. This example uses `beforeAll` to deploy a stack with real R2 and DynamoDB, and `afterAll` to destroy it. ```typescript // test/api.test.ts — isolated stack per suite. const stack = beforeAll(deploy(Stack)); // real R2, real DynamoDB afterAll(destroy(stack)); // torn down at the end test("PUT + GET round-trips through R2", Effect.gen(function* () { const { url } = yield* stack; const res = yield* HttpClient.get(`${url}/object/hello.txt`); expect(yield* res.text).toBe("hi!"); })); ``` -------------------------------- ### Start Container from Durable Object Source: https://v2.alchemy.run/providers/cloudflare/container In the inner per-instance phase of a Durable Object, use `Cloudflare.start` with the bound container to start it and obtain a typed handle for RPC communication. ```typescript // init (outer Effect) — only imports the class const sandbox = yield* Cloudflare.Container.bind(Sandbox); // per-instance (inner Effect) return Effect.gen(function* () { const container = yield* Cloudflare.start(sandbox); return { exec: (cmd: string) => container.exec(cmd), }; }); ``` -------------------------------- ### Create Vite project with React TS template Source: https://v2.alchemy.run/tutorial/cloudflare/vite-spa Use Bun to create a new Vite project with the React + TypeScript template, then install dependencies. ```bash bun create vite@latest web -- --template react-ts cd web && bun install && cd .. ``` -------------------------------- ### Write an Async Lambda Handler Source: https://v2.alchemy.run/providers/aws/lambda/function This is an example of a standard asynchronous Lambda handler function that can be exported from your entry point file. ```typescript export const handler = async (event: any) => { return { statusCode: 200, body: JSON.stringify({ message: "Hello from Lambda!" }), }; }; ``` -------------------------------- ### Stage-Specific Command Execution Source: https://v2.alchemy.run/guides/cli Examples demonstrating how to target specific stages for commands like `deploy` and `destroy`. Stages isolate stack instances, with a default of `dev_$USER`. ```sh alchemy deploy --stage prod ``` ```sh alchemy deploy --stage pr-42 ``` ```sh alchemy destroy --stage dev_sam ``` -------------------------------- ### Resource Dependency Graph Example Source: https://v2.alchemy.run/concepts/resource Illustrates how Alchemy builds a dependency graph based on resource outputs passed as inputs. This graph determines the topological order of deployment. ```typescript const Bucket = yield* Cloudflare.R2Bucket("Bucket"); const Sessions = yield* Cloudflare.KVNamespace("Sessions"); const Queue = yield* AWS.SQS.Queue("Queue", { name: Output.interpolate`${Bucket.bucketName}-events`, }); const Worker = yield* Cloudflare.Worker("Worker", { main: import.meta.path, bindings: { Bucket, Sessions, Queue }, }); ``` -------------------------------- ### Setup pnpm for CI Source: https://v2.alchemy.run/guides/ci Configures pnpm for use in CI environments, including setting the version and disabling automatic installation. This snippet is part of a larger GitHub Actions workflow setup. ```yaml setup: - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: "10" run_install: false ``` -------------------------------- ### Deploying Resources Source: https://v2.alchemy.run/guides/cli Compute a plan, ask for approval, and create/update/delete resources to match the desired state. Use `--yes` to skip the approval prompt, specify a different stage with `--stage`, or deploy a different stack file. ```sh alchemy deploy [file] [options] ``` ```sh # Deploy to production, skip the prompt alchemy deploy --stage prod --yes ``` ```sh # Deploy a different stack file alchemy deploy stacks/github.ts ``` ```sh # Preview what would change alchemy deploy --dry-run ``` ```sh # Re-import existing cloud resources into a fresh state store alchemy deploy --adopt ``` -------------------------------- ### Create Project with Bun Source: https://v2.alchemy.run/getting-started Use this command to create a new project directory and initialize it with Bun. ```sh mkdir my-app && cd my-app && bun init -y ``` -------------------------------- ### Clone a D1 database from a resource Source: https://v2.alchemy.run/providers/cloudflare/d1database Create a new D1 database by cloning an existing one. This example shows cloning by passing the source D1Database resource directly. ```typescript const source = yield* Cloudflare.D1Database("source-db"); const cloned = yield* Cloudflare.D1Database("cloned-db", { clone: source, }); ``` -------------------------------- ### Create Project with npm Source: https://v2.alchemy.run/getting-started Use this command to create a new project directory and initialize it with npm. ```sh mkdir my-app && cd my-app && npm init -y ``` -------------------------------- ### Verify S3 Integration with Tests Source: https://v2.alchemy.run/tutorial/aws/s3 Example test suite using Alchemy's testing utilities to verify S3 PUT and GET operations. ```typescript import * as Alchemy from "alchemy"; import * as AWS from "alchemy/AWS"; import * as Test from "alchemy/Test/Bun"; import { expect } from "bun:test"; import * as Effect from "effect/Effect"; import * as HttpBody from "effect/unstable/http/HttpBody"; import * as HttpClient from "effect/unstable/http/HttpClient"; import Stack from "../alchemy.run.ts"; const { test, beforeAll, deploy } = Test.make({ providers: AWS.providers(), state: Alchemy.localState(), }); const stack = beforeAll(deploy(Stack)); test( "S3 round-trip", Effect.gen(function* () { const { url } = yield* stack; const put = yield* HttpClient.put(`${url}/hello.txt`, { body: HttpBody.text("world"), }); expect(put.status).toBe(204); const get = yield* HttpClient.get(`${url}/hello.txt`); expect(yield* get.text).toBe("world"); }), ); ``` -------------------------------- ### HTTP Client in Test Effects Source: https://v2.alchemy.run/concepts/testing The `HttpClient` is automatically available within `test` Effects. This example shows a round-trip test using PUT and GET requests. ```typescript import * as HttpClient from "effect/unstable/http/HttpClient"; import * as HttpBody from "effect/unstable/http/HttpBody"; test( "PUT and GET round-trip", Effect.gen(function* () { const { url } = yield* stack; const put = yield* HttpClient.put(`${url}/k`, { body: HttpBody.text("hello"), }); expect(put.status).toBe(201); const get = yield* HttpClient.get(`${url}/k`); expect(yield* get.text).toBe("hello"); }), ); ``` -------------------------------- ### Create Project with pnpm Source: https://v2.alchemy.run/getting-started Use this command to create a new project directory and initialize it with pnpm. ```sh mkdir my-app && cd my-app && pnpm init ``` -------------------------------- ### GitHub Actions Workflow for Deployments Source: https://v2.alchemy.run/tutorial/part-5 Defines the CI/CD workflow for deploying to different stages (production, pull request previews). It handles installation, deployment, and cleanup of preview environments. ```yaml name: Deploy on: push: branches: [main] pull_request: types: [opened, reopened, synchronize, closed] concurrency: group: deploy-${{ github.ref }} cancel-in-progress: false env: STAGE: >- ${{ github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || (github.ref == 'refs/heads/main' && 'prod' || github.ref_name) }} jobs: deploy: if: github.event.action != 'closed' runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - run: bun install - name: Deploy run: bun alchemy deploy --stage ${{ env.STAGE }} env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} PULL_REQUEST: ${{ github.event.number }} GITHUB_SHA: ${{ github.sha }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} cleanup: if: github.event_name == 'pull_request' && github.event.action == 'closed' runs-on: ubuntu-latest permissions: contents: read pull-requests: write steps: - uses: actions/checkout@v4 - uses: oven-sh/setup-bun@v2 - run: bun install - name: Safety Check run: | if [ "${{ env.STAGE }}" = "prod" ]; then echo "ERROR: Cannot destroy prod environment in cleanup job" exit 1 fi - name: Destroy Preview run: bun alchemy destroy --stage ${{ env.STAGE }} env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} PULL_REQUEST: ${{ github.event.number }} ``` -------------------------------- ### Create Project with Yarn Source: https://v2.alchemy.run/getting-started Use this command to create a new project directory and initialize it with Yarn. ```sh mkdir my-app && cd my-app && yarn init -y ``` -------------------------------- ### pnpm CI Workflow Steps Source: https://v2.alchemy.run/guides/ci Specifies the CI workflow steps for pnpm, including setup for pnpm and Node.js, dependency installation, and running Alchemy commands. It ensures pnpm is configured correctly for the CI environment. ```yaml setup: - name: Setup pnpm uses: pnpm/action-setup@v4 with: version: "10" run_install: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "24" cache: "pnpm" install: pnpm install run: pnpm dlx alchemy destroy: pnpm dlx alchemy ``` -------------------------------- ### Create and Bind R2 Bucket Source: https://v2.alchemy.run/tutorial/part-2 Demonstrates how to create an R2 bucket resource and bind it to be used within a Worker. Includes examples for basic creation and with a location hint, as well as reading and writing objects. ```typescript const bucket = yield* Cloudflare.R2Bucket("MyBucket"); ``` ```typescript const bucket = yield* Cloudflare.R2Bucket("MyBucket", { locationHint: "wnam", }); ``` ```typescript const bucket = yield* Cloudflare.R2Bucket.bind(MyBucket); // Write an object yield* bucket.put("hello.txt", "Hello, World!"); // Read an object const object = yield* bucket.get("hello.txt"); if (object) { const text = yield* object.text(); } ``` -------------------------------- ### Calling RPC methods from a Worker Source: https://v2.alchemy.run/providers/cloudflare/durableobjectnamespace Yield the DO class in your Worker's init phase to get a namespace handle. Call `getByName` to get a typed stub, then call RPC methods like `increment` and `get`. ```typescript // init const counters = yield* Counter; return { fetch: Effect.gen(function* () { const counter = counters.getByName("user-123"); yield* counter.increment(); const value = yield* counter.get(); return HttpServerResponse.text(String(value)); }), }; ``` -------------------------------- ### Implement `set` and `get` for Postgres State Store Source: https://v2.alchemy.run/guides/custom-state-store Implements the `get` and `set` methods for a PostgreSQL-backed state store. Uses `encodeState` and `reviveState` for serialization and `StateStoreError` for error handling. Returns `undefined` from `get` for missing rows. ```typescript // src/postgres-state.ts import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import postgres from "postgres"; import { State, StateStoreError, encodeState, reviveState, type StateService, } from "alchemy/State"; // ... const makePostgresState = (props: PostgresStateProps) => Effect.gen(function* () { const sql = yield* Effect.acquireRelease( Effect.sync(() => postgres(props.connectionString)), (sql) => Effect.promise(() => sql.end()), ); // ... create table ... const run = (thunk: () => Promise) => Effect.tryPromise({ try: thunk, catch: (cause) => new StateStoreError({ message: cause instanceof Error ? cause.message : String(cause), cause: cause instanceof Error ? cause : undefined, }), }); const service: StateService = { listStacks: () => Effect.die("not implemented"), listStages: () => Effect.die("not implemented"), list: () => Effect.die("not implemented"), get: ({ stack, stage, fqn }) => run( () => sql<{ value: string }[]> ` select value::text from alchemy_state where stack = ${stack} and stage = ${stage} and fqn = ${fqn} `, ).pipe( Effect.map((rows) => rows.length === 0 ? undefined : JSON.parse(rows[0].value, reviveState), ), ), set: ({ stack, stage, fqn, value }) => run( () => sql` insert into alchemy_state (stack, stage, fqn, value) values (${stack}, ${stage}, ${fqn}, ${sql.json(encodeState(value))}) on conflict (stack, stage, fqn) do update set value = excluded.value `, ).pipe(Effect.as(value)), delete: () => Effect.die("not implemented"), deleteStack: () => Effect.die("not implemented"), getReplacedResources: () => Effect.die("not implemented"), }; return service; }); ``` -------------------------------- ### Basic StaticSite Configuration Source: https://v2.alchemy.run/providers/cloudflare/staticsite Configure the build command and output directory for a static site. Use this when your site has its own build step. ```typescript const site = yield* Cloudflare.StaticSite("Blog", { command: "hugo --minify", outdir: "public", }); ``` -------------------------------- ### Creating an R2 Bucket Source: https://v2.alchemy.run/providers/cloudflare/r2bucket Demonstrates how to create a new R2 bucket, optionally specifying a location hint. ```APIDOC ## Creating a Bucket ### Basic R2 bucket ```typescript const bucket = yield* Cloudflare.R2Bucket("MyBucket"); ``` ### Bucket with location hint ```typescript const bucket = yield* Cloudflare.R2Bucket("MyBucket", { locationHint: "wnam", }); ``` ``` -------------------------------- ### Install Alchemy and Effect Dependencies with pnpm Source: https://v2.alchemy.run/tutorial/part-1 Installs Alchemy, Effect, and related platform packages using pnpm. ```sh pnpm add alchemy@0.2.0 effect@0.3.10 @effect/platform-bun@0.3.10 @effect/platform-node@0.3.10 ``` -------------------------------- ### Deploy Stack with Bun Source: https://v2.alchemy.run/getting-started Execute the Alchemy deployment command using Bun. ```sh bun alchemy deploy ``` -------------------------------- ### Deploying with Adoption Source: https://v2.alchemy.run/guides/cli Use the `--adopt` flag to reconcile against pre-existing cloud resources instead of failing with 'already exists' errors. This is useful when the state store is lost or wiped but the cloud infrastructure remains. Subsequent deploys can drop the flag. ```sh alchemy deploy --adopt ``` -------------------------------- ### Example Kinesis Audit Log Output Source: https://v2.alchemy.run/tutorial/aws/kinesis Example output showing a processed Kinesis record with partition key and content. ```text [k1] {"type":"job.created","id":"k1","content":"audit me","at":1718000000000} ``` -------------------------------- ### Creating a Queue Source: https://v2.alchemy.run/providers/cloudflare/queue Demonstrates how to create a Cloudflare Queue. You can create a basic queue or one with an explicit name. ```APIDOC ## Creating a Queue ### Basic queue ```typescript const queue = yield* Cloudflare.Queue("MyQueue"); ``` ### Queue with explicit name ```typescript const queue = yield* Cloudflare.Queue("MyQueue", { name: "my-app-queue", }); ``` ``` -------------------------------- ### Configure test environment with Test.make Source: https://v2.alchemy.run/tutorial/part-3 Sets up the testing environment by configuring providers and state using `Test.make`. This is done once at the top of the test file. ```typescript import * as Test from "alchemy/Test/Bun"; import * as Cloudflare from "alchemy/Cloudflare"; const { test, deploy, destroy, beforeAll, afterAll } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(), }); ``` -------------------------------- ### Stage Isolation Example Source: https://v2.alchemy.run/concepts/stages Illustrates how deploying to different stages results in distinct physical resource names, preventing interference between environments. This ensures that operations on one stage do not affect others. ```bash $ alchemy deploy --stage dev_sam # -> myapp-dev_sam-photos-a3f1 $ alchemy deploy --stage pr-147 # -> myapp-pr_147-photos-9b2c $ alchemy deploy --stage prod # -> myapp-prod-photos-7d4e $ alchemy destroy --stage pr-147 # only removes pr-147 resources ``` -------------------------------- ### Test HTTP PUT and GET Round-trip Source: https://v2.alchemy.run/tutorial/part-3 Tests a round-trip operation for HTTP PUT and GET requests. Requires `HttpClient` and `HttpBody` modules. ```typescript test( "PUT and GET round-trip an object", Effect.gen(function*() { const { url } = yield* stack; const put = yield* HttpClient.put(`${url}/hello.txt`, { body: HttpBody.text("Hello, World!"), }); expect(put.status).toBe(200); }), ); ``` -------------------------------- ### Install Yarn Globally for CI Source: https://v2.alchemy.run/guides/ci Installs Yarn globally using npm. This is a prerequisite step for using Yarn commands within a CI environment when it's not pre-installed. ```yaml setup: - name: Install yarn run: npm install -g yarn ``` -------------------------------- ### Return 'Hello, world!' Response Source: https://v2.alchemy.run/tutorial/part-2 Creates a simple HTTP response with 'Hello, world!' as the body. ```typescript HttpServerResponse.text("Hello, world!"); }). pipe( ``` -------------------------------- ### CI/CD for Pull Request Previews Source: https://v2.alchemy.run/concepts/stages Provides example CI configurations for deploying a new stage for each pull request and destroying it upon merge or closure. This enables isolated testing of PRs. ```yaml - run: alchemy deploy --stage pr-${{ github.event.number }} --yes # on PR close: - run: alchemy destroy --stage pr-${{ github.event.number }} --yes ``` -------------------------------- ### Test workflow completion Source: https://v2.alchemy.run/tutorial/cloudflare/workflows Write an integration test to verify that a workflow instance starts, progresses, and completes within a specified timeout. This involves POSTing to start the workflow and polling its status. ```typescript import * as Cloudflare from "alchemy/Cloudflare"; import * as Test from "alchemy/Test/Bun"; import { expect } from "bun:test"; import * as Effect from "effect/Effect"; import * as HttpClient from "effect/unstable/http/HttpClient"; import Stack from "../alchemy.run.ts"; const { test, beforeAll, deploy } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(), }); const stack = beforeAll(deploy(Stack)); test( "Notifier workflow completes within 60s", Effect.gen(function* () { const { url } = yield* stack; const roomId = `room-${Date.now()}`; const start = yield* HttpClient.post(`${url}/workflow/start/${roomId}`); const { instanceId } = (yield* start.json) as { instanceId: string }; expect(instanceId).toBeString(); let status: { status: string } | undefined; const deadline = Date.now() + 60_000; while (Date.now() < deadline) { const res = yield* HttpClient.get(`${url}/workflow/status/${instanceId}`); status = (yield* res.json) as { status: string }; if (status.status === "complete" || status.status === "errored") break; yield* Effect.sleep("2 seconds"); } expect(status?.status).toBe("complete"); }), { timeout: 120_000 }, ); ``` -------------------------------- ### Add Increment and Get Methods to Durable Object Source: https://v2.alchemy.run/tutorial/cloudflare/durable-objects Define RPC methods for a Durable Object to mutate and read its state. 'increment' updates the count in storage, and 'get' returns the current count. ```typescript return Effect.gen(function* () { const state = yield* Cloudflare.DurableObjectState; let count = (yield* state.storage.get("count")) ?? 0; return {}; return { increment: () => Effect.gen(function* () { count += 1; yield* state.storage.put("count", count); return count; }), get: () => Effect.succeed(count), }; }); ``` -------------------------------- ### Deploy and Send Prompt to AI Gateway Source: https://v2.alchemy.run/tutorial/cloudflare/ai-gateway Deploy the AI Gateway and send a prompt using curl. The second identical prompt demonstrates caching. ```bash bun alchemy deploy curl -X POST "$(bun alchemy stack output url)/ai" \ -H "content-type: application/json" \ -d '{"prompt":"Write a haiku about Effect"}' ``` -------------------------------- ### Forwarding an HTTP request from a Worker Source: https://v2.alchemy.run/providers/cloudflare/durableobjectnamespace Yield the DO class in your Worker's init phase to get a namespace handle. Call `getByName` to get a typed stub, then forward an HTTP request using `fetch`. ```typescript // init const rooms = yield* Room; return { fetch: Effect.gen(function* () { const request = yield* HttpServerRequest; const room = rooms.getByName(roomId); return yield* room.fetch(request); }), }; ``` -------------------------------- ### Deploying to Specific Stages Source: https://v2.alchemy.run/concepts/stages Shows commands for deploying and destroying resources in different stages, including production and pull request previews. Stage names must adhere to the `[a-z0-9][-_a-z0-9]*` pattern. ```bash alchemy deploy --stage prod alchemy deploy --stage pr-42 alchemy destroy --stage pr-42 ``` -------------------------------- ### Get Fetch Handle for Container Port Source: https://v2.alchemy.run/providers/cloudflare/container Use `getTcpPort` to get a `fetch` handle for a specific port on the running container. This allows making HTTP requests to servers running inside the container process. ```javascript const container = yield* Cloudflare.start(sandbox); const { fetch } = yield* container.getTcpPort(3000); const response = yield* fetch( HttpClientRequest.get("http://container/health"), ); ``` -------------------------------- ### Testing HTTP GET Request for Missing Key Source: https://v2.alchemy.run/tutorial/part-3 This test case verifies that a GET request for a non-existent key returns a 404 status code. It uses `Effect.gen` to handle the asynchronous HTTP request and `expect` for assertions. ```typescript import Effect from "effect"; import HttpClient from "HttpClient"; const get: (url: string | URL, options?: Options.NoUrl | undefined) => Effect.Effect = HttpClient.get; const url = `/no-such-key`; const response = yield* get(url); expect(response.status).toBe(404); ``` -------------------------------- ### Control DynamoDB Stream Consumption Start Position Source: https://v2.alchemy.run/tutorial/aws/dynamodb-streams Sets the starting position for consuming DynamoDB stream records. `TRIM_HORIZON` replays all records within the stream's retention window, while `LATEST` (the default) only processes new records. `batchSize` controls the number of records processed per invocation. ```typescript yield* DynamoDB.stream(table, { streamViewType: "NEW_AND_OLD_IMAGES", startingPosition: "TRIM_HORIZON", batchSize: 10, }).process((stream) => stream.pipe(/* ... */), ); ``` -------------------------------- ### Configure Container with Stack Context Source: https://v2.alchemy.run/providers/cloudflare/container Configure container properties like `main` entrypoint, `instanceType`, and `observability` using `Stack.useSync` to adapt settings based on the deployment stage. ```typescript export class Sandbox extends Cloudflare.Container()( "Sandbox", Stack.useSync((stack) => ({ main: import.meta.filename, instanceType: stack.stage === "prod" ? "standard-1" : "dev", observability: { logs: { enabled: true } }, })), ) {} ``` -------------------------------- ### Deploy Stack with npm Source: https://v2.alchemy.run/getting-started Execute the Alchemy deployment command using npm. ```sh npx alchemy deploy ``` -------------------------------- ### DynamoDB Round-Trip Test Source: https://v2.alchemy.run/tutorial/aws/dynamodb Perform a round-trip test to verify PUT and GET operations for DynamoDB items. ```typescript test( "DynamoDB round-trip", Effect.gen(function* () { const { url } = yield* stack; yield* HttpClient.put(`${url}/items/abc`, { body: HttpBody.text("hello dynamo"), }); const get = yield* HttpClient.get(`${url}/items/abc`); expect(yield* get.json).toEqual({ id: "abc", content: "hello dynamo" }); }), ); ``` -------------------------------- ### Create an ECS Cluster Source: https://v2.alchemy.run/providers/aws/ecs/cluster Defines a new ECS cluster named 'AppCluster'. This is a basic setup for a cluster. ```typescript const cluster = yield* Cluster("AppCluster", {}); ``` -------------------------------- ### Vite configuration with incompatible Cloudflare plugin Source: https://v2.alchemy.run/tutorial/cloudflare/vite-spa Example of a vite.config.ts that includes the @cloudflare/vite-plugin, which is incompatible with Alchemy's integration. ```typescript import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import cloudflare from "@cloudflare/vite-plugin"; export default defineConfig({ plugins: [react(), cloudflare()], plugins: [react()], }); ``` -------------------------------- ### Initialize test API with Cloudflare providers Source: https://v2.alchemy.run/tutorial/part-3 Sets up the test API using `Test.make`, configuring it with Cloudflare providers and state management. This is typically done once at the top of a test file. ```typescript const { test, deploy, destroy, beforeAll, afterAll } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(), }); ``` -------------------------------- ### Get an Object from R2 Bucket Source: https://v2.alchemy.run/tutorial/part-2 Retrieves an object from an R2 bucket using its key. Returns null if the object is not found. ```typescript const object: Cloudflare.R2ObjectBody | null object = yield* bucket.get( key); ``` -------------------------------- ### Login and Configure Profile Source: https://v2.alchemy.run/concepts/profiles Use `alchemy login` to refresh credentials for the current profile or re-run the interactive setup to configure a new or existing profile. This command imports the stack file to determine necessary providers. ```sh # Refresh credentials for the current profile alchemy login # Re-run the interactive setup (e.g. switch from OAuth → API token) alchemy login --configure # Log into a separate profile alchemy login --profile prod --configure ``` -------------------------------- ### Create R2 Bucket with Location Hint Source: https://v2.alchemy.run/providers/cloudflare/r2bucket Creates an R2 bucket resource with a specified location hint. Use location hints to influence where your data is stored. ```typescript const bucket = yield* Cloudflare.R2Bucket("MyBucket", { locationHint: "wnam", }); ``` -------------------------------- ### Fetch Transaction Amount Effect Source: https://v2.alchemy.run/tutorial/part-3 An Effect that simulates fetching a transaction amount. Use this when you need to get the base amount for calculations. ```typescript const fetchTransactionAmount = Effect.promise(() => Promise.resolve(100)) ``` -------------------------------- ### Conditional Resource Configuration by Stage Source: https://v2.alchemy.run/concepts/stages Demonstrates how to conditionally configure resources based on the current stage using the Stack service. This allows for different settings (e.g., removal policy) for production versus other environments. ```typescript import { Stack } from "alchemy/Stack"; Effect.gen(function* () { const stack = yield* Stack; const queue = yield* SQS.Queue("Jobs").pipe( RemovalPolicy.retain(stack.stage === "prod"), ); }); ``` -------------------------------- ### Implement getReplacedResources with Postgres Source: https://v2.alchemy.run/guides/custom-state-store Implement `getReplacedResources` to efficiently query for replaced resources in Postgres. This avoids the overhead of `list` + `get` operations. ```typescript const service: StateService = { // ... - getReplacedResources: () => Effect.die("not implemented"), + getReplacedResources: ({ stack, stage }) => run( () => sql<{ value: string }[]>` select value::text from alchemy_state where stack = ${stack} and stage = ${stage} and value->>'status' = 'replaced' `, ).pipe( Effect.map((rows) => rows.map((r) => JSON.parse(r.value, reviveState)), ), ) } ``` -------------------------------- ### Import and Bind Bucket in Init Phase Source: https://v2.alchemy.run/tutorial/part-2 Import the `Bucket` and bind it in the Init phase of your worker. Ensure necessary imports from Alchemy and Effect. ```typescript import * as Cloudflare from "alchemy/Cloudflare"; import * as Effect from "effect/Effect"; import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse"; const Bucket: Effect.Effect = (await import("./bucket.ts")).Bucket; export default Cloudflare.Worker( "Worker", { main: import.meta.path, }, impl: Effect.gen(function*() { const bucket = yield* Bucket; return { bucketName: Alchemy.Output, }; }), ); ``` -------------------------------- ### Durable Object Two-Phase Pattern Source: https://v2.alchemy.run/providers/cloudflare/durableobjectnamespace Illustrates the two-phase pattern for Durable Objects, involving shared dependency resolution and per-instance setup. ```typescript Effect.gen(function* () { // Phase 1: resolve shared dependencies const db = yield* Cloudflare.D1Connection.bind(MyDB); return Effect.gen(function* () { // Phase 2: per-instance setup and public API const state = yield* Cloudflare.DurableObjectState; return { save: (data: string) => db.exec("INSERT ..."), fetch: Effect.gen(function* () { ... }), webSocketMessage: Effect.fnUntraced(function* (ws, msg) { ... }), }; }); }) ``` -------------------------------- ### Import necessary modules for testing Source: https://v2.alchemy.run/tutorial/part-3 Imports `Cloudflare` for bindings, `Test` utilities for Bun with Effect support, `Expect` for assertions, `Effect` for asynchronous operations, and `Stack` for the application definition. ```typescript import Cloudflare from "alchemy/Cloudflare"; import Test from "alchemy/Test/Bun"; import { expect } from "bun:test"; import Effect from "effect/Effect"; import Stack from "../alchemy.run.ts"; const { test, beforeAll, afterAll, deploy, destroy } = Test.make({ providers: Cloudflare.providers(), state: Cloudflare.state(), }); ``` -------------------------------- ### In-memory state store for testing Source: https://v2.alchemy.run/concepts/state-store Use this for tests to avoid filesystem access. The test harness automatically handles state setup. ```typescript import * as TestState from "alchemy/Test/TestState"; // Seed with existing resource state const state = TestState.state({ Bucket: { /* ... */ }, }); ``` -------------------------------- ### Stage and Profile Pairing Source: https://v2.alchemy.run/concepts/stages Illustrates how to combine stage isolation with cloud provider authentication profiles using CLI flags. This allows for different credentials to be used for different deployment environments. ```bash alchemy deploy --stage prod --profile prod alchemy deploy --stage pr-42 --profile default ``` -------------------------------- ### Binding R2 Bucket to a Worker Source: https://v2.alchemy.run/providers/cloudflare/r2bucket Shows how to bind an R2 bucket to a Worker and perform basic object operations like put and get. ```APIDOC ## Binding to a Worker ### Reading and writing objects ```typescript const bucket = yield* Cloudflare.R2Bucket.bind(MyBucket); // Write an object yield* bucket.put("hello.txt", "Hello, World!"); // Read an object const object = yield* bucket.get("hello.txt"); if (object) { const text = yield* object.text(); } ``` ``` -------------------------------- ### Deploy Stack with pnpm Source: https://v2.alchemy.run/getting-started Execute the Alchemy deployment command using pnpm. ```sh pnpm alchemy deploy ```