@venturekit/data 0.0.0-dev.20260721010549 → 0.0.0-dev.20260725205100
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/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/query/index.d.ts +1 -0
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/index.js +28 -1
- package/dist/query/index.js.map +1 -1
- package/dist/query/pool.d.ts +40 -0
- package/dist/query/pool.d.ts.map +1 -1
- package/dist/query/pool.js +67 -0
- package/dist/query/pool.js.map +1 -1
- package/dist/query/tenant.d.ts +134 -0
- package/dist/query/tenant.d.ts.map +1 -0
- package/dist/query/tenant.js +197 -0
- package/dist/query/tenant.js.map +1 -0
- package/dist/query/transaction.d.ts.map +1 -1
- package/dist/query/transaction.js +6 -0
- package/dist/query/transaction.js.map +1 -1
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,6 @@ export { createRdsConfig, DEFAULT_RDS_CONFIG, buildRdsConfig, } from './rds/inde
|
|
|
8
8
|
export type { RdsOutputs, RdsInfraConfig } from './rds/index.js';
|
|
9
9
|
export { createMigrationConfig, DEFAULT_MIGRATION_CONFIG, getFlywayEnv, runMigrations, getMigrationStatus, runSeeds, getSeedStatus, MIGRATIONS_TRACKING_TABLE, SEEDS_TRACKING_TABLE, MigrationToolNotImplementedError, MigrationHashMismatchError, MigrationCollisionError, applyDatabaseUrlToEnv, } from './migrations/index.js';
|
|
10
10
|
export type { RunResult, StatusEntry, RunOptions, SeedRunOptions, } from './migrations/index.js';
|
|
11
|
-
export { query, getPool, mapResults, mapRow, configureMapper, getMapperConfig, beginTransaction, withTransaction, buildTransaction, applyDbSecretToEnv, } from './query/index.js';
|
|
11
|
+
export { query, getPool, mapResults, mapRow, configureMapper, getMapperConfig, beginTransaction, withTransaction, buildTransaction, applyDbSecretToEnv, TENANT_GUC, runWithTenant, runWithoutTenant, getCurrentTenantId, isTenancyEngaged, } from './query/index.js';
|
|
12
12
|
export type { Transaction, ResultsMapper, Querier, MapperOptions, } from './query/index.js';
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKjE,OAAO,EAEL,qBAAqB,EACrB,wBAAwB,EACxB,YAAY,EAEZ,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,yBAAyB,EACzB,oBAAoB,EAEpB,gCAAgC,EAChC,0BAA0B,EAC1B,uBAAuB,EAGvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAKhB,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKjE,OAAO,EAEL,qBAAqB,EACrB,wBAAwB,EACxB,YAAY,EAEZ,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,yBAAyB,EACzB,oBAAoB,EAEpB,gCAAgC,EAChC,0BAA0B,EAC1B,uBAAuB,EAGvB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,SAAS,EACT,WAAW,EACX,UAAU,EACV,cAAc,GACf,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAKhB,kBAAkB,EAOlB,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,WAAW,EACX,aAAa,EACb,OAAO,EACP,aAAa,GACd,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -26,5 +26,12 @@ export { query, getPool, mapResults, mapRow, configureMapper, getMapperConfig, b
|
|
|
26
26
|
// Secrets Manager when `DB_SECRET_ARN` is set. Auto-applied at the
|
|
27
27
|
// top of `query()` and `beginTransaction()`, so consumers rarely
|
|
28
28
|
// need to call this themselves.
|
|
29
|
-
applyDbSecretToEnv,
|
|
29
|
+
applyDbSecretToEnv,
|
|
30
|
+
// Tenant context for row-level security. Wrap a request in
|
|
31
|
+
// `runWithTenant(id, fn)` and every query inside it — pooled or
|
|
32
|
+
// transactional — carries the `app.tenant_id` GUC, so RLS policies
|
|
33
|
+
// enforce isolation the application SQL may have forgotten.
|
|
34
|
+
// See ./query/tenant.ts for the required policy shape and the
|
|
35
|
+
// database-role split RLS depends on.
|
|
36
|
+
TENANT_GUC, runWithTenant, runWithoutTenant, getCurrentTenantId, isTenancyEngaged, } from './query/index.js';
|
|
30
37
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,QAAQ;AACR,cAAc,kBAAkB,CAAC;AAEjC,MAAM;AACN,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,uEAAuE;AACvE,iEAAiE;AACjE,gDAAgD;AAChD,OAAO;AACL,4BAA4B;AAC5B,qBAAqB,EACrB,wBAAwB,EACxB,YAAY;AACZ,sEAAsE;AACtE,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,yBAAyB,EACzB,oBAAoB;AACpB,SAAS;AACT,gCAAgC,EAChC,0BAA0B,EAC1B,uBAAuB;AACvB,uEAAuE;AACvE,qEAAqE;AACrE,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAQ/B,kDAAkD;AAClD,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB;AAChB,0DAA0D;AAC1D,mEAAmE;AACnE,iEAAiE;AACjE,gCAAgC;AAChC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,QAAQ;AACR,cAAc,kBAAkB,CAAC;AAEjC,MAAM;AACN,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,GACf,MAAM,gBAAgB,CAAC;AAGxB,uEAAuE;AACvE,iEAAiE;AACjE,gDAAgD;AAChD,OAAO;AACL,4BAA4B;AAC5B,qBAAqB,EACrB,wBAAwB,EACxB,YAAY;AACZ,sEAAsE;AACtE,aAAa,EACb,kBAAkB,EAClB,QAAQ,EACR,aAAa,EACb,yBAAyB,EACzB,oBAAoB;AACpB,SAAS;AACT,gCAAgC,EAChC,0BAA0B,EAC1B,uBAAuB;AACvB,uEAAuE;AACvE,qEAAqE;AACrE,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAQ/B,kDAAkD;AAClD,OAAO,EACL,KAAK,EACL,OAAO,EACP,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,gBAAgB;AAChB,0DAA0D;AAC1D,mEAAmE;AACnE,iEAAiE;AACjE,gCAAgC;AAChC,kBAAkB;AAClB,2DAA2D;AAC3D,gEAAgE;AAChE,mEAAmE;AACnE,4DAA4D;AAC5D,8DAA8D;AAC9D,sCAAsC;AACtC,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC"}
|
package/dist/query/index.d.ts
CHANGED
|
@@ -56,6 +56,7 @@ import type { ResultsMapper } from './transaction.js';
|
|
|
56
56
|
export declare const DEFAULT_SLOW_QUERY_THRESHOLD_MS = 1000;
|
|
57
57
|
export { getPool, applyDatabaseUrlToEnv } from './pool.js';
|
|
58
58
|
export { applyDbSecretToEnv } from './secret.js';
|
|
59
|
+
export { TENANT_GUC, runWithTenant, runWithoutTenant, getCurrentTenantId, isTenancyEngaged, } from './tenant.js';
|
|
59
60
|
export { mapResults, mapRow, configureMapper, getMapperConfig, } from './mapper.js';
|
|
60
61
|
export type { MapperOptions } from './mapper.js';
|
|
61
62
|
export { beginTransaction, withTransaction, buildTransaction, } from './transaction.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAIH,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAIH,OAAO,EAAsB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKtD;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,OAAQ,CAAC;AAqBrD,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AA+B5E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAsB,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACvD,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,OAAO,EAAE,EACvB,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,EAChC,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,CAAC,CAAC,CA6CZ"}
|
package/dist/query/index.js
CHANGED
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
import { getPool } from './pool.js';
|
|
48
48
|
import { mapResults } from './mapper.js';
|
|
49
49
|
import { applyDbSecretToEnv } from './secret.js';
|
|
50
|
+
import { applyTenantToClient, isTenancyEngaged } from './tenant.js';
|
|
50
51
|
import { dbLog } from '../internal/logger.js';
|
|
51
52
|
/**
|
|
52
53
|
* Default threshold above which a successful query is logged as slow.
|
|
@@ -76,8 +77,34 @@ function previewSql(sql) {
|
|
|
76
77
|
}
|
|
77
78
|
export { getPool, applyDatabaseUrlToEnv } from './pool.js';
|
|
78
79
|
export { applyDbSecretToEnv } from './secret.js';
|
|
80
|
+
export { TENANT_GUC, runWithTenant, runWithoutTenant, getCurrentTenantId, isTenancyEngaged, } from './tenant.js';
|
|
79
81
|
export { mapResults, mapRow, configureMapper, getMapperConfig, } from './mapper.js';
|
|
80
82
|
export { beginTransaction, withTransaction, buildTransaction, } from './transaction.js';
|
|
83
|
+
/**
|
|
84
|
+
* Run one statement, ensuring the tenant GUC is in place when tenancy
|
|
85
|
+
* is engaged.
|
|
86
|
+
*
|
|
87
|
+
* `pool.query()` borrows a connection for the duration of a single
|
|
88
|
+
* statement, which is why the tenant-scoped path checks out the
|
|
89
|
+
* connection EXPLICITLY: `set_config` and the statement itself must
|
|
90
|
+
* land on the same physical connection, and only an explicit checkout
|
|
91
|
+
* guarantees that. When tenancy has never been engaged we keep the
|
|
92
|
+
* original `pool.query()` call so existing consumers see no behavioural
|
|
93
|
+
* or performance change at all.
|
|
94
|
+
*/
|
|
95
|
+
async function execute(pool, sqlQuery, queryParams) {
|
|
96
|
+
if (!isTenancyEngaged()) {
|
|
97
|
+
return pool.query(sqlQuery, queryParams);
|
|
98
|
+
}
|
|
99
|
+
const client = await pool.connect();
|
|
100
|
+
try {
|
|
101
|
+
await applyTenantToClient(client);
|
|
102
|
+
return await client.query(sqlQuery, queryParams);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
client.release();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
81
108
|
/**
|
|
82
109
|
* Execute a SQL query against the connection pool.
|
|
83
110
|
*
|
|
@@ -122,7 +149,7 @@ export async function query(sqlQuery, queryParams, resultsMapper, mapperOptions)
|
|
|
122
149
|
const startedAt = Date.now();
|
|
123
150
|
let res;
|
|
124
151
|
try {
|
|
125
|
-
res = await pool
|
|
152
|
+
res = await execute(pool, sqlQuery, queryParams);
|
|
126
153
|
}
|
|
127
154
|
catch (err) {
|
|
128
155
|
// Capture pg's structured fields when present (`code`, `severity`,
|
package/dist/query/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAA8B,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,KAAK,CAAC;AAErD,SAAS,2BAA2B;IAClC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;IACnD,IAAI,CAAC,GAAG;QAAE,OAAO,+BAA+B,CAAC;IACjD,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,+BAA+B,CAAC;AAC5E,CAAC;AAED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;AACrE,CAAC;AAED,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EACL,UAAU,EACV,MAAM,EACN,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAG1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CACzB,QAAgB,EAChB,WAAuB,EACvB,aAAgC,EAChC,aAA6B;IAE7B,sEAAsE;IACtE,0EAA0E;IAC1E,8EAA8E;IAC9E,6CAA6C;IAC7C,MAAM,kBAAkB,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IAEvB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,GAAgB,CAAC;IACrB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/query/index.ts"],"names":[],"mappings":"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"}
|
package/dist/query/pool.d.ts
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* - DB_SSL_INSECURE ("true" to skip certificate verification — NOT recommended)
|
|
16
16
|
* - DB_POOL_MAX (default 10)
|
|
17
17
|
* - DB_CONNECT_TIMEOUT_MS (default 5000)
|
|
18
|
+
* - DB_QUERY_TIMEOUT_MS (client-side per-query ceiling; default 0 = disabled)
|
|
19
|
+
* - DB_KEEPALIVE_INITIAL_DELAY_MS (TCP keepalive first-probe delay; default 10000)
|
|
18
20
|
*
|
|
19
21
|
* The connection-timeout default is intentionally well below the 10 s
|
|
20
22
|
* Lambda timeout used by the `nano` / `micro` presets: an unreachable
|
|
@@ -31,6 +33,44 @@ import { Pool, type PoolConfig } from 'pg';
|
|
|
31
33
|
* to RDS Postgres) don't get false-positive aborts.
|
|
32
34
|
*/
|
|
33
35
|
export declare const DEFAULT_CONNECT_TIMEOUT_MS = 5000;
|
|
36
|
+
/**
|
|
37
|
+
* Default `pg.Client#query_timeout` — a CLIENT-side per-query ceiling, in ms.
|
|
38
|
+
*
|
|
39
|
+
* `0` (the default) leaves it disabled, preserving pre-existing behavior.
|
|
40
|
+
* Unlike a server-side `statement_timeout`, a client-side timeout fires
|
|
41
|
+
* even when the TCP connection is a black hole — the server never receives
|
|
42
|
+
* the query and so can never cancel it. That is exactly the failure mode of
|
|
43
|
+
* a pooled connection reused after a Lambda freeze/thaw, where the socket
|
|
44
|
+
* died mid-freeze: without a client ceiling the query hangs until the OS TCP
|
|
45
|
+
* retransmit budget is exhausted (minutes), which is how a fire-and-forget
|
|
46
|
+
* write can surface as a ~300 s "connection timeout".
|
|
47
|
+
*
|
|
48
|
+
* It is pool-wide (inherited by every pooled client, transaction clients
|
|
49
|
+
* included), so it is DISABLED by default and must be opted into via
|
|
50
|
+
* `DB_QUERY_TIMEOUT_MS` on runtime Lambdas ONLY — never in the migration
|
|
51
|
+
* runner, whose long index builds run with `statementTimeoutMs: 0` and would
|
|
52
|
+
* be aborted client-side by it.
|
|
53
|
+
*/
|
|
54
|
+
export declare const DEFAULT_QUERY_TIMEOUT_MS = 0;
|
|
55
|
+
/**
|
|
56
|
+
* Resolve the client-side `query_timeout` (ms) from `DB_QUERY_TIMEOUT_MS`.
|
|
57
|
+
* Falls back to the (disabled) default on unset / non-finite / negative
|
|
58
|
+
* values, matching `resolveConnectionTimeoutMs`. Exported for the unit tests.
|
|
59
|
+
*/
|
|
60
|
+
export declare function resolveQueryTimeoutMs(): number;
|
|
61
|
+
/**
|
|
62
|
+
* Default TCP-keepalive first-probe delay (ms). `keepAlive` is enabled
|
|
63
|
+
* unconditionally on the pool so a peer that vanished while the socket sat
|
|
64
|
+
* idle (e.g. an RDS connection dropped during a Lambda freeze) is detected
|
|
65
|
+
* by the OS rather than lingering as a half-open connection. This value maps
|
|
66
|
+
* to TCP_KEEPIDLE — how long the socket is idle before the first probe.
|
|
67
|
+
*/
|
|
68
|
+
export declare const DEFAULT_KEEPALIVE_INITIAL_DELAY_MS = 10000;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve the TCP-keepalive first-probe delay (ms) from
|
|
71
|
+
* `DB_KEEPALIVE_INITIAL_DELAY_MS`. Exported for the unit tests.
|
|
72
|
+
*/
|
|
73
|
+
export declare function resolveKeepAliveInitialDelayMs(): number;
|
|
34
74
|
/**
|
|
35
75
|
* Bridge `DATABASE_URL` into the granular `DB_*` slots `getPool()` reads.
|
|
36
76
|
* Idempotent — only fills slots that aren't already set, so the granular
|
package/dist/query/pool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/query/pool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/query/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,IAAI,EAAE,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AAM3C;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,OAAQ,CAAC;AAShD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAK9C;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kCAAkC,QAAS,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,8BAA8B,IAAI,MAAM,CAKvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAoC5C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAG3D;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,GAAG,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC;IACvB,IAAI,EAAE,KAAK,GAAG,UAAU,GAAG,oBAAoB,GAAG,qBAAqB,GAAG,oBAAoB,CAAC;CAChG,CAAC;AAEF,8DAA8D;AAC9D,wBAAgB,UAAU,IAAI,WAAW,CA8CxC;AAED,wBAAgB,OAAO,IAAI,IAAI,CAqE9B"}
|
package/dist/query/pool.js
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* - DB_SSL_INSECURE ("true" to skip certificate verification — NOT recommended)
|
|
16
16
|
* - DB_POOL_MAX (default 10)
|
|
17
17
|
* - DB_CONNECT_TIMEOUT_MS (default 5000)
|
|
18
|
+
* - DB_QUERY_TIMEOUT_MS (client-side per-query ceiling; default 0 = disabled)
|
|
19
|
+
* - DB_KEEPALIVE_INITIAL_DELAY_MS (TCP keepalive first-probe delay; default 10000)
|
|
18
20
|
*
|
|
19
21
|
* The connection-timeout default is intentionally well below the 10 s
|
|
20
22
|
* Lambda timeout used by the `nano` / `micro` presets: an unreachable
|
|
@@ -41,6 +43,56 @@ function resolveConnectionTimeoutMs() {
|
|
|
41
43
|
const n = Number.parseInt(raw, 10);
|
|
42
44
|
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_CONNECT_TIMEOUT_MS;
|
|
43
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Default `pg.Client#query_timeout` — a CLIENT-side per-query ceiling, in ms.
|
|
48
|
+
*
|
|
49
|
+
* `0` (the default) leaves it disabled, preserving pre-existing behavior.
|
|
50
|
+
* Unlike a server-side `statement_timeout`, a client-side timeout fires
|
|
51
|
+
* even when the TCP connection is a black hole — the server never receives
|
|
52
|
+
* the query and so can never cancel it. That is exactly the failure mode of
|
|
53
|
+
* a pooled connection reused after a Lambda freeze/thaw, where the socket
|
|
54
|
+
* died mid-freeze: without a client ceiling the query hangs until the OS TCP
|
|
55
|
+
* retransmit budget is exhausted (minutes), which is how a fire-and-forget
|
|
56
|
+
* write can surface as a ~300 s "connection timeout".
|
|
57
|
+
*
|
|
58
|
+
* It is pool-wide (inherited by every pooled client, transaction clients
|
|
59
|
+
* included), so it is DISABLED by default and must be opted into via
|
|
60
|
+
* `DB_QUERY_TIMEOUT_MS` on runtime Lambdas ONLY — never in the migration
|
|
61
|
+
* runner, whose long index builds run with `statementTimeoutMs: 0` and would
|
|
62
|
+
* be aborted client-side by it.
|
|
63
|
+
*/
|
|
64
|
+
export const DEFAULT_QUERY_TIMEOUT_MS = 0;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve the client-side `query_timeout` (ms) from `DB_QUERY_TIMEOUT_MS`.
|
|
67
|
+
* Falls back to the (disabled) default on unset / non-finite / negative
|
|
68
|
+
* values, matching `resolveConnectionTimeoutMs`. Exported for the unit tests.
|
|
69
|
+
*/
|
|
70
|
+
export function resolveQueryTimeoutMs() {
|
|
71
|
+
const raw = process.env.DB_QUERY_TIMEOUT_MS;
|
|
72
|
+
if (!raw)
|
|
73
|
+
return DEFAULT_QUERY_TIMEOUT_MS;
|
|
74
|
+
const n = Number.parseInt(raw, 10);
|
|
75
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_QUERY_TIMEOUT_MS;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Default TCP-keepalive first-probe delay (ms). `keepAlive` is enabled
|
|
79
|
+
* unconditionally on the pool so a peer that vanished while the socket sat
|
|
80
|
+
* idle (e.g. an RDS connection dropped during a Lambda freeze) is detected
|
|
81
|
+
* by the OS rather than lingering as a half-open connection. This value maps
|
|
82
|
+
* to TCP_KEEPIDLE — how long the socket is idle before the first probe.
|
|
83
|
+
*/
|
|
84
|
+
export const DEFAULT_KEEPALIVE_INITIAL_DELAY_MS = 10_000;
|
|
85
|
+
/**
|
|
86
|
+
* Resolve the TCP-keepalive first-probe delay (ms) from
|
|
87
|
+
* `DB_KEEPALIVE_INITIAL_DELAY_MS`. Exported for the unit tests.
|
|
88
|
+
*/
|
|
89
|
+
export function resolveKeepAliveInitialDelayMs() {
|
|
90
|
+
const raw = process.env.DB_KEEPALIVE_INITIAL_DELAY_MS;
|
|
91
|
+
if (!raw)
|
|
92
|
+
return DEFAULT_KEEPALIVE_INITIAL_DELAY_MS;
|
|
93
|
+
const n = Number.parseInt(raw, 10);
|
|
94
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_KEEPALIVE_INITIAL_DELAY_MS;
|
|
95
|
+
}
|
|
44
96
|
/**
|
|
45
97
|
* Bridge `DATABASE_URL` into the granular `DB_*` slots `getPool()` reads.
|
|
46
98
|
* Idempotent — only fills slots that aren't already set, so the granular
|
|
@@ -157,6 +209,8 @@ export function getPool() {
|
|
|
157
209
|
const { ssl, mode: sslMode } = resolveSsl();
|
|
158
210
|
const max = Number(process.env.DB_POOL_MAX ?? 10);
|
|
159
211
|
const connectionTimeoutMillis = resolveConnectionTimeoutMs();
|
|
212
|
+
const queryTimeoutMillis = resolveQueryTimeoutMs();
|
|
213
|
+
const keepAliveInitialDelayMillis = resolveKeepAliveInitialDelayMs();
|
|
160
214
|
const host = process.env.DB_HOST;
|
|
161
215
|
const port = Number(process.env.DB_PORT ?? 5432);
|
|
162
216
|
const database = process.env.DB_NAME;
|
|
@@ -180,6 +234,9 @@ export function getPool() {
|
|
|
180
234
|
sslMode,
|
|
181
235
|
max,
|
|
182
236
|
connectionTimeoutMillis,
|
|
237
|
+
// 0 = disabled; any positive value is a hard client-side ceiling.
|
|
238
|
+
queryTimeoutMillis,
|
|
239
|
+
keepAliveInitialDelayMillis,
|
|
183
240
|
});
|
|
184
241
|
pool = new Pool({
|
|
185
242
|
host,
|
|
@@ -190,6 +247,16 @@ export function getPool() {
|
|
|
190
247
|
ssl,
|
|
191
248
|
max,
|
|
192
249
|
connectionTimeoutMillis,
|
|
250
|
+
// Enable TCP keepalive so a connection whose peer disappeared while
|
|
251
|
+
// this Lambda was frozen is detected by the OS instead of looking
|
|
252
|
+
// healthy until the next query hangs on the dead socket.
|
|
253
|
+
keepAlive: true,
|
|
254
|
+
keepAliveInitialDelayMillis,
|
|
255
|
+
// Only set query_timeout when explicitly enabled (> 0). Left off by
|
|
256
|
+
// default so the migration runner (long index builds via
|
|
257
|
+
// beginTransaction({ statementTimeoutMs: 0 })) is never aborted
|
|
258
|
+
// client-side. Enable via DB_QUERY_TIMEOUT_MS on runtime Lambdas.
|
|
259
|
+
...(queryTimeoutMillis > 0 ? { query_timeout: queryTimeoutMillis } : {}),
|
|
193
260
|
});
|
|
194
261
|
// Async pool errors (e.g. an idle client losing its TCP connection)
|
|
195
262
|
// would otherwise crash the Lambda with no breadcrumb. Capture them
|
package/dist/query/pool.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/query/pool.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/query/pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant context for row-level security (RLS).
|
|
3
|
+
*
|
|
4
|
+
* # What this is for
|
|
5
|
+
*
|
|
6
|
+
* Multi-tenant apps filter nearly every query by a tenant column. That
|
|
7
|
+
* filter is applied by hand, in application SQL, hundreds of times —
|
|
8
|
+
* and a single omission silently returns another tenant's rows. Neither
|
|
9
|
+
* the type system nor code review reliably catches it: the usual shape
|
|
10
|
+
* is "resolve the row by primary key after checking the tenant
|
|
11
|
+
* separately", so the dangerous query looks identical to the safe one.
|
|
12
|
+
*
|
|
13
|
+
* This module moves the guarantee into Postgres. The caller wraps a
|
|
14
|
+
* request in {@link runWithTenant}; every query issued inside that
|
|
15
|
+
* scope — pooled or transactional — runs with the `app.tenant_id` GUC
|
|
16
|
+
* set, so RLS policies can filter rows the application forgot to.
|
|
17
|
+
* A missing predicate then yields ZERO rows instead of a cross-tenant
|
|
18
|
+
* leak.
|
|
19
|
+
*
|
|
20
|
+
* # The policy shape this expects
|
|
21
|
+
*
|
|
22
|
+
* ```sql
|
|
23
|
+
* ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
|
|
24
|
+
* ALTER TABLE posts FORCE ROW LEVEL SECURITY;
|
|
25
|
+
* CREATE POLICY tenant_isolation ON posts
|
|
26
|
+
* USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::uuid);
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Two details matter:
|
|
30
|
+
* - the `true` second argument to `current_setting` makes an UNSET
|
|
31
|
+
* GUC return NULL rather than raising;
|
|
32
|
+
* - `NULLIF(..., '')` maps the "no tenant" sentinel this module
|
|
33
|
+
* writes onto NULL, so the comparison is NULL, so the row is
|
|
34
|
+
* filtered. **Unset means nothing is visible** — fail-closed. Get
|
|
35
|
+
* this wrong (e.g. omit the NULLIF and cast `''::uuid`) and you
|
|
36
|
+
* trade a leak for a runtime error on every unscoped query.
|
|
37
|
+
*
|
|
38
|
+
* RLS does not apply to a table's OWNER unless `FORCE ROW LEVEL
|
|
39
|
+
* SECURITY` is set, and is skipped entirely for roles with `BYPASSRLS`.
|
|
40
|
+
* Run the application as a role that owns nothing and has neither
|
|
41
|
+
* attribute; keep migrations and platform-level jobs on a separate
|
|
42
|
+
* privileged role. Enabling RLS without that split gives you the
|
|
43
|
+
* overhead and none of the protection.
|
|
44
|
+
*
|
|
45
|
+
* # Why the GUC is set per connection, not per query
|
|
46
|
+
*
|
|
47
|
+
* `query()` borrows a connection from the pool for the duration of one
|
|
48
|
+
* statement, so a session-level `SET` would not survive to the next
|
|
49
|
+
* call, and `SET LOCAL` requires an open transaction. Instead the
|
|
50
|
+
* applied value is memoized per physical connection: the extra
|
|
51
|
+
* round-trip is paid only when a connection's tenant actually changes.
|
|
52
|
+
* A warm Lambda container serving one tenant pays it once.
|
|
53
|
+
*
|
|
54
|
+
* Transactions take the cheaper path — `set_config(..., is_local =>
|
|
55
|
+
* true)`, which reverts on COMMIT/ROLLBACK and therefore never
|
|
56
|
+
* disturbs the memoized session value.
|
|
57
|
+
*
|
|
58
|
+
* # Backwards compatibility
|
|
59
|
+
*
|
|
60
|
+
* Consumers that never call {@link runWithTenant} are untouched: the
|
|
61
|
+
* module stays dormant until the first call, and `query()` keeps using
|
|
62
|
+
* `pool.query()` directly with no added statements.
|
|
63
|
+
*/
|
|
64
|
+
import type { PoolClient } from 'pg';
|
|
65
|
+
/**
|
|
66
|
+
* The GUC that carries the current tenant into Postgres. `app.` is a
|
|
67
|
+
* customizable-options prefix, so no superuser configuration is
|
|
68
|
+
* needed for the setting to exist.
|
|
69
|
+
*/
|
|
70
|
+
export declare const TENANT_GUC = "app.tenant_id";
|
|
71
|
+
/** True once tenancy has been engaged. Read by `query()`. */
|
|
72
|
+
export declare function isTenancyEngaged(): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The tenant id for the current async scope, or `null` outside any
|
|
75
|
+
* scope / inside a {@link runWithoutTenant} block.
|
|
76
|
+
*/
|
|
77
|
+
export declare function getCurrentTenantId(): string | null;
|
|
78
|
+
/**
|
|
79
|
+
* Run `fn` with `tenantId` applied to every query it issues.
|
|
80
|
+
*
|
|
81
|
+
* Wrap the whole request here — typically from tenant-resolution
|
|
82
|
+
* middleware, once `ctx.tenant` is known — so repos and helpers
|
|
83
|
+
* inherit the scope without threading an argument through every
|
|
84
|
+
* signature.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* await runWithTenant(ctx.tenant.id, async () => {
|
|
89
|
+
* // Any query in here, at any depth, is tenant-scoped by Postgres.
|
|
90
|
+
* return handler(body, ctx);
|
|
91
|
+
* });
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function runWithTenant<T>(tenantId: string, fn: () => Promise<T>): Promise<T>;
|
|
95
|
+
/**
|
|
96
|
+
* Run `fn` with NO tenant applied, clearing any inherited scope.
|
|
97
|
+
*
|
|
98
|
+
* For work that is legitimately cross-tenant: resolving which tenant a
|
|
99
|
+
* hostname belongs to, platform-operator queries, cron jobs sweeping
|
|
100
|
+
* every tenant. Queries inside still execute against RLS with an
|
|
101
|
+
* unset GUC, so tenant-scoped tables return nothing — the caller is
|
|
102
|
+
* expected to be reading un-scoped tables, or to be connected as a
|
|
103
|
+
* privileged role that bypasses RLS.
|
|
104
|
+
*
|
|
105
|
+
* Deliberately verbose to write. An escape hatch should be visible in
|
|
106
|
+
* review.
|
|
107
|
+
*/
|
|
108
|
+
export declare function runWithoutTenant<T>(fn: () => Promise<T>): Promise<T>;
|
|
109
|
+
/**
|
|
110
|
+
* Ensure `client`'s session GUC matches the current scope, issuing
|
|
111
|
+
* `set_config` only when it differs.
|
|
112
|
+
*
|
|
113
|
+
* Uses a bound parameter — GUC values are user-controlled tenant ids
|
|
114
|
+
* and `SET` does not accept placeholders, so `set_config()` is the
|
|
115
|
+
* only injection-safe way to write one.
|
|
116
|
+
*/
|
|
117
|
+
export declare function applyTenantToClient(client: PoolClient): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Apply the current scope's tenant to an open transaction.
|
|
120
|
+
*
|
|
121
|
+
* `is_local => true` scopes the value to the transaction, so it
|
|
122
|
+
* reverts on COMMIT/ROLLBACK and leaves the connection's session
|
|
123
|
+
* value — and therefore {@link appliedByClient} — untouched.
|
|
124
|
+
*
|
|
125
|
+
* No-op until tenancy is engaged, so existing transactional consumers
|
|
126
|
+
* are unaffected.
|
|
127
|
+
*/
|
|
128
|
+
export declare function applyTenantToTransaction(client: PoolClient): Promise<void>;
|
|
129
|
+
/**
|
|
130
|
+
* Reset module state. Test-only — production code has no reason to
|
|
131
|
+
* disengage tenancy once engaged.
|
|
132
|
+
*/
|
|
133
|
+
export declare function __resetTenancyForTests(): void;
|
|
134
|
+
//# sourceMappingURL=tenant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../src/query/tenant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAErC;;;;GAIG;AACH,eAAO,MAAM,UAAU,kBAAkB,CAAC;AAiC1C,6DAA6D;AAC7D,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAElD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CASnF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAGpE;AAaD;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAQ3E;AAED;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tenant context for row-level security (RLS).
|
|
3
|
+
*
|
|
4
|
+
* # What this is for
|
|
5
|
+
*
|
|
6
|
+
* Multi-tenant apps filter nearly every query by a tenant column. That
|
|
7
|
+
* filter is applied by hand, in application SQL, hundreds of times —
|
|
8
|
+
* and a single omission silently returns another tenant's rows. Neither
|
|
9
|
+
* the type system nor code review reliably catches it: the usual shape
|
|
10
|
+
* is "resolve the row by primary key after checking the tenant
|
|
11
|
+
* separately", so the dangerous query looks identical to the safe one.
|
|
12
|
+
*
|
|
13
|
+
* This module moves the guarantee into Postgres. The caller wraps a
|
|
14
|
+
* request in {@link runWithTenant}; every query issued inside that
|
|
15
|
+
* scope — pooled or transactional — runs with the `app.tenant_id` GUC
|
|
16
|
+
* set, so RLS policies can filter rows the application forgot to.
|
|
17
|
+
* A missing predicate then yields ZERO rows instead of a cross-tenant
|
|
18
|
+
* leak.
|
|
19
|
+
*
|
|
20
|
+
* # The policy shape this expects
|
|
21
|
+
*
|
|
22
|
+
* ```sql
|
|
23
|
+
* ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
|
|
24
|
+
* ALTER TABLE posts FORCE ROW LEVEL SECURITY;
|
|
25
|
+
* CREATE POLICY tenant_isolation ON posts
|
|
26
|
+
* USING (tenant_id = NULLIF(current_setting('app.tenant_id', true), '')::uuid);
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* Two details matter:
|
|
30
|
+
* - the `true` second argument to `current_setting` makes an UNSET
|
|
31
|
+
* GUC return NULL rather than raising;
|
|
32
|
+
* - `NULLIF(..., '')` maps the "no tenant" sentinel this module
|
|
33
|
+
* writes onto NULL, so the comparison is NULL, so the row is
|
|
34
|
+
* filtered. **Unset means nothing is visible** — fail-closed. Get
|
|
35
|
+
* this wrong (e.g. omit the NULLIF and cast `''::uuid`) and you
|
|
36
|
+
* trade a leak for a runtime error on every unscoped query.
|
|
37
|
+
*
|
|
38
|
+
* RLS does not apply to a table's OWNER unless `FORCE ROW LEVEL
|
|
39
|
+
* SECURITY` is set, and is skipped entirely for roles with `BYPASSRLS`.
|
|
40
|
+
* Run the application as a role that owns nothing and has neither
|
|
41
|
+
* attribute; keep migrations and platform-level jobs on a separate
|
|
42
|
+
* privileged role. Enabling RLS without that split gives you the
|
|
43
|
+
* overhead and none of the protection.
|
|
44
|
+
*
|
|
45
|
+
* # Why the GUC is set per connection, not per query
|
|
46
|
+
*
|
|
47
|
+
* `query()` borrows a connection from the pool for the duration of one
|
|
48
|
+
* statement, so a session-level `SET` would not survive to the next
|
|
49
|
+
* call, and `SET LOCAL` requires an open transaction. Instead the
|
|
50
|
+
* applied value is memoized per physical connection: the extra
|
|
51
|
+
* round-trip is paid only when a connection's tenant actually changes.
|
|
52
|
+
* A warm Lambda container serving one tenant pays it once.
|
|
53
|
+
*
|
|
54
|
+
* Transactions take the cheaper path — `set_config(..., is_local =>
|
|
55
|
+
* true)`, which reverts on COMMIT/ROLLBACK and therefore never
|
|
56
|
+
* disturbs the memoized session value.
|
|
57
|
+
*
|
|
58
|
+
* # Backwards compatibility
|
|
59
|
+
*
|
|
60
|
+
* Consumers that never call {@link runWithTenant} are untouched: the
|
|
61
|
+
* module stays dormant until the first call, and `query()` keeps using
|
|
62
|
+
* `pool.query()` directly with no added statements.
|
|
63
|
+
*/
|
|
64
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
65
|
+
/**
|
|
66
|
+
* The GUC that carries the current tenant into Postgres. `app.` is a
|
|
67
|
+
* customizable-options prefix, so no superuser configuration is
|
|
68
|
+
* needed for the setting to exist.
|
|
69
|
+
*/
|
|
70
|
+
export const TENANT_GUC = 'app.tenant_id';
|
|
71
|
+
/**
|
|
72
|
+
* Value written when a scope is explicitly un-tenanted
|
|
73
|
+
* ({@link runWithoutTenant}). The empty string — rather than
|
|
74
|
+
* unsetting — so the reset is an ordinary value assignment that the
|
|
75
|
+
* per-connection memo can track, and so policies distinguish "cleared"
|
|
76
|
+
* from "never set" identically via `NULLIF`.
|
|
77
|
+
*/
|
|
78
|
+
const NO_TENANT = '';
|
|
79
|
+
const storage = new AsyncLocalStorage();
|
|
80
|
+
/**
|
|
81
|
+
* Whether any caller has engaged tenancy in this process.
|
|
82
|
+
*
|
|
83
|
+
* Gates the whole feature so existing consumers see byte-identical
|
|
84
|
+
* behaviour: until someone calls {@link runWithTenant} or
|
|
85
|
+
* {@link runWithoutTenant}, `query()` must not issue `set_config` or
|
|
86
|
+
* take the explicit connect/release path.
|
|
87
|
+
*
|
|
88
|
+
* One-way latch — once engaged, every subsequent query participates,
|
|
89
|
+
* including those OUTSIDE any tenant scope. That is the fail-closed
|
|
90
|
+
* half of the design: a request that forgets to establish context does
|
|
91
|
+
* not silently inherit whichever tenant last used its connection.
|
|
92
|
+
*/
|
|
93
|
+
let engaged = false;
|
|
94
|
+
/** True once tenancy has been engaged. Read by `query()`. */
|
|
95
|
+
export function isTenancyEngaged() {
|
|
96
|
+
return engaged;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The tenant id for the current async scope, or `null` outside any
|
|
100
|
+
* scope / inside a {@link runWithoutTenant} block.
|
|
101
|
+
*/
|
|
102
|
+
export function getCurrentTenantId() {
|
|
103
|
+
return storage.getStore()?.tenantId ?? null;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Run `fn` with `tenantId` applied to every query it issues.
|
|
107
|
+
*
|
|
108
|
+
* Wrap the whole request here — typically from tenant-resolution
|
|
109
|
+
* middleware, once `ctx.tenant` is known — so repos and helpers
|
|
110
|
+
* inherit the scope without threading an argument through every
|
|
111
|
+
* signature.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* await runWithTenant(ctx.tenant.id, async () => {
|
|
116
|
+
* // Any query in here, at any depth, is tenant-scoped by Postgres.
|
|
117
|
+
* return handler(body, ctx);
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function runWithTenant(tenantId, fn) {
|
|
122
|
+
if (!tenantId) {
|
|
123
|
+
throw new Error('runWithTenant requires a non-empty tenantId. Use runWithoutTenant() for ' +
|
|
124
|
+
'deliberately un-scoped work.');
|
|
125
|
+
}
|
|
126
|
+
engaged = true;
|
|
127
|
+
return storage.run({ tenantId }, fn);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Run `fn` with NO tenant applied, clearing any inherited scope.
|
|
131
|
+
*
|
|
132
|
+
* For work that is legitimately cross-tenant: resolving which tenant a
|
|
133
|
+
* hostname belongs to, platform-operator queries, cron jobs sweeping
|
|
134
|
+
* every tenant. Queries inside still execute against RLS with an
|
|
135
|
+
* unset GUC, so tenant-scoped tables return nothing — the caller is
|
|
136
|
+
* expected to be reading un-scoped tables, or to be connected as a
|
|
137
|
+
* privileged role that bypasses RLS.
|
|
138
|
+
*
|
|
139
|
+
* Deliberately verbose to write. An escape hatch should be visible in
|
|
140
|
+
* review.
|
|
141
|
+
*/
|
|
142
|
+
export function runWithoutTenant(fn) {
|
|
143
|
+
engaged = true;
|
|
144
|
+
return storage.run({ tenantId: null }, fn);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Last value applied to each physical connection.
|
|
148
|
+
*
|
|
149
|
+
* WeakMap so entries vanish with the connection and nothing is
|
|
150
|
+
* retained across warm invocations. Absent means "never set on this
|
|
151
|
+
* connection", which is distinct from `NO_TENANT` (explicitly
|
|
152
|
+
* cleared) and forces the first query on a fresh connection to write
|
|
153
|
+
* the GUC.
|
|
154
|
+
*/
|
|
155
|
+
const appliedByClient = new WeakMap();
|
|
156
|
+
/**
|
|
157
|
+
* Ensure `client`'s session GUC matches the current scope, issuing
|
|
158
|
+
* `set_config` only when it differs.
|
|
159
|
+
*
|
|
160
|
+
* Uses a bound parameter — GUC values are user-controlled tenant ids
|
|
161
|
+
* and `SET` does not accept placeholders, so `set_config()` is the
|
|
162
|
+
* only injection-safe way to write one.
|
|
163
|
+
*/
|
|
164
|
+
export async function applyTenantToClient(client) {
|
|
165
|
+
const want = getCurrentTenantId() ?? NO_TENANT;
|
|
166
|
+
if (appliedByClient.get(client) === want)
|
|
167
|
+
return;
|
|
168
|
+
// Record BEFORE awaiting: a rejected set_config must not leave the
|
|
169
|
+
// memo claiming a value the server never accepted.
|
|
170
|
+
appliedByClient.delete(client);
|
|
171
|
+
await client.query(`SELECT set_config($1, $2, false)`, [TENANT_GUC, want]);
|
|
172
|
+
appliedByClient.set(client, want);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Apply the current scope's tenant to an open transaction.
|
|
176
|
+
*
|
|
177
|
+
* `is_local => true` scopes the value to the transaction, so it
|
|
178
|
+
* reverts on COMMIT/ROLLBACK and leaves the connection's session
|
|
179
|
+
* value — and therefore {@link appliedByClient} — untouched.
|
|
180
|
+
*
|
|
181
|
+
* No-op until tenancy is engaged, so existing transactional consumers
|
|
182
|
+
* are unaffected.
|
|
183
|
+
*/
|
|
184
|
+
export async function applyTenantToTransaction(client) {
|
|
185
|
+
if (!engaged)
|
|
186
|
+
return;
|
|
187
|
+
const want = getCurrentTenantId() ?? NO_TENANT;
|
|
188
|
+
await client.query(`SELECT set_config($1, $2, true)`, [TENANT_GUC, want]);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Reset module state. Test-only — production code has no reason to
|
|
192
|
+
* disengage tenancy once engaged.
|
|
193
|
+
*/
|
|
194
|
+
export function __resetTenancyForTests() {
|
|
195
|
+
engaged = false;
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=tenant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant.js","sourceRoot":"","sources":["../../src/query/tenant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,eAAe,CAAC;AAE1C;;;;;;GAMG;AACH,MAAM,SAAS,GAAG,EAAE,CAAC;AAOrB,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAe,CAAC;AAErD;;;;;;;;;;;;GAYG;AACH,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB,6DAA6D;AAC7D,MAAM,UAAU,gBAAgB;IAC9B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAC,QAAQ,EAAE,EAAE,QAAQ,IAAI,IAAI,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,aAAa,CAAI,QAAgB,EAAE,EAAoB;IACrE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,0EAA0E;YACxE,8BAA8B,CACjC,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,IAAI,CAAC;IACf,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,gBAAgB,CAAI,EAAoB;IACtD,OAAO,GAAG,IAAI,CAAC;IACf,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,eAAe,GAAG,IAAI,OAAO,EAAsB,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAkB;IAC1D,MAAM,IAAI,GAAG,kBAAkB,EAAE,IAAI,SAAS,CAAC;IAC/C,IAAI,eAAe,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;QAAE,OAAO;IACjD,mEAAmE;IACnE,mDAAmD;IACnD,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;IAC3E,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,MAAkB;IAC/D,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,MAAM,IAAI,GAAG,kBAAkB,EAAE,IAAI,SAAS,CAAC;IAC/C,MAAM,MAAM,CAAC,KAAK,CAAC,iCAAiC,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,GAAG,KAAK,CAAC;AAClB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/query/transaction.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,IAAI,CAAC;AAElD,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/query/transaction.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAe,MAAM,IAAI,CAAC;AAElD,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAe7D,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;AAEtE;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACjC,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,OAAO,EAAE,EACvB,aAAa,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,EAChC,aAAa,CAAC,EAAE,aAAa,GAC5B,OAAO,CAAC,CAAC,CAAC,CAAC;IACd,6BAA6B;IAC7B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,gCAAgC;IAChC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;;;;;;;;;OAWG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAUnD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,WAAW,CAAC,CA8CzF;AAaD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC;AACd,wBAAsB,eAAe,CAAC,CAAC,EACrC,OAAO,EAAE,WAAW,GAAG,SAAS,EAChC,EAAE,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACnC,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,CAAC,CAAC,CAAC;AAkDd;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAkDhE"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { getPool } from './pool.js';
|
|
10
10
|
import { mapResults } from './mapper.js';
|
|
11
11
|
import { applyDbSecretToEnv } from './secret.js';
|
|
12
|
+
import { applyTenantToTransaction } from './tenant.js';
|
|
12
13
|
import { dbLog } from '../internal/logger.js';
|
|
13
14
|
/**
|
|
14
15
|
* Same single-line clip used by `query()`'s logger. Duplicated here
|
|
@@ -90,6 +91,11 @@ export async function beginTransaction(options) {
|
|
|
90
91
|
const ms = Math.floor(Number(timeoutMs));
|
|
91
92
|
await client.query(`SET LOCAL statement_timeout = ${ms}`);
|
|
92
93
|
}
|
|
94
|
+
// Publish the ambient tenant scope to this transaction so RLS policies
|
|
95
|
+
// see it. Transaction-local, so it reverts on COMMIT/ROLLBACK and never
|
|
96
|
+
// leaks to the next borrower of this pooled connection. No-op until a
|
|
97
|
+
// consumer engages tenancy via runWithTenant().
|
|
98
|
+
await applyTenantToTransaction(client);
|
|
93
99
|
return buildTransaction(client);
|
|
94
100
|
}
|
|
95
101
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/query/transaction.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/query/transaction.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@venturekit/data",
|
|
3
|
-
"version": "0.0.0-dev.
|
|
3
|
+
"version": "0.0.0-dev.20260725205100",
|
|
4
4
|
"description": "Database and data layer for VentureKit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
"license": "Apache-2.0",
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
27
|
+
"types": "./dist/index.d.ts",
|
|
28
|
+
"import": "./dist/index.js"
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@aws-sdk/client-secrets-manager": "^3.1068.0",
|
|
33
|
-
"@venturekit/core": "0.0.0-dev.
|
|
33
|
+
"@venturekit/core": "0.0.0-dev.20260725205100",
|
|
34
34
|
"pg": "^8.12.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|