@ionite/react 0.0.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/dist/index.d.ts +162 -0
- package/dist/index.js +1 -0
- package/package.json +36 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# @ionite/react
|
|
2
|
+
|
|
3
|
+
Client/browser React components and hooks for ionite apps: sign-in UI, current-user
|
|
4
|
+
state, and tenant URL helpers. This package is **client-safe** — it never pulls server-only SDK code
|
|
5
|
+
(tenant stores, session discovery, webhooks, vault, IAM/SCIM handlers) into your bundle.
|
|
6
|
+
|
|
7
|
+
> Import server-side and shared types/utilities from `@ionite/core`, and server handler
|
|
8
|
+
> code from `@ionite/core/server` or `@ionite/server`. This package
|
|
9
|
+
> intentionally re-exports only the client-safe symbols listed below.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add @ionite/react
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Peer dependencies: `react` and `react-dom` (`^18.0.0 || ^19.0.0`).
|
|
18
|
+
|
|
19
|
+
## Client-safe exports
|
|
20
|
+
|
|
21
|
+
Workforce (SSO):
|
|
22
|
+
|
|
23
|
+
- `SSOProvider`
|
|
24
|
+
- `useSSOContext` / `useOptionalSSOContext` (non-throwing)
|
|
25
|
+
- `logout`
|
|
26
|
+
|
|
27
|
+
Customer (CIAM):
|
|
28
|
+
|
|
29
|
+
- `CIAMProvider`
|
|
30
|
+
- `useCIAMContext` / `useOptionalCIAMContext` (non-throwing)
|
|
31
|
+
- `CIAMProviderList`, `useCIAMProviders`
|
|
32
|
+
- `getCustomer`
|
|
33
|
+
- `logoutCustomer`
|
|
34
|
+
|
|
35
|
+
Gating / shared:
|
|
36
|
+
|
|
37
|
+
- `SignedIn`, `SignedOut`, `SignInLoading` (each accepts `audience?: 'workforce' | 'customer'`, default `'workforce'`)
|
|
38
|
+
- `TenantProvider`, `useTenant`, `useOptionalTenant` (non-throwing), `createTenantUrls`
|
|
39
|
+
|
|
40
|
+
Re-exported client-safe types/utilities from core: `WorkforceUser`, `Customer`, `AuthenticatedUser`,
|
|
41
|
+
`CIAMProviderDescriptor` (+ branding/color/type), `IdTokenClaims`, `TenantRoutingStrategy`,
|
|
42
|
+
`TenantPathNamespace`, `Logger`, `silentLogger`, `defaultLogger`.
|
|
43
|
+
|
|
44
|
+
## Canonical pattern
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { SignedIn, SignedOut, SignInLoading, SSOProvider } from '@ionite/react';
|
|
48
|
+
|
|
49
|
+
<SSOProvider userUrl="/api/ionite/auth/user">
|
|
50
|
+
<SignInLoading>Loading…</SignInLoading>
|
|
51
|
+
<SignedIn>
|
|
52
|
+
<UserDisplay />
|
|
53
|
+
</SignedIn>
|
|
54
|
+
<SignedOut>
|
|
55
|
+
<a href="/api/ionite/auth/login">Sign in</a>
|
|
56
|
+
</SignedOut>
|
|
57
|
+
</SSOProvider>;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Auth state and errors
|
|
61
|
+
|
|
62
|
+
`useSSOContext()` / `useCIAMContext()` return `{ user|customer, setUser|setCustomer, isLoading, error }`.
|
|
63
|
+
|
|
64
|
+
`error` lets you distinguish a backend outage from a signed-out user:
|
|
65
|
+
|
|
66
|
+
- `value === null && error === null` → signed out (the server returned `401`).
|
|
67
|
+
- `value === null && error !== null` → the fetch failed for a non-auth reason (network/5xx). Any
|
|
68
|
+
previously loaded value is preserved; render a "try again" affordance rather than treating the
|
|
69
|
+
user as logged out.
|
|
70
|
+
|
|
71
|
+
`CIAMProviderList` accepts an `errorFallback={(error, retry) => ...}` and clears the stale list when a
|
|
72
|
+
refresh fails.
|
|
73
|
+
|
|
74
|
+
## Storage
|
|
75
|
+
|
|
76
|
+
`storage` defaults to `'memory'` (no tokens are ever stored). Opt into `'local'`/`'session'` to
|
|
77
|
+
survive reloads; the stored record is a non-secret display subset. On load, records are validated
|
|
78
|
+
against an identity shape and discarded if expired. A custom `storageKey` is honored by the provider,
|
|
79
|
+
`getCustomer`, and `logout`/`logoutCustomer`.
|
|
80
|
+
|
|
81
|
+
## Cross-origin
|
|
82
|
+
|
|
83
|
+
By default `fetch` does not send cookies cross-origin. When `userUrl`/`customerUrl` is on a different
|
|
84
|
+
origin, pass `fetchInit={{ credentials: 'include' }}` (keep the object stable/memoized). The same
|
|
85
|
+
option exists on `getCustomer`/`logout`/`logoutCustomer`.
|
|
86
|
+
|
|
87
|
+
## Docs
|
|
88
|
+
|
|
89
|
+
See `site/public/docs/llms-react.txt` for the full usage guide, and the root `README.md` for server-side
|
|
90
|
+
setup that backs these components.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { AuthenticatedUser, CIAMProviderBranding, CIAMProviderColors, CIAMProviderDescriptor as CIAMProviderDescriptor3, CIAMProviderType, Customer as Customer2, IdTokenClaims, TenantPathNamespace, TenantRoutingStrategy as TenantRoutingStrategy2, WorkforceUser as WorkforceUser2 } from "@ionite/core";
|
|
2
|
+
import { defaultLogger, Logger as Logger5, silentLogger } from "@ionite/core";
|
|
3
|
+
import { Customer, Logger as Logger2 } from "@ionite/core";
|
|
4
|
+
import { ReactNode as ReactNode2 } from "react";
|
|
5
|
+
type StorageType = "local" | "session" | "memory";
|
|
6
|
+
interface CIAMProviderProps {
|
|
7
|
+
customerUrl: string;
|
|
8
|
+
/** Optional storage key. When provided, this key is used for localStorage/sessionStorage; otherwise `'ion.ciam.customer'` is used. */
|
|
9
|
+
storageKey?: string;
|
|
10
|
+
storage?: StorageType;
|
|
11
|
+
disableListener?: boolean;
|
|
12
|
+
/** Extra fetch options for `customerUrl` (e.g. `{ credentials: 'include' }` when it is cross-origin). Keep it stable/memoized. */
|
|
13
|
+
fetchInit?: RequestInit;
|
|
14
|
+
log?: Logger2;
|
|
15
|
+
children: ReactNode2;
|
|
16
|
+
}
|
|
17
|
+
interface CIAMContext {
|
|
18
|
+
customer: Customer | null;
|
|
19
|
+
setCustomer: (customer: Customer | null) => void;
|
|
20
|
+
isLoading: boolean;
|
|
21
|
+
/** Set when the last customer fetch failed for a non-auth reason (network/5xx). Null on success or 401 (signed out). */
|
|
22
|
+
error: Error | null;
|
|
23
|
+
}
|
|
24
|
+
declare function CIAMProvider({ storageKey: storageKeyProp, customerUrl, storage, disableListener, fetchInit, log, children }: CIAMProviderProps): React.ReactNode2;
|
|
25
|
+
declare function useCIAMContext(): CIAMContext;
|
|
26
|
+
/** Non-throwing variant; returns undefined when no CIAMProvider is present. */
|
|
27
|
+
declare function useOptionalCIAMContext(): CIAMContext | undefined;
|
|
28
|
+
declare function getCustomer(customerUrl: string, options?: {
|
|
29
|
+
storageKey?: string;
|
|
30
|
+
storage?: StorageType;
|
|
31
|
+
fetchInit?: RequestInit;
|
|
32
|
+
log?: Logger2;
|
|
33
|
+
}): Promise<Customer | undefined>;
|
|
34
|
+
declare function logoutCustomer(logoutUrl: string, options?: {
|
|
35
|
+
navigate?: boolean;
|
|
36
|
+
storageKey?: string;
|
|
37
|
+
fetchInit?: RequestInit;
|
|
38
|
+
}): Promise<{
|
|
39
|
+
success: boolean;
|
|
40
|
+
redirect?: string;
|
|
41
|
+
error?: string;
|
|
42
|
+
}>;
|
|
43
|
+
import { CIAMProviderDescriptor, Logger as Logger3 } from "@ionite/core";
|
|
44
|
+
import { ReactNode as ReactNode3 } from "react";
|
|
45
|
+
type UseCIAMProvidersResult = {
|
|
46
|
+
/** Providers in the recommended display order returned by the discovery endpoint. */
|
|
47
|
+
providers: CIAMProviderDescriptor[];
|
|
48
|
+
isLoading: boolean;
|
|
49
|
+
error: Error | null;
|
|
50
|
+
/** Re-fetch the provider list. */
|
|
51
|
+
refresh: () => void;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Fetch the sanitized, ordered list of CIAM customer-login providers from the
|
|
55
|
+
* discovery endpoint (`${basePath}/auth/customer/providers`). The list is
|
|
56
|
+
* returned in the recommended presentation order declared in RemoteConfig; do
|
|
57
|
+
* not re-sort it.
|
|
58
|
+
*/
|
|
59
|
+
declare function useCIAMProviders(providersUrl: string, log?: Logger3): UseCIAMProvidersResult;
|
|
60
|
+
type CIAMProviderListProps = {
|
|
61
|
+
/** Discovery endpoint URL (`${basePath}/auth/customer/providers`). */
|
|
62
|
+
providersUrl: string;
|
|
63
|
+
/**
|
|
64
|
+
* Maximum number of providers to show initially. Remaining providers are
|
|
65
|
+
* revealed via a "Show more" affordance. Preserves recommended order.
|
|
66
|
+
*/
|
|
67
|
+
limit?: number;
|
|
68
|
+
/** Resolve the theme used to pick a provider's branding color. Defaults to 'light'. */
|
|
69
|
+
theme?: "light" | "dark";
|
|
70
|
+
/** Optional render override for a single provider entry (headless usage). */
|
|
71
|
+
renderProvider?: (provider: CIAMProviderDescriptor) => ReactNode3;
|
|
72
|
+
/** Rendered while the provider list is loading. */
|
|
73
|
+
loadingFallback?: ReactNode3;
|
|
74
|
+
/** Rendered when no providers are available. */
|
|
75
|
+
emptyFallback?: ReactNode3;
|
|
76
|
+
/**
|
|
77
|
+
* Rendered when the provider list could not be fetched (network/5xx). Receives the error and a
|
|
78
|
+
* `retry` callback. When omitted, the list falls back to `emptyFallback` on error.
|
|
79
|
+
*/
|
|
80
|
+
errorFallback?: (error: Error, retry: () => void) => ReactNode3;
|
|
81
|
+
/** Label for the "show more" button. */
|
|
82
|
+
moreLabel?: string;
|
|
83
|
+
className?: string;
|
|
84
|
+
log?: Logger3;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Renders the CIAM customer-login providers as branded buttons in the
|
|
88
|
+
* recommended order. Each entry navigates to its SDK-derived `loginUrl`
|
|
89
|
+
* (mirrors the SSO `<a href={LOGIN_URL}>` pattern). Supports an optional
|
|
90
|
+
* `limit` (first N + "show more") that preserves order by default.
|
|
91
|
+
*/
|
|
92
|
+
declare function CIAMProviderList({ providersUrl, limit, theme, renderProvider, loadingFallback, emptyFallback, errorFallback, moreLabel, className, log }: CIAMProviderListProps): React.ReactNode3;
|
|
93
|
+
import { PropsWithChildren } from "react";
|
|
94
|
+
type Audience = "workforce" | "customer";
|
|
95
|
+
declare function SignInLoading({ complete, audience, children }: {
|
|
96
|
+
complete?: boolean;
|
|
97
|
+
audience?: Audience;
|
|
98
|
+
} & PropsWithChildren): React.ReactNode;
|
|
99
|
+
import { PropsWithChildren as PropsWithChildren2 } from "react";
|
|
100
|
+
type Audience2 = "workforce" | "customer";
|
|
101
|
+
declare function SignedIn({ audience, children }: {
|
|
102
|
+
audience?: Audience2;
|
|
103
|
+
} & PropsWithChildren2): React.ReactNode;
|
|
104
|
+
import { PropsWithChildren as PropsWithChildren3 } from "react";
|
|
105
|
+
type Audience3 = "workforce" | "customer";
|
|
106
|
+
declare function SignedOut({ audience, children }: {
|
|
107
|
+
audience?: Audience3;
|
|
108
|
+
} & PropsWithChildren3): React.ReactNode;
|
|
109
|
+
import { Logger as Logger4, WorkforceUser } from "@ionite/core";
|
|
110
|
+
import { ReactNode as ReactNode4 } from "react";
|
|
111
|
+
interface SSOProviderProps {
|
|
112
|
+
userUrl: string;
|
|
113
|
+
/** Optional storage key. When provided, this key is used for localStorage/sessionStorage; otherwise `'ion.sso.user'` is used. */
|
|
114
|
+
storageKey?: string;
|
|
115
|
+
storage?: StorageType;
|
|
116
|
+
disableListener?: boolean;
|
|
117
|
+
/** Extra fetch options for `userUrl` (e.g. `{ credentials: 'include' }` when it is cross-origin). Keep it stable/memoized. */
|
|
118
|
+
fetchInit?: RequestInit;
|
|
119
|
+
log?: Logger4;
|
|
120
|
+
children: ReactNode4;
|
|
121
|
+
}
|
|
122
|
+
interface SSOContext {
|
|
123
|
+
user: WorkforceUser | null;
|
|
124
|
+
setUser: (user: WorkforceUser | null) => void;
|
|
125
|
+
isLoading: boolean;
|
|
126
|
+
/** Set when the last user fetch failed for a non-auth reason (network/5xx). Null on success or 401 (signed out). */
|
|
127
|
+
error: Error | null;
|
|
128
|
+
}
|
|
129
|
+
declare function SSOProvider({ storageKey: storageKeyProp, userUrl, storage, disableListener, fetchInit, log, children }: SSOProviderProps): React.ReactNode4;
|
|
130
|
+
declare function useSSOContext(): SSOContext;
|
|
131
|
+
/** Non-throwing variant; returns undefined when no SSOProvider is present. */
|
|
132
|
+
declare function useOptionalSSOContext(): SSOContext | undefined;
|
|
133
|
+
declare function logout(logoutUrl: string, options?: {
|
|
134
|
+
navigate?: boolean;
|
|
135
|
+
storageKey?: string;
|
|
136
|
+
fetchInit?: RequestInit;
|
|
137
|
+
}): Promise<{
|
|
138
|
+
success: boolean;
|
|
139
|
+
redirect?: string;
|
|
140
|
+
error?: string;
|
|
141
|
+
}>;
|
|
142
|
+
import { TenantRoutingStrategy } from "@ionite/core";
|
|
143
|
+
type TenantUrls = {
|
|
144
|
+
ui: (restPath?: string) => string;
|
|
145
|
+
api: (restPath?: string) => string;
|
|
146
|
+
};
|
|
147
|
+
type TenantContextValue = {
|
|
148
|
+
id: string;
|
|
149
|
+
strategy: TenantRoutingStrategy;
|
|
150
|
+
urls: TenantUrls;
|
|
151
|
+
};
|
|
152
|
+
type TenantProviderProps = {
|
|
153
|
+
id: string;
|
|
154
|
+
strategy?: TenantRoutingStrategy;
|
|
155
|
+
children: React.ReactNode;
|
|
156
|
+
};
|
|
157
|
+
declare function createTenantUrls(id: string, strategy?: TenantRoutingStrategy): TenantUrls;
|
|
158
|
+
declare function TenantProvider({ id, strategy, children }: TenantProviderProps): React.ReactNode;
|
|
159
|
+
declare function useTenant(): TenantContextValue;
|
|
160
|
+
/** Non-throwing variant; returns undefined when no TenantProvider is present (parity with `useOptionalSSOContext`). */
|
|
161
|
+
declare function useOptionalTenant(): TenantContextValue | undefined;
|
|
162
|
+
export { useTenant, useSSOContext, useOptionalTenant, useOptionalSSOContext, useOptionalCIAMContext, useCIAMProviders, useCIAMContext, silentLogger, logoutCustomer, logout, getCustomer, defaultLogger, createTenantUrls, WorkforceUser2 as WorkforceUser, UseCIAMProvidersResult, TenantUrls, TenantRoutingStrategy2 as TenantRoutingStrategy, TenantProviderProps, TenantProvider, TenantPathNamespace, TenantContextValue, SignedOut, SignedIn, SignInLoading, SSOProvider, Logger5 as Logger, IdTokenClaims, Customer2 as Customer, CIAMProviderType, CIAMProviderListProps, CIAMProviderList, CIAMProviderDescriptor3 as CIAMProviderDescriptor, CIAMProviderColors, CIAMProviderBranding, CIAMProvider, AuthenticatedUser };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{defaultLogger as VM,silentLogger as _M}from"@ionite/core";import{silentLogger as ZW}from"@ionite/core";import{createContext as $W,useContext as i,useMemo as OW}from"react";import{silentLogger as S}from"@ionite/core";import{useCallback as R,useEffect as v,useRef as c,useState as U}from"react";var JW=/^[a-zA-Z0-9._-]{1,1024}$/;function QW(W,M){if(!W.trim())throw Error(`${M} storageKey must be a non-empty string.`);if(!JW.test(W))throw Error(`${M} storageKey must be 1-1024 characters and contain only letters, numbers, dots, underscores, and hyphens.`)}function D(W,M,C){if(M===void 0||M==="")return W;return QW(M,C),M}function n(W,M,C,H=S){if(typeof window>"u")return null;try{let q=W==="local"?localStorage:sessionStorage,J=q.getItem(M);if(!J)return null;let Q=JSON.parse(J),Z=C.validate(Q);if(!Z)return q.removeItem(M),null;let $=C.revive(Z);if(C.isExpired($))return q.removeItem(M),null;return $}catch(q){return H.error("Error loading auth record from storage:",q),null}}async function g(W,M,C,H=S){try{let q=await fetch(W,C);if(q.status===401)return{kind:"unauthenticated"};if(!q.ok){let Z=Error(`Failed to fetch auth record: ${q.status} ${q.statusText}`);return H.error("Error fetching auth record from URL:",Z),{kind:"error",error:Z}}let J=await q.json(),Q=M.validate(J);if(!Q){let Z=Error("Auth record from server failed validation.");return H.error("Error validating auth record from URL:",Z),{kind:"error",error:Z}}return{kind:"ok",value:M.revive(Q)}}catch(q){let J=q instanceof Error?q:Error(String(q));return H.error("Error fetching auth record from URL:",J),{kind:"error",error:J}}}function V(W){let{url:M,storage:C,storageKey:H,disableListener:q,logoutEventName:J,codec:Q}=W,[Z,$]=U(null),[I,O]=U(!!M),[X,P]=U(null),N=c(W.fetchInit);N.current=W.fetchInit;let z=c(W.log);z.current=W.log;let A=R((B)=>{if(C==="memory"||typeof window>"u")return;try{let f=C==="local"?localStorage:sessionStorage;if(B===null)f.removeItem(H);else f.setItem(H,JSON.stringify(B))}catch(f){z.current.error("Error saving auth record to storage:",f)}},[C,H]),w=R((B)=>{$(B),A(B)},[A]),j=R(()=>{if(C==="memory")return null;return n(C,H,Q,z.current)},[C,H,Q]),Y=R(async()=>{if(!M)return;O(!0);try{let B=await g(M,Q,N.current,z.current);if(B.kind==="ok")$(B.value),P(null),A(B.value);else if(B.kind==="unauthenticated")$(null),P(null),A(null);else P(B.error)}finally{O(!1)}},[M,Q,A]);return v(()=>{let B=j();if(B)$(B);if(M)Y();else O(!1)},[j,M,Y]),v(()=>{if(q||C==="memory")return;let B=(F)=>{if(F.key!==H)return;if(F.newValue===null){$(null);return}try{let x=JSON.parse(F.newValue),E=Q.validate(x);if(!E)return;let u=Q.revive(E);if(Q.isExpired(u)){$(null);return}$(u)}catch(x){z.current.error("Error parsing auth record from storage event:",x)}},f=()=>{$(null),P(null)};return window.addEventListener("storage",B),window.addEventListener(J,f),()=>{window.removeEventListener("storage",B),window.removeEventListener(J,f)}},[q,C,H,J,Q]),{value:Z,setValue:w,isLoading:I,error:X}}async function d(W,M,C){let{storageKey:H,storage:q,fetchInit:J,log:Q=S}=C;if(q==="local"||q==="session"){let Z=n(q,H,M,Q);if(Z)return Z}if(W){let Z=await g(W,M,J,Q);if(Z.kind==="ok")return Z.value}return}async function _(W,M,C){try{let H=await fetch(W,{...C?.fetchInit,headers:{Accept:"application/json",...C?.fetchInit?.headers}});if(!H.ok)return{success:!1,error:`HTTP ${H.status}`};let q=await H.json();if(!q.success)return{success:!1,error:q.message||"Logout failed"};let J=typeof q.redirect==="string"?q.redirect:void 0;if(typeof window<"u"){let Q=D(M.defaultStorageKey,C?.storageKey,M.providerLabel);if(localStorage.removeItem(Q),sessionStorage.removeItem(Q),window.dispatchEvent(new CustomEvent(M.logoutEventName)),J&&C?.navigate!==!1)window.location.assign(J)}return{success:!0,redirect:J}}catch(H){return{success:!1,error:H instanceof Error?H.message:"Network error"}}}import{jsx as PW}from"react/jsx-runtime";var m="ion.ciam.customer",l="es-ciam-logout",T="CIAMProvider",s={validate(W){if(!W||typeof W!=="object")return null;let M=W;if(typeof M.userName!=="string"||typeof M.name!=="string"||typeof M.email!=="string")return null;return W},revive(W){if(W.ciam?.expires)W.ciam.expires=new Date(W.ciam.expires);return W},isExpired(W){let M=W.ciam?.expires;if(!M)return!1;let C=M instanceof Date?M.getTime():new Date(M).getTime();return Number.isFinite(C)&&C<=Date.now()}},y=$W(void 0);function BW({storageKey:W,customerUrl:M,storage:C="memory",disableListener:H=!1,fetchInit:q,log:J=ZW,children:Q}){let Z=D(m,W,T),{value:$,setValue:I,isLoading:O,error:X}=V({url:M,storage:C,storageKey:Z,disableListener:H,logoutEventName:l,codec:s,fetchInit:q,log:J}),P=OW(()=>({customer:$,setCustomer:I,isLoading:O,error:X}),[$,I,O,X]);return PW(y.Provider,{value:P,children:Q})}function IW(){let W=i(y);if(W===void 0)throw Error("useCIAMContext must be used within a CIAMProvider");return W}function G(){return i(y)}async function XW(W,M){return d(W,s,{storageKey:D(m,M?.storageKey,T),storage:M?.storage??"memory",fetchInit:M?.fetchInit,log:M?.log})}async function YW(W,M){return _(W,{defaultStorageKey:m,logoutEventName:l,providerLabel:T},M)}import{silentLogger as a}from"@ionite/core";import{useCallback as zW,useEffect as AW,useState as b}from"react";import{jsx as h,jsxs as K}from"react/jsx-runtime";function t(W,M=a){let[C,H]=b([]),[q,J]=b(Boolean(W)),[Q,Z]=b(null),$=zW(()=>{if(!W)return;let I=!1;return J(!0),Z(null),fetch(W,{headers:{Accept:"application/json"}}).then(async(O)=>{if(!O.ok)throw Error(`Failed to fetch CIAM providers: ${O.status} ${O.statusText}`);let X=await O.json();if(!I)H(Array.isArray(X.providers)?X.providers:[])}).catch((O)=>{let X=O instanceof Error?O:Error(String(O));if(M.error("Error fetching CIAM providers:",X),!I)H([]),Z(X)}).finally(()=>{if(!I)J(!1)}),()=>{I=!0}},[W,M]);return AW(()=>{return $()},[$]),{providers:C,isLoading:q,error:Q,refresh:$}}function fW(W,M){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:(M==="dark"?W.colors?.dark:W.colors?.light)??(M==="dark"?"#1f1f1f":"#ffffff"),color:M==="dark"?"#ffffff":"#111111",textDecoration:"none",font:"inherit",cursor:"pointer"}}function GW({providersUrl:W,limit:M,theme:C="light",renderProvider:H,loadingFallback:q,emptyFallback:J,errorFallback:Q,moreLabel:Z="Show more",className:$,log:I=a}){let{providers:O,isLoading:X,error:P,refresh:N}=t(W,I),[z,A]=b(!1);if(X)return q??null;if(P)return Q?Q(P,N):J??null;if(O.length===0)return J??null;let w=!z&&typeof M==="number"&&M>0?O.slice(0,M):O,j=w.length<O.length;return K("div",{className:$,style:{display:"flex",flexDirection:"column",gap:"0.5rem"},"data-es-ciam-providers":"",children:[w.map((Y)=>H?h("span",{children:H(Y)},Y.name):K("a",{href:Y.loginUrl,style:fW(Y,C),"data-es-ciam-provider":Y.name,children:[Y.iconUrl?h("img",{src:Y.iconUrl,alt:"",width:20,height:20,"aria-hidden":"true"}):null,K("span",{children:["Continue with ",Y.displayName]})]},Y.name)),j?h("button",{type:"button",onClick:()=>A(!0),"data-es-ciam-show-more":"",children:Z}):null]})}import{silentLogger as kW}from"@ionite/core";import{createContext as DW,useContext as o,useMemo as NW}from"react";import{jsx as _W}from"react/jsx-runtime";var r="ion.sso.user",e="es-sso-logout",WW="SSOProvider",wW={validate(W){if(!W||typeof W!=="object")return null;let M=W;if(typeof M.userName!=="string"||typeof M.name!=="string"||typeof M.email!=="string")return null;return W},revive(W){if(W.sso?.expires)W.sso.expires=new Date(W.sso.expires);return W},isExpired(W){let M=W.sso?.expires;if(!M)return!1;let C=M instanceof Date?M.getTime():new Date(M).getTime();return Number.isFinite(C)&&C<=Date.now()}},L=DW(void 0);function jW({storageKey:W,userUrl:M,storage:C="memory",disableListener:H=!1,fetchInit:q,log:J=kW,children:Q}){let Z=D(r,W,WW),{value:$,setValue:I,isLoading:O,error:X}=V({url:M,storage:C,storageKey:Z,disableListener:H,logoutEventName:e,codec:wW,fetchInit:q,log:J}),P=NW(()=>({user:$,setUser:I,isLoading:O,error:X}),[$,I,O,X]);return _W(L.Provider,{value:P,children:Q})}function RW(){let W=o(L);if(W===void 0)throw Error("useSSOContext must be used within a SSOProvider");return W}function k(){return o(L)}async function VW(W,M){return _(W,{defaultStorageKey:r,logoutEventName:e,providerLabel:WW},M)}import{jsx as xW,Fragment as FW}from"react/jsx-runtime";function bW({complete:W=!1,audience:M="workforce",children:C}){let H=k(),q=G();if((M==="customer"?!!q?.isLoading:!!H?.isLoading)&&!W)return xW(FW,{children:C});return null}import{jsx as mW,Fragment as SW}from"react/jsx-runtime";function UW({audience:W="workforce",children:M}){let C=k(),H=G();if(W==="customer"?!!H?.customer:!!C?.user)return mW(SW,{children:M});return null}import{jsx as hW,Fragment as yW}from"react/jsx-runtime";function TW({audience:W="workforce",children:M}){let C=k(),H=G(),q=W==="customer"?!!H?.customer:!!C?.user,J=W==="customer"?!!H?.isLoading:!!C?.isLoading;if(q||J)return null;return hW(yW,{children:M})}import{buildTenantPath as MW,DEFAULT_TENANT_API_NAMESPACE as KW,DEFAULT_TENANT_UI_NAMESPACE as LW,normalizeTenantRoutingStrategy as CW}from"@ionite/core";import{createContext as pW,useContext as qW,useMemo as EW}from"react";import{jsx as nW}from"react/jsx-runtime";var p=pW(null);function HW(W,M){let C=CW(M),H=C.ui??LW,q=C.api??KW;return{ui:(J="/")=>MW(W,J,H),api:(J="/")=>MW(W,J,q)}}function uW({id:W,strategy:M,children:C}){let H=EW(()=>{let q=CW(M);return{id:W,strategy:q,urls:HW(W,q)}},[M,W]);return nW(p.Provider,{value:H,children:C})}function vW(){let W=qW(p);if(!W)throw Error("useTenant() must be used within a TenantProvider");return W}function cW(){return qW(p)??void 0}export{vW as useTenant,RW as useSSOContext,cW as useOptionalTenant,k as useOptionalSSOContext,G as useOptionalCIAMContext,t as useCIAMProviders,IW as useCIAMContext,_M as silentLogger,YW as logoutCustomer,VW as logout,XW as getCustomer,VM as defaultLogger,HW as createTenantUrls,uW as TenantProvider,TW as SignedOut,UW as SignedIn,bW as SignInLoading,jW as SSOProvider,GW as CIAMProviderList,BW as CIAMProvider};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ionite/react",
|
|
3
|
+
"version": "0.0.21",
|
|
4
|
+
"description": "ionite React Components",
|
|
5
|
+
"private": false,
|
|
6
|
+
"author": "ionite",
|
|
7
|
+
"license": "proprietary",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20.6"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist"
|
|
14
|
+
],
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"import": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"./package.json": "./package.json"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@ionite/core": "^0.0.21"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
31
|
+
"react-dom": "^18.0.0 || ^19.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/react": "^19.2.17"
|
|
35
|
+
}
|
|
36
|
+
}
|