hazo_auth 5.1.25 → 5.1.28

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.
Files changed (74) hide show
  1. package/README.md +59 -21
  2. package/SETUP_CHECKLIST.md +159 -48
  3. package/bin/hazo_auth.mjs +8 -1
  4. package/cli-src/assets/images/new_firm_default.jpg +0 -0
  5. package/cli-src/cli/index.ts +36 -2
  6. package/cli-src/cli/init.ts +119 -7
  7. package/cli-src/cli/init_db.ts +144 -0
  8. package/cli-src/cli/init_permissions.ts +4 -6
  9. package/cli-src/cli/validate.ts +215 -0
  10. package/cli-src/lib/auth/hazo_get_auth.server.ts +2 -2
  11. package/cli-src/lib/auth/with_auth.server.ts +6 -0
  12. package/cli-src/lib/config/default_config.ts +13 -0
  13. package/cli-src/lib/constants.ts +15 -0
  14. package/cli-src/lib/cookies_config.edge.ts +15 -2
  15. package/cli-src/lib/cookies_config.server.ts +15 -6
  16. package/cli-src/lib/hazo_connect_setup.server.ts +33 -4
  17. package/cli-src/lib/multi_tenancy_config.server.ts +4 -71
  18. package/cli-src/lib/schema/sqlite_schema.ts +141 -0
  19. package/cli-src/lib/services/post_verification_service.ts +23 -0
  20. package/config/hazo_auth_config.example.ini +6 -5
  21. package/dist/cli/index.js +34 -2
  22. package/dist/cli/init.d.ts +1 -1
  23. package/dist/cli/init.d.ts.map +1 -1
  24. package/dist/cli/init.js +110 -7
  25. package/dist/cli/init_db.d.ts +2 -0
  26. package/dist/cli/init_db.d.ts.map +1 -0
  27. package/dist/cli/init_db.js +119 -0
  28. package/dist/cli/init_permissions.d.ts.map +1 -1
  29. package/dist/cli/init_permissions.js +5 -6
  30. package/dist/cli/validate.d.ts.map +1 -1
  31. package/dist/cli/validate.js +210 -4
  32. package/dist/client.d.ts +1 -0
  33. package/dist/client.d.ts.map +1 -1
  34. package/dist/client.js +2 -0
  35. package/dist/components/layouts/shared/components/visual_panel.d.ts.map +1 -1
  36. package/dist/components/layouts/shared/components/visual_panel.js +3 -1
  37. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  38. package/dist/components/layouts/user_management/index.js +3 -1
  39. package/dist/index.d.ts +1 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -0
  42. package/dist/lib/auth/hazo_get_auth.server.js +2 -2
  43. package/dist/lib/auth/with_auth.server.d.ts.map +1 -1
  44. package/dist/lib/auth/with_auth.server.js +6 -5
  45. package/dist/lib/config/default_config.d.ts +20 -0
  46. package/dist/lib/config/default_config.d.ts.map +1 -1
  47. package/dist/lib/config/default_config.js +12 -0
  48. package/dist/lib/constants.d.ts +11 -0
  49. package/dist/lib/constants.d.ts.map +1 -0
  50. package/dist/lib/constants.js +13 -0
  51. package/dist/lib/cookies_config.edge.d.ts +2 -1
  52. package/dist/lib/cookies_config.edge.d.ts.map +1 -1
  53. package/dist/lib/cookies_config.edge.js +11 -2
  54. package/dist/lib/cookies_config.server.d.ts +1 -1
  55. package/dist/lib/cookies_config.server.d.ts.map +1 -1
  56. package/dist/lib/cookies_config.server.js +12 -5
  57. package/dist/lib/hazo_connect_setup.server.d.ts.map +1 -1
  58. package/dist/lib/hazo_connect_setup.server.js +31 -4
  59. package/dist/lib/multi_tenancy_config.server.d.ts +7 -0
  60. package/dist/lib/multi_tenancy_config.server.d.ts.map +1 -0
  61. package/dist/lib/multi_tenancy_config.server.js +16 -0
  62. package/dist/lib/schema/sqlite_schema.d.ts +2 -0
  63. package/dist/lib/schema/sqlite_schema.d.ts.map +1 -0
  64. package/dist/lib/schema/sqlite_schema.js +140 -0
  65. package/dist/lib/services/post_verification_service.d.ts.map +1 -1
  66. package/dist/lib/services/post_verification_service.js +20 -0
  67. package/dist/page_components/index.d.ts.map +1 -1
  68. package/dist/server/middleware.d.ts +1 -1
  69. package/dist/server/middleware.d.ts.map +1 -1
  70. package/dist/server/routes/create_firm.d.ts +2 -2
  71. package/dist/server/routes/index.d.ts.map +1 -1
  72. package/dist/server/routes/invitations.d.ts +2 -2
  73. package/dist/server/routes/verify_email.d.ts +1 -1
  74. package/package.json +1 -1
package/README.md CHANGED
@@ -2,6 +2,38 @@
2
2
 
3
3
  A reusable authentication UI component package powered by Next.js, TailwindCSS, and shadcn. It integrates `hazo_config` for configuration management and `hazo_connect` for data access, enabling future components to stay aligned with platform conventions.
4
4
 
5
+ ### What's New in v5.1.28
6
+
7
+ **Schema Validation, Permission Constants & DX Improvements**
8
+
9
+ - **Schema validation** - `npx hazo_auth validate` now checks SQLite schema: required tables, TEXT ID types, `hazo_user_scopes` columns, admin permissions, and warns about v4 remnant tables
10
+ - **Permission constants** - New `HAZO_AUTH_PERMISSIONS` and `ALL_ADMIN_PERMISSIONS` exports from both `hazo_auth` and `hazo_auth/client` for programmatic permission checks
11
+ - **CLI fix** - CLI wrapper now sets `--conditions react-server` in NODE_OPTIONS, fixing "server-only" import errors when running `npx hazo_auth validate`, `init-permissions`, etc.
12
+ - **Silent permission fix** - `hazo_get_auth` now applies `String()` normalization to role_id/permission_id comparisons, fixing empty permissions when SQLite returns INTEGER IDs
13
+ - **DB-generated IDs** - `init-permissions` no longer generates UUIDs client-side; lets the database generate IDs (supports both TEXT UUID and INTEGER PK schemas)
14
+ - **Dev debug info** - `withAuth` 403 responses and `UserManagementLayout` "Access Denied" view now include permission debug details in development mode
15
+ - **Import cleanup** - Removed `.js` extensions from internal imports for better TypeScript/bundler compatibility
16
+
17
+ ### What's New in v5.1.27
18
+
19
+ **Mandatory Cookie Prefix** - `cookie_prefix` is now required for all consuming apps.
20
+
21
+ - **Breaking:** `get_cookies_config()` throws if `cookie_prefix` is not set in `[hazo_auth__cookies]` config section
22
+ - **Breaking:** `get_cookie_prefix_edge()` throws if `HAZO_AUTH_COOKIE_PREFIX` env var is not set
23
+ - **Validation:** `npx hazo_auth validate` now checks for cookie_prefix configuration
24
+ - **Init:** `.env.local.example` template includes `HAZO_AUTH_COOKIE_PREFIX` as required
25
+ - **Docs:** shadcn/ui components are bundled — consumers do NOT need to install them separately
26
+
27
+ ### What's New in v5.1.26
28
+
29
+ **Consumer Setup Improvements** - Five fixes that improve the out-of-box experience for new consumers:
30
+
31
+ - **Multi-tenancy bypass** - `enable_multi_tenancy = false` (the default) now correctly skips scope/invitation checks in OAuth and post-verification flows. No more redirect loops to `/hazo_auth/create_firm` for simple apps.
32
+ - **Clear SQLite errors** - Missing `sqlite_path` in config now throws a clear error instead of silently falling back to a test fixture database. Unrecognized config keys produce warnings with typo suggestions.
33
+ - **Auto-schema creation** - `npx hazo_auth init` now creates the SQLite database with all required tables automatically. Also available standalone via `npx hazo_auth init-db`. Use `npx hazo_auth schema` to print the canonical SQL.
34
+ - **Auth page images** - `npx hazo_auth init` now copies default login/register/forgot-password images to `public/hazo_auth/images/`.
35
+ - **Graceful image fallback** - Visual panels on auth pages fall back to a colored background instead of crashing when images are missing.
36
+
5
37
  ### What's New in v5.2.0 ⚠️ BREAKING CHANGE
6
38
 
7
39
  **Server/Client Module Separation** - Complete fix for "Module not found: Can't resolve 'fs'" errors.
@@ -117,9 +149,12 @@ See [CHANGE_LOG.md](./CHANGE_LOG.md) for detailed migration guide, rationale, an
117
149
  ## Installation
118
150
 
119
151
  ```bash
120
- npm install hazo_auth
152
+ # Install hazo_auth and required peer dependencies
153
+ npm install hazo_auth hazo_config hazo_connect hazo_logs
121
154
  ```
122
155
 
156
+ **Note:** `hazo_config`, `hazo_connect`, and `hazo_logs` are required peer dependencies.
157
+
123
158
  ---
124
159
 
125
160
  ## Quick Start
@@ -127,20 +162,31 @@ npm install hazo_auth
127
162
  The fastest way to get started is using the CLI commands:
128
163
 
129
164
  ```bash
130
- # 1. Install the package
131
- npm install hazo_auth
165
+ # 1. Install the package and peer dependencies
166
+ npm install hazo_auth hazo_config hazo_connect hazo_logs
132
167
 
133
- # 2. Initialize your project (creates directories, copies config files)
168
+ # 2. Initialize your project (directories, config, database, images)
134
169
  npx hazo_auth init
135
170
 
136
- # 3. Generate API routes and pages
137
- npx hazo_auth generate-routes --pages
171
+ # 3. Configure cookie prefix (REQUIRED)
172
+ # Edit config/hazo_auth_config.ini and set a unique prefix:
173
+ # [hazo_auth__cookies]
174
+ # cookie_prefix = myapp_
138
175
 
139
176
  # 4. Set up environment variables
140
177
  cp .env.local.example .env.local
141
- # Edit .env.local and add your ZEPTOMAIL_API_KEY
178
+ # Edit .env.local and set:
179
+ # HAZO_AUTH_COOKIE_PREFIX=myapp_ (MUST match cookie_prefix above)
180
+ # JWT_SECRET=<your-secret>
181
+ # ZEPTOMAIL_API_KEY=<your-key>
182
+
183
+ # 5. Initialize default permissions and roles
184
+ npx hazo_auth init-users
142
185
 
143
- # 5. Start your dev server
186
+ # 6. Generate API routes and pages
187
+ npx hazo_auth generate-routes --pages
188
+
189
+ # 7. Start your dev server
144
190
  npm run dev
145
191
  ```
146
192
 
@@ -309,22 +355,14 @@ import { hazo_get_auth } from "hazo_auth/lib/auth/hazo_get_auth.server";
309
355
 
310
356
  ## Required Dependencies
311
357
 
312
- **Note:** The `jose` package is now included as a dependency for Edge-compatible JWT operations. This is automatically installed when you run `npm install hazo_auth`.
313
-
314
- hazo_auth uses shadcn/ui components. Install the required dependencies in your project:
315
-
358
+ **Peer Dependencies (Required):**
316
359
  ```bash
317
- # Required for all auth pages
318
- npx shadcn@latest add button input label
319
-
320
- # Required for My Settings page
321
- npx shadcn@latest add dialog tabs switch avatar dropdown-menu
322
-
323
- # Required for toast notifications
324
- npx shadcn@latest add sonner
360
+ npm install hazo_config hazo_connect hazo_logs
325
361
  ```
326
362
 
327
- **Add Toaster to your app layout:**
363
+ **UI Components:** All shadcn/ui components are bundled with hazo_auth. You do NOT need to install them separately.
364
+
365
+ **Toast Notifications:** Add the Toaster component to your app layout:
328
366
 
329
367
  ```tsx
330
368
  // app/layout.tsx
@@ -10,24 +10,35 @@ The fastest way to set up hazo_auth:
10
10
  # 1. Install the package and peer dependencies
11
11
  npm install hazo_auth hazo_config hazo_connect hazo_logs
12
12
 
13
- # 2. Initialize project (creates directories, copies config files)
13
+ # 2. Initialize project (creates directories, config files, database, images)
14
14
  npx hazo_auth init
15
15
 
16
- # 3. Generate API routes and pages
17
- npx hazo_auth generate-routes --pages
16
+ # 3. Configure cookie prefix (REQUIRED)
17
+ # Edit config/hazo_auth_config.ini and set a unique prefix:
18
+ # [hazo_auth__cookies]
19
+ # cookie_prefix = myapp_
18
20
 
19
21
  # 4. Set up environment variables
20
22
  cp .env.local.example .env.local
21
- # Edit .env.local and add ZEPTOMAIL_API_KEY and JWT_SECRET
23
+ # Edit .env.local and set:
24
+ # HAZO_AUTH_COOKIE_PREFIX=myapp_ (MUST match cookie_prefix above)
25
+ # JWT_SECRET=<generate with: openssl rand -base64 32>
26
+ # ZEPTOMAIL_API_KEY=your_key_here
27
+
28
+ # 5. Initialize default permissions and roles
29
+ npx hazo_auth init-users
22
30
 
23
- # 5. Configure navbar logo and company name (IMPORTANT)
24
- # Edit hazo_auth_config.ini and set:
31
+ # 6. Generate API routes and pages
32
+ npx hazo_auth generate-routes --pages
33
+
34
+ # 7. Configure navbar logo and company name (IMPORTANT)
35
+ # Edit config/hazo_auth_config.ini and set:
25
36
  # [hazo_auth__navbar]
26
37
  # logo_path = /logo.png
27
38
  # company_name = My Company
28
39
  # Note: Copy your logo to public/logo.png
29
40
 
30
- # 6. Start dev server and test
41
+ # 8. Start dev server and test
31
42
  npm run dev
32
43
  # Visit http://localhost:3000/hazo_auth/login
33
44
  ```
@@ -69,26 +80,11 @@ ls node_modules/hazo_auth/package.json
69
80
  # Expected: file exists
70
81
  ```
71
82
 
72
- ### Step 1.2: Install Required shadcn/ui Components
73
-
74
- hazo_auth uses shadcn/ui components. Install the required dependencies:
75
-
76
- **For all auth pages (login, register, etc.):**
77
- ```bash
78
- npx shadcn@latest add button input label
79
- ```
80
-
81
- **For My Settings page:**
82
- ```bash
83
- npx shadcn@latest add dialog tabs switch avatar dropdown-menu
84
- ```
83
+ ### Step 1.2: Add Toast Notifications
85
84
 
86
- **For toast notifications:**
87
- ```bash
88
- npx shadcn@latest add sonner
89
- ```
85
+ All shadcn/ui components are bundled with hazo_auth — you do NOT need to install them separately.
90
86
 
91
- **Add Toaster to your app layout:**
87
+ **Add Toaster to your app layout** (required for toast notifications):
92
88
 
93
89
  Edit `app/layout.tsx` and add the Toaster component:
94
90
 
@@ -178,7 +174,18 @@ This command:
178
174
  - Creates `data/` directory (for SQLite database)
179
175
  - Copies `hazo_auth_config.ini` and `hazo_notify_config.ini`
180
176
  - Copies profile picture library images
177
+ - Copies default auth page images (login, register, forgot password, etc.)
181
178
  - Creates `.env.local.example` template
179
+ - Creates SQLite database with all required tables (if `better-sqlite3` is installed)
180
+
181
+ **Additional CLI commands:**
182
+ ```bash
183
+ # Create/recreate SQLite database with schema (standalone)
184
+ npx hazo_auth init-db
185
+
186
+ # Print the canonical SQLite schema SQL
187
+ npx hazo_auth schema
188
+ ```
182
189
 
183
190
  ### Step 1.2b: Manual config setup (Alternative)
184
191
 
@@ -238,18 +245,20 @@ layout_mode = standalone
238
245
  Create `.env.local` in your project root:
239
246
 
240
247
  ```env
248
+ # REQUIRED: Cookie prefix (MUST match cookie_prefix in hazo_auth_config.ini)
249
+ # Each app using hazo_auth needs a unique prefix to prevent cookie conflicts
250
+ HAZO_AUTH_COOKIE_PREFIX=myapp_
251
+
252
+ # Required for JWT authentication
253
+ JWT_SECRET=your_secure_random_string_at_least_32_characters
254
+
241
255
  # Required for email functionality (Zeptomail)
242
256
  ZEPTOMAIL_API_KEY=your_zeptomail_api_key_here
243
257
 
244
258
  # Required for PostgreSQL/PostgREST (if using)
245
259
  HAZO_CONNECT_POSTGREST_API_KEY=your_postgrest_api_key_here
246
260
 
247
- # Required for JWT authentication
248
- JWT_SECRET=your_secure_random_string_at_least_32_characters
249
- # Note: JWT_SECRET is required for JWT session token functionality (Edge-compatible proxy/middleware authentication)
250
-
251
- # Optional: Cookie customization (prevents conflicts when running multiple apps)
252
- HAZO_AUTH_COOKIE_PREFIX=myapp_
261
+ # Optional: Cookie domain (for cross-subdomain sharing)
253
262
  HAZO_AUTH_COOKIE_DOMAIN=
254
263
  ```
255
264
 
@@ -258,17 +267,25 @@ HAZO_AUTH_COOKIE_DOMAIN=
258
267
  openssl rand -base64 32
259
268
  ```
260
269
 
261
- **Cookie Customization (Optional):**
262
- If you're running multiple apps that use hazo_auth on localhost (different ports), set `HAZO_AUTH_COOKIE_PREFIX` to prevent cookie conflicts. For example:
263
- - App 1 (port 3000): `HAZO_AUTH_COOKIE_PREFIX=app1_`
264
- - App 2 (port 3001): `HAZO_AUTH_COOKIE_PREFIX=app2_`
270
+ **Cookie Prefix (REQUIRED):**
271
+ Every app using hazo_auth MUST set a unique cookie prefix. This prevents cookie conflicts between apps. The value must be set in TWO places:
265
272
 
266
- Also configure in `hazo_auth_config.ini`:
267
- ```ini
268
- [hazo_auth__cookies]
269
- cookie_prefix = myapp_
270
- cookie_domain =
271
- ```
273
+ 1. **Config file** (`config/hazo_auth_config.ini`):
274
+ ```ini
275
+ [hazo_auth__cookies]
276
+ cookie_prefix = myapp_
277
+ ```
278
+
279
+ 2. **Environment variable** (`.env.local`):
280
+ ```env
281
+ HAZO_AUTH_COOKIE_PREFIX=myapp_
282
+ ```
283
+
284
+ Both values MUST match. The env var is needed because Edge runtime (middleware/proxy) cannot read config files.
285
+
286
+ **Examples for multiple apps:**
287
+ - App 1 (port 3000): `cookie_prefix = app1_` / `HAZO_AUTH_COOKIE_PREFIX=app1_`
288
+ - App 2 (port 3001): `cookie_prefix = app2_` / `HAZO_AUTH_COOKIE_PREFIX=app2_`
272
289
 
273
290
  ### Step 2.2: Configure email settings
274
291
 
@@ -282,8 +299,9 @@ from_name = Your App Name
282
299
 
283
300
  **Checklist:**
284
301
  - [ ] `.env.local` file created
302
+ - [ ] `HAZO_AUTH_COOKIE_PREFIX` set (REQUIRED - must match config file)
303
+ - [ ] `JWT_SECRET` set (required for JWT session tokens)
285
304
  - [ ] `ZEPTOMAIL_API_KEY` set (or email will not work)
286
- - [ ] `JWT_SECRET` set (required for JWT session tokens - Edge-compatible proxy/middleware authentication)
287
305
  - [ ] `from_email` configured in `hazo_notify_config.ini`
288
306
 
289
307
  ---
@@ -1108,20 +1126,23 @@ If you prefer a simpler approach without JWT validation:
1108
1126
  import { NextResponse } from "next/server";
1109
1127
  import type { NextRequest } from "next/server";
1110
1128
 
1129
+ // Cookie prefix must match HAZO_AUTH_COOKIE_PREFIX env var
1130
+ const COOKIE_PREFIX = process.env.HAZO_AUTH_COOKIE_PREFIX || "";
1131
+
1111
1132
  export async function proxy(request: NextRequest) {
1112
1133
  const { pathname } = request.nextUrl;
1113
-
1134
+
1114
1135
  if (pathname.startsWith("/members")) {
1115
- const user_id = request.cookies.get("hazo_auth_user_id")?.value;
1116
- const user_email = request.cookies.get("hazo_auth_user_email")?.value;
1117
-
1136
+ const user_id = request.cookies.get(`${COOKIE_PREFIX}hazo_auth_user_id`)?.value;
1137
+ const user_email = request.cookies.get(`${COOKIE_PREFIX}hazo_auth_user_email`)?.value;
1138
+
1118
1139
  if (!user_id || !user_email) {
1119
1140
  const login_url = new URL("/hazo_auth/login", request.url);
1120
1141
  login_url.searchParams.set("redirect", pathname);
1121
1142
  return NextResponse.redirect(login_url);
1122
1143
  }
1123
1144
  }
1124
-
1145
+
1125
1146
  return NextResponse.next();
1126
1147
  }
1127
1148
  ```
@@ -1944,14 +1965,104 @@ curl -H "Cookie: hazo_auth_session=YOUR_TOKEN; hazo_auth_scope_id=SCOPE_UUID" \
1944
1965
 
1945
1966
  **Note:** By default, `logo_path` and `company_name` are empty strings, so nothing displays until you configure them.
1946
1967
 
1968
+ ### Issue: Migrating from v4 to v5 schema
1969
+
1970
+ **Symptoms:** Permissions resolve to `[]`, "Access Denied" on all admin pages, 403 responses from withAuth, despite user having roles assigned.
1971
+
1972
+ **Cause:** v5 replaced `hazo_user_roles` with `hazo_user_scopes` (scope-based role assignments) and requires several new tables. If your database still has v4 schema, the permission lookup finds no role assignments.
1973
+
1974
+ **Key schema differences (v4 vs v5):**
1975
+ - `hazo_user_roles` replaced by `hazo_user_scopes` (with `root_scope_id` and `role_id` columns)
1976
+ - `hazo_org` replaced by `hazo_scopes` (unified hierarchical scope model)
1977
+ - All ID columns must be TEXT (UUID), not INTEGER
1978
+ - `hazo_role_permissions` uses composite PK `(role_id, permission_id)` with no `id` column
1979
+
1980
+ **Solution:**
1981
+ 1. Run `npx hazo_auth validate` to identify schema issues
1982
+ 2. Run migration 009: `npm run migrate migrations/009_scope_consolidation.sql`
1983
+ 3. Migrate existing role assignments:
1984
+ ```sql
1985
+ -- Example: migrate hazo_user_roles data to hazo_user_scopes
1986
+ INSERT INTO hazo_user_scopes (user_id, scope_id, root_scope_id, role_id, status)
1987
+ SELECT
1988
+ ur.user_id,
1989
+ '00000000-0000-0000-0000-000000000001', -- default system scope
1990
+ '00000000-0000-0000-0000-000000000001', -- default system scope
1991
+ ur.role_id,
1992
+ 'ACTIVE'
1993
+ FROM hazo_user_roles ur;
1994
+ ```
1995
+ 4. Run `npx hazo_auth init-permissions` to ensure all admin permissions exist
1996
+
1997
+ ### Issue: Understanding permission configuration
1998
+
1999
+ **Symptoms:** Confusion about which config sections control permissions and how they relate.
2000
+
2001
+ **Explanation:** Permissions are configured in three related places:
2002
+
2003
+ 1. **`[hazo_auth__app_permissions]`** - Declares app-level permission names with descriptions (for documentation/UI display):
2004
+ ```ini
2005
+ app_permission_1 = can_view_reports:View analytical reports
2006
+ app_permission_2 = can_export_data:Export data to CSV
2007
+ ```
2008
+
2009
+ 2. **`[hazo_auth__user_management] application_permission_list_defaults`** - Comma-separated list of permission names to create in the DB when running `npx hazo_auth init-permissions`:
2010
+ ```ini
2011
+ application_permission_list_defaults = admin_user_management,admin_role_management,admin_permission_management,can_view_reports,can_export_data
2012
+ ```
2013
+
2014
+ 3. **Built-in admin permissions** (required by `UserManagementLayout` component): `admin_user_management`, `admin_role_management`, `admin_permission_management`, `admin_scope_hierarchy_management`, `admin_user_scope_assignment`, `admin_system`, `admin_test_access`. These are available programmatically via:
2015
+ ```typescript
2016
+ import { HAZO_AUTH_PERMISSIONS, ALL_ADMIN_PERMISSIONS } from "hazo_auth/client";
2017
+ ```
2018
+
2019
+ ### Issue: Database ID type mismatches (silent permission failures)
2020
+
2021
+ **Symptoms:** User is authenticated but permissions array is always empty. No errors in console. `hazo_get_auth` returns `permissions: []` even though roles and permissions exist in the database.
2022
+
2023
+ **Cause:** SQLite drivers may return numeric values for columns defined as `INTEGER PRIMARY KEY`. v5 uses strict string comparison for role_id and permission_id matching. If the DB returns `role_id: 1` (number) but the code expects `"1"` (string), the comparison fails silently.
2024
+
2025
+ **Solutions:**
2026
+ 1. **Ensure all ID columns are TEXT type** in your schema. v5 requires TEXT (UUID) IDs:
2027
+ ```sql
2028
+ -- CORRECT (v5)
2029
+ CREATE TABLE hazo_roles (id TEXT PRIMARY KEY, ...);
2030
+
2031
+ -- WRONG (v4 legacy)
2032
+ CREATE TABLE hazo_roles (id INTEGER PRIMARY KEY, ...);
2033
+ ```
2034
+ 2. Run `npx hazo_auth validate` — the schema check will flag INTEGER ID columns
2035
+ 3. If you cannot change the schema, v5.1.28+ applies `String()` normalization to role_id and permission_id comparisons, which handles mixed types
2036
+
2037
+ **Note for PostgreSQL users:** PostgREST typically returns UUID values as strings, so this issue primarily affects SQLite with INTEGER PKs.
2038
+
2039
+ ### Issue: CLI commands fail with "server-only" import error
2040
+
2041
+ **Symptoms:** Running `npx hazo_auth validate`, `npx hazo_auth init-permissions`, etc. throws:
2042
+ ```
2043
+ Error: This module cannot be imported from a Client Component module.
2044
+ It should only be used from a Server Component.
2045
+ ```
2046
+
2047
+ **Cause:** The `server-only` package throws when imported outside a React Server Component context. CLI commands run in plain Node.js.
2048
+
2049
+ **Solution (v5.1.28+):** Fixed automatically — the CLI wrapper now sets `--conditions react-server` in NODE_OPTIONS.
2050
+
2051
+ **Workaround for older versions:** Set the condition manually:
2052
+ ```bash
2053
+ NODE_OPTIONS='--conditions react-server' npx hazo_auth validate
2054
+ ```
2055
+
1947
2056
  ---
1948
2057
 
1949
2058
  ## Final Checklist
1950
2059
 
1951
2060
  **Configuration:**
1952
2061
  - [ ] `hazo_auth_config.ini` configured
2062
+ - [ ] `cookie_prefix` set in `[hazo_auth__cookies]` section (REQUIRED)
2063
+ - [ ] `HAZO_AUTH_COOKIE_PREFIX` env var matches `cookie_prefix` (REQUIRED)
1953
2064
  - [ ] `hazo_notify_config.ini` configured
1954
- - [ ] `.env.local` with all required variables (ZEPTOMAIL_API_KEY, JWT_SECRET)
2065
+ - [ ] `.env.local` with all required variables (HAZO_AUTH_COOKIE_PREFIX, JWT_SECRET, ZEPTOMAIL_API_KEY)
1955
2066
  - [ ] Navbar configured with logo and company name (see Step 1.4)
1956
2067
 
1957
2068
  **Database:**
package/bin/hazo_auth.mjs CHANGED
@@ -18,10 +18,17 @@ const args = process.argv.slice(2);
18
18
  // Use tsx to run the TypeScript source directly
19
19
  // This avoids ESM module resolution issues with compiled JS
20
20
  // tsx is a dependency of hazo_auth so it should be available
21
+ const existingNodeOptions = process.env.NODE_OPTIONS || '';
22
+ const reactServerCondition = '--conditions react-server';
23
+ const nodeOptions = existingNodeOptions.includes(reactServerCondition)
24
+ ? existingNodeOptions
25
+ : `${existingNodeOptions} ${reactServerCondition}`.trim();
26
+
21
27
  const child = spawn('npx', ['tsx', cliPath, ...args], {
22
28
  stdio: 'inherit',
23
29
  cwd: process.cwd(),
24
- shell: true
30
+ shell: true,
31
+ env: { ...process.env, NODE_OPTIONS: nodeOptions },
25
32
  });
26
33
 
27
34
  child.on('exit', (code) => {
@@ -7,6 +7,7 @@ import { run_validation } from "./validate.js";
7
7
  import { generate_routes, type GenerateOptions } from "./generate.js";
8
8
  import { handle_init } from "./init.js";
9
9
  import { handle_init_users, show_init_users_help } from "./init_users.js";
10
+ import { handle_init_db } from "./init_db.js";
10
11
  import { handle_init_permissions, show_init_permissions_help } from "./init_permissions.js";
11
12
 
12
13
  // section: constants
@@ -18,11 +19,13 @@ const HELP_TEXT = `
18
19
  Usage: hazo_auth <command> [options]
19
20
 
20
21
  Commands:
21
- init Initialize hazo_auth in your project (creates directories, copies config)
22
+ init Initialize hazo_auth in your project (creates directories, copies config, DB)
23
+ init-db Create SQLite database with hazo_auth schema (standalone)
22
24
  init-permissions Create default permissions from config (no user required)
23
25
  init-users Initialize permissions, roles, and super user from config
24
26
  validate Check your hazo_auth setup and configuration
25
27
  generate-routes Generate API route files and pages in your project
28
+ schema Print the canonical SQLite schema SQL
26
29
 
27
30
  Options:
28
31
  --help, -h Show this help message
@@ -30,12 +33,14 @@ Options:
30
33
 
31
34
  Examples:
32
35
  npx hazo_auth init
36
+ npx hazo_auth init-db
33
37
  npx hazo_auth init-permissions
34
38
  npx hazo_auth init-users
35
39
  npx hazo_auth validate
36
40
  npx hazo_auth generate-routes
37
41
  npx hazo_auth generate-routes --pages
38
42
  npx hazo_auth generate-routes --all --dir=src/app
43
+ npx hazo_auth schema
39
44
 
40
45
  Documentation:
41
46
  https://github.com/your-repo/hazo_auth/blob/main/SETUP_CHECKLIST.md
@@ -150,13 +155,42 @@ Actions:
150
155
  - Creates data/ directory (for SQLite)
151
156
  - Copies hazo_auth_config.ini and hazo_notify_config.ini
152
157
  - Copies profile picture library images
158
+ - Copies default auth page images (login, register, etc.)
153
159
  - Creates .env.local.example template
160
+ - Creates SQLite database with schema (if better-sqlite3 is installed)
154
161
  `);
155
162
  return;
156
163
  }
157
- handle_init();
164
+ await handle_init();
158
165
  break;
159
166
 
167
+ case "init-db":
168
+ if (help) {
169
+ console.log(`
170
+ hazo_auth init-db
171
+
172
+ Create SQLite database with the hazo_auth schema.
173
+
174
+ This command:
175
+ - Reads sqlite_path from config/hazo_auth_config.ini (default: ./data/hazo_auth.sqlite)
176
+ - Creates the database file if it doesn't exist
177
+ - Creates all required tables (hazo_users, hazo_roles, hazo_scopes, etc.)
178
+ - Skips if tables already exist
179
+
180
+ Requires: better-sqlite3 (npm install better-sqlite3)
181
+ `);
182
+ return;
183
+ }
184
+ handle_init_db();
185
+ break;
186
+
187
+ case "schema": {
188
+ // Dynamic import to avoid bundling the schema in the main CLI entry
189
+ const { SQLITE_SCHEMA } = await import("../lib/schema/sqlite_schema.js");
190
+ console.log(SQLITE_SCHEMA);
191
+ break;
192
+ }
193
+
160
194
  case "init-permissions": {
161
195
  if (help) {
162
196
  show_init_permissions_help();