77 lines · 2.9 KB · TypeScript
RawDownload
import { env } from "cloudflare:workers";import { Effect, Layer } from "effect";import { type FumaDB } from "@executor-js/fumadb";import { type DrizzleConfig } from "@executor-js/fumadb/adapters/drizzle";import { type schema as fumaSchema, type RelationsMap } from "@executor-js/fumadb/schema"; import {  createExecutorFumaDb,  DbProvider,  type ExecutorDbHandle,  type ExecutorDbProvider,} from "@executor-js/api/server";import { makeR2BlobStore } from "@executor-js/cloudflare/blob-store";import type { FumaDb, FumaTables } from "@executor-js/sdk"; import { DbService } from "./db"; type DrizzleFumaSchema<TTables extends FumaTables> = ReturnType<  typeof fumaSchema<string, TTables, RelationsMap<TTables>>>; export interface DrizzleFumaDb<TTables extends FumaTables = FumaTables> {  readonly db: FumaDb<DrizzleFumaSchema<TTables>>;  readonly fuma: FumaDB<DrizzleFumaSchema<TTables>[]>;} export interface CreateDrizzleFumaDbOptions<TTables extends FumaTables = FumaTables> {  readonly db: DrizzleConfig["db"];  readonly tables: TTables;  readonly namespace: string;  readonly version?: string;  readonly provider: ExecutorDbProvider;} // Cloud opens its own postgres-js drizzle handle (see ./db.ts) and runs// migrations out-of-band, so this is the pure FumaDB assembly over an// already-opened `db`. Delegates to the shared factory; the local wrapper// keeps the cloud-specific default version + option names.export const createDrizzleFumaDb = <const TTables extends FumaTables>(  options: CreateDrizzleFumaDbOptions<TTables>,): DrizzleFumaDb<TTables> =>  createExecutorFumaDb(options.db, {    tables: options.tables,    namespace: options.namespace,    version: options.version ?? "1.0.0",    provider: options.provider,  }); export const CLOUD_NAMESPACE = "executor_cloud"; // Shared DbProvider seam (P2a). Cloud opens a fresh postgres-js connection per// request (Cloudflare forbids sharing I/O across handlers); this assembles the// FumaDB handle over the request-scoped `DbService.db`. Migrations run// out-of-band, so there is no schema bring-up here, and `close` is a no-op —// `DbService.Live` owns the postgres connection lifecycle.export const cloudDbProviderLayer = (  tables: FumaTables,): Layer.Layer<DbProvider, never, DbService> =>  Layer.effect(DbProvider)(    Effect.map(DbService.asEffect(), ({ db }): ExecutorDbHandle => {      const fuma = createDrizzleFumaDb({        db,        tables,        namespace: CLOUD_NAMESPACE,        provider: "postgresql",      });      return {        db: fuma.db,        fuma: fuma.fuma,        close: async () => {},        // Plugin blobs (multi-MB resolved specs) live in R2, not Postgres.        // Guarded because test workers / local dev may run without the        // binding — the executor then falls back to the FumaDB `blob` table.        blobs: env.BLOBS ? makeR2BlobStore(env.BLOBS) : undefined,      };    }),  );