@enterprisestandard/react 0.0.5-beta.20260115.2 → 0.0.5-beta.20260115.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 (77) hide show
  1. package/dist/index.d.ts +2573 -41
  2. package/dist/index.js +3732 -144
  3. package/dist/index.js.map +1 -0
  4. package/package.json +3 -1
  5. package/dist/group-store.d.ts +0 -164
  6. package/dist/group-store.d.ts.map +0 -1
  7. package/dist/group-store.js +0 -127
  8. package/dist/iam.d.ts +0 -206
  9. package/dist/iam.d.ts.map +0 -1
  10. package/dist/iam.js +0 -680
  11. package/dist/index.d.ts.map +0 -1
  12. package/dist/session-store.d.ts +0 -179
  13. package/dist/session-store.d.ts.map +0 -1
  14. package/dist/session-store.js +0 -105
  15. package/dist/sso-server.d.ts +0 -13
  16. package/dist/sso-server.d.ts.map +0 -1
  17. package/dist/sso-server.js +0 -46
  18. package/dist/sso.d.ts +0 -104
  19. package/dist/sso.d.ts.map +0 -1
  20. package/dist/sso.js +0 -820
  21. package/dist/tenant-server.d.ts +0 -8
  22. package/dist/tenant-server.d.ts.map +0 -1
  23. package/dist/tenant-server.js +0 -6
  24. package/dist/tenant.d.ts +0 -280
  25. package/dist/tenant.d.ts.map +0 -1
  26. package/dist/tenant.js +0 -324
  27. package/dist/types/base-user.d.ts +0 -27
  28. package/dist/types/base-user.d.ts.map +0 -1
  29. package/dist/types/base-user.js +0 -1
  30. package/dist/types/enterprise-user.d.ts +0 -158
  31. package/dist/types/enterprise-user.d.ts.map +0 -1
  32. package/dist/types/enterprise-user.js +0 -1
  33. package/dist/types/oidc-schema.d.ts +0 -86
  34. package/dist/types/oidc-schema.d.ts.map +0 -1
  35. package/dist/types/oidc-schema.js +0 -328
  36. package/dist/types/scim-schema.d.ts +0 -419
  37. package/dist/types/scim-schema.d.ts.map +0 -1
  38. package/dist/types/scim-schema.js +0 -519
  39. package/dist/types/standard-schema.d.ts +0 -56
  40. package/dist/types/standard-schema.d.ts.map +0 -1
  41. package/dist/types/standard-schema.js +0 -1
  42. package/dist/types/user.d.ts +0 -41
  43. package/dist/types/user.d.ts.map +0 -1
  44. package/dist/types/user.js +0 -1
  45. package/dist/types/workload-schema.d.ts +0 -106
  46. package/dist/types/workload-schema.d.ts.map +0 -1
  47. package/dist/types/workload-schema.js +0 -208
  48. package/dist/ui/sign-in-loading.d.ts +0 -5
  49. package/dist/ui/sign-in-loading.d.ts.map +0 -1
  50. package/dist/ui/sign-in-loading.js +0 -8
  51. package/dist/ui/signed-in.d.ts +0 -3
  52. package/dist/ui/signed-in.d.ts.map +0 -1
  53. package/dist/ui/signed-in.js +0 -8
  54. package/dist/ui/signed-out.d.ts +0 -3
  55. package/dist/ui/signed-out.d.ts.map +0 -1
  56. package/dist/ui/signed-out.js +0 -8
  57. package/dist/ui/sso-provider.d.ts +0 -35
  58. package/dist/ui/sso-provider.d.ts.map +0 -1
  59. package/dist/ui/sso-provider.js +0 -275
  60. package/dist/user-store.d.ts +0 -161
  61. package/dist/user-store.d.ts.map +0 -1
  62. package/dist/user-store.js +0 -114
  63. package/dist/utils.d.ts +0 -9
  64. package/dist/utils.d.ts.map +0 -1
  65. package/dist/utils.js +0 -23
  66. package/dist/vault.d.ts +0 -18
  67. package/dist/vault.d.ts.map +0 -1
  68. package/dist/vault.js +0 -22
  69. package/dist/workload-server.d.ts +0 -127
  70. package/dist/workload-server.d.ts.map +0 -1
  71. package/dist/workload-server.js +0 -167
  72. package/dist/workload-token-store.d.ts +0 -187
  73. package/dist/workload-token-store.d.ts.map +0 -1
  74. package/dist/workload-token-store.js +0 -95
  75. package/dist/workload.d.ts +0 -227
  76. package/dist/workload.d.ts.map +0 -1
  77. package/dist/workload.js +0 -691
@@ -1,275 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { createContext, useCallback, useContext, useEffect, useState } from 'react';
3
- const CTX = createContext(undefined);
4
- const generateStorageKey = (tenantId) => {
5
- return `es-sso-user-${tenantId
6
- .replace(/[^a-zA-Z0-9]/g, '-')
7
- .replace(/-+/g, '-')
8
- .replace(/^-|-$/g, '')}`;
9
- };
10
- export function SSOProvider({ tenantId, storage = 'memory', storageKey, userUrl, tokenUrl, refreshUrl, disableListener = false, children, }) {
11
- const [user, setUserState] = useState(null);
12
- const [isLoading, setIsLoading] = useState(!!userUrl);
13
- const actualStorageKey = storageKey || (tenantId ? generateStorageKey(tenantId) : 'es-sso-user');
14
- const isValidUser = useCallback((user) => {
15
- if (!user || !tenantId)
16
- return true;
17
- return user.sso?.tenant?.id === tenantId;
18
- }, [tenantId]);
19
- const loadUserFromStorage = useCallback(() => {
20
- if (storage === 'memory' || typeof window === 'undefined')
21
- return null;
22
- try {
23
- const storageObject = storage === 'local' ? localStorage : sessionStorage;
24
- const userData = storageObject.getItem(actualStorageKey);
25
- if (!userData)
26
- return null;
27
- const parsedUser = JSON.parse(userData);
28
- if (parsedUser.sso?.expires) {
29
- parsedUser.sso.expires = new Date(parsedUser.sso.expires);
30
- }
31
- return isValidUser(parsedUser) ? parsedUser : null;
32
- }
33
- catch (error) {
34
- console.error('Error loading user from storage:', error);
35
- return null;
36
- }
37
- }, [storage, actualStorageKey, isValidUser]);
38
- const saveUserToStorage = useCallback((user) => {
39
- if (storage === 'memory' || typeof window === 'undefined')
40
- return;
41
- try {
42
- const storageObject = storage === 'local' ? localStorage : sessionStorage;
43
- if (user === null) {
44
- storageObject.removeItem(actualStorageKey);
45
- }
46
- else {
47
- storageObject.setItem(actualStorageKey, JSON.stringify(user));
48
- }
49
- }
50
- catch (error) {
51
- console.error('Error saving user to storage:', error);
52
- }
53
- }, [storage, actualStorageKey]);
54
- const setUser = useCallback((newUser) => {
55
- if (newUser && !isValidUser(newUser))
56
- return;
57
- setUserState(newUser);
58
- saveUserToStorage(newUser);
59
- }, [isValidUser, saveUserToStorage]);
60
- const fetchUserFromUrl = useCallback(async () => {
61
- if (!userUrl)
62
- return;
63
- setIsLoading(true);
64
- try {
65
- const response = await fetch(userUrl);
66
- if (response.status === 401) {
67
- setUserState(null);
68
- saveUserToStorage(null);
69
- setIsLoading(false);
70
- return;
71
- }
72
- if (!response.ok) {
73
- throw new Error(`Failed to fetch user: ${response.status} ${response.statusText}`);
74
- }
75
- const userData = (await response.json());
76
- if (userData.sso?.expires && typeof userData.sso.expires === 'string') {
77
- userData.sso.expires = new Date(userData.sso.expires);
78
- }
79
- if (isValidUser(userData)) {
80
- setUserState(userData);
81
- saveUserToStorage(userData);
82
- }
83
- }
84
- catch (error) {
85
- console.error('Error fetching user from URL:', error);
86
- }
87
- finally {
88
- setIsLoading(false);
89
- }
90
- }, [userUrl, isValidUser, saveUserToStorage]);
91
- useEffect(() => {
92
- const storedUser = loadUserFromStorage();
93
- if (storedUser) {
94
- setUserState(storedUser);
95
- }
96
- if (userUrl) {
97
- fetchUserFromUrl();
98
- }
99
- else {
100
- setIsLoading(false);
101
- }
102
- }, [loadUserFromStorage, userUrl, fetchUserFromUrl]);
103
- useEffect(() => {
104
- if (disableListener || storage === 'memory')
105
- return;
106
- const handleStorageChange = (event) => {
107
- if (event.key !== actualStorageKey)
108
- return;
109
- if (event.newValue === null) {
110
- setUserState(null);
111
- }
112
- else {
113
- try {
114
- const parsedUser = JSON.parse(event.newValue);
115
- if (parsedUser.sso?.expires) {
116
- parsedUser.sso.expires = new Date(parsedUser.sso.expires);
117
- }
118
- if (isValidUser(parsedUser)) {
119
- setUserState(parsedUser);
120
- }
121
- }
122
- catch (error) {
123
- console.error('Error parsing user from storage event:', error);
124
- }
125
- }
126
- };
127
- const handleLogout = () => {
128
- setUserState(null);
129
- };
130
- window.addEventListener('storage', handleStorageChange);
131
- window.addEventListener('es-sso-logout', handleLogout);
132
- return () => {
133
- window.removeEventListener('storage', handleStorageChange);
134
- window.removeEventListener('es-sso-logout', handleLogout);
135
- };
136
- }, [disableListener, storage, actualStorageKey, isValidUser]);
137
- const contextValue = {
138
- user,
139
- setUser,
140
- isLoading,
141
- tokenUrl,
142
- refreshUrl,
143
- };
144
- return _jsx(CTX.Provider, { value: contextValue, children: children });
145
- }
146
- export function useUser() {
147
- const context = useContext(CTX);
148
- if (context === undefined) {
149
- throw new Error('useUser must be used within a SSOProvider');
150
- }
151
- return context;
152
- }
153
- export function useToken() {
154
- const context = useContext(CTX);
155
- if (context === undefined) {
156
- throw new Error('useToken must be used within a SSOProvider');
157
- }
158
- const { tokenUrl, refreshUrl } = context;
159
- if (!tokenUrl || !refreshUrl) {
160
- throw new Error('useToken requires that a "tokenUrl" and "refreshUrl" be set in the SSOProvider');
161
- }
162
- const [token, setToken] = useState(null);
163
- const [expires, setExpires] = useState(null);
164
- const [isLoading, setIsLoading] = useState(!!tokenUrl);
165
- const [error, setError] = useState(null);
166
- const fetchJwt = useCallback(async (url) => {
167
- setIsLoading(true);
168
- setError(null);
169
- try {
170
- const response = await fetch(url);
171
- if (response.status === 401) {
172
- context.setUser(null);
173
- setToken(null);
174
- setExpires(null);
175
- setIsLoading(false);
176
- return;
177
- }
178
- if (!response.ok) {
179
- throw new Error(`Failed to fetch JWT: ${response.status} ${response.statusText}`);
180
- }
181
- const data = (await response.json());
182
- setToken(data.token);
183
- setExpires(new Date(data.expires));
184
- }
185
- catch (err) {
186
- const error = err instanceof Error ? err : new Error(String(err));
187
- setError(error);
188
- setToken(null);
189
- setExpires(null);
190
- console.error('Error fetching JWT:', error);
191
- }
192
- finally {
193
- setIsLoading(false);
194
- }
195
- }, [context]);
196
- const refresh = useCallback(async () => {
197
- const url = refreshUrl || tokenUrl;
198
- if (!url) {
199
- console.warn('No tokenUrl or refreshUrl provided');
200
- return;
201
- }
202
- await fetchJwt(url);
203
- }, [refreshUrl, tokenUrl, fetchJwt]);
204
- useEffect(() => {
205
- if (!tokenUrl) {
206
- setIsLoading(false);
207
- return;
208
- }
209
- fetchJwt(tokenUrl);
210
- }, [tokenUrl, fetchJwt]);
211
- useEffect(() => {
212
- if (!expires || !refreshUrl)
213
- return;
214
- const checkExpiration = () => {
215
- const now = new Date();
216
- const timeUntilExpiry = expires.getTime() - now.getTime();
217
- // Refresh 1 minute before expiration
218
- if (timeUntilExpiry <= 60000 && timeUntilExpiry > 0) {
219
- refresh();
220
- }
221
- };
222
- // Check immediately
223
- checkExpiration();
224
- // Check every 30 seconds
225
- const interval = setInterval(checkExpiration, 30000);
226
- return () => clearInterval(interval);
227
- }, [expires, refreshUrl, refresh]);
228
- return {
229
- token,
230
- isLoading,
231
- error,
232
- refresh,
233
- };
234
- }
235
- export async function logout(logoutUrl) {
236
- try {
237
- // Make AJAX logout call
238
- const response = await fetch(logoutUrl, {
239
- headers: { Accept: 'application/json' },
240
- });
241
- if (!response.ok) {
242
- return { success: false, error: `HTTP ${response.status}` };
243
- }
244
- const data = await response.json();
245
- if (!data.success) {
246
- return { success: false, error: data.message || 'Logout failed' };
247
- }
248
- // Clear managed storage keys (all es-sso-user-* keys)
249
- if (typeof window !== 'undefined') {
250
- // Clear localStorage
251
- for (let i = localStorage.length - 1; i >= 0; i--) {
252
- const key = localStorage.key(i);
253
- if (key?.startsWith('es-sso-user')) {
254
- localStorage.removeItem(key);
255
- }
256
- }
257
- // Clear sessionStorage
258
- for (let i = sessionStorage.length - 1; i >= 0; i--) {
259
- const key = sessionStorage.key(i);
260
- if (key?.startsWith('es-sso-user')) {
261
- sessionStorage.removeItem(key);
262
- }
263
- }
264
- // Dispatch custom event for same-tab state updates
265
- window.dispatchEvent(new CustomEvent('es-sso-logout'));
266
- }
267
- return { success: true };
268
- }
269
- catch (error) {
270
- return {
271
- success: false,
272
- error: error instanceof Error ? error.message : 'Network error',
273
- };
274
- }
275
- }
@@ -1,161 +0,0 @@
1
- /**
2
- * User storage for persisting user profiles from SSO authentication.
3
- *
4
- * User stores are optional - the package works with JWT cookies alone.
5
- * User stores are useful when you want to:
6
- * - Cache user profiles for fast lookup
7
- * - Store users close to your application (in-memory, Redis, etc.)
8
- * - Avoid custom IAM/SCIM integration for simple use cases
9
- *
10
- * ## When to Use UserStore vs IAM
11
- *
12
- * **Use UserStore when:**
13
- * - You just need fast user lookups without external systems
14
- * - Users are managed by an external IdP and you just cache them locally
15
- * - You want simple in-memory or Redis storage
16
- *
17
- * **Use IAM (SCIM) when:**
18
- * - You need to provision users to an external identity provider
19
- * - You need custom user attributes beyond what SSO provides
20
- * - You need to sync users with enterprise directories
21
- *
22
- * ## Example Usage
23
- *
24
- * ```typescript
25
- * import { sso, InMemoryUserStore } from '@enterprisestandard/react/server';
26
- *
27
- * const userStore = new InMemoryUserStore();
28
- *
29
- * const auth = sso({
30
- * // ... other config
31
- * user_store: userStore,
32
- * });
33
- *
34
- * // Later, look up users
35
- * const user = await userStore.get('user-sub-id');
36
- * const userByEmail = await userStore.getByEmail('user@example.com');
37
- * ```
38
- */
39
- import type { User } from './types/user';
40
- /**
41
- * Stored user data with required id and tracking metadata.
42
- *
43
- * Extends the SSO User type with:
44
- * - Required `id` (the `sub` claim from the IdP)
45
- * - Timestamps for tracking when users were first seen and last updated
46
- * - Optional custom extended data
47
- *
48
- * @template TExtended - Type-safe custom data that consumers can add to users
49
- */
50
- export type StoredUser<TExtended = {}> = User & {
51
- /**
52
- * Required unique identifier (the `sub` claim from the IdP).
53
- * This is the primary key for user storage.
54
- */
55
- id: string;
56
- /**
57
- * Timestamp when the user was first stored.
58
- */
59
- createdAt: Date;
60
- /**
61
- * Timestamp when the user was last updated (e.g., on re-login).
62
- */
63
- updatedAt: Date;
64
- } & TExtended;
65
- /**
66
- * Abstract interface for user storage backends.
67
- *
68
- * Consumers can implement this interface to use different storage backends:
69
- * - In-memory (for development/testing)
70
- * - Redis (for production with fast lookups)
71
- * - Database (PostgreSQL, MySQL, etc.)
72
- *
73
- * @template TExtended - Type-safe custom data that consumers can add to users
74
- *
75
- * @example
76
- * ```typescript
77
- * // Custom user data
78
- * type MyUserData = {
79
- * department: string;
80
- * roles: string[];
81
- * };
82
- *
83
- * // Implement custom store
84
- * class RedisUserStore implements UserStore<MyUserData> {
85
- * async get(sub: string): Promise<StoredUser<MyUserData> | null> {
86
- * const data = await redis.get(`user:${sub}`);
87
- * return data ? JSON.parse(data) : null;
88
- * }
89
- * // ... other methods
90
- * }
91
- * ```
92
- */
93
- export interface UserStore<TExtended = {}> {
94
- /**
95
- * Retrieve a user by their subject identifier (sub).
96
- *
97
- * @param sub - The user's unique identifier from the IdP
98
- * @returns The user if found, null otherwise
99
- */
100
- get(sub: string): Promise<StoredUser<TExtended> | null>;
101
- /**
102
- * Retrieve a user by their email address.
103
- *
104
- * @param email - The user's email address
105
- * @returns The user if found, null otherwise
106
- */
107
- getByEmail(email: string): Promise<StoredUser<TExtended> | null>;
108
- /**
109
- * Retrieve a user by their username.
110
- *
111
- * @param userName - The user's username
112
- * @returns The user if found, null otherwise
113
- */
114
- getByUserName(userName: string): Promise<StoredUser<TExtended> | null>;
115
- /**
116
- * Create or update a user in the store.
117
- *
118
- * If a user with the same `id` (sub) exists, it will be updated.
119
- * Otherwise, a new user will be created.
120
- *
121
- * @param user - The user data to store
122
- */
123
- upsert(user: StoredUser<TExtended>): Promise<void>;
124
- /**
125
- * Delete a user by their subject identifier (sub).
126
- *
127
- * @param sub - The user's unique identifier to delete
128
- */
129
- delete(sub: string): Promise<void>;
130
- }
131
- /**
132
- * In-memory user store implementation using Maps.
133
- *
134
- * Suitable for:
135
- * - Development and testing
136
- * - Single-server deployments
137
- * - Applications without high availability requirements
138
- *
139
- * NOT suitable for:
140
- * - Multi-server deployments (users not shared)
141
- * - High availability scenarios (users lost on restart)
142
- * - Production applications with distributed architecture
143
- *
144
- * For production, implement UserStore with Redis or a database.
145
- *
146
- * @template TExtended - Type-safe custom data that consumers can add to users
147
- */
148
- export declare class InMemoryUserStore<TExtended = {}> implements UserStore<TExtended> {
149
- /** Primary storage: sub -> user */
150
- private users;
151
- /** Secondary index: email -> sub */
152
- private emailIndex;
153
- /** Secondary index: userName -> sub */
154
- private userNameIndex;
155
- get(sub: string): Promise<StoredUser<TExtended> | null>;
156
- getByEmail(email: string): Promise<StoredUser<TExtended> | null>;
157
- getByUserName(userName: string): Promise<StoredUser<TExtended> | null>;
158
- upsert(user: StoredUser<TExtended>): Promise<void>;
159
- delete(sub: string): Promise<void>;
160
- }
161
- //# sourceMappingURL=user-store.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user-store.d.ts","sourceRoot":"","sources":["../src/user-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAEzC;;;;;;;;;GASG;AACH,MAAM,MAAM,UAAU,CAAC,SAAS,GAAG,EAAE,IAAI,IAAI,GAAG;IAC9C;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,SAAS,EAAE,IAAI,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,IAAI,CAAC;CACjB,GAAG,SAAS,CAAC;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,SAAS,CAAC,SAAS,GAAG,EAAE;IACvC;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAExD;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAEjE;;;;;OAKG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAEvE;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,iBAAiB,CAAC,SAAS,GAAG,EAAE,CAAE,YAAW,SAAS,CAAC,SAAS,CAAC;IAC5E,mCAAmC;IACnC,OAAO,CAAC,KAAK,CAA4C;IAEzD,oCAAoC;IACpC,OAAO,CAAC,UAAU,CAA6B;IAE/C,uCAAuC;IACvC,OAAO,CAAC,aAAa,CAA6B;IAE5C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAIvD,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAMhE,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IAMtE,MAAM,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAyBlD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAazC"}
@@ -1,114 +0,0 @@
1
- /**
2
- * User storage for persisting user profiles from SSO authentication.
3
- *
4
- * User stores are optional - the package works with JWT cookies alone.
5
- * User stores are useful when you want to:
6
- * - Cache user profiles for fast lookup
7
- * - Store users close to your application (in-memory, Redis, etc.)
8
- * - Avoid custom IAM/SCIM integration for simple use cases
9
- *
10
- * ## When to Use UserStore vs IAM
11
- *
12
- * **Use UserStore when:**
13
- * - You just need fast user lookups without external systems
14
- * - Users are managed by an external IdP and you just cache them locally
15
- * - You want simple in-memory or Redis storage
16
- *
17
- * **Use IAM (SCIM) when:**
18
- * - You need to provision users to an external identity provider
19
- * - You need custom user attributes beyond what SSO provides
20
- * - You need to sync users with enterprise directories
21
- *
22
- * ## Example Usage
23
- *
24
- * ```typescript
25
- * import { sso, InMemoryUserStore } from '@enterprisestandard/react/server';
26
- *
27
- * const userStore = new InMemoryUserStore();
28
- *
29
- * const auth = sso({
30
- * // ... other config
31
- * user_store: userStore,
32
- * });
33
- *
34
- * // Later, look up users
35
- * const user = await userStore.get('user-sub-id');
36
- * const userByEmail = await userStore.getByEmail('user@example.com');
37
- * ```
38
- */
39
- /**
40
- * In-memory user store implementation using Maps.
41
- *
42
- * Suitable for:
43
- * - Development and testing
44
- * - Single-server deployments
45
- * - Applications without high availability requirements
46
- *
47
- * NOT suitable for:
48
- * - Multi-server deployments (users not shared)
49
- * - High availability scenarios (users lost on restart)
50
- * - Production applications with distributed architecture
51
- *
52
- * For production, implement UserStore with Redis or a database.
53
- *
54
- * @template TExtended - Type-safe custom data that consumers can add to users
55
- */
56
- export class InMemoryUserStore {
57
- constructor() {
58
- /** Primary storage: sub -> user */
59
- this.users = new Map();
60
- /** Secondary index: email -> sub */
61
- this.emailIndex = new Map();
62
- /** Secondary index: userName -> sub */
63
- this.userNameIndex = new Map();
64
- }
65
- async get(sub) {
66
- return this.users.get(sub) ?? null;
67
- }
68
- async getByEmail(email) {
69
- const sub = this.emailIndex.get(email.toLowerCase());
70
- if (!sub)
71
- return null;
72
- return this.users.get(sub) ?? null;
73
- }
74
- async getByUserName(userName) {
75
- const sub = this.userNameIndex.get(userName.toLowerCase());
76
- if (!sub)
77
- return null;
78
- return this.users.get(sub) ?? null;
79
- }
80
- async upsert(user) {
81
- const existing = this.users.get(user.id);
82
- // Clean up old indexes if email or userName changed
83
- if (existing) {
84
- if (existing.email && existing.email.toLowerCase() !== user.email?.toLowerCase()) {
85
- this.emailIndex.delete(existing.email.toLowerCase());
86
- }
87
- if (existing.userName && existing.userName.toLowerCase() !== user.userName?.toLowerCase()) {
88
- this.userNameIndex.delete(existing.userName.toLowerCase());
89
- }
90
- }
91
- // Store the user
92
- this.users.set(user.id, user);
93
- // Update indexes
94
- if (user.email) {
95
- this.emailIndex.set(user.email.toLowerCase(), user.id);
96
- }
97
- if (user.userName) {
98
- this.userNameIndex.set(user.userName.toLowerCase(), user.id);
99
- }
100
- }
101
- async delete(sub) {
102
- const user = this.users.get(sub);
103
- if (user) {
104
- // Clean up indexes
105
- if (user.email) {
106
- this.emailIndex.delete(user.email.toLowerCase());
107
- }
108
- if (user.userName) {
109
- this.userNameIndex.delete(user.userName.toLowerCase());
110
- }
111
- }
112
- this.users.delete(sub);
113
- }
114
- }
package/dist/utils.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { EnterpriseStandard } from '.';
2
- export declare function must<T>(value: T | undefined | null, message?: string): T;
3
- export declare function setDefaultInstance(es: EnterpriseStandard): void;
4
- export declare function getDefaultInstance(): EnterpriseStandard | undefined;
5
- /**
6
- * If an es is defined, then return it, otherwise return the defaultEnterpriseStandard
7
- */
8
- export declare function getES(es?: EnterpriseStandard): EnterpriseStandard;
9
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,GAAG,CAAC;AAI5C,wBAAgB,IAAI,CAAC,CAAC,EACpB,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,IAAI,EAC3B,OAAO,SAA2D,GACjE,CAAC,CAKH;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,kBAAkB,QAExD;AAED,wBAAgB,kBAAkB,mCAEjC;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,CAAC,EAAE,kBAAkB,sBAI5C"}
package/dist/utils.js DELETED
@@ -1,23 +0,0 @@
1
- let defaultInstance;
2
- export function must(value, message = 'Assertion failed. Required value is null or undefined.') {
3
- if (value === undefined || value === null) {
4
- throw new Error(message);
5
- }
6
- return value;
7
- }
8
- export function setDefaultInstance(es) {
9
- defaultInstance = es;
10
- }
11
- export function getDefaultInstance() {
12
- return defaultInstance;
13
- }
14
- /**
15
- * If an es is defined, then return it, otherwise return the defaultEnterpriseStandard
16
- */
17
- export function getES(es) {
18
- if (es)
19
- return es;
20
- if (defaultInstance)
21
- return defaultInstance;
22
- throw new Error(`TODO standardize the error message when there isn't a default EntepriseStandard`);
23
- }
package/dist/vault.d.ts DELETED
@@ -1,18 +0,0 @@
1
- type Secret<T> = {
2
- data: T;
3
- metadata: MetaData;
4
- };
5
- type MetaData = {
6
- created_time: string;
7
- deletion_time: string;
8
- destroyed: boolean;
9
- version: number;
10
- };
11
- export type Vault = {
12
- url: string;
13
- getFullSecret: <T>(path: string, token: string) => Promise<Secret<T>>;
14
- getSecret: <T>(path: string, token: string) => Promise<T>;
15
- };
16
- export declare function vault(url: string): Vault;
17
- export {};
18
- //# sourceMappingURL=vault.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../src/vault.ts"],"names":[],"mappings":"AAAA,KAAK,MAAM,CAAC,CAAC,IAAI;IACf,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,SAAS,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;CAC3D,CAAC;AAEF,wBAAgB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAqBxC"}
package/dist/vault.js DELETED
@@ -1,22 +0,0 @@
1
- export function vault(url) {
2
- async function getFullSecret(path, token) {
3
- const resp = await fetch(`${url}/${path}`, { headers: { 'X-Vault-Token': token } });
4
- if (resp.status !== 200) {
5
- throw new Error(`Vault returned invalid status, ${resp.status}: '${resp.statusText}' from URL: ${url}`);
6
- }
7
- try {
8
- const secret = await resp.json();
9
- return secret.data;
10
- }
11
- catch (cause) {
12
- throw new Error('Error retrieving secret', { cause });
13
- }
14
- }
15
- return {
16
- url,
17
- getFullSecret,
18
- getSecret: async (path, token) => {
19
- return (await getFullSecret(path, token)).data;
20
- },
21
- };
22
- }