@coreframe/db 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ function e(){var e=typeof SuppressedError==`function`?SuppressedError:function(e,t){var n=Error();return n.name=`SuppressedError`,n.error=e,n.suppressed=t,n},t={},n=[];function r(e,t){if(t!=null){if(Object(t)!==t)throw TypeError(`using declarations can only be used with objects, functions, null, or undefined.`);if(e)var r=t[Symbol.asyncDispose||Symbol.for(`Symbol.asyncDispose`)];if(r===void 0&&(r=t[Symbol.dispose||Symbol.for(`Symbol.dispose`)],e))var i=r;if(typeof r!=`function`)throw TypeError(`Object is not disposable.`);i&&(r=function(){try{i.call(t)}catch(e){return Promise.reject(e)}}),n.push({v:t,d:r,a:e})}else e&&n.push({d:t,a:e});return t}return{e:t,u:r.bind(null,!1),a:r.bind(null,!0),d:function(){var r,i=this.e,a=0;function o(){for(;r=n.pop();)try{if(!r.a&&a===1)return a=0,n.push(r),Promise.resolve().then(o);if(r.d){var e=r.d.call(r.v);if(r.a)return a|=2,Promise.resolve(e).then(o,s)}else a|=1}catch(e){return s(e)}if(a===1)return i===t?Promise.resolve():Promise.reject(i);if(i!==t)throw i}function s(n){return i=i===t?n:new e(n,i),o()}return o()}}}export{e as default};
@@ -0,0 +1,8 @@
1
+ //#region src/apply-seed.d.ts
2
+ type SeedQuery = object;
3
+ type SeedDatabase = {
4
+ transaction<T>(transaction: (tx: any) => Promise<T>): Promise<T>;
5
+ };
6
+ declare function applySeed(db: SeedDatabase, seed: readonly SeedQuery[]): Promise<void>;
7
+ //#endregion
8
+ export { SeedDatabase, SeedQuery, applySeed };
@@ -0,0 +1 @@
1
+ async function e(e,t){t.length!==0&&await e.transaction(async e=>{let n=e;for(let e of t)await n.execute(e.getSQL())})}export{e as applySeed};
@@ -0,0 +1,4 @@
1
+ //#region src/check-migrations.d.ts
2
+ declare function checkDeployMigrations(): Promise<void>;
3
+ //#endregion
4
+ export { checkDeployMigrations };
@@ -0,0 +1 @@
1
+ import{collectDeployMigrationFiles as e,formatMigrationList as t,formatMigrationScanFailures as n,scanDeployMigrationFiles as r}from"./migrations.js";async function i(){let i=await e();console.log(`Deploy migration files:`),console.log(t(i));let a=await r(i);if(a.length>0)throw Error(`Deploy migrations contain unsafe SQL. Move unsafe statements to held migrations.\n${n(a)}`);console.log(`Deploy migrations passed safety checks.`)}export{i as checkDeployMigrations};
@@ -0,0 +1,30 @@
1
+ import { SQL } from "drizzle-orm";
2
+
3
+ //#region src/client.d.ts
4
+ type DatabaseDialect = "postgres" | "sqlite";
5
+ type QueryResult<Row extends Record<string, unknown> = Record<string, unknown>> = {
6
+ rowCount?: number | null;
7
+ rows: Row[];
8
+ };
9
+ type DatabaseClient = {
10
+ dialect: DatabaseDialect;
11
+ execute<Row extends Record<string, unknown> = Record<string, unknown>>(statement: string): Promise<QueryResult<Row>>;
12
+ transaction?<Result>(run: (database: DatabaseClient) => Promise<Result>): Promise<Result>;
13
+ close?(): Promise<void>;
14
+ };
15
+ type DrizzleExecutor = {
16
+ execute<Result = unknown>(query: SQL): Result | Promise<Result>;
17
+ };
18
+ type CreateDatabaseAdapterOptions = {
19
+ close?(): Promise<void>;
20
+ database: DrizzleExecutor;
21
+ dialect: DatabaseDialect;
22
+ };
23
+ declare function createDatabaseAdapter({
24
+ close,
25
+ database,
26
+ dialect
27
+ }: CreateDatabaseAdapterOptions): DatabaseClient;
28
+ declare function normalizeQueryResult<Row extends Record<string, unknown> = Record<string, unknown>>(result: unknown): QueryResult<Row>;
29
+ //#endregion
30
+ export { CreateDatabaseAdapterOptions, DatabaseClient, DatabaseDialect, DrizzleExecutor, QueryResult, createDatabaseAdapter, normalizeQueryResult };
package/dist/client.js ADDED
@@ -0,0 +1 @@
1
+ import{sql as e}from"drizzle-orm";function t({close:t,database:r,dialect:i}){return{dialect:i,async execute(t){return n(await r.execute(e.raw(t)))},close:t}}function n(e){return Array.isArray(e)?{rows:e}:r(e)?{rowCount:typeof e.rowCount==`number`?e.rowCount:null,rows:e.rows}:{rows:[]}}function r(e){return typeof e==`object`&&!!e&&`rows`in e&&Array.isArray(e.rows)}export{t as createDatabaseAdapter,n as normalizeQueryResult};
@@ -0,0 +1,24 @@
1
+ //#region src/config.d.ts
2
+ declare const MIGRATIONS_FOLDER = "drizzle";
3
+ declare const HELD_MIGRATIONS_FOLDER = "drizzle-hold";
4
+ declare const NOW: Date;
5
+ declare const SEED_IDS: {
6
+ readonly adminUser: "00000000-0000-4000-8000-000000000001";
7
+ readonly adminCredentialAccount: "00000000-0000-4000-8000-000000000101";
8
+ readonly viewerUser: "00000000-0000-4000-8000-000000000002";
9
+ readonly inactiveUser: "00000000-0000-4000-8000-000000000003";
10
+ readonly unicodeUser: "00000000-0000-4000-8000-000000000004";
11
+ readonly longNameUser: "00000000-0000-4000-8000-000000000005";
12
+ };
13
+ declare const SEED_EMAILS: {
14
+ readonly adminUser: "admin@example.com";
15
+ readonly viewerUser: "viewer@example.com";
16
+ readonly inactiveUser: "inactive@example.com";
17
+ readonly unicodeUser: "unicode@example.com";
18
+ readonly longNameUser: "long-name@example.com";
19
+ };
20
+ type SeedProfile = "default" | "large";
21
+ declare function getSeedProfile(argv?: string[]): SeedProfile;
22
+ declare function generatedUserId(index: number): string;
23
+ //#endregion
24
+ export { HELD_MIGRATIONS_FOLDER, MIGRATIONS_FOLDER, NOW, SEED_EMAILS, SEED_IDS, SeedProfile, generatedUserId, getSeedProfile };
package/dist/config.js ADDED
@@ -0,0 +1 @@
1
+ const e=`drizzle`,t=`drizzle-hold`,n=new Date(`2026-01-15T12:00:00.000Z`),r={adminUser:`00000000-0000-4000-8000-000000000001`,adminCredentialAccount:`00000000-0000-4000-8000-000000000101`,viewerUser:`00000000-0000-4000-8000-000000000002`,inactiveUser:`00000000-0000-4000-8000-000000000003`,unicodeUser:`00000000-0000-4000-8000-000000000004`,longNameUser:`00000000-0000-4000-8000-000000000005`},i={adminUser:`admin@example.com`,viewerUser:`viewer@example.com`,inactiveUser:`inactive@example.com`,unicodeUser:`unicode@example.com`,longNameUser:`long-name@example.com`};function a(e=process.argv.slice(2)){if(e.includes(`--large`))return`large`;let t=e.find(e=>e.startsWith(`--profile=`))?.slice(10)??`default`;if(t==="default"||t===`large`)return t;throw Error(`Unknown seed profile "${t}". Expected default or large.`)}function o(e){return`00000000-0000-4000-8000-${String(1e3+e).padStart(12,`0`)}`}export{t as HELD_MIGRATIONS_FOLDER,e as MIGRATIONS_FOLDER,n as NOW,i as SEED_EMAILS,r as SEED_IDS,o as generatedUserId,a as getSeedProfile};
@@ -0,0 +1,10 @@
1
+ //#region src/drizzle-kit.d.ts
2
+ type DrizzleKitCommand = "generate" | "migrate" | "studio";
3
+ type RunDrizzleKitCommandOptions = {
4
+ env?: NodeJS.ProcessEnv;
5
+ };
6
+ declare function runDrizzleKitCommand(command: DrizzleKitCommand, args?: string[], {
7
+ env
8
+ }?: RunDrizzleKitCommandOptions): Promise<void>;
9
+ //#endregion
10
+ export { runDrizzleKitCommand };
@@ -0,0 +1 @@
1
+ import{startProjectPostgres as e}from"./local-postgres.js";import t from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import n from"node:path";import r from"node:process";import{readProjectConfig as i}from"@coreframe/config";import a from"nano-spawn";const o=n.resolve(`node_modules`,`.bin`),s=r.platform===`win32`?`drizzle-kit.cmd`:`drizzle-kit`;async function c(n,a=[],{env:o=r.env}={}){try{var s=t();if((await i()).database?.dialect===`sqlite`){let e=o.TURSO_DATABASE_URL??o.DATABASE_URL;if(!e)throw Error(`TURSO_DATABASE_URL or DATABASE_URL is required for SQLite Drizzle commands.`);await l(a,n,{...o,DATABASE_URL:e});return}await l(a,n,s.a(await e({env:o,useSupervisorLease:!0})).env)}catch(e){s.e=e}finally{await s.d()}}async function l(e,t,r){let i=r.PATH??r.Path??``;await a(s,[t,...e],{env:{...r,PATH:o+n.delimiter+i},stdio:`inherit`})}export{c as runDrizzleKitCommand};
@@ -0,0 +1,9 @@
1
+ //#region src/ensure.d.ts
2
+ type EnsureLocalDbOptions = {
3
+ env?: NodeJS.ProcessEnv;
4
+ };
5
+ declare function ensureLocalDb({
6
+ env
7
+ }?: EnsureLocalDbOptions): Promise<void>;
8
+ //#endregion
9
+ export { ensureLocalDb };
package/dist/ensure.js ADDED
@@ -0,0 +1 @@
1
+ import{SEED_EMAILS as e,SEED_IDS as t}from"./config.js";import{createLocalPostgresDb as n,startProjectPostgres as r}from"./local-postgres.js";import i from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{inferSchemaDialect as a,planLocalSchemaPush as o}from"./schema-push.js";import{seedLocalDb as s}from"./seed.js";import{setupLocalDb as c}from"./setup.js";import{eq as l}from"drizzle-orm";import{importProjectModule as u}from"@coreframe/config";async function d(){return{schema:await u(`src/db/schema.ts`)}}async function f(n,{users:r}){let[i]=await n.select({id:r.id}).from(r).where(l(r.email,e.adminUser)).limit(1);return i?.id===t.adminUser}async function p(e,{schema:t}){let n=await o(a(t),t,e);return n.sqlStatements.length===0?(console.log(`Local database schema already in sync`),{appliedStatements:0,plan:n}):(console.log(`Local database schema drift detected; applying ${n.sqlStatements.length} statement(s)`),await n.apply(),console.log(`Local database schema synced`),{appliedStatements:n.sqlStatements.length,plan:n})}async function m({env:e=process.env}={}){try{var t=i();let a=t.a(await r({env:e,useSupervisorLease:!0})).env,o=await d(),l=await n({env:a});try{if(await h(l,o.schema))console.log(`Local database already set up`);else{console.log(`Local database is missing or unseeded; running setup`),await c(`default`,{env:a});return}(await p(l,o)).appliedStatements>0&&!await h(l,o.schema)&&(console.log(`Local database seed data missing after schema sync; running seed`),await s(void 0,{env:a}))}finally{await l.$client.end()}}catch(e){t.e=e}finally{await t.d()}}async function h(e,t){try{return await f(e,t)}catch{return!1}}export{m as ensureLocalDb};
@@ -0,0 +1 @@
1
+ import{access as e,mkdtemp as t,readFile as n,rm as r,stat as i}from"node:fs/promises";import a from"node:process";import{tmpdir as o}from"node:os";const s=a.kill.bind(a),c={access:e,mkdtemp:t,readFile:n,rm:r,stat:i},l={kill:s,tmpdir:o};a.argv,a.cwd.bind(a),a.env,a.platform;export{c as fs,l as os};
@@ -0,0 +1,4 @@
1
+ //#region src/error.d.ts
2
+ declare function formatDbErrorMessage(error: unknown): string | undefined;
3
+ //#endregion
4
+ export { formatDbErrorMessage };
package/dist/error.js ADDED
@@ -0,0 +1 @@
1
+ import{DrizzleQueryError as e}from"drizzle-orm/errors";function t(t){if(!(!(t instanceof e)||!t.cause?.message))return`${n(t.message)}\nCause: ${n(t.cause.message)}`}function n(e){return e.split(/\r?\n/,1)[0]||`Unknown error`}export{t as formatDbErrorMessage};
@@ -0,0 +1,19 @@
1
+ import { SeedDatabase, SeedQuery, applySeed } from "./apply-seed.js";
2
+ import { checkDeployMigrations } from "./check-migrations.js";
3
+ import { CreateDatabaseAdapterOptions, DatabaseClient, DatabaseDialect, DrizzleExecutor, QueryResult, createDatabaseAdapter, normalizeQueryResult } from "./client.js";
4
+ import { HELD_MIGRATIONS_FOLDER, MIGRATIONS_FOLDER, NOW, SEED_EMAILS, SEED_IDS, SeedProfile, generatedUserId, getSeedProfile } from "./config.js";
5
+ import { runDrizzleKitCommand } from "./drizzle-kit.js";
6
+ import { ensureLocalDb } from "./ensure.js";
7
+ import { formatDbErrorMessage } from "./error.js";
8
+ import { CreateProjectDatabaseOptions, createProjectDeployDatabase, createProjectPostgresDrizzleDatabase } from "./project.js";
9
+ import { LOCAL_POSTGRES_ENV_FLAG, LocalPostgresDb, ProjectPostgresAlreadyRunningError, ProjectPostgresSidecar, StartProjectPostgresOptions, StartTemporaryProjectPostgresOptions, createLocalPostgresDb, createLocalPostgresEnv, getLocalPostgresConnectionString, startProjectPostgres, startTemporaryProjectPostgres, stopProjectPostgres } from "./local-postgres.js";
10
+ import { heldMigrationInsertQuery, heldMigrationSelectQuery, migrateHeldMigrations, validateHeldMigrationHeader } from "./migrate-held.js";
11
+ import { migrateLocalDb } from "./migrate.js";
12
+ import { MigrationFile, MigrationRisk, MigrationScanResult, collectDeployMigrationFiles, collectHeldMigrationFiles, formatMigrationList, formatMigrationScanFailures, scanDeployMigrationFiles, scanMigrationSql } from "./migrations.js";
13
+ import { appliedMigrationsQuery, filterPendingMigrations, readAppliedMigrationNames } from "./pending-migrations.js";
14
+ import { resetLocalDb } from "./reset.js";
15
+ import { checkSchemaPush } from "./schema-check.js";
16
+ import { SchemaPushModule, SchemaPushPlan, inferSchemaDialect, planLocalSchemaPush } from "./schema-push.js";
17
+ import { runProjectSeed, seedLocalDb } from "./seed.js";
18
+ import { setupLocalDb } from "./setup.js";
19
+ export { CreateDatabaseAdapterOptions, CreateProjectDatabaseOptions, DatabaseClient, DatabaseDialect, DrizzleExecutor, HELD_MIGRATIONS_FOLDER, LOCAL_POSTGRES_ENV_FLAG, LocalPostgresDb, MIGRATIONS_FOLDER, MigrationFile, MigrationRisk, MigrationScanResult, NOW, ProjectPostgresAlreadyRunningError, ProjectPostgresSidecar, QueryResult, SEED_EMAILS, SEED_IDS, SchemaPushModule, SchemaPushPlan, SeedDatabase, SeedProfile, SeedQuery, StartProjectPostgresOptions, StartTemporaryProjectPostgresOptions, appliedMigrationsQuery, applySeed, checkDeployMigrations, checkSchemaPush, collectDeployMigrationFiles, collectHeldMigrationFiles, createDatabaseAdapter, createLocalPostgresDb, createLocalPostgresEnv, createProjectDeployDatabase, createProjectPostgresDrizzleDatabase, ensureLocalDb, filterPendingMigrations, formatDbErrorMessage, formatMigrationList, formatMigrationScanFailures, generatedUserId, getLocalPostgresConnectionString, getSeedProfile, heldMigrationInsertQuery, heldMigrationSelectQuery, inferSchemaDialect, migrateHeldMigrations, migrateLocalDb, normalizeQueryResult, planLocalSchemaPush, readAppliedMigrationNames, resetLocalDb, runDrizzleKitCommand, runProjectSeed, scanDeployMigrationFiles, scanMigrationSql, seedLocalDb, setupLocalDb, startProjectPostgres, startTemporaryProjectPostgres, stopProjectPostgres, validateHeldMigrationHeader };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{applySeed as e}from"./apply-seed.js";import{HELD_MIGRATIONS_FOLDER as t,MIGRATIONS_FOLDER as n,NOW as r,SEED_EMAILS as i,SEED_IDS as a,generatedUserId as o,getSeedProfile as s}from"./config.js";import{collectDeployMigrationFiles as c,collectHeldMigrationFiles as l,formatMigrationList as u,formatMigrationScanFailures as d,scanDeployMigrationFiles as f,scanMigrationSql as p}from"./migrations.js";import{checkDeployMigrations as m}from"./check-migrations.js";import{createDatabaseAdapter as h,normalizeQueryResult as g}from"./client.js";import{createProjectDeployDatabase as _,createProjectPostgresDrizzleDatabase as v}from"./project.js";import{LOCAL_POSTGRES_ENV_FLAG as y,ProjectPostgresAlreadyRunningError as b,createLocalPostgresDb as x,createLocalPostgresEnv as S,getLocalPostgresConnectionString as C,startProjectPostgres as w,startTemporaryProjectPostgres as T,stopProjectPostgres as E}from"./local-postgres.js";import{runDrizzleKitCommand as D}from"./drizzle-kit.js";import{inferSchemaDialect as O,planLocalSchemaPush as k}from"./schema-push.js";import{runProjectSeed as A,seedLocalDb as j}from"./seed.js";import{migrateLocalDb as M}from"./migrate.js";import{resetLocalDb as N}from"./reset.js";import{setupLocalDb as P}from"./setup.js";import{ensureLocalDb as F}from"./ensure.js";import{formatDbErrorMessage as I}from"./error.js";import{heldMigrationInsertQuery as L,heldMigrationSelectQuery as R,migrateHeldMigrations as z,validateHeldMigrationHeader as B}from"./migrate-held.js";import{appliedMigrationsQuery as V,filterPendingMigrations as H,readAppliedMigrationNames as U}from"./pending-migrations.js";import{checkSchemaPush as W}from"./schema-check.js";export{t as HELD_MIGRATIONS_FOLDER,y as LOCAL_POSTGRES_ENV_FLAG,n as MIGRATIONS_FOLDER,r as NOW,b as ProjectPostgresAlreadyRunningError,i as SEED_EMAILS,a as SEED_IDS,V as appliedMigrationsQuery,e as applySeed,m as checkDeployMigrations,W as checkSchemaPush,c as collectDeployMigrationFiles,l as collectHeldMigrationFiles,h as createDatabaseAdapter,x as createLocalPostgresDb,S as createLocalPostgresEnv,_ as createProjectDeployDatabase,v as createProjectPostgresDrizzleDatabase,F as ensureLocalDb,H as filterPendingMigrations,I as formatDbErrorMessage,u as formatMigrationList,d as formatMigrationScanFailures,o as generatedUserId,C as getLocalPostgresConnectionString,s as getSeedProfile,L as heldMigrationInsertQuery,R as heldMigrationSelectQuery,O as inferSchemaDialect,z as migrateHeldMigrations,M as migrateLocalDb,g as normalizeQueryResult,k as planLocalSchemaPush,U as readAppliedMigrationNames,N as resetLocalDb,D as runDrizzleKitCommand,A as runProjectSeed,f as scanDeployMigrationFiles,p as scanMigrationSql,j as seedLocalDb,P as setupLocalDb,w as startProjectPostgres,T as startTemporaryProjectPostgres,E as stopProjectPostgres,B as validateHeldMigrationHeader};
@@ -0,0 +1,67 @@
1
+ import { DrizzleExecutor } from "./client.js";
2
+ import { createProjectPostgresDrizzleDatabase } from "./project.js";
3
+ import { CoreframeConfig } from "@coreframe/config";
4
+ import { LocalPostgresEnv, PostgresOutputTarget } from "local-postgres";
5
+
6
+ //#region src/local-postgres.d.ts
7
+ declare const LOCAL_POSTGRES_ENV_FLAG = "COREFRAME_LOCAL_POSTGRES";
8
+ type LocalPostgresDb = Awaited<ReturnType<typeof createProjectPostgresDrizzleDatabase>> & {
9
+ $client: {
10
+ end(): Promise<void>;
11
+ };
12
+ transaction<Result>(run: (database: DrizzleExecutor) => Promise<Result>): Promise<Result>;
13
+ select(selection: Record<string, unknown>): {
14
+ from(table: unknown): {
15
+ where(condition: unknown): {
16
+ limit(count: number): Promise<Array<{
17
+ id: string;
18
+ }>>;
19
+ };
20
+ };
21
+ };
22
+ };
23
+ type LocalPostgresOptions = {
24
+ env?: NodeJS.ProcessEnv;
25
+ };
26
+ type ProjectPostgresSidecar = {
27
+ env: NodeJS.ProcessEnv;
28
+ [Symbol.asyncDispose](): Promise<void>;
29
+ };
30
+ type StartProjectPostgresOptions = {
31
+ config?: CoreframeConfig;
32
+ cwd?: string;
33
+ env?: NodeJS.ProcessEnv;
34
+ failIfRunning?: boolean;
35
+ postgresOutput?: PostgresOutputTarget;
36
+ useSupervisorLease?: boolean;
37
+ };
38
+ type StartTemporaryProjectPostgresOptions = Omit<StartProjectPostgresOptions, "useSupervisorLease">;
39
+ declare class ProjectPostgresAlreadyRunningError extends Error {
40
+ readonly dataDir: string;
41
+ readonly pid: number;
42
+ constructor(dataDir: string, pid: number, options?: ErrorOptions);
43
+ }
44
+ declare function startProjectPostgres({
45
+ config,
46
+ cwd,
47
+ env,
48
+ failIfRunning,
49
+ postgresOutput,
50
+ useSupervisorLease
51
+ }?: StartProjectPostgresOptions): Promise<ProjectPostgresSidecar>;
52
+ declare function stopProjectPostgres({
53
+ dataDir,
54
+ pid
55
+ }: ProjectPostgresAlreadyRunningError): Promise<void>;
56
+ declare function startTemporaryProjectPostgres({
57
+ config,
58
+ cwd,
59
+ env
60
+ }?: StartTemporaryProjectPostgresOptions): Promise<ProjectPostgresSidecar>;
61
+ declare function createLocalPostgresEnv(env: NodeJS.ProcessEnv, postgresEnv: LocalPostgresEnv): NodeJS.ProcessEnv;
62
+ declare function createLocalPostgresDb({
63
+ env
64
+ }?: LocalPostgresOptions): Promise<LocalPostgresDb>;
65
+ declare function getLocalPostgresConnectionString(env?: NodeJS.ProcessEnv): string;
66
+ //#endregion
67
+ export { LOCAL_POSTGRES_ENV_FLAG, LocalPostgresDb, ProjectPostgresAlreadyRunningError, ProjectPostgresSidecar, StartProjectPostgresOptions, StartTemporaryProjectPostgresOptions, createLocalPostgresDb, createLocalPostgresEnv, getLocalPostgresConnectionString, startProjectPostgres, startTemporaryProjectPostgres, stopProjectPostgres };
@@ -0,0 +1 @@
1
+ import{fs as e,os as t}from"./environment.js";import{createProjectPostgresDrizzleDatabase as n}from"./project.js";import r from"node:path";import{readProjectConfig as i}from"@coreframe/config";import{connectExistingDevSupervisor as a}from"@coreframe/dev-supervisor";import{startPostgres as o}from"local-postgres";import{PostgresDataDirInUseError as s,stopPostgresDataDir as c}from"local-postgres/core";const l=`COREFRAME_LOCAL_POSTGRES`,u=`coreframe`,d=2e3,f=4e3,p=new Map,m={name:`coreframe`,password:`coreframe`};var h=class extends Error{dataDir;pid;constructor(e,t,n){super(`PostgreSQL is already running for this project (PID ${t}). Stop the other top-level \`coreframe dev\` process before starting another.`,n),this.name=`ProjectPostgresAlreadyRunningError`,this.dataDir=e,this.pid=t}};async function g({config:t,cwd:n=process.cwd(),env:s=process.env,failIfRunning:c=!1,postgresOutput:l,useSupervisorLease:f=!1}={}){if(s.COREFRAME_LOCAL_POSTGRES===`1`)return T(s);let p=t??await i({cwd:n});if((p.database?.dialect??`postgres`)!==`postgres`)return T(s);if(f){if(s.COREFRAME_DEV_SUPERVISOR!==`0`){let e=await a({cwd:n,env:s});if(e)try{let t=await e.acquirePostgres({config:p,env:s});return E(e,t.leaseId,t.env)}catch(t){throw e.close(),t}}return v({config:p,cwd:n,env:s})}let g=r.resolve(n,`.coreframe/postgres`),_=await D(g);if(_){if(c)throw new h(g,_.pid);return T(O(s,g,_))}let y=r.join(g,`postgres.log`);await e.rm(y,{force:!0});let b;try{b=await o({dataDir:g,database:u,postgresOutput:l??{filePath:y},postgres:{strategy:`prefer-local`},stopTimeoutMs:d,superuser:m})}catch(e){throw await k(e,l?void 0:y)}return x(s,b)}async function _({dataDir:e,pid:t}){let n=`${e}\0${t}`,r=p.get(n);if(r){await r;return}let i=C(e,t);p.set(n,i);try{await i}finally{p.get(n)===i&&p.delete(n)}}async function v({config:n,cwd:a=process.cwd(),env:s=process.env}={}){let c=(n??await i({cwd:a})).database?.dialect??`postgres`;if(c!==`postgres`)throw Error(`Temporary schema push checks require PostgreSQL, but this project uses ${c}.`);let l=await e.mkdtemp(r.join(t.tmpdir(),`coreframe-schema-check-`));try{let t=x(s,await o({dataDir:l,database:u,postgresOutput:`ignore`,postgres:{strategy:`prefer-local`},stopTimeoutMs:d,superuser:m}));return{env:t.env,async[Symbol.asyncDispose](){await t[Symbol.asyncDispose](),await e.rm(l,{force:!0,recursive:!0})}}}catch(e){throw await w(l,e),e}}function y(e,t){return{...e,...t,[l]:`1`}}async function b({env:e=process.env}={}){let t=j(e);return n({env:{...e,DATABASE_URL:t}})}function x(e,t){let n;return{env:y(e,t.env),async[Symbol.asyncDispose](){n??=S(t),await n}}}async function S(e){let t;try{await e[Symbol.asyncDispose]()}catch(e){t=e}if(e.pid===void 0){if(t)throw t;return}try{await c({dataDir:e.dataDir,expectedPid:e.pid,mode:`immediate`,timeoutMs:f})}catch(n){throw t?AggregateError([t,n],`Failed to stop PostgreSQL process ${e.pid}.`):n}}async function C(e,t){try{await c({dataDir:e,expectedPid:t,mode:`fast`,timeoutMs:f})}catch(n){try{await c({dataDir:e,expectedPid:t,mode:`immediate`,timeoutMs:f})}catch(e){throw AggregateError([n,e],`Failed to stop PostgreSQL process ${t}.`)}}}async function w(t,n){try{await c({dataDir:t,mode:`immediate`,timeoutMs:f})}catch(e){throw AggregateError([n,e],`Temporary PostgreSQL failed to start and could not be stopped for ${t}.`)}await e.rm(t,{force:!0,recursive:!0})}function T(e){return{env:e,async[Symbol.asyncDispose](){}}}function E(e,t,n){let r;return{env:n,async[Symbol.asyncDispose](){r??=(async()=>{try{await e.release(t)}finally{e.close()}})(),await r}}}async function D(n){let i;try{i=await e.readFile(r.join(n,`postmaster.pid`),`utf8`)}catch{return}let[a,,,o,,s]=i.split(/\r?\n/),c=Number(a);if(!Number.isSafeInteger(c)||c<=0)return;try{t.kill(c,0)}catch(e){if(!A(e)||e.code!==`EPERM`)return}let l=Number(o);if(!Number.isSafeInteger(l)||l<=0||l>65535||!s)throw Error(`Cannot read connection details for PostgreSQL process ${c} from ${n}.`);return{host:s,pid:c,port:l}}function O(e,t,{host:n,port:r}){let i=new URL(`postgresql://${n}:${r}/${u}`);return i.username=m.name,i.password=m.password,y(e,{DATABASE_URL:i.href,PGDATA:t,PGDATABASE:u,PGHOST:n,PGPASSWORD:m.password,PGPORT:String(r),PGUSER:m.name})}async function k(t,n){if(t instanceof s)return new h(t.dataDir,t.pid,{cause:t});let r=t instanceof Error?t.message:String(t),i;if(n)try{i=(await e.readFile(n,`utf8`)).trim()||void 0}catch{}let a=i?`\n\nPostgreSQL output:\n${i}`:``,o=n?`\n\nPostgreSQL log: ${n}`:``;return Error(`Local PostgreSQL failed to start: ${r}${a}${o}`,{cause:t})}function A(e){return e instanceof Error}function j(e=process.env){let t=e.DATABASE_URL||M(e);if(!t)throw Error(`DATABASE_URL or PGDATABASE, PGHOST, PGPORT, and PGUSER are required.`);return t}function M(e){let{PGDATABASE:t,PGHOST:n,PGPASSWORD:r,PGPORT:i,PGUSER:a}=e;if(!t||!n||!i||!a)return;let o=new URL(`postgresql://${n}:${i}/${t}`);return o.username=a,r&&(o.password=r),o.href}export{l as LOCAL_POSTGRES_ENV_FLAG,h as ProjectPostgresAlreadyRunningError,b as createLocalPostgresDb,y as createLocalPostgresEnv,j as getLocalPostgresConnectionString,g as startProjectPostgres,v as startTemporaryProjectPostgres,_ as stopProjectPostgres};
@@ -0,0 +1,16 @@
1
+ import { DatabaseDialect } from "./client.js";
2
+
3
+ //#region src/migrate-held.d.ts
4
+ type MigrateHeldOptions = {
5
+ argv?: string[];
6
+ env?: NodeJS.ProcessEnv;
7
+ };
8
+ declare function migrateHeldMigrations({
9
+ argv,
10
+ env
11
+ }?: MigrateHeldOptions): Promise<void>;
12
+ declare function validateHeldMigrationHeader(sql: string, relativePath: string): void;
13
+ declare function heldMigrationSelectQuery(dialect: DatabaseDialect, id: string): string;
14
+ declare function heldMigrationInsertQuery(dialect: DatabaseDialect, id: string, sha256: string): string;
15
+ //#endregion
16
+ export { heldMigrationInsertQuery, heldMigrationSelectQuery, migrateHeldMigrations, validateHeldMigrationHeader };
@@ -0,0 +1,9 @@
1
+ import{collectHeldMigrationFiles as e,formatMigrationList as t}from"./migrations.js";import{createProjectDeployDatabase as n}from"./project.js";import{readFile as r}from"node:fs/promises";import{createHash as i}from"node:crypto";const a=`--confirm=run-held-migrations`,o=[`-- Held migration:`,`-- Safe after:`,`-- Verification:`];async function s({argv:i=process.argv.slice(2),env:o=process.env}={}){let s=await e();if(console.log(`Held migration files:`),console.log(t(s)),!i.includes(a))throw Error(`Held migrations require explicit confirmation. Re-run with ${a}.`);if(s.length===0){console.log(`No held migrations to run.`);return}let d=await n({env:o});try{await u(d);for(let e of s){let t=await r(e.path,`utf8`);c(t,e.relativePath);let n=l(t),i=await d.execute(f(d.dialect,e.id));if(i.rows.length===1){if(i.rows[0]?.sha256!==n)throw Error(`Held migration ${e.relativePath} changed after it was applied.`);console.log(`Skipping already-applied held migration ${e.relativePath}`);continue}console.log(`Applying held migration ${e.relativePath}`),await h(d,async r=>{await r.execute(t),await r.execute(p(d.dialect,e.id,n))})}}finally{await d.close?.()}}function c(e,t){let n=o.filter(t=>!e.includes(t));if(n.length>0)throw Error(`${t} is missing held migration header fields: ${n.join(`, `)}`)}function l(e){return i(`sha256`).update(e).digest(`hex`)}async function u(e){for(let t of d(e.dialect))await e.execute(t)}function d(e){switch(e){case`postgres`:return[`create schema if not exists drizzle`,`create table if not exists drizzle.__held_migrations (
2
+ id text primary key,
3
+ sha256 text not null,
4
+ applied_at timestamptz not null default now()
5
+ )`];case`sqlite`:return[`create table if not exists __held_migrations (
6
+ id text primary key,
7
+ sha256 text not null,
8
+ applied_at text not null default current_timestamp
9
+ )`]}}function f(e,t){return`select sha256 from ${m(e)} where id = ${g(t)}`}function p(e,t,n){return`insert into ${m(e)} (id, sha256) values (${g(t)}, ${g(n)})`}function m(e){switch(e){case`postgres`:return`drizzle.__held_migrations`;case`sqlite`:return`__held_migrations`}}async function h(e,t){if(e.transaction){await e.transaction(t);return}await e.execute(`begin`);try{await t(e),await e.execute(`commit`)}catch(t){throw await e.execute(`rollback`),t}}function g(e){return`'${e.replaceAll(`'`,`''`)}'`}export{p as heldMigrationInsertQuery,f as heldMigrationSelectQuery,s as migrateHeldMigrations,c as validateHeldMigrationHeader};
@@ -0,0 +1,9 @@
1
+ //#region src/migrate.d.ts
2
+ type MigrateLocalDbOptions = {
3
+ env?: NodeJS.ProcessEnv;
4
+ };
5
+ declare function migrateLocalDb({
6
+ env
7
+ }?: MigrateLocalDbOptions): Promise<void>;
8
+ //#endregion
9
+ export { migrateLocalDb };
@@ -0,0 +1 @@
1
+ import{MIGRATIONS_FOLDER as e}from"./config.js";import{createLocalPostgresDb as t,startProjectPostgres as n}from"./local-postgres.js";import r from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{access as i}from"node:fs/promises";import{resolve as a}from"node:path";import{migrate as o}from"drizzle-orm/node-postgres/migrator";const s=a(e);async function c({env:e=process.env}={}){try{var a=r();await i(s);let c=await t({env:a.a(await n({env:e,useSupervisorLease:!0})).env});try{await o(c,{migrationsFolder:s}),console.log(`Applied local migrations from ${s}`)}finally{await c.$client.end()}}catch(e){a.e=e}finally{await a.d()}}export{c as migrateLocalDb};
@@ -0,0 +1,24 @@
1
+ //#region src/migrations.d.ts
2
+ type MigrationFile = {
3
+ id: string;
4
+ path: string;
5
+ relativePath: string;
6
+ };
7
+ type MigrationRisk = {
8
+ code: string;
9
+ line: number;
10
+ match: string;
11
+ reason: string;
12
+ };
13
+ type MigrationScanResult = {
14
+ migration: MigrationFile;
15
+ risks: MigrationRisk[];
16
+ };
17
+ declare function collectDeployMigrationFiles(cwd?: string): Promise<MigrationFile[]>;
18
+ declare function collectHeldMigrationFiles(cwd?: string): Promise<MigrationFile[]>;
19
+ declare function scanDeployMigrationFiles(migrations: MigrationFile[]): Promise<MigrationScanResult[]>;
20
+ declare function scanMigrationSql(sql: string): MigrationRisk[];
21
+ declare function formatMigrationScanFailures(results: MigrationScanResult[]): string;
22
+ declare function formatMigrationList(migrations: MigrationFile[]): string;
23
+ //#endregion
24
+ export { MigrationFile, MigrationRisk, MigrationScanResult, collectDeployMigrationFiles, collectHeldMigrationFiles, formatMigrationList, formatMigrationScanFailures, scanDeployMigrationFiles, scanMigrationSql };
@@ -0,0 +1,4 @@
1
+ import{HELD_MIGRATIONS_FOLDER as e,MIGRATIONS_FOLDER as t}from"./config.js";import{access as n,readFile as r,readdir as i}from"node:fs/promises";import{basename as a,join as o,relative as s,resolve as c}from"node:path";const l=[{code:`drop-schema-object`,pattern:/\bdrop\s+(?:table|view|materialized\s+view|index|sequence|type|schema|function|trigger|policy)\b/giu,reason:`drops schema that the currently deployed app may still depend on`},{code:`drop-column`,pattern:/\balter\s+table\b[^;]*?\bdrop\s+column\b/giu,reason:`removes a column that the currently deployed app may still read or write`},{code:`drop-constraint`,pattern:/\balter\s+table\b[^;]*?\bdrop\s+constraint\b/giu,reason:`removes a constraint outside the staged contract phase`},{code:`truncate`,pattern:/\btruncate\b/giu,reason:`removes data outside the deploy-safe migration path`},{code:`rename-table-or-column`,pattern:/\balter\s+table\b[^;]*?\brename(?:\s+column)?\b/giu,reason:`renames schema in a way old and new app versions cannot both address`},{code:`rewrite-column-type`,pattern:/\balter\s+table\b[^;]*?\balter\s+column\b[^;]*?\btype\b/giu,reason:`rewrites a column type outside a staged expand/contract rollout`},{code:`set-not-null`,pattern:/\balter\s+table\b[^;]*?\balter\s+column\b[^;]*?\bset\s+not\s+null\b/giu,reason:`enforces NOT NULL before a separate backfill and verification step`},{code:`set-default`,pattern:/\balter\s+table\b[^;]*?\balter\s+column\b[^;]*?\bset\s+default\b/giu,reason:`changes default write behavior while old app code may still be running`},{code:`broad-update`,pattern:/\bupdate\b/giu,reason:`changes data outside a separately reviewed backfill or held migration`},{code:`broad-delete`,pattern:/\bdelete\s+from\b/giu,reason:`removes data outside a held migration`}];async function u(e=process.cwd()){return _(c(e,t),e)}async function d(t=process.cwd()){return v(c(t,e),t)}async function f(e){return(await Promise.all(e.map(async e=>({migration:e,risks:p(await r(e.path,`utf8`))})))).filter(e=>e.risks.length>0)}function p(e){let t=S(e),n=g(t),r=[];for(let n of l)for(let i of t.matchAll(n.pattern))r.push(T(e,i,n.code,n.reason));for(let i of t.matchAll(/\balter\s+table\s+(?:if\s+exists\s+|only\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)\s+add\s+column\b[^;]*?\bnot\s+null\b/giu))n.has(w(i.groups?.table))||r.push(T(e,i,`add-not-null-column`,`adds a required column to an existing table before a separate compatibility rollout`));for(let i of t.matchAll(/\balter\s+table\s+(?:if\s+exists\s+|only\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)\s+add\s+constraint\b[^;]*?\b(?:foreign\s+key|unique|primary\s+key|check)\b/giu))n.has(w(i.groups?.table))||r.push(T(e,i,`add-constraint`,`enforces a constraint on an existing table before a separate validation step`));for(let i of t.matchAll(/\bcreate\s+unique\s+index(?:\s+concurrently)?(?:\s+if\s+not\s+exists)?\s+(?:"[^"]+"|\w+)\s+on\s+(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)/giu))n.has(w(i.groups?.table))||r.push(T(e,i,`create-unique-index`,`adds uniqueness to existing data before a separate dedupe and validation step`));return r.sort((e,t)=>e.line-t.line||e.code.localeCompare(t.code))}function m(e){return e.flatMap(e=>e.risks.map(t=>`${e.migration.relativePath}:${t.line} ${t.code}: ${t.reason} (${t.match.trim()})`)).join(`
2
+ `)}function h(e){return e.length===0?`No migration files found.`:e.map(e=>`- ${e.relativePath}`).join(`
3
+ `)}function g(e){let t=new Set;for(let n of e.matchAll(/\bcreate\s+(?:temporary\s+|temp\s+)?table\s+(?:if\s+not\s+exists\s+)?(?<table>(?:"[^"]+"|\w+)(?:\s*\.\s*(?:"[^"]+"|\w+))?)/giu))t.add(w(n.groups?.table));return t}async function _(e,t){let n=await y(e),r=[];for(let i of n){let n=o(e,i.name);if(i.isDirectory()){let e=o(n,`migration.sql`);await b(e)&&r.push(x(e,t,i.name));continue}i.isFile()&&i.name.endsWith(`.sql`)&&r.push(x(n,t,i.name.replace(/\.sql$/u,``)))}return r.sort((e,t)=>e.id.localeCompare(t.id))}async function v(e,t){return(await y(e)).filter(e=>e.isFile()&&e.name.endsWith(`.sql`)).map(n=>x(o(e,n.name),t,n.name.replace(/\.sql$/u,``))).sort((e,t)=>e.id.localeCompare(t.id))}async function y(e){try{return await i(e,{withFileTypes:!0})}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return[];throw e}}async function b(e){try{return await n(e),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw e}}function x(e,t,n=a(e,`.sql`)){return{id:n,path:e,relativePath:s(t,e)}}function S(e){return e.replace(/--[^\n\r]*/gu,C).replace(/\/\*[\s\S]*?\*\//gu,C).replace(/\$([A-Za-z_][A-Za-z0-9_]*)?\$[\s\S]*?\$\1\$/gu,C).replace(/'(?:''|[^'])*'/gu,C)}function C(e){return e.replace(/[^\n\r]/gu,` `)}function w(e){return(e??``).split(`.`).map(e=>e.trim().replace(/^"|"$/gu,``).toLowerCase()).at(-1)??``}function T(e,t,n,r){return{code:n,line:E(e,t.index??0),match:e.slice(t.index??0,(t.index??0)+t[0].length),reason:r}}function E(e,t){let n=1;for(let r=0;r<t;r+=1)e[r]===`
4
+ `&&(n+=1);return n}export{u as collectDeployMigrationFiles,d as collectHeldMigrationFiles,h as formatMigrationList,m as formatMigrationScanFailures,f as scanDeployMigrationFiles,p as scanMigrationSql};
@@ -0,0 +1,9 @@
1
+ import { DatabaseClient, DatabaseDialect } from "./client.js";
2
+ import { MigrationFile } from "./migrations.js";
3
+
4
+ //#region src/pending-migrations.d.ts
5
+ declare function filterPendingMigrations(migrations: MigrationFile[], appliedNames: Iterable<string>): MigrationFile[];
6
+ declare function readAppliedMigrationNames(database: DatabaseClient): Promise<Set<string>>;
7
+ declare function appliedMigrationsQuery(dialect: DatabaseDialect): "select name from drizzle.__drizzle_migrations where name is not null" | "select name from __drizzle_migrations where name is not null";
8
+ //#endregion
9
+ export { appliedMigrationsQuery, filterPendingMigrations, readAppliedMigrationNames };
@@ -0,0 +1 @@
1
+ function e(e,t){let n=new Set(t);return e.filter(e=>!n.has(e.id))}async function t(e){try{let t=await e.execute(n(e.dialect));return new Set(t.rows.flatMap(e=>e.name?[e.name]:[]))}catch(e){if(r(e))return new Set;throw e}}function n(e){switch(e){case`postgres`:return`select name from drizzle.__drizzle_migrations where name is not null`;case`sqlite`:return`select name from __drizzle_migrations where name is not null`}}function r(e){return e instanceof Error&&(`code`in e&&(e.code===`42P01`||e.code===`3F000`)||e.message.includes(`no such table`)||e.message.includes(`no such schema`))}export{n as appliedMigrationsQuery,e as filterPendingMigrations,t as readAppliedMigrationNames};
@@ -0,0 +1,23 @@
1
+ import { DatabaseClient, DrizzleExecutor } from "./client.js";
2
+ import { DatabaseConfig } from "@coreframe/config";
3
+
4
+ //#region src/project.d.ts
5
+ type CreateProjectDatabaseOptions = {
6
+ config?: DatabaseConfig;
7
+ env?: NodeJS.ProcessEnv;
8
+ };
9
+ type DrizzleDatabase = DrizzleExecutor & {
10
+ $client?: {
11
+ close?(): Promise<void> | void;
12
+ end?(): Promise<void>;
13
+ };
14
+ };
15
+ declare function createProjectDeployDatabase({
16
+ config,
17
+ env
18
+ }?: CreateProjectDatabaseOptions): Promise<DatabaseClient>;
19
+ declare function createProjectPostgresDrizzleDatabase({
20
+ env
21
+ }?: CreateProjectDatabaseOptions): Promise<DrizzleDatabase>;
22
+ //#endregion
23
+ export { CreateProjectDatabaseOptions, createProjectDeployDatabase, createProjectPostgresDrizzleDatabase };
@@ -0,0 +1 @@
1
+ import{createDatabaseAdapter as e}from"./client.js";import{importProjectDependency as t,importProjectModule as n,readProjectConfig as r}from"@coreframe/config";const i=`src/db/relations.ts`;async function a({config:e,env:t=process.env}={}){let n=(e??(await r()).database)?.dialect??`postgres`;if(n===`postgres`)return s({env:t});if(n===`sqlite`)return c({env:t});throw Error(`Unsupported database dialect "${n}".`)}async function o({env:e=process.env}={}){let r=e.DATABASE_URL;if(!r)throw Error(`DATABASE_URL is required to create the PostgreSQL database.`);let[{drizzle:a},{relations:o}]=await Promise.all([t(`drizzle-orm/node-postgres`),n(i)]);return a({connection:{connectionString:r,max:1},relations:o})}async function s({env:t}){let n=await o({env:t});return e({database:n,dialect:`postgres`,close:()=>n.$client?.end?.()??Promise.resolve()})}async function c({env:r}){let a=r.TURSO_DATABASE_URL??r.DATABASE_URL;if(!a)throw Error(`TURSO_DATABASE_URL or DATABASE_URL is required to create the deploy database.`);let[{createClient:o},{drizzle:s},{relations:c}]=await Promise.all([t(`@libsql/client`),t(`drizzle-orm/libsql`),n(i)]),l=o({url:a,authToken:r.TURSO_AUTH_TOKEN});return e({database:s({client:l,relations:c}),dialect:`sqlite`,close:async()=>{await l.close?.()}})}export{a as createProjectDeployDatabase,o as createProjectPostgresDrizzleDatabase};
@@ -0,0 +1,9 @@
1
+ //#region src/reset.d.ts
2
+ type ResetLocalDbOptions = {
3
+ env?: NodeJS.ProcessEnv;
4
+ };
5
+ declare function resetLocalDb({
6
+ env
7
+ }?: ResetLocalDbOptions): Promise<void>;
8
+ //#endregion
9
+ export { resetLocalDb };
package/dist/reset.js ADDED
@@ -0,0 +1 @@
1
+ import{createLocalPostgresDb as e,startProjectPostgres as t}from"./local-postgres.js";import n from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{sql as r}from"drizzle-orm";async function i({env:i=process.env}={}){try{var a=n();let o=await e({env:a.a(await t({env:i,useSupervisorLease:!0})).env});try{await o.transaction(async e=>{await e.execute(r`drop schema if exists public cascade`),await e.execute(r`drop schema if exists drizzle cascade`),await e.execute(r`create schema public`)}),console.log(`Reset local PostgreSQL schema`)}finally{await o.$client.end()}}catch(e){a.e=e}finally{await a.d()}}export{i as resetLocalDb};
@@ -0,0 +1,11 @@
1
+ //#region src/schema-check.d.ts
2
+ type CheckSchemaPushOptions = {
3
+ env?: NodeJS.ProcessEnv;
4
+ seed?: boolean;
5
+ };
6
+ declare function checkSchemaPush({
7
+ env,
8
+ seed
9
+ }?: CheckSchemaPushOptions): Promise<void>;
10
+ //#endregion
11
+ export { checkSchemaPush };
@@ -0,0 +1 @@
1
+ import{createLocalPostgresDb as e,startTemporaryProjectPostgres as t}from"./local-postgres.js";import n from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{inferSchemaDialect as r,planLocalSchemaPush as i}from"./schema-push.js";import{runProjectSeed as a}from"./seed.js";import{importProjectModule as o}from"@coreframe/config";async function s({env:s=process.env,seed:l=!1}={}){try{var u=n();console.log(`Checking Drizzle schema against a throwaway PostgreSQL database`);let d=u.a(await t({env:s})),f=await o(`src/db/schema.ts`),p=await e({env:d.env});try{let e=r(f);if(e!==`postgres`)throw Error(`Temporary schema push checks require PostgreSQL schema, but found ${e}.`);let t=await i(e,f,p);t.sqlStatements.length===0?console.log(`Drizzle schema check passed with no changes`):(console.log(`Applying ${t.sqlStatements.length} statement(s) to throwaway database`),await t.apply(),console.log(`Drizzle schema check passed`)),l&&(console.log(`Seeding throwaway database`),await a(`default`,{env:d.env}),console.log(`Throwaway database seed check passed`))}finally{await c(p)}}catch(e){u.e=e}finally{await u.d()}}function c(e){return e.$client.end()}export{s as checkSchemaPush};
@@ -0,0 +1,22 @@
1
+ import { DatabaseDialect } from "./client.js";
2
+
3
+ //#region src/schema-push.d.ts
4
+ type SchemaPushPlan = {
5
+ sqlStatements: string[];
6
+ hints: Array<{
7
+ hint: string;
8
+ statement?: string;
9
+ }>;
10
+ apply(): Promise<void>;
11
+ };
12
+ type SchemaPushModule = {
13
+ pushSchema(schema: Record<string, unknown>, db: never, migrationsConfig?: {
14
+ table?: string;
15
+ schema?: string;
16
+ }): Promise<SchemaPushPlan>;
17
+ };
18
+ type ImportSchemaPushModule = (dialect: DatabaseDialect) => Promise<SchemaPushModule>;
19
+ declare function planLocalSchemaPush(dialect: DatabaseDialect, schema: Record<string, unknown>, db: unknown, importModule?: ImportSchemaPushModule): Promise<SchemaPushPlan>;
20
+ declare function inferSchemaDialect(schema: Record<string, unknown>): DatabaseDialect;
21
+ //#endregion
22
+ export { SchemaPushModule, SchemaPushPlan, inferSchemaDialect, planLocalSchemaPush };
@@ -0,0 +1 @@
1
+ import{resolve as e}from"node:path";import{is as t}from"drizzle-orm";import{pathToFileURL as n}from"node:url";import{PgMaterializedView as r,PgTable as i,PgView as a}from"drizzle-orm/pg-core";import{SQLiteTable as o,SQLiteView as s}from"drizzle-orm/sqlite-core";import{resolve as c}from"import-meta-resolve";const l={postgres:`drizzle-kit/payload/postgres`,sqlite:`drizzle-kit/payload/sqlite`};async function u(e,t,n,r=f){let{pushSchema:i}=await r(e);return i(t,n)}function d(e){let t=!1,n=!1;for(let r of Object.values(e))t||=p(r),n||=m(r);if(t&&n)throw Error(`Local database schema mixes PostgreSQL and SQLite entities.`);if(t)return`postgres`;if(n)return`sqlite`;throw Error(`Could not infer local database dialect from src/db/schema.ts.`)}async function f(t){return await import(c(l[t],n(e(`package.json`)).href))}function p(e){return t(e,i)||t(e,a)||t(e,r)}function m(e){return t(e,o)||t(e,s)}export{d as inferSchemaDialect,u as planLocalSchemaPush};
package/dist/seed.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { SeedProfile } from "./config.js";
2
+
3
+ //#region src/seed.d.ts
4
+ type SeedLocalDbOptions = {
5
+ env?: NodeJS.ProcessEnv;
6
+ };
7
+ type RunProjectSeedOptions = {
8
+ env: NodeJS.ProcessEnv;
9
+ seedEntryPoint?: string;
10
+ };
11
+ declare function seedLocalDb(profile?: SeedProfile, {
12
+ env
13
+ }?: SeedLocalDbOptions): Promise<void>;
14
+ declare function runProjectSeed(profile: SeedProfile | undefined, {
15
+ env,
16
+ seedEntryPoint
17
+ }: RunProjectSeedOptions): Promise<void>;
18
+ //#endregion
19
+ export { runProjectSeed, seedLocalDb };
package/dist/seed.js ADDED
@@ -0,0 +1 @@
1
+ import{getSeedProfile as e}from"./config.js";import{startProjectPostgres as t}from"./local-postgres.js";import n from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{importProjectModule as r,readProjectConfig as i}from"@coreframe/config";async function a(r=e(),{env:a=process.env}={}){try{var c=n();let e=await i(),l=s(e);await o(r,{env:c.a(await t({config:e,env:a,useSupervisorLease:!0})).env,seedEntryPoint:l}),console.log(`Seeded local database with "${r}" profile`)}catch(e){c.e=e}finally{await c.d()}}async function o(t=e(),{env:n,seedEntryPoint:a}){a??=s(await i()),await l(n,async()=>{await c(await r(a),a)({env:n,profile:t})})}function s(e){let t=e.database?.seed;if(!t)throw Error(`coreframe.config.ts must configure database.seed before running db seed.`);return t}function c(e,t){let n=e.default??e.seed??e.seedLocalDb;if(!n)throw Error(`${t} must export a default seed function, seed function, or seedLocalDb function.`);return n}async function l(e,t){let n=new Map;for(let[t,r]of Object.entries(e))n.set(t,process.env[t]),r===void 0?delete process.env[t]:process.env[t]=r;try{await t()}finally{for(let[e,t]of n)t===void 0?delete process.env[e]:process.env[e]=t}}export{o as runProjectSeed,a as seedLocalDb};
@@ -0,0 +1,11 @@
1
+ import { SeedProfile } from "./config.js";
2
+
3
+ //#region src/setup.d.ts
4
+ type SetupLocalDbOptions = {
5
+ env?: NodeJS.ProcessEnv;
6
+ };
7
+ declare function setupLocalDb(profile?: SeedProfile, {
8
+ env
9
+ }?: SetupLocalDbOptions): Promise<void>;
10
+ //#endregion
11
+ export { setupLocalDb };
package/dist/setup.js ADDED
@@ -0,0 +1 @@
1
+ import{startProjectPostgres as e}from"./local-postgres.js";import t from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{seedLocalDb as n}from"./seed.js";import{migrateLocalDb as r}from"./migrate.js";import{resetLocalDb as i}from"./reset.js";async function a(a=`default`,{env:o=process.env}={}){try{var s=t();let c=s.a(await e({env:o,useSupervisorLease:!0})).env;await i({env:c}),await r({env:c}),await n(a,{env:c})}catch(e){s.e=e}finally{await s.d()}}export{a as setupLocalDb};
package/package.json CHANGED
@@ -1,13 +1,40 @@
1
1
  {
2
2
  "name": "@coreframe/db",
3
- "version": "0.0.0",
4
- "description": "",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
3
+ "version": "0.1.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/airlock-labs/coreframe.git",
7
+ "directory": "node/db"
8
+ },
9
+ "files": [
10
+ "dist/"
11
+ ],
12
+ "type": "module",
13
+ "exports": {
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "dependencies": {
20
+ "drizzle-orm": "1.0.0-rc.4",
21
+ "import-meta-resolve": "^4.2.0",
22
+ "local-postgres": "0.3.1",
23
+ "nano-spawn": "^2.1.0",
24
+ "@coreframe/config": "^0.1.0",
25
+ "@coreframe/dev-supervisor": "^0.1.0"
8
26
  },
9
- "keywords": [],
10
- "author": "",
11
- "license": "All rights reserved",
12
- "type": "commonjs"
13
- }
27
+ "devDependencies": {
28
+ "@types/node": "^26.1.0",
29
+ "tsdown": "0.22.3",
30
+ "typescript": "6.0.3",
31
+ "vitest": "^4.1.9"
32
+ },
33
+ "scripts": {
34
+ "build": "tsdown",
35
+ "test": "vitest run --reporter=minimal",
36
+ "typecheck": "tsc --noEmit -p tsconfig.json",
37
+ "format": "oxlint --fix && oxfmt",
38
+ "lint": "oxlint"
39
+ }
40
+ }
package/readme.md DELETED
@@ -1 +0,0 @@
1
- Coming soon...