{"version":3,"file":"bindings.mjs","names":[],"sources":["../../src/db/bindings.ts"],"sourcesContent":["import { resolve } from \"node:path\";\nimport { Context, Data, Effect, Layer } from \"effect\";\nimport type { RuntimeConfig } from \"../types\";\nimport { getDatabaseUrlSecretName, getMigrationStorage, pluginMigrationSlug } from \"./core\";\nimport { type WorkspaceIdentity, workspaceIdentityFromWorkspaceDir } from \"./identity\";\n\nexport interface DatabaseBinding {\n  readonly key: string;\n  readonly source: \"local\" | \"remote\";\n  readonly section: \"app.api\" | \"app.auth\" | \"plugins\";\n  readonly identity: WorkspaceIdentity;\n  readonly url: string;\n}\n\nexport class DatabaseBindingError extends Data.TaggedError(\"DatabaseBindingError\")<{\n  readonly pluginKey: string;\n  readonly message: string;\n}> {}\n\nexport interface DatabaseBindingsService {\n  readonly forPluginKey: (\n    pluginKey: string,\n  ) => Effect.Effect<DatabaseBinding, DatabaseBindingError>;\n}\n\nexport class DatabaseBindings extends Context.Service<DatabaseBindings, DatabaseBindingsService>()(\n  \"everything-dev/DatabaseBindings\",\n) {}\n\ninterface RuntimePluginEntry {\n  readonly source?: string;\n  readonly secrets?: string[];\n  readonly localPath?: string;\n}\n\nfunction resolvePluginBinding(\n  pluginKey: string,\n  runtimeConfig: RuntimeConfig | null,\n  projectDir: string,\n  env: Record<string, string | undefined>,\n): DatabaseBinding {\n  if (!runtimeConfig) {\n    throw new Error(\"Runtime config not loaded — cannot resolve plugin database binding\");\n  }\n\n  let source: \"local\" | \"remote\" | undefined;\n  let section: DatabaseBinding[\"section\"];\n  let secrets: string[] | undefined;\n  let localPath: string | undefined;\n  let key: string;\n\n  if (pluginKey === \"api\" && runtimeConfig.api) {\n    source = runtimeConfig.api.source as \"local\" | \"remote\";\n    section = \"app.api\";\n    secrets = runtimeConfig.api.secrets;\n    localPath = runtimeConfig.api.localPath;\n    key = \"api\";\n  } else if (pluginKey === \"auth\" && runtimeConfig.auth) {\n    source = runtimeConfig.auth.source as \"local\" | \"remote\";\n    section = \"app.auth\";\n    secrets = runtimeConfig.auth.secrets;\n    localPath = runtimeConfig.auth.localPath;\n    key = \"auth\";\n  } else if (runtimeConfig.plugins?.[pluginKey]) {\n    const plugin = runtimeConfig.plugins[pluginKey] as RuntimePluginEntry;\n    source = plugin.source as \"local\" | \"remote\";\n    section = \"plugins\";\n    secrets = plugin.secrets;\n    localPath = plugin.localPath;\n    key = pluginKey;\n  } else {\n    const available = [\n      \"api\",\n      ...(runtimeConfig.auth ? [\"auth\"] : []),\n      ...Object.keys(runtimeConfig.plugins ?? {}),\n    ].join(\", \");\n    throw new Error(\n      `Plugin \"${pluginKey}\" not found in app.api, app.auth, or plugins. Available: ${available}`,\n    );\n  }\n\n  const identity: WorkspaceIdentity = localPath\n    ? workspaceIdentityFromWorkspaceDir(resolve(projectDir, localPath))\n    : {\n        slug: pluginMigrationSlug(key),\n        secretName: getDatabaseUrlSecretName(pluginMigrationSlug(key)),\n        journal: getMigrationStorage(pluginMigrationSlug(key)),\n        workspaceDir: undefined,\n      };\n\n  const url = env[identity.secretName];\n  if (!url) {\n    const declaredDatabaseSecrets = (secrets ?? []).filter((s) => s.endsWith(\"_DATABASE_URL\"));\n    const mismatch =\n      declaredDatabaseSecrets.length > 0 && !declaredDatabaseSecrets.includes(identity.secretName)\n        ? ` Config declares ${declaredDatabaseSecrets.join(\", \")} — the workspace package name and the declared secret disagree.`\n        : \"\";\n    throw new Error(\n      `.env missing ${identity.secretName} for plugin \"${key}\".` +\n        mismatch +\n        ` Add it to your .env file (see .env.example).`,\n    );\n  }\n\n  return {\n    key,\n    source: source ?? \"remote\",\n    section,\n    identity,\n    url,\n  };\n}\n\nexport interface DatabaseBindingsOptions {\n  readonly projectDir: string;\n  readonly loadRuntimeConfig: () => Promise<RuntimeConfig | null>;\n  /** May return a promise — a rejection propagates into the binding error instead of silently proceeding with an unloaded .env. */\n  readonly loadEnv?: () => void | Promise<void>;\n  readonly env?: Record<string, string | undefined>;\n}\n\nexport const makeDatabaseBindings = (\n  options: DatabaseBindingsOptions,\n): Layer.Layer<DatabaseBindings> =>\n  Layer.succeed(DatabaseBindings, {\n    forPluginKey: (pluginKey) =>\n      Effect.tryPromise({\n        try: async () => {\n          await options.loadEnv?.();\n          const runtimeConfig = await options.loadRuntimeConfig();\n          return resolvePluginBinding(\n            pluginKey,\n            runtimeConfig,\n            options.projectDir,\n            options.env ?? process.env,\n          );\n        },\n        catch: (error) =>\n          new DatabaseBindingError({\n            pluginKey,\n            message: error instanceof Error ? error.message : String(error),\n          }),\n      }),\n  });\n"],"mappings":";;;;;;AAcA,IAAa,uBAAb,cAA0C,KAAK,YAAY,sBAAsB,CAAC,CAG/E,CAAC;AAQJ,IAAa,mBAAb,cAAsC,QAAQ,QAAmD,CAAC,CAChG,iCACF,CAAC,CAAC,CAAC;AAQH,SAAS,qBACP,WACA,eACA,YACA,KACiB;CACjB,IAAI,CAAC,eACH,MAAM,IAAI,MAAM,oEAAoE;CAGtF,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CAEJ,IAAI,cAAc,SAAS,cAAc,KAAK;EAC5C,SAAS,cAAc,IAAI;EAC3B,UAAU;EACV,UAAU,cAAc,IAAI;EAC5B,YAAY,cAAc,IAAI;EAC9B,MAAM;CACR,OAAO,IAAI,cAAc,UAAU,cAAc,MAAM;EACrD,SAAS,cAAc,KAAK;EAC5B,UAAU;EACV,UAAU,cAAc,KAAK;EAC7B,YAAY,cAAc,KAAK;EAC/B,MAAM;CACR,OAAO,IAAI,cAAc,UAAU,YAAY;EAC7C,MAAM,SAAS,cAAc,QAAQ;EACrC,SAAS,OAAO;EAChB,UAAU;EACV,UAAU,OAAO;EACjB,YAAY,OAAO;EACnB,MAAM;CACR,OAAO;EACL,MAAM,YAAY;GAChB;GACA,GAAI,cAAc,OAAO,CAAC,MAAM,IAAI,CAAC;GACrC,GAAG,OAAO,KAAK,cAAc,WAAW,CAAC,CAAC;EAC5C,CAAC,CAAC,KAAK,IAAI;EACX,MAAM,IAAI,MACR,WAAW,UAAU,2DAA2D,WAClF;CACF;CAEA,MAAM,WAA8B,YAChC,kCAAkC,QAAQ,YAAY,SAAS,CAAC,IAChE;EACE,MAAM,oBAAoB,GAAG;EAC7B,YAAY,yBAAyB,oBAAoB,GAAG,CAAC;EAC7D,SAAS,oBAAoB,oBAAoB,GAAG,CAAC;EACrD,cAAc;CAChB;CAEJ,MAAM,MAAM,IAAI,SAAS;CACzB,IAAI,CAAC,KAAK;EACR,MAAM,2BAA2B,WAAW,CAAC,EAAC,CAAE,QAAQ,MAAM,EAAE,SAAS,eAAe,CAAC;EACzF,MAAM,WACJ,wBAAwB,SAAS,KAAK,CAAC,wBAAwB,SAAS,SAAS,UAAU,IACvF,oBAAoB,wBAAwB,KAAK,IAAI,EAAE,mEACvD;EACN,MAAM,IAAI,MACR,gBAAgB,SAAS,WAAW,eAAe,IAAI,MACrD,WACA,+CACJ;CACF;CAEA,OAAO;EACL;EACA,QAAQ,UAAU;EAClB;EACA;EACA;CACF;AACF;AAUA,MAAa,wBACX,YAEA,MAAM,QAAQ,kBAAkB,EAC9B,eAAe,cACb,OAAO,WAAW;CAChB,KAAK,YAAY;EACf,MAAM,QAAQ,UAAU;EAExB,OAAO,qBACL,WACA,MAH0B,QAAQ,kBAAkB,GAIpD,QAAQ,YACR,QAAQ,OAAO,QAAQ,GACzB;CACF;CACA,QAAQ,UACN,IAAI,qBAAqB;EACvB;EACA,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;CAChE,CAAC;AACL,CAAC,EACL,CAAC"}