cloudflare-next-intl 0.8.51 → 0.8.52

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 CHANGED
@@ -868,7 +868,7 @@ npx cfni-db-codegen --check
868
868
  | `--ddl-dir=` | `CFNI_DB_DDL_DIR` | `supabase/data-base` |
869
869
  | `--out-dir=` | `CFNI_DB_OUT_DIR` | `src/shared/db/generated` |
870
870
  | `--out-file=` | `CFNI_DB_OUT_FILE` | `schema.ts` |
871
- | `--db-url=` | `CODEGEN_DATABASE_URL` | `postgresql://postgres:postgres@127.0.0.1:54322/postgres` |
871
+ | `--db-url=` | `CODEGEN_DATABASE_URL` | none (prefers `embedded-postgres`) |
872
872
  | `--drizzle-config=` | `CFNI_DB_DRIZZLE_CONFIG` | none |
873
873
  | `--rpc-dir=` | `CFNI_DB_RPC_DIR` | inside `--ddl-dir`, e.g. `supabase/data-base/rpcs` |
874
874
  | `--rpc-file-name=` | `CFNI_DB_RPC_FILE_NAME` | `cfni_exec.sql` |
@@ -888,14 +888,9 @@ them and fails naming the first one that is stale.
888
888
  npx cfni-db-codegen --out-dir=src/shared/db/generated --out-dir=../other-app/src/db/generated
889
889
  ```
890
890
 
891
- If no `--db-url`/`CODEGEN_DATABASE_URL` is set and nothing is reachable at the
892
- local Supabase default, `cfni-db-codegen` falls back to a throwaway,
893
- local-only Postgres started via the optional `embedded-postgres` package (a
894
- prebuilt binary, no Docker required): install it once with
895
- `npm install --save-dev embedded-postgres`, and no local DB setup is needed —
896
- the DDL in `--ddl-dir` is loaded into it, introspected, and it's torn down
897
- after. Passing an explicit `--db-url`/`CODEGEN_DATABASE_URL` skips this
898
- fallback entirely and fails loudly if that target is unreachable.
891
+ By default, `cfni-db-codegen` uses the built-in `embedded-postgres` package to spin up a throwaway local Postgres, load your project's DDL from `--ddl-dir`, and introspect it with zero external dependencies (no Docker or running Postgres required).
892
+
893
+ If you explicitly pass `--db-url=` or set `CODEGEN_DATABASE_URL`, `cfni-db-codegen` will connect to that specific live database instead. If the provided database URL is unreachable or invalid, a warning is printed and it automatically falls back to generating the schema via `embedded-postgres`.
899
894
 
900
895
  ##### Keeping `cfni_exec.sql` in sync (`--rpc-dir`/`--rpc-file-name`/`--tests-dir`/`--tests-file-name`/`--force`/`--skip-exec`)
901
896
 
@@ -13,11 +13,10 @@
13
13
  // same schema into several projects at once (CFNI_DB_OUT_DIR accepts a
14
14
  // comma-separated list too).
15
15
  //
16
- // Needs a reachable Postgres to introspect any Postgres, not specifically
17
- // a Docker one. Set CODEGEN_DATABASE_URL to point at whichever you have:
18
- // local Supabase (./supabase/scripts/db_start.sh --reset, needs Docker), a
19
- // native Postgres install, or a remote/staging database. With no env var
20
- // set, it tries the local Supabase default (127.0.0.1:54322).
16
+ // Prefers the embedded-postgres library by default (zero setup, no Docker needed)
17
+ // to introspect the DDL in --ddl-dir. If the user explicitly sets --db-url or
18
+ // CODEGEN_DATABASE_URL, it uses that URL; if the explicit URL is unreachable,
19
+ // it warns and falls back to embedded-postgres.
21
20
  // CODEGEN_CONNECT_TIMEOUT_MS overrides the 5s default reachability-check
22
21
  // timeout — raise it for a slow/cold-starting remote or serverless target.
23
22
  //
@@ -55,13 +54,12 @@ async function isReachable(url) {
55
54
  }
56
55
  }
57
56
 
58
- function failUnreachable(url) {
59
- console.error(`❌ Could not reach Postgres at ${url}`);
60
- console.error("\n drizzle-kit pull needs a live Postgres to introspect — any one works, this script has no Docker dependency of its own. Pick one:");
61
- console.error(" - Local Supabase (needs Docker running): ./supabase/scripts/db_start.sh --reset");
62
- console.error(" - A native Postgres you already have: CODEGEN_DATABASE_URL=postgresql://... npm run db:codegen");
63
- console.error(" - A remote/staging database: CODEGEN_DATABASE_URL=postgresql://... npm run db:codegen");
64
- console.error(" - Zero setup (no Docker/Postgres at all): npm install --save-dev embedded-postgres (auto-used as a fallback)");
57
+ function failUnreachable(target) {
58
+ console.error(`❌ Could not reach Postgres at ${target} and embedded-postgres could not be started.`);
59
+ console.error("\n drizzle-kit pull needs a Postgres to introspect. You can:");
60
+ console.error(" - Ensure embedded-postgres is installed (default, no Docker): npm install --save-dev embedded-postgres");
61
+ console.error(" - Or specify a reachable database URL: CODEGEN_DATABASE_URL=postgresql://... npm run db:codegen");
62
+ console.error(" - Or start local Supabase (needs Docker): ./supabase/scripts/db_start.sh --reset");
65
63
  console.error(` Slow/cold-starting target? Raise the timeout: CODEGEN_CONNECT_TIMEOUT_MS=15000 npm run db:codegen`);
66
64
  process.exit(1);
67
65
  }
@@ -96,7 +94,7 @@ if (paths.check) {
96
94
  process.exit(0);
97
95
  }
98
96
 
99
- let effectiveDbUrl = paths.dbUrl;
97
+ let effectiveDbUrl = null;
100
98
  let ephemeral = null;
101
99
  // drizzle-kit's own default config resolution looks for `drizzle.config.json`
102
100
  // in the cwd and errors out if it's missing — a project has no reason to
@@ -105,11 +103,32 @@ let ephemeral = null;
105
103
  // when the caller didn't pass --drizzle-config, generate one on the fly.
106
104
  let generatedConfigPath = null;
107
105
  try {
108
- if (!(await isReachable(paths.dbUrl))) {
109
- if (paths.dbUrlExplicit) failUnreachable(paths.dbUrl);
106
+ if (paths.dbUrlExplicit && paths.dbUrl) {
107
+ if (await isReachable(paths.dbUrl)) {
108
+ effectiveDbUrl = paths.dbUrl;
109
+ } else {
110
+ console.warn(`⚠️ Database URL '${paths.dbUrl}' is unreachable or invalid. Falling back to embedded-postgres library...\n`);
111
+ ephemeral = await startEphemeralPostgres(orderedSqlFiles(paths.ddlDir));
112
+ if (ephemeral) {
113
+ effectiveDbUrl = ephemeral.url;
114
+ } else {
115
+ failUnreachable(paths.dbUrl);
116
+ }
117
+ }
118
+ } else {
119
+ // By default, prefer embedded-postgres library directly (zero setup, no Docker/external DB dependency)
110
120
  ephemeral = await startEphemeralPostgres(orderedSqlFiles(paths.ddlDir));
111
- if (!ephemeral) failUnreachable(paths.dbUrl);
112
- effectiveDbUrl = ephemeral.url;
121
+ if (ephemeral) {
122
+ effectiveDbUrl = ephemeral.url;
123
+ } else {
124
+ // If embedded-postgres is not available / failed, check local Supabase default as fallback
125
+ const localFallback = 'postgresql://postgres:postgres@127.0.0.1:54322/postgres';
126
+ if (await isReachable(localFallback)) {
127
+ effectiveDbUrl = localFallback;
128
+ } else {
129
+ failUnreachable('embedded-postgres library or local Supabase (127.0.0.1:54322)');
130
+ }
131
+ }
113
132
  }
114
133
 
115
134
  let configPath = paths.drizzleConfig;
@@ -1,8 +1,6 @@
1
1
  // Spins up a throwaway, local-only Postgres (via `embedded-postgres`, a
2
2
  // prebuilt binary — no Docker) so `cfni-db-codegen` can introspect DDL
3
- // without any live Postgres already running. Used only as a fallback when
4
- // no --db-url/CODEGEN_DATABASE_URL was given and nothing is reachable at the
5
- // local Supabase default.
3
+ // without any external live Postgres running.
6
4
  import { readFileSync, rmSync } from 'node:fs';
7
5
  import { relative } from 'node:path';
8
6
  import { Client } from 'pg';
@@ -44,7 +42,7 @@ export async function startEphemeralPostgres(sqlFiles) {
44
42
  persistent: false,
45
43
  });
46
44
 
47
- console.log('ℹ️ No reachable Postgres found — starting an ephemeral one (embedded-postgres, no Docker needed)…');
45
+ console.log('ℹ️ Using embedded-postgres (zero setup, no Docker) to introspect DDL…');
48
46
  try {
49
47
  await pg.initialise();
50
48
  await pg.start();
@@ -53,8 +51,90 @@ export async function startEphemeralPostgres(sqlFiles) {
53
51
  await client.connect();
54
52
  try {
55
53
  for (const role of SUPABASE_ROLES) {
56
- await client.query(`CREATE ROLE ${role} NOLOGIN NOINHERIT;`);
54
+ await client.query(`CREATE ROLE ${role} NOLOGIN NOINHERIT;`).catch(() => {});
57
55
  }
56
+ await client.query(`CREATE SCHEMA IF NOT EXISTS auth;`).catch(() => {});
57
+ await client.query(`CREATE SCHEMA IF NOT EXISTS storage;`).catch(() => {});
58
+ await client.query(`CREATE SCHEMA IF NOT EXISTS extensions;`).catch(() => {});
59
+ await client.query(`CREATE EXTENSION IF NOT EXISTS "uuid-ossp";`).catch(() => {});
60
+ await client.query(`CREATE EXTENSION IF NOT EXISTS "pgcrypto";`).catch(() => {});
61
+
62
+ // Bootstrap common Supabase helper functions and tables for DDL compatibility
63
+ await client.query(`
64
+ CREATE OR REPLACE FUNCTION auth.uid() RETURNS uuid LANGUAGE sql STABLE AS $$ SELECT null::uuid $$;
65
+ CREATE OR REPLACE FUNCTION auth.jwt() RETURNS jsonb LANGUAGE sql STABLE AS $$ SELECT '{}'::jsonb $$;
66
+ CREATE OR REPLACE FUNCTION auth.role() RETURNS text LANGUAGE sql STABLE AS $$ SELECT 'anon'::text $$;
67
+ CREATE OR REPLACE FUNCTION auth.email() RETURNS text LANGUAGE sql STABLE AS $$ SELECT ''::text $$;
68
+
69
+ CREATE TABLE IF NOT EXISTS auth.users (
70
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
71
+ email text,
72
+ created_at timestamptz DEFAULT now(),
73
+ updated_at timestamptz DEFAULT now(),
74
+ raw_user_meta_data jsonb DEFAULT '{}'::jsonb,
75
+ raw_app_meta_data jsonb DEFAULT '{}'::jsonb
76
+ );
77
+
78
+ CREATE TABLE IF NOT EXISTS storage.buckets (
79
+ id text PRIMARY KEY,
80
+ name text NOT NULL,
81
+ owner uuid,
82
+ created_at timestamptz DEFAULT now(),
83
+ updated_at timestamptz DEFAULT now(),
84
+ public boolean DEFAULT false,
85
+ avif_autodetection boolean DEFAULT false,
86
+ file_size_limit bigint,
87
+ allowed_mime_types text[],
88
+ owner_id text
89
+ );
90
+
91
+ CREATE TABLE IF NOT EXISTS storage.objects (
92
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
93
+ bucket_id text REFERENCES storage.buckets(id),
94
+ name text,
95
+ owner uuid,
96
+ created_at timestamptz DEFAULT now(),
97
+ updated_at timestamptz DEFAULT now(),
98
+ last_accessed_at timestamptz DEFAULT now(),
99
+ metadata jsonb,
100
+ path_tokens text[] GENERATED ALWAYS AS (string_to_array(name, '/')) STORED,
101
+ version text,
102
+ owner_id text
103
+ );
104
+
105
+ CREATE OR REPLACE FUNCTION storage.foldername(name text) RETURNS text[] LANGUAGE plpgsql AS $$
106
+ BEGIN
107
+ RETURN string_to_array(name, '/');
108
+ END
109
+ $$;
110
+
111
+ CREATE OR REPLACE FUNCTION storage.filename(name text) RETURNS text LANGUAGE plpgsql AS $$
112
+ DECLARE
113
+ parts text[];
114
+ BEGIN
115
+ parts := string_to_array(name, '/');
116
+ RETURN parts[array_length(parts, 1)];
117
+ END
118
+ $$;
119
+
120
+ CREATE OR REPLACE FUNCTION storage.extension(name text) RETURNS text LANGUAGE plpgsql AS $$
121
+ DECLARE
122
+ parts text[];
123
+ filename text;
124
+ ext_parts text[];
125
+ BEGIN
126
+ parts := string_to_array(name, '/');
127
+ filename := parts[array_length(parts, 1)];
128
+ ext_parts := string_to_array(filename, '.');
129
+ IF array_length(ext_parts, 1) > 1 THEN
130
+ RETURN ext_parts[array_length(ext_parts, 1)];
131
+ ELSE
132
+ RETURN '';
133
+ END IF;
134
+ END
135
+ $$;
136
+ `).catch(() => {});
137
+
58
138
  for (const file of sqlFiles) {
59
139
  const sql = readFileSync(file, 'utf8');
60
140
  if (sql.trim().length === 0) continue;
@@ -10,7 +10,7 @@ export interface CodegenPaths {
10
10
  outFile: string;
11
11
  pullDir: string;
12
12
  manifest: string;
13
- dbUrl: string;
13
+ dbUrl: string | null;
14
14
  dbUrlExplicit: boolean;
15
15
  check: boolean;
16
16
  timeoutMs: number;
@@ -2,7 +2,7 @@ import { dirname, isAbsolute, join, resolve } from 'node:path';
2
2
  const DEFAULT_DDL_DIR = 'supabase/data-base';
3
3
  const DEFAULT_OUT_DIR = 'src/shared/db/generated';
4
4
  const DEFAULT_OUT_FILE = 'schema.ts';
5
- const DEFAULT_DB_URL = 'postgresql://postgres:postgres@127.0.0.1:54322/postgres';
5
+ const DEFAULT_DB_URL = null;
6
6
  const DEFAULT_TIMEOUT_MS = 5000;
7
7
  const DEFAULT_RPC_FILE_NAME = 'cfni_exec.sql';
8
8
  const DEFAULT_TESTS_FILE_NAME = 'cfni_exec.sql';
package/llms.txt CHANGED
@@ -69,7 +69,7 @@ Two transports, picked by which `db` fields are set — `pg`/`drizzle-orm`/`@sup
69
69
  - `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.
70
70
  - `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.
71
71
  - `./dbHelpers` functions are plain Drizzle `sql`-building utilities with no config dependency — usable standalone.
72
- - `cfni-db-codegen` binary — regenerates Drizzle models via `drizzle-kit pull`. Flags/env: `--ddl-dir`/`CFNI_DB_DDL_DIR`, `--out-dir`/`CFNI_DB_OUT_DIR`, `--out-file`/`CFNI_DB_OUT_FILE`, `--db-url`/`CODEGEN_DATABASE_URL`, `--drizzle-config`/`CFNI_DB_DRIZZLE_CONFIG`, `--rpc-dir`/`CFNI_DB_RPC_DIR`, `--tests-dir`/`CFNI_DB_TESTS_DIR`, `--force`/`CFNI_DB_FORCE_EXEC`, `--skip-exec`/`CFNI_DB_SKIP_EXEC`, `--check`. `--out-dir` is repeatable and accepts a comma-separated list, so one run generates the same schema (and `manifest.json`) into several projects; `--check` verifies every target. After a successful run it also copies `supabase/cfni_exec.sql` + its pgTAP test file into `--rpc-dir`/`--tests-dir` (siblings of `--ddl-dir` by default), gated on `db.supabase.rawSql` (read from `next.config.*`'s `@intl-config` alias; unknown → warns and assumes `true`) — skips if `rawSql: false`, skips if `--skip-exec`, skips-with-warning on a differing existing file unless `--force`. `cfni-db-install-exec` runs only this copy step, same flags, no Postgres/drizzle-kit needed.
72
+ - `cfni-db-codegen` binary — regenerates Drizzle models via `drizzle-kit pull`. By default, prefers `embedded-postgres` (zero setup, no Docker needed) to load DDL from `--ddl-dir` and introspect it. If an explicit `--db-url`/`CODEGEN_DATABASE_URL` is set, connects to that live DB (and falls back to `embedded-postgres` with a warning if unreachable). Flags/env: `--ddl-dir`/`CFNI_DB_DDL_DIR`, `--out-dir`/`CFNI_DB_OUT_DIR`, `--out-file`/`CFNI_DB_OUT_FILE`, `--db-url`/`CODEGEN_DATABASE_URL`, `--drizzle-config`/`CFNI_DB_DRIZZLE_CONFIG`, `--rpc-dir`/`CFNI_DB_RPC_DIR`, `--tests-dir`/`CFNI_DB_TESTS_DIR`, `--force`/`CFNI_DB_FORCE_EXEC`, `--skip-exec`/`CFNI_DB_SKIP_EXEC`, `--check`. `--out-dir` is repeatable and accepts a comma-separated list, so one run generates the same schema (and `manifest.json`) into several projects; `--check` verifies every target. After a successful run it also copies `supabase/cfni_exec.sql` + its pgTAP test file into `--rpc-dir`/`--tests-dir` (siblings of `--ddl-dir` by default), gated on `db.supabase.rawSql` (read from `next.config.*`'s `@intl-config` alias; unknown → warns and assumes `true`) — skips if `rawSql: false`, skips if `--skip-exec`, skips-with-warning on a differing existing file unless `--force`. `cfni-db-install-exec` runs only this copy step, same flags, no Postgres/drizzle-kit needed.
73
73
 
74
74
  ```typescript
75
75
  // src/i18n/intl_config.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudflare-next-intl",
3
- "version": "0.8.51",
3
+ "version": "0.8.52",
4
4
  "description": "Optimized Next Intl Package Special for App Router and Cloudflare",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",