@nodii/db-rls 0.2.2 → 0.4.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/configure.d.ts +42 -8
- package/dist/configure.d.ts.map +1 -1
- package/dist/configure.js +87 -16
- package/dist/configure.js.map +1 -1
- package/dist/context.d.ts +36 -7
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +67 -6
- package/dist/context.js.map +1 -1
- package/dist/drizzle-client.d.ts +9 -2
- package/dist/drizzle-client.d.ts.map +1 -1
- package/dist/drizzle-client.js +28 -2
- package/dist/drizzle-client.js.map +1 -1
- package/dist/drizzle-grants.d.ts +203 -0
- package/dist/drizzle-grants.d.ts.map +1 -0
- package/dist/drizzle-grants.js +68 -0
- package/dist/drizzle-grants.js.map +1 -0
- package/dist/drizzle-policies.d.ts +90 -0
- package/dist/drizzle-policies.d.ts.map +1 -0
- package/dist/drizzle-policies.js +223 -0
- package/dist/drizzle-policies.js.map +1 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -10
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +23 -5
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +38 -4
- package/dist/init.js.map +1 -1
- package/dist/metrics.d.ts +28 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +263 -0
- package/dist/metrics.js.map +1 -0
- package/dist/migrate-guard.d.ts +14 -0
- package/dist/migrate-guard.d.ts.map +1 -0
- package/dist/migrate-guard.js +33 -0
- package/dist/migrate-guard.js.map +1 -0
- package/dist/pg-pool-adapter.d.ts.map +1 -1
- package/dist/pg-pool-adapter.js +78 -25
- package/dist/pg-pool-adapter.js.map +1 -1
- package/dist/postgres-js-client.d.ts +60 -0
- package/dist/postgres-js-client.d.ts.map +1 -0
- package/dist/postgres-js-client.js +223 -0
- package/dist/postgres-js-client.js.map +1 -0
- package/dist/types.d.ts +68 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +31 -1
- package/dist/types.js.map +1 -1
- package/package.json +24 -5
package/dist/pg-pool-adapter.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
// Pool-leak guard: client.release() ALWAYS runs in the finally block,
|
|
14
14
|
// regardless of commit/rollback outcome. The acquire-timer fires a
|
|
15
15
|
// telemetry span when acquisition exceeds 50ms (§ 5.10).
|
|
16
|
+
import { emitSlowAcquireSpan, recordAcquisition, recordAcquisitionDuration, recordGucSetFailure, recordPoolSize, recordTxDuration, withTxSpan, } from "./metrics";
|
|
16
17
|
class PgClientTx {
|
|
17
18
|
poolKind;
|
|
18
19
|
client;
|
|
@@ -26,7 +27,13 @@ class PgClientTx {
|
|
|
26
27
|
async setConfig(key, value) {
|
|
27
28
|
// set_config(name, value, is_local=true) — tx-local per § 5.3.
|
|
28
29
|
// Never expose the false variant; library refuses session-scoped GUCs.
|
|
29
|
-
|
|
30
|
+
try {
|
|
31
|
+
await this.client.query("SELECT set_config($1, $2, true)", [key, value]);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
recordGucSetFailure(key);
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
30
37
|
}
|
|
31
38
|
}
|
|
32
39
|
/**
|
|
@@ -56,48 +63,94 @@ export class PgClientPool {
|
|
|
56
63
|
}
|
|
57
64
|
async withTransaction(fn) {
|
|
58
65
|
const acquireStart = Date.now();
|
|
59
|
-
|
|
66
|
+
let client;
|
|
67
|
+
try {
|
|
68
|
+
client = await this.pool.connect();
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
recordAcquisition(this.kind, "failure");
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
60
74
|
const acquireMs = Date.now() - acquireStart;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
75
|
+
recordAcquisition(this.kind, "success");
|
|
76
|
+
recordAcquisitionDuration(this.kind, acquireMs);
|
|
77
|
+
if (acquireMs >= this.slowAcquireMs) {
|
|
78
|
+
emitSlowAcquireSpan(this.kind, acquireMs);
|
|
79
|
+
if (this.onSlowAcquire) {
|
|
80
|
+
try {
|
|
81
|
+
this.onSlowAcquire({ pool: this.kind, durationMs: acquireMs });
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
/* hook errors are non-fatal */
|
|
85
|
+
}
|
|
67
86
|
}
|
|
68
87
|
}
|
|
69
88
|
const txStart = Date.now();
|
|
70
89
|
let outcome = "error";
|
|
71
90
|
try {
|
|
72
|
-
await
|
|
73
|
-
const tx = new PgClientTx(this.kind, client);
|
|
74
|
-
let result;
|
|
75
|
-
try {
|
|
76
|
-
result = await fn(tx);
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
// Rollback then re-throw. Swallow rollback failure (don't double-throw).
|
|
91
|
+
return await withTxSpan(this.kind, async (setOutcome) => {
|
|
80
92
|
try {
|
|
81
|
-
await client.query("
|
|
93
|
+
await client.query("BEGIN");
|
|
94
|
+
const tx = new PgClientTx(this.kind, client);
|
|
95
|
+
let result;
|
|
96
|
+
try {
|
|
97
|
+
result = await fn(tx);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
// Rollback then re-throw. Swallow rollback failure (don't
|
|
101
|
+
// double-throw).
|
|
102
|
+
try {
|
|
103
|
+
await client.query("ROLLBACK");
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* swallow per § 5.9 */
|
|
107
|
+
}
|
|
108
|
+
outcome = "rolled_back";
|
|
109
|
+
setOutcome("rolled_back");
|
|
110
|
+
throw err;
|
|
111
|
+
}
|
|
112
|
+
await client.query("COMMIT");
|
|
113
|
+
outcome = "committed";
|
|
114
|
+
setOutcome("committed");
|
|
115
|
+
return result;
|
|
82
116
|
}
|
|
83
|
-
catch {
|
|
84
|
-
|
|
117
|
+
catch (err) {
|
|
118
|
+
// BEGIN failure (or other pre-fn throw) — record error path.
|
|
119
|
+
if (outcome === "error") {
|
|
120
|
+
setOutcome("error");
|
|
121
|
+
}
|
|
122
|
+
throw err;
|
|
85
123
|
}
|
|
86
|
-
|
|
87
|
-
throw err;
|
|
88
|
-
}
|
|
89
|
-
await client.query("COMMIT");
|
|
90
|
-
outcome = "committed";
|
|
91
|
-
return result;
|
|
124
|
+
});
|
|
92
125
|
}
|
|
93
126
|
finally {
|
|
94
127
|
const durationMs = Date.now() - txStart;
|
|
128
|
+
recordTxDuration(this.kind, outcome, durationMs);
|
|
95
129
|
try {
|
|
96
130
|
this.onTxFinish?.({ pool: this.kind, outcome, durationMs });
|
|
97
131
|
}
|
|
98
132
|
catch {
|
|
99
133
|
/* hook errors are non-fatal */
|
|
100
134
|
}
|
|
135
|
+
// Sample pool-size gauge at tx end. pg.Pool exposes totalCount /
|
|
136
|
+
// idleCount / waitingCount; if absent (mocked or wrapped pool),
|
|
137
|
+
// skip silently.
|
|
138
|
+
try {
|
|
139
|
+
// biome-ignore lint/suspicious/noExplicitAny: pg.Pool stats
|
|
140
|
+
const stats = this.pool;
|
|
141
|
+
if (typeof stats.totalCount === "number") {
|
|
142
|
+
const total = stats.totalCount;
|
|
143
|
+
const idle = stats.idleCount ?? 0;
|
|
144
|
+
const waiting = stats.waitingCount ?? 0;
|
|
145
|
+
const active = Math.max(0, total - idle);
|
|
146
|
+
recordPoolSize(this.kind, "active", active);
|
|
147
|
+
recordPoolSize(this.kind, "idle", idle);
|
|
148
|
+
recordPoolSize(this.kind, "waiting", waiting);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
/* gauge sampling errors are non-fatal */
|
|
153
|
+
}
|
|
101
154
|
// Pool-leak guard — release ALWAYS runs, even on commit/rollback failure.
|
|
102
155
|
try {
|
|
103
156
|
client.release();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-pool-adapter.js","sourceRoot":"","sources":["../src/pg-pool-adapter.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,qEAAqE;AACrE,qEAAqE;AACrE,qBAAqB;AACrB,EAAE;AACF,uBAAuB;AACvB,2EAA2E;AAC3E,aAAa;AACb,wEAAwE;AACxE,8BAA8B;AAC9B,+CAA+C;AAC/C,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,yDAAyD;
|
|
1
|
+
{"version":3,"file":"pg-pool-adapter.js","sourceRoot":"","sources":["../src/pg-pool-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
2
|
+
import type { Sql } from "postgres";
|
|
3
|
+
import { type OwnerContextOpts } from "./migrate-guard";
|
|
4
|
+
import { type PgPool, type PgTx, type PoolKind, type SystemContextOpts, type UserContextOpts } from "./types";
|
|
5
|
+
type PostgresJsDrizzleClient<TSchema extends Record<string, unknown> = Record<string, unknown>> = PostgresJsDatabase<TSchema>;
|
|
6
|
+
/**
|
|
7
|
+
* PgPool adapter wrapping a postgres-js `Sql` instance. Caller owns the
|
|
8
|
+
* underlying Sql's lifecycle (creation + .end()).
|
|
9
|
+
*
|
|
10
|
+
* The adapter implements the substrate-agnostic `PgPool` interface from
|
|
11
|
+
* `src/types.ts` so the existing `withUserContext` / `withSystemContext` /
|
|
12
|
+
* `withOwnerContext` helpers (in `src/context.ts`) work transparently
|
|
13
|
+
* against postgres-js — they receive a `PgTx` whose `setConfig` /
|
|
14
|
+
* `exec` calls land on the underlying postgres-js transaction.
|
|
15
|
+
*/
|
|
16
|
+
export declare class PgPostgresJsPool implements PgPool {
|
|
17
|
+
readonly kind: PoolKind;
|
|
18
|
+
private readonly sql;
|
|
19
|
+
private readonly slowAcquireMs;
|
|
20
|
+
private readonly onSlowAcquire?;
|
|
21
|
+
private readonly onTxFinish?;
|
|
22
|
+
constructor(opts: {
|
|
23
|
+
sql: Sql;
|
|
24
|
+
kind: PoolKind;
|
|
25
|
+
slowAcquireMs?: number;
|
|
26
|
+
onSlowAcquire?: (info: {
|
|
27
|
+
pool: PoolKind;
|
|
28
|
+
durationMs: number;
|
|
29
|
+
}) => void;
|
|
30
|
+
onTxFinish?: (info: {
|
|
31
|
+
pool: PoolKind;
|
|
32
|
+
outcome: "committed" | "rolled_back" | "error";
|
|
33
|
+
durationMs: number;
|
|
34
|
+
}) => void;
|
|
35
|
+
});
|
|
36
|
+
/** Direct access to the underlying postgres-js Sql (for ORM clients
|
|
37
|
+
* that need the raw handle — e.g. Drizzle's `drizzle(sql)`). */
|
|
38
|
+
get rawSql(): Sql;
|
|
39
|
+
withTransaction<T>(fn: (tx: PgTx) => Promise<T>): Promise<T>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* postgres-js Drizzle variant of `withUserContext`. Opens a tx on the
|
|
43
|
+
* `authenticated` pool, sets `app.user_id` + `app.tenant_id` via the
|
|
44
|
+
* canonical `auth.init(...)` helper, yields a Drizzle client.
|
|
45
|
+
*/
|
|
46
|
+
export declare function withUserContextDbPostgresJs<T, TSchema extends Record<string, unknown> = Record<string, unknown>>(opts: UserContextOpts, fn: (db: PostgresJsDrizzleClient<TSchema>) => Promise<T>): Promise<T>;
|
|
47
|
+
/**
|
|
48
|
+
* postgres-js Drizzle variant of `withSystemContext`. Opens a tx on the
|
|
49
|
+
* `services` pool with `app.tenant_id` GUC bound; yields a Drizzle client.
|
|
50
|
+
*/
|
|
51
|
+
export declare function withSystemContextDbPostgresJs<T, TSchema extends Record<string, unknown> = Record<string, unknown>>(opts: SystemContextOpts, fn: (db: PostgresJsDrizzleClient<TSchema>) => Promise<T>): Promise<T>;
|
|
52
|
+
/**
|
|
53
|
+
* postgres-js Drizzle variant of `withOwnerContext`. Opens a tx on the
|
|
54
|
+
* `owner` (BYPASSRLS) pool with no GUCs. Migrations only per § 5.3 +
|
|
55
|
+
* doctrine § 10.2 — gated by `NODII_ENV=migrate` or explicit
|
|
56
|
+
* `{ allowOutsideMigrate: true, reason }` opt-in.
|
|
57
|
+
*/
|
|
58
|
+
export declare function withOwnerContextDbPostgresJs<T, TSchema extends Record<string, unknown> = Record<string, unknown>>(fnOrOpts: OwnerContextOpts | ((db: PostgresJsDrizzleClient<TSchema>) => Promise<T>), maybeFn?: (db: PostgresJsDrizzleClient<TSchema>) => Promise<T>): Promise<T>;
|
|
59
|
+
export type { PostgresJsDrizzleClient };
|
|
60
|
+
//# sourceMappingURL=postgres-js-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-js-client.d.ts","sourceRoot":"","sources":["../src/postgres-js-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
// postgres-js adapter per request 813cd066 + 06-library-integration § 4.9.
|
|
2
|
+
//
|
|
3
|
+
// Exposed via subpath `@nodii/db-rls/postgres-js`. nodii-auth uses
|
|
4
|
+
// `postgres` (postgres-js driver) — not `pg` (node-postgres). The
|
|
5
|
+
// existing `drizzle-client.ts` hard-imports `drizzle-orm/node-postgres`
|
|
6
|
+
// + requires `pool instanceof PgClient`, so it's unusable from
|
|
7
|
+
// postgres-js callers. This module mirrors the same surface for the
|
|
8
|
+
// postgres-js driver.
|
|
9
|
+
//
|
|
10
|
+
// Surface:
|
|
11
|
+
// - PgPostgresJsPool — wraps a `postgres.Sql` into the PgPool interface
|
|
12
|
+
// so the existing with*Context helpers in src/context.ts work
|
|
13
|
+
// transparently.
|
|
14
|
+
// - withUserContextDbPostgresJs / withSystemContextDbPostgresJs /
|
|
15
|
+
// withOwnerContextDbPostgresJs — Drizzle-bound helpers that return
|
|
16
|
+
// a `drizzle-orm/postgres-js` client bound to the transaction.
|
|
17
|
+
//
|
|
18
|
+
// Lifecycle per § 5.3 — identical to the node-postgres path:
|
|
19
|
+
// 1. `sql.begin(...)` → BEGIN
|
|
20
|
+
// 2. `tx.unsafe("SELECT set_config(...)")` → GUC binding
|
|
21
|
+
// 3. yield Drizzle client to caller
|
|
22
|
+
// 4. throw → ROLLBACK; clean exit → COMMIT
|
|
23
|
+
// postgres-js handles the BEGIN/COMMIT/ROLLBACK + connection release
|
|
24
|
+
// internally inside `sql.begin(...)`.
|
|
25
|
+
import { drizzle } from "drizzle-orm/postgres-js";
|
|
26
|
+
import { requirePool } from "./init";
|
|
27
|
+
import { emitSlowAcquireSpan, recordAcquisition, recordAcquisitionDuration, recordGucSetFailure, recordOwnerContextInvocation, recordTxDuration, withTxSpan, } from "./metrics";
|
|
28
|
+
import { assertMigrateAllowed } from "./migrate-guard";
|
|
29
|
+
import { MissingTenantContext, TransactionRolledBack, } from "./types";
|
|
30
|
+
/**
|
|
31
|
+
* PgPool adapter wrapping a postgres-js `Sql` instance. Caller owns the
|
|
32
|
+
* underlying Sql's lifecycle (creation + .end()).
|
|
33
|
+
*
|
|
34
|
+
* The adapter implements the substrate-agnostic `PgPool` interface from
|
|
35
|
+
* `src/types.ts` so the existing `withUserContext` / `withSystemContext` /
|
|
36
|
+
* `withOwnerContext` helpers (in `src/context.ts`) work transparently
|
|
37
|
+
* against postgres-js — they receive a `PgTx` whose `setConfig` /
|
|
38
|
+
* `exec` calls land on the underlying postgres-js transaction.
|
|
39
|
+
*/
|
|
40
|
+
export class PgPostgresJsPool {
|
|
41
|
+
kind;
|
|
42
|
+
sql;
|
|
43
|
+
slowAcquireMs;
|
|
44
|
+
onSlowAcquire;
|
|
45
|
+
onTxFinish;
|
|
46
|
+
constructor(opts) {
|
|
47
|
+
this.kind = opts.kind;
|
|
48
|
+
this.sql = opts.sql;
|
|
49
|
+
this.slowAcquireMs = opts.slowAcquireMs ?? 50;
|
|
50
|
+
this.onSlowAcquire = opts.onSlowAcquire;
|
|
51
|
+
this.onTxFinish = opts.onTxFinish;
|
|
52
|
+
}
|
|
53
|
+
/** Direct access to the underlying postgres-js Sql (for ORM clients
|
|
54
|
+
* that need the raw handle — e.g. Drizzle's `drizzle(sql)`). */
|
|
55
|
+
get rawSql() {
|
|
56
|
+
return this.sql;
|
|
57
|
+
}
|
|
58
|
+
async withTransaction(fn) {
|
|
59
|
+
const acquireStart = Date.now();
|
|
60
|
+
const txStart = Date.now();
|
|
61
|
+
let outcome = "error";
|
|
62
|
+
let pendingError;
|
|
63
|
+
try {
|
|
64
|
+
const result = await withTxSpan(this.kind, async (setOutcome) => {
|
|
65
|
+
return await this.sql.begin(async (tx) => {
|
|
66
|
+
const acquireMs = Date.now() - acquireStart;
|
|
67
|
+
recordAcquisition(this.kind, "success");
|
|
68
|
+
recordAcquisitionDuration(this.kind, acquireMs);
|
|
69
|
+
if (acquireMs >= this.slowAcquireMs) {
|
|
70
|
+
emitSlowAcquireSpan(this.kind, acquireMs);
|
|
71
|
+
if (this.onSlowAcquire) {
|
|
72
|
+
try {
|
|
73
|
+
this.onSlowAcquire({ pool: this.kind, durationMs: acquireMs });
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
/* non-fatal */
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const pgTx = new PostgresJsTx(this.kind, tx);
|
|
81
|
+
try {
|
|
82
|
+
const out = await fn(pgTx);
|
|
83
|
+
outcome = "committed";
|
|
84
|
+
setOutcome("committed");
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
outcome = "rolled_back";
|
|
89
|
+
setOutcome("rolled_back");
|
|
90
|
+
pendingError = err;
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
if (outcome === "error") {
|
|
99
|
+
// sql.begin's connect failed (or rethrown unwrapped) — count
|
|
100
|
+
// acquisition failure if we never recorded success.
|
|
101
|
+
recordAcquisition(this.kind, "failure");
|
|
102
|
+
outcome = "rolled_back";
|
|
103
|
+
pendingError = err;
|
|
104
|
+
}
|
|
105
|
+
throw pendingError ?? err;
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
const durationMs = Date.now() - txStart;
|
|
109
|
+
recordTxDuration(this.kind, outcome, durationMs);
|
|
110
|
+
try {
|
|
111
|
+
this.onTxFinish?.({ pool: this.kind, outcome, durationMs });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
/* non-fatal */
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
class PostgresJsTx {
|
|
120
|
+
poolKind;
|
|
121
|
+
raw;
|
|
122
|
+
constructor(kind, raw) {
|
|
123
|
+
this.poolKind = kind;
|
|
124
|
+
this.raw = raw;
|
|
125
|
+
}
|
|
126
|
+
async exec(sql, params = []) {
|
|
127
|
+
await this.raw.unsafe(sql, params);
|
|
128
|
+
}
|
|
129
|
+
async setConfig(key, value) {
|
|
130
|
+
// set_config(name, value, is_local=true) — tx-local per § 5.3.
|
|
131
|
+
try {
|
|
132
|
+
await this.raw.unsafe("SELECT set_config($1, $2, true)", [key, value]);
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
recordGucSetFailure(key);
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function requirePostgresJsPool(kind) {
|
|
141
|
+
const pool = requirePool(kind);
|
|
142
|
+
if (!(pool instanceof PgPostgresJsPool)) {
|
|
143
|
+
throw new Error(`db-rls: ${kind} pool is not a PgPostgresJsPool — the postgres-js Drizzle helpers require a postgres-js-backed pool. Use withUserContextDb (node-postgres) or wire a PgPostgresJsPool for postgres-js.`);
|
|
144
|
+
}
|
|
145
|
+
return pool;
|
|
146
|
+
}
|
|
147
|
+
async function withPostgresJsTx(pool, setup, fn) {
|
|
148
|
+
return pool.withTransaction(async (pgTx) => {
|
|
149
|
+
const raw = pgTx.raw;
|
|
150
|
+
try {
|
|
151
|
+
await setup(raw);
|
|
152
|
+
const db = drizzle(raw);
|
|
153
|
+
return await fn(db);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
throw new TransactionRolledBack(err);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* postgres-js Drizzle variant of `withUserContext`. Opens a tx on the
|
|
162
|
+
* `authenticated` pool, sets `app.user_id` + `app.tenant_id` via the
|
|
163
|
+
* canonical `auth.init(...)` helper, yields a Drizzle client.
|
|
164
|
+
*/
|
|
165
|
+
export async function withUserContextDbPostgresJs(opts, fn) {
|
|
166
|
+
if (!opts.userId)
|
|
167
|
+
throw new MissingTenantContext();
|
|
168
|
+
if (!opts.tenantId)
|
|
169
|
+
throw new MissingTenantContext();
|
|
170
|
+
const pool = requirePostgresJsPool("authenticated");
|
|
171
|
+
return withPostgresJsTx(pool, async (tx) => {
|
|
172
|
+
await tx.unsafe("SELECT auth.init($1::uuid, $2::uuid)", [
|
|
173
|
+
opts.userId,
|
|
174
|
+
opts.tenantId,
|
|
175
|
+
]);
|
|
176
|
+
if (opts.sourceIp !== undefined) {
|
|
177
|
+
await tx.unsafe("SELECT set_config('app.source_ip', $1, true)", [
|
|
178
|
+
opts.sourceIp,
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
}, fn);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* postgres-js Drizzle variant of `withSystemContext`. Opens a tx on the
|
|
185
|
+
* `services` pool with `app.tenant_id` GUC bound; yields a Drizzle client.
|
|
186
|
+
*/
|
|
187
|
+
export async function withSystemContextDbPostgresJs(opts, fn) {
|
|
188
|
+
if (!opts.tenantId)
|
|
189
|
+
throw new MissingTenantContext();
|
|
190
|
+
const pool = requirePostgresJsPool("services");
|
|
191
|
+
return withPostgresJsTx(pool, async (tx) => {
|
|
192
|
+
await tx.unsafe("SELECT auth.init_tenant($1::uuid)", [opts.tenantId]);
|
|
193
|
+
}, fn);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* postgres-js Drizzle variant of `withOwnerContext`. Opens a tx on the
|
|
197
|
+
* `owner` (BYPASSRLS) pool with no GUCs. Migrations only per § 5.3 +
|
|
198
|
+
* doctrine § 10.2 — gated by `NODII_ENV=migrate` or explicit
|
|
199
|
+
* `{ allowOutsideMigrate: true, reason }` opt-in.
|
|
200
|
+
*/
|
|
201
|
+
export async function withOwnerContextDbPostgresJs(fnOrOpts, maybeFn) {
|
|
202
|
+
const { opts, fn } = normalizeOwnerArgs(fnOrOpts, maybeFn);
|
|
203
|
+
try {
|
|
204
|
+
assertMigrateAllowed(opts);
|
|
205
|
+
}
|
|
206
|
+
catch (err) {
|
|
207
|
+
recordOwnerContextInvocation("refused");
|
|
208
|
+
throw err;
|
|
209
|
+
}
|
|
210
|
+
recordOwnerContextInvocation("allowed");
|
|
211
|
+
const pool = requirePostgresJsPool("owner");
|
|
212
|
+
return withPostgresJsTx(pool, async () => { }, fn);
|
|
213
|
+
}
|
|
214
|
+
function normalizeOwnerArgs(fnOrOpts, maybeFn) {
|
|
215
|
+
if (typeof fnOrOpts === "function") {
|
|
216
|
+
return { opts: {}, fn: fnOrOpts };
|
|
217
|
+
}
|
|
218
|
+
if (!maybeFn) {
|
|
219
|
+
throw new TypeError("withOwnerContextDbPostgresJs: when opts are passed, the second argument must be the callback.");
|
|
220
|
+
}
|
|
221
|
+
return { opts: fnOrOpts, fn: maybeFn };
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=postgres-js-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres-js-client.js","sourceRoot":"","sources":["../src/postgres-js-client.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
/** PoolKind names map 1:1 to the canonical
|
|
2
|
-
|
|
1
|
+
/** PoolKind names map 1:1 to the canonical pool roles.
|
|
2
|
+
*
|
|
3
|
+
* v0.4.0 adds `platform_ops` per hub decision D185 — a 4th
|
|
4
|
+
* RLS-bound pool with RBAC-gated cross-tenant + platform-global
|
|
5
|
+
* predicates via the `platform_ops_grants` table. NOT BYPASSRLS
|
|
6
|
+
* (unlike owner): just a different predicate shape. */
|
|
7
|
+
export type PoolKind = "owner" | "services" | "authenticated" | "platform_ops";
|
|
3
8
|
/** Pluggable transaction handle — substrate-agnostic. v0.1.0 ships the
|
|
4
9
|
* in-memory transcript-recording test double; pg / psycopg / pgx adapters
|
|
5
10
|
* arrive in v0.1.x. */
|
|
@@ -18,6 +23,16 @@ export interface PgPool {
|
|
|
18
23
|
/** Acquire a connection, BEGIN a tx, yield, and COMMIT/ROLLBACK. */
|
|
19
24
|
withTransaction<T>(fn: (tx: PgTx) => Promise<T>): Promise<T>;
|
|
20
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* Pool topology mode. v0.2.x adds the `2-pool` exception per
|
|
28
|
+
* `08-rls-doctrine § 7` — nodii-auth runs owner + services only until
|
|
29
|
+
* its admin portal lands. v0.4.0 adds the 4-pool platform-ops variant
|
|
30
|
+
* per hub decision D185 — services that expose a platform-ops surface
|
|
31
|
+
* (nodii-tenant-service, nodii-billing-service, etc.) add a 4th
|
|
32
|
+
* `platform_ops` pool with RBAC-gated grants policies. Default is
|
|
33
|
+
* `3-pool`.
|
|
34
|
+
*/
|
|
35
|
+
export type DbRlsMode = "3-pool" | "2-pool" | "3-pool-with-platform-ops";
|
|
21
36
|
/** Auth context bound by `@nodii/auth-sdk` middleware. Mirrors the
|
|
22
37
|
* fields autoDispatch reads — kept structural so the real auth-sdk
|
|
23
38
|
* context shape can grow without breaking us. */
|
|
@@ -44,6 +59,34 @@ export interface AutoDispatchOpts {
|
|
|
44
59
|
authContext?: AuthContext;
|
|
45
60
|
tenantId?: string;
|
|
46
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* withPlatformOps opts. Per hub decision D185:
|
|
64
|
+
* - `userId` — verified principal id (sub) from JWT.
|
|
65
|
+
* - `serviceId` — which consumer service's platform-ops surface
|
|
66
|
+
* this request is exercising. Must match the `service_id` column
|
|
67
|
+
* in `platform_ops_grants_replica` for the grants-predicate to
|
|
68
|
+
* allow the row.
|
|
69
|
+
* - `permission` — the specific catalog entry being exercised
|
|
70
|
+
* (e.g. `"modules.write"`, `"tenant.read"`). Denormalized in the
|
|
71
|
+
* JWT `permissions[]` array per E6; matched against the
|
|
72
|
+
* `permission` column in `platform_ops_grants_replica`.
|
|
73
|
+
* - `grantId` — optional audit linkage to a specific grant row.
|
|
74
|
+
* - `supportTicketId` — optional linkage for support-engineer
|
|
75
|
+
* flows; emitted as a span attribute for forensic tracing.
|
|
76
|
+
*
|
|
77
|
+
* Sets transaction-local GUCs `app.user_id` +
|
|
78
|
+
* `app.platform_ops_service_id` + `app.platform_ops_permission` per
|
|
79
|
+
* D185 § 4. The RLS policies on the table being accessed read these
|
|
80
|
+
* GUCs and join against `platform_ops_grants_replica` to decide
|
|
81
|
+
* allow/deny per-row.
|
|
82
|
+
*/
|
|
83
|
+
export interface PlatformOpsContextOpts {
|
|
84
|
+
userId: string;
|
|
85
|
+
serviceId: string;
|
|
86
|
+
permission: string;
|
|
87
|
+
grantId?: string;
|
|
88
|
+
supportTicketId?: string;
|
|
89
|
+
}
|
|
47
90
|
/** generateRlsPolicy opts. */
|
|
48
91
|
export interface GenerateRlsPolicyOpts {
|
|
49
92
|
/** Table name (unqualified). */
|
|
@@ -68,4 +111,27 @@ export declare class TransactionRolledBack extends DbRlsError {
|
|
|
68
111
|
readonly cause: unknown;
|
|
69
112
|
constructor(cause: unknown);
|
|
70
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Thrown by `withOwnerContext` / `withOwnerContextDb` when invoked outside
|
|
116
|
+
* `NODII_ENV=migrate` per `08-rls-doctrine § 10.2`. The owner pool runs
|
|
117
|
+
* BYPASSRLS — invoking it from a request handler is a tenant-isolation
|
|
118
|
+
* escape and must be loud + refused by default. Migration scripts opt in
|
|
119
|
+
* by setting `NODII_ENV=migrate`; ops tooling that genuinely needs owner
|
|
120
|
+
* access at runtime opts in by passing `{ allowOutsideMigrate: true }`
|
|
121
|
+
* with an operator-attested reason (audit row emitted in a future slot).
|
|
122
|
+
*/
|
|
123
|
+
export declare class OwnerContextOutsideMigrate extends DbRlsError {
|
|
124
|
+
readonly nodiiEnv: string;
|
|
125
|
+
constructor(nodiiEnv: string);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Thrown by `initDbRls` / `configureDbRls` when the supplied pool topology
|
|
129
|
+
* doesn't match the declared `mode`. E.g. `mode: "3-pool"` without a
|
|
130
|
+
* `services` pool, or `mode: "2-pool"` with an `authenticated` pool
|
|
131
|
+
* supplied (the 2-pool exception has no authenticated role per
|
|
132
|
+
* 08-rls § 7).
|
|
133
|
+
*/
|
|
134
|
+
export declare class DbRlsConfigError extends DbRlsError {
|
|
135
|
+
constructor(message: string);
|
|
136
|
+
}
|
|
71
137
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAoBA
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAoBA;;;;;wDAKwD;AACxD,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,eAAe,GAAG,cAAc,CAAC;AAE/E;;wBAEwB;AACxB,MAAM,WAAW,IAAI;IACnB,6CAA6C;IAC7C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D,uDAAuD;IACvD,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;CAC7B;AAED,sEAAsE;AACtE,MAAM,WAAW,MAAM;IACrB,iDAAiD;IACjD,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,oEAAoE;IACpE,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC9D;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,0BAA0B,CAAC;AAEzE;;kDAEkD;AAClD,MAAM,WAAW,WAAW;IAC1B,mCAAmC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,4BAA4B;AAC5B,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,8BAA8B;AAC9B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,yBAAyB;AACzB,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,8BAA8B;AAC9B,MAAM,WAAW,qBAAqB;IACpC,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAKD,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B;AAED,qBAAa,mBAAoB,SAAQ,UAAU;;CAOlD;AAED,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;gBACZ,IAAI,EAAE,QAAQ;CAK3B;AAED,qBAAa,oBAAqB,SAAQ,UAAU;;CAOnD;AAED,qBAAa,qBAAsB,SAAQ,UAAU;IACnD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;gBACZ,KAAK,EAAE,OAAO;CAS3B;AAED;;;;;;;;GAQG;AACH,qBAAa,0BAA2B,SAAQ,UAAU;IACxD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM;CAO7B;AAED;;;;;;GAMG;AACH,qBAAa,gBAAiB,SAAQ,UAAU;gBAClC,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/types.js
CHANGED
|
@@ -27,7 +27,7 @@ export class DbRlsError extends Error {
|
|
|
27
27
|
}
|
|
28
28
|
export class DbRlsNotInitialized extends DbRlsError {
|
|
29
29
|
constructor() {
|
|
30
|
-
super("@nodii/db-rls is not initialized — call initDbRls({ owner, services, authenticated }) at process start.");
|
|
30
|
+
super("@nodii/db-rls is not initialized — call initDbRls({ owner, services, authenticated, platformOps? }) at process start.");
|
|
31
31
|
this.name = "DbRlsNotInitialized";
|
|
32
32
|
}
|
|
33
33
|
}
|
|
@@ -53,4 +53,34 @@ export class TransactionRolledBack extends DbRlsError {
|
|
|
53
53
|
this.cause = cause;
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* Thrown by `withOwnerContext` / `withOwnerContextDb` when invoked outside
|
|
58
|
+
* `NODII_ENV=migrate` per `08-rls-doctrine § 10.2`. The owner pool runs
|
|
59
|
+
* BYPASSRLS — invoking it from a request handler is a tenant-isolation
|
|
60
|
+
* escape and must be loud + refused by default. Migration scripts opt in
|
|
61
|
+
* by setting `NODII_ENV=migrate`; ops tooling that genuinely needs owner
|
|
62
|
+
* access at runtime opts in by passing `{ allowOutsideMigrate: true }`
|
|
63
|
+
* with an operator-attested reason (audit row emitted in a future slot).
|
|
64
|
+
*/
|
|
65
|
+
export class OwnerContextOutsideMigrate extends DbRlsError {
|
|
66
|
+
nodiiEnv;
|
|
67
|
+
constructor(nodiiEnv) {
|
|
68
|
+
super(`owner_context_outside_migrate: NODII_ENV=${JSON.stringify(nodiiEnv)}, expected "migrate". Owner pool BYPASSRLS — only callable during migrations (08-rls § 10.2). Set NODII_ENV=migrate for migration scripts, or pass { allowOutsideMigrate: true, reason: "..." } with operator-attested reason.`);
|
|
69
|
+
this.name = "OwnerContextOutsideMigrate";
|
|
70
|
+
this.nodiiEnv = nodiiEnv;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Thrown by `initDbRls` / `configureDbRls` when the supplied pool topology
|
|
75
|
+
* doesn't match the declared `mode`. E.g. `mode: "3-pool"` without a
|
|
76
|
+
* `services` pool, or `mode: "2-pool"` with an `authenticated` pool
|
|
77
|
+
* supplied (the 2-pool exception has no authenticated role per
|
|
78
|
+
* 08-rls § 7).
|
|
79
|
+
*/
|
|
80
|
+
export class DbRlsConfigError extends DbRlsError {
|
|
81
|
+
constructor(message) {
|
|
82
|
+
super(message);
|
|
83
|
+
this.name = "DbRlsConfigError";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
56
86
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,oEAAoE;AACpE,uEAAuE;AACvE,EAAE;AACF,gBAAgB;AAChB,qDAAqD;AACrD,uEAAuE;AACvE,0EAA0E;AAC1E,oDAAoD;AACpD,0EAA0E;AAC1E,wBAAwB;AACxB,+DAA+D;AAC/D,iDAAiD;AACjD,EAAE;AACF,uCAAuC;AACvC,0CAA0C;AAC1C,kDAAkD;AAClD,0EAA0E;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,oEAAoE;AACpE,uEAAuE;AACvE,EAAE;AACF,gBAAgB;AAChB,qDAAqD;AACrD,uEAAuE;AACvE,0EAA0E;AAC1E,oDAAoD;AACpD,0EAA0E;AAC1E,wBAAwB;AACxB,+DAA+D;AAC/D,iDAAiD;AACjD,EAAE;AACF,uCAAuC;AACvC,0CAA0C;AAC1C,kDAAkD;AAClD,0EAA0E;AA4G1E,+EAA+E;AAC/E,yBAAyB;AAEzB,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF;AAED,MAAM,OAAO,mBAAoB,SAAQ,UAAU;IACjD;QACE,KAAK,CACH,uHAAuH,CACxH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,UAAU;IACpC,IAAI,CAAW;IACxB,YAAY,IAAc;QACxB,KAAK,CAAC,yBAAyB,IAAI,sCAAsC,CAAC,CAAC;QAC3E,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,MAAM,OAAO,oBAAqB,SAAQ,UAAU;IAClD;QACE,KAAK,CACH,+EAA+E,CAChF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;IACrC,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,UAAU;IAC1C,KAAK,CAAU;IACxB,YAAY,KAAc;QACxB,KAAK,CACH,4BACE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CACvD,EAAE,CACH,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,0BAA2B,SAAQ,UAAU;IAC/C,QAAQ,CAAS;IAC1B,YAAY,QAAgB;QAC1B,KAAK,CACH,4CAA4C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,gOAAgO,CACrS,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF"}
|