hazo_auth 4.2.0 → 4.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.
Files changed (82) hide show
  1. package/bin/hazo_auth.mjs +35 -0
  2. package/cli-src/assets/images/forgot_password_default.jpg +0 -0
  3. package/cli-src/assets/images/login_default.jpg +0 -0
  4. package/cli-src/assets/images/register_default.jpg +0 -0
  5. package/cli-src/assets/images/reset_password_default.jpg +0 -0
  6. package/cli-src/assets/images/verify_email_default.jpg +0 -0
  7. package/cli-src/cli/generate.ts +276 -0
  8. package/cli-src/cli/index.ts +207 -0
  9. package/cli-src/cli/init.ts +254 -0
  10. package/cli-src/cli/init_users.ts +376 -0
  11. package/cli-src/cli/validate.ts +581 -0
  12. package/cli-src/lib/already_logged_in_config.server.ts +46 -0
  13. package/cli-src/lib/app_logger.ts +24 -0
  14. package/cli-src/lib/auth/auth_cache.ts +220 -0
  15. package/cli-src/lib/auth/auth_rate_limiter.ts +121 -0
  16. package/cli-src/lib/auth/auth_types.ts +110 -0
  17. package/cli-src/lib/auth/auth_utils.server.ts +196 -0
  18. package/cli-src/lib/auth/hazo_get_auth.server.ts +512 -0
  19. package/cli-src/lib/auth/index.ts +23 -0
  20. package/cli-src/lib/auth/nextauth_config.ts +227 -0
  21. package/cli-src/lib/auth/scope_cache.ts +233 -0
  22. package/cli-src/lib/auth/server_auth.ts +88 -0
  23. package/cli-src/lib/auth/session_token_validator.edge.ts +91 -0
  24. package/cli-src/lib/auth_utility_config.server.ts +136 -0
  25. package/cli-src/lib/config/config_loader.server.ts +164 -0
  26. package/cli-src/lib/config/default_config.ts +199 -0
  27. package/cli-src/lib/email_verification_config.server.ts +63 -0
  28. package/cli-src/lib/file_types_config.server.ts +25 -0
  29. package/cli-src/lib/forgot_password_config.server.ts +63 -0
  30. package/cli-src/lib/hazo_connect_instance.server.ts +101 -0
  31. package/cli-src/lib/hazo_connect_setup.server.ts +194 -0
  32. package/cli-src/lib/hazo_connect_setup.ts +54 -0
  33. package/cli-src/lib/index.ts +46 -0
  34. package/cli-src/lib/login_config.server.ts +106 -0
  35. package/cli-src/lib/messages_config.server.ts +45 -0
  36. package/cli-src/lib/migrations/apply_migration.ts +105 -0
  37. package/cli-src/lib/my_settings_config.server.ts +135 -0
  38. package/cli-src/lib/oauth_config.server.ts +87 -0
  39. package/cli-src/lib/password_requirements_config.server.ts +40 -0
  40. package/cli-src/lib/profile_pic_menu_config.server.ts +138 -0
  41. package/cli-src/lib/profile_picture_config.server.ts +56 -0
  42. package/cli-src/lib/register_config.server.ts +101 -0
  43. package/cli-src/lib/reset_password_config.server.ts +103 -0
  44. package/cli-src/lib/scope_hierarchy_config.server.ts +151 -0
  45. package/cli-src/lib/services/email_service.ts +587 -0
  46. package/cli-src/lib/services/email_verification_service.ts +270 -0
  47. package/cli-src/lib/services/index.ts +16 -0
  48. package/cli-src/lib/services/login_service.ts +150 -0
  49. package/cli-src/lib/services/oauth_service.ts +494 -0
  50. package/cli-src/lib/services/password_change_service.ts +154 -0
  51. package/cli-src/lib/services/password_reset_service.ts +418 -0
  52. package/cli-src/lib/services/profile_picture_remove_service.ts +120 -0
  53. package/cli-src/lib/services/profile_picture_service.ts +451 -0
  54. package/cli-src/lib/services/profile_picture_source_mapper.ts +62 -0
  55. package/cli-src/lib/services/registration_service.ts +185 -0
  56. package/cli-src/lib/services/scope_labels_service.ts +348 -0
  57. package/cli-src/lib/services/scope_service.ts +778 -0
  58. package/cli-src/lib/services/session_token_service.ts +177 -0
  59. package/cli-src/lib/services/token_service.ts +240 -0
  60. package/cli-src/lib/services/user_profiles_cache.ts +189 -0
  61. package/cli-src/lib/services/user_profiles_service.ts +264 -0
  62. package/cli-src/lib/services/user_scope_service.ts +554 -0
  63. package/cli-src/lib/services/user_update_service.ts +141 -0
  64. package/cli-src/lib/ui_shell_config.server.ts +73 -0
  65. package/cli-src/lib/ui_sizes_config.server.ts +37 -0
  66. package/cli-src/lib/user_fields_config.server.ts +31 -0
  67. package/cli-src/lib/user_management_config.server.ts +39 -0
  68. package/cli-src/lib/user_profiles_config.server.ts +55 -0
  69. package/cli-src/lib/utils/api_route_helpers.ts +60 -0
  70. package/cli-src/lib/utils/error_sanitizer.ts +75 -0
  71. package/cli-src/lib/utils/password_validator.ts +65 -0
  72. package/cli-src/lib/utils.ts +11 -0
  73. package/cli-src/server/logging/logger_service.ts +56 -0
  74. package/dist/cli/index.js +18 -0
  75. package/dist/cli/init_users.d.ts +17 -0
  76. package/dist/cli/init_users.d.ts.map +1 -0
  77. package/dist/cli/init_users.js +307 -0
  78. package/dist/components/layouts/shared/config/layout_customization.d.ts +2 -7
  79. package/dist/components/layouts/shared/config/layout_customization.d.ts.map +1 -1
  80. package/dist/lib/utils/password_validator.d.ts +7 -1
  81. package/dist/lib/utils/password_validator.d.ts.map +1 -1
  82. package/package.json +5 -2
@@ -0,0 +1,348 @@
1
+ // file_description: service for managing HRBAC scope labels using hazo_connect
2
+ // section: imports
3
+ import type { HazoConnectAdapter } from "hazo_connect";
4
+ import { createCrudService } from "hazo_connect/server";
5
+ import { randomUUID } from "crypto";
6
+ import { create_app_logger } from "../app_logger";
7
+ import { sanitize_error_for_user } from "../utils/error_sanitizer";
8
+ import type { ScopeLevel } from "./scope_service";
9
+ import { SCOPE_LEVELS } from "./scope_service";
10
+
11
+ // section: types
12
+ export type ScopeLabel = {
13
+ id: string;
14
+ org: string;
15
+ scope_type: ScopeLevel;
16
+ label: string;
17
+ created_at: string;
18
+ changed_at: string;
19
+ };
20
+
21
+ export type ScopeLabelResult = {
22
+ success: boolean;
23
+ label?: ScopeLabel;
24
+ labels?: ScopeLabel[];
25
+ error?: string;
26
+ };
27
+
28
+ // section: constants
29
+ export const DEFAULT_SCOPE_LABELS: Record<ScopeLevel, string> = {
30
+ hazo_scopes_l1: "Level 1",
31
+ hazo_scopes_l2: "Level 2",
32
+ hazo_scopes_l3: "Level 3",
33
+ hazo_scopes_l4: "Level 4",
34
+ hazo_scopes_l5: "Level 5",
35
+ hazo_scopes_l6: "Level 6",
36
+ hazo_scopes_l7: "Level 7",
37
+ };
38
+
39
+ // section: helpers
40
+
41
+ /**
42
+ * Gets all scope labels for an organization
43
+ */
44
+ export async function get_scope_labels(
45
+ adapter: HazoConnectAdapter,
46
+ org: string,
47
+ ): Promise<ScopeLabelResult> {
48
+ try {
49
+ const label_service = createCrudService(adapter, "hazo_scope_labels");
50
+ const labels = await label_service.findBy({ org });
51
+
52
+ return {
53
+ success: true,
54
+ labels: Array.isArray(labels) ? (labels as ScopeLabel[]) : [],
55
+ };
56
+ } catch (error) {
57
+ const logger = create_app_logger();
58
+ const error_message = sanitize_error_for_user(error, {
59
+ logToConsole: true,
60
+ logToLogger: true,
61
+ logger,
62
+ context: {
63
+ filename: "scope_labels_service.ts",
64
+ line_number: 0,
65
+ operation: "get_scope_labels",
66
+ org,
67
+ },
68
+ });
69
+
70
+ return {
71
+ success: false,
72
+ error: error_message,
73
+ };
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Gets all scope labels for an organization, with defaults filled in for missing levels
79
+ */
80
+ export async function get_scope_labels_with_defaults(
81
+ adapter: HazoConnectAdapter,
82
+ org: string,
83
+ custom_defaults?: Record<ScopeLevel, string>,
84
+ ): Promise<ScopeLabelResult> {
85
+ try {
86
+ const result = await get_scope_labels(adapter, org);
87
+ if (!result.success) {
88
+ return result;
89
+ }
90
+
91
+ const existing_labels = result.labels || [];
92
+ const labels_map = new Map<ScopeLevel, ScopeLabel>();
93
+
94
+ // Add existing labels to map
95
+ for (const label of existing_labels) {
96
+ labels_map.set(label.scope_type, label);
97
+ }
98
+
99
+ // Create synthetic entries for missing levels (with default labels)
100
+ const defaults = custom_defaults || DEFAULT_SCOPE_LABELS;
101
+ const all_labels: ScopeLabel[] = [];
102
+
103
+ for (const level of SCOPE_LEVELS) {
104
+ if (labels_map.has(level)) {
105
+ all_labels.push(labels_map.get(level)!);
106
+ } else {
107
+ // Create a synthetic label entry (not persisted)
108
+ all_labels.push({
109
+ id: "", // Empty ID indicates this is a default, not from DB
110
+ org,
111
+ scope_type: level,
112
+ label: defaults[level],
113
+ created_at: "",
114
+ changed_at: "",
115
+ });
116
+ }
117
+ }
118
+
119
+ return {
120
+ success: true,
121
+ labels: all_labels,
122
+ };
123
+ } catch (error) {
124
+ const logger = create_app_logger();
125
+ const error_message = sanitize_error_for_user(error, {
126
+ logToConsole: true,
127
+ logToLogger: true,
128
+ logger,
129
+ context: {
130
+ filename: "scope_labels_service.ts",
131
+ line_number: 0,
132
+ operation: "get_scope_labels_with_defaults",
133
+ org,
134
+ },
135
+ });
136
+
137
+ return {
138
+ success: false,
139
+ error: error_message,
140
+ };
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Gets the label for a specific scope level
146
+ * Returns the custom label if set, otherwise returns the default
147
+ */
148
+ export async function get_label_for_level(
149
+ adapter: HazoConnectAdapter,
150
+ org: string,
151
+ scope_type: ScopeLevel,
152
+ custom_default?: string,
153
+ ): Promise<string> {
154
+ try {
155
+ const label_service = createCrudService(adapter, "hazo_scope_labels");
156
+ const labels = await label_service.findBy({ org, scope_type });
157
+
158
+ if (Array.isArray(labels) && labels.length > 0) {
159
+ return (labels[0] as ScopeLabel).label;
160
+ }
161
+
162
+ return custom_default || DEFAULT_SCOPE_LABELS[scope_type];
163
+ } catch {
164
+ // Return default on any error
165
+ return custom_default || DEFAULT_SCOPE_LABELS[scope_type];
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Creates or updates a scope label for an organization
171
+ * Uses upsert pattern - creates if not exists, updates if exists
172
+ */
173
+ export async function upsert_scope_label(
174
+ adapter: HazoConnectAdapter,
175
+ org: string,
176
+ scope_type: ScopeLevel,
177
+ label: string,
178
+ ): Promise<ScopeLabelResult> {
179
+ try {
180
+ const label_service = createCrudService(adapter, "hazo_scope_labels");
181
+ const now = new Date().toISOString();
182
+
183
+ // Check if label already exists for this org + scope_type
184
+ const existing = await label_service.findBy({ org, scope_type });
185
+
186
+ if (Array.isArray(existing) && existing.length > 0) {
187
+ // Update existing
188
+ const existing_label = existing[0] as ScopeLabel;
189
+ const updated = await label_service.updateById(existing_label.id, {
190
+ label,
191
+ changed_at: now,
192
+ });
193
+
194
+ if (!Array.isArray(updated) || updated.length === 0) {
195
+ return {
196
+ success: false,
197
+ error: "Failed to update scope label",
198
+ };
199
+ }
200
+
201
+ return {
202
+ success: true,
203
+ label: updated[0] as ScopeLabel,
204
+ };
205
+ } else {
206
+ // Create new
207
+ const inserted = await label_service.insert({
208
+ id: randomUUID(),
209
+ org,
210
+ scope_type,
211
+ label,
212
+ created_at: now,
213
+ changed_at: now,
214
+ });
215
+
216
+ if (!Array.isArray(inserted) || inserted.length === 0) {
217
+ return {
218
+ success: false,
219
+ error: "Failed to create scope label",
220
+ };
221
+ }
222
+
223
+ return {
224
+ success: true,
225
+ label: inserted[0] as ScopeLabel,
226
+ };
227
+ }
228
+ } catch (error) {
229
+ const logger = create_app_logger();
230
+ const error_message = sanitize_error_for_user(error, {
231
+ logToConsole: true,
232
+ logToLogger: true,
233
+ logger,
234
+ context: {
235
+ filename: "scope_labels_service.ts",
236
+ line_number: 0,
237
+ operation: "upsert_scope_label",
238
+ org,
239
+ scope_type,
240
+ label,
241
+ },
242
+ });
243
+
244
+ return {
245
+ success: false,
246
+ error: error_message,
247
+ };
248
+ }
249
+ }
250
+
251
+ /**
252
+ * Batch upsert scope labels for an organization
253
+ * Useful for saving all labels at once from the UI
254
+ */
255
+ export async function batch_upsert_scope_labels(
256
+ adapter: HazoConnectAdapter,
257
+ org: string,
258
+ labels: Array<{ scope_type: ScopeLevel; label: string }>,
259
+ ): Promise<ScopeLabelResult> {
260
+ try {
261
+ const results: ScopeLabel[] = [];
262
+
263
+ for (const { scope_type, label } of labels) {
264
+ const result = await upsert_scope_label(adapter, org, scope_type, label);
265
+ if (!result.success) {
266
+ return {
267
+ success: false,
268
+ error: `Failed to save label for ${scope_type}: ${result.error}`,
269
+ };
270
+ }
271
+ if (result.label) {
272
+ results.push(result.label);
273
+ }
274
+ }
275
+
276
+ return {
277
+ success: true,
278
+ labels: results,
279
+ };
280
+ } catch (error) {
281
+ const logger = create_app_logger();
282
+ const error_message = sanitize_error_for_user(error, {
283
+ logToConsole: true,
284
+ logToLogger: true,
285
+ logger,
286
+ context: {
287
+ filename: "scope_labels_service.ts",
288
+ line_number: 0,
289
+ operation: "batch_upsert_scope_labels",
290
+ org,
291
+ },
292
+ });
293
+
294
+ return {
295
+ success: false,
296
+ error: error_message,
297
+ };
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Deletes a scope label, reverting to default
303
+ */
304
+ export async function delete_scope_label(
305
+ adapter: HazoConnectAdapter,
306
+ org: string,
307
+ scope_type: ScopeLevel,
308
+ ): Promise<ScopeLabelResult> {
309
+ try {
310
+ const label_service = createCrudService(adapter, "hazo_scope_labels");
311
+
312
+ // Find the label
313
+ const existing = await label_service.findBy({ org, scope_type });
314
+
315
+ if (!Array.isArray(existing) || existing.length === 0) {
316
+ return {
317
+ success: true, // Already doesn't exist
318
+ };
319
+ }
320
+
321
+ const existing_label = existing[0] as ScopeLabel;
322
+ await label_service.deleteById(existing_label.id);
323
+
324
+ return {
325
+ success: true,
326
+ label: existing_label,
327
+ };
328
+ } catch (error) {
329
+ const logger = create_app_logger();
330
+ const error_message = sanitize_error_for_user(error, {
331
+ logToConsole: true,
332
+ logToLogger: true,
333
+ logger,
334
+ context: {
335
+ filename: "scope_labels_service.ts",
336
+ line_number: 0,
337
+ operation: "delete_scope_label",
338
+ org,
339
+ scope_type,
340
+ },
341
+ });
342
+
343
+ return {
344
+ success: false,
345
+ error: error_message,
346
+ };
347
+ }
348
+ }