cloudflare-next-intl 0.8.2 → 0.8.4
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 +40 -15
- package/dist/src/db/connection.d.ts +1 -1
- package/dist/src/db/connection.js +12 -19
- package/dist/src/db/context.js +1 -1
- package/dist/src/db/helpers.d.ts +16 -0
- package/dist/src/db/helpers.js +18 -0
- package/dist/src/db/index.d.ts +3 -4
- package/dist/src/db/index.js +3 -4
- package/dist/src/db/require_config.js +1 -1
- package/dist/src/db/resolve_config_value.d.ts +9 -0
- package/dist/src/db/resolve_config_value.js +10 -0
- package/dist/src/db/resolve_mode.d.ts +2 -2
- package/dist/src/db/resolve_mode.js +3 -3
- package/dist/src/db/supabase_config.d.ts +2 -1
- package/dist/src/db/supabase_config.js +5 -3
- package/dist/src/db/supabase_transport.js +1 -1
- package/dist/src/types/index.d.ts +1 -1
- package/dist/src/types/types.d.ts +20 -16
- package/llms.txt +7 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ and Cloudflare environment.
|
|
|
14
14
|
- **Error handling**: shared, opt-in `console.error` override and
|
|
15
15
|
`reportError`/`withErrorHandling` helpers, GDPR-aware (consent-gated).
|
|
16
16
|
- **Database**: optional Postgres/Drizzle data-access layer, reachable either
|
|
17
|
-
directly (
|
|
17
|
+
directly (a connection string, e.g. from Cloudflare Hyperdrive) or through the
|
|
18
18
|
Supabase Data API (project URL + anon key only), with request-scoped
|
|
19
19
|
public/user contexts and RLS wiring in both modes.
|
|
20
20
|
|
|
@@ -390,8 +390,8 @@ third party without consent can itself be GDPR-relevant.
|
|
|
390
390
|
|
|
391
391
|
### Database (`db`)
|
|
392
392
|
|
|
393
|
-
Thin Postgres/Drizzle data-access layer over a
|
|
394
|
-
(
|
|
393
|
+
Thin Postgres/Drizzle data-access layer over a Postgres connection string
|
|
394
|
+
(which may come from a Cloudflare Hyperdrive binding). `pg` and `drizzle-orm` ship as dependencies of
|
|
395
395
|
this package, so there is nothing extra to install. They are loaded through
|
|
396
396
|
dynamic `import()` inside the `db` exports, so an app that never calls a `db`
|
|
397
397
|
export never pulls them into its bundle. Enable it by setting `db` on your
|
|
@@ -405,19 +405,20 @@ export default setIntlConfig({
|
|
|
405
405
|
locales: ["en", "uk"] as const,
|
|
406
406
|
defaultLocale: "en",
|
|
407
407
|
generate: { getCloudflareContext },
|
|
408
|
-
db: {
|
|
408
|
+
db: {
|
|
409
|
+
connectionString: async () =>
|
|
410
|
+
(await getCloudflareContext({ async: true })).env.HYPERDRIVE
|
|
411
|
+
.connectionString,
|
|
412
|
+
},
|
|
409
413
|
});
|
|
410
414
|
```
|
|
411
415
|
|
|
412
416
|
`db` fields (all optional):
|
|
413
417
|
|
|
414
|
-
- `connectionString` — a Postgres connection string
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
- `hyperdriveBinding` — name of the Hyperdrive binding on `env` to read a
|
|
419
|
-
connection string from when `connectionString` is not set. Defaults to
|
|
420
|
-
`'HYPERDRIVE'`. Requires `generate.getCloudflareContext` to be configured.
|
|
418
|
+
- `connectionString` — a Postgres connection string, or a sync/async function
|
|
419
|
+
returning one (resolved on each connect). The function form is how you reach
|
|
420
|
+
a value that isn't available at module scope — a Cloudflare Hyperdrive
|
|
421
|
+
binding, or a secret store — as in the example above.
|
|
421
422
|
- `disconnectAfterRequest` — whether the pooled client is closed once the
|
|
422
423
|
last in-flight `withPublicDb`/`withUserDb` call of the request
|
|
423
424
|
finishes. Defaults to `true` (one connection per request, released to
|
|
@@ -441,7 +442,7 @@ query code is identical either way — switching is a config change only.
|
|
|
441
442
|
|
|
442
443
|
| Config | Transport | Use when |
|
|
443
444
|
|---|---|---|
|
|
444
|
-
| `connectionString`
|
|
445
|
+
| `connectionString` | Direct Postgres via `pg` | You have a Postgres connection string, or a Hyperdrive binding to read one from. |
|
|
445
446
|
| `supabase` | Supabase Data API (PostgREST) | You only have `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY`. |
|
|
446
447
|
|
|
447
448
|
A direct connection always wins if both are configured, so adding a `supabase`
|
|
@@ -472,11 +473,35 @@ bundles any of them.
|
|
|
472
473
|
|
|
473
474
|
`db.supabase` fields (all optional):
|
|
474
475
|
|
|
475
|
-
- `url` — project URL. Defaults to
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
- `url` — project URL, or a sync/async function returning one. Defaults to
|
|
477
|
+
`NEXT_PUBLIC_SUPABASE_URL`.
|
|
478
|
+
- `anonKey` — anon/publishable key, or a sync/async function returning one.
|
|
479
|
+
Defaults to `NEXT_PUBLIC_SUPABASE_ANON_KEY`. Never put a service-role key
|
|
480
|
+
here.
|
|
478
481
|
- `execFunction` — name of the exec function. Defaults to `'cfni_exec'`.
|
|
479
482
|
|
|
483
|
+
Any of `connectionString`, `supabase.url`, and `supabase.anonKey` may be a
|
|
484
|
+
function instead of a string, resolved (and awaited) at use time rather than
|
|
485
|
+
when the config object is built — useful when the value lives in a secret
|
|
486
|
+
store or a Cloudflare binding rather than an environment variable:
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
export default setIntlConfig({
|
|
490
|
+
locales: ["en", "uk"] as const,
|
|
491
|
+
defaultLocale: "en",
|
|
492
|
+
generate: { getCloudflareContext },
|
|
493
|
+
db: {
|
|
494
|
+
supabase: {
|
|
495
|
+
url: "https://abc.supabase.co",
|
|
496
|
+
anonKey: async () => {
|
|
497
|
+
const { env } = await getCloudflareContext({ async: true });
|
|
498
|
+
return env.SUPABASE_ANON_KEY.get();
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
480
505
|
`db.getAccessToken` resolves the JWT `withUserDb` sends as
|
|
481
506
|
`Authorization: Bearer`, which is what makes PostgREST resolve the caller as
|
|
482
507
|
`authenticated`. Omit it when `firebaseAuth` is configured — the signed-in
|
|
@@ -23,7 +23,7 @@ export declare function resetConnectionState(): void;
|
|
|
23
23
|
* @param config Your routing config; `config.db` must be set.
|
|
24
24
|
* @returns The connected, shared client.
|
|
25
25
|
* @throws If `db` is not set, or no connection string can be resolved from
|
|
26
|
-
* `db.connectionString
|
|
26
|
+
* `db.connectionString`.
|
|
27
27
|
*/
|
|
28
28
|
export default function connectToPostgres(config: DbConfig): Promise<Client>;
|
|
29
29
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import reportError from '../error_handling/report_error';
|
|
2
2
|
import requireDbConfig from './require_config';
|
|
3
|
-
|
|
3
|
+
import resolveConfigValue from './resolve_config_value';
|
|
4
4
|
const DEFAULT_DISCONNECT_TIMEOUT_MS = 2000;
|
|
5
5
|
let connectionString = null;
|
|
6
6
|
let client = null;
|
|
@@ -26,23 +26,16 @@ export function resetConnectionState() {
|
|
|
26
26
|
activeUsers = 0;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* Resolves the connection string from `db.connectionString
|
|
30
|
-
*
|
|
29
|
+
* Resolves the connection string from `db.connectionString`, awaiting it when
|
|
30
|
+
* it was given as a function.
|
|
31
31
|
*/
|
|
32
|
-
async function resolveConnectionString(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const binding = env?.[db.hyperdriveBinding ?? DEFAULT_BINDING];
|
|
40
|
-
if (binding?.connectionString)
|
|
41
|
-
return binding.connectionString;
|
|
42
|
-
}
|
|
43
|
-
throw new Error('db: could not resolve a Postgres connection string. Set `db.connectionString`, or ' +
|
|
44
|
-
`configure \`generate.getCloudflareContext\` and a \`${db.hyperdriveBinding ?? DEFAULT_BINDING}\` ` +
|
|
45
|
-
'Hyperdrive binding on your Worker.');
|
|
32
|
+
async function resolveConnectionString(db) {
|
|
33
|
+
const configured = await resolveConfigValue(db.connectionString);
|
|
34
|
+
if (configured)
|
|
35
|
+
return configured;
|
|
36
|
+
throw new Error('db: could not resolve a Postgres connection string. Set `db.connectionString` ' +
|
|
37
|
+
'to a connection string, or to a function returning one (e.g. reading a ' +
|
|
38
|
+
'Hyperdrive binding off `getCloudflareContext().env`).');
|
|
46
39
|
}
|
|
47
40
|
// A single `pg.Client` is not safe for concurrent queries; Next.js fires many
|
|
48
41
|
// in parallel per request. Serializing every `query` through one promise chain
|
|
@@ -73,7 +66,7 @@ function serializeQueries(raw) {
|
|
|
73
66
|
* @param config Your routing config; `config.db` must be set.
|
|
74
67
|
* @returns The connected, shared client.
|
|
75
68
|
* @throws If `db` is not set, or no connection string can be resolved from
|
|
76
|
-
* `db.connectionString
|
|
69
|
+
* `db.connectionString`.
|
|
77
70
|
*/
|
|
78
71
|
export default async function connectToPostgres(config) {
|
|
79
72
|
const db = config.db;
|
|
@@ -82,7 +75,7 @@ export default async function connectToPostgres(config) {
|
|
|
82
75
|
if (connectingPromise === null) {
|
|
83
76
|
connectingPromise = (async () => {
|
|
84
77
|
try {
|
|
85
|
-
connectionString ?? (connectionString = await resolveConnectionString(
|
|
78
|
+
connectionString ?? (connectionString = await resolveConnectionString(db));
|
|
86
79
|
const { Client } = await import('pg');
|
|
87
80
|
const created = serializeQueries(new Client({ connectionString }));
|
|
88
81
|
client = created;
|
package/dist/src/db/context.js
CHANGED
|
@@ -60,7 +60,7 @@ export async function withPublicDb(fn) {
|
|
|
60
60
|
requireDbConfig(db);
|
|
61
61
|
if (resolveDbMode(db) === 'supabase') {
|
|
62
62
|
const supabase = db.supabase;
|
|
63
|
-
const { anonKey } = resolveSupabaseEndpoint(supabase);
|
|
63
|
+
const { anonKey } = await resolveSupabaseEndpoint(supabase);
|
|
64
64
|
return fn(await supabaseDb(supabase, anonKey));
|
|
65
65
|
}
|
|
66
66
|
const client = await connectToPostgres(config);
|
package/dist/src/db/helpers.d.ts
CHANGED
|
@@ -60,5 +60,21 @@ export declare function maxOf<T = unknown>(expression: unknown): SQL<T>;
|
|
|
60
60
|
export declare function roundReal(expression: unknown, digits: number): SQL<number>;
|
|
61
61
|
/** Multiplies an expression by a factor. */
|
|
62
62
|
export declare function multiply(expression: unknown, factor: number): SQL<number>;
|
|
63
|
+
/**
|
|
64
|
+
* Wraps an aggregate over a subquery/CTE as a scalar subquery:
|
|
65
|
+
* `(select <expr> from <source>)`.
|
|
66
|
+
*
|
|
67
|
+
* Unlike {@link scalarFromCte} this takes the Drizzle CTE/subquery object
|
|
68
|
+
* rather than its name, so the source is referenced through the query builder
|
|
69
|
+
* and its columns stay typed.
|
|
70
|
+
*
|
|
71
|
+
* @param source A Drizzle CTE or subquery to read from.
|
|
72
|
+
* @param expression The aggregate expression to select.
|
|
73
|
+
* @returns A scalar subquery usable directly in a `select({...})`.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* select({ lowest: scalarFrom(filtered, minOf(filtered.price)) })
|
|
77
|
+
*/
|
|
78
|
+
export declare function scalarFrom<T = unknown>(source: unknown, expression: unknown): SQL<T>;
|
|
63
79
|
/** Wraps an expression as a scalar subquery over a named CTE: `(select <expr> from <cte>)`. */
|
|
64
80
|
export declare function scalarFromCte<T = unknown>(cte: string, expression: unknown): SQL<T>;
|
package/dist/src/db/helpers.js
CHANGED
|
@@ -113,6 +113,24 @@ export function roundReal(expression, digits) {
|
|
|
113
113
|
export function multiply(expression, factor) {
|
|
114
114
|
return sql `${expression} * ${factor}`;
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* Wraps an aggregate over a subquery/CTE as a scalar subquery:
|
|
118
|
+
* `(select <expr> from <source>)`.
|
|
119
|
+
*
|
|
120
|
+
* Unlike {@link scalarFromCte} this takes the Drizzle CTE/subquery object
|
|
121
|
+
* rather than its name, so the source is referenced through the query builder
|
|
122
|
+
* and its columns stay typed.
|
|
123
|
+
*
|
|
124
|
+
* @param source A Drizzle CTE or subquery to read from.
|
|
125
|
+
* @param expression The aggregate expression to select.
|
|
126
|
+
* @returns A scalar subquery usable directly in a `select({...})`.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* select({ lowest: scalarFrom(filtered, minOf(filtered.price)) })
|
|
130
|
+
*/
|
|
131
|
+
export function scalarFrom(source, expression) {
|
|
132
|
+
return sql `(select ${expression} from ${source})`;
|
|
133
|
+
}
|
|
116
134
|
/** Wraps an expression as a scalar subquery over a named CTE: `(select <expr> from <cte>)`. */
|
|
117
135
|
export function scalarFromCte(cte, expression) {
|
|
118
136
|
return sql `(select ${expression} from ${sql.raw(cte)})`;
|
package/dist/src/db/index.d.ts
CHANGED
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
* - {@link withUserDb} — the signed-in user, with RLS applied to their id.
|
|
9
9
|
*
|
|
10
10
|
* Two transports reach Postgres behind that same Drizzle query API, chosen by
|
|
11
|
-
* `resolveDbMode` from which `db` config fields are set: `connectionString
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* key are available. `pg`, `drizzle-orm`, and `@supabase/supabase-js` all
|
|
11
|
+
* `resolveDbMode` from which `db` config fields are set: `connectionString`
|
|
12
|
+
* for a direct connection (wins if both are configured), or `supabase` for
|
|
13
|
+
* the Supabase Data API when only a project URL and anon key are available. `pg`, `drizzle-orm`, and `@supabase/supabase-js` all
|
|
15
14
|
* load through dynamic `import()` inside these functions, so an app that
|
|
16
15
|
* never calls a `db` export never bundles any of them.
|
|
17
16
|
*
|
package/dist/src/db/index.js
CHANGED
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
* - {@link withUserDb} — the signed-in user, with RLS applied to their id.
|
|
9
9
|
*
|
|
10
10
|
* Two transports reach Postgres behind that same Drizzle query API, chosen by
|
|
11
|
-
* `resolveDbMode` from which `db` config fields are set: `connectionString
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* key are available. `pg`, `drizzle-orm`, and `@supabase/supabase-js` all
|
|
11
|
+
* `resolveDbMode` from which `db` config fields are set: `connectionString`
|
|
12
|
+
* for a direct connection (wins if both are configured), or `supabase` for
|
|
13
|
+
* the Supabase Data API when only a project URL and anon key are available. `pg`, `drizzle-orm`, and `@supabase/supabase-js` all
|
|
15
14
|
* load through dynamic `import()` inside these functions, so an app that
|
|
16
15
|
* never calls a `db` export never bundles any of them.
|
|
17
16
|
*
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
export default function requireDbConfig(db) {
|
|
15
15
|
if (!db) {
|
|
16
16
|
throw new Error('db: `db` is not set on your RoutingConfig. Add a `db` object ' +
|
|
17
|
-
'(connectionString or
|
|
17
|
+
'(connectionString or supabase) to the config passed to ' +
|
|
18
18
|
'`setIntlConfig` before using any db export.');
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConfigValue } from '../types/types';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a config value that may have been supplied directly or as a
|
|
4
|
+
* sync/async function.
|
|
5
|
+
*
|
|
6
|
+
* @param value The configured value or resolver.
|
|
7
|
+
* @returns The resolved value, or `undefined` when nothing was configured.
|
|
8
|
+
*/
|
|
9
|
+
export default function resolveConfigValue<T>(value: ConfigValue<T | undefined> | undefined): Promise<T | undefined>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a config value that may have been supplied directly or as a
|
|
3
|
+
* sync/async function.
|
|
4
|
+
*
|
|
5
|
+
* @param value The configured value or resolver.
|
|
6
|
+
* @returns The resolved value, or `undefined` when nothing was configured.
|
|
7
|
+
*/
|
|
8
|
+
export default async function resolveConfigValue(value) {
|
|
9
|
+
return typeof value === 'function' ? value() : value;
|
|
10
|
+
}
|
|
@@ -8,10 +8,10 @@ export type DbMode = 'postgres' | 'supabase';
|
|
|
8
8
|
* block to an existing config never silently reroutes live traffic. With
|
|
9
9
|
* neither set the result is still `'postgres'`, which lets
|
|
10
10
|
* `connectToPostgres` raise its existing, more specific error about the
|
|
11
|
-
* missing
|
|
11
|
+
* missing connection string.
|
|
12
12
|
*
|
|
13
13
|
* @param db The `db` field off your routing config.
|
|
14
|
-
* @returns `'postgres'` for connection-string
|
|
14
|
+
* @returns `'postgres'` for direct connection-string access, `'supabase'`
|
|
15
15
|
* for PostgREST access.
|
|
16
16
|
*/
|
|
17
17
|
export default function resolveDbMode(db: DbRoutingConfig): DbMode;
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* block to an existing config never silently reroutes live traffic. With
|
|
6
6
|
* neither set the result is still `'postgres'`, which lets
|
|
7
7
|
* `connectToPostgres` raise its existing, more specific error about the
|
|
8
|
-
* missing
|
|
8
|
+
* missing connection string.
|
|
9
9
|
*
|
|
10
10
|
* @param db The `db` field off your routing config.
|
|
11
|
-
* @returns `'postgres'` for connection-string
|
|
11
|
+
* @returns `'postgres'` for direct connection-string access, `'supabase'`
|
|
12
12
|
* for PostgREST access.
|
|
13
13
|
*/
|
|
14
14
|
export default function resolveDbMode(db) {
|
|
15
|
-
if (db.connectionString
|
|
15
|
+
if (db.connectionString)
|
|
16
16
|
return 'postgres';
|
|
17
17
|
return db.supabase ? 'supabase' : 'postgres';
|
|
18
18
|
}
|
|
@@ -13,6 +13,7 @@ export interface ResolvedSupabaseEndpoint {
|
|
|
13
13
|
*
|
|
14
14
|
* @param supabase The `db.supabase` config block.
|
|
15
15
|
* @returns The project URL and anon key to build a Supabase client from.
|
|
16
|
+
* Values given as functions are resolved here.
|
|
16
17
|
* @throws If neither config nor environment supplies a URL or an anon key.
|
|
17
18
|
*/
|
|
18
|
-
export default function resolveSupabaseEndpoint(supabase: SupabaseDbConfig): ResolvedSupabaseEndpoint
|
|
19
|
+
export default function resolveSupabaseEndpoint(supabase: SupabaseDbConfig): Promise<ResolvedSupabaseEndpoint>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import resolveConfigValue from './resolve_config_value';
|
|
1
2
|
/**
|
|
2
3
|
* Resolves the Supabase project URL and anon key, preferring explicit config
|
|
3
4
|
* over the `NEXT_PUBLIC_SUPABASE_URL`/`NEXT_PUBLIC_SUPABASE_ANON_KEY`
|
|
@@ -5,15 +6,16 @@
|
|
|
5
6
|
*
|
|
6
7
|
* @param supabase The `db.supabase` config block.
|
|
7
8
|
* @returns The project URL and anon key to build a Supabase client from.
|
|
9
|
+
* Values given as functions are resolved here.
|
|
8
10
|
* @throws If neither config nor environment supplies a URL or an anon key.
|
|
9
11
|
*/
|
|
10
|
-
export default function resolveSupabaseEndpoint(supabase) {
|
|
11
|
-
const url = supabase.url ?? process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
12
|
+
export default async function resolveSupabaseEndpoint(supabase) {
|
|
13
|
+
const url = (await resolveConfigValue(supabase.url)) ?? process.env.NEXT_PUBLIC_SUPABASE_URL;
|
|
12
14
|
if (!url) {
|
|
13
15
|
throw new Error('db: could not resolve a Supabase project URL. Set `db.supabase.url` ' +
|
|
14
16
|
'or the NEXT_PUBLIC_SUPABASE_URL environment variable.');
|
|
15
17
|
}
|
|
16
|
-
const anonKey = supabase.anonKey ?? process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
18
|
+
const anonKey = (await resolveConfigValue(supabase.anonKey)) ?? process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
|
17
19
|
if (!anonKey) {
|
|
18
20
|
throw new Error('db: could not resolve a Supabase anon key. Set `db.supabase.anonKey` ' +
|
|
19
21
|
'or the NEXT_PUBLIC_SUPABASE_ANON_KEY environment variable.');
|
|
@@ -21,11 +21,11 @@ const DEFAULT_EXEC_FUNCTION = 'cfni_exec';
|
|
|
21
21
|
* @returns A callback suitable for `drizzle-orm/pg-proxy`'s `drizzle()`.
|
|
22
22
|
*/
|
|
23
23
|
export default function createSupabaseTransport(supabase, bearerToken) {
|
|
24
|
-
const { url, anonKey } = resolveSupabaseEndpoint(supabase);
|
|
25
24
|
const execFunction = supabase.execFunction ?? DEFAULT_EXEC_FUNCTION;
|
|
26
25
|
let clientPromise = null;
|
|
27
26
|
async function getClient() {
|
|
28
27
|
clientPromise ?? (clientPromise = (async () => {
|
|
28
|
+
const { url, anonKey } = await resolveSupabaseEndpoint(supabase);
|
|
29
29
|
const { createClient } = await import('@supabase/supabase-js');
|
|
30
30
|
return createClient(url, anonKey, { accessToken: async () => bearerToken });
|
|
31
31
|
})());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type { CookieAttributes, LocalePrefixMode, Locales, ReturnType, RoutingConfig, TranslationEntry, TranslationObject, TranslatorReturnType, Alternates, changeFrequency, IntlSitemap, CookieConsentRoutingConfig, CookieConsentAnalyticsConfig, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, DbRoutingConfig, SupabaseDbConfig, } from './types';
|
|
1
|
+
export type { CookieAttributes, LocalePrefixMode, Locales, ReturnType, RoutingConfig, TranslationEntry, TranslationObject, TranslatorReturnType, Alternates, changeFrequency, IntlSitemap, CookieConsentRoutingConfig, CookieConsentAnalyticsConfig, CookieConsentCloudflareContext, CookieConsentGetCloudflareContext, DbRoutingConfig, SupabaseDbConfig, ConfigValue, } from './types';
|
|
@@ -817,18 +817,27 @@ export interface IntlSitemap {
|
|
|
817
817
|
lastModified: Date | string | undefined;
|
|
818
818
|
videos?: Videos[] | undefined;
|
|
819
819
|
}
|
|
820
|
+
/**
|
|
821
|
+
* A config value that may be given directly, or as a sync/async function
|
|
822
|
+
* resolved at use time. The function form lets a value come from a secret
|
|
823
|
+
* store, a Cloudflare binding, or any other source that isn't available when
|
|
824
|
+
* the config object is first created.
|
|
825
|
+
*/
|
|
826
|
+
export type ConfigValue<T> = T | (() => T | Promise<T>);
|
|
820
827
|
export interface SupabaseDbConfig {
|
|
821
828
|
/**
|
|
822
829
|
* Supabase project URL, e.g. `https://abc.supabase.co`. Defaults to
|
|
823
|
-
* `process.env.NEXT_PUBLIC_SUPABASE_URL`.
|
|
830
|
+
* `process.env.NEXT_PUBLIC_SUPABASE_URL`. May be a function (sync or
|
|
831
|
+
* async) resolved on each use.
|
|
824
832
|
*/
|
|
825
|
-
url?: string
|
|
833
|
+
url?: ConfigValue<string | undefined>;
|
|
826
834
|
/**
|
|
827
835
|
* Supabase anon (publishable) key. Defaults to
|
|
828
836
|
* `process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY`. This is the only key the
|
|
829
|
-
* `db` module ever needs — never put a service-role key here.
|
|
837
|
+
* `db` module ever needs — never put a service-role key here. May be a
|
|
838
|
+
* function (sync or async) resolved on each use.
|
|
830
839
|
*/
|
|
831
|
-
anonKey?: string
|
|
840
|
+
anonKey?: ConfigValue<string | undefined>;
|
|
832
841
|
/**
|
|
833
842
|
* Name of the Postgres function that runs the generated SQL. Defaults to
|
|
834
843
|
* `'cfni_exec'` — the function shipped in `supabase/cfni_exec.sql`.
|
|
@@ -837,18 +846,13 @@ export interface SupabaseDbConfig {
|
|
|
837
846
|
}
|
|
838
847
|
export interface DbRoutingConfig {
|
|
839
848
|
/**
|
|
840
|
-
* Postgres connection string
|
|
841
|
-
*
|
|
842
|
-
*
|
|
843
|
-
*
|
|
844
|
-
|
|
845
|
-
connectionString?: string;
|
|
846
|
-
/**
|
|
847
|
-
* Name of the Hyperdrive binding on `env` whose `connectionString` is used
|
|
848
|
-
* when `connectionString` is not set. Defaults to `'HYPERDRIVE'`. Requires
|
|
849
|
-
* `generate.getCloudflareContext` to be configured.
|
|
849
|
+
* Postgres connection string, or a function (sync or async) returning one,
|
|
850
|
+
* resolved on each connect. The function form is how you reach a value that
|
|
851
|
+
* isn't available at module scope — e.g. a Cloudflare Hyperdrive binding:
|
|
852
|
+
* `connectionString: async () => (await getCloudflareContext({ async: true
|
|
853
|
+
* })).env.HYPERDRIVE.connectionString`.
|
|
850
854
|
*/
|
|
851
|
-
|
|
855
|
+
connectionString?: ConfigValue<string | undefined>;
|
|
852
856
|
/**
|
|
853
857
|
* Whether the pooled client is closed once the last in-flight
|
|
854
858
|
* `withPublicDb`/`withUserDb` call of the request finishes.
|
|
@@ -879,7 +883,7 @@ export interface DbRoutingConfig {
|
|
|
879
883
|
* `withUserDb` behave the same either way, so switching is a config change
|
|
880
884
|
* with no app-code change.
|
|
881
885
|
*
|
|
882
|
-
* Ignored when `connectionString`
|
|
886
|
+
* Ignored when `connectionString` is set: a direct
|
|
883
887
|
* connection always wins, so adding this block cannot silently reroute
|
|
884
888
|
* live traffic. Requires the `cfni_exec` function from
|
|
885
889
|
* `supabase/cfni_exec.sql` to be installed in your database.
|
package/llms.txt
CHANGED
|
@@ -50,8 +50,8 @@ other subpath can be used.
|
|
|
50
50
|
|
|
51
51
|
Two transports, picked by which `db` fields are set — `pg`/`drizzle-orm`/`@supabase/supabase-js` ship as dependencies and load via dynamic `import()`, so nothing bundles unless a `db` export is called.
|
|
52
52
|
|
|
53
|
-
- Direct Postgres (wins if configured): `db.connectionString` — Postgres connection string
|
|
54
|
-
- Supabase Data API (used only when neither of the above is set): `db.supabase` — `{ url?, anonKey?, execFunction? }
|
|
53
|
+
- 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.
|
|
54
|
+
- Supabase Data API (used only when neither of the above is set): `db.supabase` — `{ url?, anonKey?, execFunction? }` 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`. Requires installing `supabase/cfni_exec.sql` (a `security invoker` SQL-exec function) in your database. No multi-statement transactions — each statement in a `withUserDb` callback is its own round-trip.
|
|
55
55
|
- `db.disconnectAfterRequest` — direct-Postgres mode only: closes the pooled client once the last in-flight `withPublicDb`/`withUserDb` call of the request finishes. Defaults to `true`; set `false` to keep the connection open for the isolate's lifetime (holds a Hyperdrive slot between requests).
|
|
56
56
|
- `db.authenticatedRole` — direct-Postgres mode only: Postgres role assumed inside `withUserDb`'s transaction. Defaults to `'authenticated'` (Supabase RLS convention).
|
|
57
57
|
- `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()`.
|
|
@@ -69,7 +69,11 @@ export default setIntlConfig({
|
|
|
69
69
|
locales: ["en", "uk"] as const,
|
|
70
70
|
defaultLocale: "en",
|
|
71
71
|
generate: { getCloudflareContext },
|
|
72
|
-
db: {
|
|
72
|
+
db: {
|
|
73
|
+
connectionString: async () =>
|
|
74
|
+
(await getCloudflareContext({ async: true })).env.HYPERDRIVE
|
|
75
|
+
.connectionString,
|
|
76
|
+
},
|
|
73
77
|
});
|
|
74
78
|
|
|
75
79
|
// anywhere on the server
|