hazo_auth 1.6.1 → 1.6.4

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 (46) hide show
  1. package/README.md +259 -1
  2. package/SETUP_CHECKLIST.md +89 -3
  3. package/dist/app/api/hazo_auth/me/route.d.ts +30 -1
  4. package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
  5. package/dist/app/api/hazo_auth/me/route.js +76 -16
  6. package/dist/cli/init.d.ts.map +1 -1
  7. package/dist/cli/init.js +5 -0
  8. package/dist/client.d.ts +8 -0
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +25 -0
  11. package/dist/components/layouts/email_verification/index.d.ts +2 -1
  12. package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
  13. package/dist/components/layouts/email_verification/index.js +3 -2
  14. package/dist/components/layouts/forgot_password/index.d.ts +3 -1
  15. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  16. package/dist/components/layouts/forgot_password/index.js +3 -2
  17. package/dist/components/layouts/my_settings/components/editable_field.js +1 -1
  18. package/dist/components/layouts/my_settings/components/password_change_dialog.js +1 -1
  19. package/dist/components/layouts/my_settings/components/profile_picture_display.js +1 -1
  20. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.js +1 -1
  21. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +4 -4
  22. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.js +4 -4
  23. package/dist/components/layouts/my_settings/index.js +1 -1
  24. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts +6 -2
  25. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
  26. package/dist/components/layouts/shared/components/profile_pic_menu.js +41 -6
  27. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts +4 -2
  28. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts.map +1 -1
  29. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.js +3 -3
  30. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  31. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
  32. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +3 -0
  33. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -1
  34. package/dist/components/layouts/shared/hooks/use_auth_status.js +4 -0
  35. package/dist/lib/auth_utility_config.server.js +2 -2
  36. package/dist/lib/services/user_profiles_cache.d.ts +76 -0
  37. package/dist/lib/services/user_profiles_cache.d.ts.map +1 -0
  38. package/dist/lib/services/user_profiles_cache.js +141 -0
  39. package/dist/lib/services/user_profiles_service.d.ts +17 -0
  40. package/dist/lib/services/user_profiles_service.d.ts.map +1 -1
  41. package/dist/lib/services/user_profiles_service.js +136 -44
  42. package/dist/lib/user_profiles_config.server.d.ts +15 -0
  43. package/dist/lib/user_profiles_config.server.d.ts.map +1 -0
  44. package/dist/lib/user_profiles_config.server.js +23 -0
  45. package/hazo_auth_config.example.ini +25 -5
  46. package/package.json +5 -1
@@ -0,0 +1,76 @@
1
+ import type { UserProfileInfo } from "./user_profiles_service";
2
+ /**
3
+ * LRU cache implementation with TTL and size limits for user profiles
4
+ * Uses Map to maintain insertion order for LRU eviction
5
+ */
6
+ declare class UserProfilesCache {
7
+ private cache;
8
+ private max_size;
9
+ private ttl_ms;
10
+ constructor(max_size: number, ttl_minutes: number);
11
+ /**
12
+ * Gets a cached profile for a user
13
+ * Returns undefined if not found or expired
14
+ * @param user_id - User ID to look up
15
+ * @returns Profile or undefined
16
+ */
17
+ get(user_id: string): UserProfileInfo | undefined;
18
+ /**
19
+ * Gets multiple profiles from cache
20
+ * Returns object with found profiles and missing IDs
21
+ * @param user_ids - Array of user IDs to look up
22
+ * @returns Object with cached profiles and IDs not in cache
23
+ */
24
+ get_many(user_ids: string[]): {
25
+ cached: UserProfileInfo[];
26
+ missing_ids: string[];
27
+ };
28
+ /**
29
+ * Sets a cache entry for a user profile
30
+ * Evicts least recently used entries if cache is full
31
+ * @param user_id - User ID
32
+ * @param profile - User profile data
33
+ */
34
+ set(user_id: string, profile: UserProfileInfo): void;
35
+ /**
36
+ * Sets multiple cache entries at once
37
+ * @param profiles - Array of user profiles to cache
38
+ */
39
+ set_many(profiles: UserProfileInfo[]): void;
40
+ /**
41
+ * Invalidates cache for a specific user
42
+ * @param user_id - User ID to invalidate
43
+ */
44
+ invalidate_user(user_id: string): void;
45
+ /**
46
+ * Invalidates cache for multiple users
47
+ * @param user_ids - Array of user IDs to invalidate
48
+ */
49
+ invalidate_users(user_ids: string[]): void;
50
+ /**
51
+ * Invalidates all cache entries
52
+ */
53
+ invalidate_all(): void;
54
+ /**
55
+ * Gets cache statistics
56
+ * @returns Object with cache size and max size
57
+ */
58
+ get_stats(): {
59
+ size: number;
60
+ max_size: number;
61
+ ttl_minutes: number;
62
+ };
63
+ }
64
+ /**
65
+ * Gets or creates the global user profiles cache instance
66
+ * @param max_size - Maximum cache size (default: 5000)
67
+ * @param ttl_minutes - TTL in minutes (default: 5)
68
+ * @returns User profiles cache instance
69
+ */
70
+ export declare function get_user_profiles_cache(max_size?: number, ttl_minutes?: number): UserProfilesCache;
71
+ /**
72
+ * Resets the global cache instance (useful for testing)
73
+ */
74
+ export declare function reset_user_profiles_cache(): void;
75
+ export {};
76
+ //# sourceMappingURL=user_profiles_cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user_profiles_cache.d.ts","sourceRoot":"","sources":["../../../src/lib/services/user_profiles_cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAc/D;;;GAGG;AACH,cAAM,iBAAiB;IACrB,OAAO,CAAC,KAAK,CAAiC;IAC9C,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAS;gBAEX,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM;IAMjD;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAuBjD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG;QAC5B,MAAM,EAAE,eAAe,EAAE,CAAC;QAC1B,WAAW,EAAE,MAAM,EAAE,CAAC;KACvB;IAgBD;;;;;OAKG;IACH,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAmBpD;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,IAAI;IAM3C;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAItC;;;OAGG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI;IAM1C;;OAEG;IACH,cAAc,IAAI,IAAI;IAItB;;;OAGG;IACH,SAAS,IAAI;QACX,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;KACrB;CAOF;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,GAAE,MAAa,EACvB,WAAW,GAAE,MAAU,GACtB,iBAAiB,CAKnB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
@@ -0,0 +1,141 @@
1
+ // section: cache_class
2
+ /**
3
+ * LRU cache implementation with TTL and size limits for user profiles
4
+ * Uses Map to maintain insertion order for LRU eviction
5
+ */
6
+ class UserProfilesCache {
7
+ constructor(max_size, ttl_minutes) {
8
+ this.cache = new Map();
9
+ this.max_size = max_size;
10
+ this.ttl_ms = ttl_minutes * 60 * 1000;
11
+ }
12
+ /**
13
+ * Gets a cached profile for a user
14
+ * Returns undefined if not found or expired
15
+ * @param user_id - User ID to look up
16
+ * @returns Profile or undefined
17
+ */
18
+ get(user_id) {
19
+ const entry = this.cache.get(user_id);
20
+ if (!entry) {
21
+ return undefined;
22
+ }
23
+ const now = Date.now();
24
+ const age = now - entry.timestamp;
25
+ // Check if entry is expired
26
+ if (age > this.ttl_ms) {
27
+ this.cache.delete(user_id);
28
+ return undefined;
29
+ }
30
+ // Move to end (most recently used)
31
+ this.cache.delete(user_id);
32
+ this.cache.set(user_id, entry);
33
+ return entry.profile;
34
+ }
35
+ /**
36
+ * Gets multiple profiles from cache
37
+ * Returns object with found profiles and missing IDs
38
+ * @param user_ids - Array of user IDs to look up
39
+ * @returns Object with cached profiles and IDs not in cache
40
+ */
41
+ get_many(user_ids) {
42
+ const cached = [];
43
+ const missing_ids = [];
44
+ for (const user_id of user_ids) {
45
+ const profile = this.get(user_id);
46
+ if (profile) {
47
+ cached.push(profile);
48
+ }
49
+ else {
50
+ missing_ids.push(user_id);
51
+ }
52
+ }
53
+ return { cached, missing_ids };
54
+ }
55
+ /**
56
+ * Sets a cache entry for a user profile
57
+ * Evicts least recently used entries if cache is full
58
+ * @param user_id - User ID
59
+ * @param profile - User profile data
60
+ */
61
+ set(user_id, profile) {
62
+ // Evict LRU entries if cache is full
63
+ while (this.cache.size >= this.max_size) {
64
+ const first_key = this.cache.keys().next().value;
65
+ if (first_key) {
66
+ this.cache.delete(first_key);
67
+ }
68
+ else {
69
+ break;
70
+ }
71
+ }
72
+ const entry = {
73
+ profile,
74
+ timestamp: Date.now(),
75
+ };
76
+ this.cache.set(user_id, entry);
77
+ }
78
+ /**
79
+ * Sets multiple cache entries at once
80
+ * @param profiles - Array of user profiles to cache
81
+ */
82
+ set_many(profiles) {
83
+ for (const profile of profiles) {
84
+ this.set(profile.user_id, profile);
85
+ }
86
+ }
87
+ /**
88
+ * Invalidates cache for a specific user
89
+ * @param user_id - User ID to invalidate
90
+ */
91
+ invalidate_user(user_id) {
92
+ this.cache.delete(user_id);
93
+ }
94
+ /**
95
+ * Invalidates cache for multiple users
96
+ * @param user_ids - Array of user IDs to invalidate
97
+ */
98
+ invalidate_users(user_ids) {
99
+ for (const user_id of user_ids) {
100
+ this.cache.delete(user_id);
101
+ }
102
+ }
103
+ /**
104
+ * Invalidates all cache entries
105
+ */
106
+ invalidate_all() {
107
+ this.cache.clear();
108
+ }
109
+ /**
110
+ * Gets cache statistics
111
+ * @returns Object with cache size and max size
112
+ */
113
+ get_stats() {
114
+ return {
115
+ size: this.cache.size,
116
+ max_size: this.max_size,
117
+ ttl_minutes: this.ttl_ms / 60000,
118
+ };
119
+ }
120
+ }
121
+ // section: singleton
122
+ // Global cache instance (initialized with defaults, will be configured on first use)
123
+ let user_profiles_cache_instance = null;
124
+ /**
125
+ * Gets or creates the global user profiles cache instance
126
+ * @param max_size - Maximum cache size (default: 5000)
127
+ * @param ttl_minutes - TTL in minutes (default: 5)
128
+ * @returns User profiles cache instance
129
+ */
130
+ export function get_user_profiles_cache(max_size = 5000, ttl_minutes = 5) {
131
+ if (!user_profiles_cache_instance) {
132
+ user_profiles_cache_instance = new UserProfilesCache(max_size, ttl_minutes);
133
+ }
134
+ return user_profiles_cache_instance;
135
+ }
136
+ /**
137
+ * Resets the global cache instance (useful for testing)
138
+ */
139
+ export function reset_user_profiles_cache() {
140
+ user_profiles_cache_instance = null;
141
+ }
@@ -19,13 +19,30 @@ export type GetProfilesResult = {
19
19
  profiles: UserProfileInfo[];
20
20
  not_found_ids: string[];
21
21
  error?: string;
22
+ cache_stats?: {
23
+ hits: number;
24
+ misses: number;
25
+ cache_enabled: boolean;
26
+ };
22
27
  };
23
28
  /**
24
29
  * Retrieves basic profile information for multiple users in a single batch call
25
30
  * Useful for chat applications and similar use cases where basic user info is needed
31
+ * Uses LRU cache with configurable TTL for performance (default: 5 minutes)
26
32
  * @param adapter - The hazo_connect adapter instance
27
33
  * @param user_ids - Array of user IDs to retrieve profiles for
28
34
  * @returns GetProfilesResult with found profiles and list of not found IDs
29
35
  */
30
36
  export declare function hazo_get_user_profiles(adapter: HazoConnectAdapter, user_ids: string[]): Promise<GetProfilesResult>;
37
+ /**
38
+ * Invalidates cache for specific user IDs
39
+ * Call this after user profile updates to ensure fresh data on next fetch
40
+ * @param user_ids - Array of user IDs to invalidate from cache
41
+ */
42
+ export declare function invalidate_user_profiles_cache(user_ids: string[]): void;
43
+ /**
44
+ * Invalidates the entire user profiles cache
45
+ * Use sparingly - prefer invalidating specific users when possible
46
+ */
47
+ export declare function invalidate_all_user_profiles_cache(): void;
31
48
  //# sourceMappingURL=user_profiles_service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user_profiles_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/user_profiles_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAOvD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,iBAAiB,CAAC,CAkG5B"}
1
+ {"version":3,"file":"user_profiles_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/user_profiles_service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;CACH,CAAC;AAuDF;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,EAAE,GACjB,OAAO,CAAC,iBAAiB,CAAC,CA4H5B;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAWvE;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,IAAI,IAAI,CAWzD"}
@@ -2,16 +2,60 @@ import { createCrudService } from "hazo_connect/server";
2
2
  import { differenceInDays } from "date-fns";
3
3
  import { create_app_logger } from "../app_logger";
4
4
  import { sanitize_error_for_user } from "../utils/error_sanitizer";
5
+ import { get_user_profiles_cache } from "./user_profiles_cache";
6
+ import { get_user_profiles_cache_config } from "../user_profiles_config.server";
5
7
  // section: helpers
8
+ /**
9
+ * Fetches profiles from database for given user IDs
10
+ * @param adapter - The hazo_connect adapter instance
11
+ * @param user_ids - Array of user IDs to fetch
12
+ * @returns Object with profiles and not found IDs
13
+ */
14
+ async function fetch_profiles_from_db(adapter, user_ids) {
15
+ const users_service = createCrudService(adapter, "hazo_users");
16
+ // Query users by IDs using the 'in' filter
17
+ // PostgREST supports 'in' filter syntax: id=in.(id1,id2,id3)
18
+ const users = await users_service.findBy({
19
+ id: `in.(${user_ids.join(",")})`,
20
+ });
21
+ // Handle case where no users are found
22
+ if (!Array.isArray(users)) {
23
+ return {
24
+ profiles: [],
25
+ not_found_ids: user_ids,
26
+ };
27
+ }
28
+ // Build set of found user IDs for quick lookup
29
+ const found_user_ids = new Set(users.map((user) => user.id));
30
+ // Determine which user IDs were not found
31
+ const not_found_ids = user_ids.filter((id) => !found_user_ids.has(id));
32
+ // Transform database records to UserProfileInfo
33
+ const now = new Date();
34
+ const profiles = users.map((user) => {
35
+ const created_at = user.created_at;
36
+ const created_date = new Date(created_at);
37
+ const days_since_created = differenceInDays(now, created_date);
38
+ return {
39
+ user_id: user.id,
40
+ profile_picture_url: user.profile_picture_url || null,
41
+ email: user.email_address,
42
+ name: user.name || null,
43
+ days_since_created,
44
+ };
45
+ });
46
+ return { profiles, not_found_ids };
47
+ }
6
48
  /**
7
49
  * Retrieves basic profile information for multiple users in a single batch call
8
50
  * Useful for chat applications and similar use cases where basic user info is needed
51
+ * Uses LRU cache with configurable TTL for performance (default: 5 minutes)
9
52
  * @param adapter - The hazo_connect adapter instance
10
53
  * @param user_ids - Array of user IDs to retrieve profiles for
11
54
  * @returns GetProfilesResult with found profiles and list of not found IDs
12
55
  */
13
56
  export async function hazo_get_user_profiles(adapter, user_ids) {
14
57
  const logger = create_app_logger();
58
+ const config = get_user_profiles_cache_config();
15
59
  try {
16
60
  // Handle empty input
17
61
  if (!user_ids || user_ids.length === 0) {
@@ -19,62 +63,85 @@ export async function hazo_get_user_profiles(adapter, user_ids) {
19
63
  success: true,
20
64
  profiles: [],
21
65
  not_found_ids: [],
66
+ cache_stats: {
67
+ hits: 0,
68
+ misses: 0,
69
+ cache_enabled: config.cache_enabled,
70
+ },
22
71
  };
23
72
  }
24
73
  // Remove duplicates from input
25
74
  const unique_user_ids = [...new Set(user_ids)];
26
- // Create CRUD service for hazo_users table
27
- const users_service = createCrudService(adapter, "hazo_users");
28
- // Query users by IDs using the 'in' filter
29
- // PostgREST supports 'in' filter syntax: id=in.(id1,id2,id3)
30
- const users = await users_service.findBy({
31
- id: `in.(${unique_user_ids.join(",")})`,
32
- });
33
- // Handle case where no users are found
34
- if (!Array.isArray(users)) {
35
- logger.warn("hazo_get_user_profiles_unexpected_response", {
36
- filename: "user_profiles_service.ts",
37
- line_number: 70,
38
- message: "Unexpected response format from database query",
39
- user_ids: unique_user_ids,
40
- });
41
- return {
42
- success: true,
43
- profiles: [],
44
- not_found_ids: unique_user_ids,
45
- };
75
+ // Initialize variables for cache tracking
76
+ let cache_hits = 0;
77
+ let cache_misses = 0;
78
+ let all_profiles = [];
79
+ let all_not_found_ids = [];
80
+ if (config.cache_enabled) {
81
+ // Get cache instance with config settings
82
+ const cache = get_user_profiles_cache(config.cache_max_entries, config.cache_ttl_minutes);
83
+ // Check cache first
84
+ const { cached, missing_ids } = cache.get_many(unique_user_ids);
85
+ cache_hits = cached.length;
86
+ cache_misses = missing_ids.length;
87
+ // If all profiles were cached, return immediately
88
+ if (missing_ids.length === 0) {
89
+ logger.info("hazo_get_user_profiles_cache_hit_all", {
90
+ filename: "user_profiles_service.ts",
91
+ line_number: 130,
92
+ message: "All profiles served from cache",
93
+ requested_count: unique_user_ids.length,
94
+ cache_hits,
95
+ });
96
+ return {
97
+ success: true,
98
+ profiles: cached,
99
+ not_found_ids: [],
100
+ cache_stats: {
101
+ hits: cache_hits,
102
+ misses: 0,
103
+ cache_enabled: true,
104
+ },
105
+ };
106
+ }
107
+ // Fetch missing profiles from database
108
+ const db_result = await fetch_profiles_from_db(adapter, missing_ids);
109
+ // Cache the newly fetched profiles
110
+ if (db_result.profiles.length > 0) {
111
+ cache.set_many(db_result.profiles);
112
+ }
113
+ // Combine cached and freshly fetched profiles
114
+ all_profiles = [...cached, ...db_result.profiles];
115
+ all_not_found_ids = db_result.not_found_ids;
116
+ }
117
+ else {
118
+ // Cache disabled - fetch all from database
119
+ cache_misses = unique_user_ids.length;
120
+ const db_result = await fetch_profiles_from_db(adapter, unique_user_ids);
121
+ all_profiles = db_result.profiles;
122
+ all_not_found_ids = db_result.not_found_ids;
46
123
  }
47
- // Build set of found user IDs for quick lookup
48
- const found_user_ids = new Set(users.map((user) => user.id));
49
- // Determine which user IDs were not found
50
- const not_found_ids = unique_user_ids.filter((id) => !found_user_ids.has(id));
51
- // Transform database records to UserProfileInfo
52
- const now = new Date();
53
- const profiles = users.map((user) => {
54
- const created_at = user.created_at;
55
- const created_date = new Date(created_at);
56
- const days_since_created = differenceInDays(now, created_date);
57
- return {
58
- user_id: user.id,
59
- profile_picture_url: user.profile_picture_url || null,
60
- email: user.email_address,
61
- name: user.name || null,
62
- days_since_created,
63
- };
64
- });
65
124
  // Log successful retrieval
66
125
  logger.info("hazo_get_user_profiles_success", {
67
126
  filename: "user_profiles_service.ts",
68
- line_number: 105,
127
+ line_number: 170,
69
128
  message: "Successfully retrieved user profiles",
70
129
  requested_count: unique_user_ids.length,
71
- found_count: profiles.length,
72
- not_found_count: not_found_ids.length,
130
+ found_count: all_profiles.length,
131
+ not_found_count: all_not_found_ids.length,
132
+ cache_hits,
133
+ cache_misses,
134
+ cache_enabled: config.cache_enabled,
73
135
  });
74
136
  return {
75
137
  success: true,
76
- profiles,
77
- not_found_ids,
138
+ profiles: all_profiles,
139
+ not_found_ids: all_not_found_ids,
140
+ cache_stats: {
141
+ hits: cache_hits,
142
+ misses: cache_misses,
143
+ cache_enabled: config.cache_enabled,
144
+ },
78
145
  };
79
146
  }
80
147
  catch (error) {
@@ -84,7 +151,7 @@ export async function hazo_get_user_profiles(adapter, user_ids) {
84
151
  logger,
85
152
  context: {
86
153
  filename: "user_profiles_service.ts",
87
- line_number: 122,
154
+ line_number: 195,
88
155
  operation: "hazo_get_user_profiles",
89
156
  user_ids_count: (user_ids === null || user_ids === void 0 ? void 0 : user_ids.length) || 0,
90
157
  },
@@ -97,3 +164,28 @@ export async function hazo_get_user_profiles(adapter, user_ids) {
97
164
  };
98
165
  }
99
166
  }
167
+ /**
168
+ * Invalidates cache for specific user IDs
169
+ * Call this after user profile updates to ensure fresh data on next fetch
170
+ * @param user_ids - Array of user IDs to invalidate from cache
171
+ */
172
+ export function invalidate_user_profiles_cache(user_ids) {
173
+ const config = get_user_profiles_cache_config();
174
+ if (!config.cache_enabled) {
175
+ return;
176
+ }
177
+ const cache = get_user_profiles_cache(config.cache_max_entries, config.cache_ttl_minutes);
178
+ cache.invalidate_users(user_ids);
179
+ }
180
+ /**
181
+ * Invalidates the entire user profiles cache
182
+ * Use sparingly - prefer invalidating specific users when possible
183
+ */
184
+ export function invalidate_all_user_profiles_cache() {
185
+ const config = get_user_profiles_cache_config();
186
+ if (!config.cache_enabled) {
187
+ return;
188
+ }
189
+ const cache = get_user_profiles_cache(config.cache_max_entries, config.cache_ttl_minutes);
190
+ cache.invalidate_all();
191
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * User profiles cache configuration options
3
+ */
4
+ export type UserProfilesCacheConfig = {
5
+ cache_enabled: boolean;
6
+ cache_max_entries: number;
7
+ cache_ttl_minutes: number;
8
+ };
9
+ /**
10
+ * Reads user profiles cache configuration from hazo_auth_config.ini file
11
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
12
+ * @returns User profiles cache configuration options
13
+ */
14
+ export declare function get_user_profiles_cache_config(): UserProfilesCacheConfig;
15
+ //# sourceMappingURL=user_profiles_config.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user_profiles_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/user_profiles_config.server.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,aAAa,EAAE,OAAO,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,8BAA8B,IAAI,uBAAuB,CA6BxE"}
@@ -0,0 +1,23 @@
1
+ // file_description: server-only helper to read user profiles cache configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_number, } from "./config/config_loader.server";
4
+ // section: helpers
5
+ /**
6
+ * Reads user profiles cache configuration from hazo_auth_config.ini file
7
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
8
+ * @returns User profiles cache configuration options
9
+ */
10
+ export function get_user_profiles_cache_config() {
11
+ const section_name = "hazo_auth__user_profiles";
12
+ // Cache settings
13
+ // cache_enabled: 0 = disabled, 1 = enabled (default: 1)
14
+ const cache_enabled_num = get_config_number(section_name, "cache_enabled", 1);
15
+ const cache_enabled = cache_enabled_num === 1;
16
+ const cache_max_entries = get_config_number(section_name, "cache_max_entries", 5000);
17
+ const cache_ttl_minutes = get_config_number(section_name, "cache_ttl_minutes", 5);
18
+ return {
19
+ cache_enabled,
20
+ cache_max_entries,
21
+ cache_ttl_minutes,
22
+ };
23
+ }
@@ -305,17 +305,21 @@ enable_admin_ui = true
305
305
  # default_super_user_email = admin@example.com
306
306
 
307
307
  [hazo_auth__auth_utility]
308
- # Authentication utility configuration
308
+ # Authentication utility configuration for hazo_get_auth()
309
+ # This function retrieves the current user, their permissions, and role IDs from cookies
310
+ # Results are cached in memory to improve performance on repeated calls
309
311
 
310
312
  # Cache settings
311
313
  # Maximum number of users to cache (LRU eviction, default: 10000)
312
314
  # cache_max_users = 10000
313
315
 
314
- # Cache TTL in minutes (default: 15)
315
- # cache_ttl_minutes = 15
316
+ # Cache TTL in minutes - how long cached auth data is valid (default: 5)
317
+ # After TTL expires, the next call will fetch fresh data from database
318
+ # cache_ttl_minutes = 5
316
319
 
317
- # Force cache refresh if older than this many minutes (default: 30)
318
- # cache_max_age_minutes = 30
320
+ # Force cache refresh if older than this many minutes (default: 10)
321
+ # This is the hard limit - entries older than this are always refreshed
322
+ # cache_max_age_minutes = 10
319
323
 
320
324
  # Rate limiting for /api/auth/get_auth endpoint
321
325
  # Per-user rate limit (requests per minute, default: 100)
@@ -336,6 +340,22 @@ enable_admin_ui = true
336
340
  # Example: admin_user_management:You don't have access to user management,admin_role_management:You don't have access to role management
337
341
  # permission_error_messages =
338
342
 
343
+ [hazo_auth__user_profiles]
344
+ # User profiles cache configuration for hazo_get_user_profiles()
345
+ # This function retrieves basic profile info (name, email, profile picture) for multiple users
346
+ # Used by chat applications and similar use cases where batch user info is needed
347
+ # Results are cached in memory to improve performance on repeated calls
348
+
349
+ # Enable caching (1 = enabled, 0 = disabled, default: 1)
350
+ # cache_enabled = 1
351
+
352
+ # Maximum number of user profiles to cache (LRU eviction, default: 5000)
353
+ # cache_max_entries = 5000
354
+
355
+ # Cache TTL in minutes - how long cached profile data is valid (default: 5)
356
+ # After TTL expires, the next call will fetch fresh data from database
357
+ # cache_ttl_minutes = 5
358
+
339
359
  [hazo_auth__profile_pic_menu]
340
360
  # Profile picture menu configuration
341
361
  # This component can be used in navbar or sidebar to show user profile picture or sign up/sign in buttons
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_auth",
3
- "version": "1.6.1",
3
+ "version": "1.6.4",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "module",
@@ -12,6 +12,10 @@
12
12
  "types": "./dist/index.d.ts",
13
13
  "import": "./dist/index.js"
14
14
  },
15
+ "./client": {
16
+ "types": "./dist/client.d.ts",
17
+ "import": "./dist/client.js"
18
+ },
15
19
  "./components/layouts/login": {
16
20
  "types": "./dist/components/layouts/login/index.d.ts",
17
21
  "import": "./dist/components/layouts/login/index.js"