@schemavaults/dbh 0.10.1 → 0.11.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,244 @@
1
+ ---
2
+ name: database-migrations
3
+ description: Authoring, building, validating, and running PostgreSQL database migrations with the @schemavaults/dbh package. Use when a project depends on @schemavaults/dbh and you are creating or editing Kysely migration files, setting up a migrations/ directory, or when the user mentions migrations, up()/down(), schema changes, or the dbh CLI's migrate / build-db-migrations / validate-migration-directory commands.
4
+ ---
5
+
6
+ # Database Migrations with @schemavaults/dbh
7
+
8
+ `@schemavaults/dbh` provides [Kysely](https://kysely.dev/) migrations for
9
+ PostgreSQL, applied through the `dbh` CLI. Migrations are opinionated: every file
10
+ is a numbered module that exports an `up()` and a `down()` function. TypeScript
11
+ source migrations are **built** to JavaScript first, then **applied** with the
12
+ CLI.
13
+
14
+ Invoke the CLI with your package runner. Use **`bunx @schemavaults/dbh`** for
15
+ **validating and building** migrations — `build-db-migrations` uses Bun's
16
+ bundler and requires Bun anyway. Use **`npx @schemavaults/dbh`** for **running /
17
+ applying** migrations (`migrate` and `reverse`): most PostgreSQL drivers are
18
+ built for Node.js rather than Bun, so apply migrations on the Node runtime.
19
+
20
+ ## One-time setup (for consumers)
21
+
22
+ Migrations import the `sql` template tag from `@/sql` rather than directly from
23
+ the package. This indirection is required by the build step (see the note under
24
+ "Building migrations"), so configure it once:
25
+
26
+ 1. **Create a local `sql` module** somewhere in your source tree, e.g.
27
+ `./src/db/sql.ts`, that re-exports the tag from the package:
28
+
29
+ ```ts
30
+ // src/db/sql.ts
31
+ export { sql, sql as default } from "@schemavaults/dbh/sql";
32
+ export type * from "@schemavaults/dbh/sql";
33
+ ```
34
+
35
+ 2. **Configure the `@/sql` path alias** in your `tsconfig.json` so migration
36
+ sources typecheck and resolve:
37
+
38
+ ```jsonc
39
+ {
40
+ "compilerOptions": {
41
+ "baseUrl": ".",
42
+ "paths": {
43
+ "@/sql": ["./src/db/sql.ts"]
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ 3. **Create a migrations directory**, e.g. `./src/db/migrations/`, and add your
50
+ numbered migration files there.
51
+
52
+ ## Migration file format
53
+
54
+ Each migration is a single file in your migrations directory. The rules are:
55
+
56
+ 1. **The directory is non-empty.**
57
+ 2. **Each file name is prefixed with a 5-digit migration number**, followed by a
58
+ short kebab-case description, e.g. `00000-template-migration.ts`,
59
+ `00001-create-users-table.ts`. The number defines apply order.
60
+ 3. **Each module exports an `up(db)` and a `down(db)` function.** `up()` applies
61
+ the change; `down()` must reverse it exactly so migrations can be rolled back.
62
+ 4. **Migration numbers are unique** — never reuse a number. If two branches both
63
+ add `00040-*.ts`, that collision must be resolved by renumbering one of them
64
+ before merge.
65
+
66
+ Both `up` and `down` receive a `Kysely<any>` instance and return a `Promise`.
67
+ Import the `Kysely` type from the package: `import type { Kysely } from "@schemavaults/dbh"`.
68
+
69
+ ### Example: using the `Kysely<any>` query builder
70
+
71
+ Prefer the typed query builder for schema operations:
72
+
73
+ ```ts
74
+ // 00001-create-users-table.ts
75
+ import type { Kysely } from "@schemavaults/dbh";
76
+
77
+ export async function up(db: Kysely<any>): Promise<void> {
78
+ await db.schema
79
+ .createTable("users")
80
+ .addColumn("user_id", "uuid", (col) => col.primaryKey())
81
+ .addColumn("email", "text", (col) => col.notNull().unique())
82
+ .addColumn("created_at", "bigint", (col) => col.notNull())
83
+ .execute();
84
+ }
85
+
86
+ export async function down(db: Kysely<any>): Promise<void> {
87
+ await db.schema.dropTable("users").execute();
88
+ }
89
+ ```
90
+
91
+ ### Example: using the `sql` template tag
92
+
93
+ For statements the builder can't express (or raw DDL), import `sql` from
94
+ `@/sql` (your local module from setup, which re-exports Kysely's `sql` tag) and
95
+ call `.execute(db)`:
96
+
97
+ ```ts
98
+ // 00002-create-squirrels-table.ts
99
+ import type { Kysely } from "@schemavaults/dbh";
100
+ import { sql } from "@/sql";
101
+
102
+ export async function up(db: Kysely<any>): Promise<void> {
103
+ await sql`
104
+ CREATE TABLE IF NOT EXISTS EXAMPLE_SQUIRRELS (
105
+ squirrel_id UUID PRIMARY KEY,
106
+ squirrel_name TEXT NOT NULL,
107
+ created_at BIGINT NOT NULL
108
+ );
109
+ `.execute(db);
110
+
111
+ // Always interpolate values via ${...}; the sql tag parameterizes them.
112
+ await sql`CREATE INDEX squirrels_name_idx ON EXAMPLE_SQUIRRELS (squirrel_name);`.execute(
113
+ db,
114
+ );
115
+ }
116
+
117
+ export async function down(db: Kysely<any>): Promise<void> {
118
+ await sql`DROP TABLE IF EXISTS EXAMPLE_SQUIRRELS;`.execute(db);
119
+ }
120
+ ```
121
+
122
+ > Important: migration files must **always** import `sql` from `@/sql`, never
123
+ > directly from `@schemavaults/dbh/sql`. The `build-db-migrations` step rewrites
124
+ > the literal `@/sql` import specifier to a relative path pointing at the built,
125
+ > standalone `sql.js`, so the import must be written exactly as `@/sql` for the
126
+ > build to work. (This is why the one-time setup configures the `@/sql` alias.)
127
+
128
+ ### Empty template migration
129
+
130
+ A no-op migration is valid (useful as a starting template):
131
+
132
+ ```ts
133
+ // 00000-template-migration.ts
134
+ import type { Kysely } from "@schemavaults/dbh";
135
+
136
+ export async function up(
137
+ db: Kysely<any>, // eslint-disable-line @typescript-eslint/no-unused-vars
138
+ ): Promise<void> {}
139
+
140
+ export async function down(
141
+ db: Kysely<any>, // eslint-disable-line @typescript-eslint/no-unused-vars
142
+ ): Promise<void> {}
143
+ ```
144
+
145
+ ## Validating migrations
146
+
147
+ Before building or applying, assert your source migrations directory is
148
+ well-formed. The `validate-migration-directory` command checks all four rules
149
+ above and exits `0` when valid, non-zero otherwise (good for CI / pre-commit):
150
+
151
+ ```bash
152
+ bunx @schemavaults/dbh validate-migration-directory ./src/db/migrations
153
+ ```
154
+
155
+ It reports each problem with an `[ERROR]`/`[WARN]` prefix:
156
+ - empty directory,
157
+ - a file missing the 5-digit prefix,
158
+ - a module missing `up()` or `down()`,
159
+ - duplicate migration numbers (branch collisions).
160
+
161
+ Treat duplicate numbers as warnings (non-fatal) with `--duplicates-as-warnings`.
162
+
163
+ ## Building migrations
164
+
165
+ TypeScript migrations must be compiled to JavaScript before they're applied
166
+ (the `migrate` step runs on Node and imports `.js`). The `build-db-migrations`
167
+ command uses Bun's bundler and also builds the standalone `sql` module the
168
+ migrations depend on. Point `--sql-module` at the local `sql.ts` you created
169
+ during setup:
170
+
171
+ ```bash
172
+ bunx @schemavaults/dbh build-db-migrations ./src/db/migrations \
173
+ --outdir ./dist/migrations \
174
+ --sql-module ./src/db/sql.ts \
175
+ --sql-outdir ./dist
176
+ ```
177
+
178
+ Key options:
179
+ - `<migrations-src>` — directory of `.ts` migration sources (positional).
180
+ - `--outdir <dir>` — where compiled `.js` migrations are written (required).
181
+ - `--sql-module <path>` — path to your local `sql.ts` module to build alongside (required).
182
+ - `--sql-outdir <dir>` — where the built `sql.js` goes (defaults to the parent of `--outdir`).
183
+ - `--external <pkg...>` — packages to keep external (default: `@schemavaults/dbh`, `kysely`).
184
+
185
+ `build-db-migrations` requires `bun` to be installed and on the PATH.
186
+
187
+ ## Running migrations
188
+
189
+ Apply built migrations with `migrate`, and roll back with `reverse`. Both take
190
+ the **built** migration folder and require an `--environment`; credentials come
191
+ from `process.env` (or an `--env-file`). Run these with **`npx`** (Node.js):
192
+ most PostgreSQL drivers target Node rather than Bun.
193
+
194
+ ```bash
195
+ # Apply all pending migrations (to latest):
196
+ npx @schemavaults/dbh migrate ./dist/migrations --environment production --env-file ./.env.production
197
+
198
+ # Apply up to a specific version (the migration name w/o extension):
199
+ npx @schemavaults/dbh migrate ./dist/migrations 00001-create-users-table --environment staging
200
+
201
+ # Roll back down to a target version:
202
+ npx @schemavaults/dbh reverse ./dist/migrations 00000-template-migration --environment staging
203
+ ```
204
+
205
+ Options for `migrate` / `reverse`:
206
+ - `<folder>` — path to the built migration folder (positional).
207
+ - `[version]` / `<version>` — target migration name; `migrate` defaults to latest, `reverse` requires it.
208
+ - `-e, --environment <env>` — `development | test | staging | production` (required).
209
+ - `--ws-proxy-url <url>` — custom Neon-compatible WebSocket proxy URL.
210
+ - `--env-file <path>` — load DB credentials from a `.env` file first.
211
+
212
+ Each result line prints as `[Up|Down] <migrationName>: <Success|Error|NotExecuted>`.
213
+
214
+ ### Programmatic API
215
+
216
+ The same operations are available from `@schemavaults/dbh/migrate` for tests or
217
+ custom scripts, using the adapter's Kysely instance:
218
+
219
+ ```ts
220
+ import { migrate, reverse } from "@schemavaults/dbh/migrate";
221
+
222
+ await migrate({ db: adapter.db, migrationFolder, version /* optional */ });
223
+ await reverse({ db: adapter.db, migrationFolder, version });
224
+ ```
225
+
226
+ ## Typical end-to-end flow
227
+
228
+ ```bash
229
+ # 1. Validate the source migrations directory.
230
+ bunx @schemavaults/dbh validate-migration-directory ./src/db/migrations
231
+
232
+ # 2. Build .ts migrations (+ sql module) to .js.
233
+ bunx @schemavaults/dbh build-db-migrations ./src/db/migrations \
234
+ --outdir ./dist/migrations --sql-module ./src/db/sql.ts --sql-outdir ./dist
235
+
236
+ # 3. Apply the built migrations (npx / Node.js — pg drivers target Node).
237
+ npx @schemavaults/dbh migrate ./dist/migrations --environment production --env-file ./.env.production
238
+ ```
239
+
240
+ ## Required environment variables (for migrate/reverse)
241
+
242
+ `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_URL`, `POSTGRES_HOST`,
243
+ `POSTGRES_PORT`, `POSTGRES_DATABASE` (and optional `POSTGRES_URL_NON_POOLING`).
244
+ Set `SCHEMAVAULTS_DBH_DEBUG=true` for verbose debug logging.
package/README.md CHANGED
@@ -20,7 +20,7 @@ Ensure that you have both `postgres` and a `postgres-ws-proxy` containers runnin
20
20
 
21
21
  You'll likely want to replace the `build:` sections for the services in the e2e test example `.yml` file with `image:`. For example, use `image: postgres:17.7` for the `postgres` service. For the proxy, you can pull the docker image from `ghcr.io/schemavaults/dbh/postgres-ws-proxy`; use the version number equal to your `@schemavaults/dbh` npm package installation:
22
22
  ```md
23
- # NPM Package: @schemavaults/dbh@0.10.1 => ghcr.io/schemavaults/dbh/postgres-ws-proxy:0.10.1
23
+ # NPM Package: @schemavaults/dbh@0.11.0 => ghcr.io/schemavaults/dbh/postgres-ws-proxy:0.11.0
24
24
  ```
25
25
 
26
26
  ### In your application server code
@@ -40,6 +40,20 @@ npx @schemavaults/dbh --help
40
40
  # or `bun run cli --help` if you have the dbh source repository as your working directory
41
41
  ```
42
42
 
43
+ #### Validate the shape of a migrations directory
44
+ ```bash
45
+ # assert the migrations directory is well-formed:
46
+ # - non-empty
47
+ # - every file is prefixed with a 5-digit migration number (e.g. 00000-my-migration.ts)
48
+ # - every module exports an up() and down() function
49
+ # - there are no duplicate migration numbers (branch collisions, e.g. 00040-a.ts and 00040-b.ts)
50
+ # exits 0 when the directory is valid, non-zero otherwise.
51
+ bunx @schemavaults/dbh validate-migration-directory ./src/db/migrations
52
+
53
+ # treat duplicate migration numbers as warnings instead of errors (still exits 0)
54
+ bunx @schemavaults/dbh validate-migration-directory ./src/db/migrations --duplicates-as-warnings
55
+ ```
56
+
43
57
  #### Build example database migrations with the CLI
44
58
  ```bash
45
59
  mkdir ./tests/tmp
@@ -1,6 +1,6 @@
1
- import type { BaseInitializablePostgresDatabaseCredentials, PostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials";
2
- import { IDatabaseHandler } from "../types/IDatabaseHandler";
3
- import { type SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment";
1
+ import type { BaseInitializablePostgresDatabaseCredentials, PostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials.js";
2
+ import { IDatabaseHandler } from "../types/IDatabaseHandler.js";
3
+ import { type SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment.js";
4
4
  import type { Dialect } from "kysely";
5
5
  import { Kysely } from "kysely";
6
6
  export interface IAbstractSchemaVaultsDbhAdapterConstructorOpts {
@@ -1,7 +1,7 @@
1
- import { isValidAppEnvironment, } from "../types/SchemaVaultsAppEnvironment";
2
- import isDbhInDebugMode from "../utils/isDbhInDebugMode";
3
- import parseDatabaseCredentials from "../utils/parseDatabaseCredentials";
4
- import parseDatabaseCredentialsFromEnv from "../utils/parseDatabaseCredentialsFromEnv";
1
+ import { isValidAppEnvironment, } from "../types/SchemaVaultsAppEnvironment.js";
2
+ import isDbhInDebugMode from "../utils/isDbhInDebugMode.js";
3
+ import parseDatabaseCredentials from "../utils/parseDatabaseCredentials.js";
4
+ import parseDatabaseCredentialsFromEnv from "../utils/parseDatabaseCredentialsFromEnv.js";
5
5
  import { Kysely } from "kysely";
6
6
  export default class AbstractSchemaVaultsDbhAdapter {
7
7
  credentials;
@@ -1,6 +1,6 @@
1
- import type { IDatabaseHandler } from "../types/IDatabaseHandler";
2
- import type { IAbstractSchemaVaultsDbhAdapterConstructorOpts } from "../adapters/abstract-schemavaults-dbh-adapter";
3
- import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter";
1
+ import type { IDatabaseHandler } from "../types/IDatabaseHandler.js";
2
+ import type { IAbstractSchemaVaultsDbhAdapterConstructorOpts } from "../adapters/abstract-schemavaults-dbh-adapter.js";
3
+ import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter.js";
4
4
  import { type Dialect } from "kysely";
5
5
  export interface ISchemaVaultsPostgresAdapterConstructorOpts extends IAbstractSchemaVaultsDbhAdapterConstructorOpts {
6
6
  }
@@ -1,7 +1,7 @@
1
1
  // schemavaults-postgres-adapter.ts
2
2
  // This file sets up kysely to connect to postgres
3
- import parsePort from "../utils/parsePort";
4
- import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter";
3
+ import parsePort from "../utils/parsePort.js";
4
+ import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter.js";
5
5
  import { PostgresDialect, } from "kysely";
6
6
  import { Pool } from "pg";
7
7
  export class SchemaVaultsPostgresAdapter extends AbstractSchemaVaultsDbhAdapter {
@@ -1,7 +1,7 @@
1
- import { type WsProxyUrlGenerator } from "../utils/getPostgresNeonWsProxyUrl";
2
- import type { IDatabaseHandler } from "../types/IDatabaseHandler";
3
- import type { IAbstractSchemaVaultsDbhAdapterConstructorOpts } from "../adapters/abstract-schemavaults-dbh-adapter";
4
- import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter";
1
+ import { type WsProxyUrlGenerator } from "../utils/getPostgresNeonWsProxyUrl.js";
2
+ import type { IDatabaseHandler } from "../types/IDatabaseHandler.js";
3
+ import type { IAbstractSchemaVaultsDbhAdapterConstructorOpts } from "../adapters/abstract-schemavaults-dbh-adapter.js";
4
+ import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter.js";
5
5
  import type { Dialect } from "kysely";
6
6
  export interface ISchemaVaultsPostgresNeonProxyAdapterConstructorOpts extends IAbstractSchemaVaultsDbhAdapterConstructorOpts {
7
7
  /**
@@ -15,4 +15,4 @@ export declare class SchemaVaultsPostgresNeonProxyAdapter<KyselyTablesType exten
15
15
  constructor(opts: ISchemaVaultsPostgresNeonProxyAdapterConstructorOpts);
16
16
  }
17
17
  export default SchemaVaultsPostgresNeonProxyAdapter;
18
- export type { WsProxyUrlGenerator, IGetPostgresNeonWsProxyUrlOpts, } from "../utils/getPostgresNeonWsProxyUrl";
18
+ export type { WsProxyUrlGenerator, IGetPostgresNeonWsProxyUrlOpts, } from "../utils/getPostgresNeonWsProxyUrl.js";
@@ -2,9 +2,9 @@
2
2
  // This file sets up kysely to connect to postgres via a Neon websocket proxy
3
3
  // (allows database usage from a serverless/edge environment)
4
4
  import { NeonDialect } from "kysely-neon";
5
- import getPostgresNeonWsProxyUrl from "../utils/getPostgresNeonWsProxyUrl";
6
- import parsePort from "../utils/parsePort";
7
- import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter";
5
+ import getPostgresNeonWsProxyUrl from "../utils/getPostgresNeonWsProxyUrl.js";
6
+ import parsePort from "../utils/parsePort.js";
7
+ import AbstractSchemaVaultsDbhAdapter from "../adapters/abstract-schemavaults-dbh-adapter.js";
8
8
  export class SchemaVaultsPostgresNeonProxyAdapter extends AbstractSchemaVaultsDbhAdapter {
9
9
  initializeDbDialect(opts) {
10
10
  const debug = this.debug;
@@ -1,5 +1,5 @@
1
- import type { SchemaVaultsPostgresAdapter, ISchemaVaultsPostgresAdapterConstructorOpts } from "./adapters/schemavaults-postgres-adapter";
2
- import type { SchemaVaultsPostgresNeonProxyAdapter, ISchemaVaultsPostgresNeonProxyAdapterConstructorOpts } from "./adapters/schemavaults-postgres-neon-proxy-adapter";
1
+ import type { SchemaVaultsPostgresAdapter, ISchemaVaultsPostgresAdapterConstructorOpts } from "./adapters/schemavaults-postgres-adapter.js";
2
+ import type { SchemaVaultsPostgresNeonProxyAdapter, ISchemaVaultsPostgresNeonProxyAdapterConstructorOpts } from "./adapters/schemavaults-postgres-neon-proxy-adapter.js";
3
3
  /**
4
4
  * Asynchronously construct a SchemaVaults database handler for the given
5
5
  * adapter type, dynamically importing only the adapter that was requested.
@@ -1,7 +1,7 @@
1
1
  // create-dbh.ts
2
2
  const ADAPTER_MAP = {
3
- postgres: async () => await import("./adapters/schemavaults-postgres-adapter").then((mod) => mod.SchemaVaultsPostgresAdapter),
4
- "postgres-neon-proxy": async () => await import("./adapters/schemavaults-postgres-neon-proxy-adapter").then((mod) => mod.SchemaVaultsPostgresNeonProxyAdapter),
3
+ postgres: async () => await import("./adapters/schemavaults-postgres-adapter.js").then((mod) => mod.SchemaVaultsPostgresAdapter),
4
+ "postgres-neon-proxy": async () => await import("./adapters/schemavaults-postgres-neon-proxy-adapter.js").then((mod) => mod.SchemaVaultsPostgresNeonProxyAdapter),
5
5
  };
6
6
  export default async function createDbh(adapter_type, opts) {
7
7
  if (typeof adapter_type !== "string") {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { default as default, default as createDbh } from "./create-dbh";
2
- export { SchemaVaultsPostgresNeonProxyAdapter } from "./adapters/schemavaults-postgres-neon-proxy-adapter";
3
- export type { WsProxyUrlGenerator, IGetPostgresNeonWsProxyUrlOpts, } from "./adapters/schemavaults-postgres-neon-proxy-adapter";
4
- export { SchemaVaultsPostgresAdapter } from "./adapters/schemavaults-postgres-adapter";
5
- export { sql } from "./sql";
1
+ export { default as default, default as createDbh } from "./create-dbh.js";
2
+ export { SchemaVaultsPostgresNeonProxyAdapter } from "./adapters/schemavaults-postgres-neon-proxy-adapter.js";
3
+ export type { WsProxyUrlGenerator, IGetPostgresNeonWsProxyUrlOpts, } from "./adapters/schemavaults-postgres-neon-proxy-adapter.js";
4
+ export { SchemaVaultsPostgresAdapter } from "./adapters/schemavaults-postgres-adapter.js";
5
+ export { sql } from "./sql.js";
6
6
  export type * from "kysely";
package/dist/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  // index.ts
2
- export { default as default, default as createDbh } from "./create-dbh";
2
+ export { default as default, default as createDbh } from "./create-dbh.js";
3
3
  // Postgres Neon Proxy Adapter (for use in serverless environments)
4
- export { SchemaVaultsPostgresNeonProxyAdapter } from "./adapters/schemavaults-postgres-neon-proxy-adapter";
4
+ export { SchemaVaultsPostgresNeonProxyAdapter } from "./adapters/schemavaults-postgres-neon-proxy-adapter.js";
5
5
  // Postgres Adapter (for use in standard Node.js environments)
6
- export { SchemaVaultsPostgresAdapter } from "./adapters/schemavaults-postgres-adapter";
6
+ export { SchemaVaultsPostgresAdapter } from "./adapters/schemavaults-postgres-adapter.js";
7
7
  // Kysely SQL builder + types
8
- export { sql } from "./sql";
8
+ export { sql } from "./sql.js";
9
9
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,3 @@
1
- import type { BaseInitializablePostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials";
1
+ import type { BaseInitializablePostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials.js";
2
2
  declare function buildPostgresUrl(opts: Pick<BaseInitializablePostgresDatabaseCredentials, "POSTGRES_HOST" | "POSTGRES_PORT" | "POSTGRES_USER" | "POSTGRES_PASSWORD" | "POSTGRES_DATABASE">): string;
3
3
  export default buildPostgresUrl;
@@ -1,3 +1,3 @@
1
- import { type SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment";
1
+ import { type SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment.js";
2
2
  export declare function getAppEnvironment(): SchemaVaultsAppEnvironment;
3
3
  export default getAppEnvironment;
@@ -1,4 +1,4 @@
1
- import { isValidAppEnvironment, } from "../types/SchemaVaultsAppEnvironment";
1
+ import { isValidAppEnvironment, } from "../types/SchemaVaultsAppEnvironment.js";
2
2
  export function getAppEnvironment() {
3
3
  const env = process.env["SCHEMAVAULTS_APP_ENVIRONMENT"];
4
4
  if (isValidAppEnvironment(env)) {
@@ -1,4 +1,4 @@
1
- import { type SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment";
1
+ import { type SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment.js";
2
2
  export interface IGetPostgresNeonWsProxyUrlOpts {
3
3
  pg_host: string;
4
4
  environment: SchemaVaultsAppEnvironment;
@@ -1,4 +1,4 @@
1
- import { isValidAppEnvironment, } from "../types/SchemaVaultsAppEnvironment";
1
+ import { isValidAppEnvironment, } from "../types/SchemaVaultsAppEnvironment.js";
2
2
  export function getPostgresNeonWsProxyUrl({ pg_host, environment, ...opts }) {
3
3
  const debug = opts.debug ?? false;
4
4
  if (debug) {
@@ -1,4 +1,4 @@
1
- import type { SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment";
1
+ import type { SchemaVaultsAppEnvironment } from "../types/SchemaVaultsAppEnvironment.js";
2
2
  declare global {
3
3
  namespace NodeJS {
4
4
  interface ProcessEnv {
@@ -1,3 +1,3 @@
1
- import type { BaseInitializablePostgresDatabaseCredentials, PostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials";
1
+ import type { BaseInitializablePostgresDatabaseCredentials, PostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials.js";
2
2
  declare function parseDatabaseCredentials(minimum_credentials: Record<string, boolean | string | number | undefined> | BaseInitializablePostgresDatabaseCredentials, debug?: boolean): PostgresDatabaseCredentials;
3
3
  export default parseDatabaseCredentials;
@@ -1,5 +1,5 @@
1
- import maybeStripQuotes from "../utils/maybeStripQuotes";
2
- import buildPostgresUrl from "./buildPostgresUrl";
1
+ import maybeStripQuotes from "../utils/maybeStripQuotes.js";
2
+ import buildPostgresUrl from "./buildPostgresUrl.js";
3
3
  function parseDatabaseCredentials(minimum_credentials, debug = false) {
4
4
  if (typeof minimum_credentials !== "object") {
5
5
  throw new Error("Did not receive an object to parse database credentials from!");
@@ -1,3 +1,3 @@
1
- import type { PostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials";
1
+ import type { PostgresDatabaseCredentials } from "../types/PostgresDatabaseCredentials.js";
2
2
  export declare function parseDatabaseCredentialsFromEnv(env: Record<string, string | undefined>, debug?: boolean): PostgresDatabaseCredentials;
3
3
  export default parseDatabaseCredentialsFromEnv;
@@ -1,4 +1,4 @@
1
- import parseDatabaseCredentials from "./parseDatabaseCredentials";
1
+ import parseDatabaseCredentials from "./parseDatabaseCredentials.js";
2
2
  export function parseDatabaseCredentialsFromEnv(env, debug = false) {
3
3
  return parseDatabaseCredentials(env, debug);
4
4
  }
@@ -0,0 +1,35 @@
1
+ export type MigrationValidationLevel = "error" | "warning";
2
+ export interface MigrationValidationIssue {
3
+ level: MigrationValidationLevel;
4
+ message: string;
5
+ /** The offending file name (relative to the migration directory), if any. */
6
+ file?: string;
7
+ }
8
+ export interface ValidateMigrationDirectoryOptions {
9
+ /**
10
+ * When true, duplicate migration numbers are reported as warnings instead of
11
+ * errors (they will not, on their own, cause validation to fail).
12
+ * @default false
13
+ */
14
+ duplicatesAsWarnings?: boolean;
15
+ }
16
+ export interface ValidateMigrationDirectoryResult {
17
+ /** True when there are no `error`-level issues. */
18
+ ok: boolean;
19
+ /** The absolute path that was validated. */
20
+ directory: string;
21
+ /** The migration file names that were considered (relative to `directory`). */
22
+ migrationFiles: string[];
23
+ issues: MigrationValidationIssue[];
24
+ }
25
+ /**
26
+ * Validates the shape of an opinionated Kysely migrations directory.
27
+ *
28
+ * Asserts that the directory:
29
+ * - exists and is non-empty,
30
+ * - contains only files prefixed with a 5-digit migration number,
31
+ * - has no duplicate migration numbers (branch collisions), and
32
+ * - exports an `up()` and `down()` function from every migration module.
33
+ */
34
+ export declare function validateMigrationDirectory(directory: string, options?: ValidateMigrationDirectoryOptions): Promise<ValidateMigrationDirectoryResult>;
35
+ export default validateMigrationDirectory;