@enterprisestandard/react 0.0.20-beta.20260623.1 → 0.0.20-beta.20260623.2
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/dist/index.js +1 -712
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,712 +1 @@
|
|
|
1
|
-
// packages/react/src/index.ts
|
|
2
|
-
export * from "@enterprisestandard/core";
|
|
3
|
-
import { generateULID } from "@enterprisestandard/core";
|
|
4
|
-
|
|
5
|
-
// packages/react/src/ciam-provider.tsx
|
|
6
|
-
import { silentLogger } from "@enterprisestandard/core";
|
|
7
|
-
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
|
8
|
-
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
9
|
-
var CTX = createContext(undefined);
|
|
10
|
-
var VALID_STORAGE_KEY = /^[a-zA-Z0-9._-]{1,1024}$/;
|
|
11
|
-
function validateStorageKey(key) {
|
|
12
|
-
if (!key.trim()) {
|
|
13
|
-
throw new Error("CIAMProvider storageKey must be a non-empty string.");
|
|
14
|
-
}
|
|
15
|
-
if (!VALID_STORAGE_KEY.test(key)) {
|
|
16
|
-
throw new Error("CIAMProvider storageKey must be 1-1024 characters and contain only letters, numbers, dots, underscores, and hyphens.");
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
var getStorageKey = (storageKey) => {
|
|
20
|
-
if (storageKey === undefined || storageKey === "") {
|
|
21
|
-
return "es.ciam.customer";
|
|
22
|
-
}
|
|
23
|
-
validateStorageKey(storageKey);
|
|
24
|
-
return storageKey;
|
|
25
|
-
};
|
|
26
|
-
function loadCustomerFromStorageForKey(storage, storageKey, log = silentLogger) {
|
|
27
|
-
if (typeof window === "undefined")
|
|
28
|
-
return null;
|
|
29
|
-
try {
|
|
30
|
-
const storageObject = storage === "local" ? localStorage : sessionStorage;
|
|
31
|
-
const customerData = storageObject.getItem(storageKey);
|
|
32
|
-
if (!customerData)
|
|
33
|
-
return null;
|
|
34
|
-
const parsedCustomer = JSON.parse(customerData);
|
|
35
|
-
if (parsedCustomer.ciam?.expires) {
|
|
36
|
-
parsedCustomer.ciam.expires = new Date(parsedCustomer.ciam.expires);
|
|
37
|
-
}
|
|
38
|
-
return parsedCustomer;
|
|
39
|
-
} catch (error) {
|
|
40
|
-
log.error("Error loading customer from storage:", error);
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
async function fetchCustomerFromServer(customerUrl, log = silentLogger) {
|
|
45
|
-
try {
|
|
46
|
-
const response = await fetch(customerUrl);
|
|
47
|
-
if (response.status === 401) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
if (!response.ok) {
|
|
51
|
-
throw new Error(`Failed to fetch customer: ${response.status} ${response.statusText}`);
|
|
52
|
-
}
|
|
53
|
-
const customerData = await response.json();
|
|
54
|
-
if (customerData.ciam?.expires && typeof customerData.ciam.expires === "string") {
|
|
55
|
-
customerData.ciam.expires = new Date(customerData.ciam.expires);
|
|
56
|
-
}
|
|
57
|
-
return customerData;
|
|
58
|
-
} catch (error) {
|
|
59
|
-
log.error("Error fetching customer from URL:", error);
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
function CIAMProvider({
|
|
64
|
-
storageKey: storageKeyProp,
|
|
65
|
-
customerUrl,
|
|
66
|
-
storage = "memory",
|
|
67
|
-
disableListener = false,
|
|
68
|
-
log = silentLogger,
|
|
69
|
-
children
|
|
70
|
-
}) {
|
|
71
|
-
const [customer, setCustomerState] = useState(null);
|
|
72
|
-
const [isLoading, setIsLoading] = useState(!!customerUrl);
|
|
73
|
-
const storageKey = getStorageKey(storageKeyProp);
|
|
74
|
-
const loadCustomerFromStorage = useCallback(() => {
|
|
75
|
-
if (storage === "memory")
|
|
76
|
-
return null;
|
|
77
|
-
return loadCustomerFromStorageForKey(storage, storageKey, log);
|
|
78
|
-
}, [storage, storageKey, log]);
|
|
79
|
-
const saveCustomerToStorage = useCallback((customer2) => {
|
|
80
|
-
if (storage === "memory" || typeof window === "undefined")
|
|
81
|
-
return;
|
|
82
|
-
try {
|
|
83
|
-
const storageObject = storage === "local" ? localStorage : sessionStorage;
|
|
84
|
-
if (customer2 === null) {
|
|
85
|
-
storageObject.removeItem(storageKey);
|
|
86
|
-
} else {
|
|
87
|
-
storageObject.setItem(storageKey, JSON.stringify(customer2));
|
|
88
|
-
}
|
|
89
|
-
} catch (error) {
|
|
90
|
-
log.error("Error saving customer to storage:", error);
|
|
91
|
-
}
|
|
92
|
-
}, [storage, storageKey, log]);
|
|
93
|
-
const setCustomer = useCallback((newCustomer) => {
|
|
94
|
-
setCustomerState(newCustomer);
|
|
95
|
-
saveCustomerToStorage(newCustomer);
|
|
96
|
-
}, [saveCustomerToStorage]);
|
|
97
|
-
const fetchCustomerFromUrl = useCallback(async () => {
|
|
98
|
-
if (!customerUrl)
|
|
99
|
-
return;
|
|
100
|
-
setIsLoading(true);
|
|
101
|
-
try {
|
|
102
|
-
const customerData = await fetchCustomerFromServer(customerUrl, log);
|
|
103
|
-
setCustomerState(customerData);
|
|
104
|
-
saveCustomerToStorage(customerData);
|
|
105
|
-
} finally {
|
|
106
|
-
setIsLoading(false);
|
|
107
|
-
}
|
|
108
|
-
}, [customerUrl, saveCustomerToStorage, log]);
|
|
109
|
-
useEffect(() => {
|
|
110
|
-
const storedCustomer = loadCustomerFromStorage();
|
|
111
|
-
if (storedCustomer) {
|
|
112
|
-
setCustomerState(storedCustomer);
|
|
113
|
-
}
|
|
114
|
-
if (customerUrl) {
|
|
115
|
-
fetchCustomerFromUrl();
|
|
116
|
-
} else {
|
|
117
|
-
setIsLoading(false);
|
|
118
|
-
}
|
|
119
|
-
}, [loadCustomerFromStorage, customerUrl, fetchCustomerFromUrl]);
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
if (disableListener || storage === "memory")
|
|
122
|
-
return;
|
|
123
|
-
const handleStorageChange = (event) => {
|
|
124
|
-
if (event.key !== storageKey)
|
|
125
|
-
return;
|
|
126
|
-
if (event.newValue === null) {
|
|
127
|
-
setCustomerState(null);
|
|
128
|
-
} else {
|
|
129
|
-
try {
|
|
130
|
-
const parsedCustomer = JSON.parse(event.newValue);
|
|
131
|
-
if (parsedCustomer.ciam?.expires) {
|
|
132
|
-
parsedCustomer.ciam.expires = new Date(parsedCustomer.ciam.expires);
|
|
133
|
-
}
|
|
134
|
-
setCustomerState(parsedCustomer);
|
|
135
|
-
} catch (error) {
|
|
136
|
-
log.error("Error parsing customer from storage event:", error);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
const handleLogout = () => {
|
|
141
|
-
setCustomerState(null);
|
|
142
|
-
};
|
|
143
|
-
window.addEventListener("storage", handleStorageChange);
|
|
144
|
-
window.addEventListener("es-ciam-logout", handleLogout);
|
|
145
|
-
return () => {
|
|
146
|
-
window.removeEventListener("storage", handleStorageChange);
|
|
147
|
-
window.removeEventListener("es-ciam-logout", handleLogout);
|
|
148
|
-
};
|
|
149
|
-
}, [disableListener, storage, storageKey, log]);
|
|
150
|
-
const contextValue = {
|
|
151
|
-
customer,
|
|
152
|
-
setCustomer,
|
|
153
|
-
isLoading
|
|
154
|
-
};
|
|
155
|
-
return /* @__PURE__ */ jsxDEV(CTX.Provider, {
|
|
156
|
-
value: contextValue,
|
|
157
|
-
children
|
|
158
|
-
}, undefined, false, undefined, this);
|
|
159
|
-
}
|
|
160
|
-
function useCIAMContext() {
|
|
161
|
-
const context = useContext(CTX);
|
|
162
|
-
if (context === undefined) {
|
|
163
|
-
throw new Error("useCIAMContext must be used within a CIAMProvider");
|
|
164
|
-
}
|
|
165
|
-
return context;
|
|
166
|
-
}
|
|
167
|
-
function useOptionalCIAMContext() {
|
|
168
|
-
return useContext(CTX);
|
|
169
|
-
}
|
|
170
|
-
async function getCustomer(customerUrl, storageKey) {
|
|
171
|
-
const key = getStorageKey(storageKey);
|
|
172
|
-
const fromLocal = loadCustomerFromStorageForKey("local", key);
|
|
173
|
-
if (fromLocal)
|
|
174
|
-
return fromLocal;
|
|
175
|
-
const fromSession = loadCustomerFromStorageForKey("session", key);
|
|
176
|
-
if (fromSession)
|
|
177
|
-
return fromSession;
|
|
178
|
-
if (customerUrl) {
|
|
179
|
-
const fromServer = await fetchCustomerFromServer(customerUrl);
|
|
180
|
-
if (fromServer)
|
|
181
|
-
return fromServer;
|
|
182
|
-
}
|
|
183
|
-
return;
|
|
184
|
-
}
|
|
185
|
-
async function logoutCustomer(logoutUrl) {
|
|
186
|
-
try {
|
|
187
|
-
const response = await fetch(logoutUrl, {
|
|
188
|
-
headers: { Accept: "application/json" }
|
|
189
|
-
});
|
|
190
|
-
if (!response.ok) {
|
|
191
|
-
return { success: false, error: `HTTP ${response.status}` };
|
|
192
|
-
}
|
|
193
|
-
const data = await response.json();
|
|
194
|
-
if (!data.success) {
|
|
195
|
-
return { success: false, error: data.message || "Logout failed" };
|
|
196
|
-
}
|
|
197
|
-
if (typeof window !== "undefined") {
|
|
198
|
-
localStorage.removeItem("es.ciam.customer");
|
|
199
|
-
sessionStorage.removeItem("es.ciam.customer");
|
|
200
|
-
window.dispatchEvent(new CustomEvent("es-ciam-logout"));
|
|
201
|
-
}
|
|
202
|
-
return { success: true };
|
|
203
|
-
} catch (error) {
|
|
204
|
-
return {
|
|
205
|
-
success: false,
|
|
206
|
-
error: error instanceof Error ? error.message : "Network error"
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
// packages/react/src/ciam-providers.tsx
|
|
211
|
-
import { silentLogger as silentLogger2 } from "@enterprisestandard/core";
|
|
212
|
-
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
213
|
-
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
214
|
-
function useCIAMProviders(providersUrl, log = silentLogger2) {
|
|
215
|
-
const [providers, setProviders] = useState2([]);
|
|
216
|
-
const [isLoading, setIsLoading] = useState2(Boolean(providersUrl));
|
|
217
|
-
const [error, setError] = useState2(null);
|
|
218
|
-
const refresh = useCallback2(() => {
|
|
219
|
-
if (!providersUrl)
|
|
220
|
-
return;
|
|
221
|
-
let cancelled = false;
|
|
222
|
-
setIsLoading(true);
|
|
223
|
-
setError(null);
|
|
224
|
-
fetch(providersUrl, { headers: { Accept: "application/json" } }).then(async (response) => {
|
|
225
|
-
if (!response.ok) {
|
|
226
|
-
throw new Error(`Failed to fetch CIAM providers: ${response.status} ${response.statusText}`);
|
|
227
|
-
}
|
|
228
|
-
const data = await response.json();
|
|
229
|
-
if (!cancelled)
|
|
230
|
-
setProviders(Array.isArray(data.providers) ? data.providers : []);
|
|
231
|
-
}).catch((err) => {
|
|
232
|
-
const normalized = err instanceof Error ? err : new Error(String(err));
|
|
233
|
-
log.error("Error fetching CIAM providers:", normalized);
|
|
234
|
-
if (!cancelled)
|
|
235
|
-
setError(normalized);
|
|
236
|
-
}).finally(() => {
|
|
237
|
-
if (!cancelled)
|
|
238
|
-
setIsLoading(false);
|
|
239
|
-
});
|
|
240
|
-
return () => {
|
|
241
|
-
cancelled = true;
|
|
242
|
-
};
|
|
243
|
-
}, [providersUrl, log]);
|
|
244
|
-
useEffect2(() => {
|
|
245
|
-
const cleanup = refresh();
|
|
246
|
-
return cleanup;
|
|
247
|
-
}, [refresh]);
|
|
248
|
-
return { providers, isLoading, error, refresh };
|
|
249
|
-
}
|
|
250
|
-
function providerButtonStyle(provider, theme) {
|
|
251
|
-
const background = theme === "dark" ? provider.colors?.dark : provider.colors?.light;
|
|
252
|
-
return {
|
|
253
|
-
display: "flex",
|
|
254
|
-
alignItems: "center",
|
|
255
|
-
gap: "0.5rem",
|
|
256
|
-
width: "100%",
|
|
257
|
-
padding: "0.625rem 0.875rem",
|
|
258
|
-
border: "1px solid rgba(0,0,0,0.15)",
|
|
259
|
-
borderRadius: "0.5rem",
|
|
260
|
-
background: background ?? (theme === "dark" ? "#1f1f1f" : "#ffffff"),
|
|
261
|
-
color: theme === "dark" ? "#ffffff" : "#111111",
|
|
262
|
-
textDecoration: "none",
|
|
263
|
-
font: "inherit",
|
|
264
|
-
cursor: "pointer"
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
function CIAMProviderList({
|
|
268
|
-
providersUrl,
|
|
269
|
-
limit,
|
|
270
|
-
theme = "light",
|
|
271
|
-
renderProvider,
|
|
272
|
-
loadingFallback,
|
|
273
|
-
emptyFallback,
|
|
274
|
-
moreLabel = "Show more",
|
|
275
|
-
className,
|
|
276
|
-
log = silentLogger2
|
|
277
|
-
}) {
|
|
278
|
-
const { providers, isLoading } = useCIAMProviders(providersUrl, log);
|
|
279
|
-
const [expanded, setExpanded] = useState2(false);
|
|
280
|
-
if (isLoading) {
|
|
281
|
-
return loadingFallback ?? null;
|
|
282
|
-
}
|
|
283
|
-
if (providers.length === 0) {
|
|
284
|
-
return emptyFallback ?? null;
|
|
285
|
-
}
|
|
286
|
-
const visible = !expanded && typeof limit === "number" && limit > 0 ? providers.slice(0, limit) : providers;
|
|
287
|
-
const hasMore = visible.length < providers.length;
|
|
288
|
-
return /* @__PURE__ */ jsxDEV2("div", {
|
|
289
|
-
className,
|
|
290
|
-
style: { display: "flex", flexDirection: "column", gap: "0.5rem" },
|
|
291
|
-
"data-es-ciam-providers": "",
|
|
292
|
-
children: [
|
|
293
|
-
visible.map((provider) => renderProvider ? /* @__PURE__ */ jsxDEV2("span", {
|
|
294
|
-
children: renderProvider(provider)
|
|
295
|
-
}, provider.name, false, undefined, this) : /* @__PURE__ */ jsxDEV2("a", {
|
|
296
|
-
href: provider.loginUrl,
|
|
297
|
-
style: providerButtonStyle(provider, theme),
|
|
298
|
-
"data-es-ciam-provider": provider.name,
|
|
299
|
-
children: [
|
|
300
|
-
provider.iconUrl ? /* @__PURE__ */ jsxDEV2("img", {
|
|
301
|
-
src: provider.iconUrl,
|
|
302
|
-
alt: "",
|
|
303
|
-
width: 20,
|
|
304
|
-
height: 20,
|
|
305
|
-
"aria-hidden": "true"
|
|
306
|
-
}, undefined, false, undefined, this) : null,
|
|
307
|
-
/* @__PURE__ */ jsxDEV2("span", {
|
|
308
|
-
children: [
|
|
309
|
-
"Continue with ",
|
|
310
|
-
provider.displayName
|
|
311
|
-
]
|
|
312
|
-
}, undefined, true, undefined, this)
|
|
313
|
-
]
|
|
314
|
-
}, provider.name, true, undefined, this)),
|
|
315
|
-
hasMore ? /* @__PURE__ */ jsxDEV2("button", {
|
|
316
|
-
type: "button",
|
|
317
|
-
onClick: () => setExpanded(true),
|
|
318
|
-
"data-es-ciam-show-more": "",
|
|
319
|
-
children: moreLabel
|
|
320
|
-
}, undefined, false, undefined, this) : null
|
|
321
|
-
]
|
|
322
|
-
}, undefined, true, undefined, this);
|
|
323
|
-
}
|
|
324
|
-
// packages/react/src/sso-provider.tsx
|
|
325
|
-
import { silentLogger as silentLogger3 } from "@enterprisestandard/core";
|
|
326
|
-
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect3, useState as useState3 } from "react";
|
|
327
|
-
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
328
|
-
var CTX2 = createContext2(undefined);
|
|
329
|
-
var VALID_STORAGE_KEY2 = /^[a-zA-Z0-9._-]{1,1024}$/;
|
|
330
|
-
function validateStorageKey2(key) {
|
|
331
|
-
if (!key.trim()) {
|
|
332
|
-
throw new Error("SSOProvider storageKey must be a non-empty string.");
|
|
333
|
-
}
|
|
334
|
-
if (!VALID_STORAGE_KEY2.test(key)) {
|
|
335
|
-
throw new Error("SSOProvider storageKey must be 1-1024 characters and contain only letters, numbers, dots, underscores, and hyphens.");
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
var getStorageKey2 = (storageKey) => {
|
|
339
|
-
if (storageKey === undefined || storageKey === "") {
|
|
340
|
-
return "es.sso.user";
|
|
341
|
-
}
|
|
342
|
-
validateStorageKey2(storageKey);
|
|
343
|
-
return storageKey;
|
|
344
|
-
};
|
|
345
|
-
function loadUserFromStorageForKey(storage, storageKey, log = silentLogger3) {
|
|
346
|
-
if (typeof window === "undefined")
|
|
347
|
-
return null;
|
|
348
|
-
try {
|
|
349
|
-
const storageObject = storage === "local" ? localStorage : sessionStorage;
|
|
350
|
-
const userData = storageObject.getItem(storageKey);
|
|
351
|
-
if (!userData)
|
|
352
|
-
return null;
|
|
353
|
-
const parsedUser = JSON.parse(userData);
|
|
354
|
-
if (parsedUser.sso?.expires) {
|
|
355
|
-
parsedUser.sso.expires = new Date(parsedUser.sso.expires);
|
|
356
|
-
}
|
|
357
|
-
return parsedUser;
|
|
358
|
-
} catch (error) {
|
|
359
|
-
log.error("Error loading user from storage:", error);
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
async function fetchUserFromServer(userUrl, log = silentLogger3) {
|
|
364
|
-
try {
|
|
365
|
-
const response = await fetch(userUrl);
|
|
366
|
-
if (response.status === 401) {
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
if (!response.ok) {
|
|
370
|
-
throw new Error(`Failed to fetch user: ${response.status} ${response.statusText}`);
|
|
371
|
-
}
|
|
372
|
-
const userData = await response.json();
|
|
373
|
-
if (userData.sso?.expires && typeof userData.sso.expires === "string") {
|
|
374
|
-
userData.sso.expires = new Date(userData.sso.expires);
|
|
375
|
-
}
|
|
376
|
-
return userData;
|
|
377
|
-
} catch (error) {
|
|
378
|
-
log.error("Error fetching user from URL:", error);
|
|
379
|
-
return null;
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
function SSOProvider({
|
|
383
|
-
storageKey: storageKeyProp,
|
|
384
|
-
userUrl,
|
|
385
|
-
storage = "memory",
|
|
386
|
-
disableListener = false,
|
|
387
|
-
log = silentLogger3,
|
|
388
|
-
children
|
|
389
|
-
}) {
|
|
390
|
-
const [user, setUserState] = useState3(null);
|
|
391
|
-
const [isLoading, setIsLoading] = useState3(!!userUrl);
|
|
392
|
-
const storageKey = getStorageKey2(storageKeyProp);
|
|
393
|
-
const loadUserFromStorage = useCallback3(() => {
|
|
394
|
-
if (storage === "memory")
|
|
395
|
-
return null;
|
|
396
|
-
return loadUserFromStorageForKey(storage, storageKey, log);
|
|
397
|
-
}, [storage, storageKey, log]);
|
|
398
|
-
const saveUserToStorage = useCallback3((user2) => {
|
|
399
|
-
if (storage === "memory" || typeof window === "undefined")
|
|
400
|
-
return;
|
|
401
|
-
try {
|
|
402
|
-
const storageObject = storage === "local" ? localStorage : sessionStorage;
|
|
403
|
-
if (user2 === null) {
|
|
404
|
-
storageObject.removeItem(storageKey);
|
|
405
|
-
} else {
|
|
406
|
-
storageObject.setItem(storageKey, JSON.stringify(user2));
|
|
407
|
-
}
|
|
408
|
-
} catch (error) {
|
|
409
|
-
log.error("Error saving user to storage:", error);
|
|
410
|
-
}
|
|
411
|
-
}, [storage, storageKey, log]);
|
|
412
|
-
const setUser = useCallback3((newUser) => {
|
|
413
|
-
setUserState(newUser);
|
|
414
|
-
saveUserToStorage(newUser);
|
|
415
|
-
}, [saveUserToStorage]);
|
|
416
|
-
const fetchUserFromUrl = useCallback3(async () => {
|
|
417
|
-
if (!userUrl)
|
|
418
|
-
return;
|
|
419
|
-
setIsLoading(true);
|
|
420
|
-
try {
|
|
421
|
-
const userData = await fetchUserFromServer(userUrl, log);
|
|
422
|
-
setUserState(userData);
|
|
423
|
-
saveUserToStorage(userData);
|
|
424
|
-
} finally {
|
|
425
|
-
setIsLoading(false);
|
|
426
|
-
}
|
|
427
|
-
}, [userUrl, saveUserToStorage, log]);
|
|
428
|
-
useEffect3(() => {
|
|
429
|
-
const storedUser = loadUserFromStorage();
|
|
430
|
-
if (storedUser) {
|
|
431
|
-
setUserState(storedUser);
|
|
432
|
-
}
|
|
433
|
-
if (userUrl) {
|
|
434
|
-
fetchUserFromUrl();
|
|
435
|
-
} else {
|
|
436
|
-
setIsLoading(false);
|
|
437
|
-
}
|
|
438
|
-
}, [loadUserFromStorage, userUrl, fetchUserFromUrl]);
|
|
439
|
-
useEffect3(() => {
|
|
440
|
-
if (disableListener || storage === "memory")
|
|
441
|
-
return;
|
|
442
|
-
const handleStorageChange = (event) => {
|
|
443
|
-
if (event.key !== storageKey)
|
|
444
|
-
return;
|
|
445
|
-
if (event.newValue === null) {
|
|
446
|
-
setUserState(null);
|
|
447
|
-
} else {
|
|
448
|
-
try {
|
|
449
|
-
const parsedUser = JSON.parse(event.newValue);
|
|
450
|
-
if (parsedUser.sso?.expires) {
|
|
451
|
-
parsedUser.sso.expires = new Date(parsedUser.sso.expires);
|
|
452
|
-
}
|
|
453
|
-
setUserState(parsedUser);
|
|
454
|
-
} catch (error) {
|
|
455
|
-
log.error("Error parsing user from storage event:", error);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
};
|
|
459
|
-
const handleLogout = () => {
|
|
460
|
-
setUserState(null);
|
|
461
|
-
};
|
|
462
|
-
window.addEventListener("storage", handleStorageChange);
|
|
463
|
-
window.addEventListener("es-sso-logout", handleLogout);
|
|
464
|
-
return () => {
|
|
465
|
-
window.removeEventListener("storage", handleStorageChange);
|
|
466
|
-
window.removeEventListener("es-sso-logout", handleLogout);
|
|
467
|
-
};
|
|
468
|
-
}, [disableListener, storage, storageKey, log]);
|
|
469
|
-
const contextValue = {
|
|
470
|
-
user,
|
|
471
|
-
setUser,
|
|
472
|
-
isLoading
|
|
473
|
-
};
|
|
474
|
-
return /* @__PURE__ */ jsxDEV3(CTX2.Provider, {
|
|
475
|
-
value: contextValue,
|
|
476
|
-
children
|
|
477
|
-
}, undefined, false, undefined, this);
|
|
478
|
-
}
|
|
479
|
-
function useSSOContext() {
|
|
480
|
-
const context = useContext2(CTX2);
|
|
481
|
-
if (context === undefined) {
|
|
482
|
-
throw new Error("useSSOContext must be used within a SSOProvider");
|
|
483
|
-
}
|
|
484
|
-
return context;
|
|
485
|
-
}
|
|
486
|
-
function useOptionalSSOContext() {
|
|
487
|
-
return useContext2(CTX2);
|
|
488
|
-
}
|
|
489
|
-
async function getUser(userUrl, storageKey) {
|
|
490
|
-
const key = getStorageKey2(storageKey);
|
|
491
|
-
const fromLocal = loadUserFromStorageForKey("local", key);
|
|
492
|
-
if (fromLocal)
|
|
493
|
-
return fromLocal;
|
|
494
|
-
const fromSession = loadUserFromStorageForKey("session", key);
|
|
495
|
-
if (fromSession)
|
|
496
|
-
return fromSession;
|
|
497
|
-
if (userUrl) {
|
|
498
|
-
const fromServer = await fetchUserFromServer(userUrl);
|
|
499
|
-
if (fromServer)
|
|
500
|
-
return fromServer;
|
|
501
|
-
}
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
async function logout(logoutUrl) {
|
|
505
|
-
try {
|
|
506
|
-
const response = await fetch(logoutUrl, {
|
|
507
|
-
headers: { Accept: "application/json" }
|
|
508
|
-
});
|
|
509
|
-
if (!response.ok) {
|
|
510
|
-
return { success: false, error: `HTTP ${response.status}` };
|
|
511
|
-
}
|
|
512
|
-
const data = await response.json();
|
|
513
|
-
if (!data.success) {
|
|
514
|
-
return { success: false, error: data.message || "Logout failed" };
|
|
515
|
-
}
|
|
516
|
-
if (typeof window !== "undefined") {
|
|
517
|
-
localStorage.removeItem("es.sso.user");
|
|
518
|
-
sessionStorage.removeItem("es.sso.user");
|
|
519
|
-
window.dispatchEvent(new CustomEvent("es-sso-logout"));
|
|
520
|
-
}
|
|
521
|
-
return { success: true };
|
|
522
|
-
} catch (error) {
|
|
523
|
-
return {
|
|
524
|
-
success: false,
|
|
525
|
-
error: error instanceof Error ? error.message : "Network error"
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// packages/react/src/sign-in-loading.tsx
|
|
531
|
-
import { jsxDEV as jsxDEV4, Fragment } from "react/jsx-dev-runtime";
|
|
532
|
-
function SignInLoading({
|
|
533
|
-
complete = false,
|
|
534
|
-
audience = "workforce",
|
|
535
|
-
children
|
|
536
|
-
}) {
|
|
537
|
-
const sso = useOptionalSSOContext();
|
|
538
|
-
const ciam = useOptionalCIAMContext();
|
|
539
|
-
const isLoading = audience === "customer" ? !!ciam?.isLoading : !!sso?.isLoading;
|
|
540
|
-
if (isLoading && !complete)
|
|
541
|
-
return /* @__PURE__ */ jsxDEV4(Fragment, {
|
|
542
|
-
children
|
|
543
|
-
}, undefined, false, undefined, this);
|
|
544
|
-
return null;
|
|
545
|
-
}
|
|
546
|
-
// packages/react/src/signed-in.tsx
|
|
547
|
-
import { jsxDEV as jsxDEV5, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
548
|
-
function SignedIn({
|
|
549
|
-
audience = "workforce",
|
|
550
|
-
children
|
|
551
|
-
}) {
|
|
552
|
-
const sso = useOptionalSSOContext();
|
|
553
|
-
const ciam = useOptionalCIAMContext();
|
|
554
|
-
const present = audience === "customer" ? !!ciam?.customer : !!sso?.user;
|
|
555
|
-
if (present)
|
|
556
|
-
return /* @__PURE__ */ jsxDEV5(Fragment2, {
|
|
557
|
-
children
|
|
558
|
-
}, undefined, false, undefined, this);
|
|
559
|
-
return null;
|
|
560
|
-
}
|
|
561
|
-
// packages/react/src/signed-out.tsx
|
|
562
|
-
import { jsxDEV as jsxDEV6, Fragment as Fragment3 } from "react/jsx-dev-runtime";
|
|
563
|
-
function SignedOut({
|
|
564
|
-
audience = "workforce",
|
|
565
|
-
children
|
|
566
|
-
}) {
|
|
567
|
-
const sso = useOptionalSSOContext();
|
|
568
|
-
const ciam = useOptionalCIAMContext();
|
|
569
|
-
const present = audience === "customer" ? !!ciam?.customer : !!sso?.user;
|
|
570
|
-
const isLoading = audience === "customer" ? !!ciam?.isLoading : !!sso?.isLoading;
|
|
571
|
-
if (present || isLoading)
|
|
572
|
-
return null;
|
|
573
|
-
return /* @__PURE__ */ jsxDEV6(Fragment3, {
|
|
574
|
-
children
|
|
575
|
-
}, undefined, false, undefined, this);
|
|
576
|
-
}
|
|
577
|
-
// packages/react/src/tenant-context.tsx
|
|
578
|
-
import {
|
|
579
|
-
buildTenantPath,
|
|
580
|
-
DEFAULT_TENANT_API_NAMESPACE,
|
|
581
|
-
DEFAULT_TENANT_UI_NAMESPACE,
|
|
582
|
-
normalizeTenantRoutingStrategy
|
|
583
|
-
} from "@enterprisestandard/core";
|
|
584
|
-
import { createContext as createContext3, useContext as useContext3, useMemo } from "react";
|
|
585
|
-
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
586
|
-
var TenantContext = createContext3(null);
|
|
587
|
-
function createTenantUrls(id, strategy) {
|
|
588
|
-
const normalized = normalizeTenantRoutingStrategy(strategy);
|
|
589
|
-
if (normalized.type === "jwt") {
|
|
590
|
-
const uiSegments = normalized.ui?.segments ?? [];
|
|
591
|
-
const apiSegments = normalized.api?.segments ?? ["api"];
|
|
592
|
-
return {
|
|
593
|
-
ui: (restPath = "/") => buildStaticPath(uiSegments, restPath),
|
|
594
|
-
api: (restPath = "/") => buildStaticPath(apiSegments, restPath)
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
const uiNamespace = normalized.ui ?? DEFAULT_TENANT_UI_NAMESPACE;
|
|
598
|
-
const apiNamespace = normalized.api ?? DEFAULT_TENANT_API_NAMESPACE;
|
|
599
|
-
return {
|
|
600
|
-
ui: (restPath = "/") => buildTenantPath(id, restPath, uiNamespace),
|
|
601
|
-
api: (restPath = "/") => buildTenantPath(id, restPath, apiNamespace)
|
|
602
|
-
};
|
|
603
|
-
}
|
|
604
|
-
function buildStaticPath(prefixSegments, restPath = "/") {
|
|
605
|
-
const prefix = prefixSegments.join("/");
|
|
606
|
-
const rest = restPath.trim().replace(/^\/+/, "");
|
|
607
|
-
if (!prefix && !rest)
|
|
608
|
-
return "/";
|
|
609
|
-
if (!prefix)
|
|
610
|
-
return `/${rest}`;
|
|
611
|
-
if (!rest)
|
|
612
|
-
return `/${prefix}`;
|
|
613
|
-
return `/${prefix}/${rest}`;
|
|
614
|
-
}
|
|
615
|
-
function TenantProvider({ id, strategy, children }) {
|
|
616
|
-
const value = useMemo(() => {
|
|
617
|
-
const normalized = normalizeTenantRoutingStrategy(strategy);
|
|
618
|
-
return {
|
|
619
|
-
id,
|
|
620
|
-
strategy: normalized,
|
|
621
|
-
urls: createTenantUrls(id, normalized)
|
|
622
|
-
};
|
|
623
|
-
}, [strategy, id]);
|
|
624
|
-
return /* @__PURE__ */ jsxDEV7(TenantContext.Provider, {
|
|
625
|
-
value,
|
|
626
|
-
children
|
|
627
|
-
}, undefined, false, undefined, this);
|
|
628
|
-
}
|
|
629
|
-
function useTenant() {
|
|
630
|
-
const value = useContext3(TenantContext);
|
|
631
|
-
if (!value) {
|
|
632
|
-
throw new Error("useTenant() must be used within a TenantProvider");
|
|
633
|
-
}
|
|
634
|
-
return value;
|
|
635
|
-
}
|
|
636
|
-
// packages/react/src/use-tenant-directory.ts
|
|
637
|
-
import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo2, useState as useState4 } from "react";
|
|
638
|
-
function useTenantDirectory(options = {}) {
|
|
639
|
-
const tenantManagerBaseUrl = options.tenantManagerBaseUrl ?? "/api/tenants/mine";
|
|
640
|
-
const [directory, setDirectory] = useState4(null);
|
|
641
|
-
const [isLoading, setIsLoading] = useState4(true);
|
|
642
|
-
const [error, setError] = useState4(null);
|
|
643
|
-
const requestUrl = useMemo2(() => {
|
|
644
|
-
const url = new URL(tenantManagerBaseUrl, "http://localhost");
|
|
645
|
-
if (options.start != null) {
|
|
646
|
-
url.searchParams.set("start", String(options.start));
|
|
647
|
-
}
|
|
648
|
-
if (options.limit != null) {
|
|
649
|
-
url.searchParams.set("limit", String(options.limit));
|
|
650
|
-
}
|
|
651
|
-
if (options.order) {
|
|
652
|
-
url.searchParams.set("order", options.order);
|
|
653
|
-
}
|
|
654
|
-
return `${url.pathname}${url.search}`;
|
|
655
|
-
}, [options.limit, options.order, options.start, tenantManagerBaseUrl]);
|
|
656
|
-
const refresh = useCallback4(async () => {
|
|
657
|
-
setIsLoading(true);
|
|
658
|
-
setError(null);
|
|
659
|
-
try {
|
|
660
|
-
const response = await fetch(requestUrl);
|
|
661
|
-
if (!response.ok) {
|
|
662
|
-
setDirectory(null);
|
|
663
|
-
setError(new Error(`Tenant directory request failed with status ${response.status}`));
|
|
664
|
-
return;
|
|
665
|
-
}
|
|
666
|
-
const data = await response.json();
|
|
667
|
-
setDirectory(data);
|
|
668
|
-
} catch (cause) {
|
|
669
|
-
setDirectory(null);
|
|
670
|
-
setError(cause instanceof Error ? cause : new Error("Failed to load tenant directory"));
|
|
671
|
-
} finally {
|
|
672
|
-
setIsLoading(false);
|
|
673
|
-
}
|
|
674
|
-
}, [requestUrl]);
|
|
675
|
-
useEffect4(() => {
|
|
676
|
-
refresh();
|
|
677
|
-
}, [refresh]);
|
|
678
|
-
const tenants = directory?.tenants ?? {};
|
|
679
|
-
const ids = directory?.ids ?? [];
|
|
680
|
-
const items = ids.map((id) => tenants[id]).filter((tenant) => !!tenant);
|
|
681
|
-
return {
|
|
682
|
-
directory,
|
|
683
|
-
tenants,
|
|
684
|
-
ids,
|
|
685
|
-
items,
|
|
686
|
-
isLoading,
|
|
687
|
-
error,
|
|
688
|
-
refresh
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
export {
|
|
692
|
-
useTenantDirectory,
|
|
693
|
-
useTenant,
|
|
694
|
-
useSSOContext,
|
|
695
|
-
useOptionalSSOContext,
|
|
696
|
-
useOptionalCIAMContext,
|
|
697
|
-
useCIAMProviders,
|
|
698
|
-
useCIAMContext,
|
|
699
|
-
logoutCustomer,
|
|
700
|
-
logout,
|
|
701
|
-
getUser,
|
|
702
|
-
getCustomer,
|
|
703
|
-
generateULID,
|
|
704
|
-
createTenantUrls,
|
|
705
|
-
TenantProvider,
|
|
706
|
-
SignedOut,
|
|
707
|
-
SignedIn,
|
|
708
|
-
SignInLoading,
|
|
709
|
-
SSOProvider,
|
|
710
|
-
CIAMProviderList,
|
|
711
|
-
CIAMProvider
|
|
712
|
-
};
|
|
1
|
+
export*from"@enterprisestandard/core";import{generateULID as Bi}from"@enterprisestandard/core";import{silentLogger as Y}from"@enterprisestandard/core";import{createContext as s,useCallback as J,useContext as b,useEffect as C,useState as L}from"react";import{jsx as Rn}from"react/jsx-runtime";var G=s(void 0),r=/^[a-zA-Z0-9._-]{1,1024}$/;function e(n){if(!n.trim())throw Error("CIAMProvider storageKey must be a non-empty string.");if(!r.test(n))throw Error("CIAMProvider storageKey must be 1-1024 characters and contain only letters, numbers, dots, underscores, and hyphens.")}var u=(n)=>{if(n===void 0||n==="")return"es.ciam.customer";return e(n),n};function Z(n,T,i=Y){if(typeof window>"u")return null;try{let P=(n==="local"?localStorage:sessionStorage).getItem(T);if(!P)return null;let R=JSON.parse(P);if(R.ciam?.expires)R.ciam.expires=new Date(R.ciam.expires);return R}catch(f){return i.error("Error loading customer from storage:",f),null}}async function F(n,T=Y){try{let i=await fetch(n);if(i.status===401)return null;if(!i.ok)throw Error(`Failed to fetch customer: ${i.status} ${i.statusText}`);let f=await i.json();if(f.ciam?.expires&&typeof f.ciam.expires==="string")f.ciam.expires=new Date(f.ciam.expires);return f}catch(i){return T.error("Error fetching customer from URL:",i),null}}function nn({storageKey:n,customerUrl:T,storage:i="memory",disableListener:f=!1,log:P=Y,children:R}){let[q,M]=L(null),[E,x]=L(!!T),A=u(n),N=J(()=>{if(i==="memory")return null;return Z(i,A,P)},[i,A,P]),W=J((c)=>{if(i==="memory"||typeof window>"u")return;try{let $=i==="local"?localStorage:sessionStorage;if(c===null)$.removeItem(A);else $.setItem(A,JSON.stringify(c))}catch($){P.error("Error saving customer to storage:",$)}},[i,A,P]),O=J((c)=>{M(c),W(c)},[W]),B=J(async()=>{if(!T)return;x(!0);try{let c=await F(T,P);M(c),W(c)}finally{x(!1)}},[T,W,P]);C(()=>{let c=N();if(c)M(c);if(T)B();else x(!1)},[N,T,B]),C(()=>{if(f||i==="memory")return;let c=(z)=>{if(z.key!==A)return;if(z.newValue===null)M(null);else try{let I=JSON.parse(z.newValue);if(I.ciam?.expires)I.ciam.expires=new Date(I.ciam.expires);M(I)}catch(I){P.error("Error parsing customer from storage event:",I)}},$=()=>{M(null)};return window.addEventListener("storage",c),window.addEventListener("es-ciam-logout",$),()=>{window.removeEventListener("storage",c),window.removeEventListener("es-ciam-logout",$)}},[f,i,A,P]);let w={customer:q,setCustomer:O,isLoading:E};return Rn(G.Provider,{value:w,children:R})}function Tn(){let n=b(G);if(n===void 0)throw Error("useCIAMContext must be used within a CIAMProvider");return n}function _(){return b(G)}async function fn(n,T){let i=u(T),f=Z("local",i);if(f)return f;let P=Z("session",i);if(P)return P;if(n){let R=await F(n);if(R)return R}return}async function Pn(n){try{let T=await fetch(n,{headers:{Accept:"application/json"}});if(!T.ok)return{success:!1,error:`HTTP ${T.status}`};let i=await T.json();if(!i.success)return{success:!1,error:i.message||"Logout failed"};if(typeof window<"u")localStorage.removeItem("es.ciam.customer"),sessionStorage.removeItem("es.ciam.customer"),window.dispatchEvent(new CustomEvent("es-ciam-logout"));return{success:!0}}catch(T){return{success:!1,error:T instanceof Error?T.message:"Network error"}}}import{silentLogger as y}from"@enterprisestandard/core";import{useCallback as An,useEffect as cn,useState as Q}from"react";import{jsx as p,jsxs as X}from"react/jsx-runtime";function S(n,T=y){let[i,f]=Q([]),[P,R]=Q(Boolean(n)),[q,M]=Q(null),E=An(()=>{if(!n)return;let x=!1;return R(!0),M(null),fetch(n,{headers:{Accept:"application/json"}}).then(async(A)=>{if(!A.ok)throw Error(`Failed to fetch CIAM providers: ${A.status} ${A.statusText}`);let N=await A.json();if(!x)f(Array.isArray(N.providers)?N.providers:[])}).catch((A)=>{let N=A instanceof Error?A:Error(String(A));if(T.error("Error fetching CIAM providers:",N),!x)M(N)}).finally(()=>{if(!x)R(!1)}),()=>{x=!0}},[n,T]);return cn(()=>{return E()},[E]),{providers:i,isLoading:P,error:q,refresh:E}}function Mn(n,T){return{display:"flex",alignItems:"center",gap:"0.5rem",width:"100%",padding:"0.625rem 0.875rem",border:"1px solid rgba(0,0,0,0.15)",borderRadius:"0.5rem",background:(T==="dark"?n.colors?.dark:n.colors?.light)??(T==="dark"?"#1f1f1f":"#ffffff"),color:T==="dark"?"#ffffff":"#111111",textDecoration:"none",font:"inherit",cursor:"pointer"}}function On({providersUrl:n,limit:T,theme:i="light",renderProvider:f,loadingFallback:P,emptyFallback:R,moreLabel:q="Show more",className:M,log:E=y}){let{providers:x,isLoading:A}=S(n,E),[N,W]=Q(!1);if(A)return P??null;if(x.length===0)return R??null;let O=!N&&typeof T==="number"&&T>0?x.slice(0,T):x,B=O.length<x.length;return X("div",{className:M,style:{display:"flex",flexDirection:"column",gap:"0.5rem"},"data-es-ciam-providers":"",children:[O.map((w)=>f?p("span",{children:f(w)},w.name):X("a",{href:w.loginUrl,style:Mn(w,i),"data-es-ciam-provider":w.name,children:[w.iconUrl?p("img",{src:w.iconUrl,alt:"",width:20,height:20,"aria-hidden":"true"}):null,X("span",{children:["Continue with ",w.displayName]})]},w.name)),B?p("button",{type:"button",onClick:()=>W(!0),"data-es-ciam-show-more":"",children:q}):null]})}import{silentLogger as h}from"@enterprisestandard/core";import{createContext as xn,useCallback as V,useContext as K,useEffect as t,useState as m}from"react";import{jsx as qn}from"react/jsx-runtime";var k=xn(void 0),Nn=/^[a-zA-Z0-9._-]{1,1024}$/;function $n(n){if(!n.trim())throw Error("SSOProvider storageKey must be a non-empty string.");if(!Nn.test(n))throw Error("SSOProvider storageKey must be 1-1024 characters and contain only letters, numbers, dots, underscores, and hyphens.")}var v=(n)=>{if(n===void 0||n==="")return"es.sso.user";return $n(n),n};function D(n,T,i=h){if(typeof window>"u")return null;try{let P=(n==="local"?localStorage:sessionStorage).getItem(T);if(!P)return null;let R=JSON.parse(P);if(R.sso?.expires)R.sso.expires=new Date(R.sso.expires);return R}catch(f){return i.error("Error loading user from storage:",f),null}}async function U(n,T=h){try{let i=await fetch(n);if(i.status===401)return null;if(!i.ok)throw Error(`Failed to fetch user: ${i.status} ${i.statusText}`);let f=await i.json();if(f.sso?.expires&&typeof f.sso.expires==="string")f.sso.expires=new Date(f.sso.expires);return f}catch(i){return T.error("Error fetching user from URL:",i),null}}function Wn({storageKey:n,userUrl:T,storage:i="memory",disableListener:f=!1,log:P=h,children:R}){let[q,M]=m(null),[E,x]=m(!!T),A=v(n),N=V(()=>{if(i==="memory")return null;return D(i,A,P)},[i,A,P]),W=V((c)=>{if(i==="memory"||typeof window>"u")return;try{let $=i==="local"?localStorage:sessionStorage;if(c===null)$.removeItem(A);else $.setItem(A,JSON.stringify(c))}catch($){P.error("Error saving user to storage:",$)}},[i,A,P]),O=V((c)=>{M(c),W(c)},[W]),B=V(async()=>{if(!T)return;x(!0);try{let c=await U(T,P);M(c),W(c)}finally{x(!1)}},[T,W,P]);t(()=>{let c=N();if(c)M(c);if(T)B();else x(!1)},[N,T,B]),t(()=>{if(f||i==="memory")return;let c=(z)=>{if(z.key!==A)return;if(z.newValue===null)M(null);else try{let I=JSON.parse(z.newValue);if(I.sso?.expires)I.sso.expires=new Date(I.sso.expires);M(I)}catch(I){P.error("Error parsing user from storage event:",I)}},$=()=>{M(null)};return window.addEventListener("storage",c),window.addEventListener("es-sso-logout",$),()=>{window.removeEventListener("storage",c),window.removeEventListener("es-sso-logout",$)}},[f,i,A,P]);let w={user:q,setUser:O,isLoading:E};return qn(k.Provider,{value:w,children:R})}function wn(){let n=K(k);if(n===void 0)throw Error("useSSOContext must be used within a SSOProvider");return n}function H(){return K(k)}async function In(n,T){let i=v(T),f=D("local",i);if(f)return f;let P=D("session",i);if(P)return P;if(n){let R=await U(n);if(R)return R}return}async function En(n){try{let T=await fetch(n,{headers:{Accept:"application/json"}});if(!T.ok)return{success:!1,error:`HTTP ${T.status}`};let i=await T.json();if(!i.success)return{success:!1,error:i.message||"Logout failed"};if(typeof window<"u")localStorage.removeItem("es.sso.user"),sessionStorage.removeItem("es.sso.user"),window.dispatchEvent(new CustomEvent("es-sso-logout"));return{success:!0}}catch(T){return{success:!1,error:T instanceof Error?T.message:"Network error"}}}import{jsx as _n,Fragment as zn}from"react/jsx-runtime";function Bn({complete:n=!1,audience:T="workforce",children:i}){let f=H(),P=_();if((T==="customer"?!!P?.isLoading:!!f?.isLoading)&&!n)return _n(zn,{children:i});return null}import{jsx as Qn,Fragment as Jn}from"react/jsx-runtime";function Hn({audience:n="workforce",children:T}){let i=H(),f=_();if(n==="customer"?!!f?.customer:!!i?.user)return Qn(Jn,{children:T});return null}import{jsx as Yn,Fragment as Zn}from"react/jsx-runtime";function Vn({audience:n="workforce",children:T}){let i=H(),f=_(),P=n==="customer"?!!f?.customer:!!i?.user,R=n==="customer"?!!f?.isLoading:!!i?.isLoading;if(P||R)return null;return Yn(Zn,{children:T})}import{buildTenantPath as d,DEFAULT_TENANT_API_NAMESPACE as Gn,DEFAULT_TENANT_UI_NAMESPACE as pn,normalizeTenantRoutingStrategy as a}from"@enterprisestandard/core";import{createContext as Xn,useContext as Dn,useMemo as hn}from"react";import{jsx as Cn}from"react/jsx-runtime";var g=Xn(null);function o(n,T){let i=a(T);if(i.type==="jwt"){let R=i.ui?.segments??[],q=i.api?.segments??["api"];return{ui:(M="/")=>l(R,M),api:(M="/")=>l(q,M)}}let f=i.ui??pn,P=i.api??Gn;return{ui:(R="/")=>d(n,R,f),api:(R="/")=>d(n,R,P)}}function l(n,T="/"){let i=n.join("/"),f=T.trim().replace(/^\/+/,"");if(!i&&!f)return"/";if(!i)return`/${f}`;if(!f)return`/${i}`;return`/${i}/${f}`}function kn({id:n,strategy:T,children:i}){let f=hn(()=>{let P=a(T);return{id:n,strategy:P,urls:o(n,P)}},[T,n]);return Cn(g.Provider,{value:f,children:i})}function jn(){let n=Dn(g);if(!n)throw Error("useTenant() must be used within a TenantProvider");return n}import{useCallback as Ln,useEffect as bn,useMemo as un,useState as j}from"react";function Fn(n={}){let T=n.tenantManagerBaseUrl??"/api/tenants/mine",[i,f]=j(null),[P,R]=j(!0),[q,M]=j(null),E=un(()=>{let O=new URL(T,"http://localhost");if(n.start!=null)O.searchParams.set("start",String(n.start));if(n.limit!=null)O.searchParams.set("limit",String(n.limit));if(n.order)O.searchParams.set("order",n.order);return`${O.pathname}${O.search}`},[n.limit,n.order,n.start,T]),x=Ln(async()=>{R(!0),M(null);try{let O=await fetch(E);if(!O.ok){f(null),M(Error(`Tenant directory request failed with status ${O.status}`));return}let B=await O.json();f(B)}catch(O){f(null),M(O instanceof Error?O:Error("Failed to load tenant directory"))}finally{R(!1)}},[E]);bn(()=>{x()},[x]);let A=i?.tenants??{},N=i?.ids??[],W=N.map((O)=>A[O]).filter((O)=>!!O);return{directory:i,tenants:A,ids:N,items:W,isLoading:P,error:q,refresh:x}}export{Fn as useTenantDirectory,jn as useTenant,wn as useSSOContext,H as useOptionalSSOContext,_ as useOptionalCIAMContext,S as useCIAMProviders,Tn as useCIAMContext,Pn as logoutCustomer,En as logout,In as getUser,fn as getCustomer,Bi as generateULID,o as createTenantUrls,kn as TenantProvider,Vn as SignedOut,Hn as SignedIn,Bn as SignInLoading,Wn as SSOProvider,On as CIAMProviderList,nn as CIAMProvider};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enterprisestandard/react",
|
|
3
|
-
"version": "0.0.20-beta.20260623.
|
|
3
|
+
"version": "0.0.20-beta.20260623.2",
|
|
4
4
|
"description": "Enterprise Standard React Components",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "enterprisestandard",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@enterprisestandard/core": "0.0.20-beta.20260623.
|
|
25
|
+
"@enterprisestandard/core": "0.0.20-beta.20260623.2"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^18.0.0 || ^19.0.0",
|