1import * as Config from "effect/Config";
2import * as Effect from "effect/Effect";
3
4declare global {
5 /**
6 * Build-time flag marking the runtime (post-bundle) phase.
7 *
8 * The bundler folds this to `true` in every runtime artifact (see
9 * `ALCHEMY_DEFINE` in `Bundle/Bundle.ts`), so plan-only code guarded by
10 * `if (!globalThis.__ALCHEMY_RUNTIME__)` is dead-code-eliminated from deployed
11 * Workers/Lambdas/Containers.
12 *
13 * When running source directly with bun/node (no bundler) it is `undefined`
14 * (falsy), so plan-only branches run. Reading it never throws because it is a
15 * property access on `globalThis`.
16 */
17 var __ALCHEMY_RUNTIME__: boolean | undefined;
18}
19
20export type AlchemyPhase = "plan" | "runtime";
21
22export const ALCHEMY_PHASE = Config.String("ALCHEMY_PHASE").pipe(
23 Config.withDefault("plan"),
24 Config.mapEffect((value) => {
25 if (value !== "plan" && value !== "runtime") {
26 return Effect.die(new Error(`Invalid ALCHEMY_PHASE: ${value}`));
27 }
28 return Effect.succeed(value as AlchemyPhase);
29 }),
30 Effect.orDie,
31);
32
33/**
34 * Whether the program is running under `alchemy dev` (local development with
35 * hot reload), exposed as the `ALCHEMY_DEV` environment variable / config key.
36 *
37 * The `alchemy dev` CLI command sets `ALCHEMY_DEV=true` on the spawned process;
38 * every other entrypoint (`deploy`, `plan`, deployed runtime) leaves it unset,
39 * so it defaults to `false`. Accepts the usual truthy strings (`true`, `1`,
40 * `yes`, `on`).
41 *
42 * Read it from user code to branch on dev mode:
43 *
44 * ```typescript
45 * import { ALCHEMY_DEV } from "alchemy";
46 *
47 * Effect.gen(function* () {
48 * if (yield* ALCHEMY_DEV) {
49 * // local-dev-only behavior
50 * }
51 * });
52 * ```
53 */
54export const ALCHEMY_DEV = Config.Boolean("ALCHEMY_DEV").pipe(
55 Config.withDefault(false),
56);