hazo_auth 5.1.40 → 5.3.0
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/SETUP_CHECKLIST.md +46 -0
- package/cli-src/lib/auth/ensure_anon_id.server.ts +88 -0
- package/cli-src/lib/auth/index.ts +3 -0
- package/cli-src/lib/cookies_config.edge.ts +1 -0
- package/cli-src/lib/cookies_config.server.ts +1 -0
- package/cli-src/lib/hazo_connect_setup.server.ts +0 -8
- package/cli-src/lib/services/email_service.ts +136 -289
- package/cli-src/lib/services/email_template_manifest.ts +104 -0
- package/cli-src/lib/services/email_templates/email_verification.html +18 -0
- package/cli-src/lib/services/email_templates/email_verification.txt +9 -0
- package/cli-src/lib/services/email_templates/forgot_password.html +18 -0
- package/cli-src/lib/services/email_templates/forgot_password.txt +9 -0
- package/cli-src/lib/services/email_templates/password_changed.html +14 -0
- package/cli-src/lib/services/email_templates/password_changed.txt +9 -0
- package/cli-src/lib/services/session_token_service.ts +2 -2
- package/cli-src/lib/ui_shell_config.server.ts +6 -2
- package/dist/components/layouts/login/index.d.ts +16 -3
- package/dist/components/layouts/login/index.d.ts.map +1 -1
- package/dist/components/layouts/login/index.js +49 -5
- package/dist/components/layouts/register/index.d.ts +7 -3
- package/dist/components/layouts/register/index.d.ts.map +1 -1
- package/dist/components/layouts/register/index.js +36 -3
- package/dist/components/layouts/shared/components/floating_home_link.d.ts +20 -0
- package/dist/components/layouts/shared/components/floating_home_link.d.ts.map +1 -0
- package/dist/components/layouts/shared/components/floating_home_link.js +29 -0
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts +8 -0
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.js +18 -8
- package/dist/components/layouts/shared/index.d.ts +2 -0
- package/dist/components/layouts/shared/index.d.ts.map +1 -1
- package/dist/components/layouts/shared/index.js +1 -0
- package/dist/lib/auth/ensure_anon_id.server.d.ts +21 -0
- package/dist/lib/auth/ensure_anon_id.server.d.ts.map +1 -0
- package/dist/lib/auth/ensure_anon_id.server.js +73 -0
- package/dist/lib/auth/index.d.ts +1 -0
- package/dist/lib/auth/index.d.ts.map +1 -1
- package/dist/lib/auth/index.js +2 -0
- package/dist/lib/cookies_config.edge.d.ts +1 -0
- package/dist/lib/cookies_config.edge.d.ts.map +1 -1
- package/dist/lib/cookies_config.edge.js +1 -0
- package/dist/lib/cookies_config.server.d.ts +1 -0
- package/dist/lib/cookies_config.server.d.ts.map +1 -1
- package/dist/lib/cookies_config.server.js +1 -0
- package/dist/lib/hazo_connect_setup.server.d.ts.map +1 -1
- package/dist/lib/hazo_connect_setup.server.js +0 -8
- package/dist/lib/services/email_service.d.ts +17 -4
- package/dist/lib/services/email_service.d.ts.map +1 -1
- package/dist/lib/services/email_service.js +93 -221
- package/dist/lib/services/email_template_manifest.d.ts +11 -0
- package/dist/lib/services/email_template_manifest.d.ts.map +1 -0
- package/dist/lib/services/email_template_manifest.js +95 -0
- package/dist/lib/services/email_templates/email_verification.html +18 -0
- package/dist/lib/services/email_templates/email_verification.txt +9 -0
- package/dist/lib/services/email_templates/forgot_password.html +18 -0
- package/dist/lib/services/email_templates/forgot_password.txt +9 -0
- package/dist/lib/services/email_templates/password_changed.html +14 -0
- package/dist/lib/services/email_templates/password_changed.txt +9 -0
- package/dist/lib/services/session_token_service.js +2 -2
- package/dist/lib/ui_shell_config.server.d.ts.map +1 -1
- package/dist/lib/ui_shell_config.server.js +6 -2
- package/dist/server/routes/oauth_google_callback.d.ts.map +1 -1
- package/dist/server/routes/oauth_google_callback.js +33 -6
- package/dist/server-lib.d.ts +1 -0
- package/dist/server-lib.d.ts.map +1 -1
- package/dist/server-lib.js +1 -0
- package/dist/server_pages/login.d.ts +13 -1
- package/dist/server_pages/login.d.ts.map +1 -1
- package/dist/server_pages/login.js +25 -9
- package/dist/server_pages/login_client_wrapper.d.ts +6 -4
- package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/login_client_wrapper.js +2 -2
- package/dist/server_pages/register.d.ts +7 -1
- package/dist/server_pages/register.d.ts.map +1 -1
- package/dist/server_pages/register.js +18 -9
- package/dist/server_pages/register_client_wrapper.d.ts +6 -4
- package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
- package/dist/server_pages/register_client_wrapper.js +2 -2
- package/package.json +26 -20
- package/cli-src/assets/images/new_firm_default.jpg +0 -0
- package/cli-src/lib/auth/org_cache.ts +0 -148
- package/cli-src/lib/index.ts +0 -48
- package/cli-src/lib/services/org_service.ts +0 -965
- package/cli-src/lib/services/scope_labels_service.ts +0 -348
package/SETUP_CHECKLIST.md
CHANGED
|
@@ -2,6 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
This checklist provides step-by-step instructions for setting up the `hazo_auth` package in your Next.js project. AI assistants can follow this guide to ensure complete and correct setup.
|
|
4
4
|
|
|
5
|
+
## v5.3.0 Migration (from v5.2.x)
|
|
6
|
+
|
|
7
|
+
If you are already on hazo_auth `5.2.x`, the only mandatory work is wiring up hazo_notify's template manager at boot. Apps that don't use the templated email path (only the plain `send_email`) keep working unchanged after bumping the peer dep.
|
|
8
|
+
|
|
9
|
+
**1. Bump the peer dep.** Update your app's `package.json`:
|
|
10
|
+
|
|
11
|
+
```diff
|
|
12
|
+
- "hazo_notify": "^1.1.0",
|
|
13
|
+
+ "hazo_notify": "^3.0.0",
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then `npm install`.
|
|
17
|
+
|
|
18
|
+
**2. Apply the hazo_notify template-manager migration.** hazo_notify 3.0.0 introduces two new tables (`hazo_notify_template_cat`, `hazo_notify_templates`). If you are using SQLite via the existing schema seed, the tables are created on first connect when `initial_sql` is provided to the adapter (see step 4 below). If you are on PostgREST or you manage migrations explicitly, run `migrations/002_template_manager.sql` from hazo_notify.
|
|
19
|
+
|
|
20
|
+
**3. Register the `notify_templates_admin` permission (optional).** Users with this permission can edit auth email templates via the hazo_notify admin UI. Grant `notify_templates_super_admin` to also allow deleting system templates. These are hazo_notify permissions, declared in your app's permission set; hazo_auth does not grant them itself.
|
|
21
|
+
|
|
22
|
+
**4. Wire up `init_template_manager` and `set_hazo_notify_connect` at boot.** In your Next.js `instrumentation.ts` (or equivalent), feed hazo_auth's manifest into hazo_notify and register the connect instance with hazo_auth:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// instrumentation.ts
|
|
26
|
+
import { init_template_manager } from "hazo_notify/template_manager";
|
|
27
|
+
import { hazo_auth_template_manifest } from "hazo_auth/server-lib";
|
|
28
|
+
import { set_hazo_notify_connect } from "hazo_auth/server-lib"; // re-exported from email_service
|
|
29
|
+
import { build_my_hazo_notify_connect } from "./lib/hazo_notify_connect";
|
|
30
|
+
|
|
31
|
+
export async function register() {
|
|
32
|
+
if (process.env.NEXT_RUNTIME !== "nodejs") return;
|
|
33
|
+
|
|
34
|
+
const notify_connect = build_my_hazo_notify_connect();
|
|
35
|
+
|
|
36
|
+
await init_template_manager({
|
|
37
|
+
hazo_connect_factory: () => notify_connect,
|
|
38
|
+
manifests: [...hazo_auth_template_manifest],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
set_hazo_notify_connect(notify_connect);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`build_my_hazo_notify_connect()` is consuming-app code that wraps your `hazo_connect` adapter into the `HazoConnectInstance` shape hazo_notify expects (`list`/`findById`/`findBy`/`insert`/`updateById`/`deleteById`/`query`). hazo_auth's own test-app ships an example wrapper at `instrumentation_hazo_notify_connect.ts` you can copy.
|
|
46
|
+
|
|
47
|
+
**5. Migrate any custom templates.** The `[hazo_auth__email] email_template_main_directory` config key is deprecated and no longer overrides anything — a one-time `warn` log will fire on first send if it is set. Move any custom HTML/text into the admin UI as scope-specific (or super-admin-edited global) templates before `hazo_auth@6.0.0` removes the key.
|
|
48
|
+
|
|
49
|
+
**6. (Optional) Mount the template admin UI.** Use `<TemplateManagerAdmin />` from `hazo_notify/template_manager_admin` to give your admins a UI for managing the auth templates. See hazo_notify's docs for routing and permission-gating.
|
|
50
|
+
|
|
5
51
|
## Quick Start (Recommended)
|
|
6
52
|
|
|
7
53
|
The fastest way to set up hazo_auth:
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// file_description: server-only helper to issue/read a stable opaque anonymous visitor ID via httpOnly cookie
|
|
2
|
+
//
|
|
3
|
+
// Used by hazo_feedback (and any future caller) to group submissions from the
|
|
4
|
+
// same anonymous visitor across page loads / weeks without requiring login.
|
|
5
|
+
//
|
|
6
|
+
// Signature choice (v5.2.0): async, request-only — Option A in the design doc.
|
|
7
|
+
// - Reads the existing cookie from the incoming `request.cookies`.
|
|
8
|
+
// - Writes a freshly-issued cookie via the async `cookies()` API from
|
|
9
|
+
// `next/headers`, which is the supported write surface in Server Components,
|
|
10
|
+
// Server Actions, and Route Handlers in Next.js 15+.
|
|
11
|
+
// - Tradeoff: NOT valid in Edge middleware (where `next/headers` throws). If a
|
|
12
|
+
// middleware caller ever needs this, add a sibling `ensure_anon_id_edge`
|
|
13
|
+
// that takes (request, response) and writes via `response.cookies.set`.
|
|
14
|
+
//
|
|
15
|
+
// Idempotent per-request: a per-request WeakMap remembers which id was issued
|
|
16
|
+
// for a given NextRequest instance, so calling `ensure_anon_id(request)` twice
|
|
17
|
+
// in the same request returns the same id and queues only one Set-Cookie. This
|
|
18
|
+
// matters because `request.cookies` reflects the *incoming* state and won't
|
|
19
|
+
// see an id that the same request just issued.
|
|
20
|
+
|
|
21
|
+
// section: server-only-guard
|
|
22
|
+
import "server-only";
|
|
23
|
+
|
|
24
|
+
// section: imports
|
|
25
|
+
import { NextRequest } from "next/server";
|
|
26
|
+
import { cookies } from "next/headers";
|
|
27
|
+
import {
|
|
28
|
+
BASE_COOKIE_NAMES,
|
|
29
|
+
get_cookie_name,
|
|
30
|
+
get_cookie_options,
|
|
31
|
+
} from "../cookies_config.server.js";
|
|
32
|
+
|
|
33
|
+
// section: constants
|
|
34
|
+
const TWO_YEARS_SECONDS = 60 * 60 * 24 * 365 * 2;
|
|
35
|
+
|
|
36
|
+
// section: state
|
|
37
|
+
// WeakMap keyed by NextRequest so entries are GC'd with the request.
|
|
38
|
+
const issued_per_request: WeakMap<NextRequest, string> = new WeakMap();
|
|
39
|
+
|
|
40
|
+
// section: main_function
|
|
41
|
+
/**
|
|
42
|
+
* Returns a stable opaque anonymous visitor ID for the caller, reading an
|
|
43
|
+
* existing httpOnly cookie or issuing a fresh UUID v4 if absent.
|
|
44
|
+
*
|
|
45
|
+
* - Cookie name: `hazo_auth_anon_id` (prefixed via `[hazo_auth__cookies] cookie_prefix`)
|
|
46
|
+
* - Cookie attributes: httpOnly, sameSite=lax, path=/, secure in production,
|
|
47
|
+
* maxAge = 2 years.
|
|
48
|
+
* - Idempotent per-request: calling twice with the same NextRequest returns
|
|
49
|
+
* the same id and only queues one Set-Cookie.
|
|
50
|
+
*
|
|
51
|
+
* Independent from authenticated identity: an authenticated user can still
|
|
52
|
+
* have an anon id cookie. Whether to consult it for a logged-in caller is up
|
|
53
|
+
* to the caller (hazo_feedback, for example, doesn't bother).
|
|
54
|
+
*
|
|
55
|
+
* @param request - The incoming NextRequest.
|
|
56
|
+
* @returns The existing or freshly-issued anonymous visitor id (UUID v4 string).
|
|
57
|
+
*/
|
|
58
|
+
export async function ensure_anon_id(request: NextRequest): Promise<string> {
|
|
59
|
+
const cookie_name = get_cookie_name(BASE_COOKIE_NAMES.ANON_ID);
|
|
60
|
+
|
|
61
|
+
// Per-request idempotency: if we already issued for this NextRequest, reuse it.
|
|
62
|
+
const already_issued = issued_per_request.get(request);
|
|
63
|
+
if (already_issued) {
|
|
64
|
+
return already_issued;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Read the existing cookie from the incoming request.
|
|
68
|
+
const existing = request.cookies.get(cookie_name)?.value;
|
|
69
|
+
if (existing) {
|
|
70
|
+
return existing;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Issue a new id and queue the Set-Cookie via the next/headers cookie store.
|
|
74
|
+
const new_id = crypto.randomUUID();
|
|
75
|
+
const cookie_options = get_cookie_options({
|
|
76
|
+
httpOnly: true,
|
|
77
|
+
secure: process.env.NODE_ENV === "production",
|
|
78
|
+
sameSite: "lax" as const,
|
|
79
|
+
path: "/",
|
|
80
|
+
maxAge: TWO_YEARS_SECONDS,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const cookie_store = await cookies();
|
|
84
|
+
cookie_store.set(cookie_name, new_id, cookie_options);
|
|
85
|
+
|
|
86
|
+
issued_per_request.set(request, new_id);
|
|
87
|
+
return new_id;
|
|
88
|
+
}
|
|
@@ -11,6 +11,9 @@ export {
|
|
|
11
11
|
} from "./auth_utils.server.js";
|
|
12
12
|
export type { AuthResult, AuthUser } from "./auth_utils.server";
|
|
13
13
|
|
|
14
|
+
// section: anon_id_exports (v5.2)
|
|
15
|
+
export { ensure_anon_id } from "./ensure_anon_id.server.js";
|
|
16
|
+
|
|
14
17
|
// section: tenant_auth_exports
|
|
15
18
|
export {
|
|
16
19
|
hazo_get_tenant_auth,
|
|
@@ -8,6 +8,7 @@ export const BASE_COOKIE_NAMES = {
|
|
|
8
8
|
USER_EMAIL: "hazo_auth_user_email",
|
|
9
9
|
SESSION: "hazo_auth_session",
|
|
10
10
|
DEV_LOCK: "hazo_auth_dev_lock",
|
|
11
|
+
ANON_ID: "hazo_auth_anon_id", // v5.2: Stable opaque per-visitor ID for anonymous flows (e.g. hazo_feedback). Kept in sync with the server constant.
|
|
11
12
|
} as const;
|
|
12
13
|
|
|
13
14
|
// section: main_functions
|
|
@@ -29,6 +29,7 @@ export const BASE_COOKIE_NAMES = {
|
|
|
29
29
|
SESSION: "hazo_auth_session",
|
|
30
30
|
DEV_LOCK: "hazo_auth_dev_lock",
|
|
31
31
|
SCOPE_ID: "hazo_auth_scope_id", // v5.2: Tenant context cookie for multi-tenancy
|
|
32
|
+
ANON_ID: "hazo_auth_anon_id", // v5.2: Stable opaque per-visitor ID for anonymous flows (e.g. hazo_feedback)
|
|
32
33
|
} as const;
|
|
33
34
|
|
|
34
35
|
// section: main_function
|
|
@@ -109,14 +109,6 @@ function get_hazo_connect_config(): {
|
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
// Log the resolved path so consumers can see which DB file is being used
|
|
113
|
-
logger.info("hazo_connect_sqlite_path_resolved", {
|
|
114
|
-
filename: "hazo_connect_setup.server.ts",
|
|
115
|
-
line_number: 0,
|
|
116
|
-
sqlite_path,
|
|
117
|
-
process_cwd: process.cwd(),
|
|
118
|
-
config_source: hazo_connect_section ? "hazo_auth_config.ini" : "environment variables",
|
|
119
|
-
});
|
|
120
112
|
|
|
121
113
|
return {
|
|
122
114
|
type: "sqlite",
|