@devsym/graph-toolkit-react 0.1.0-next.2 → 1.0.0-next.5
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/components/Person/Person.d.ts.map +1 -1
- package/dist/components/Person/Person.types.d.ts +3 -14
- package/dist/components/Person/Person.types.d.ts.map +1 -1
- package/dist/hooks/usePersonData.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +287 -203
- package/dist/providers/IProvider.d.ts +1 -5
- package/dist/providers/IProvider.d.ts.map +1 -1
- package/dist/providers/MockProvider.d.ts.map +1 -1
- package/dist/providers/MsalBrowserProvider.d.ts.map +1 -1
- package/dist/providers/ProviderContext.d.ts +6 -0
- package/dist/providers/ProviderContext.d.ts.map +1 -1
- package/dist/providers/TeamsHostedProvider.d.ts +1 -1
- package/dist/providers/TeamsHostedProvider.d.ts.map +1 -1
- package/dist/utils/personCache.d.ts +24 -0
- package/dist/utils/personCache.d.ts.map +1 -0
- package/package.json +9 -4
- package/readme.md +8 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Person.d.ts","sourceRoot":"","sources":["../../../src/components/Person/Person.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"Person.d.ts","sourceRoot":"","sources":["../../../src/components/Person/Person.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAwB7C,eAAO,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAkFxC,CAAC"}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Person component types
|
|
3
3
|
*/
|
|
4
|
-
import type {
|
|
5
|
-
|
|
6
|
-
export type PersonView = 'avatar' | 'oneline' | 'twolines' | 'threelines';
|
|
7
|
-
export type PersonSize = 'small' | 'medium' | 'large' | 'extra-large';
|
|
8
|
-
export type PersonTextAlignment = 'start' | 'center';
|
|
9
|
-
export type PersonTextPosition = 'before' | 'after' | 'below';
|
|
4
|
+
import type { PersonaProps } from '@fluentui/react-components';
|
|
5
|
+
export type PersonView = 'avatar' | 'oneline' | 'twolines' | 'threelines' | 'fourlines';
|
|
10
6
|
export interface PersonDetails {
|
|
11
7
|
displayName?: string;
|
|
12
8
|
mail?: string;
|
|
@@ -16,20 +12,13 @@ export interface PersonDetails {
|
|
|
16
12
|
id?: string;
|
|
17
13
|
userPrincipalName?: string;
|
|
18
14
|
}
|
|
19
|
-
export interface PersonProps {
|
|
15
|
+
export interface PersonProps extends PersonaProps {
|
|
20
16
|
userId?: string;
|
|
21
17
|
userPrincipalName?: string;
|
|
22
18
|
email?: string;
|
|
23
19
|
personDetails?: PersonDetails;
|
|
24
20
|
view?: PersonView;
|
|
25
21
|
showPresence?: boolean;
|
|
26
|
-
avatarSize?: PersonSize;
|
|
27
|
-
textAlignment?: PersonTextAlignment;
|
|
28
|
-
textPosition?: PersonTextPosition;
|
|
29
|
-
numericSize?: number;
|
|
30
22
|
fetchImage?: boolean;
|
|
31
|
-
onClick?: (person: User) => void;
|
|
32
|
-
className?: string;
|
|
33
|
-
style?: CSSProperties;
|
|
34
23
|
}
|
|
35
24
|
//# sourceMappingURL=Person.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Person.types.d.ts","sourceRoot":"","sources":["../../../src/components/Person/Person.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"Person.types.d.ts","sourceRoot":"","sources":["../../../src/components/Person/Person.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE/D,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAExF,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAY,SAAQ,YAAY;IAE/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,aAAa,CAAC,EAAE,aAAa,CAAC;IAG9B,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IAGvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePersonData.d.ts","sourceRoot":"","sources":["../../src/hooks/usePersonData.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"usePersonData.d.ts","sourceRoot":"","sources":["../../src/hooks/usePersonData.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAYlE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA8BD;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,SAAS,oBAAoB,KAAG,UA2O7D,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const w=require("react/jsx-runtime"),O=require("@fluentui/react-components"),d=require("react"),q=require("@microsoft/microsoft-graph-client");var o=(t=>(t.Loading="Loading",t.SignedOut="SignedOut",t.SignedIn="SignedIn",t))(o||{});const P=d.createContext({provider:null,state:o.Loading}),G=({provider:t,children:e})=>{const s=d.useCallback(()=>t?.getState?.()??o.Loading,[t]),r=d.useCallback(i=>(t.onStateChanged?.(i),()=>{const c=t;typeof c.removeStateChangedHandler=="function"&&c.removeStateChangedHandler(i)}),[t]),n=d.useSyncExternalStore(r,s,s),a=d.useMemo(()=>({provider:t,state:n}),[t,n]);return w.jsx(P.Provider,{value:a,children:e})},I=()=>{const{provider:t}=d.useContext(P);return t},b=()=>{const{state:t}=d.useContext(P);return t},L=t=>q.Client.init({authProvider:async e=>{try{const s=await t.getAccessToken();e(null,s)}catch(s){e(s,null)}}}),z=t=>{const e=t.trim().split(" ");return e.length===1?e[0].substring(0,2).toUpperCase():(e[0][0]+e[e.length-1][0]).toUpperCase()},U=()=>{const t=I(),e=b();return d.useMemo(()=>!t||e!=="SignedIn"?null:L(t),[t,e])};class C{state=o.SignedOut;listeners=[];constructor(e){e?.autoSignIn&&(this.state=o.SignedIn)}getAccessToken(){return this.state!==o.SignedIn?Promise.reject(new Error("Not signed in")):Promise.resolve("mock-token")}async login(){this.state=o.SignedIn,this.emit()}async logout(){this.state=o.SignedOut,this.emit()}getState(){return this.state}onStateChanged(e){this.listeners.push(e)}removeStateChangedHandler(e){this.listeners=this.listeners.filter(s=>s!==e)}emit(){for(const e of this.listeners)try{e()}catch{}}}const B=()=>new C({autoSignIn:!0}),j=t=>{const e=U(),s=I(),r=b(),{userId:n,userPrincipalName:a,fetchPresence:i=!1,fetchPhoto:c=!0}=t,[f,p]=d.useState({user:null,presence:null,photoUrl:null,loading:!0,error:null});return d.useEffect(()=>{let h=!1;return(async()=>{if(s instanceof C){const l={id:"00000000-0000-0000-0000-000000000000",displayName:"Adele Vance",userPrincipalName:"adelev@contoso.com",jobTitle:"Product Manager",department:"Marketing",officeLocation:"19/3106",mail:"adelev@contoso.com"},u={availability:"Available",activity:"Available",id:l.id,odataType:"#microsoft.graph.presence"};h||p({user:l,presence:i?u:null,photoUrl:c?"https://ui-avatars.com/api/?name=Adele+Vance&background=0D8ABC&color=ffffff":null,loading:!1,error:null});return}if(r!=="SignedIn"){h||p({user:null,presence:null,photoUrl:null,loading:!1,error:r==="SignedOut"?null:new Error("Provider not signed in")});return}if(!e){h||p(l=>({...l,loading:!0}));return}const m=n||a;if(!m){h||p({user:null,presence:null,photoUrl:null,loading:!1,error:null});return}try{p(g=>({...g,loading:!0,error:null}));const l=m.toLowerCase()==="me",u=await e.api(l?"/me":`/users/${m}`).select("id,displayName,jobTitle,mail,department,officeLocation,userPrincipalName").get();if(h)return;let S=null,k=null;if(i&&u.id)try{S=await e.api(l?"/me/presence":`/users/${u.id}/presence`).get()}catch(g){console.warn("Failed to fetch presence:",g)}if(c&&u.id)try{const g=await e.api(l?"/me/photo/$value":`/users/${u.id}/photo/$value`).get();k=URL.createObjectURL(g)}catch(g){console.warn("Failed to fetch photo:",g)}h||p({user:u,presence:S,photoUrl:k,loading:!1,error:null})}catch(l){h||p({user:null,presence:null,photoUrl:null,loading:!1,error:l})}})(),()=>{h=!0}},[e,s,r,n,a,i,c]),f},N=t=>{switch(t){case"small":return"small";case"large":return"large";case"extra-large":return"extra-large";default:return"medium"}},$=t=>{switch(t?.toLowerCase()){case"available":case"availableidle":return"available";case"away":case"berightback":return"away";case"busy":case"busyidle":case"donotdisturb":return"busy";default:return"offline"}},D=({userId:t,userPrincipalName:e,email:s,personDetails:r,view:n="oneline",showPresence:a=!1,avatarSize:i="medium",textAlignment:c,textPosition:f,numericSize:p,fetchImage:h=!0,onClick:y,className:m,style:l})=>{const{user:u,presence:S,photoUrl:k,loading:g}=j({userId:r?void 0:t||e||s,fetchPresence:a,fetchPhoto:h}),T=r||u,E=p??N(i);if(g)return w.jsx(O.Persona,{size:E,name:"Loading...",textAlignment:c,textPosition:f,className:m,style:l});if(!T)return null;const M=T.displayName||"Unknown User",F=z(M),v={size:E,name:M,textAlignment:c,textPosition:f,avatar:{image:k?{src:k}:void 0,initials:k?void 0:F},className:m,style:l};return a&&S&&(v.presence={status:$(S.availability)}),n!=="avatar"&&((n==="twolines"||n==="threelines")&&(v.secondaryText=T.jobTitle??void 0),n==="threelines"&&(v.tertiaryText=T.department??void 0)),y&&(v.onClick=()=>{u&&y(u)}),w.jsx(O.Persona,{...v})};function H(t){return`See https://aka.ms/msal.js.errors#${t} for details`}class x extends Error{constructor(e,s,r){const n=s||(e?H(e):""),a=n?`${e}: ${n}`:e;super(a),Object.setPrototypeOf(this,x.prototype),this.errorCode=e||"",this.errorMessage=n||"",this.subError=r||"",this.name="AuthError"}setCorrelationId(e){this.correlationId=e}}class A extends x{constructor(e,s,r,n,a,i,c,f){super(e,s,r),Object.setPrototypeOf(this,A.prototype),this.timestamp=n||"",this.traceId=a||"",this.correlationId=i||"",this.claims=c||"",this.name="InteractionRequiredAuthError",this.errorNo=f}}class R{msalInstance;defaultScopes;account=null;state=o.Loading;listeners=[];constructor(e,s){this.msalInstance=e,this.defaultScopes=s}async initialize(){await this.msalInstance.initialize(),await this.msalInstance.handleRedirectPromise();const e=this.msalInstance.getActiveAccount(),s=this.msalInstance.getAllAccounts();this.account=e??s[0]??null,this.account?(this.msalInstance.setActiveAccount(this.account),this.setState(o.SignedIn)):this.setState(o.SignedOut)}async login(){const e={scopes:this.defaultScopes},s=await this.msalInstance.loginPopup(e);this.account=s.account,this.account&&this.msalInstance.setActiveAccount(this.account),this.setState(o.SignedIn)}async logout(){const e=this.msalInstance.getActiveAccount()??this.account??void 0;await this.msalInstance.logoutPopup({account:e}),this.account=null,this.setState(o.SignedOut)}async getAccessToken(e){const s=e&&e.length>0?e:this.defaultScopes,r=this.msalInstance.getActiveAccount()??this.account;if(!r)throw new Error("No active account. User must sign in first.");const n={scopes:s,account:r};try{return(await this.msalInstance.acquireTokenSilent(n)).accessToken}catch(a){if(a instanceof A){const i={scopes:s,account:r};return(await this.msalInstance.acquireTokenPopup(i)).accessToken}throw a}}getState(){return this.state}onStateChanged(e){this.listeners.push(e)}removeStateChangedHandler(e){this.listeners=this.listeners.filter(s=>s!==e)}setState(e){this.state=e,this.emit()}emit(){for(const e of this.listeners)try{e()}catch{}}}const K=6e4;function V(t){const e=t.fetchFn??fetch;return async({ssoToken:s,scopes:r})=>{const n=await e(t.endpoint,{method:"POST",headers:{Authorization:`Bearer ${s}`,"Content-Type":"application/json"},body:JSON.stringify({scopes:r})}),a=await n.json().catch(()=>({error:n.statusText||"Token exchange failed"}));if(!n.ok){const i=a?.error||a?.message||n.statusText;throw new Error(`Backend token exchange failed: ${i}`)}if(!a?.accessToken)throw new Error("Backend token exchange response did not include accessToken.");return{accessToken:a.accessToken,expiresAt:a.expiresAt}}}class J{defaultScopes;getTeamsSsoTokenFn;exchangeForGraphTokenFn;refreshSkewMs;state=o.SignedOut;listeners=[];tokenCache=new Map;constructor(e){if(!e.defaultScopes||e.defaultScopes.length===0)throw new Error("TeamsHostedProvider requires at least one default scope.");this.defaultScopes=[...new Set(e.defaultScopes)],this.getTeamsSsoTokenFn=e.getTeamsSsoToken,this.exchangeForGraphTokenFn=e.exchangeForGraphToken,this.refreshSkewMs=e.refreshSkewMs??K}async login(){try{await this.getAccessToken(),this.setState(o.SignedIn)}catch(e){throw this.clearCache(),this.setState(o.SignedOut),e}}async logout(){this.clearCache(),this.setState(o.SignedOut)}async getAccessToken(e){const s=this.normalizeScopes(e),r=this.buildScopeKey(s),n=this.tokenCache.get(r);if(n&&this.isTokenValid(n))return n.accessToken;const a=await this.getTeamsSsoTokenFn(s);if(!a)throw new Error("Teams SSO token acquisition returned empty token.");const i=await this.exchangeForGraphTokenFn({ssoToken:a,scopes:s}),c=this.normalizeExchangedToken(i);return this.tokenCache.set(r,c),this.setState(o.SignedIn),c.accessToken}getState(){return this.state}onStateChanged(e){this.listeners.push(e)}removeStateChangedHandler(e){this.listeners=this.listeners.filter(s=>s!==e)}normalizeScopes(e){const s=e&&e.length>0?e:this.defaultScopes,r=[...new Set(s.filter(Boolean))];if(r.length===0)throw new Error("At least one scope is required to request a Graph token.");return r}buildScopeKey(e){return[...e].sort().join(" ")}isTokenValid(e){return e.expiresAtMs?Date.now()+this.refreshSkewMs<e.expiresAtMs:!0}normalizeExchangedToken(e){if(typeof e=="string"){if(!e)throw new Error("Graph token exchange returned empty access token.");return{accessToken:e}}if(!e.accessToken)throw new Error("Graph token exchange returned empty access token.");return{accessToken:e.accessToken,expiresAtMs:this.toEpochMs(e.expiresAt)}}toEpochMs(e){if(e)return e instanceof Date?e.getTime():e}clearCache(){this.tokenCache.clear()}setState(e){this.state!==e&&(this.state=e,this.emit())}emit(){for(const e of this.listeners)try{e()}catch{}}}exports.GraphProvider=G;exports.MockProvider=C;exports.MsalBrowserProvider=R;exports.Person=D;exports.ProviderState=o;exports.TeamsHostedProvider=J;exports.createBackendTokenExchange=V;exports.createMockSignedInProvider=B;exports.useGraphClient=U;exports.usePersonData=j;exports.useProvider=I;exports.useProviderState=b;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const F=require("react/jsx-runtime"),L=require("@fluentui/react-components"),d=require("react"),V=require("@microsoft/microsoft-graph-client"),Q="graph-toolkit-person-cache",P="personData",J=1,W=3600*1e3,X=3600*1e3,Y=300*1e3,q={enabled:!0,userTtlMs:W,photoTtlMs:X,presenceTtlMs:Y},D=()=>typeof window<"u"&&typeof window.indexedDB<"u",G=t=>new Promise((e,n)=>{t.onsuccess=()=>e(t.result),t.onerror=()=>n(t.error)}),R=()=>new Promise((t,e)=>{if(!D()){e(new Error("IndexedDB unavailable"));return}const n=window.indexedDB.open(Q,J);n.onupgradeneeded=()=>{const r=n.result;r.objectStoreNames.contains(P)||r.createObjectStore(P)},n.onsuccess=()=>t(n.result),n.onerror=()=>e(n.error)}),Z=t=>`person:${t.trim().toLowerCase()}`,U=(t,e)=>t?Date.now()-t<e:!1,ee=async t=>{if(!D())return null;let e=null;try{e=await R();const r=e.transaction(P,"readonly").objectStore(P);return await G(r.get(t))??null}catch{return null}finally{e?.close()}},te=async(t,e)=>{if(!D())return;let n=null;try{n=await R();const s=n.transaction(P,"readwrite").objectStore(P);await G(s.put(e,t))}catch{return}finally{n?.close()}},O=d.createContext({provider:null,state:"Loading",personCacheOptions:q}),ne=({provider:t,children:e,personCacheOptions:n})=>{const r=d.useCallback(()=>t?.getState?.()??"Loading",[t]),s=d.useCallback(l=>(t.onStateChanged?.(l),()=>{const m=t;typeof m.removeStateChangedHandler=="function"&&m.removeStateChangedHandler(l)}),[t]),o=d.useSyncExternalStore(s,r,r),i=d.useMemo(()=>({...q,...n??{}}),[n]),a=d.useMemo(()=>({provider:t,state:o,personCacheOptions:i}),[t,o,i]);return F.jsx(O.Provider,{value:a,children:e})},N=()=>{const{provider:t}=d.useContext(O);return t},_=()=>{const{state:t}=d.useContext(O);return t},$=()=>{const{personCacheOptions:t}=d.useContext(O);return t},se=t=>V.Client.init({authProvider:async e=>{try{const n=await t.getAccessToken();e(null,n)}catch(n){e(n,null)}}}),re=t=>{const e=t.trim().split(" ");return e.length===1?e[0].substring(0,2).toUpperCase():(e[0][0]+e[e.length-1][0]).toUpperCase()},z=()=>{const t=N(),e=_();return d.useMemo(()=>!t||e!=="SignedIn"?null:se(t),[t,e])};class B{state="SignedOut";listeners=[];constructor(e){e?.autoSignIn&&(this.state="SignedIn")}getAccessToken(){return this.state!=="SignedIn"?Promise.reject(new Error("Not signed in")):Promise.resolve("mock-token")}async login(){this.state="SignedIn",this.emit()}async logout(){this.state="SignedOut",this.emit()}getState(){return this.state}onStateChanged(e){this.listeners.push(e)}removeStateChangedHandler(e){this.listeners=this.listeners.filter(n=>n!==e)}emit(){for(const e of this.listeners)try{e()}catch{}}}const oe=()=>new B({autoSignIn:!0}),ae=async t=>{if(!t)return null;if(typeof t=="string")return t;const e=t instanceof Blob?t:t instanceof ArrayBuffer?new Blob([t]):null;return e?new Promise((n,r)=>{const s=new FileReader;s.onloadend=()=>n(typeof s.result=="string"?s.result:null),s.onerror=()=>r(s.error),s.readAsDataURL(e)}):null},K=t=>{const e=z(),n=N(),r=_(),s=$(),{userId:o,userPrincipalName:i,fetchPresence:a=!1,fetchPhoto:l=!0}=t,[m,u]=d.useState({user:null,presence:null,photoUrl:null,loading:!0,error:null});return d.useEffect(()=>{let f=!1;return(async()=>{if(n instanceof B){const h={id:"00000000-0000-0000-0000-000000000000",displayName:"Adele Vance",userPrincipalName:"adelev@contoso.com",jobTitle:"Product Manager",department:"Marketing",officeLocation:"19/3106",mail:"adelev@contoso.com"},y={availability:"Available",activity:"Available",id:h.id,odataType:"#microsoft.graph.presence"};f||u({user:h,presence:a?y:null,photoUrl:l?"https://ui-avatars.com/api/?name=Adele+Vance&background=0D8ABC&color=ffffff":null,loading:!1,error:null});return}if(r!=="SignedIn"){f||u({user:null,presence:null,photoUrl:null,loading:!1,error:r==="SignedOut"?null:new Error("Provider not signed in")});return}if(!e){f||u(h=>({...h,loading:!0}));return}const T=o||i;if(!T){f||u({user:null,presence:null,photoUrl:null,loading:!1,error:null});return}const E=Z(T),c=s.enabled?await ee(E):null,x=!!(c?.user&&U(c.userCachedAt,s.userTtlMs)),A=!!(c?.presenceCachedAt&&U(c.presenceCachedAt,s.presenceTtlMs)),b=!!(c?.photoCachedAt&&U(c.photoCachedAt,s.photoTtlMs));if(x&&(!a||A)&&(!l||b)){f||u({user:c?.user??null,presence:a?c?.presence??null:null,photoUrl:l?c?.photoUrl??null:null,loading:!1,error:null});return}try{u(v=>({...v,loading:!0,error:null}));const h=T.toLowerCase()==="me",y=Date.now();let k=!1,w=!1,C=!1,p=x?c?.user??null:null;if(p||(p=await e.api(h?"/me":`/users/${T}`).select("id,displayName,jobTitle,mail,department,officeLocation,userPrincipalName").get(),k=!0),f)return;let I=null,M=null;if(a){if(A)I=c?.presence??null;else if(p?.id){try{I=await e.api(h?"/me/presence":`/users/${p.id}/presence`).get()}catch(v){console.warn("Failed to fetch presence:",v)}w=!0}}if(l){if(b)M=c?.photoUrl??null;else if(p?.id){try{const v=await e.api(h?"/me/photo/$value":`/users/${p.id}/photo/$value`).get();M=await ae(v)}catch(v){console.warn("Failed to fetch photo:",v)}C=!0}}const g={...c??{}};k&&p&&(g.user=p,g.userCachedAt=y),a&&(w||A)&&(g.presence=w?I:c?.presence,g.presenceCachedAt=w?y:c?.presenceCachedAt),l&&(C||b)&&(g.photoUrl=C?M:c?.photoUrl,g.photoCachedAt=C?y:c?.photoCachedAt),s.enabled&&(k||w||C)&&g.user&&await te(E,g),f||u({user:p,presence:I,photoUrl:M,loading:!1,error:null})}catch(h){f||u({user:null,presence:null,photoUrl:null,loading:!1,error:h})}})(),()=>{f=!0}},[e,n,r,o,i,a,l,s]),m},ce=t=>{switch(t?.toLowerCase()){case"available":case"availableidle":return"available";case"away":case"berightback":return"away";case"busy":case"busyidle":case"donotdisturb":return"busy";default:return"offline"}},ie=({userId:t,userPrincipalName:e,email:n,personDetails:r,view:s="oneline",showPresence:o=!1,fetchImage:i=!0,...a})=>{const{user:l,presence:m,photoUrl:u,loading:f}=K({userId:r?void 0:t||e||n,fetchPresence:o,fetchPhoto:i}),S=r||l;if(f)return F.jsx(L.Persona,{...a,name:a.name??"Loading..."});if(!S)return null;const T=S.displayName||"Unknown User",E=re(T),c=s!=="avatar"&&(s==="twolines"||s==="threelines"||s==="fourlines")?S.jobTitle??void 0:void 0,x=s!=="avatar"&&(s==="threelines"||s==="fourlines")?S.department??void 0:void 0,A=s!=="avatar"&&s==="fourlines"?S.officeLocation??S.mail??void 0:void 0,b=o&&m?{status:ce(m.availability)}:void 0,h=a.presence??b,y=a.avatar??{image:u?{src:u}:void 0,initials:u?void 0:E},k=a.name??T,w=a.secondaryText??c,C=a.tertiaryText??x,p=a.quaternaryText??A;return F.jsx(L.Persona,{...a,name:k,avatar:y,presence:h,secondaryText:w,tertiaryText:C,quaternaryText:p})};function le(t){return`See https://aka.ms/msal.js.errors#${t} for details`}class j extends Error{constructor(e,n,r){const s=n||(e?le(e):""),o=s?`${e}: ${s}`:e;super(o),Object.setPrototypeOf(this,j.prototype),this.errorCode=e||"",this.errorMessage=s||"",this.subError=r||"",this.name="AuthError"}setCorrelationId(e){this.correlationId=e}}class H extends j{constructor(e,n,r,s,o,i,a,l){super(e,n,r),Object.setPrototypeOf(this,H.prototype),this.timestamp=s||"",this.traceId=o||"",this.correlationId=i||"",this.claims=a||"",this.name="InteractionRequiredAuthError",this.errorNo=l}}class ue{msalInstance;defaultScopes;account=null;state="Loading";listeners=[];constructor(e,n){this.msalInstance=e,this.defaultScopes=n}async initialize(){await this.msalInstance.initialize(),await this.msalInstance.handleRedirectPromise();const e=this.msalInstance.getActiveAccount(),n=this.msalInstance.getAllAccounts();this.account=e??n[0]??null,this.account?(this.msalInstance.setActiveAccount(this.account),this.setState("SignedIn")):this.setState("SignedOut")}async login(){const e={scopes:this.defaultScopes},n=await this.msalInstance.loginPopup(e);this.account=n.account,this.account&&this.msalInstance.setActiveAccount(this.account),this.setState("SignedIn")}async logout(){const e=this.msalInstance.getActiveAccount()??this.account??void 0;await this.msalInstance.logoutPopup({account:e}),this.account=null,this.setState("SignedOut")}async getAccessToken(e){const n=e&&e.length>0?e:this.defaultScopes,r=this.msalInstance.getActiveAccount()??this.account;if(!r)throw new Error("No active account. User must sign in first.");const s={scopes:n,account:r};try{return(await this.msalInstance.acquireTokenSilent(s)).accessToken}catch(o){if(o instanceof H){const i={scopes:n,account:r};return(await this.msalInstance.acquireTokenPopup(i)).accessToken}throw o}}getState(){return this.state}onStateChanged(e){this.listeners.push(e)}removeStateChangedHandler(e){this.listeners=this.listeners.filter(n=>n!==e)}setState(e){this.state=e,this.emit()}emit(){for(const e of this.listeners)try{e()}catch{}}}const he=6e4;function de(t){const e=t.fetchFn??fetch;return async({ssoToken:n,scopes:r})=>{const s=await e(t.endpoint,{method:"POST",headers:{Authorization:`Bearer ${n}`,"Content-Type":"application/json"},body:JSON.stringify({scopes:r})}),o=await s.json().catch(()=>({error:s.statusText||"Token exchange failed"}));if(!s.ok){const i=o?.error||o?.message||s.statusText;throw new Error(`Backend token exchange failed: ${i}`)}if(!o?.accessToken)throw new Error("Backend token exchange response did not include accessToken.");return{accessToken:o.accessToken,expiresAt:o.expiresAt}}}class fe{defaultScopes;getTeamsSsoTokenFn;exchangeForGraphTokenFn;refreshSkewMs;state="SignedOut";listeners=[];tokenCache=new Map;constructor(e){if(!e.defaultScopes||e.defaultScopes.length===0)throw new Error("TeamsHostedProvider requires at least one default scope.");this.defaultScopes=[...new Set(e.defaultScopes)],this.getTeamsSsoTokenFn=e.getTeamsSsoToken,this.exchangeForGraphTokenFn=e.exchangeForGraphToken,this.refreshSkewMs=e.refreshSkewMs??he}async login(){try{await this.getAccessToken(),this.setState("SignedIn")}catch(e){throw this.clearCache(),this.setState("SignedOut"),e}}async logout(){this.clearCache(),this.setState("SignedOut")}async getAccessToken(e){const n=this.normalizeScopes(e),r=this.buildScopeKey(n),s=this.tokenCache.get(r);if(s&&this.isTokenValid(s))return s.accessToken;const o=await this.getTeamsSsoTokenFn(n);if(!o)throw new Error("Teams SSO token acquisition returned empty token.");const i=await this.exchangeForGraphTokenFn({ssoToken:o,scopes:n}),a=this.normalizeExchangedToken(i);return this.tokenCache.set(r,a),this.setState("SignedIn"),a.accessToken}getState(){return this.state}onStateChanged(e){this.listeners.push(e)}removeStateChangedHandler(e){this.listeners=this.listeners.filter(n=>n!==e)}normalizeScopes(e){const n=e&&e.length>0?e:this.defaultScopes,r=[...new Set(n.filter(Boolean))];if(r.length===0)throw new Error("At least one scope is required to request a Graph token.");return r}buildScopeKey(e){return[...e].sort().join(" ")}isTokenValid(e){return e.expiresAtMs?Date.now()+this.refreshSkewMs<e.expiresAtMs:!0}normalizeExchangedToken(e){if(typeof e=="string"){if(!e)throw new Error("Graph token exchange returned empty access token.");return{accessToken:e}}if(!e.accessToken)throw new Error("Graph token exchange returned empty access token.");return{accessToken:e.accessToken,expiresAtMs:this.toEpochMs(e.expiresAt)}}toEpochMs(e){if(e)return e instanceof Date?e.getTime():e}clearCache(){this.tokenCache.clear()}setState(e){this.state!==e&&(this.state=e,this.emit())}emit(){for(const e of this.listeners)try{e()}catch{}}}exports.GraphProvider=ne;exports.MockProvider=B;exports.MsalBrowserProvider=ue;exports.Person=ie;exports.TeamsHostedProvider=fe;exports.createBackendTokenExchange=de;exports.createMockSignedInProvider=oe;exports.useGraphClient=z;exports.usePersonCacheOptions=$;exports.usePersonData=K;exports.useProvider=N;exports.useProviderState=_;
|
package/dist/index.mjs
CHANGED
|
@@ -1,59 +1,122 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { Persona as
|
|
3
|
-
import { createContext as
|
|
4
|
-
import { Client as
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { jsx as U } from "react/jsx-runtime";
|
|
2
|
+
import { Persona as H } from "@fluentui/react-components";
|
|
3
|
+
import { createContext as K, useCallback as L, useSyncExternalStore as V, useMemo as F, useContext as N, useState as Q, useEffect as J } from "react";
|
|
4
|
+
import { Client as W } from "@microsoft/microsoft-graph-client";
|
|
5
|
+
const X = "graph-toolkit-person-cache", v = "personData", Y = 1, Z = 3600 * 1e3, ee = 3600 * 1e3, te = 300 * 1e3, j = {
|
|
6
|
+
enabled: !0,
|
|
7
|
+
userTtlMs: Z,
|
|
8
|
+
photoTtlMs: ee,
|
|
9
|
+
presenceTtlMs: te
|
|
10
|
+
}, _ = () => typeof window < "u" && typeof window.indexedDB < "u", R = (t) => new Promise((e, n) => {
|
|
11
|
+
t.onsuccess = () => e(t.result), t.onerror = () => n(t.error);
|
|
12
|
+
}), q = () => new Promise((t, e) => {
|
|
13
|
+
if (!_()) {
|
|
14
|
+
e(new Error("IndexedDB unavailable"));
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const n = window.indexedDB.open(X, Y);
|
|
18
|
+
n.onupgradeneeded = () => {
|
|
19
|
+
const r = n.result;
|
|
20
|
+
r.objectStoreNames.contains(v) || r.createObjectStore(v);
|
|
21
|
+
}, n.onsuccess = () => t(n.result), n.onerror = () => e(n.error);
|
|
22
|
+
}), ne = (t) => `person:${t.trim().toLowerCase()}`, M = (t, e) => t ? Date.now() - t < e : !1, se = async (t) => {
|
|
23
|
+
if (!_())
|
|
24
|
+
return null;
|
|
25
|
+
let e = null;
|
|
26
|
+
try {
|
|
27
|
+
e = await q();
|
|
28
|
+
const r = e.transaction(v, "readonly").objectStore(v);
|
|
29
|
+
return await R(r.get(t)) ?? null;
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
} finally {
|
|
33
|
+
e?.close();
|
|
34
|
+
}
|
|
35
|
+
}, re = async (t, e) => {
|
|
36
|
+
if (!_())
|
|
37
|
+
return;
|
|
38
|
+
let n = null;
|
|
39
|
+
try {
|
|
40
|
+
n = await q();
|
|
41
|
+
const s = n.transaction(v, "readwrite").objectStore(v);
|
|
42
|
+
await R(s.put(e, t));
|
|
43
|
+
} catch {
|
|
44
|
+
return;
|
|
45
|
+
} finally {
|
|
46
|
+
n?.close();
|
|
47
|
+
}
|
|
48
|
+
}, O = K({
|
|
7
49
|
provider: null,
|
|
8
|
-
state:
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
50
|
+
state: "Loading",
|
|
51
|
+
personCacheOptions: j
|
|
52
|
+
}), Te = ({
|
|
53
|
+
provider: t,
|
|
54
|
+
children: e,
|
|
55
|
+
personCacheOptions: n
|
|
56
|
+
}) => {
|
|
57
|
+
const r = L(
|
|
58
|
+
() => t?.getState?.() ?? "Loading",
|
|
12
59
|
[t]
|
|
13
|
-
),
|
|
14
|
-
(
|
|
15
|
-
const
|
|
16
|
-
typeof
|
|
60
|
+
), s = L(
|
|
61
|
+
(l) => (t.onStateChanged?.(l), () => {
|
|
62
|
+
const g = t;
|
|
63
|
+
typeof g.removeStateChangedHandler == "function" && g.removeStateChangedHandler(l);
|
|
17
64
|
}),
|
|
18
65
|
[t]
|
|
19
|
-
),
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
66
|
+
), o = V(s, r, r), i = F(
|
|
67
|
+
() => ({
|
|
68
|
+
...j,
|
|
69
|
+
...n ?? {}
|
|
70
|
+
}),
|
|
71
|
+
[n]
|
|
72
|
+
), a = F(
|
|
73
|
+
() => ({
|
|
74
|
+
provider: t,
|
|
75
|
+
state: o,
|
|
76
|
+
personCacheOptions: i
|
|
77
|
+
}),
|
|
78
|
+
[t, o, i]
|
|
79
|
+
);
|
|
80
|
+
return /* @__PURE__ */ U(O.Provider, { value: a, children: e });
|
|
81
|
+
}, G = () => {
|
|
82
|
+
const { provider: t } = N(O);
|
|
83
|
+
return t;
|
|
84
|
+
}, $ = () => {
|
|
85
|
+
const { state: t } = N(O);
|
|
23
86
|
return t;
|
|
24
|
-
},
|
|
25
|
-
const {
|
|
87
|
+
}, oe = () => {
|
|
88
|
+
const { personCacheOptions: t } = N(O);
|
|
26
89
|
return t;
|
|
27
|
-
},
|
|
90
|
+
}, ae = (t) => W.init({
|
|
28
91
|
authProvider: async (e) => {
|
|
29
92
|
try {
|
|
30
|
-
const
|
|
31
|
-
e(null,
|
|
32
|
-
} catch (
|
|
33
|
-
e(
|
|
93
|
+
const n = await t.getAccessToken();
|
|
94
|
+
e(null, n);
|
|
95
|
+
} catch (n) {
|
|
96
|
+
e(n, null);
|
|
34
97
|
}
|
|
35
98
|
}
|
|
36
|
-
}),
|
|
99
|
+
}), ce = (t) => {
|
|
37
100
|
const e = t.trim().split(" ");
|
|
38
101
|
return e.length === 1 ? e[0].substring(0, 2).toUpperCase() : (e[0][0] + e[e.length - 1][0]).toUpperCase();
|
|
39
|
-
},
|
|
40
|
-
const t =
|
|
41
|
-
return
|
|
102
|
+
}, ie = () => {
|
|
103
|
+
const t = G(), e = $();
|
|
104
|
+
return F(() => !t || e !== "SignedIn" ? null : ae(t), [t, e]);
|
|
42
105
|
};
|
|
43
|
-
class
|
|
44
|
-
state =
|
|
106
|
+
class z {
|
|
107
|
+
state = "SignedOut";
|
|
45
108
|
listeners = [];
|
|
46
109
|
constructor(e) {
|
|
47
|
-
e?.autoSignIn && (this.state =
|
|
110
|
+
e?.autoSignIn && (this.state = "SignedIn");
|
|
48
111
|
}
|
|
49
112
|
getAccessToken() {
|
|
50
|
-
return this.state !==
|
|
113
|
+
return this.state !== "SignedIn" ? Promise.reject(new Error("Not signed in")) : Promise.resolve("mock-token");
|
|
51
114
|
}
|
|
52
115
|
async login() {
|
|
53
|
-
this.state =
|
|
116
|
+
this.state = "SignedIn", this.emit();
|
|
54
117
|
}
|
|
55
118
|
async logout() {
|
|
56
|
-
this.state =
|
|
119
|
+
this.state = "SignedOut", this.emit();
|
|
57
120
|
}
|
|
58
121
|
getState() {
|
|
59
122
|
return this.state;
|
|
@@ -62,7 +125,7 @@ class F {
|
|
|
62
125
|
this.listeners.push(e);
|
|
63
126
|
}
|
|
64
127
|
removeStateChangedHandler(e) {
|
|
65
|
-
this.listeners = this.listeners.filter((
|
|
128
|
+
this.listeners = this.listeners.filter((n) => n !== e);
|
|
66
129
|
}
|
|
67
130
|
emit() {
|
|
68
131
|
for (const e of this.listeners)
|
|
@@ -72,19 +135,29 @@ class F {
|
|
|
72
135
|
}
|
|
73
136
|
}
|
|
74
137
|
}
|
|
75
|
-
const
|
|
76
|
-
|
|
138
|
+
const ye = () => new z({ autoSignIn: !0 }), le = async (t) => {
|
|
139
|
+
if (!t)
|
|
140
|
+
return null;
|
|
141
|
+
if (typeof t == "string")
|
|
142
|
+
return t;
|
|
143
|
+
const e = t instanceof Blob ? t : t instanceof ArrayBuffer ? new Blob([t]) : null;
|
|
144
|
+
return e ? new Promise((n, r) => {
|
|
145
|
+
const s = new FileReader();
|
|
146
|
+
s.onloadend = () => n(typeof s.result == "string" ? s.result : null), s.onerror = () => r(s.error), s.readAsDataURL(e);
|
|
147
|
+
}) : null;
|
|
148
|
+
}, ue = (t) => {
|
|
149
|
+
const e = ie(), n = G(), r = $(), s = oe(), { userId: o, userPrincipalName: i, fetchPresence: a = !1, fetchPhoto: l = !0 } = t, [g, u] = Q({
|
|
77
150
|
user: null,
|
|
78
151
|
presence: null,
|
|
79
152
|
photoUrl: null,
|
|
80
153
|
loading: !0,
|
|
81
154
|
error: null
|
|
82
155
|
});
|
|
83
|
-
return
|
|
84
|
-
let
|
|
156
|
+
return J(() => {
|
|
157
|
+
let d = !1;
|
|
85
158
|
return (async () => {
|
|
86
|
-
if (
|
|
87
|
-
const
|
|
159
|
+
if (n instanceof z) {
|
|
160
|
+
const h = {
|
|
88
161
|
id: "00000000-0000-0000-0000-000000000000",
|
|
89
162
|
displayName: "Adele Vance",
|
|
90
163
|
userPrincipalName: "adelev@contoso.com",
|
|
@@ -92,23 +165,23 @@ const Z = () => new F({ autoSignIn: !0 }), H = (t) => {
|
|
|
92
165
|
department: "Marketing",
|
|
93
166
|
officeLocation: "19/3106",
|
|
94
167
|
mail: "adelev@contoso.com"
|
|
95
|
-
},
|
|
168
|
+
}, T = {
|
|
96
169
|
availability: "Available",
|
|
97
170
|
activity: "Available",
|
|
98
|
-
id:
|
|
171
|
+
id: h.id,
|
|
99
172
|
odataType: "#microsoft.graph.presence"
|
|
100
173
|
};
|
|
101
|
-
|
|
102
|
-
user:
|
|
103
|
-
presence:
|
|
104
|
-
photoUrl:
|
|
174
|
+
d || u({
|
|
175
|
+
user: h,
|
|
176
|
+
presence: a ? T : null,
|
|
177
|
+
photoUrl: l ? "https://ui-avatars.com/api/?name=Adele+Vance&background=0D8ABC&color=ffffff" : null,
|
|
105
178
|
loading: !1,
|
|
106
179
|
error: null
|
|
107
180
|
});
|
|
108
181
|
return;
|
|
109
182
|
}
|
|
110
183
|
if (r !== "SignedIn") {
|
|
111
|
-
|
|
184
|
+
d || u({
|
|
112
185
|
user: null,
|
|
113
186
|
presence: null,
|
|
114
187
|
photoUrl: null,
|
|
@@ -118,12 +191,12 @@ const Z = () => new F({ autoSignIn: !0 }), H = (t) => {
|
|
|
118
191
|
return;
|
|
119
192
|
}
|
|
120
193
|
if (!e) {
|
|
121
|
-
|
|
194
|
+
d || u((h) => ({ ...h, loading: !0 }));
|
|
122
195
|
return;
|
|
123
196
|
}
|
|
124
|
-
const
|
|
125
|
-
if (!
|
|
126
|
-
|
|
197
|
+
const S = o || i;
|
|
198
|
+
if (!S) {
|
|
199
|
+
d || u({
|
|
127
200
|
user: null,
|
|
128
201
|
presence: null,
|
|
129
202
|
photoUrl: null,
|
|
@@ -132,64 +205,81 @@ const Z = () => new F({ autoSignIn: !0 }), H = (t) => {
|
|
|
132
205
|
});
|
|
133
206
|
return;
|
|
134
207
|
}
|
|
208
|
+
const E = ne(S), c = s.enabled ? await se(E) : null, b = !!(c?.user && M(c.userCachedAt, s.userTtlMs)), A = !!(c?.presenceCachedAt && M(c.presenceCachedAt, s.presenceTtlMs)), P = !!(c?.photoCachedAt && M(c.photoCachedAt, s.photoTtlMs));
|
|
209
|
+
if (b && (!a || A) && (!l || P)) {
|
|
210
|
+
d || u({
|
|
211
|
+
user: c?.user ?? null,
|
|
212
|
+
presence: a ? c?.presence ?? null : null,
|
|
213
|
+
photoUrl: l ? c?.photoUrl ?? null : null,
|
|
214
|
+
loading: !1,
|
|
215
|
+
error: null
|
|
216
|
+
});
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
135
219
|
try {
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
220
|
+
u((k) => ({ ...k, loading: !0, error: null }));
|
|
221
|
+
const h = S.toLowerCase() === "me", T = Date.now();
|
|
222
|
+
let C = !1, y = !1, w = !1, f = b ? c?.user ?? null : null;
|
|
223
|
+
if (f || (f = await e.api(h ? "/me" : `/users/${S}`).select("id,displayName,jobTitle,mail,department,officeLocation,userPrincipalName").get(), C = !0), d) return;
|
|
224
|
+
let x = null, I = null;
|
|
225
|
+
if (a) {
|
|
226
|
+
if (A)
|
|
227
|
+
x = c?.presence ?? null;
|
|
228
|
+
else if (f?.id) {
|
|
229
|
+
try {
|
|
230
|
+
x = await e.api(h ? "/me/presence" : `/users/${f.id}/presence`).get();
|
|
231
|
+
} catch (k) {
|
|
232
|
+
console.warn("Failed to fetch presence:", k);
|
|
233
|
+
}
|
|
234
|
+
y = !0;
|
|
145
235
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
236
|
+
}
|
|
237
|
+
if (l) {
|
|
238
|
+
if (P)
|
|
239
|
+
I = c?.photoUrl ?? null;
|
|
240
|
+
else if (f?.id) {
|
|
241
|
+
try {
|
|
242
|
+
const k = await e.api(h ? "/me/photo/$value" : `/users/${f.id}/photo/$value`).get();
|
|
243
|
+
I = await le(k);
|
|
244
|
+
} catch (k) {
|
|
245
|
+
console.warn("Failed to fetch photo:", k);
|
|
246
|
+
}
|
|
247
|
+
w = !0;
|
|
152
248
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
249
|
+
}
|
|
250
|
+
const p = {
|
|
251
|
+
...c ?? {}
|
|
252
|
+
};
|
|
253
|
+
C && f && (p.user = f, p.userCachedAt = T), a && (y || A) && (p.presence = y ? x : c?.presence, p.presenceCachedAt = y ? T : c?.presenceCachedAt), l && (w || P) && (p.photoUrl = w ? I : c?.photoUrl, p.photoCachedAt = w ? T : c?.photoCachedAt), s.enabled && (C || y || w) && p.user && await re(E, p), d || u({
|
|
254
|
+
user: f,
|
|
255
|
+
presence: x,
|
|
256
|
+
photoUrl: I,
|
|
157
257
|
loading: !1,
|
|
158
258
|
error: null
|
|
159
259
|
});
|
|
160
|
-
} catch (
|
|
161
|
-
|
|
260
|
+
} catch (h) {
|
|
261
|
+
d || u({
|
|
162
262
|
user: null,
|
|
163
263
|
presence: null,
|
|
164
264
|
photoUrl: null,
|
|
165
265
|
loading: !1,
|
|
166
|
-
error:
|
|
266
|
+
error: h
|
|
167
267
|
});
|
|
168
268
|
}
|
|
169
269
|
})(), () => {
|
|
170
|
-
|
|
270
|
+
d = !0;
|
|
171
271
|
};
|
|
172
272
|
}, [
|
|
173
273
|
e,
|
|
174
|
-
s,
|
|
175
|
-
r,
|
|
176
274
|
n,
|
|
177
|
-
|
|
275
|
+
r,
|
|
276
|
+
o,
|
|
178
277
|
i,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
return "small";
|
|
185
|
-
case "large":
|
|
186
|
-
return "large";
|
|
187
|
-
case "extra-large":
|
|
188
|
-
return "extra-large";
|
|
189
|
-
default:
|
|
190
|
-
return "medium";
|
|
191
|
-
}
|
|
192
|
-
}, K = (t) => {
|
|
278
|
+
a,
|
|
279
|
+
l,
|
|
280
|
+
s
|
|
281
|
+
]), g;
|
|
282
|
+
}, he = (t) => {
|
|
193
283
|
switch (t?.toLowerCase()) {
|
|
194
284
|
case "available":
|
|
195
285
|
case "availableidle":
|
|
@@ -204,117 +294,108 @@ const Z = () => new F({ autoSignIn: !0 }), H = (t) => {
|
|
|
204
294
|
default:
|
|
205
295
|
return "offline";
|
|
206
296
|
}
|
|
207
|
-
},
|
|
297
|
+
}, we = ({
|
|
208
298
|
userId: t,
|
|
209
299
|
userPrincipalName: e,
|
|
210
|
-
email:
|
|
300
|
+
email: n,
|
|
211
301
|
personDetails: r,
|
|
212
|
-
view:
|
|
213
|
-
showPresence:
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
textPosition: p,
|
|
217
|
-
numericSize: d,
|
|
218
|
-
fetchImage: h = !0,
|
|
219
|
-
onClick: T,
|
|
220
|
-
className: g,
|
|
221
|
-
style: l
|
|
302
|
+
view: s = "oneline",
|
|
303
|
+
showPresence: o = !1,
|
|
304
|
+
fetchImage: i = !0,
|
|
305
|
+
...a
|
|
222
306
|
}) => {
|
|
223
|
-
const { user:
|
|
224
|
-
userId: r ? void 0 : t || e ||
|
|
225
|
-
fetchPresence:
|
|
226
|
-
fetchPhoto:
|
|
227
|
-
}),
|
|
228
|
-
if (
|
|
229
|
-
return /* @__PURE__ */
|
|
230
|
-
|
|
307
|
+
const { user: l, presence: g, photoUrl: u, loading: d } = ue({
|
|
308
|
+
userId: r ? void 0 : t || e || n,
|
|
309
|
+
fetchPresence: o,
|
|
310
|
+
fetchPhoto: i
|
|
311
|
+
}), m = r || l;
|
|
312
|
+
if (d)
|
|
313
|
+
return /* @__PURE__ */ U(
|
|
314
|
+
H,
|
|
231
315
|
{
|
|
232
|
-
|
|
233
|
-
name: "Loading..."
|
|
234
|
-
textAlignment: c,
|
|
235
|
-
textPosition: p,
|
|
236
|
-
className: g,
|
|
237
|
-
style: l
|
|
316
|
+
...a,
|
|
317
|
+
name: a.name ?? "Loading..."
|
|
238
318
|
}
|
|
239
319
|
);
|
|
240
|
-
if (!
|
|
320
|
+
if (!m)
|
|
241
321
|
return null;
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
322
|
+
const S = m.displayName || "Unknown User", E = ce(S), c = s !== "avatar" && (s === "twolines" || s === "threelines" || s === "fourlines") ? m.jobTitle ?? void 0 : void 0, b = s !== "avatar" && (s === "threelines" || s === "fourlines") ? m.department ?? void 0 : void 0, A = s !== "avatar" && s === "fourlines" ? m.officeLocation ?? m.mail ?? void 0 : void 0, P = o && g ? {
|
|
323
|
+
status: he(g.availability)
|
|
324
|
+
} : void 0, h = a.presence ?? P, T = a.avatar ?? {
|
|
325
|
+
image: u ? { src: u } : void 0,
|
|
326
|
+
initials: u ? void 0 : E
|
|
327
|
+
}, C = a.name ?? S, y = a.secondaryText ?? c, w = a.tertiaryText ?? b, f = a.quaternaryText ?? A;
|
|
328
|
+
return /* @__PURE__ */ U(
|
|
329
|
+
H,
|
|
330
|
+
{
|
|
331
|
+
...a,
|
|
332
|
+
name: C,
|
|
333
|
+
avatar: T,
|
|
334
|
+
presence: h,
|
|
335
|
+
secondaryText: y,
|
|
336
|
+
tertiaryText: w,
|
|
337
|
+
quaternaryText: f
|
|
338
|
+
}
|
|
339
|
+
);
|
|
259
340
|
};
|
|
260
|
-
function
|
|
341
|
+
function de(t) {
|
|
261
342
|
return `See https://aka.ms/msal.js.errors#${t} for details`;
|
|
262
343
|
}
|
|
263
|
-
class
|
|
264
|
-
constructor(e,
|
|
265
|
-
const
|
|
266
|
-
super(
|
|
344
|
+
class D extends Error {
|
|
345
|
+
constructor(e, n, r) {
|
|
346
|
+
const s = n || (e ? de(e) : ""), o = s ? `${e}: ${s}` : e;
|
|
347
|
+
super(o), Object.setPrototypeOf(this, D.prototype), this.errorCode = e || "", this.errorMessage = s || "", this.subError = r || "", this.name = "AuthError";
|
|
267
348
|
}
|
|
268
349
|
setCorrelationId(e) {
|
|
269
350
|
this.correlationId = e;
|
|
270
351
|
}
|
|
271
352
|
}
|
|
272
|
-
class
|
|
273
|
-
constructor(e,
|
|
274
|
-
super(e,
|
|
353
|
+
class B extends D {
|
|
354
|
+
constructor(e, n, r, s, o, i, a, l) {
|
|
355
|
+
super(e, n, r), Object.setPrototypeOf(this, B.prototype), this.timestamp = s || "", this.traceId = o || "", this.correlationId = i || "", this.claims = a || "", this.name = "InteractionRequiredAuthError", this.errorNo = l;
|
|
275
356
|
}
|
|
276
357
|
}
|
|
277
|
-
class
|
|
358
|
+
class ke {
|
|
278
359
|
msalInstance;
|
|
279
360
|
defaultScopes;
|
|
280
361
|
account = null;
|
|
281
|
-
state =
|
|
362
|
+
state = "Loading";
|
|
282
363
|
listeners = [];
|
|
283
|
-
constructor(e,
|
|
284
|
-
this.msalInstance = e, this.defaultScopes =
|
|
364
|
+
constructor(e, n) {
|
|
365
|
+
this.msalInstance = e, this.defaultScopes = n;
|
|
285
366
|
}
|
|
286
367
|
async initialize() {
|
|
287
368
|
await this.msalInstance.initialize(), await this.msalInstance.handleRedirectPromise();
|
|
288
|
-
const e = this.msalInstance.getActiveAccount(),
|
|
289
|
-
this.account = e ??
|
|
369
|
+
const e = this.msalInstance.getActiveAccount(), n = this.msalInstance.getAllAccounts();
|
|
370
|
+
this.account = e ?? n[0] ?? null, this.account ? (this.msalInstance.setActiveAccount(this.account), this.setState("SignedIn")) : this.setState("SignedOut");
|
|
290
371
|
}
|
|
291
372
|
async login() {
|
|
292
|
-
const e = { scopes: this.defaultScopes },
|
|
293
|
-
this.account =
|
|
373
|
+
const e = { scopes: this.defaultScopes }, n = await this.msalInstance.loginPopup(e);
|
|
374
|
+
this.account = n.account, this.account && this.msalInstance.setActiveAccount(this.account), this.setState("SignedIn");
|
|
294
375
|
}
|
|
295
376
|
async logout() {
|
|
296
377
|
const e = this.msalInstance.getActiveAccount() ?? this.account ?? void 0;
|
|
297
|
-
await this.msalInstance.logoutPopup({ account: e }), this.account = null, this.setState(
|
|
378
|
+
await this.msalInstance.logoutPopup({ account: e }), this.account = null, this.setState("SignedOut");
|
|
298
379
|
}
|
|
299
380
|
async getAccessToken(e) {
|
|
300
|
-
const
|
|
381
|
+
const n = e && e.length > 0 ? e : this.defaultScopes, r = this.msalInstance.getActiveAccount() ?? this.account;
|
|
301
382
|
if (!r)
|
|
302
383
|
throw new Error("No active account. User must sign in first.");
|
|
303
|
-
const
|
|
304
|
-
scopes:
|
|
384
|
+
const s = {
|
|
385
|
+
scopes: n,
|
|
305
386
|
account: r
|
|
306
387
|
};
|
|
307
388
|
try {
|
|
308
|
-
return (await this.msalInstance.acquireTokenSilent(
|
|
309
|
-
} catch (
|
|
310
|
-
if (
|
|
389
|
+
return (await this.msalInstance.acquireTokenSilent(s)).accessToken;
|
|
390
|
+
} catch (o) {
|
|
391
|
+
if (o instanceof B) {
|
|
311
392
|
const i = {
|
|
312
|
-
scopes:
|
|
393
|
+
scopes: n,
|
|
313
394
|
account: r
|
|
314
395
|
};
|
|
315
396
|
return (await this.msalInstance.acquireTokenPopup(i)).accessToken;
|
|
316
397
|
}
|
|
317
|
-
throw
|
|
398
|
+
throw o;
|
|
318
399
|
}
|
|
319
400
|
}
|
|
320
401
|
getState() {
|
|
@@ -324,7 +405,7 @@ class te {
|
|
|
324
405
|
this.listeners.push(e);
|
|
325
406
|
}
|
|
326
407
|
removeStateChangedHandler(e) {
|
|
327
|
-
this.listeners = this.listeners.filter((
|
|
408
|
+
this.listeners = this.listeners.filter((n) => n !== e);
|
|
328
409
|
}
|
|
329
410
|
setState(e) {
|
|
330
411
|
this.state = e, this.emit();
|
|
@@ -337,65 +418,68 @@ class te {
|
|
|
337
418
|
}
|
|
338
419
|
}
|
|
339
420
|
}
|
|
340
|
-
const
|
|
341
|
-
function
|
|
421
|
+
const fe = 6e4;
|
|
422
|
+
function Ce(t) {
|
|
342
423
|
const e = t.fetchFn ?? fetch;
|
|
343
|
-
return async ({
|
|
344
|
-
|
|
424
|
+
return async ({
|
|
425
|
+
ssoToken: n,
|
|
426
|
+
scopes: r
|
|
427
|
+
}) => {
|
|
428
|
+
const s = await e(t.endpoint, {
|
|
345
429
|
method: "POST",
|
|
346
430
|
headers: {
|
|
347
|
-
Authorization: `Bearer ${
|
|
431
|
+
Authorization: `Bearer ${n}`,
|
|
348
432
|
"Content-Type": "application/json"
|
|
349
433
|
},
|
|
350
434
|
body: JSON.stringify({ scopes: r })
|
|
351
|
-
}),
|
|
352
|
-
if (!
|
|
353
|
-
const i =
|
|
435
|
+
}), o = await s.json().catch(() => ({ error: s.statusText || "Token exchange failed" }));
|
|
436
|
+
if (!s.ok) {
|
|
437
|
+
const i = o?.error || o?.message || s.statusText;
|
|
354
438
|
throw new Error(`Backend token exchange failed: ${i}`);
|
|
355
439
|
}
|
|
356
|
-
if (!
|
|
440
|
+
if (!o?.accessToken)
|
|
357
441
|
throw new Error("Backend token exchange response did not include accessToken.");
|
|
358
442
|
return {
|
|
359
|
-
accessToken:
|
|
360
|
-
expiresAt:
|
|
443
|
+
accessToken: o.accessToken,
|
|
444
|
+
expiresAt: o.expiresAt
|
|
361
445
|
};
|
|
362
446
|
};
|
|
363
447
|
}
|
|
364
|
-
class
|
|
448
|
+
class ve {
|
|
365
449
|
defaultScopes;
|
|
366
450
|
getTeamsSsoTokenFn;
|
|
367
451
|
exchangeForGraphTokenFn;
|
|
368
452
|
refreshSkewMs;
|
|
369
|
-
state =
|
|
453
|
+
state = "SignedOut";
|
|
370
454
|
listeners = [];
|
|
371
455
|
tokenCache = /* @__PURE__ */ new Map();
|
|
372
456
|
constructor(e) {
|
|
373
457
|
if (!e.defaultScopes || e.defaultScopes.length === 0)
|
|
374
458
|
throw new Error("TeamsHostedProvider requires at least one default scope.");
|
|
375
|
-
this.defaultScopes = [...new Set(e.defaultScopes)], this.getTeamsSsoTokenFn = e.getTeamsSsoToken, this.exchangeForGraphTokenFn = e.exchangeForGraphToken, this.refreshSkewMs = e.refreshSkewMs ??
|
|
459
|
+
this.defaultScopes = [...new Set(e.defaultScopes)], this.getTeamsSsoTokenFn = e.getTeamsSsoToken, this.exchangeForGraphTokenFn = e.exchangeForGraphToken, this.refreshSkewMs = e.refreshSkewMs ?? fe;
|
|
376
460
|
}
|
|
377
461
|
async login() {
|
|
378
462
|
try {
|
|
379
|
-
await this.getAccessToken(), this.setState(
|
|
463
|
+
await this.getAccessToken(), this.setState("SignedIn");
|
|
380
464
|
} catch (e) {
|
|
381
|
-
throw this.clearCache(), this.setState(
|
|
465
|
+
throw this.clearCache(), this.setState("SignedOut"), e;
|
|
382
466
|
}
|
|
383
467
|
}
|
|
384
468
|
async logout() {
|
|
385
|
-
this.clearCache(), this.setState(
|
|
469
|
+
this.clearCache(), this.setState("SignedOut");
|
|
386
470
|
}
|
|
387
471
|
async getAccessToken(e) {
|
|
388
|
-
const
|
|
389
|
-
if (
|
|
390
|
-
return
|
|
391
|
-
const
|
|
392
|
-
if (!
|
|
472
|
+
const n = this.normalizeScopes(e), r = this.buildScopeKey(n), s = this.tokenCache.get(r);
|
|
473
|
+
if (s && this.isTokenValid(s))
|
|
474
|
+
return s.accessToken;
|
|
475
|
+
const o = await this.getTeamsSsoTokenFn(n);
|
|
476
|
+
if (!o)
|
|
393
477
|
throw new Error("Teams SSO token acquisition returned empty token.");
|
|
394
478
|
const i = await this.exchangeForGraphTokenFn({
|
|
395
|
-
ssoToken:
|
|
396
|
-
scopes:
|
|
397
|
-
}),
|
|
398
|
-
return this.tokenCache.set(r,
|
|
479
|
+
ssoToken: o,
|
|
480
|
+
scopes: n
|
|
481
|
+
}), a = this.normalizeExchangedToken(i);
|
|
482
|
+
return this.tokenCache.set(r, a), this.setState("SignedIn"), a.accessToken;
|
|
399
483
|
}
|
|
400
484
|
getState() {
|
|
401
485
|
return this.state;
|
|
@@ -404,10 +488,10 @@ class ne {
|
|
|
404
488
|
this.listeners.push(e);
|
|
405
489
|
}
|
|
406
490
|
removeStateChangedHandler(e) {
|
|
407
|
-
this.listeners = this.listeners.filter((
|
|
491
|
+
this.listeners = this.listeners.filter((n) => n !== e);
|
|
408
492
|
}
|
|
409
493
|
normalizeScopes(e) {
|
|
410
|
-
const
|
|
494
|
+
const n = e && e.length > 0 ? e : this.defaultScopes, r = [...new Set(n.filter(Boolean))];
|
|
411
495
|
if (r.length === 0)
|
|
412
496
|
throw new Error("At least one scope is required to request a Graph token.");
|
|
413
497
|
return r;
|
|
@@ -450,16 +534,16 @@ class ne {
|
|
|
450
534
|
}
|
|
451
535
|
}
|
|
452
536
|
export {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
537
|
+
Te as GraphProvider,
|
|
538
|
+
z as MockProvider,
|
|
539
|
+
ke as MsalBrowserProvider,
|
|
540
|
+
we as Person,
|
|
541
|
+
ve as TeamsHostedProvider,
|
|
542
|
+
Ce as createBackendTokenExchange,
|
|
543
|
+
ye as createMockSignedInProvider,
|
|
544
|
+
ie as useGraphClient,
|
|
545
|
+
oe as usePersonCacheOptions,
|
|
546
|
+
ue as usePersonData,
|
|
547
|
+
G as useProvider,
|
|
548
|
+
$ as useProviderState
|
|
465
549
|
};
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Provider interface for Microsoft Graph authentication
|
|
3
3
|
*/
|
|
4
|
-
export
|
|
5
|
-
Loading = "Loading",
|
|
6
|
-
SignedOut = "SignedOut",
|
|
7
|
-
SignedIn = "SignedIn"
|
|
8
|
-
}
|
|
4
|
+
export type ProviderState = 'Loading' | 'SignedOut' | 'SignedIn';
|
|
9
5
|
export interface IProvider {
|
|
10
6
|
/**
|
|
11
7
|
* Get an access token for the specified scopes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IProvider.d.ts","sourceRoot":"","sources":["../../src/providers/IProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,
|
|
1
|
+
{"version":3,"file":"IProvider.d.ts","sourceRoot":"","sources":["../../src/providers/IProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAC;AAEjE,MAAM,WAAW,SAAS;IACxB;;OAEG;IACH,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnD;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAExB;;OAEG;IACH,QAAQ,IAAI,aAAa,CAAC;IAE1B;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CAChD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MockProvider.d.ts","sourceRoot":"","sources":["../../src/providers/MockProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIvD,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"MockProvider.d.ts","sourceRoot":"","sources":["../../src/providers/MockProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIvD,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,SAAS,CAAuB;gBAC5B,OAAO,CAAC,EAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;IAMnE,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7B,QAAQ,IAAI,aAAa;IAIzB,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIzC,yBAAyB,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpD,OAAO,CAAC,IAAI;CASb;AAED,eAAO,MAAM,0BAA0B,oBAA+C,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MsalBrowserProvider.d.ts","sourceRoot":"","sources":["../../src/providers/MsalBrowserProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"MsalBrowserProvider.d.ts","sourceRoot":"","sources":["../../src/providers/MsalBrowserProvider.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAIL,uBAAuB,EAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEvD,qBAAa,mBAAoB,YAAW,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;IACvD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,SAAS,CAAyB;gBAE9B,YAAY,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,EAAE;IAKpE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAOvB,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA8BxD,QAAQ,IAAI,aAAa;IAIzB,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIzC,yBAAyB,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpD,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,IAAI;CASb"}
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import React, { ReactNode } from 'react';
|
|
5
5
|
import { IProvider, ProviderState } from './IProvider';
|
|
6
|
+
import { PersonCacheOptions } from '../utils/personCache';
|
|
6
7
|
export interface GraphProviderProps {
|
|
7
8
|
provider: IProvider;
|
|
8
9
|
children: ReactNode;
|
|
10
|
+
personCacheOptions?: Partial<PersonCacheOptions>;
|
|
9
11
|
}
|
|
10
12
|
export declare const GraphProvider: React.FC<GraphProviderProps>;
|
|
11
13
|
/**
|
|
@@ -16,4 +18,8 @@ export declare const useProvider: () => IProvider | null;
|
|
|
16
18
|
* Hook to access the current provider state
|
|
17
19
|
*/
|
|
18
20
|
export declare const useProviderState: () => ProviderState;
|
|
21
|
+
/**
|
|
22
|
+
* Hook to access configured person cache options
|
|
23
|
+
*/
|
|
24
|
+
export declare const usePersonCacheOptions: () => PersonCacheOptions;
|
|
19
25
|
//# sourceMappingURL=ProviderContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProviderContext.d.ts","sourceRoot":"","sources":["../../src/providers/ProviderContext.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,EAIZ,SAAS,EAGV,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"ProviderContext.d.ts","sourceRoot":"","sources":["../../src/providers/ProviderContext.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,EAIZ,SAAS,EAGV,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAgC,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAcxF,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAClD;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8CtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,QAAO,SAAS,GAAG,IAG1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAO,aAGnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,QAAO,kBAGxC,CAAC"}
|
|
@@ -24,7 +24,7 @@ export interface CreateBackendTokenExchangeOptions {
|
|
|
24
24
|
* Creates a typed callback for exchanging a Teams SSO token with a backend
|
|
25
25
|
* endpoint that performs OBO and returns a Graph token.
|
|
26
26
|
*/
|
|
27
|
-
export declare function createBackendTokenExchange(options: CreateBackendTokenExchangeOptions): ({ ssoToken, scopes }: ExchangeForGraphTokenParams) => Promise<BackendTokenExchangeResponse>;
|
|
27
|
+
export declare function createBackendTokenExchange(options: CreateBackendTokenExchangeOptions): ({ ssoToken, scopes, }: ExchangeForGraphTokenParams) => Promise<BackendTokenExchangeResponse>;
|
|
28
28
|
/**
|
|
29
29
|
* Teams-hosted auth provider for Graph Toolkit React.
|
|
30
30
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TeamsHostedProvider.d.ts","sourceRoot":"","sources":["../../src/providers/TeamsHostedProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIvD,MAAM,WAAW,2BAA2B;
|
|
1
|
+
{"version":3,"file":"TeamsHostedProvider.d.ts","sourceRoot":"","sources":["../../src/providers/TeamsHostedProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIvD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,qBAAqB,EAAE,CACrB,MAAM,EAAE,2BAA2B,KAChC,OAAO,CAAC,MAAM,GAAG,mBAAmB,CAAC,CAAC;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,4BAA6B,SAAQ,mBAAmB;IACvE,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AASD;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,iCAAiC,IAGrE,uBAGX,2BAA2B,KAAG,OAAO,CAAC,4BAA4B,CAAC,CA4BvE;AAED;;;;;;GAMG;AACH,qBAAa,mBAAoB,YAAW,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAwC;IAC3E,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAEG;IAC3C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;gBAEjD,OAAO,EAAE,0BAA0B;IAWzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAKvB,cAAc,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA0BxD,QAAQ,IAAI,aAAa;IAIzB,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIzC,yBAAyB,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpD,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,uBAAuB;IAmB/B,OAAO,CAAC,SAAS;IAYjB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,IAAI;CASb"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Presence, User } from '@microsoft/microsoft-graph-types';
|
|
2
|
+
export declare const USER_CACHE_TTL_MS: number;
|
|
3
|
+
export declare const PHOTO_CACHE_TTL_MS: number;
|
|
4
|
+
export declare const PRESENCE_CACHE_TTL_MS: number;
|
|
5
|
+
export interface PersonCacheOptions {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
userTtlMs: number;
|
|
8
|
+
photoTtlMs: number;
|
|
9
|
+
presenceTtlMs: number;
|
|
10
|
+
}
|
|
11
|
+
export declare const DEFAULT_PERSON_CACHE_OPTIONS: PersonCacheOptions;
|
|
12
|
+
export interface PersonCacheEntry {
|
|
13
|
+
user?: User | null;
|
|
14
|
+
userCachedAt?: number;
|
|
15
|
+
presence?: Presence | null;
|
|
16
|
+
presenceCachedAt?: number;
|
|
17
|
+
photoUrl?: string | null;
|
|
18
|
+
photoCachedAt?: number;
|
|
19
|
+
}
|
|
20
|
+
export declare const getPersonCacheKey: (identifier: string) => string;
|
|
21
|
+
export declare const isTimestampFresh: (timestamp: number | undefined, ttlMs: number) => boolean;
|
|
22
|
+
export declare const readPersonCache: (key: string) => Promise<PersonCacheEntry | null>;
|
|
23
|
+
export declare const writePersonCache: (key: string, value: PersonCacheEntry) => Promise<void>;
|
|
24
|
+
//# sourceMappingURL=personCache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"personCache.d.ts","sourceRoot":"","sources":["../../src/utils/personCache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kCAAkC,CAAC;AAMlE,eAAO,MAAM,iBAAiB,QAAiB,CAAC;AAChD,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AACjD,eAAO,MAAM,qBAAqB,QAAgB,CAAC;AAEnD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,eAAO,MAAM,4BAA4B,EAAE,kBAK1C,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAkCD,eAAO,MAAM,iBAAiB,GAAI,YAAY,MAAM,KAAG,MAEtD,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,WAAW,MAAM,GAAG,SAAS,EAAE,OAAO,MAAM,KAAG,OAK/E,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,KAAK,MAAM,KAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAkBlF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,KAAK,MAAM,EAAE,OAAO,gBAAgB,KAAG,OAAO,CAAC,IAAI,CAiBzF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devsym/graph-toolkit-react",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0-next.5",
|
|
4
4
|
"description": "React components for Microsoft Graph powered by Fluent UI",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"dev": "vite build --watch",
|
|
23
23
|
"changeset": "changeset",
|
|
24
24
|
"version-packages": "changeset version",
|
|
25
|
-
"publish-packages": "changeset publish",
|
|
25
|
+
"publish-packages": "changeset publish --provenance",
|
|
26
26
|
"type-check": "tsc --noEmit",
|
|
27
27
|
"lint": "eslint src --ext .ts,.tsx",
|
|
28
28
|
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
@@ -43,8 +43,13 @@
|
|
|
43
43
|
],
|
|
44
44
|
"author": "",
|
|
45
45
|
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/ThomasPe/graph-toolkit-react"
|
|
49
|
+
},
|
|
46
50
|
"publishConfig": {
|
|
47
|
-
"access": "public"
|
|
51
|
+
"access": "public",
|
|
52
|
+
"tag": "next"
|
|
48
53
|
},
|
|
49
54
|
"peerDependencies": {
|
|
50
55
|
"@azure/msal-browser": "^4.0.0 || ^5.0.0",
|
|
@@ -91,4 +96,4 @@
|
|
|
91
96
|
"vite-plugin-dts": "^4.5.4",
|
|
92
97
|
"vitest": "^4.0.18"
|
|
93
98
|
}
|
|
94
|
-
}
|
|
99
|
+
}
|
package/readme.md
CHANGED
|
@@ -62,13 +62,17 @@ import { Person } from '@devsym/graph-toolkit-react';
|
|
|
62
62
|
|
|
63
63
|
<Person
|
|
64
64
|
userId="user@contoso.com"
|
|
65
|
-
view="
|
|
65
|
+
view="twolines"
|
|
66
66
|
showPresence
|
|
67
|
+
presenceOnly={false}
|
|
68
|
+
size="large"
|
|
67
69
|
textAlignment="center"
|
|
68
|
-
onClick={() => console.log('
|
|
70
|
+
onClick={() => console.log('Persona clicked!')}
|
|
69
71
|
/>
|
|
70
72
|
```
|
|
71
73
|
|
|
74
|
+
`Person` supports Fluent UI Persona props directly.
|
|
75
|
+
|
|
72
76
|
|
|
73
77
|
<a id="getting-started"></a>
|
|
74
78
|
## 🚀 Getting Started
|
|
@@ -115,7 +119,7 @@ function App() {
|
|
|
115
119
|
return (
|
|
116
120
|
<FluentProvider theme={webLightTheme}>
|
|
117
121
|
<GraphProvider provider={provider}>
|
|
118
|
-
<Person userId="AdeleV@contoso.com" view="
|
|
122
|
+
<Person userId="AdeleV@contoso.com" view="twolines" showPresence />
|
|
119
123
|
</GraphProvider>
|
|
120
124
|
</FluentProvider>
|
|
121
125
|
);
|
|
@@ -218,7 +222,7 @@ Use explicit mode selection in your app:
|
|
|
218
222
|
import { IProvider, ProviderState } from '@devsym/graph-toolkit-react';
|
|
219
223
|
|
|
220
224
|
class MyAuthProvider implements IProvider {
|
|
221
|
-
state =
|
|
225
|
+
state: ProviderState = 'SignedOut';
|
|
222
226
|
|
|
223
227
|
async login(): Promise<void> { /* ... */ }
|
|
224
228
|
async logout(): Promise<void> { /* ... */ }
|