hazo_auth 9.0.1 → 10.0.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 +39 -11
- package/SETUP_CHECKLIST.md +35 -16
- package/cli-src/cli/init_users.ts +40 -48
- package/cli-src/lib/auth/auth_types.ts +0 -2
- package/cli-src/lib/auth/hazo_get_auth.server.ts +31 -25
- package/cli-src/lib/auth/hazo_get_tenant_auth.server.ts +9 -13
- package/cli-src/lib/config/config_loader.server.ts +41 -3
- package/cli-src/lib/config/hazo_auth_core_config.ts +1 -1
- package/cli-src/lib/constants.ts +2 -0
- package/cli-src/lib/hazo_connect_setup.server.ts +20 -2
- package/cli-src/lib/profile_pic_menu_config.server.ts +4 -3
- package/cli-src/lib/schema/sqlite_schema.ts +0 -4
- package/cli-src/lib/scope_hierarchy_config.server.ts +1 -9
- package/cli-src/lib/services/invitation_service.ts +1 -1
- package/cli-src/lib/services/scope_service.ts +2 -76
- package/cli-src/lib/services/user_scope_service.ts +7 -61
- package/config/hazo_auth_config.example.ini +3 -1
- package/dist/cli/init_users.d.ts.map +1 -1
- package/dist/cli/init_users.js +42 -42
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
- package/dist/components/layouts/shared/components/profile_pic_menu.js +7 -1
- package/dist/components/ui/input-otp.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/lib/auth/auth_types.d.ts +0 -2
- package/dist/lib/auth/auth_types.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +27 -19
- package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_tenant_auth.server.js +10 -10
- package/dist/lib/config/config_loader.server.d.ts.map +1 -1
- package/dist/lib/config/config_loader.server.js +38 -3
- package/dist/lib/config/hazo_auth_core_config.js +1 -1
- package/dist/lib/constants.d.ts +1 -0
- package/dist/lib/constants.d.ts.map +1 -1
- package/dist/lib/constants.js +1 -0
- package/dist/lib/hazo_connect_setup.server.d.ts +1 -0
- package/dist/lib/hazo_connect_setup.server.d.ts.map +1 -1
- package/dist/lib/hazo_connect_setup.server.js +15 -2
- package/dist/lib/profile_pic_menu_config.server.d.ts +2 -1
- package/dist/lib/profile_pic_menu_config.server.d.ts.map +1 -1
- package/dist/lib/profile_pic_menu_config.server.js +1 -1
- package/dist/lib/schema/sqlite_schema.d.ts +1 -1
- package/dist/lib/schema/sqlite_schema.d.ts.map +1 -1
- package/dist/lib/schema/sqlite_schema.js +0 -4
- package/dist/lib/scope_hierarchy_config.server.d.ts +0 -2
- package/dist/lib/scope_hierarchy_config.server.d.ts.map +1 -1
- package/dist/lib/scope_hierarchy_config.server.js +1 -3
- package/dist/lib/services/invitation_service.d.ts +1 -1
- package/dist/lib/services/invitation_service.js +1 -1
- package/dist/lib/services/scope_service.d.ts +1 -14
- package/dist/lib/services/scope_service.d.ts.map +1 -1
- package/dist/lib/services/scope_service.js +2 -67
- package/dist/lib/services/user_scope_service.d.ts +5 -12
- package/dist/lib/services/user_scope_service.d.ts.map +1 -1
- package/dist/lib/services/user_scope_service.js +8 -45
- package/dist/server/routes/invitations.d.ts +1 -1
- package/dist/server/routes/invitations.d.ts.map +1 -1
- package/dist/server/routes/invitations.js +12 -11
- package/dist/server/routes/user_management_users.d.ts +1 -1
- package/package.json +15 -15
|
@@ -18,7 +18,6 @@ export type HazoAuthUser = {
|
|
|
18
18
|
export type ScopeAccessInfo = {
|
|
19
19
|
scope_id: string;
|
|
20
20
|
scope_name?: string;
|
|
21
|
-
is_super_admin?: boolean;
|
|
22
21
|
};
|
|
23
22
|
/**
|
|
24
23
|
* Result type for hazo_get_auth function
|
|
@@ -114,7 +113,6 @@ export type TenantOrganization = {
|
|
|
114
113
|
slug: string | null;
|
|
115
114
|
level: string;
|
|
116
115
|
role_id: string;
|
|
117
|
-
is_super_admin: boolean;
|
|
118
116
|
branding?: {
|
|
119
117
|
logo_url: string | null;
|
|
120
118
|
primary_color: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth_types.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth_types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAE9C,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC7C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"auth_types.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth_types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM1C,OAAO,KAAK,EACV,cAAc,EAEd,eAAe,EAGhB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAM1C,OAAO,KAAK,EACV,cAAc,EAEd,eAAe,EAGhB,MAAM,cAAc,CAAC;AAgEtB;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU1D;AA4SD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CA+NzB"}
|
|
@@ -16,6 +16,7 @@ import { is_hrbac_enabled, get_scope_hierarchy_config } from "../scope_hierarchy
|
|
|
16
16
|
import { check_user_scope_access, get_user_scopes, } from "../services/user_scope_service.js";
|
|
17
17
|
import { get_cookie_name, BASE_COOKIE_NAMES } from "../cookies_config.server.js";
|
|
18
18
|
import { get_app_permission_descriptions } from "../app_permissions_config.server.js";
|
|
19
|
+
import { GLOBAL_ADMIN_PERMISSION } from "../constants.js";
|
|
19
20
|
// section: helpers
|
|
20
21
|
/**
|
|
21
22
|
* Parse JSON string to object, returning null on failure
|
|
@@ -287,7 +288,6 @@ async function check_scope_access_internal(user_id, scope_id) {
|
|
|
287
288
|
scope_access_via: {
|
|
288
289
|
scope_id: result.access_via.scope_id,
|
|
289
290
|
scope_name: result.access_via.scope_name,
|
|
290
|
-
is_super_admin: result.is_super_admin,
|
|
291
291
|
},
|
|
292
292
|
user_scopes,
|
|
293
293
|
};
|
|
@@ -445,25 +445,33 @@ export async function hazo_get_auth(request, options) {
|
|
|
445
445
|
let scope_access_via;
|
|
446
446
|
const hrbac_enabled = is_hrbac_enabled();
|
|
447
447
|
if (hrbac_enabled && (options === null || options === void 0 ? void 0 : options.scope_id)) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const client_ip = get_client_ip(request);
|
|
454
|
-
logger.warn("auth_utility_scope_access_denied", {
|
|
455
|
-
filename: get_filename(),
|
|
456
|
-
line_number: get_line_number(),
|
|
457
|
-
user_id: user.id,
|
|
458
|
-
scope_id: options.scope_id,
|
|
459
|
-
user_scopes: scope_result.user_scopes,
|
|
460
|
-
ip: client_ip,
|
|
461
|
-
correlation_id: getCorrelationId(),
|
|
462
|
-
});
|
|
448
|
+
// Global admin permission grants access to all scopes
|
|
449
|
+
const has_global_admin = permissions.includes(GLOBAL_ADMIN_PERMISSION);
|
|
450
|
+
if (has_global_admin) {
|
|
451
|
+
scope_ok = true;
|
|
452
|
+
scope_access_via = { scope_id: options.scope_id };
|
|
463
453
|
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
454
|
+
else {
|
|
455
|
+
const scope_result = await check_scope_access_internal(user.id, options.scope_id);
|
|
456
|
+
scope_ok = scope_result.scope_ok;
|
|
457
|
+
scope_access_via = scope_result.scope_access_via;
|
|
458
|
+
// Log scope denial if permission logging is enabled
|
|
459
|
+
if (!scope_ok && config.log_permission_denials) {
|
|
460
|
+
const client_ip = get_client_ip(request);
|
|
461
|
+
logger.warn("auth_utility_scope_access_denied", {
|
|
462
|
+
filename: get_filename(),
|
|
463
|
+
line_number: get_line_number(),
|
|
464
|
+
user_id: user.id,
|
|
465
|
+
scope_id: options.scope_id,
|
|
466
|
+
user_scopes: scope_result.user_scopes,
|
|
467
|
+
ip: client_ip,
|
|
468
|
+
correlation_id: getCorrelationId(),
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
// Throw error if strict mode and scope access denied
|
|
472
|
+
if (!scope_ok && options.strict) {
|
|
473
|
+
throw new ScopeAccessError(options.scope_id, scope_result.user_scopes);
|
|
474
|
+
}
|
|
467
475
|
}
|
|
468
476
|
}
|
|
469
477
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_get_tenant_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_tenant_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hazo_get_tenant_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_tenant_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ1C,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EAGzB,MAAM,cAAc,CAAC;AAqBtB;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,iBAAiB,GACzB,MAAM,GAAG,SAAS,CAYpB;AA8BD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,gBAAgB,CAAC,CAwF3B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CA0BnC"}
|
|
@@ -4,6 +4,7 @@ import "server-only";
|
|
|
4
4
|
import { hazo_get_auth } from "./hazo_get_auth.server.js";
|
|
5
5
|
import { get_auth_cache } from "./auth_cache.js";
|
|
6
6
|
import { get_scope_by_id } from "../services/scope_service.js";
|
|
7
|
+
import { GLOBAL_ADMIN_PERMISSION } from "../constants.js";
|
|
7
8
|
import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
|
|
8
9
|
import { get_cookie_name } from "../cookies_config.server.js";
|
|
9
10
|
import { get_auth_utility_config } from "../auth_utility_config.server.js";
|
|
@@ -39,19 +40,17 @@ export function extract_scope_id_from_request(request, options) {
|
|
|
39
40
|
return cookie_value;
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
|
-
* Builds TenantOrganization from scope details
|
|
43
|
+
* Builds TenantOrganization from scope details
|
|
43
44
|
* @param scope_details - Full scope details from cache
|
|
44
|
-
* @param is_super_admin - Whether user is accessing as super admin
|
|
45
45
|
* @returns TenantOrganization object
|
|
46
46
|
*/
|
|
47
|
-
function build_tenant_organization(scope_details
|
|
47
|
+
function build_tenant_organization(scope_details) {
|
|
48
48
|
return {
|
|
49
49
|
id: scope_details.id,
|
|
50
50
|
name: scope_details.name,
|
|
51
51
|
slug: scope_details.slug,
|
|
52
52
|
level: scope_details.level,
|
|
53
53
|
role_id: scope_details.role_id,
|
|
54
|
-
is_super_admin,
|
|
55
54
|
branding: scope_details.logo_url || scope_details.primary_color
|
|
56
55
|
? {
|
|
57
56
|
logo_url: scope_details.logo_url,
|
|
@@ -113,13 +112,15 @@ export async function hazo_get_tenant_auth(request, options = {}) {
|
|
|
113
112
|
// Build organization info if scope access was successful
|
|
114
113
|
let organization = null;
|
|
115
114
|
if (scope_id && auth_result.scope_ok && auth_result.scope_access_via) {
|
|
116
|
-
//
|
|
115
|
+
// Try to find the scope in user's cached scope assignments first.
|
|
116
|
+
// For global admins the scope may not be in their cache (they can access any scope),
|
|
117
|
+
// in which case we fall through to the permission-based fetch below.
|
|
117
118
|
const access_scope = user_scopes.find((s) => { var _a; return s.id === ((_a = auth_result.scope_access_via) === null || _a === void 0 ? void 0 : _a.scope_id); });
|
|
118
119
|
if (access_scope) {
|
|
119
|
-
organization = build_tenant_organization(access_scope
|
|
120
|
+
organization = build_tenant_organization(access_scope);
|
|
120
121
|
}
|
|
121
|
-
else if (auth_result.
|
|
122
|
-
//
|
|
122
|
+
else if (auth_result.permissions.includes(GLOBAL_ADMIN_PERMISSION)) {
|
|
123
|
+
// Global admin accessing a scope they aren't directly assigned to — fetch scope details
|
|
123
124
|
const hazoConnect = get_hazo_connect_instance();
|
|
124
125
|
const scope_result = await get_scope_by_id(hazoConnect, scope_id);
|
|
125
126
|
if (scope_result.success && scope_result.scope) {
|
|
@@ -128,8 +129,7 @@ export async function hazo_get_tenant_auth(request, options = {}) {
|
|
|
128
129
|
name: scope_result.scope.name,
|
|
129
130
|
slug: null, // Could fetch from scope if slug column exists
|
|
130
131
|
level: scope_result.scope.level,
|
|
131
|
-
role_id: "", //
|
|
132
|
-
is_super_admin: true,
|
|
132
|
+
role_id: "", // Global admin doesn't have a role assignment in the scope
|
|
133
133
|
branding: scope_result.scope.logo_url
|
|
134
134
|
? {
|
|
135
135
|
logo_url: scope_result.scope.logo_url,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config_loader.server.d.ts","sourceRoot":"","sources":["../../../src/lib/config/config_loader.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"config_loader.server.d.ts","sourceRoot":"","sources":["../../../src/lib/config/config_loader.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AA8DrB;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAwBpC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAQR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAMR;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,OAAO,EACtB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAST;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAeR;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EAAE,EACvB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,EAAE,CAcV"}
|
|
@@ -8,6 +8,14 @@ import fs from "fs";
|
|
|
8
8
|
import { create_app_logger } from "../app_logger.js";
|
|
9
9
|
// section: constants
|
|
10
10
|
const DEFAULT_CONFIG_FILE = "config/hazo_auth_config.ini";
|
|
11
|
+
// section: config_instance_cache
|
|
12
|
+
// Cache HazoConfig instances by resolved file path so we never construct (and re-parse)
|
|
13
|
+
// more than one instance per config file per server process. This prevents repeated
|
|
14
|
+
// warnings when multiple getters read the same file in a single request, and eliminates
|
|
15
|
+
// redundant synchronous file I/O.
|
|
16
|
+
const _config_instance_cache = new Map();
|
|
17
|
+
// Track paths that failed to construct so we don't retry and warn repeatedly.
|
|
18
|
+
const _config_failed_paths = new Set();
|
|
11
19
|
// section: helpers
|
|
12
20
|
/**
|
|
13
21
|
* Gets the default config file path
|
|
@@ -20,6 +28,33 @@ function get_config_file_path(custom_path) {
|
|
|
20
28
|
}
|
|
21
29
|
return path.resolve(process.cwd(), DEFAULT_CONFIG_FILE);
|
|
22
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Returns a cached HazoConfig instance for the given path, constructing one if needed.
|
|
33
|
+
* Returns null if construction fails (logs the error once on first failure).
|
|
34
|
+
*/
|
|
35
|
+
function get_config_instance(config_path, logger) {
|
|
36
|
+
const cached = _config_instance_cache.get(config_path);
|
|
37
|
+
if (cached)
|
|
38
|
+
return cached;
|
|
39
|
+
if (_config_failed_paths.has(config_path))
|
|
40
|
+
return null;
|
|
41
|
+
try {
|
|
42
|
+
const instance = new HazoConfig({ filePath: config_path });
|
|
43
|
+
_config_instance_cache.set(config_path, instance);
|
|
44
|
+
return instance;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
_config_failed_paths.add(config_path);
|
|
48
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
49
|
+
logger.warn("config_loader_construct_failed", {
|
|
50
|
+
filename: "config_loader.server.ts",
|
|
51
|
+
line_number: 0,
|
|
52
|
+
config_path,
|
|
53
|
+
error: error_message,
|
|
54
|
+
});
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
23
58
|
/**
|
|
24
59
|
* Reads a section from the config file
|
|
25
60
|
* @param section_name - Name of the section to read (e.g., "hazo_auth__register_layout")
|
|
@@ -32,10 +67,10 @@ export function read_config_section(section_name, file_path) {
|
|
|
32
67
|
if (!fs.existsSync(config_path)) {
|
|
33
68
|
return undefined;
|
|
34
69
|
}
|
|
70
|
+
const hazo_config = get_config_instance(config_path, logger);
|
|
71
|
+
if (!hazo_config)
|
|
72
|
+
return undefined;
|
|
35
73
|
try {
|
|
36
|
-
const hazo_config = new HazoConfig({
|
|
37
|
-
filePath: config_path,
|
|
38
|
-
});
|
|
39
74
|
return hazo_config.getSection(section_name);
|
|
40
75
|
}
|
|
41
76
|
catch (error) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// file_description: Zod-validated config loader for hazo_auth core settings.
|
|
2
|
-
// Covers server-critical sections ([hazo_auth__tokens], [hazo_auth__cookies], [hazo_auth__rate_limit], [
|
|
2
|
+
// Covers server-critical sections ([hazo_auth__tokens], [hazo_auth__cookies], [hazo_auth__rate_limit], [log_overrides]).
|
|
3
3
|
// UI sections (login_layout, register_layout, etc.) are still handled by config_loader.server.ts.
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { loadConfig } from 'hazo_core';
|
package/dist/lib/constants.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export declare const HAZO_AUTH_PERMISSIONS: {
|
|
|
8
8
|
readonly ADMIN_TEST_ACCESS: "admin_test_access";
|
|
9
9
|
};
|
|
10
10
|
export declare const ALL_ADMIN_PERMISSIONS: string[];
|
|
11
|
+
export declare const GLOBAL_ADMIN_PERMISSION = "hazo_org_global_admin";
|
|
11
12
|
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB;;;;;;;;CAQxB,CAAC;AAEX,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAAyC,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/lib/constants.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,qBAAqB;;;;;;;;CAQxB,CAAC;AAEX,eAAO,MAAM,qBAAqB,EAAE,MAAM,EAAyC,CAAC;AAEpF,eAAO,MAAM,uBAAuB,0BAA0B,CAAC"}
|
package/dist/lib/constants.js
CHANGED
|
@@ -13,6 +13,7 @@ export declare function create_sqlite_hazo_connect_server(): import("hazo_connec
|
|
|
13
13
|
export declare function get_hazo_connect_config_options(): {
|
|
14
14
|
type?: "sqlite" | "postgrest";
|
|
15
15
|
sqlitePath?: string;
|
|
16
|
+
sqliteDriver?: "sql.js" | "better-sqlite3";
|
|
16
17
|
enableAdminUi?: boolean;
|
|
17
18
|
readOnly?: boolean;
|
|
18
19
|
baseUrl?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_connect_setup.server.d.ts","sourceRoot":"","sources":["../../src/lib/hazo_connect_setup.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"hazo_connect_setup.server.d.ts","sourceRoot":"","sources":["../../src/lib/hazo_connect_setup.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AA0KrB;;;;GAIG;AACH,wBAAgB,iCAAiC,8CA2BhD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI;IACjD,IAAI,CAAC,EAAE,QAAQ,GAAG,WAAW,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,QAAQ,GAAG,gBAAgB,CAAC;IAC3C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAuBA"}
|
|
@@ -60,9 +60,16 @@ function get_hazo_connect_config() {
|
|
|
60
60
|
"or set HAZO_CONNECT_SQLITE_PATH environment variable.",
|
|
61
61
|
});
|
|
62
62
|
}
|
|
63
|
+
// SQLite driver: 'sql.js' (default, WAL-unaware WASM) or 'better-sqlite3' (native, WAL-aware).
|
|
64
|
+
// Forwarded to hazo_connect's factory as sqlite.driver. Defaults to undefined so hazo_connect
|
|
65
|
+
// keeps its own default ('sql.js') when unset — no behavior change.
|
|
66
|
+
const sqlite_driver_raw = (hazo_connect_section === null || hazo_connect_section === void 0 ? void 0 : hazo_connect_section.sqlite_driver) || process.env.HAZO_CONNECT_SQLITE_DRIVER;
|
|
67
|
+
const sqliteDriver = sqlite_driver_raw === "better-sqlite3" || sqlite_driver_raw === "sql.js"
|
|
68
|
+
? sqlite_driver_raw
|
|
69
|
+
: undefined;
|
|
63
70
|
// Validate config keys for typos
|
|
64
71
|
if (hazo_connect_section) {
|
|
65
|
-
const known_keys = ["type", "sqlite_path", "enable_admin_ui", "read_only", "postgrest_url"];
|
|
72
|
+
const known_keys = ["type", "sqlite_path", "sqlite_driver", "enable_admin_ui", "read_only", "postgrest_url"];
|
|
66
73
|
for (const key of Object.keys(hazo_connect_section)) {
|
|
67
74
|
if (!known_keys.includes(key)) {
|
|
68
75
|
// Simple similarity check for common typos
|
|
@@ -86,6 +93,7 @@ function get_hazo_connect_config() {
|
|
|
86
93
|
return {
|
|
87
94
|
type: "sqlite",
|
|
88
95
|
sqlitePath: sqlite_path,
|
|
96
|
+
sqliteDriver,
|
|
89
97
|
enableAdminUi,
|
|
90
98
|
readOnly,
|
|
91
99
|
};
|
|
@@ -130,8 +138,12 @@ export function create_sqlite_hazo_connect_server() {
|
|
|
130
138
|
if (config.type === "sqlite") {
|
|
131
139
|
return createHazoConnect({
|
|
132
140
|
type: "sqlite",
|
|
133
|
-
database: config.sqlitePath,
|
|
134
141
|
enable_admin_ui: config.enableAdminUi,
|
|
142
|
+
sqlite: {
|
|
143
|
+
database_path: config.sqlitePath,
|
|
144
|
+
read_only: config.readOnly,
|
|
145
|
+
driver: config.sqliteDriver,
|
|
146
|
+
},
|
|
135
147
|
});
|
|
136
148
|
}
|
|
137
149
|
if (config.type === "postgrest") {
|
|
@@ -156,6 +168,7 @@ export function get_hazo_connect_config_options() {
|
|
|
156
168
|
return {
|
|
157
169
|
type: "sqlite",
|
|
158
170
|
sqlitePath: config.sqlitePath,
|
|
171
|
+
sqliteDriver: config.sqliteDriver,
|
|
159
172
|
enableAdminUi: config.enableAdminUi,
|
|
160
173
|
readOnly: config.readOnly,
|
|
161
174
|
};
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import "server-only";
|
|
2
|
-
export type MenuItemType = "info" | "link" | "separator";
|
|
2
|
+
export type MenuItemType = "info" | "link" | "separator" | "action";
|
|
3
3
|
export type ProfilePicMenuMenuItem = {
|
|
4
4
|
type: MenuItemType;
|
|
5
5
|
label?: string;
|
|
6
6
|
value?: string;
|
|
7
7
|
href?: string;
|
|
8
|
+
onSelect?: () => void;
|
|
8
9
|
order: number;
|
|
9
10
|
id: string;
|
|
10
11
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile_pic_menu_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/profile_pic_menu_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAQrB,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"profile_pic_menu_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/profile_pic_menu_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAQrB,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEpE,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;CAC7C,CAAC;AA4EF;;;;GAIG;AACH,wBAAgB,2BAA2B,IAAI,oBAAoB,CA4BlE"}
|
|
@@ -20,7 +20,7 @@ function parse_custom_menu_items(items_string) {
|
|
|
20
20
|
}
|
|
21
21
|
const type = parts[0];
|
|
22
22
|
if (type !== "info" && type !== "link" && type !== "separator") {
|
|
23
|
-
return; // Invalid type,
|
|
23
|
+
return; // Invalid type or action (action items carry callbacks, not expressible in INI)
|
|
24
24
|
}
|
|
25
25
|
if (type === "separator") {
|
|
26
26
|
const order = parseInt(parts[1] || "1", 10);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SQLITE_SCHEMA = "\n-- hazo_auth canonical SQLite schema\n-- This schema creates all tables required by hazo_auth\n\n-- Users table (from migration 011)\nCREATE TABLE IF NOT EXISTS hazo_users (\n id TEXT PRIMARY KEY,\n email_address TEXT NOT NULL UNIQUE,\n password_hash TEXT,\n name TEXT,\n email_verified BOOLEAN DEFAULT false,\n login_attempts INTEGER DEFAULT 0,\n last_logon TEXT,\n profile_picture_url TEXT,\n profile_source TEXT CHECK(profile_source IN ('gravatar', 'custom', 'predefined')),\n mfa_secret TEXT,\n url_on_logon TEXT,\n google_id TEXT UNIQUE,\n auth_providers TEXT DEFAULT 'email',\n user_type TEXT,\n app_user_data TEXT,\n status TEXT DEFAULT 'ACTIVE' CHECK(status IN ('PENDING', 'ACTIVE', 'BLOCKED')),\n managed_by_user_id TEXT REFERENCES hazo_users(id) ON DELETE SET NULL,\n pin_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_users_email ON hazo_users(email_address);\nCREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_users_status ON hazo_users(status);\n\n-- Refresh tokens table\n-- Note: runtime (token_service.ts) writes token_hash (argon2-hashed value) on\n-- insert and verifies via argon2.verify(token_hash, plaintext_token) on read.\n-- The plaintext \"token\" column is retained nullable for legacy compatibility\n-- but new writes only set token_hash.\nCREATE TABLE IF NOT EXISTS hazo_refresh_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,\n token TEXT UNIQUE,\n token_hash TEXT,\n token_type TEXT DEFAULT 'refresh',\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_user ON hazo_refresh_tokens(user_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token ON hazo_refresh_tokens(token);\nCREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token_hash ON hazo_refresh_tokens(token_hash);\n\n-- Roles table\nCREATE TABLE IF NOT EXISTS hazo_roles (\n id TEXT PRIMARY KEY,\n role_name TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Permissions table\nCREATE TABLE IF NOT EXISTS hazo_permissions (\n id TEXT PRIMARY KEY,\n permission_name TEXT NOT NULL UNIQUE,\n description TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Role-permission assignments (composite PK, no id column)\nCREATE TABLE IF NOT EXISTS hazo_role_permissions (\n role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,\n permission_id TEXT NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (role_id, permission_id)\n);\n\n-- Unified scopes table (hierarchical multi-tenancy)\nCREATE TABLE IF NOT EXISTS hazo_scopes (\n id TEXT PRIMARY KEY,\n parent_id TEXT REFERENCES hazo_scopes(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n level TEXT NOT NULL,\n logo_url TEXT,\n primary_color TEXT,\n secondary_color TEXT,\n tagline TEXT,\n slug TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_scopes_parent ON hazo_scopes(parent_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_scopes_level ON hazo_scopes(level);\nCREATE INDEX IF NOT EXISTS idx_hazo_scopes_slug ON hazo_scopes(slug);\n\n--
|
|
1
|
+
export declare const SQLITE_SCHEMA = "\n-- hazo_auth canonical SQLite schema\n-- This schema creates all tables required by hazo_auth\n\n-- Users table (from migration 011)\nCREATE TABLE IF NOT EXISTS hazo_users (\n id TEXT PRIMARY KEY,\n email_address TEXT NOT NULL UNIQUE,\n password_hash TEXT,\n name TEXT,\n email_verified BOOLEAN DEFAULT false,\n login_attempts INTEGER DEFAULT 0,\n last_logon TEXT,\n profile_picture_url TEXT,\n profile_source TEXT CHECK(profile_source IN ('gravatar', 'custom', 'predefined')),\n mfa_secret TEXT,\n url_on_logon TEXT,\n google_id TEXT UNIQUE,\n auth_providers TEXT DEFAULT 'email',\n user_type TEXT,\n app_user_data TEXT,\n status TEXT DEFAULT 'ACTIVE' CHECK(status IN ('PENDING', 'ACTIVE', 'BLOCKED')),\n managed_by_user_id TEXT REFERENCES hazo_users(id) ON DELETE SET NULL,\n pin_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_users_email ON hazo_users(email_address);\nCREATE INDEX IF NOT EXISTS idx_hazo_users_google_id ON hazo_users(google_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_users_status ON hazo_users(status);\n\n-- Refresh tokens table\n-- Note: runtime (token_service.ts) writes token_hash (argon2-hashed value) on\n-- insert and verifies via argon2.verify(token_hash, plaintext_token) on read.\n-- The plaintext \"token\" column is retained nullable for legacy compatibility\n-- but new writes only set token_hash.\nCREATE TABLE IF NOT EXISTS hazo_refresh_tokens (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,\n token TEXT UNIQUE,\n token_hash TEXT,\n token_type TEXT DEFAULT 'refresh',\n expires_at TEXT NOT NULL,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_user ON hazo_refresh_tokens(user_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token ON hazo_refresh_tokens(token);\nCREATE INDEX IF NOT EXISTS idx_hazo_refresh_tokens_token_hash ON hazo_refresh_tokens(token_hash);\n\n-- Roles table\nCREATE TABLE IF NOT EXISTS hazo_roles (\n id TEXT PRIMARY KEY,\n role_name TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Permissions table\nCREATE TABLE IF NOT EXISTS hazo_permissions (\n id TEXT PRIMARY KEY,\n permission_name TEXT NOT NULL UNIQUE,\n description TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\n-- Role-permission assignments (composite PK, no id column)\nCREATE TABLE IF NOT EXISTS hazo_role_permissions (\n role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,\n permission_id TEXT NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (role_id, permission_id)\n);\n\n-- Unified scopes table (hierarchical multi-tenancy)\nCREATE TABLE IF NOT EXISTS hazo_scopes (\n id TEXT PRIMARY KEY,\n parent_id TEXT REFERENCES hazo_scopes(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n level TEXT NOT NULL,\n logo_url TEXT,\n primary_color TEXT,\n secondary_color TEXT,\n tagline TEXT,\n slug TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_scopes_parent ON hazo_scopes(parent_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_scopes_level ON hazo_scopes(level);\nCREATE INDEX IF NOT EXISTS idx_hazo_scopes_slug ON hazo_scopes(slug);\n\n-- Default system scope (for non-multi-tenancy mode)\nINSERT OR IGNORE INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)\nVALUES ('00000000-0000-0000-0000-000000000001', NULL, 'System', 'default', datetime('now'), datetime('now'));\n\n-- User-scope assignments (membership model with scope-specific roles)\nCREATE TABLE IF NOT EXISTS hazo_user_scopes (\n user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,\n scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,\n root_scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,\n role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,\n status TEXT DEFAULT 'ACTIVE' CHECK (status IN ('INVITED', 'ACTIVE', 'SUSPENDED', 'DEPARTED')),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now')),\n PRIMARY KEY (user_id, scope_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_user_scopes_scope ON hazo_user_scopes(scope_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_user_scopes_root ON hazo_user_scopes(root_scope_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_user_scopes_role ON hazo_user_scopes(role_id);\n\n-- Invitations table\nCREATE TABLE IF NOT EXISTS hazo_invitations (\n id TEXT PRIMARY KEY,\n email_address TEXT NOT NULL,\n token TEXT NOT NULL UNIQUE,\n scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,\n root_scope_id TEXT NOT NULL REFERENCES hazo_scopes(id) ON DELETE CASCADE,\n role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,\n invited_by TEXT REFERENCES hazo_users(id) ON DELETE SET NULL,\n status TEXT NOT NULL DEFAULT 'PENDING' CHECK(status IN ('PENDING', 'ACCEPTED', 'EXPIRED', 'REVOKED')),\n expires_at TEXT NOT NULL,\n accepted_at TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n changed_at TEXT NOT NULL DEFAULT (datetime('now'))\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_invitations_email ON hazo_invitations(email_address);\nCREATE INDEX IF NOT EXISTS idx_hazo_invitations_token ON hazo_invitations(token);\nCREATE INDEX IF NOT EXISTS idx_hazo_invitations_scope ON hazo_invitations(scope_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_invitations_status ON hazo_invitations(status);\nCREATE INDEX IF NOT EXISTS idx_hazo_invitations_expires ON hazo_invitations(expires_at);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_users_managed_by ON hazo_users(managed_by_user_id);\n\n-- Relationships table\nCREATE TABLE IF NOT EXISTS hazo_user_relationships (\n id TEXT PRIMARY KEY,\n parent_user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,\n child_user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,\n relationship_type TEXT NOT NULL DEFAULT 'parent',\n can_view_progress BOOLEAN DEFAULT true,\n can_edit_profile BOOLEAN DEFAULT true,\n can_delete BOOLEAN DEFAULT false,\n is_self BOOLEAN DEFAULT false,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n UNIQUE(parent_user_id, child_user_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_hazo_user_relationships_parent ON hazo_user_relationships(parent_user_id);\nCREATE INDEX IF NOT EXISTS idx_hazo_user_relationships_child ON hazo_user_relationships(child_user_id);\n\n-- Firm admin role (for firm creators)\nINSERT OR IGNORE INTO hazo_roles (id, role_name, created_at, changed_at)\nVALUES (lower(hex(randomblob(4)) || '-' || hex(randomblob(2)) || '-4' || substr(hex(randomblob(2)),2) || '-' || substr('89ab',abs(random()) % 4 + 1, 1) || substr(hex(randomblob(2)),2) || '-' || hex(randomblob(6))), 'firm_admin', datetime('now'), datetime('now'));\n";
|
|
2
2
|
//# sourceMappingURL=sqlite_schema.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite_schema.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/sqlite_schema.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"sqlite_schema.d.ts","sourceRoot":"","sources":["../../../src/lib/schema/sqlite_schema.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,aAAa,ogOA+JzB,CAAC"}
|
|
@@ -96,10 +96,6 @@ CREATE INDEX IF NOT EXISTS idx_hazo_scopes_parent ON hazo_scopes(parent_id);
|
|
|
96
96
|
CREATE INDEX IF NOT EXISTS idx_hazo_scopes_level ON hazo_scopes(level);
|
|
97
97
|
CREATE INDEX IF NOT EXISTS idx_hazo_scopes_slug ON hazo_scopes(slug);
|
|
98
98
|
|
|
99
|
-
-- Super admin scope
|
|
100
|
-
INSERT OR IGNORE INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)
|
|
101
|
-
VALUES ('00000000-0000-0000-0000-000000000000', NULL, 'Super Admin', 'system', datetime('now'), datetime('now'));
|
|
102
|
-
|
|
103
99
|
-- Default system scope (for non-multi-tenancy mode)
|
|
104
100
|
INSERT OR IGNORE INTO hazo_scopes (id, parent_id, name, level, created_at, changed_at)
|
|
105
101
|
VALUES ('00000000-0000-0000-0000-000000000001', NULL, 'System', 'default', datetime('now'), datetime('now'));
|
|
@@ -10,8 +10,6 @@ export type ScopeHierarchyConfig = {
|
|
|
10
10
|
scope_cache_ttl_minutes: number;
|
|
11
11
|
/** Maximum entries in scope cache (default: 5000) */
|
|
12
12
|
scope_cache_max_entries: number;
|
|
13
|
-
/** Super admin scope ID */
|
|
14
|
-
super_admin_scope_id: string;
|
|
15
13
|
/** Default system scope ID (for non-multi-tenancy mode) */
|
|
16
14
|
default_system_scope_id: string;
|
|
17
15
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope_hierarchy_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/scope_hierarchy_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAYrB;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,gDAAgD;IAChD,YAAY,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,uBAAuB,EAAE,MAAM,CAAC;IAChC,qDAAqD;IACrD,uBAAuB,EAAE,MAAM,CAAC;IAChC,
|
|
1
|
+
{"version":3,"file":"scope_hierarchy_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/scope_hierarchy_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAYrB;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,gDAAgD;IAChD,YAAY,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,uBAAuB,EAAE,MAAM,CAAC;IAChC,qDAAqD;IACrD,uBAAuB,EAAE,MAAM,CAAC;IAChC,2DAA2D;IAC3D,uBAAuB,EAAE,MAAM,CAAC;CACjC,CAAC;AAQF;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,oBAAoB,CA6BjE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import "server-only";
|
|
4
4
|
// section: imports
|
|
5
5
|
import { get_config_value, get_config_number, get_config_boolean, } from "./config/config_loader.server.js";
|
|
6
|
-
import {
|
|
6
|
+
import { DEFAULT_SYSTEM_SCOPE_ID } from "./services/scope_service.js";
|
|
7
7
|
// section: constants
|
|
8
8
|
const SECTION_NAME = "hazo_auth__scope_hierarchy";
|
|
9
9
|
// section: helpers
|
|
@@ -19,13 +19,11 @@ export function get_scope_hierarchy_config() {
|
|
|
19
19
|
const scope_cache_ttl_minutes = get_config_number(SECTION_NAME, "scope_cache_ttl_minutes", 15);
|
|
20
20
|
const scope_cache_max_entries = get_config_number(SECTION_NAME, "scope_cache_max_entries", 5000);
|
|
21
21
|
// Scope IDs (with defaults)
|
|
22
|
-
const super_admin_scope_id = get_config_value(SECTION_NAME, "super_admin_scope_id", SUPER_ADMIN_SCOPE_ID);
|
|
23
22
|
const default_system_scope_id = get_config_value(SECTION_NAME, "default_system_scope_id", DEFAULT_SYSTEM_SCOPE_ID);
|
|
24
23
|
return {
|
|
25
24
|
enable_hrbac,
|
|
26
25
|
scope_cache_ttl_minutes,
|
|
27
26
|
scope_cache_max_entries,
|
|
28
|
-
super_admin_scope_id,
|
|
29
27
|
default_system_scope_id,
|
|
30
28
|
};
|
|
31
29
|
}
|
|
@@ -53,7 +53,7 @@ export declare function revoke_invitation(adapter: HazoConnectAdapter, invitatio
|
|
|
53
53
|
*/
|
|
54
54
|
export declare function list_invitations_by_scope(adapter: HazoConnectAdapter, scope_id: string, status?: InvitationStatus): Promise<InvitationServiceResult>;
|
|
55
55
|
/**
|
|
56
|
-
* Lists all invitations (for
|
|
56
|
+
* Lists all invitations (for global admins)
|
|
57
57
|
*/
|
|
58
58
|
export declare function list_all_invitations(adapter: HazoConnectAdapter, status?: InvitationStatus): Promise<InvitationServiceResult>;
|
|
59
59
|
/**
|
|
@@ -365,7 +365,7 @@ export async function list_invitations_by_scope(adapter, scope_id, status) {
|
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
367
|
/**
|
|
368
|
-
* Lists all invitations (for
|
|
368
|
+
* Lists all invitations (for global admins)
|
|
369
369
|
*/
|
|
370
370
|
export async function list_all_invitations(adapter, status) {
|
|
371
371
|
try {
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import type { HazoConnectAdapter } from "hazo_connect";
|
|
2
|
-
/**
|
|
3
|
-
* Super admin scope ID - special UUID for system-level administrators
|
|
4
|
-
* Users assigned to this scope have global access
|
|
5
|
-
*/
|
|
6
|
-
export declare const SUPER_ADMIN_SCOPE_ID = "00000000-0000-0000-0000-000000000000";
|
|
7
2
|
/**
|
|
8
3
|
* Default system scope ID - for non-multi-tenancy mode
|
|
9
4
|
* All users are assigned to this scope when multi-tenancy is disabled
|
|
@@ -67,16 +62,12 @@ export declare function extract_branding(scope: ScopeRecord): FirmBranding | nul
|
|
|
67
62
|
* Checks if a scope has any branding set
|
|
68
63
|
*/
|
|
69
64
|
export declare function has_branding(scope: ScopeRecord): boolean;
|
|
70
|
-
/**
|
|
71
|
-
* Checks if the given scope_id is the super admin scope
|
|
72
|
-
*/
|
|
73
|
-
export declare function is_super_admin_scope(scope_id: string): boolean;
|
|
74
65
|
/**
|
|
75
66
|
* Checks if the given scope_id is the default system scope
|
|
76
67
|
*/
|
|
77
68
|
export declare function is_default_system_scope(scope_id: string): boolean;
|
|
78
69
|
/**
|
|
79
|
-
* Checks if the given scope_id is a system scope (
|
|
70
|
+
* Checks if the given scope_id is a system scope (default system)
|
|
80
71
|
*/
|
|
81
72
|
export declare function is_system_scope(scope_id: string): boolean;
|
|
82
73
|
/**
|
|
@@ -133,10 +124,6 @@ export declare function get_scope_tree(adapter: HazoConnectAdapter, root_scope_i
|
|
|
133
124
|
tree?: ScopeTreeNode[];
|
|
134
125
|
error?: string;
|
|
135
126
|
}>;
|
|
136
|
-
/**
|
|
137
|
-
* Ensures the super admin scope exists
|
|
138
|
-
*/
|
|
139
|
-
export declare function ensure_super_admin_scope(adapter: HazoConnectAdapter): Promise<ScopeServiceResult>;
|
|
140
127
|
/**
|
|
141
128
|
* Ensures the default system scope exists
|
|
142
129
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/scope_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOvD;;;GAGG;AACH,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"scope_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/scope_service.ts"],"names":[],"mappings":"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"}
|