cloudflare-next-intl 0.8.13 → 0.8.14
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/src/db/connection.d.ts +5 -1
- package/dist/src/db/connection.js +6 -2
- package/dist/src/db/context.d.ts +9 -6
- package/dist/src/db/context.js +26 -19
- package/dist/src/db/resolve_config_value.d.ts +7 -4
- package/dist/src/db/resolve_config_value.js +5 -2
- package/dist/src/db/resolve_mode.d.ts +29 -9
- package/dist/src/db/resolve_mode.js +22 -11
- package/dist/src/types/types.d.ts +19 -6
- package/package.json +1 -1
|
@@ -21,11 +21,15 @@ export declare function resetConnectionState(): void;
|
|
|
21
21
|
* `disconnectPostgres` call, or the connection is never released.
|
|
22
22
|
*
|
|
23
23
|
* @param config Your routing config; `config.db` must be set.
|
|
24
|
+
* @param resolved A connection string already resolved by the caller (e.g.
|
|
25
|
+
* `resolveDbMode`, which has to call `db.connectionString` itself to decide
|
|
26
|
+
* the transport) — pass it to skip resolving `db.connectionString` a second
|
|
27
|
+
* time. Omit it to have this function resolve it itself, as before.
|
|
24
28
|
* @returns The connected, shared client.
|
|
25
29
|
* @throws If `db` is not set, or no connection string can be resolved from
|
|
26
30
|
* `db.connectionString`.
|
|
27
31
|
*/
|
|
28
|
-
export default function connectToPostgres(config: DbConfig): Promise<Client>;
|
|
32
|
+
export default function connectToPostgres(config: DbConfig, resolved?: string | undefined): Promise<Client>;
|
|
29
33
|
/**
|
|
30
34
|
* Releases one caller's hold on the shared client, closing it once the last
|
|
31
35
|
* holder of the request is done. Call it exactly once per
|
|
@@ -64,18 +64,22 @@ function serializeQueries(raw) {
|
|
|
64
64
|
* `disconnectPostgres` call, or the connection is never released.
|
|
65
65
|
*
|
|
66
66
|
* @param config Your routing config; `config.db` must be set.
|
|
67
|
+
* @param resolved A connection string already resolved by the caller (e.g.
|
|
68
|
+
* `resolveDbMode`, which has to call `db.connectionString` itself to decide
|
|
69
|
+
* the transport) — pass it to skip resolving `db.connectionString` a second
|
|
70
|
+
* time. Omit it to have this function resolve it itself, as before.
|
|
67
71
|
* @returns The connected, shared client.
|
|
68
72
|
* @throws If `db` is not set, or no connection string can be resolved from
|
|
69
73
|
* `db.connectionString`.
|
|
70
74
|
*/
|
|
71
|
-
export default async function connectToPostgres(config) {
|
|
75
|
+
export default async function connectToPostgres(config, resolved) {
|
|
72
76
|
const db = config.db;
|
|
73
77
|
requireDbConfig(db);
|
|
74
78
|
await disconnectionPromise;
|
|
75
79
|
if (connectingPromise === null) {
|
|
76
80
|
connectingPromise = (async () => {
|
|
77
81
|
try {
|
|
78
|
-
connectionString ?? (connectionString = await resolveConnectionString(db));
|
|
82
|
+
connectionString ?? (connectionString = resolved ?? await resolveConnectionString(db));
|
|
79
83
|
const { Client } = await import('pg');
|
|
80
84
|
const created = serializeQueries(new Client({ connectionString }));
|
|
81
85
|
client = created;
|
package/dist/src/db/context.d.ts
CHANGED
|
@@ -44,11 +44,14 @@ export declare function withPublicDb<T>(fn: (db: DrizzleDb) => Promise<T>): Prom
|
|
|
44
44
|
* @param fn Receives the Drizzle handle. In connection-string mode it is
|
|
45
45
|
* bound to a transaction; in Supabase mode it is not — do not rely on
|
|
46
46
|
* multi-statement atomicity there.
|
|
47
|
-
* @param uid Connection-string mode only: overrides the user id. Omit it
|
|
48
|
-
* normal use — the id then comes from
|
|
49
|
-
* from the signed-in Firebase user when
|
|
50
|
-
*
|
|
51
|
-
*
|
|
47
|
+
* @param uid Connection-string mode only: overrides the user id. Omit it, or
|
|
48
|
+
* pass `null`, in normal use — either way the id then comes from
|
|
49
|
+
* `db.getUserId()` when set, otherwise from the signed-in Firebase user when
|
|
50
|
+
* `firebaseAuth` is configured. `null` is accepted alongside `undefined` so a
|
|
51
|
+
* caller's own lookup (which may itself come back empty) can be passed
|
|
52
|
+
* straight through without an extra check. Ignored in Supabase mode, which
|
|
53
|
+
* resolves identity via `db.getAccessToken`/Firebase instead — see
|
|
54
|
+
* {@link resolveAccessToken}.
|
|
52
55
|
* @returns Whatever `fn` resolves to.
|
|
53
56
|
* @throws If `db` is not set on your `RoutingConfig`, if no user id/access
|
|
54
57
|
* token can be resolved, or the connection fails.
|
|
@@ -56,7 +59,7 @@ export declare function withPublicDb<T>(fn: (db: DrizzleDb) => Promise<T>): Prom
|
|
|
56
59
|
* @example
|
|
57
60
|
* const mine = await withUserDb((db) => db.select().from(orders));
|
|
58
61
|
*/
|
|
59
|
-
export declare function withUserDb<T>(fn: (db: DrizzleDb) => Promise<T>, uid?: string): Promise<T>;
|
|
62
|
+
export declare function withUserDb<T>(fn: (db: DrizzleDb) => Promise<T>, uid?: string | null): Promise<T>;
|
|
60
63
|
/** One statement's `{rows, rowCount}` result from a `withUserTransaction`/`withPublicTransaction` batch. */
|
|
61
64
|
export type { ExecResult as TransactionResult } from './supabase_transport';
|
|
62
65
|
/**
|
package/dist/src/db/context.js
CHANGED
|
@@ -9,7 +9,9 @@ import runTransactionBatch from './transaction_batch';
|
|
|
9
9
|
const DEFAULT_ROLE = 'authenticated';
|
|
10
10
|
/**
|
|
11
11
|
* Resolves the user id for `withUserDb`, trying, in order: the explicit `uid`
|
|
12
|
-
* argument, `db.getUserId()`, then the signed-in Firebase user.
|
|
12
|
+
* argument, `db.getUserId()`, then the signed-in Firebase user. `uid` may be
|
|
13
|
+
* `null` (as well as omitted) to mean "skip this source, try the next one" —
|
|
14
|
+
* useful when the caller's own uid lookup can itself come back empty.
|
|
13
15
|
*/
|
|
14
16
|
async function resolveUserId(uid) {
|
|
15
17
|
if (uid)
|
|
@@ -86,12 +88,12 @@ function buildOnlyDb() {
|
|
|
86
88
|
export async function withPublicDb(fn) {
|
|
87
89
|
const db = config.db;
|
|
88
90
|
requireDbConfig(db);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const { anonKey } = await resolveSupabaseEndpoint(supabase);
|
|
92
|
-
return fn(await supabaseDb(supabase, anonKey));
|
|
91
|
+
const resolved = await resolveDbMode(db);
|
|
92
|
+
if (resolved.mode === 'supabase') {
|
|
93
|
+
const { anonKey } = await resolveSupabaseEndpoint(resolved.supabase);
|
|
94
|
+
return fn(await supabaseDb(resolved.supabase, anonKey));
|
|
93
95
|
}
|
|
94
|
-
const client = await connectToPostgres(config);
|
|
96
|
+
const client = await connectToPostgres(config, resolved.connectionString);
|
|
95
97
|
try {
|
|
96
98
|
const { drizzle } = await import('drizzle-orm/node-postgres');
|
|
97
99
|
return await fn(drizzle(client));
|
|
@@ -116,11 +118,14 @@ export async function withPublicDb(fn) {
|
|
|
116
118
|
* @param fn Receives the Drizzle handle. In connection-string mode it is
|
|
117
119
|
* bound to a transaction; in Supabase mode it is not — do not rely on
|
|
118
120
|
* multi-statement atomicity there.
|
|
119
|
-
* @param uid Connection-string mode only: overrides the user id. Omit it
|
|
120
|
-
* normal use — the id then comes from
|
|
121
|
-
* from the signed-in Firebase user when
|
|
122
|
-
*
|
|
123
|
-
*
|
|
121
|
+
* @param uid Connection-string mode only: overrides the user id. Omit it, or
|
|
122
|
+
* pass `null`, in normal use — either way the id then comes from
|
|
123
|
+
* `db.getUserId()` when set, otherwise from the signed-in Firebase user when
|
|
124
|
+
* `firebaseAuth` is configured. `null` is accepted alongside `undefined` so a
|
|
125
|
+
* caller's own lookup (which may itself come back empty) can be passed
|
|
126
|
+
* straight through without an extra check. Ignored in Supabase mode, which
|
|
127
|
+
* resolves identity via `db.getAccessToken`/Firebase instead — see
|
|
128
|
+
* {@link resolveAccessToken}.
|
|
124
129
|
* @returns Whatever `fn` resolves to.
|
|
125
130
|
* @throws If `db` is not set on your `RoutingConfig`, if no user id/access
|
|
126
131
|
* token can be resolved, or the connection fails.
|
|
@@ -131,12 +136,13 @@ export async function withPublicDb(fn) {
|
|
|
131
136
|
export async function withUserDb(fn, uid) {
|
|
132
137
|
const db = config.db;
|
|
133
138
|
requireDbConfig(db);
|
|
134
|
-
|
|
139
|
+
const resolved = await resolveDbMode(db);
|
|
140
|
+
if (resolved.mode === 'supabase') {
|
|
135
141
|
const token = await resolveAccessToken(config);
|
|
136
|
-
return fn(await supabaseDb(
|
|
142
|
+
return fn(await supabaseDb(resolved.supabase, token));
|
|
137
143
|
}
|
|
138
144
|
const userId = await resolveUserId(uid);
|
|
139
|
-
const client = await connectToPostgres(config);
|
|
145
|
+
const client = await connectToPostgres(config, resolved.connectionString);
|
|
140
146
|
const role = db.authenticatedRole ?? DEFAULT_ROLE;
|
|
141
147
|
try {
|
|
142
148
|
const { drizzle } = await import('drizzle-orm/node-postgres');
|
|
@@ -171,13 +177,14 @@ export async function withUserDb(fn, uid) {
|
|
|
171
177
|
* @param build Returns the queries to run, via `.toSQL()` — never executes them directly.
|
|
172
178
|
* @returns One result per query, in the same order as `build`'s array.
|
|
173
179
|
*/
|
|
174
|
-
function requireSupabaseTransactionMode(db) {
|
|
175
|
-
|
|
180
|
+
async function requireSupabaseTransactionMode(db) {
|
|
181
|
+
const resolved = await resolveDbMode(db);
|
|
182
|
+
if (resolved.mode !== 'supabase') {
|
|
176
183
|
throw new Error('db: withUserTransaction/withPublicTransaction only run their Supabase-mode batch path ' +
|
|
177
184
|
'right now. In connection-string mode, use withUserDb/withPublicDb\'s own `.transaction()` ' +
|
|
178
185
|
'— it already provides real atomicity there.');
|
|
179
186
|
}
|
|
180
|
-
const supabase =
|
|
187
|
+
const supabase = resolved.supabase;
|
|
181
188
|
if (supabase.rawSql === false) {
|
|
182
189
|
throw new Error('db: withUserTransaction/withPublicTransaction need `cfni_exec_batch`, which runs through ' +
|
|
183
190
|
'`cfni_exec` — both are unavailable while `db.supabase.rawSql` is `false`. Install ' +
|
|
@@ -211,7 +218,7 @@ async function runTransaction(supabase, bearerToken, build) {
|
|
|
211
218
|
export async function withPublicTransaction(build) {
|
|
212
219
|
const db = config.db;
|
|
213
220
|
requireDbConfig(db);
|
|
214
|
-
const supabase = requireSupabaseTransactionMode(db);
|
|
221
|
+
const supabase = await requireSupabaseTransactionMode(db);
|
|
215
222
|
const { anonKey } = await resolveSupabaseEndpoint(supabase);
|
|
216
223
|
return runTransaction(supabase, anonKey, build);
|
|
217
224
|
}
|
|
@@ -239,7 +246,7 @@ export async function withPublicTransaction(build) {
|
|
|
239
246
|
export async function withUserTransaction(build) {
|
|
240
247
|
const db = config.db;
|
|
241
248
|
requireDbConfig(db);
|
|
242
|
-
const supabase = requireSupabaseTransactionMode(db);
|
|
249
|
+
const supabase = await requireSupabaseTransactionMode(db);
|
|
243
250
|
const token = await resolveAccessToken(config);
|
|
244
251
|
return runTransaction(supabase, token, build);
|
|
245
252
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FallibleConfigValue } from '../types/types';
|
|
2
2
|
/**
|
|
3
3
|
* Resolves a config value that may have been supplied directly or as a
|
|
4
|
-
* sync/async function.
|
|
4
|
+
* sync/async function. A resolver may return `null` to mean "nothing here —
|
|
5
|
+
* fall through to whatever the caller checks next" — callers already treat
|
|
6
|
+
* that the same as `undefined` wherever they use `??`/truthiness on the
|
|
7
|
+
* result, so this passes it through rather than coercing it away.
|
|
5
8
|
*
|
|
6
9
|
* @param value The configured value or resolver.
|
|
7
|
-
* @returns The resolved value, or `undefined` when nothing was configured.
|
|
10
|
+
* @returns The resolved value, or `null`/`undefined` when nothing was configured.
|
|
8
11
|
*/
|
|
9
|
-
export default function resolveConfigValue<T>(value:
|
|
12
|
+
export default function resolveConfigValue<T>(value: FallibleConfigValue<T> | undefined): Promise<T | null | undefined>;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Resolves a config value that may have been supplied directly or as a
|
|
3
|
-
* sync/async function.
|
|
3
|
+
* sync/async function. A resolver may return `null` to mean "nothing here —
|
|
4
|
+
* fall through to whatever the caller checks next" — callers already treat
|
|
5
|
+
* that the same as `undefined` wherever they use `??`/truthiness on the
|
|
6
|
+
* result, so this passes it through rather than coercing it away.
|
|
4
7
|
*
|
|
5
8
|
* @param value The configured value or resolver.
|
|
6
|
-
* @returns The resolved value, or `undefined` when nothing was configured.
|
|
9
|
+
* @returns The resolved value, or `null`/`undefined` when nothing was configured.
|
|
7
10
|
*/
|
|
8
11
|
export default async function resolveConfigValue(value) {
|
|
9
12
|
return typeof value === 'function' ? value() : value;
|
|
@@ -1,17 +1,37 @@
|
|
|
1
|
-
import type { DbRoutingConfig } from '../types/types';
|
|
1
|
+
import type { DbRoutingConfig, SupabaseDbConfig } from '../types/types';
|
|
2
2
|
/** Which transport the `db` exports use for a given config. */
|
|
3
3
|
export type DbMode = 'postgres' | 'supabase';
|
|
4
|
+
/**
|
|
5
|
+
* The resolved transport for a `db` config, carrying whatever
|
|
6
|
+
* {@link resolveDbMode} already resolved to decide it — so a caller that
|
|
7
|
+
* picks `'postgres'` already has the connection string in hand and never
|
|
8
|
+
* needs to call a function-based `db.connectionString` a second time.
|
|
9
|
+
*/
|
|
10
|
+
export type ResolvedDbMode = {
|
|
11
|
+
mode: 'postgres';
|
|
12
|
+
connectionString: string | undefined;
|
|
13
|
+
} | {
|
|
14
|
+
mode: 'supabase';
|
|
15
|
+
supabase: SupabaseDbConfig;
|
|
16
|
+
};
|
|
4
17
|
/**
|
|
5
18
|
* Decides how to reach the database from the shape of the `db` config.
|
|
6
19
|
*
|
|
7
|
-
* Direct Postgres wins whenever it
|
|
8
|
-
* block to an existing config never silently reroutes
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
20
|
+
* Direct Postgres wins whenever it resolves to a real connection string, so
|
|
21
|
+
* adding a `supabase` block to an existing config never silently reroutes
|
|
22
|
+
* live traffic. `connectionString` given as a function is actually called
|
|
23
|
+
* (and awaited) here — not just checked for presence — so a resolver that
|
|
24
|
+
* comes back `null`/`undefined` (its own source having nothing right now)
|
|
25
|
+
* falls through to `supabase` instead of locking in `'postgres'` mode and
|
|
26
|
+
* failing later in `connectToPostgres` with no `supabase` fallback tried.
|
|
27
|
+
* With neither resolving to anything, the result is still `'postgres'`
|
|
28
|
+
* (with an `undefined` connection string), which lets `connectToPostgres`
|
|
29
|
+
* raise its existing, more specific error about the missing connection
|
|
30
|
+
* string — it is never asked to resolve `db.connectionString` itself, so a
|
|
31
|
+
* resolver given as a function runs exactly once per call here, not twice.
|
|
12
32
|
*
|
|
13
33
|
* @param db The `db` field off your routing config.
|
|
14
|
-
* @returns
|
|
15
|
-
*
|
|
34
|
+
* @returns The resolved mode, plus whichever of `connectionString`/`supabase`
|
|
35
|
+
* that mode needs.
|
|
16
36
|
*/
|
|
17
|
-
export default function resolveDbMode(db: DbRoutingConfig):
|
|
37
|
+
export default function resolveDbMode(db: DbRoutingConfig): Promise<ResolvedDbMode>;
|
|
@@ -1,18 +1,29 @@
|
|
|
1
|
+
import resolveConfigValue from './resolve_config_value';
|
|
1
2
|
/**
|
|
2
3
|
* Decides how to reach the database from the shape of the `db` config.
|
|
3
4
|
*
|
|
4
|
-
* Direct Postgres wins whenever it
|
|
5
|
-
* block to an existing config never silently reroutes
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Direct Postgres wins whenever it resolves to a real connection string, so
|
|
6
|
+
* adding a `supabase` block to an existing config never silently reroutes
|
|
7
|
+
* live traffic. `connectionString` given as a function is actually called
|
|
8
|
+
* (and awaited) here — not just checked for presence — so a resolver that
|
|
9
|
+
* comes back `null`/`undefined` (its own source having nothing right now)
|
|
10
|
+
* falls through to `supabase` instead of locking in `'postgres'` mode and
|
|
11
|
+
* failing later in `connectToPostgres` with no `supabase` fallback tried.
|
|
12
|
+
* With neither resolving to anything, the result is still `'postgres'`
|
|
13
|
+
* (with an `undefined` connection string), which lets `connectToPostgres`
|
|
14
|
+
* raise its existing, more specific error about the missing connection
|
|
15
|
+
* string — it is never asked to resolve `db.connectionString` itself, so a
|
|
16
|
+
* resolver given as a function runs exactly once per call here, not twice.
|
|
9
17
|
*
|
|
10
18
|
* @param db The `db` field off your routing config.
|
|
11
|
-
* @returns
|
|
12
|
-
*
|
|
19
|
+
* @returns The resolved mode, plus whichever of `connectionString`/`supabase`
|
|
20
|
+
* that mode needs.
|
|
13
21
|
*/
|
|
14
|
-
export default function resolveDbMode(db) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
export default async function resolveDbMode(db) {
|
|
23
|
+
const connectionString = await resolveConfigValue(db.connectionString);
|
|
24
|
+
if (connectionString)
|
|
25
|
+
return { mode: 'postgres', connectionString };
|
|
26
|
+
if (db.supabase)
|
|
27
|
+
return { mode: 'supabase', supabase: db.supabase };
|
|
28
|
+
return { mode: 'postgres', connectionString: undefined };
|
|
18
29
|
}
|
|
@@ -824,20 +824,31 @@ export interface IntlSitemap {
|
|
|
824
824
|
* the config object is first created.
|
|
825
825
|
*/
|
|
826
826
|
export type ConfigValue<T> = T | (() => T | Promise<T>);
|
|
827
|
+
/**
|
|
828
|
+
* A {@link ConfigValue} whose function form may also return `null` to mean
|
|
829
|
+
* "this source has nothing — fall through to the next one" (an env var
|
|
830
|
+
* default, or another resolver), the same way `getUserId`/`getAccessToken`
|
|
831
|
+
* already do. `undefined` means the same thing; both are treated
|
|
832
|
+
* identically by every resolver that reads one of these.
|
|
833
|
+
*/
|
|
834
|
+
export type FallibleConfigValue<T> = ConfigValue<T | null | undefined>;
|
|
827
835
|
export interface SupabaseDbConfig {
|
|
828
836
|
/**
|
|
829
837
|
* Supabase project URL, e.g. `https://abc.supabase.co`. Defaults to
|
|
830
838
|
* `process.env.NEXT_PUBLIC_SUPABASE_URL`. May be a function (sync or
|
|
831
|
-
* async) resolved on each use
|
|
839
|
+
* async) resolved on each use — return `null`/`undefined` from it to
|
|
840
|
+
* fall through to the environment variable instead of erroring.
|
|
832
841
|
*/
|
|
833
|
-
url?:
|
|
842
|
+
url?: FallibleConfigValue<string>;
|
|
834
843
|
/**
|
|
835
844
|
* Supabase anon (publishable) key. Defaults to
|
|
836
845
|
* `process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY`. This is the only key the
|
|
837
846
|
* `db` module ever needs — never put a service-role key here. May be a
|
|
838
|
-
* function (sync or async) resolved on each use
|
|
847
|
+
* function (sync or async) resolved on each use — return
|
|
848
|
+
* `null`/`undefined` from it to fall through to the environment variable
|
|
849
|
+
* instead of erroring.
|
|
839
850
|
*/
|
|
840
|
-
anonKey?:
|
|
851
|
+
anonKey?: FallibleConfigValue<string>;
|
|
841
852
|
/**
|
|
842
853
|
* Name of the Postgres function that runs the generated SQL. Defaults to
|
|
843
854
|
* `'cfni_exec'` — the function shipped in `supabase/cfni_exec.sql`.
|
|
@@ -865,9 +876,11 @@ export interface DbRoutingConfig {
|
|
|
865
876
|
* resolved on each connect. The function form is how you reach a value that
|
|
866
877
|
* isn't available at module scope — e.g. a Cloudflare Hyperdrive binding:
|
|
867
878
|
* `connectionString: async () => (await getCloudflareContext({ async: true
|
|
868
|
-
* })).env.HYPERDRIVE.connectionString`.
|
|
879
|
+
* })).env.HYPERDRIVE.connectionString`. Return `null`/`undefined` from it
|
|
880
|
+
* when there is nothing to give — both surface the same "could not
|
|
881
|
+
* resolve a Postgres connection string" error as leaving this unset.
|
|
869
882
|
*/
|
|
870
|
-
connectionString?:
|
|
883
|
+
connectionString?: FallibleConfigValue<string>;
|
|
871
884
|
/**
|
|
872
885
|
* Whether the pooled client is closed once the last in-flight
|
|
873
886
|
* `withPublicDb`/`withUserDb` call of the request finishes.
|