hazo_auth 10.1.0 โ†’ 10.2.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/README.md CHANGED
@@ -2,6 +2,25 @@
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 v10.2.0 ๐Ÿงช
6
+
7
+ **Test-friendly hazo_connect injection + autotest/middleware fixes.**
8
+
9
+ - **`set_hazo_connect_instance(adapter)` / `reset_hazo_connect_instance()`** from `hazo_auth/server-lib` โ€” inject a pre-built adapter into both the hazo_auth singleton cache and the underlying hazo_connect singleton (companion to hazo_connect 3.6.0 FR-001). Call `set_*` in `beforeAll` and `reset_*` in `afterAll` to swap in a test SQLite adapter without touching the production config:
10
+
11
+ ```typescript
12
+ import { set_hazo_connect_instance, reset_hazo_connect_instance } from "hazo_auth/server-lib";
13
+
14
+ beforeAll(() => set_hazo_connect_instance(testAdapter));
15
+ afterAll(() => reset_hazo_connect_instance());
16
+ ```
17
+
18
+ - **Middleware no longer redirects `/api/` requests to the login page** โ€” protected API routes return JSON `401`/`403` and the login redirect is now built from the request's own origin (fixes `Failed to fetch` on any non-default dev/prod port).
19
+ - **`/api/hazo_auth/me`** now exposes `legal_acceptance` at the top level; **`/api/hazo_auth/health`** now returns a top-level `ok` boolean.
20
+ - Browser autotest scenarios corrected for browser `fetch` semantics (opaque redirects, `*_default.jpg` images, admin-gated `401`/`403`, current `relationships` body shape).
21
+
22
+ Requires `hazo_connect ^3.6.0`.
23
+
5
24
  ### What's New in v10.1.0 ๐Ÿš€
6
25
 
7
26
  **Incremental Google OAuth Scopes & Server-Side Token Access** โ€” Grant additional Google API scopes (Analytics, Sheets, Drive, etc.) without creating a separate OAuth app. Store encrypted tokens server-side and access them programmatically.
@@ -8,6 +8,7 @@ import "server-only";
8
8
  // section: imports
9
9
  import type { HazoConnectAdapter } from "hazo_connect";
10
10
  import { getHazoConnectSingleton } from "hazo_connect/nextjs/setup";
11
+ import { setHazoConnectSingleton, resetHazoConnectSingleton } from "hazo_connect/testing";
11
12
  import { create_sqlite_hazo_connect_server, get_hazo_connect_config_options } from "./hazo_connect_setup.server.js";
12
13
  import { initializeAdminService, getSqliteAdminService } from "hazo_connect/server";
13
14
  import { create_app_logger } from "./app_logger.js";
@@ -32,6 +33,8 @@ let isInitialized = false;
32
33
  * @returns The singleton HazoConnectAdapter instance
33
34
  */
34
35
  export function get_hazo_connect_instance(): HazoConnectAdapter {
36
+ // Honor test injection or cached fallback first
37
+ if (hazoConnectInstance) return hazoConnectInstance;
35
38
  // Use the new singleton API from hazo_connect
36
39
  // This automatically handles:
37
40
  // - Instance reuse
@@ -102,3 +105,16 @@ export function get_hazo_connect_instance(): HazoConnectAdapter {
102
105
  }
103
106
  }
104
107
 
108
+ /** Inject a connect adapter for tests (mirrors set_hazo_connect_instance pattern). */
109
+ export function set_hazo_connect_instance(adapter: HazoConnectAdapter): void {
110
+ hazoConnectInstance = adapter;
111
+ setHazoConnectSingleton(adapter);
112
+ }
113
+
114
+ /** Reset the injected adapter (call in afterAll). */
115
+ export function reset_hazo_connect_instance(): void {
116
+ hazoConnectInstance = null;
117
+ isInitialized = false;
118
+ resetHazoConnectSingleton();
119
+ }
120
+
@@ -11,5 +11,5 @@ import { ProfilePicMenu } from "./profile_pic_menu.js";
11
11
  // section: component
12
12
  export function SidebarLayoutWrapper({ children }) {
13
13
  const authStatus = use_auth_status();
14
- return (_jsx(SidebarProvider, { children: _jsxs("div", { className: "cls_sidebar_layout_wrapper flex min-h-screen w-full", children: [_jsxs(Sidebar, { children: [_jsx(SidebarHeader, { className: "cls_sidebar_layout_header", children: _jsx("div", { className: "cls_sidebar_layout_title flex items-center gap-2 px-2 py-4", children: _jsx("h1", { className: "cls_sidebar_layout_title_text text-lg font-semibold text-sidebar-foreground", children: "hazo auth" }) }) }), _jsxs(SidebarContent, { className: "cls_sidebar_layout_content", children: [_jsxs(SidebarGroup, { className: "cls_sidebar_layout_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Test components" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_test_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_login_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/login", className: "cls_sidebar_layout_test_login_link flex items-center gap-2", "aria-label": "Test login layout component", children: [_jsx(LogIn, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test login" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_register_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/register", className: "cls_sidebar_layout_test_register_link flex items-center gap-2", "aria-label": "Test register layout component", children: [_jsx(UserPlus, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test register" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_forgot_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/forgot_password", className: "cls_sidebar_layout_test_forgot_password_link flex items-center gap-2", "aria-label": "Test forgot password layout component", children: [_jsx(KeyRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test forgot password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_reset_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/reset_password", className: "cls_sidebar_layout_test_reset_password_link flex items-center gap-2", "aria-label": "Test reset password layout component", children: [_jsx(Key, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test reset password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_email_verification_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/verify_email", className: "cls_sidebar_layout_test_email_verification_link flex items-center gap-2", "aria-label": "Test email verification layout component", children: [_jsx(MailCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test email verification" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_sqlite_admin_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_connect/sqlite_admin", className: "cls_sidebar_layout_sqlite_admin_link flex items-center gap-2", "aria-label": "Open SQLite admin UI to browse and edit database", children: [_jsx(Database, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "SQLite Admin" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_user_management_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/user_management", className: "cls_sidebar_layout_user_management_link flex items-center gap-2", "aria-label": "Open User Management to manage users, roles, and permissions", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "User Management" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_rbac_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/rbac_test", className: "cls_sidebar_layout_rbac_test_link flex items-center gap-2", "aria-label": "Test RBAC and HRBAC access control", children: [_jsx(ShieldCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "RBAC/HRBAC Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_profile_stamp_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/profile_stamp_test", className: "cls_sidebar_layout_profile_stamp_test_link flex items-center gap-2", "aria-label": "Test ProfileStamp component", children: [_jsx(CircleUserRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "ProfileStamp Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_app_user_data_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/app_user_data_test", className: "cls_sidebar_layout_app_user_data_test_link flex items-center gap-2", "aria-label": "Test app_user_data JSON storage", children: [_jsx(FileJson, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "App User Data Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_google_token_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/google_token_test", className: "cls_sidebar_layout_google_token_test_link flex items-center gap-2", "aria-label": "Test Google OAuth token storage and revocation", children: [_jsx(Globe, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Google Token Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_create_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/create_firm", className: "cls_sidebar_layout_create_firm_link flex items-center gap-2", "aria-label": "Test create firm flow", children: [_jsx(Building2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Create Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_edit_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/edit_firm", className: "cls_sidebar_layout_edit_firm_link flex items-center gap-2", "aria-label": "Test branding editor for firm", children: [_jsx(Palette, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Edit Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_relationships_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/relationships", className: "cls_sidebar_layout_relationships_link flex items-center gap-2", "aria-label": "Test relationship accounts", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Relationships" })] }) }) })] })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_testing_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Testing" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_testing_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_scenarios_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/test_scenarios", className: "cls_sidebar_layout_test_scenarios_link flex items-center gap-2", "aria-label": "Test scenarios", children: [_jsx(Settings2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test Scenarios" })] }) }) }) })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_auto_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Auto Tests" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_auto_test_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_auto_test_runner_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/auto_test", className: "cls_sidebar_layout_auto_test_runner_link flex items-center gap-2", "aria-label": "Run automated tests", children: [_jsx(Play, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Auto Test Runner" })] }) }) }) })] }), _jsx(ProfilePicMenu, { variant: "sidebar", avatar_size: "sm", className: "cls_sidebar_layout_profile_menu", sidebar_group_label: "Account" }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_resources_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Resources" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_resources_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_storybook_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "http://localhost:6006", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_storybook_link flex items-center gap-2", "aria-label": "Open Storybook preview for reusable components", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Storybook" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_docs_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "https://ui.shadcn.com/docs", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_docs_link flex items-center gap-2", "aria-label": "Review shadcn documentation for styling guidance", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Shadcn docs" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) })] })] })] })] }), _jsxs(SidebarInset, { className: "cls_sidebar_layout_inset", children: [_jsxs("header", { className: "cls_sidebar_layout_main_header flex h-16 shrink-0 items-center gap-2 border-b px-4", children: [_jsx(SidebarTrigger, { className: "cls_sidebar_layout_trigger" }), _jsx("div", { className: "cls_sidebar_layout_main_header_content flex flex-1 items-center gap-2", children: _jsx("h2", { className: "cls_sidebar_layout_main_title text-lg font-semibold text-foreground", children: "hazo reusable ui library workspace" }) }), _jsx(ProfilePicMenu, { className: "cls_sidebar_layout_auth_status", avatar_size: "sm" })] }), _jsx("main", { className: "cls_sidebar_layout_main_content flex flex-1 items-center justify-center p-6", children: children })] })] }) }));
14
+ return (_jsx(SidebarProvider, { children: _jsxs("div", { className: "cls_sidebar_layout_wrapper flex min-h-screen w-full", children: [_jsxs(Sidebar, { children: [_jsx(SidebarHeader, { className: "cls_sidebar_layout_header", children: _jsx("div", { className: "cls_sidebar_layout_title flex items-center gap-2 px-2 py-4", children: _jsx("h1", { className: "cls_sidebar_layout_title_text text-lg font-semibold text-sidebar-foreground", children: "hazo auth" }) }) }), _jsxs(SidebarContent, { className: "cls_sidebar_layout_content", children: [_jsxs(SidebarGroup, { className: "cls_sidebar_layout_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Test components" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_test_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_login_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/login", className: "cls_sidebar_layout_test_login_link flex items-center gap-2", "aria-label": "Test login layout component", children: [_jsx(LogIn, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test login" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_register_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/register", className: "cls_sidebar_layout_test_register_link flex items-center gap-2", "aria-label": "Test register layout component", children: [_jsx(UserPlus, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test register" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_forgot_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/forgot_password", className: "cls_sidebar_layout_test_forgot_password_link flex items-center gap-2", "aria-label": "Test forgot password layout component", children: [_jsx(KeyRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test forgot password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_reset_password_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/reset_password", className: "cls_sidebar_layout_test_reset_password_link flex items-center gap-2", "aria-label": "Test reset password layout component", children: [_jsx(Key, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test reset password" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_email_verification_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/verify_email", className: "cls_sidebar_layout_test_email_verification_link flex items-center gap-2", "aria-label": "Test email verification layout component", children: [_jsx(MailCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test email verification" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_sqlite_admin_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_connect/sqlite_admin", className: "cls_sidebar_layout_sqlite_admin_link flex items-center gap-2", "aria-label": "Open SQLite admin UI to browse and edit database", children: [_jsx(Database, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "SQLite Admin" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_user_management_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/user_management", className: "cls_sidebar_layout_user_management_link flex items-center gap-2", "aria-label": "Open User Management to manage users, roles, and permissions", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "User Management" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_rbac_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/rbac_test", className: "cls_sidebar_layout_rbac_test_link flex items-center gap-2", "aria-label": "Test RBAC and HRBAC access control", children: [_jsx(ShieldCheck, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "RBAC/HRBAC Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_profile_stamp_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/profile_stamp_test", className: "cls_sidebar_layout_profile_stamp_test_link flex items-center gap-2", "aria-label": "Test ProfileStamp component", children: [_jsx(CircleUserRound, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "ProfileStamp Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_app_user_data_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/app_user_data_test", className: "cls_sidebar_layout_app_user_data_test_link flex items-center gap-2", "aria-label": "Test app_user_data JSON storage", children: [_jsx(FileJson, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "App User Data Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_google_token_test_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/google_token_test", className: "cls_sidebar_layout_google_token_test_link flex items-center gap-2", "aria-label": "Test Google OAuth token storage and revocation", children: [_jsx(Globe, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Google Token Test" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_create_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/create_firm", className: "cls_sidebar_layout_create_firm_link flex items-center gap-2", "aria-label": "Test create firm flow", children: [_jsx(Building2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Create Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_edit_firm_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/edit_firm", className: "cls_sidebar_layout_edit_firm_link flex items-center gap-2", "aria-label": "Test branding editor for firm", children: [_jsx(Palette, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Edit Firm" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_relationships_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/relationships", className: "cls_sidebar_layout_relationships_link flex items-center gap-2", "aria-label": "Test relationship accounts", children: [_jsx(User, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Relationships" })] }) }) })] })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_testing_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Testing" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_testing_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_test_scenarios_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/test_scenarios", className: "cls_sidebar_layout_test_scenarios_link flex items-center gap-2", "aria-label": "Test scenarios", children: [_jsx(Settings2, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Test Scenarios" })] }) }) }) })] }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_auto_test_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Auto Tests" }), _jsx(SidebarMenu, { className: "cls_sidebar_layout_auto_test_menu", children: _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_auto_test_runner_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs(Link, { href: "/hazo_auth/autotest", className: "cls_sidebar_layout_auto_test_runner_link flex items-center gap-2", "aria-label": "Run browser autotests", children: [_jsx(Play, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Browser Autotest" })] }) }) }) })] }), _jsx(ProfilePicMenu, { variant: "sidebar", avatar_size: "sm", className: "cls_sidebar_layout_profile_menu", sidebar_group_label: "Account" }), _jsxs(SidebarGroup, { className: "cls_sidebar_layout_resources_group", children: [_jsx(SidebarGroupLabel, { className: "cls_sidebar_layout_group_label", children: "Resources" }), _jsxs(SidebarMenu, { className: "cls_sidebar_layout_resources_menu", children: [_jsx(SidebarMenuItem, { className: "cls_sidebar_layout_storybook_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "http://localhost:6006", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_storybook_link flex items-center gap-2", "aria-label": "Open Storybook preview for reusable components", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Storybook" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) }), _jsx(SidebarMenuItem, { className: "cls_sidebar_layout_docs_item", children: _jsx(SidebarMenuButton, { asChild: true, children: _jsxs("a", { href: "https://ui.shadcn.com/docs", target: "_blank", rel: "noopener noreferrer", className: "cls_sidebar_layout_docs_link flex items-center gap-2", "aria-label": "Review shadcn documentation for styling guidance", children: [_jsx(BookOpen, { className: "h-4 w-4", "aria-hidden": "true" }), _jsx("span", { children: "Shadcn docs" }), _jsx(ExternalLink, { className: "ml-auto h-3 w-3", "aria-hidden": "true" })] }) }) })] })] })] })] }), _jsxs(SidebarInset, { className: "cls_sidebar_layout_inset", children: [_jsxs("header", { className: "cls_sidebar_layout_main_header flex h-16 shrink-0 items-center gap-2 border-b px-4", children: [_jsx(SidebarTrigger, { className: "cls_sidebar_layout_trigger" }), _jsx("div", { className: "cls_sidebar_layout_main_header_content flex flex-1 items-center gap-2", children: _jsx("h2", { className: "cls_sidebar_layout_main_title text-lg font-semibold text-foreground", children: "hazo reusable ui library workspace" }) }), _jsx(ProfilePicMenu, { className: "cls_sidebar_layout_auth_status", avatar_size: "sm" })] }), _jsx("main", { className: "cls_sidebar_layout_main_content flex flex-1 items-center justify-center p-6", children: children })] })] }) }));
15
15
  }
@@ -15,4 +15,8 @@ import type { HazoConnectAdapter } from "hazo_connect";
15
15
  * @returns The singleton HazoConnectAdapter instance
16
16
  */
17
17
  export declare function get_hazo_connect_instance(): HazoConnectAdapter;
18
+ /** Inject a connect adapter for tests (mirrors set_hazo_connect_instance pattern). */
19
+ export declare function set_hazo_connect_instance(adapter: HazoConnectAdapter): void;
20
+ /** Reset the injected adapter (call in afterAll). */
21
+ export declare function reset_hazo_connect_instance(): void;
18
22
  //# sourceMappingURL=hazo_connect_instance.server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hazo_connect_instance.server.d.ts","sourceRoot":"","sources":["../../src/lib/hazo_connect_instance.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAWvD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,IAAI,kBAAkB,CAqE9D"}
1
+ {"version":3,"file":"hazo_connect_instance.server.d.ts","sourceRoot":"","sources":["../../src/lib/hazo_connect_instance.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAYvD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,IAAI,kBAAkB,CAuE9D;AAED,sFAAsF;AACtF,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAG3E;AAED,qDAAqD;AACrD,wBAAgB,2BAA2B,IAAI,IAAI,CAIlD"}
@@ -2,6 +2,7 @@
2
2
  // section: server-only-guard
3
3
  import "server-only";
4
4
  import { getHazoConnectSingleton } from "hazo_connect/nextjs/setup";
5
+ import { setHazoConnectSingleton, resetHazoConnectSingleton } from "hazo_connect/testing";
5
6
  import { create_sqlite_hazo_connect_server, get_hazo_connect_config_options } from "./hazo_connect_setup.server.js";
6
7
  import { initializeAdminService, getSqliteAdminService } from "hazo_connect/server";
7
8
  import { create_app_logger } from "./app_logger.js";
@@ -24,6 +25,9 @@ let isInitialized = false;
24
25
  * @returns The singleton HazoConnectAdapter instance
25
26
  */
26
27
  export function get_hazo_connect_instance() {
28
+ // Honor test injection or cached fallback first
29
+ if (hazoConnectInstance)
30
+ return hazoConnectInstance;
27
31
  // Use the new singleton API from hazo_connect
28
32
  // This automatically handles:
29
33
  // - Instance reuse
@@ -89,3 +93,14 @@ export function get_hazo_connect_instance() {
89
93
  return hazoConnectInstance;
90
94
  }
91
95
  }
96
+ /** Inject a connect adapter for tests (mirrors set_hazo_connect_instance pattern). */
97
+ export function set_hazo_connect_instance(adapter) {
98
+ hazoConnectInstance = adapter;
99
+ setHazoConnectSingleton(adapter);
100
+ }
101
+ /** Reset the injected adapter (call in afterAll). */
102
+ export function reset_hazo_connect_instance() {
103
+ hazoConnectInstance = null;
104
+ isInitialized = false;
105
+ resetHazoConnectSingleton();
106
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../../src/server/routes/me.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoBxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;IA+G7C"}
1
+ {"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../../src/server/routes/me.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoBxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;IAiH7C"}
@@ -24,6 +24,7 @@ function strip_sentinel_email(email) {
24
24
  * Always returns the same format to prevent downstream variations.
25
25
  */
26
26
  export async function GET(request) {
27
+ var _a;
27
28
  const logger = create_app_logger();
28
29
  try {
29
30
  // Use hazo_get_auth to get user with permissions
@@ -94,6 +95,8 @@ export async function GET(request) {
94
95
  user_type_info,
95
96
  // App-specific user data (JSON object, always included)
96
97
  app_user_data: auth_result.user.app_user_data,
98
+ // Legal documents the user has accepted (map of key -> { hash, accepted_at })
99
+ legal_acceptance: (_a = auth_result.user.legal_acceptance) !== null && _a !== void 0 ? _a : null,
97
100
  // Permissions and user object (always included)
98
101
  user: auth_result.user,
99
102
  permissions: auth_result.permissions,
@@ -25,7 +25,7 @@ export type { OAuthConfig } from "./lib/oauth_config.server";
25
25
  export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_max_logo_size_bytes, } from "./lib/branding_config.server.js";
26
26
  export type { FirmBrandingConfig } from "./lib/branding_config.server";
27
27
  export { create_sqlite_hazo_connect } from "./lib/hazo_connect_setup.js";
28
- export { get_hazo_connect_instance } from "./lib/hazo_connect_instance.server.js";
28
+ export { get_hazo_connect_instance, set_hazo_connect_instance, reset_hazo_connect_instance, } from "./lib/hazo_connect_instance.server.js";
29
29
  export { create_app_logger } from "./lib/app_logger.js";
30
30
  export { sanitize_error_for_user } from "./lib/utils/error_sanitizer.js";
31
31
  export type { ErrorSanitizationOptions } from "./lib/utils/error_sanitizer";
@@ -1 +1 @@
1
- {"version":3,"file":"server-lib.d.ts","sourceRoot":"","sources":["../src/server-lib.ts"],"names":[],"mappings":"AAYA,OAAO,aAAa,CAAC;AAGrB,cAAc,kBAAkB,CAAC;AAGjC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAGrF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAG/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,cAAc,+BAA+B,CAAC"}
1
+ {"version":3,"file":"server-lib.d.ts","sourceRoot":"","sources":["../src/server-lib.ts"],"names":[],"mappings":"AAYA,OAAO,aAAa,CAAC;AAGrB,cAAc,kBAAkB,CAAC;AAGjC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAGrF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EACL,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,cAAc,+BAA+B,CAAC"}
@@ -39,7 +39,7 @@ export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled, }
39
39
  export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_max_logo_size_bytes, } from "./lib/branding_config.server.js";
40
40
  // section: hazo_connect_exports
41
41
  export { create_sqlite_hazo_connect } from "./lib/hazo_connect_setup.js";
42
- export { get_hazo_connect_instance } from "./lib/hazo_connect_instance.server.js";
42
+ export { get_hazo_connect_instance, set_hazo_connect_instance, reset_hazo_connect_instance, } from "./lib/hazo_connect_instance.server.js";
43
43
  // section: logger_exports
44
44
  export { create_app_logger } from "./lib/app_logger.js";
45
45
  // section: util_exports
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_auth",
3
- "version": "10.1.0",
3
+ "version": "10.2.0",
4
4
  "description": "Zero-config authentication UI components for Next.js with RBAC, OAuth, scope-based multi-tenancy, and invitations",
5
5
  "keywords": [
6
6
  "authentication",
@@ -252,14 +252,14 @@
252
252
  "@radix-ui/react-switch": "^1.2.0",
253
253
  "@radix-ui/react-tabs": "^1.1.0",
254
254
  "@radix-ui/react-tooltip": "^1.2.0",
255
- "hazo_api": "^2.3.1",
255
+ "hazo_api": "^2.4.0",
256
256
  "hazo_config": "^2.1.10",
257
- "hazo_connect": "^3.5.1",
257
+ "hazo_connect": "^3.6.0",
258
258
  "hazo_core": "^1.1.0",
259
259
  "hazo_logs": "^2.0.3",
260
260
  "hazo_notify": "^6.1.3",
261
261
  "hazo_secure": "^1.1.0",
262
- "hazo_ui": "^3.4.1",
262
+ "hazo_ui": "^4.0.0",
263
263
  "input-otp": "^1.4.0",
264
264
  "lucide-react": "^0.553.0",
265
265
  "next": "^14.0.0",
@@ -392,13 +392,13 @@
392
392
  "eslint": "^9.39.1",
393
393
  "eslint-config-next": "^16.0.4",
394
394
  "eslint-plugin-storybook": "^10.0.6",
395
- "hazo_api": "^2.3.1",
395
+ "hazo_api": "^2.4.0",
396
396
  "hazo_config": "^2.1.10",
397
- "hazo_connect": "^3.5.1",
397
+ "hazo_connect": "^3.6.0",
398
398
  "hazo_core": "^1.1.0",
399
399
  "hazo_logs": "^2.0.3",
400
400
  "hazo_notify": "^6.1.3",
401
- "hazo_ui": "^3.4.1",
401
+ "hazo_ui": "^4.0.0",
402
402
  "input-otp": "^1.4.0",
403
403
  "jest": "^30.2.0",
404
404
  "jest-environment-jsdom": "^30.0.0",