@enterprisestandard/react 0.0.11 → 0.0.13-beta.20260325.1
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.d.ts +36 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,24 @@ declare function logout(logoutUrl: string): Promise<{
|
|
|
30
30
|
success: boolean;
|
|
31
31
|
error?: string;
|
|
32
32
|
}>;
|
|
33
|
+
import { TenantRoutingStrategy } from "@enterprisestandard/core";
|
|
34
|
+
type TenantUrls = {
|
|
35
|
+
ui: (restPath?: string) => string;
|
|
36
|
+
api: (restPath?: string) => string;
|
|
37
|
+
};
|
|
38
|
+
type TenantContextValue = {
|
|
39
|
+
tenantId: string;
|
|
40
|
+
strategy: TenantRoutingStrategy;
|
|
41
|
+
urls: TenantUrls;
|
|
42
|
+
};
|
|
43
|
+
type TenantProviderProps = {
|
|
44
|
+
tenantId: string;
|
|
45
|
+
strategy?: TenantRoutingStrategy;
|
|
46
|
+
children: React.ReactNode;
|
|
47
|
+
};
|
|
48
|
+
declare function createTenantUrls(tenantId: string, strategy?: TenantRoutingStrategy): TenantUrls;
|
|
49
|
+
declare function TenantProvider({ tenantId, strategy, children }: TenantProviderProps): React.ReactNode;
|
|
50
|
+
declare function useTenant(): TenantContextValue;
|
|
33
51
|
import { User as User2 } from "@enterprisestandard/core";
|
|
34
52
|
type SessionInfo = {
|
|
35
53
|
clientId: string;
|
|
@@ -49,7 +67,7 @@ declare function useSessions(options?: UseSessionsOptions): {
|
|
|
49
67
|
sessions: SessionInfo[];
|
|
50
68
|
isLoading: boolean;
|
|
51
69
|
refresh: () => Promise<void>;
|
|
52
|
-
switchSession: (clientId: string) => Promise<void>;
|
|
70
|
+
switchSession: (clientId: string, redirectTo?: string) => Promise<void>;
|
|
53
71
|
};
|
|
54
72
|
declare function useActiveUser(sessionsUrl?: string): {
|
|
55
73
|
user: User2 | null;
|
|
@@ -69,4 +87,20 @@ type TenantSwitcherProps = {
|
|
|
69
87
|
onLogin?: (clientId: string) => void;
|
|
70
88
|
};
|
|
71
89
|
declare function TenantSwitcher({ activeSession, sessions, onSwitch, availableTenants, onLogin }: TenantSwitcherProps): React.ReactNode;
|
|
72
|
-
|
|
90
|
+
import { TenantDirectoryResponse, TenantDirectoryTenant } from "@enterprisestandard/core";
|
|
91
|
+
type UseTenantDirectoryOptions = {
|
|
92
|
+
tenantManagerBaseUrl?: string;
|
|
93
|
+
start?: number;
|
|
94
|
+
limit?: number;
|
|
95
|
+
order?: string;
|
|
96
|
+
};
|
|
97
|
+
declare function useTenantDirectory(options?: UseTenantDirectoryOptions): {
|
|
98
|
+
directory: TenantDirectoryResponse | null;
|
|
99
|
+
tenants: Record<string, TenantDirectoryTenant>;
|
|
100
|
+
tenantIds: string[];
|
|
101
|
+
items: TenantDirectoryTenant[];
|
|
102
|
+
isLoading: boolean;
|
|
103
|
+
error: Error | null;
|
|
104
|
+
refresh: () => Promise<void>;
|
|
105
|
+
};
|
|
106
|
+
export { useUser, useTenantDirectory, useTenant, useSessions, useActiveUser, logout, getUser, createTenantUrls, UseTenantDirectoryOptions, TenantSwitcher, TenantProvider, SignedOut, SignedIn, SignInLoading, SessionInfo, SSOProvider };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"@enterprisestandard/core";import{createContext as
|
|
1
|
+
export*from"@enterprisestandard/core";import{createContext as k,useCallback as I,useContext as q,useEffect as E,useState as A}from"react";import{jsx as G}from"react/jsx-runtime";var C=k(void 0),V=/^[a-zA-Z0-9._-]{1,1024}$/;function J(n){if(!n.trim())throw Error("SSOProvider storageKey must be a non-empty string.");if(!V.test(n))throw Error("SSOProvider storageKey must be 1-1024 characters and contain only letters, numbers, dots, underscores, and hyphens.")}var O=(n)=>{if(n===void 0||n==="")return"es.sso.user";return J(n),n};function x(n,i){if(typeof window>"u")return null;try{let o=(n==="local"?localStorage:sessionStorage).getItem(i);if(!o)return null;let r=JSON.parse(o);if(r.sso?.expires)r.sso.expires=new Date(r.sso.expires);return r}catch(t){return console.error("Error loading user from storage:",t),null}}async function $(n){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 t=await i.json();if(t.sso?.expires&&typeof t.sso.expires==="string")t.sso.expires=new Date(t.sso.expires);return t}catch(i){return console.error("Error fetching user from URL:",i),null}}function H({storageKey:n,userUrl:i,storage:t="memory",disableListener:o=!1,children:r}){let[e,l]=A(null),[p,m]=A(!!i),a=O(n),y=I(()=>{if(t==="memory")return null;return x(t,a)},[t,a]),d=I((c)=>{if(t==="memory"||typeof window>"u")return;try{let T=t==="local"?localStorage:sessionStorage;if(c===null)T.removeItem(a);else T.setItem(a,JSON.stringify(c))}catch(T){console.error("Error saving user to storage:",T)}},[t,a]),u=I((c)=>{l(c),d(c)},[d]),s=I(async()=>{if(!i)return;m(!0);try{let c=await $(i);l(c),d(c)}finally{m(!1)}},[i,d]);E(()=>{let c=y();if(c)l(c);if(i)s();else m(!1)},[y,i,s]),E(()=>{if(o||t==="memory")return;let c=(P)=>{if(P.key!==a)return;if(P.newValue===null)l(null);else try{let N=JSON.parse(P.newValue);if(N.sso?.expires)N.sso.expires=new Date(N.sso.expires);l(N)}catch(N){console.error("Error parsing user from storage event:",N)}},T=()=>{l(null)};return window.addEventListener("storage",c),window.addEventListener("es-sso-logout",T),()=>{window.removeEventListener("storage",c),window.removeEventListener("es-sso-logout",T)}},[o,t,a]);let v={user:e,setUser:u,isLoading:p};return G(C.Provider,{value:v,children:r})}function h(){let n=q(C);if(n===void 0)throw Error("useUser must be used within a SSOProvider");return n}async function Q(n,i){let t=O(i),o=x("local",t);if(o)return o;let r=x("session",t);if(r)return r;if(n){let e=await $(n);if(e)return e}return}async function Z(n){try{let i=await fetch(n,{headers:{Accept:"application/json"}});if(!i.ok)return{success:!1,error:`HTTP ${i.status}`};let t=await i.json();if(!t.success)return{success:!1,error:t.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(i){return{success:!1,error:i instanceof Error?i.message:"Network error"}}}import{jsx as F,Fragment as X}from"react/jsx-runtime";function Y({complete:n=!1,children:i}){let{isLoading:t}=h();if(t&&!n)return F(X,{children:i});return null}import{jsx as K,Fragment as j}from"react/jsx-runtime";function U({children:n}){let{user:i}=h();if(i)return K(j,{children:n});return null}import{jsx as en,Fragment as tn}from"react/jsx-runtime";function nn({children:n}){let{user:i,isLoading:t}=h();if(i||t)return null;return en(tn,{children:n})}import{buildTenantPath as D,DEFAULT_TENANT_API_NAMESPACE as on,DEFAULT_TENANT_UI_NAMESPACE as sn,normalizeTenantRoutingStrategy as W}from"@enterprisestandard/core";import{createContext as rn,useContext as an,useMemo as cn}from"react";import{jsx as pn}from"react/jsx-runtime";var L=rn(null);function _(n,i){let t=W(i);if(t.type==="jwt"){let e=t.ui?.segments??[],l=t.api?.segments??["api"];return{ui:(p="/")=>M(e,p),api:(p="/")=>M(l,p)}}let o=t.ui??sn,r=t.api??on;return{ui:(e="/")=>D(n,e,o),api:(e="/")=>D(n,e,r)}}function M(n,i="/"){let t=n.join("/"),o=i.trim().replace(/^\/+/,"");if(!t&&!o)return"/";if(!t)return`/${o}`;if(!o)return`/${t}`;return`/${t}/${o}`}function ln({tenantId:n,strategy:i,children:t}){let o=cn(()=>{let r=W(i);return{tenantId:n,strategy:r,urls:_(n,r)}},[i,n]);return pn(L.Provider,{value:o,children:t})}function dn(){let n=an(L);if(!n)throw Error("useTenant() must be used within a TenantProvider");return n}import{jsx as f,jsxs as w,Fragment as mn}from"react/jsx-runtime";function b(n){if(!n)return"Unknown user";return n.name??n.email??n.id??"Unknown user"}function R(n){return n.tenantName??n.companyName??n.tenantId??n.clientId}function un({activeSession:n,sessions:i,onSwitch:t,availableTenants:o=[],onLogin:r}){return w("details",{className:"relative inline-block text-left",children:[w("summary",{className:"cursor-pointer select-none rounded-md border px-3 py-2 text-sm",children:[b(n?.user)," · ",n?R(n):"No active session"]}),w("div",{className:"absolute left-0 mt-2 w-64 rounded-md border bg-white p-3 text-sm shadow",children:[f("div",{className:"mb-2 text-gray-500 text-xs uppercase",children:"Active"}),f("div",{className:"mb-4",children:n?w("div",{className:"rounded-md border px-2 py-1",children:[R(n)," · ",b(n.user)]}):f("div",{className:"text-gray-500",children:"No active session"})}),f("div",{className:"mb-2 text-gray-500 text-xs uppercase",children:"Sessions"}),w("div",{className:"space-y-2",children:[i.length===0&&f("div",{className:"text-gray-500",children:"No sessions"}),i.map((e)=>w("button",{type:"button",className:"w-full rounded-md border px-2 py-1 text-left hover:bg-gray-50",onClick:()=>t(e.clientId),children:[R(e)," · ",b(e.user)]},e.clientId))]}),o.length>0&&w(mn,{children:[f("div",{className:"mt-4 mb-2 text-gray-500 text-xs uppercase",children:"Login to another tenant"}),f("div",{className:"space-y-2",children:o.map((e)=>f("button",{type:"button",className:"w-full rounded-md border px-2 py-1 text-left hover:bg-gray-50",onClick:()=>r?.(e.clientId),children:e.tenantName??e.companyName??e.tenantId??e.clientId},e.clientId))})]})]})]})}import{useCallback as z,useEffect as fn,useState as S}from"react";function B(n={}){let i=n.sessionsUrl??"/api/sessions",t=n.switchUrl??"/api/sessions/switch",[o,r]=S([]),[e,l]=S(null),[p,m]=S(!0),a=z(async()=>{m(!0);try{let d=await fetch(i);if(!d.ok){r([]),l(null);return}let u=await d.json();r(u.sessions??[]);let s=u.sessions?.find((v)=>v.clientId===u.activeSession)??null;l(s)}finally{m(!1)}},[i]),y=z(async(d,u)=>{let s=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({clientId:d,redirectTo:u})});if(s.redirected&&typeof window<"u"){window.location.assign(s.url);return}if(!s.ok){if(typeof window<"u")window.location.assign(`/api/auth/login?clientId=${d}`);return}if(await a(),u&&typeof window<"u")window.location.assign(u)},[a,t]);return fn(()=>{a()},[a]),{activeSession:e,sessions:o,isLoading:p,refresh:a,switchSession:y}}function yn(n){let{activeSession:i,isLoading:t}=B({sessionsUrl:n});return{user:i?.user??null,isLoading:t}}import{useCallback as Tn,useEffect as hn,useMemo as wn,useState as g}from"react";function Nn(n={}){let i=n.tenantManagerBaseUrl??"/api/tenants",[t,o]=g(null),[r,e]=g(!0),[l,p]=g(null),m=wn(()=>{let s=new URL(i,"http://localhost");if(n.start!=null)s.searchParams.set("start",String(n.start));if(n.limit!=null)s.searchParams.set("limit",String(n.limit));if(n.order)s.searchParams.set("order",n.order);return`${s.pathname}${s.search}`},[n.limit,n.order,n.start,i]),a=Tn(async()=>{e(!0),p(null);try{let s=await fetch(m);if(!s.ok){o(null),p(Error(`Tenant directory request failed with status ${s.status}`));return}let v=await s.json();o(v)}catch(s){o(null),p(s instanceof Error?s:Error("Failed to load tenant directory"))}finally{e(!1)}},[m]);hn(()=>{a()},[a]);let y=t?.tenants??{},d=t?.tenantIds??[],u=d.map((s)=>y[s]).filter((s)=>!!s);return{directory:t,tenants:y,tenantIds:d,items:u,isLoading:r,error:l,refresh:a}}export{h as useUser,Nn as useTenantDirectory,dn as useTenant,B as useSessions,yn as useActiveUser,Z as logout,Q as getUser,_ as createTenantUrls,un as TenantSwitcher,ln as TenantProvider,nn as SignedOut,U as SignedIn,Y as SignInLoading,H as SSOProvider};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@enterprisestandard/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13-beta.20260325.1",
|
|
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": "
|
|
25
|
+
"@enterprisestandard/core": "0.0.13-beta.20260325.1"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^18.0.0 || ^19.0.0",
|