cloudflare-next-intl 0.8.23 → 0.8.24
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/README.md +10 -12
- package/dist/src/db/connection.d.ts +31 -5
- package/dist/src/db/connection.js +71 -35
- package/dist/src/db/context.d.ts +4 -8
- package/dist/src/db/context.js +9 -27
- package/dist/src/db/index.d.ts +1 -1
- package/dist/src/db/index.js +1 -1
- package/dist/src/types/types.d.ts +12 -5
- package/llms.txt +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -461,23 +461,21 @@ export default setIntlConfig({
|
|
|
461
461
|
returning one (resolved on each connect). The function form is how you reach
|
|
462
462
|
a value that isn't available at module scope — a Cloudflare Hyperdrive
|
|
463
463
|
binding, or a secret store — as in the example above.
|
|
464
|
-
- `disconnectAfterRequest` —
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
settles — no transaction involved). Defaults to `'authenticated'` (the
|
|
473
|
-
Supabase RLS convention).
|
|
464
|
+
- `disconnectAfterRequest` — **deprecated, ignored since 0.8.23.** Every
|
|
465
|
+
`withPublicDb`/`withUserDb` call now opens and closes its own client, so
|
|
466
|
+
there is no surviving connection to keep open. Hyperdrive pools the
|
|
467
|
+
server-side connection.
|
|
468
|
+
- `authenticatedRole` — Postgres role `withUserDb` switches its
|
|
469
|
+
call-scoped session to for the duration of your callback (`set role`, no
|
|
470
|
+
transaction involved; the session is closed when the call ends). Defaults
|
|
471
|
+
to `'authenticated'` (the Supabase RLS convention).
|
|
474
472
|
- `getUserId` — resolves the user id injected as
|
|
475
473
|
`request.jwt.claims->>'sub'` inside `withUserDb`. Omit when
|
|
476
474
|
`firebaseAuth` is configured — the uid then comes from this package's own
|
|
477
475
|
`getAuthUser()` automatically. Provide it to use a different auth source
|
|
478
476
|
(or when `firebaseAuth` is absent).
|
|
479
|
-
- `disconnectTimeoutMs` —
|
|
480
|
-
|
|
477
|
+
- `disconnectTimeoutMs` — **deprecated, ignored since 0.8.23.** Client
|
|
478
|
+
teardown is awaited or deferred to `ctx.waitUntil` without a timeout.
|
|
481
479
|
|
|
482
480
|
#### Choosing a transport
|
|
483
481
|
|
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
import { Client } from 'pg';
|
|
1
|
+
import type { Client } from 'pg';
|
|
2
2
|
import type { LocalePrefixMode, Locales, RoutingConfig } from '../types/types';
|
|
3
3
|
export type DbConfig = RoutingConfig<Locales, LocalePrefixMode>;
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Runs `queryFn` on a Postgres client scoped to this single call: one
|
|
6
|
+
* `connect()`, your callback, then a guaranteed `end()`. Each call gets its own
|
|
7
|
+
* client, so concurrent renders in the same isolate can never share session
|
|
8
|
+
* state (role, `request.jwt.claims`, an open transaction) with each other.
|
|
9
|
+
* Hyperdrive pools the server-side connection behind this.
|
|
8
10
|
*/
|
|
9
11
|
export declare function withDbClient<T>(config: DbConfig, queryFn: (client: Client) => Promise<T>): Promise<T>;
|
|
12
|
+
/**
|
|
13
|
+
* No-op kept for backward compatibility. There is no cached connection state
|
|
14
|
+
* to reset now that every {@link withDbClient} call owns its client.
|
|
15
|
+
*
|
|
16
|
+
* @deprecated Connection state is per-call; this does nothing.
|
|
17
|
+
*/
|
|
10
18
|
export declare function resetConnectionState(): void;
|
|
19
|
+
/**
|
|
20
|
+
* Runs `fn` directly. Kept for backward compatibility: session state can no
|
|
21
|
+
* longer leak between callers, so there is nothing left to serialize.
|
|
22
|
+
*
|
|
23
|
+
* @deprecated Clients are per-call now; no lock is needed.
|
|
24
|
+
*/
|
|
11
25
|
export declare function withSessionLock<T>(fn: () => Promise<T>): Promise<T>;
|
|
26
|
+
/**
|
|
27
|
+
* Opens a Postgres client the caller owns and must close with
|
|
28
|
+
* {@link disconnectPostgres}. Prefer {@link withDbClient}, which closes the
|
|
29
|
+
* client for you even when the callback throws.
|
|
30
|
+
*
|
|
31
|
+
* @deprecated Use {@link withDbClient} instead.
|
|
32
|
+
*/
|
|
12
33
|
export declare function connectToPostgres(config: DbConfig): Promise<Client>;
|
|
13
|
-
|
|
34
|
+
/**
|
|
35
|
+
* Closes a client from {@link connectToPostgres}.
|
|
36
|
+
*
|
|
37
|
+
* @deprecated Use {@link withDbClient} instead.
|
|
38
|
+
*/
|
|
39
|
+
export declare function disconnectPostgres(client?: Client): Promise<void>;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { Client } from 'pg';
|
|
2
1
|
import reportError from '../error_handling/report_error';
|
|
3
2
|
import requireDbConfig from './require_config';
|
|
4
3
|
import resolveConfigValue from './resolve_config_value';
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
let pgModule;
|
|
5
|
+
/**
|
|
6
|
+
* Loads `pg` lazily, so an app that never touches the Postgres transport never
|
|
7
|
+
* bundles it, and caches the module promise so concurrent callers share one
|
|
8
|
+
* resolution instead of racing separate `import()` calls.
|
|
9
|
+
*/
|
|
10
|
+
function loadPg() {
|
|
11
|
+
pgModule ?? (pgModule = import('pg'));
|
|
12
|
+
return pgModule;
|
|
13
|
+
}
|
|
7
14
|
async function resolveConnectionString(db) {
|
|
8
15
|
const configured = await resolveConfigValue(db.connectionString);
|
|
9
16
|
if (configured)
|
|
@@ -13,70 +20,99 @@ async function resolveConnectionString(db) {
|
|
|
13
20
|
'Hyperdrive binding off `getCloudflareContext().env`).');
|
|
14
21
|
}
|
|
15
22
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
23
|
+
* Runs `queryFn` on a Postgres client scoped to this single call: one
|
|
24
|
+
* `connect()`, your callback, then a guaranteed `end()`. Each call gets its own
|
|
25
|
+
* client, so concurrent renders in the same isolate can never share session
|
|
26
|
+
* state (role, `request.jwt.claims`, an open transaction) with each other.
|
|
27
|
+
* Hyperdrive pools the server-side connection behind this.
|
|
19
28
|
*/
|
|
20
29
|
export async function withDbClient(config, queryFn) {
|
|
21
30
|
const db = config.db;
|
|
22
31
|
requireDbConfig(db);
|
|
23
32
|
const connectionString = await resolveConnectionString(db);
|
|
24
|
-
|
|
25
|
-
const client = new
|
|
33
|
+
const { Client: PgClient } = await loadPg();
|
|
34
|
+
const client = new PgClient({ connectionString });
|
|
26
35
|
let result;
|
|
36
|
+
let connected = false;
|
|
27
37
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
// Silently swallow Hyperdrive pool termination warnings that are passive/natural
|
|
34
|
-
const message = error?.message || '';
|
|
35
|
-
if (!/(connection terminated|connection closed|socket closed|unexpected eof)/i.test(message)) {
|
|
36
|
-
void reportError({ errorHandling: config.errorHandling, generate: config.generate }, { error, classOrMethodName: 'db.withDbClient.clientError' });
|
|
38
|
+
try {
|
|
39
|
+
await client.connect();
|
|
40
|
+
connected = true;
|
|
37
41
|
}
|
|
38
|
-
|
|
42
|
+
catch (error) {
|
|
43
|
+
const message = error instanceof Error ? error.message : String(error ?? '');
|
|
44
|
+
if (!/(connection terminated|connection closed|socket closed|unexpected eof)/i.test(message)) {
|
|
45
|
+
void reportError({ errorHandling: config.errorHandling, generate: config.generate }, { error, classOrMethodName: 'db.withDbClient.connectError' });
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
result = await queryFn(client);
|
|
39
50
|
}
|
|
40
51
|
finally {
|
|
41
|
-
|
|
42
|
-
// Triggers `.end()` right when your data has finished being processed.
|
|
43
|
-
const endPromise = client.end();
|
|
52
|
+
const endPromise = connected ? client.end() : Promise.resolve();
|
|
44
53
|
const getContext = config.generate?.getCloudflareContext;
|
|
45
54
|
if (!getContext || db.disconnectAfterRequest === false) {
|
|
46
|
-
await endPromise.catch(() =>
|
|
55
|
+
await endPromise.catch(() => undefined);
|
|
47
56
|
}
|
|
48
57
|
else {
|
|
49
58
|
try {
|
|
50
59
|
const context = await getContext({ async: true });
|
|
51
60
|
if (typeof context?.ctx?.waitUntil === 'function') {
|
|
52
|
-
context.ctx.waitUntil(endPromise.catch(() =>
|
|
61
|
+
context.ctx.waitUntil(endPromise.catch(() => undefined));
|
|
53
62
|
}
|
|
54
63
|
else {
|
|
55
|
-
await endPromise.catch(() =>
|
|
64
|
+
await endPromise.catch(() => undefined);
|
|
56
65
|
}
|
|
57
66
|
}
|
|
58
67
|
catch {
|
|
59
|
-
await endPromise.catch(() =>
|
|
68
|
+
await endPromise.catch(() => undefined);
|
|
60
69
|
}
|
|
61
70
|
}
|
|
62
71
|
}
|
|
63
72
|
return result;
|
|
64
73
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
74
|
+
/**
|
|
75
|
+
* No-op kept for backward compatibility. There is no cached connection state
|
|
76
|
+
* to reset now that every {@link withDbClient} call owns its client.
|
|
77
|
+
*
|
|
78
|
+
* @deprecated Connection state is per-call; this does nothing.
|
|
79
|
+
*/
|
|
70
80
|
export function resetConnectionState() {
|
|
71
|
-
//
|
|
81
|
+
// no cached state to reset
|
|
72
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Runs `fn` directly. Kept for backward compatibility: session state can no
|
|
85
|
+
* longer leak between callers, so there is nothing left to serialize.
|
|
86
|
+
*
|
|
87
|
+
* @deprecated Clients are per-call now; no lock is needed.
|
|
88
|
+
*/
|
|
73
89
|
export async function withSessionLock(fn) {
|
|
74
|
-
// Locks are no longer needed as clients are entirely isolated
|
|
75
90
|
return await fn();
|
|
76
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Opens a Postgres client the caller owns and must close with
|
|
94
|
+
* {@link disconnectPostgres}. Prefer {@link withDbClient}, which closes the
|
|
95
|
+
* client for you even when the callback throws.
|
|
96
|
+
*
|
|
97
|
+
* @deprecated Use {@link withDbClient} instead.
|
|
98
|
+
*/
|
|
77
99
|
export async function connectToPostgres(config) {
|
|
78
|
-
|
|
100
|
+
const db = config.db;
|
|
101
|
+
requireDbConfig(db);
|
|
102
|
+
const connectionString = await resolveConnectionString(db);
|
|
103
|
+
const { Client: PgClient } = await loadPg();
|
|
104
|
+
const client = new PgClient({ connectionString });
|
|
105
|
+
client.on('error', (error) => {
|
|
106
|
+
void reportError({ errorHandling: config.errorHandling, generate: config.generate }, { error, classOrMethodName: 'db.connectToPostgres.clientError' });
|
|
107
|
+
});
|
|
108
|
+
await client.connect();
|
|
109
|
+
return client;
|
|
79
110
|
}
|
|
80
|
-
|
|
81
|
-
|
|
111
|
+
/**
|
|
112
|
+
* Closes a client from {@link connectToPostgres}.
|
|
113
|
+
*
|
|
114
|
+
* @deprecated Use {@link withDbClient} instead.
|
|
115
|
+
*/
|
|
116
|
+
export async function disconnectPostgres(client) {
|
|
117
|
+
await client?.end().catch(() => undefined);
|
|
82
118
|
}
|
package/dist/src/db/context.d.ts
CHANGED
|
@@ -15,15 +15,11 @@ export type DrizzleDb = NodePgDatabase<Record<string, never>>;
|
|
|
15
15
|
*/
|
|
16
16
|
export declare function withPublicDb<T>(fn: (db: DrizzleDb) => Promise<T>): Promise<T>;
|
|
17
17
|
/**
|
|
18
|
-
* Runs a query as the **signed-in user
|
|
18
|
+
* Runs a query as the **signed-in user**, with `request.jwt.claims` and the
|
|
19
|
+
* authenticated role set on the session so RLS policies apply to their id.
|
|
19
20
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* PostgreSQL singleton reference inside Serverless architecture.
|
|
23
|
-
*
|
|
24
|
-
* Moving directly to edge single-usage wrappers inherently closes all leakage scenarios because
|
|
25
|
-
* `.connect() -> setup Roles & Session variables -> process logic -> .end()` exists per connection completely
|
|
26
|
-
* unshared across external requests globally.
|
|
21
|
+
* The session lives on a client scoped to this call and closed when it ends,
|
|
22
|
+
* so the role and claims can never be observed by another caller.
|
|
27
23
|
*
|
|
28
24
|
* @param fn Receives the Drizzle handle
|
|
29
25
|
* @param uid Overrides the user ID for authenticated calls
|
package/dist/src/db/context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import config from '../config/intl_config';
|
|
2
2
|
import requireDbConfig from './require_config';
|
|
3
|
-
import { withDbClient } from './connection';
|
|
3
|
+
import { withDbClient } from './connection';
|
|
4
4
|
import resolveDbMode from './resolve_mode';
|
|
5
5
|
import resolveSupabaseEndpoint from './supabase_config';
|
|
6
6
|
import createSupabaseTransport from './supabase_transport';
|
|
@@ -73,9 +73,8 @@ async function postgresDb(drizzleHandle, rawClient) {
|
|
|
73
73
|
* via an inline-parameterised `query()` call, wrapped in a real
|
|
74
74
|
* `BEGIN`/`COMMIT` for atomicity, and returns `ExecResult[]`.
|
|
75
75
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* You don't have to lock this transaction block as overlapping sessions are eliminated entirely.
|
|
76
|
+
* The client is scoped to one `withDbClient` call, so no other caller can
|
|
77
|
+
* interleave statements into this transaction.
|
|
79
78
|
*/
|
|
80
79
|
async function runPostgresTransaction(rawClient, build) {
|
|
81
80
|
const queries = await build(buildOnlyDb());
|
|
@@ -91,7 +90,7 @@ async function runPostgresTransaction(rawClient, build) {
|
|
|
91
90
|
return results;
|
|
92
91
|
}
|
|
93
92
|
catch (error) {
|
|
94
|
-
await rawClient.query('rollback').catch(() =>
|
|
93
|
+
await rawClient.query('rollback').catch(() => undefined);
|
|
95
94
|
throw error;
|
|
96
95
|
}
|
|
97
96
|
}
|
|
@@ -128,26 +127,19 @@ export async function withPublicDb(fn) {
|
|
|
128
127
|
const { anonKey } = await resolveSupabaseEndpoint(resolved.supabase);
|
|
129
128
|
return fn(await supabaseDb(resolved.supabase, anonKey));
|
|
130
129
|
}
|
|
131
|
-
// ✨ Uses isolated clients. Clean setup internally handles
|
|
132
|
-
// tear-down (`disconnectPostgres`) magically behind the scenes right on completion
|
|
133
130
|
return await withDbClient(config, async (client) => {
|
|
134
131
|
const { drizzle } = await import('drizzle-orm/node-postgres');
|
|
135
132
|
const drizzleHandle = drizzle(client);
|
|
136
|
-
// Execute Drizzle proxy payload natively
|
|
137
133
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
138
134
|
return await fn(await postgresDb(drizzleHandle, client));
|
|
139
135
|
});
|
|
140
136
|
}
|
|
141
137
|
/**
|
|
142
|
-
* Runs a query as the **signed-in user
|
|
138
|
+
* Runs a query as the **signed-in user**, with `request.jwt.claims` and the
|
|
139
|
+
* authenticated role set on the session so RLS policies apply to their id.
|
|
143
140
|
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* PostgreSQL singleton reference inside Serverless architecture.
|
|
147
|
-
*
|
|
148
|
-
* Moving directly to edge single-usage wrappers inherently closes all leakage scenarios because
|
|
149
|
-
* `.connect() -> setup Roles & Session variables -> process logic -> .end()` exists per connection completely
|
|
150
|
-
* unshared across external requests globally.
|
|
141
|
+
* The session lives on a client scoped to this call and closed when it ends,
|
|
142
|
+
* so the role and claims can never be observed by another caller.
|
|
151
143
|
*
|
|
152
144
|
* @param fn Receives the Drizzle handle
|
|
153
145
|
* @param uid Overrides the user ID for authenticated calls
|
|
@@ -162,23 +154,13 @@ export async function withUserDb(fn, uid) {
|
|
|
162
154
|
}
|
|
163
155
|
const userId = await resolveUserId(uid);
|
|
164
156
|
const role = db.authenticatedRole ?? DEFAULT_ROLE;
|
|
165
|
-
// ✨ Completely isolated setup per-render utilizing `.withDbClient()` Native block
|
|
166
|
-
// Eliminates requiring our application `withSessionLock` since NextJS workers do not leak!
|
|
167
157
|
return await withDbClient(config, async (client) => {
|
|
168
158
|
const rawClient = client;
|
|
169
159
|
await rawClient.query(`select set_config('request.jwt.claims', $1, false)`, [JSON.stringify({ sub: userId })]);
|
|
170
160
|
await rawClient.query(`set role "${role}"`);
|
|
171
161
|
const { drizzle } = await import('drizzle-orm/node-postgres');
|
|
172
162
|
const drizzleHandle = drizzle(client);
|
|
173
|
-
|
|
174
|
-
return await fn(await postgresDb(drizzleHandle, rawClient));
|
|
175
|
-
}
|
|
176
|
-
finally {
|
|
177
|
-
// Because Hyperdrive is going to actively obliterate (`.end()`)
|
|
178
|
-
// the connection upon scope exiting returning connection priorities automatically back up to cloudflare.
|
|
179
|
-
// Resetting is theoretically optional in stateless Cloudflare execution - but is provided as good habit/health standard here.
|
|
180
|
-
await rawClient.query('reset role').catch(() => { });
|
|
181
|
-
}
|
|
163
|
+
return await fn(await postgresDb(drizzleHandle, rawClient));
|
|
182
164
|
});
|
|
183
165
|
}
|
|
184
166
|
/**
|
package/dist/src/db/index.d.ts
CHANGED
|
@@ -38,5 +38,5 @@
|
|
|
38
38
|
*/
|
|
39
39
|
export { withPublicDb, withUserDb } from './context';
|
|
40
40
|
export type { DrizzleDb, TransactionResult } from './context';
|
|
41
|
-
export { connectToPostgres, disconnectPostgres, resetConnectionState } from './connection';
|
|
41
|
+
export { withDbClient, connectToPostgres, disconnectPostgres, resetConnectionState } from './connection';
|
|
42
42
|
export type { DbRoutingConfig } from '../types/types';
|
package/dist/src/db/index.js
CHANGED
|
@@ -37,4 +37,4 @@
|
|
|
37
37
|
* the separate `cloudflare-next-intl/dbHelpers` entry point.
|
|
38
38
|
*/
|
|
39
39
|
export { withPublicDb, withUserDb } from './context';
|
|
40
|
-
export { connectToPostgres, disconnectPostgres, resetConnectionState } from './connection';
|
|
40
|
+
export { withDbClient, connectToPostgres, disconnectPostgres, resetConnectionState } from './connection';
|
|
@@ -884,10 +884,12 @@ export interface DbRoutingConfig {
|
|
|
884
884
|
/**
|
|
885
885
|
* Whether the pooled client is closed once the last in-flight
|
|
886
886
|
* `withPublicDb`/`withUserDb` call of the request finishes.
|
|
887
|
-
*
|
|
888
|
-
*
|
|
889
|
-
*
|
|
890
|
-
*
|
|
887
|
+
*
|
|
888
|
+
* @deprecated Ignored since 0.8.23. Every `withPublicDb`/`withUserDb` call
|
|
889
|
+
* now opens and closes its own client, so no connection survives a call to
|
|
890
|
+
* be kept open. `true` and `false` behave identically; the only difference
|
|
891
|
+
* is that `false` awaits the close instead of deferring it to
|
|
892
|
+
* `ctx.waitUntil`. Hyperdrive pools the server-side connection.
|
|
891
893
|
*/
|
|
892
894
|
disconnectAfterRequest?: boolean;
|
|
893
895
|
/**
|
|
@@ -902,7 +904,12 @@ export interface DbRoutingConfig {
|
|
|
902
904
|
* to use a different auth source (or when `firebaseAuth` is absent).
|
|
903
905
|
*/
|
|
904
906
|
getUserId?: () => Promise<string | null> | string | null;
|
|
905
|
-
/**
|
|
907
|
+
/**
|
|
908
|
+
* Milliseconds `disconnectPostgres` waits for `client.end()` before giving up.
|
|
909
|
+
*
|
|
910
|
+
* @deprecated Ignored since 0.8.23. Client teardown is awaited or deferred
|
|
911
|
+
* to `ctx.waitUntil` without a timeout.
|
|
912
|
+
*/
|
|
906
913
|
disconnectTimeoutMs?: number;
|
|
907
914
|
/**
|
|
908
915
|
* Reaches Postgres through the Supabase Data API instead of a direct
|
package/llms.txt
CHANGED
|
@@ -53,11 +53,11 @@ Two transports, picked by which `db` fields are set — `pg`/`drizzle-orm`/`@sup
|
|
|
53
53
|
|
|
54
54
|
- Direct Postgres (wins if configured): `db.connectionString` — Postgres connection string, or a sync/async function returning one (resolved on each connect). The function form is the way to read a value unavailable at module scope, e.g. a Cloudflare Hyperdrive binding: `connectionString: async () => (await getCloudflareContext({ async: true })).env.HYPERDRIVE.connectionString`. There is no separate `hyperdriveBinding` option.
|
|
55
55
|
- Supabase Data API (used only when neither of the above is set): `db.supabase` — `{ url?, anonKey?, execFunction?, rawSql? }` where `url`/`anonKey` each accept a string or a sync/async function returning one, defaulting `url`/`anonKey` to `NEXT_PUBLIC_SUPABASE_URL`/`NEXT_PUBLIC_SUPABASE_ANON_KEY`. Statements are translated to PostgREST REST calls first; unsupported statements fall back to `supabase/cfni_exec.sql` (a `security invoker` SQL-exec function) in your database — `cfni-db-codegen`/`cfni-db-install-exec` can install it for you (see below). No multi-statement transactions — each statement in a `withUserDb` callback is its own round-trip; `.transaction()` throws instead of running non-atomically. `rawSql: false` disables `cfni_exec` fallback, throwing an informative error when a query cannot be served over REST.
|
|
56
|
-
- `db.disconnectAfterRequest` —
|
|
56
|
+
- `db.disconnectAfterRequest` — deprecated, ignored since 0.8.23. Each `withPublicDb`/`withUserDb` call opens and closes its own client; Hyperdrive pools the server-side connection.
|
|
57
57
|
- `db.authenticatedRole` — direct-Postgres mode only: Postgres role assumed inside `withUserDb`'s transaction. Defaults to `'authenticated'` (Supabase RLS convention).
|
|
58
58
|
- `db.getUserId` — direct-Postgres mode only: resolves the user id injected as `request.jwt.claims->>'sub'` in `withUserDb`. Omit when `firebaseAuth` is configured — the uid is then taken automatically from the signed-in Firebase user via this package's own `getAuthUser()`.
|
|
59
59
|
- `db.getAccessToken` — Supabase mode only: resolves the JWT sent as `Authorization: Bearer` in `withUserDb`, which is what makes PostgREST resolve `authenticated` and apply RLS. Omit when `firebaseAuth` is configured — the signed-in user's Firebase ID token is used automatically.
|
|
60
|
-
- `db.disconnectTimeoutMs` —
|
|
60
|
+
- `db.disconnectTimeoutMs` — deprecated, ignored since 0.8.23. Teardown is awaited or deferred to `ctx.waitUntil` without a timeout.
|
|
61
61
|
- `withPublicDb(fn)` — anonymous role. Direct-Postgres mode: the request's pooled connection, no transaction, no role switch. Supabase mode: the anon key as the PostgREST bearer token. Either way, no user id is attached — RLS keyed on `auth.jwt()` denies access.
|
|
62
62
|
- `withUserDb(fn, uid?)` — signed-in-user role. Direct-Postgres mode: a transaction with `set_config('request.jwt.claims', ...)` + `set local role`, `uid` resolution order explicit arg → `db.getUserId()` → Firebase auth uid → throws. Supabase mode: identity rides on the JWT from `db.getAccessToken`/Firebase instead (`uid` param is ignored), no transaction wraps the call.
|
|
63
63
|
- `./dbHelpers` functions are plain Drizzle `sql`-building utilities with no config dependency — usable standalone.
|