@ingram-tech/nk-db 0.4.0 → 0.6.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.
- package/dist/id.d.ts +63 -0
- package/dist/id.d.ts.map +1 -0
- package/dist/id.js +138 -0
- package/dist/id.js.map +1 -0
- package/dist/migrate-bin.d.ts +3 -0
- package/dist/migrate-bin.d.ts.map +1 -0
- package/dist/migrate-bin.js +56 -0
- package/dist/migrate-bin.js.map +1 -0
- package/dist/migrate.d.ts +90 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +209 -0
- package/dist/migrate.js.map +1 -0
- package/dist/pglite/index.d.ts +7 -0
- package/dist/pglite/index.d.ts.map +1 -1
- package/dist/pglite/index.js +25 -1
- package/dist/pglite/index.js.map +1 -1
- package/package.json +12 -3
package/dist/id.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Ingram id codec — a UUIDv7 and its base58 skin. It lives here in nk-db
|
|
3
|
+
* (the lowest package in the graph) behind the `@ingram-tech/nk-db/id` subpath,
|
|
4
|
+
* so it stays `node:crypto`-only — no `pg` / `drizzle` — and any site can mint
|
|
5
|
+
* ids without pulling a heavier slice.
|
|
6
|
+
*
|
|
7
|
+
* The Python twin lives in cloud.ingram.tech's `v1/core.py` (`new_id`); the
|
|
8
|
+
* byte → string vectors in `id.test.ts` and that repo's `tests/test_ids.py` are
|
|
9
|
+
* kept identical, so a stored UUIDv7 and an `agt_` / `smt_` id from the API are
|
|
10
|
+
* the same encoding of the same 16 bytes. That cross-impl contract is the most
|
|
11
|
+
* important property of this file — keep the vectors in lockstep.
|
|
12
|
+
*
|
|
13
|
+
* Store the hyphenated UUIDv7 at rest (uuid columns stay native and time-ordered
|
|
14
|
+
* for index locality) and use {@link toPrefixedId} to skin it as a prefixed
|
|
15
|
+
* base58 id for the wire / display, {@link fromPrefixedId} to recover it.
|
|
16
|
+
* {@link base58Id} mints a fresh one directly; {@link createIdRegistry} builds a
|
|
17
|
+
* typed, prefix-validated set of helpers for a project's entities.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Mint a **UUIDv7** (RFC 9562): a 48-bit Unix-ms timestamp prefix + random tail,
|
|
21
|
+
* version `7`, variant `10`. UUID-shaped (drops straight into a `uuid` column)
|
|
22
|
+
* while staying time-ordered for index locality. Used as Better Auth's
|
|
23
|
+
* `advanced.database.generateId`. Node/Bun's `randomUUID` is v4-only, so we lay
|
|
24
|
+
* the bytes out by hand.
|
|
25
|
+
*/
|
|
26
|
+
export declare const uuidGenerateId: () => string;
|
|
27
|
+
/** Skin a stored hyphenated UUIDv7 as a prefixed base58 id, e.g. `team_…`. */
|
|
28
|
+
export declare function toPrefixedId(uuid: string, prefix: string): string;
|
|
29
|
+
/** Inverse of {@link toPrefixedId}: recover the hyphenated UUIDv7. */
|
|
30
|
+
export declare function fromPrefixedId(id: string): string;
|
|
31
|
+
/** Mint a fresh prefixed base58 id (UUIDv7 core), for text-id sites / API parity. */
|
|
32
|
+
export declare function base58Id(prefix: string): string;
|
|
33
|
+
/** Typed helpers for one entity's prefixed ids — built by {@link createIdRegistry}. */
|
|
34
|
+
export interface IdHelper {
|
|
35
|
+
/** This entity's prefix, e.g. `"agt"` (no trailing underscore). */
|
|
36
|
+
readonly prefix: string;
|
|
37
|
+
/** Mint a fresh prefixed id (new UUIDv7 core). */
|
|
38
|
+
mint(): string;
|
|
39
|
+
/** Skin a stored hyphenated UUIDv7 as this entity's prefixed id. */
|
|
40
|
+
encode(uuid: string): string;
|
|
41
|
+
/** Recover the hyphenated UUIDv7; throws if the prefix / shape doesn't match. */
|
|
42
|
+
decode(id: string): string;
|
|
43
|
+
/** Whether `id` is a well-formed prefixed id for this entity. */
|
|
44
|
+
is(id: string): boolean;
|
|
45
|
+
}
|
|
46
|
+
/** The map returned by {@link createIdRegistry}: one {@link IdHelper} per key. */
|
|
47
|
+
export type IdRegistry<K extends string> = Record<K, IdHelper>;
|
|
48
|
+
/**
|
|
49
|
+
* Build a typed, prefix-validated id registry for a project's entities — one
|
|
50
|
+
* place to declare every prefix instead of hand-rolling encode/decode wrappers:
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* const ids = createIdRegistry({ org: "org", agent: "agt", session: "cs" });
|
|
54
|
+
* ids.org.mint(); // "org_3k9…"
|
|
55
|
+
* ids.org.encode(uuid); // "org_…"
|
|
56
|
+
* ids.org.decode("org_…"); // uuid — throws on a wrong / missing prefix
|
|
57
|
+
* ids.agent.is(someId); // boolean
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export declare function createIdRegistry<const T extends Record<string, string>>(prefixes: T): {
|
|
61
|
+
[K in keyof T]: IdHelper;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=id.d.ts.map
|
package/dist/id.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.d.ts","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,QAAO,MAYjC,CAAC;AAuDF,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,qFAAqF;AACrF,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,uFAAuF;AACvF,MAAM,WAAW,QAAQ;IACxB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kDAAkD;IAClD,IAAI,IAAI,MAAM,CAAC;IACf,oEAAoE;IACpE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,iFAAiF;IACjF,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,iEAAiE;IACjE,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,kFAAkF;AAClF,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,MAAM,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AAiB/D;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACtE,QAAQ,EAAE,CAAC,GACT;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ;CAAE,CAM9B"}
|
package/dist/id.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
2
|
+
/**
|
|
3
|
+
* The Ingram id codec — a UUIDv7 and its base58 skin. It lives here in nk-db
|
|
4
|
+
* (the lowest package in the graph) behind the `@ingram-tech/nk-db/id` subpath,
|
|
5
|
+
* so it stays `node:crypto`-only — no `pg` / `drizzle` — and any site can mint
|
|
6
|
+
* ids without pulling a heavier slice.
|
|
7
|
+
*
|
|
8
|
+
* The Python twin lives in cloud.ingram.tech's `v1/core.py` (`new_id`); the
|
|
9
|
+
* byte → string vectors in `id.test.ts` and that repo's `tests/test_ids.py` are
|
|
10
|
+
* kept identical, so a stored UUIDv7 and an `agt_` / `smt_` id from the API are
|
|
11
|
+
* the same encoding of the same 16 bytes. That cross-impl contract is the most
|
|
12
|
+
* important property of this file — keep the vectors in lockstep.
|
|
13
|
+
*
|
|
14
|
+
* Store the hyphenated UUIDv7 at rest (uuid columns stay native and time-ordered
|
|
15
|
+
* for index locality) and use {@link toPrefixedId} to skin it as a prefixed
|
|
16
|
+
* base58 id for the wire / display, {@link fromPrefixedId} to recover it.
|
|
17
|
+
* {@link base58Id} mints a fresh one directly; {@link createIdRegistry} builds a
|
|
18
|
+
* typed, prefix-validated set of helpers for a project's entities.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Mint a **UUIDv7** (RFC 9562): a 48-bit Unix-ms timestamp prefix + random tail,
|
|
22
|
+
* version `7`, variant `10`. UUID-shaped (drops straight into a `uuid` column)
|
|
23
|
+
* while staying time-ordered for index locality. Used as Better Auth's
|
|
24
|
+
* `advanced.database.generateId`. Node/Bun's `randomUUID` is v4-only, so we lay
|
|
25
|
+
* the bytes out by hand.
|
|
26
|
+
*/
|
|
27
|
+
export const uuidGenerateId = () => {
|
|
28
|
+
const bytes = randomBytes(16);
|
|
29
|
+
const ts = Date.now();
|
|
30
|
+
bytes[0] = Math.floor(ts / 2 ** 40) & 0xff;
|
|
31
|
+
bytes[1] = Math.floor(ts / 2 ** 32) & 0xff;
|
|
32
|
+
bytes[2] = Math.floor(ts / 2 ** 24) & 0xff;
|
|
33
|
+
bytes[3] = Math.floor(ts / 2 ** 16) & 0xff;
|
|
34
|
+
bytes[4] = Math.floor(ts / 2 ** 8) & 0xff;
|
|
35
|
+
bytes[5] = ts & 0xff;
|
|
36
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x70; // version 7
|
|
37
|
+
bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80; // variant 10
|
|
38
|
+
return bytesToUuid(bytes);
|
|
39
|
+
};
|
|
40
|
+
const B58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
41
|
+
// ceil(128 / log2(58)): a 16-byte value never needs more than 22 digits. We
|
|
42
|
+
// left-pad to it so every body is uniform width and sorts lexically ==
|
|
43
|
+
// chronologically (UUIDv7's ms-timestamp prefix lives in the high bytes).
|
|
44
|
+
const WIDTH = 22;
|
|
45
|
+
// A bare base58 body: 22 chars, Bitcoin alphabet (no 0 / I / O / l).
|
|
46
|
+
const BODY = "[1-9A-HJ-NP-Za-km-z]{22}";
|
|
47
|
+
/** Big-endian base58 (Bitcoin alphabet) of 16 bytes, left-padded to `WIDTH`. */
|
|
48
|
+
function encode58(bytes) {
|
|
49
|
+
let n = 0n;
|
|
50
|
+
for (const b of bytes)
|
|
51
|
+
n = (n << 8n) | BigInt(b);
|
|
52
|
+
let out = "";
|
|
53
|
+
while (n > 0n) {
|
|
54
|
+
out = B58.charAt(Number(n % 58n)) + out;
|
|
55
|
+
n /= 58n;
|
|
56
|
+
}
|
|
57
|
+
return out.padStart(WIDTH, B58.charAt(0));
|
|
58
|
+
}
|
|
59
|
+
/** Inverse of {@link encode58}: a base58 body back to 16 bytes. */
|
|
60
|
+
function decode58(body) {
|
|
61
|
+
let n = 0n;
|
|
62
|
+
for (const ch of body) {
|
|
63
|
+
const v = B58.indexOf(ch);
|
|
64
|
+
if (v < 0)
|
|
65
|
+
throw new Error(`invalid base58 char: ${ch}`);
|
|
66
|
+
n = n * 58n + BigInt(v);
|
|
67
|
+
}
|
|
68
|
+
const bytes = new Uint8Array(16);
|
|
69
|
+
for (let i = 15; i >= 0; i--) {
|
|
70
|
+
bytes[i] = Number(n & 0xffn);
|
|
71
|
+
n >>= 8n;
|
|
72
|
+
}
|
|
73
|
+
return bytes;
|
|
74
|
+
}
|
|
75
|
+
/** A hyphenated UUID string → its 16 raw bytes. */
|
|
76
|
+
function uuidToBytes(uuid) {
|
|
77
|
+
const hex = uuid.replace(/-/g, "");
|
|
78
|
+
if (!/^[0-9a-fA-F]{32}$/.test(hex))
|
|
79
|
+
throw new Error(`not a uuid: ${uuid}`);
|
|
80
|
+
const bytes = new Uint8Array(16);
|
|
81
|
+
for (let i = 0; i < 16; i++) {
|
|
82
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
83
|
+
}
|
|
84
|
+
return bytes;
|
|
85
|
+
}
|
|
86
|
+
/** 16 raw bytes → a canonical hyphenated UUID string. */
|
|
87
|
+
function bytesToUuid(bytes) {
|
|
88
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
89
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
90
|
+
}
|
|
91
|
+
/** Skin a stored hyphenated UUIDv7 as a prefixed base58 id, e.g. `team_…`. */
|
|
92
|
+
export function toPrefixedId(uuid, prefix) {
|
|
93
|
+
return `${prefix}_${encode58(uuidToBytes(uuid))}`;
|
|
94
|
+
}
|
|
95
|
+
/** Inverse of {@link toPrefixedId}: recover the hyphenated UUIDv7. */
|
|
96
|
+
export function fromPrefixedId(id) {
|
|
97
|
+
const body = id.slice(id.indexOf("_") + 1);
|
|
98
|
+
return bytesToUuid(decode58(body));
|
|
99
|
+
}
|
|
100
|
+
/** Mint a fresh prefixed base58 id (UUIDv7 core), for text-id sites / API parity. */
|
|
101
|
+
export function base58Id(prefix) {
|
|
102
|
+
return toPrefixedId(uuidGenerateId(), prefix);
|
|
103
|
+
}
|
|
104
|
+
function makeHelper(prefix) {
|
|
105
|
+
// Prefixes are developer-controlled identifier constants, never user input.
|
|
106
|
+
const matcher = new RegExp(`^${prefix}_${BODY}$`);
|
|
107
|
+
return {
|
|
108
|
+
prefix,
|
|
109
|
+
mint: () => base58Id(prefix),
|
|
110
|
+
encode: (uuid) => toPrefixedId(uuid, prefix),
|
|
111
|
+
decode: (id) => {
|
|
112
|
+
if (!matcher.test(id))
|
|
113
|
+
throw new Error(`not a ${prefix}_ id: ${id}`);
|
|
114
|
+
return fromPrefixedId(id);
|
|
115
|
+
},
|
|
116
|
+
is: (id) => matcher.test(id),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Build a typed, prefix-validated id registry for a project's entities — one
|
|
121
|
+
* place to declare every prefix instead of hand-rolling encode/decode wrappers:
|
|
122
|
+
*
|
|
123
|
+
* ```ts
|
|
124
|
+
* const ids = createIdRegistry({ org: "org", agent: "agt", session: "cs" });
|
|
125
|
+
* ids.org.mint(); // "org_3k9…"
|
|
126
|
+
* ids.org.encode(uuid); // "org_…"
|
|
127
|
+
* ids.org.decode("org_…"); // uuid — throws on a wrong / missing prefix
|
|
128
|
+
* ids.agent.is(someId); // boolean
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function createIdRegistry(prefixes) {
|
|
132
|
+
const reg = {};
|
|
133
|
+
for (const [key, prefix] of Object.entries(prefixes)) {
|
|
134
|
+
reg[key] = makeHelper(prefix);
|
|
135
|
+
}
|
|
136
|
+
return reg;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=id.js.map
|
package/dist/id.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"id.js","sourceRoot":"","sources":["../src/id.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-bin.d.ts","sourceRoot":"","sources":["../src/migrate-bin.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The `nk-pg-migrate` bin — a drop-in replacement for `drizzle-kit migrate` in a
|
|
3
|
+
// site's `db:migrate` script. Unlike drizzle-kit it surfaces the real Postgres
|
|
4
|
+
// error on failure (not an opaque exit 1), refuses to run against a drifted
|
|
5
|
+
// journal with an actionable message, and can reconcile a drifted-but-correct
|
|
6
|
+
// journal with `--baseline`.
|
|
7
|
+
//
|
|
8
|
+
// Connection comes from the env contract (DATABASE_URL [+ DATABASE_CA_CERT], or
|
|
9
|
+
// the nk-db `dbEnv()` vars). Run it via `bun run db:migrate` so the runner loads
|
|
10
|
+
// your `.env` / `.env.local` into the environment first.
|
|
11
|
+
//
|
|
12
|
+
// nk-pg-migrate apply pending migrations
|
|
13
|
+
// nk-pg-migrate --status print journal status, apply nothing
|
|
14
|
+
// nk-pg-migrate --baseline record the current file chain as applied,
|
|
15
|
+
// WITHOUT running DDL (push-built / regenerated
|
|
16
|
+
// baseline whose schema already matches)
|
|
17
|
+
// nk-pg-migrate --migrations <folder> (default: drizzle)
|
|
18
|
+
//
|
|
19
|
+
// Run directly by Node, so the relative import carries a `.js` extension.
|
|
20
|
+
import { baselineMigrations, inspectMigrations, MigrationDriftError, runMigrations, } from "./migrate.js";
|
|
21
|
+
const argv = process.argv.slice(2);
|
|
22
|
+
const flag = (name) => argv.includes(name);
|
|
23
|
+
const value = (name) => {
|
|
24
|
+
const i = argv.indexOf(name);
|
|
25
|
+
return i >= 0 ? argv[i + 1] : undefined;
|
|
26
|
+
};
|
|
27
|
+
const migrationsFolder = value("--migrations") ?? value("--migrations-folder") ?? "drizzle";
|
|
28
|
+
const main = async () => {
|
|
29
|
+
if (flag("--status")) {
|
|
30
|
+
const s = await inspectMigrations({ migrationsFolder });
|
|
31
|
+
console.log(`nk-pg-migrate: ${s.files.length} file(s), ${s.recorded.length} recorded, ${s.pending.length} pending${s.drifted ? " — DRIFTED" : ""}`);
|
|
32
|
+
if (s.drift)
|
|
33
|
+
console.log(` drift: ${s.drift.reason}`);
|
|
34
|
+
if (s.pending.length)
|
|
35
|
+
console.log(` pending: ${s.pending.map((m) => m.tag).join(", ")}`);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (flag("--baseline")) {
|
|
39
|
+
const { recorded } = await baselineMigrations({ migrationsFolder });
|
|
40
|
+
console.log(`nk-pg-migrate: baselined journal to ${recorded.length} migration(s) — recorded as applied, no DDL run.`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const { applied } = await runMigrations({ migrationsFolder });
|
|
44
|
+
console.log(applied.length
|
|
45
|
+
? `nk-pg-migrate: applied ${applied.length} migration(s) — ${applied.join(", ")}`
|
|
46
|
+
: "nk-pg-migrate: up to date, nothing to apply.");
|
|
47
|
+
};
|
|
48
|
+
main().catch((error) => {
|
|
49
|
+
if (error instanceof MigrationDriftError) {
|
|
50
|
+
console.error(`nk-pg-migrate: ${error.message}`);
|
|
51
|
+
process.exit(2);
|
|
52
|
+
}
|
|
53
|
+
console.error("nk-pg-migrate: migration failed —", error);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=migrate-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-bin.js","sourceRoot":"","sources":["../src/migrate-bin.ts"],"names":[],"mappings":";AACA,iFAAiF;AACjF,+EAA+E;AAC/E,4EAA4E;AAC5E,8EAA8E;AAC9E,6BAA6B;AAC7B,EAAE;AACF,gFAAgF;AAChF,iFAAiF;AACjF,yDAAyD;AACzD,EAAE;AACF,2DAA2D;AAC3D,sEAAsE;AACtE,4EAA4E;AAC5E,gFAAgF;AAChF,yEAAyE;AACzE,6DAA6D;AAC7D,EAAE;AACF,0EAA0E;AAC1E,OAAO,EACN,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACb,MAAM,cAAc,CAAC;AAEtB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,IAAI,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5D,MAAM,KAAK,GAAG,CAAC,IAAY,EAAsB,EAAE;IAClD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACzC,CAAC,CAAC;AAEF,MAAM,gBAAgB,GACrB,KAAK,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,IAAI,SAAS,CAAC;AAEpE,MAAM,IAAI,GAAG,KAAK,IAAmB,EAAE;IACtC,IAAI,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,MAAM,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CACV,kBAAkB,CAAC,CAAC,KAAK,CAAC,MAAM,aAAa,CAAC,CAAC,QAAQ,CAAC,MAAM,cAAc,CAAC,CAAC,OAAO,CAAC,MAAM,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CACtI,CAAC;QACF,IAAI,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM;YACnB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrE,OAAO;IACR,CAAC;IAED,IAAI,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;QACxB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,kBAAkB,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CACV,uCAAuC,QAAQ,CAAC,MAAM,kDAAkD,CACxG,CAAC;QACF,OAAO;IACR,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CACV,OAAO,CAAC,MAAM;QACb,CAAC,CAAC,0BAA0B,OAAO,CAAC,MAAM,mBAAmB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACjF,CAAC,CAAC,8CAA8C,CACjD,CAAC;AACH,CAAC,CAAC;AAEF,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC/B,IAAI,KAAK,YAAY,mBAAmB,EAAE,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,kBAAkB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;IAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { Pool } from "pg";
|
|
2
|
+
import { type CreatePoolConfig } from "./pool.js";
|
|
3
|
+
/** One migration as recorded in `drizzle/meta/_journal.json` + its file hash. */
|
|
4
|
+
export interface MigrationFileMeta {
|
|
5
|
+
/** Journal tag, e.g. `0003_illegal_jack_flag`. */
|
|
6
|
+
tag: string;
|
|
7
|
+
/** `sha256(fileContents)` — the exact value drizzle records, so our journal
|
|
8
|
+
* rows are byte-compatible with `drizzle-kit migrate`. */
|
|
9
|
+
hash: string;
|
|
10
|
+
/** The journal entry's `when` (ms epoch) — drizzle's `created_at`. */
|
|
11
|
+
folderMillis: number;
|
|
12
|
+
}
|
|
13
|
+
export interface MigrationsLocation {
|
|
14
|
+
/** Drizzle migrations folder. Default `drizzle`. */
|
|
15
|
+
migrationsFolder?: string;
|
|
16
|
+
/** Journal table name. Default `__drizzle_migrations`. */
|
|
17
|
+
migrationsTable?: string;
|
|
18
|
+
/** Journal table schema. Default `drizzle`. */
|
|
19
|
+
migrationsSchema?: string;
|
|
20
|
+
}
|
|
21
|
+
export type MigrateConfig = CreatePoolConfig & MigrationsLocation & {
|
|
22
|
+
/** Reuse an existing pool instead of creating one from the connection
|
|
23
|
+
* string. The caller owns its lifecycle — it is not ended here. Pass your
|
|
24
|
+
* app's shared pool to avoid opening a second connection. */
|
|
25
|
+
pool?: Pool;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Read `meta/_journal.json` + each `.sql` and compute the per-file hash the same
|
|
29
|
+
* way drizzle does (`sha256` of the raw file). Decoupled from drizzle's internal
|
|
30
|
+
* `readMigrationFiles` so we also keep the human-readable tag.
|
|
31
|
+
*/
|
|
32
|
+
export declare const readJournal: (migrationsFolder?: string) => MigrationFileMeta[];
|
|
33
|
+
/** A row of the drizzle journal table. */
|
|
34
|
+
export interface RecordedMigration {
|
|
35
|
+
hash: string;
|
|
36
|
+
createdAt: number;
|
|
37
|
+
}
|
|
38
|
+
export interface MigrationStatus {
|
|
39
|
+
/** All journal files, in order. */
|
|
40
|
+
files: MigrationFileMeta[];
|
|
41
|
+
/** Rows already in the journal table, oldest first. */
|
|
42
|
+
recorded: RecordedMigration[];
|
|
43
|
+
/** Files drizzle's migrator would apply next (folderMillis > max recorded). */
|
|
44
|
+
pending: MigrationFileMeta[];
|
|
45
|
+
/** True when the journal table doesn't line up with the files (see {@link drift}). */
|
|
46
|
+
drifted: boolean;
|
|
47
|
+
drift?: MigrationDrift;
|
|
48
|
+
}
|
|
49
|
+
export interface MigrationDrift {
|
|
50
|
+
reason: string;
|
|
51
|
+
/** Recorded hashes that match no current file (the regenerated-baseline tell). */
|
|
52
|
+
recordedNotInFiles: string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Compare the DB's migration journal to the `drizzle/` files without changing
|
|
56
|
+
* anything. The basis for {@link runMigrations}'s pre-flight; also useful on its
|
|
57
|
+
* own (a `--status` check).
|
|
58
|
+
*/
|
|
59
|
+
export declare const inspectMigrations: (config?: MigrateConfig) => Promise<MigrationStatus>;
|
|
60
|
+
/** Thrown by {@link runMigrations} when the journal is out of sync with the
|
|
61
|
+
* files — applying would replay already-present DDL and fail confusingly. */
|
|
62
|
+
export declare class MigrationDriftError extends Error {
|
|
63
|
+
readonly status: MigrationStatus;
|
|
64
|
+
constructor(status: MigrationStatus);
|
|
65
|
+
}
|
|
66
|
+
export interface MigrateResult {
|
|
67
|
+
/** Tags of the migrations applied by this run (empty when up to date). */
|
|
68
|
+
applied: string[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Apply pending migrations with the real drizzle-orm migrator. Runs a drift
|
|
72
|
+
* pre-flight first and throws {@link MigrationDriftError} (not a confusing
|
|
73
|
+
* `already exists`) when the journal is out of sync. Surfaces the actual
|
|
74
|
+
* Postgres error on a failing statement.
|
|
75
|
+
*/
|
|
76
|
+
export declare const runMigrations: (config?: MigrateConfig) => Promise<MigrateResult>;
|
|
77
|
+
/**
|
|
78
|
+
* Reconcile a journal whose schema is ALREADY correct but whose
|
|
79
|
+
* `__drizzle_migrations` rows don't match the files (built via db:push, or after
|
|
80
|
+
* regenerating the baseline). Records the full current file chain as applied —
|
|
81
|
+
* hashes + `when` timestamps, byte-compatible with drizzle — WITHOUT running any
|
|
82
|
+
* migration DDL, so a subsequent `runMigrations` is a clean no-op.
|
|
83
|
+
*
|
|
84
|
+
* Only call this when you've confirmed the live schema matches the migration
|
|
85
|
+
* files; it does not verify that.
|
|
86
|
+
*/
|
|
87
|
+
export declare const baselineMigrations: (config?: MigrateConfig) => Promise<{
|
|
88
|
+
recorded: string[];
|
|
89
|
+
}>;
|
|
90
|
+
//# sourceMappingURL=migrate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC/B,OAAO,EAAE,KAAK,gBAAgB,EAAc,MAAM,WAAW,CAAC;AAE9D,iFAAiF;AACjF,MAAM,WAAW,iBAAiB;IACjC,kDAAkD;IAClD,GAAG,EAAE,MAAM,CAAC;IACZ;+DAC2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAClC,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0DAA0D;IAC1D,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAC3C,kBAAkB,GAAG;IACpB;;kEAE8D;IAC9D,IAAI,CAAC,EAAE,IAAI,CAAC;CACZ,CAAC;AAkBH;;;;GAIG;AACH,eAAO,MAAM,WAAW,GACvB,mBAAkB,MAAkC,KAClD,iBAAiB,EAgBnB,CAAC;AAEF,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC/B,mCAAmC;IACnC,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,uDAAuD;IACvD,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,+EAA+E;IAC/E,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,sFAAsF;IACtF,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,kBAAkB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAuDD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAC7B,SAAQ,aAAkB,KACxB,OAAO,CAAC,eAAe,CAezB,CAAC;AAEF;8EAC8E;AAC9E,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC;gBACrB,MAAM,EAAE,eAAe;CAgBnC;AAED,MAAM,WAAW,aAAa;IAC7B,0EAA0E;IAC1E,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACzB,SAAQ,aAAkB,KACxB,OAAO,CAAC,aAAa,CAsBvB,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC9B,SAAQ,aAAkB,KACxB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAmChC,CAAC"}
|
package/dist/migrate.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Migration runner with drift detection — the framework answer to two recurring
|
|
2
|
+
// pains with `drizzle-kit migrate`:
|
|
3
|
+
//
|
|
4
|
+
// 1. It swallows the real database error and exits 1 opaquely ("applying
|
|
5
|
+
// migrations..." then nothing). {@link runMigrations} uses drizzle-orm's
|
|
6
|
+
// own migrator, so a failing statement throws the actual Postgres error.
|
|
7
|
+
// 2. When a DB's migration journal drifts from the `drizzle/` files — the
|
|
8
|
+
// classic "built via db:push, or the 0000 baseline was regenerated" case —
|
|
9
|
+
// the migrator blindly replays 0000 and dies with a confusing
|
|
10
|
+
// `relation "..." already exists`. {@link runMigrations} runs a pre-flight
|
|
11
|
+
// {@link inspectMigrations} check and throws a {@link MigrationDriftError}
|
|
12
|
+
// that explains exactly what happened and how to fix it, and
|
|
13
|
+
// {@link baselineMigrations} reconciles a journal whose schema is already
|
|
14
|
+
// correct without re-running any DDL.
|
|
15
|
+
//
|
|
16
|
+
// This module is node-only (pg + fs + the drizzle migrator); it is NOT exported
|
|
17
|
+
// from the main entry, so a production bundle that only does runtime queries
|
|
18
|
+
// never pulls it. Reached via the "@ingram-tech/nk-db/migrate" subpath and the
|
|
19
|
+
// `nk-pg-migrate` bin.
|
|
20
|
+
import { createHash } from "node:crypto";
|
|
21
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
22
|
+
import { join } from "node:path";
|
|
23
|
+
import { createPool } from "./pool.js";
|
|
24
|
+
/** Resolve the pool to use: a caller-supplied one (left open) or a fresh one we
|
|
25
|
+
* own (ended on release). */
|
|
26
|
+
const acquire = (config) => {
|
|
27
|
+
if (config.pool)
|
|
28
|
+
return { pool: config.pool, release: async () => { } };
|
|
29
|
+
const pool = createPool(config);
|
|
30
|
+
return { pool, release: () => pool.end() };
|
|
31
|
+
};
|
|
32
|
+
const DEFAULTS = {
|
|
33
|
+
migrationsFolder: "drizzle",
|
|
34
|
+
migrationsTable: "__drizzle_migrations",
|
|
35
|
+
migrationsSchema: "drizzle",
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Read `meta/_journal.json` + each `.sql` and compute the per-file hash the same
|
|
39
|
+
* way drizzle does (`sha256` of the raw file). Decoupled from drizzle's internal
|
|
40
|
+
* `readMigrationFiles` so we also keep the human-readable tag.
|
|
41
|
+
*/
|
|
42
|
+
export const readJournal = (migrationsFolder = DEFAULTS.migrationsFolder) => {
|
|
43
|
+
const journalPath = join(migrationsFolder, "meta", "_journal.json");
|
|
44
|
+
if (!existsSync(journalPath)) {
|
|
45
|
+
throw new Error(`@ingram-tech/nk-db: no migration journal at ${journalPath}`);
|
|
46
|
+
}
|
|
47
|
+
const journal = JSON.parse(readFileSync(journalPath, "utf8"));
|
|
48
|
+
return journal.entries.map((entry) => {
|
|
49
|
+
const sql = readFileSync(join(migrationsFolder, `${entry.tag}.sql`), "utf8");
|
|
50
|
+
return {
|
|
51
|
+
tag: entry.tag,
|
|
52
|
+
hash: createHash("sha256").update(sql).digest("hex"),
|
|
53
|
+
folderMillis: entry.when,
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
const qualified = (schema, table) => `"${schema.replace(/"/g, '""')}"."${table.replace(/"/g, '""')}"`;
|
|
58
|
+
/** Read the journal table; returns [] if it doesn't exist yet (fresh DB). */
|
|
59
|
+
const readRecorded = async (pool, schema, table) => {
|
|
60
|
+
try {
|
|
61
|
+
const { rows } = await pool.query(`select hash, created_at from ${qualified(schema, table)} order by created_at asc`);
|
|
62
|
+
// created_at is bigint → pg returns it as a string; coerce to number (ms
|
|
63
|
+
// epochs fit safely in a JS number).
|
|
64
|
+
return rows.map((r) => ({ hash: r.hash, createdAt: Number(r.created_at) }));
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
// 42P01 = undefined_table → never migrated; not an error.
|
|
68
|
+
if (err.code === "42P01")
|
|
69
|
+
return [];
|
|
70
|
+
throw err;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const detectDrift = (files, recorded) => {
|
|
74
|
+
const fileHashes = new Set(files.map((f) => f.hash));
|
|
75
|
+
const recordedNotInFiles = recorded
|
|
76
|
+
.map((r) => r.hash)
|
|
77
|
+
.filter((h) => !fileHashes.has(h));
|
|
78
|
+
if (recorded.length > files.length) {
|
|
79
|
+
return {
|
|
80
|
+
reason: `the journal table has ${recorded.length} recorded migration(s) but only ${files.length} file(s) exist`,
|
|
81
|
+
recordedNotInFiles,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// A healthy journal is exactly the first N files, in order, by hash.
|
|
85
|
+
for (let i = 0; i < recorded.length; i++) {
|
|
86
|
+
if (recorded[i]?.hash !== files[i]?.hash) {
|
|
87
|
+
return {
|
|
88
|
+
reason: recordedNotInFiles.length > 0
|
|
89
|
+
? `recorded migration #${i + 1} matches no current file — the baseline was likely regenerated, or the schema was built with db:push`
|
|
90
|
+
: `recorded migration #${i + 1} doesn't match file ${files[i]?.tag} (a migration file changed after it was applied)`,
|
|
91
|
+
recordedNotInFiles,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return undefined;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Compare the DB's migration journal to the `drizzle/` files without changing
|
|
99
|
+
* anything. The basis for {@link runMigrations}'s pre-flight; also useful on its
|
|
100
|
+
* own (a `--status` check).
|
|
101
|
+
*/
|
|
102
|
+
export const inspectMigrations = async (config = {}) => {
|
|
103
|
+
const folder = config.migrationsFolder ?? DEFAULTS.migrationsFolder;
|
|
104
|
+
const schema = config.migrationsSchema ?? DEFAULTS.migrationsSchema;
|
|
105
|
+
const table = config.migrationsTable ?? DEFAULTS.migrationsTable;
|
|
106
|
+
const { pool, release } = acquire(config);
|
|
107
|
+
try {
|
|
108
|
+
const files = readJournal(folder);
|
|
109
|
+
const recorded = await readRecorded(pool, schema, table);
|
|
110
|
+
const drift = detectDrift(files, recorded);
|
|
111
|
+
const maxRecorded = recorded.reduce((m, r) => Math.max(m, r.createdAt), 0);
|
|
112
|
+
const pending = files.filter((f) => f.folderMillis > maxRecorded);
|
|
113
|
+
return { files, recorded, pending, drifted: Boolean(drift), drift };
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await release();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
/** Thrown by {@link runMigrations} when the journal is out of sync with the
|
|
120
|
+
* files — applying would replay already-present DDL and fail confusingly. */
|
|
121
|
+
export class MigrationDriftError extends Error {
|
|
122
|
+
status;
|
|
123
|
+
constructor(status) {
|
|
124
|
+
const d = status.drift;
|
|
125
|
+
super([
|
|
126
|
+
`migration journal drift: ${d?.reason ?? "journal does not match files"}.`,
|
|
127
|
+
d?.recordedNotInFiles.length
|
|
128
|
+
? ` Recorded hashes matching no file: ${d.recordedNotInFiles.map((h) => h.slice(0, 12)).join(", ")}.`
|
|
129
|
+
: "",
|
|
130
|
+
" Fix: if this DB's schema already matches the files (e.g. built via db:push, or after regenerating the baseline), reconcile the journal with `baselineMigrations()` / `nk-pg-migrate --baseline` — it records the current file chain WITHOUT re-running DDL. Otherwise rebuild the database.",
|
|
131
|
+
]
|
|
132
|
+
.filter(Boolean)
|
|
133
|
+
.join("\n"));
|
|
134
|
+
this.name = "MigrationDriftError";
|
|
135
|
+
this.status = status;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Apply pending migrations with the real drizzle-orm migrator. Runs a drift
|
|
140
|
+
* pre-flight first and throws {@link MigrationDriftError} (not a confusing
|
|
141
|
+
* `already exists`) when the journal is out of sync. Surfaces the actual
|
|
142
|
+
* Postgres error on a failing statement.
|
|
143
|
+
*/
|
|
144
|
+
export const runMigrations = async (config = {}) => {
|
|
145
|
+
const folder = config.migrationsFolder ?? DEFAULTS.migrationsFolder;
|
|
146
|
+
const schema = config.migrationsSchema ?? DEFAULTS.migrationsSchema;
|
|
147
|
+
const table = config.migrationsTable ?? DEFAULTS.migrationsTable;
|
|
148
|
+
const status = await inspectMigrations(config);
|
|
149
|
+
if (status.drifted)
|
|
150
|
+
throw new MigrationDriftError(status);
|
|
151
|
+
if (status.pending.length === 0)
|
|
152
|
+
return { applied: [] };
|
|
153
|
+
const { pool, release } = acquire(config);
|
|
154
|
+
try {
|
|
155
|
+
const { drizzle } = await import("drizzle-orm/node-postgres");
|
|
156
|
+
const { migrate } = await import("drizzle-orm/node-postgres/migrator");
|
|
157
|
+
await migrate(drizzle(pool), {
|
|
158
|
+
migrationsFolder: folder,
|
|
159
|
+
migrationsTable: table,
|
|
160
|
+
migrationsSchema: schema,
|
|
161
|
+
});
|
|
162
|
+
return { applied: status.pending.map((m) => m.tag) };
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
await release();
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Reconcile a journal whose schema is ALREADY correct but whose
|
|
170
|
+
* `__drizzle_migrations` rows don't match the files (built via db:push, or after
|
|
171
|
+
* regenerating the baseline). Records the full current file chain as applied —
|
|
172
|
+
* hashes + `when` timestamps, byte-compatible with drizzle — WITHOUT running any
|
|
173
|
+
* migration DDL, so a subsequent `runMigrations` is a clean no-op.
|
|
174
|
+
*
|
|
175
|
+
* Only call this when you've confirmed the live schema matches the migration
|
|
176
|
+
* files; it does not verify that.
|
|
177
|
+
*/
|
|
178
|
+
export const baselineMigrations = async (config = {}) => {
|
|
179
|
+
const folder = config.migrationsFolder ?? DEFAULTS.migrationsFolder;
|
|
180
|
+
const schema = config.migrationsSchema ?? DEFAULTS.migrationsSchema;
|
|
181
|
+
const table = config.migrationsTable ?? DEFAULTS.migrationsTable;
|
|
182
|
+
const files = readJournal(folder);
|
|
183
|
+
const { pool, release } = acquire(config);
|
|
184
|
+
const client = await pool.connect();
|
|
185
|
+
try {
|
|
186
|
+
await client.query("begin");
|
|
187
|
+
await client.query(`create schema if not exists "${schema.replace(/"/g, '""')}"`);
|
|
188
|
+
await client.query(`create table if not exists ${qualified(schema, table)} (
|
|
189
|
+
id SERIAL PRIMARY KEY,
|
|
190
|
+
hash text NOT NULL,
|
|
191
|
+
created_at bigint
|
|
192
|
+
)`);
|
|
193
|
+
await client.query(`delete from ${qualified(schema, table)}`);
|
|
194
|
+
for (const f of files) {
|
|
195
|
+
await client.query(`insert into ${qualified(schema, table)} ("hash", "created_at") values ($1, $2)`, [f.hash, f.folderMillis]);
|
|
196
|
+
}
|
|
197
|
+
await client.query("commit");
|
|
198
|
+
return { recorded: files.map((f) => f.tag) };
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
await client.query("rollback").catch(() => { });
|
|
202
|
+
throw err;
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
client.release();
|
|
206
|
+
await release();
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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"}
|
package/dist/pglite/index.d.ts
CHANGED
|
@@ -65,6 +65,13 @@ export interface TestDb {
|
|
|
65
65
|
* Both share `resetPublicTables`. If a second in-process consumer appears, the
|
|
66
66
|
* move is to promote an in-process harness to first-class here, not to bolt one
|
|
67
67
|
* beside this socket default.
|
|
68
|
+
*
|
|
69
|
+
* Port: unlike `startPgliteDev` (which wants the stable 5432 the app dials),
|
|
70
|
+
* tests reach the db through the returned `pool`/`databaseUrl`, so the socket
|
|
71
|
+
* port is irrelevant — it defaults to an **ephemeral free port** so the harness
|
|
72
|
+
* never collides with a developer's real Postgres on 5432 (the EADDRINUSE that
|
|
73
|
+
* otherwise kills the suite). An explicit `port` option or `PGLITE_PORT` still
|
|
74
|
+
* wins.
|
|
68
75
|
*/
|
|
69
76
|
export declare const createTestDb: (options?: PgliteServerOptions) => Promise<TestDb>;
|
|
70
77
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAG/B,MAAM,WAAW,mBAAmB;IACnC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,kBAAkB,CAAC;IAC3B,wDAAwD;IACxD,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAuBD;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,GAC9B,UAAS,mBAAwB,KAC/B,OAAO,CAAC,YAAY,CAyBtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,GAC1B,UAAS,mBAAmB,GAAG;IAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,KACzD,OAAO,CAAC,IAAI,CA0Bd,CAAC;AAEF,MAAM,WAAW,MAAM;IACtB,2EAA2E;IAC3E,IAAI,EAAE,IAAI,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,YAAY,GACxB,UAAS,mBAAwB,KAC/B,OAAO,CAAC,MAAM,CAiBhB,CAAC"}
|
package/dist/pglite/index.js
CHANGED
|
@@ -9,9 +9,21 @@
|
|
|
9
9
|
// entry, so production bundles stay clean.
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
11
11
|
import { rm } from "node:fs/promises";
|
|
12
|
+
import { createServer } from "node:net";
|
|
12
13
|
import { PGlite } from "@electric-sql/pglite";
|
|
13
14
|
import { PGLiteSocketServer } from "@electric-sql/pglite-socket";
|
|
14
15
|
import { resetPublicTables } from "./reset.js";
|
|
16
|
+
/** Ask the OS for a currently-free TCP port (bind :0, read it back, release).
|
|
17
|
+
* Used so the test harness never collides with a dev Postgres on 5432. */
|
|
18
|
+
const freePort = (host) => new Promise((resolve, reject) => {
|
|
19
|
+
const srv = createServer();
|
|
20
|
+
srv.once("error", reject);
|
|
21
|
+
srv.listen(0, host, () => {
|
|
22
|
+
const addr = srv.address();
|
|
23
|
+
const port = typeof addr === "object" && addr ? addr.port : 0;
|
|
24
|
+
srv.close((err) => (err ? reject(err) : resolve(port)));
|
|
25
|
+
});
|
|
26
|
+
});
|
|
15
27
|
const defaultMigrate = (migrationsFolder) => async (db) => {
|
|
16
28
|
const { drizzle } = await import("drizzle-orm/pglite");
|
|
17
29
|
const { migrate } = await import("drizzle-orm/pglite/migrator");
|
|
@@ -84,10 +96,22 @@ export const startPgliteDev = async (options = {}) => {
|
|
|
84
96
|
* Both share `resetPublicTables`. If a second in-process consumer appears, the
|
|
85
97
|
* move is to promote an in-process harness to first-class here, not to bolt one
|
|
86
98
|
* beside this socket default.
|
|
99
|
+
*
|
|
100
|
+
* Port: unlike `startPgliteDev` (which wants the stable 5432 the app dials),
|
|
101
|
+
* tests reach the db through the returned `pool`/`databaseUrl`, so the socket
|
|
102
|
+
* port is irrelevant — it defaults to an **ephemeral free port** so the harness
|
|
103
|
+
* never collides with a developer's real Postgres on 5432 (the EADDRINUSE that
|
|
104
|
+
* otherwise kills the suite). An explicit `port` option or `PGLITE_PORT` still
|
|
105
|
+
* wins.
|
|
87
106
|
*/
|
|
88
107
|
export const createTestDb = async (options = {}) => {
|
|
89
108
|
const { Pool } = await import("pg");
|
|
90
|
-
const
|
|
109
|
+
const host = options.host ?? "127.0.0.1";
|
|
110
|
+
const port = options.port ??
|
|
111
|
+
(process.env.PGLITE_PORT
|
|
112
|
+
? Number(process.env.PGLITE_PORT)
|
|
113
|
+
: await freePort(host));
|
|
114
|
+
const { databaseUrl, stop } = await createPgliteServer({ ...options, host, port });
|
|
91
115
|
const pool = new Pool({ connectionString: databaseUrl, max: 1 });
|
|
92
116
|
const reset = () => resetPublicTables((sql) => pool.query(sql));
|
|
93
117
|
const close = async () => {
|
package/dist/pglite/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingram-tech/nk-db",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "The Ingram Postgres data layer: one TLS-aware pg pool, raw-SQL helpers, Drizzle wiring, and a PGlite (no-Docker) dev/test harness for Next.js sites.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,13 +16,22 @@
|
|
|
16
16
|
"dist"
|
|
17
17
|
],
|
|
18
18
|
"bin": {
|
|
19
|
-
"nk-pglite-dev": "./dist/pglite/dev.js"
|
|
19
|
+
"nk-pglite-dev": "./dist/pglite/dev.js",
|
|
20
|
+
"nk-pg-migrate": "./dist/migrate-bin.js"
|
|
20
21
|
},
|
|
21
22
|
"exports": {
|
|
22
23
|
".": {
|
|
23
24
|
"types": "./dist/index.d.ts",
|
|
24
25
|
"import": "./dist/index.js"
|
|
25
26
|
},
|
|
27
|
+
"./id": {
|
|
28
|
+
"types": "./dist/id.d.ts",
|
|
29
|
+
"import": "./dist/id.js"
|
|
30
|
+
},
|
|
31
|
+
"./migrate": {
|
|
32
|
+
"types": "./dist/migrate.d.ts",
|
|
33
|
+
"import": "./dist/migrate.js"
|
|
34
|
+
},
|
|
26
35
|
"./pglite": {
|
|
27
36
|
"types": "./dist/pglite/index.d.ts",
|
|
28
37
|
"import": "./dist/pglite/index.js"
|
|
@@ -57,7 +66,7 @@
|
|
|
57
66
|
"devDependencies": {
|
|
58
67
|
"@electric-sql/pglite": "^0.5.0",
|
|
59
68
|
"@electric-sql/pglite-socket": "^0.2.4",
|
|
60
|
-
"@ingram-tech/
|
|
69
|
+
"@ingram-tech/nk-dev": "workspace:*",
|
|
61
70
|
"@types/node": "^25.0.0",
|
|
62
71
|
"@types/pg": "^8.11.0",
|
|
63
72
|
"drizzle-orm": "^0.45.0",
|