1import type * as cf from "@cloudflare/workers-types";
2import * as Effect from "effect/Effect";
3import * as Layer from "effect/Layer";
4import type { RuntimeContext } from "../../RuntimeContext.ts";
5import { Worker, WorkerEnvironment } from "../Workers/Worker.ts";
6import type { App } from "./App.ts";
7import { FlagshipError, ReadFlags, type ReadFlagsClient } from "./ReadFlags.ts";
8
9export const ReadFlagsBinding = Layer.effect(
10 ReadFlags,
11 Effect.gen(function* () {
12 const env = yield* WorkerEnvironment;
13 const host = yield* Worker;
14
15 return Effect.fn(function* (app: App) {
16 if (!globalThis.__ALCHEMY_RUNTIME__) {
17 yield* host.bind(app.LogicalId, {
18 bindings: [
19 {
20 type: "flagship",
21 name: app.LogicalId,
22 appId: app.appId,
23 },
24 ],
25 });
26 }
27 const raw: Effect.Effect<cf.Flagship, never, RuntimeContext> =
28 Effect.sync(() => (env as Record<string, cf.Flagship>)[app.LogicalId]!);
29 return makeFlagshipClient(raw);
30 });
31 }),
32);
33
34/** An Effect produced by a {@link ReadFlagsClient} operation. */
35type FlagshipEffect<A> = Effect.Effect<A, FlagshipError, RuntimeContext>;
36
37const tryPromise = <T>(fn: () => Promise<T>): Effect.Effect<T, FlagshipError> =>
38 Effect.tryPromise({
39 try: fn,
40 catch: (error) =>
41 new FlagshipError({
42 message:
43 error instanceof Error ? error.message : "Unknown Flagship error",
44 cause: error,
45 }),
46 });
47
48/** @internal */
49export const makeFlagshipClient = (
50 raw: Effect.Effect<cf.Flagship, never, RuntimeContext>,
51): ReadFlagsClient => {
52 const call = <T>(
53 fn: (binding: cf.Flagship) => Promise<T>,
54 ): FlagshipEffect<T> =>
55 raw.pipe(Effect.flatMap((binding) => tryPromise(() => fn(binding))));
56
57 return {
58 raw,
59 get: (flagKey, defaultValue, context) =>
60 call((b) => b.get(flagKey, defaultValue, context)),
61 getBooleanValue: (flagKey, defaultValue, context) =>
62 call((b) => b.getBooleanValue(flagKey, defaultValue, context)),
63 getStringValue: (flagKey, defaultValue, context) =>
64 call((b) => b.getStringValue(flagKey, defaultValue, context)),
65 getNumberValue: (flagKey, defaultValue, context) =>
66 call((b) => b.getNumberValue(flagKey, defaultValue, context)),
67 getObjectValue: (flagKey, defaultValue, context) =>
68 call((b) => b.getObjectValue(flagKey, defaultValue, context)),
69 getBooleanDetails: (flagKey, defaultValue, context) =>
70 call((b) => b.getBooleanDetails(flagKey, defaultValue, context)),
71 getStringDetails: (flagKey, defaultValue, context) =>
72 call((b) => b.getStringDetails(flagKey, defaultValue, context)),
73 getNumberDetails: (flagKey, defaultValue, context) =>
74 call((b) => b.getNumberDetails(flagKey, defaultValue, context)),
75 getObjectDetails: (flagKey, defaultValue, context) =>
76 call((b) => b.getObjectDetails(flagKey, defaultValue, context)),
77 } satisfies ReadFlagsClient;
78};