@machinemetrics/mm-react-embeddable 2.0.1-0 → 2.0.1-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -23,5 +23,5 @@ the app and where it runs; footer Cancel/Approve; checkbox rows when several app
|
|
|
23
23
|
pending; legacy rows keep their own Authorize button because a popup must open from
|
|
24
24
|
the user's click on that row).
|
|
25
25
|
|
|
26
|
-
A host
|
|
27
|
-
interactive entry, and the host's UI opens the popup for it.
|
|
26
|
+
A host with no `credentialBroker`, or one whose broker returns an answer it may not act on, gets
|
|
27
|
+
an interactive entry, and the host's UI opens the popup for it.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react"),
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react"),ge=require("prop-types"),me=require("styled-components"),V=r=>r&&r.__esModule?r:{default:r},O=V(e),k=V(ge),te=V(me),Q=e.createContext(null),Y=e.createContext({pending:[],authorize:()=>{},approve:()=>{},complete:()=>{},dismiss:()=>{},originEpochs:{},credentials:{},unsupported:{}}),oe="access_token",J=r=>r?r.kind?r:r.accessToken?{kind:oe,accessToken:r.accessToken,expiresAt:r.expiresAt||null}:null:null,Ee=60,Re=120,ke=new Set(["host_not_allowed","unbound_host_bound_guest","invalid_token","provider_unavailable"]),G=r=>{try{return new URL(r).origin}catch{return null}},re=(r,o)=>{const i=o==null?void 0:o.origin;return!i||G(r==null?void 0:r.authUrl)!==i?null:i},ne=r=>{if(!r||/^\d{1,3}(?:\.\d{1,3}){3}$/.test(r)||r.includes(":"))return r;const o=r.split(".");return o.length<=2?r:o.slice(-2).join(".")},N=(r,o)=>{try{const i=new URL(r),d=new URL(o);return i.protocol!==d.protocol?!0:ne(i.hostname)!==ne(d.hostname)}catch{return!0}},ue=(r,{onBlocked:o,onClosed:i})=>{const d=window.open(r.authUrl,"mm-embed-auth","popup,width=600,height=700");if(!d)return o(),()=>{};const R=setInterval(()=>{d.closed&&(clearInterval(R),i())},1e3);return()=>clearInterval(R)},ce=({children:r,launcher:o,broker:i})=>{const d=e.useContext(Q),[R,C]=e.useState({}),[$,q]=e.useState({}),[D,W]=e.useState({}),[I,E]=e.useState({}),S=e.useRef(D);S.current=D;const B=e.useRef(R);B.current=R;const w=e.useRef(null),x=e.useRef({}),y=e.useRef({}),P=e.useRef(i);P.current=i;const U=e.useCallback(t=>{const s=x.current[t];if(!s)return;const n=c=>!c[t]||c[t].clientId?c:{...c,[t]:{...c[t],clientId:s}};C(n),E(n)},[]),F=e.useCallback((t,s)=>{t&&(E(n=>n[t]?n:{...n,[t]:{origin:t,reason:s,clientId:x.current[t]||null}}),U(t))},[U]),A=e.useCallback((t,{v2:s=!1,origin:n=null}={})=>{n&&(s&&S.current[n]||(C(c=>c[n]?c:{...c,[n]:{origin:n,authUrl:t.authUrl,status:s&&P.current?"broker":"interactive",v2:s,scope:t.scope||null,acceptsCredentials:y.current[n]||null,consent:null,error:null,clientId:t.clientId||x.current[n]||null,popupBlocked:!1}}),U(n)))},[U]),T=e.useRef({}),v=e.useCallback(t=>{T.current[t]&&(clearTimeout(T.current[t]),delete T.current[t])},[]),u=e.useCallback(t=>{v(t),C(s=>{if(!s[t])return s;const n={...s};return delete n[t],n})},[v]),l=e.useCallback(t=>{t&&(u(t),q(s=>({...s,[t]:(s[t]||0)+1})))},[u]),a=e.useCallback(t=>{u(t.origin)},[u]),p=e.useCallback((t,s)=>{const n=re(t,s);if(n){if(N(n,window.location.origin)){F(n,"cross-site-legacy");return}A(t,{origin:n})}},[A,F]);e.useEffect(()=>{if(!d)return;const t=[d.addListener("*","init",(s,n)=>{n!=null&&n.origin&&(s!=null&&s.clientId)&&(x.current[n.origin]=s.clientId,U(n.origin)),n!=null&&n.origin&&Array.isArray(s==null?void 0:s.acceptsCredentials)?y.current[n.origin]=s.acceptsCredentials:n!=null&&n.origin&&N(n.origin,window.location.origin)&&F(n.origin,"cross-site-legacy")}),d.addListener("*","authorize",p),d.addListener("*","login",p),d.addListener("*","credential-request",(s,n)=>A(s,{v2:!0,origin:re(s,n)}))];return()=>t.forEach(s=>s())},[d,p,A,U,F]),e.useEffect(()=>{const t=s=>{const n=s==null?void 0:s.data;if(!n||n.type!=="authorized")return;const c=G(n.authUrl);if(!c||s.origin!==c)return;const b=B.current[c];if(!(!b||b.status!=="interactive")){if(n.accessToken){W(L=>({...L,[c]:J({accessToken:n.accessToken})})),u(c);return}l(c)}};return window.addEventListener("message",t),()=>window.removeEventListener("message",t)},[u,l]);const h=e.useCallback((t,s)=>{const n=t==null?void 0:t.origin,c=J(s);!n||!c||(W(b=>({...b,[n]:c})),u(n))},[u]),g=e.useCallback((t,s)=>{C(n=>n[t]?{...n,[t]:{...n[t],...s}}:n)},[]),m=e.useRef({}),_=e.useCallback(async(t,{approve:s}={})=>{const n=P.current,{origin:c}=t;let b;try{b=await n({origin:c,clientId:t.clientId,scope:t.scope,authUrl:t.authUrl},{approve:s})}catch{s?g(c,{error:{reason:"broker_unavailable"}}):g(c,{status:"interactive"});return}const L=b==null?void 0:b.status,f=(b==null?void 0:b.body)||{};if(L===200&&f.credential){h(t,f.credential);return}if(L===409&&f.consentRequired){g(c,{status:"interactive",consent:{client:f.client||null,stepUp:!!f.stepUp,scope:f.scope||t.scope},error:null});return}const z=f.error||"broker_error";if(!s&&ke.has(z)){g(c,{status:"interactive"});return}if(s&&z==="consent_denied"){g(c,{error:null});return}if(z==="rate_limited"&&!t.rateLimitRetried){const X=Math.min(Number(f.retryAfter)>0?Number(f.retryAfter):Ee,Re),he={...t,rateLimitRetried:!0};v(c),T.current[c]=setTimeout(()=>{delete T.current[c],m.current[c]=!0,M.current(he,{approve:s}).finally(()=>{delete m.current[c]})},X*1e3),g(c,{rateLimitRetried:!0});return}u(c),E(X=>({...X,[c]:{origin:c,reason:`broker:${z}`,detail:{status:L!=null?L:null,reason:z},clientId:t.clientId||x.current[c]||null}}))},[h,g,u,v]),M=e.useRef(_);M.current=_,e.useEffect(()=>{Object.values(R).forEach(t=>{t.status!=="broker"||m.current[t.origin]||T.current[t.origin]||(m.current[t.origin]=!0,_(t).finally(()=>{delete m.current[t.origin]}))})},[R,_]);const K=e.useCallback(t=>!P.current||!(t!=null&&t.consent)||m.current[t.origin]?Promise.resolve():(m.current[t.origin]=!0,_(t,{approve:!0}).finally(()=>{delete m.current[t.origin]})),[_]);e.useEffect(()=>()=>{w.current&&w.current(),Object.values(T.current).forEach(clearTimeout)},[]);const Z=e.useCallback(t=>{w.current&&(w.current(),w.current=null);const s=o||ue;w.current=s(t,{onBlocked:()=>{C(n=>n[t.origin]?{...n,[t.origin]:{...n[t.origin],popupBlocked:!0}}:n)},onClosed:()=>{const n=B.current[t.origin];!n||n.v2||l(t.origin)}})},[o,l]),j={pending:Object.values(R).filter(t=>t.status==="interactive"),authorize:Z,approve:K,complete:h,dismiss:a,originEpochs:$,credentials:D,unsupported:I};return O.default.createElement(Y.Provider,{value:j},r)};ce.propTypes={children:k.default.node,launcher:k.default.func,broker:k.default.func};const Ce=()=>e.useContext(Y),ie=r=>{const{originEpochs:o}=e.useContext(Y),i=G(r);return i&&o[i]||0},ae=r=>{const{credentials:o}=e.useContext(Y),i=G(r);return i&&o[i]||null},le=r=>{const{unsupported:o}=e.useContext(Y),i=G(r);return i&&o[i]||null},se="MMEmbeddableZoneProvider requires a boolean `ready` prop (true once the host holds the bearer its credentialBroker needs). Embedded apps will not load until it is provided.",de=({children:r,authorizationLauncher:o,credentialBroker:i,ready:d})=>{const R=d===!0,C=e.useRef(!1);e.useEffect(()=>{d!==void 0||C.current||(C.current=!0,console.error(se),typeof window!="undefined"&&typeof window.alert=="function"&&window.alert(se))},[d]);const[$,q]=e.useState({}),[D,W]=e.useState({}),I=e.useRef({}),E=e.useRef({}),S=e.useRef({}),B=e.useCallback((u,l)=>{var a;return!!((a=S.current[u])!=null&&a.has(l))},[]),w=e.useCallback((u,l,a)=>{q(p=>({...p,[u]:{origin:l,frameRef:a}}))},[]),x=e.useCallback(u=>{q(l=>{const a={...l};return delete a[u],a}),W(l=>{const a={...l};return delete a[u],a}),delete S.current[u],Object.keys(E.current).forEach(l=>{E.current[l].instanceId===u&&delete E.current[l]})},[]);e.useEffect(()=>()=>{E.current={}},[]),e.useEffect(()=>{const u=(a=[],p,h)=>{a.forEach(g=>g(p,h))},l=a=>{var K,Z,j,t,s,n,c;if(!((K=a==null?void 0:a.data)!=null&&K.instanceId))return;const{instanceId:p,type:h}=a.data,g=$[p],m=(j=(Z=g==null?void 0:g.frameRef)==null?void 0:Z.current)==null?void 0:j.contentWindow;if(!m||a.source!==m||a.origin!==g.origin)return;const _={origin:a.origin},M=I.current;if(h==="response"){const{callbackId:b,response:L,error:f}=a.data,z=E.current[b];z&&z.instanceId===p&&(z.callback(L,f),delete E.current[b]);return}if(h==="mark-registered"){const{requestType:b}=a.data;S.current[p]||(S.current[p]=new Set),S.current[p].add(b);return}h==="ready"&&W(b=>({...b,[p]:!0})),u((t=M[p])==null?void 0:t[h],a.data,_),u((s=M["*"])==null?void 0:s[h],a.data,_),u((n=M[p])==null?void 0:n["*"],a.data,_),u((c=M["*"])==null?void 0:c["*"],a.data,_)};return window.addEventListener("message",l),()=>{window.removeEventListener("message",l)}},[$]);const y=e.useCallback((u,l,a,p)=>{var g,m;const h=$[u];if(!h){console.warn(`Origin not set for id: ${u}. Unable to send message.`);return}(m=(g=h==null?void 0:h.frameRef)==null?void 0:g.current)!=null&&m.contentWindow&&h.frameRef.current.contentWindow.postMessage({type:l,...a,instanceId:u},p||h.origin)},[$]),P=e.useRef(0),U=e.useCallback(()=>`${Date.now()}-${++P.current}`,[]),F=e.useCallback(async(u,l,a={})=>new Promise((p,h)=>{const g=U(),m=(_,M)=>{delete E.current[g],M?h(M):p(_)};E.current[g]={instanceId:u,callback:m},y(u,"request",{callbackId:g,requestType:l,data:a})}),[y]),A=e.useCallback((u,l)=>{y(u,"load-options",l)},[y]),T=e.useCallback((u,l)=>{y(u,"validate",l)},[y]),v=e.useMemo(()=>({registerFrame:w,unregisterFrame:x,sendMessage:y,sendRequest:F,loadOptions:A,validate:T,hasHandler:B,readyFrames:D,ready:R,addListener:(u,l,a)=>(I.current[u]||(I.current[u]={}),I.current[u][l]||(I.current[u][l]=[]),I.current[u][l].push(a),()=>{I.current[u][l]=I.current[u][l].filter(p=>p!==a)})}),[w,x,y,F,A,T,B,D,R]);return O.default.createElement(Q.Provider,{value:v},O.default.createElement(ce,{launcher:o,broker:i},r))},H=(r,o,i)=>{const d=e.useContext(Q);if(d===null)throw new Error("useEmbeddedEffect must be used within a MMEmbeddableZoneProvider");const R=e.useRef(i);e.useEffect(()=>{R.current=i},[i]),e.useEffect(()=>{if(!(!r||!o)){if(o.startsWith("key:")){const C=o.substring(4);return d.readyFrames[r]&&d.sendMessage(r,"subscribe-key",{keyChord:C}),d.addListener(r,`key-pressed:${C}`,(...q)=>R.current(...q))}return d.addListener(r,o,(...C)=>R.current(...C))}},[d,r,o])};de.propTypes={children:k.default.node.isRequired,ready:k.default.bool.isRequired,authorizationLauncher:k.default.func,credentialBroker:k.default.func};const ee=te.default.default||te.default,we=1e4,Te="credentials",_e=(r,o)=>`${r}/mm-embedded-interop?id=${encodeURIComponent(o)}&origin=${encodeURIComponent(window.location.origin)}&caps=${Te}`,Ie=ee.iframe`
|
|
2
2
|
width: 100%;
|
|
3
3
|
height: 100%;
|
|
4
4
|
border: none;
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
text-align: center;
|
|
17
17
|
color: #555;
|
|
18
18
|
font-size: 14px;
|
|
19
|
-
`,fe=r=>{const o=r&&r.origin||"This app",i=r&&r.reason||"";switch(i){case"broker:scope_above_ceiling":return{title:`${o} can’t be authorized here`,detail:"It asks for permissions your role doesn’t have."};case"broker:origin_mismatch":case"broker:unknown_client":return{title:`${o} can’t be authorized here`,detail:"It isn’t registered to run at this address."};case"broker:cross_company_principal":return{title:`${o} can’t be authorized here`,detail:"It can’t be authorized for this account."};default:return i.startsWith("broker:")?{title:`${o} can’t be authorized here`,detail:"Authorization was refused."}:{title:`${o} can’t be embedded here`,detail:"It needs an update to support embedding from a different domain."}}},pe=({entry:r})=>{const o=fe(r);return O.default.createElement(Me,{"data-reason":r&&r.reason||void 0},O.default.createElement("div",{style:{fontWeight:600}},o.title),O.default.createElement("div",{style:{fontSize:12,color:"#888"}},o.detail))};pe.propTypes={entry:
|
|
19
|
+
`,fe=r=>{const o=r&&r.origin||"This app",i=r&&r.reason||"";switch(i){case"broker:scope_above_ceiling":return{title:`${o} can’t be authorized here`,detail:"It asks for permissions your role doesn’t have."};case"broker:origin_mismatch":case"broker:unknown_client":return{title:`${o} can’t be authorized here`,detail:"It isn’t registered to run at this address."};case"broker:cross_company_principal":return{title:`${o} can’t be authorized here`,detail:"It can’t be authorized for this account."};default:return i.startsWith("broker:")?{title:`${o} can’t be authorized here`,detail:"Authorization was refused."}:{title:`${o} can’t be embedded here`,detail:"It needs an update to support embedding from a different domain."}}},pe=({entry:r})=>{const o=fe(r);return O.default.createElement(Me,{"data-reason":r&&r.reason||void 0},O.default.createElement("div",{style:{fontWeight:600}},o.title),O.default.createElement("div",{style:{fontSize:12,color:"#888"}},o.detail))};pe.propTypes={entry:k.default.shape({origin:k.default.string,name:k.default.string,reason:k.default.string,detail:k.default.object})};const ye=ee.div`
|
|
20
20
|
height: 100%;
|
|
21
21
|
display: flex;
|
|
22
22
|
flex: 1;
|
|
23
23
|
align-items: center;
|
|
24
24
|
justify-content: center;
|
|
25
|
-
`,Se=()=>O.default.createElement(ye,null,O.default.createElement("div",{style:{textAlign:"center"}},"This app couldn’t be loaded as an embeddable widget.")),be=({id:r,src:o,path:i,onInit:
|
|
25
|
+
`,Se=()=>O.default.createElement(ye,null,O.default.createElement("div",{style:{textAlign:"center"}},"This app couldn’t be loaded as an embeddable widget.")),be=({id:r,src:o,path:i,onInit:d=()=>{},onTimeout:R,context:C={},params:$={},renderUnsupported:q,renderTimeout:D,...W})=>{if("isConfiguring"in W)return console.error("isConfiguring must be passed via the params prop to MMEmbeddableZone"),null;if("colorMode"in C)return console.error("colorMode must be passed via the params prop to MMEmbeddableZone"),null;if("isFullScreen"in C)return console.error("isFullScreen must be passed via the params prop to MMEmbeddableZone"),null;const I=e.useRef(),E=G(o),[S,B]=e.useState(),[w,x]=e.useState(0),[y,P]=e.useState(!1),[U,F]=e.useState(!1),A=ie(o),T=ae(o),v=le(o),[u,l]=e.useState(0),[a,p]=e.useState(null),{registerFrame:h,unregisterFrame:g,sendMessage:m,ready:_}=e.useContext(Q),[M,K]=e.useState(),Z=e.useRef(),j=e.useRef(R),t=e.useRef(d),s=e.useRef(!1),n=e.useRef(),c=e.useCallback(()=>{s.current=!1,clearTimeout(Z.current),clearTimeout(n.current),x(0),P(!1),F(!1),p(null)},[]);e.useEffect(()=>{(A>0||u>0)&&c()},[A,u,c]),e.useEffect(()=>{j.current=R},[R]),e.useEffect(()=>{t.current=d},[d]),e.useEffect(()=>{w&&m(r,"set-context",{context:{...C}},E)},[C,r,w,E]),e.useEffect(()=>{w&&m(r,"set-params",{params:$},E)},[$,r,w,E]),e.useEffect(()=>{i!==void 0&&K((i==null?void 0:i.indexOf("/"))===0?i:`/${i}`)},[i]),e.useEffect(()=>{M===void 0||!w||m(r,"navigate",{path:M},E)},[M,w,r,m,E]),e.useEffect(()=>{if(!o||!r||!I)return;if(!_){c(),B(void 0);return}c();const f=new URL(o);return h(r,f.origin,I),t.current(),B(_e(f.origin,r)),()=>{g(r)}},[o,r,_,h,I,c]),e.useEffect(()=>{if(!(!S||s.current))return Z.current=setTimeout(()=>{P(!0),j.current&&j.current()},we),()=>clearTimeout(Z.current)},[S,o,A,u]);const b=e.useCallback(()=>{s.current=!0,clearTimeout(Z.current),P(!1)},[]);if(H(r,"init",f=>{b(),Array.isArray(f==null?void 0:f.acceptsCredentials)&&p(f.acceptsCredentials)}),H(r,"authorize",b),H(r,"login",b),H(r,"credential-request",()=>{b(),F(!0)}),e.useEffect(()=>{if(!U||!T)return;const f=a;if(Array.isArray(f)&&!f.includes(T.kind))return;const z=T.kind==="access_token"?{accessToken:T.accessToken}:{};m(r,"credential",{...z,credential:T},E)},[U,T,a,r,m,E]),H(r,"ready",()=>{b(),x(f=>f+1)}),H(r,"heartbeat",()=>{n.current&&clearTimeout(n.current),n.current=setTimeout(()=>{l(f=>f+1)},6e3)}),e.useEffect(()=>()=>{n.current&&clearTimeout(n.current)},[]),v)return q?q(v):O.default.createElement(pe,{entry:v});if(y&&!w)return D?D():O.default.createElement(Se,null);const L={...W};return delete L.skipManifestCheck,O.default.createElement(Ie,{key:`auth-epoch-${A}-frame-${u}`,$isReady:w,ref:I,src:S,...L})};be.propTypes={id:k.default.string,src:k.default.string.isRequired,path:k.default.string,onInit:k.default.func,onTimeout:k.default.func,renderUnsupported:k.default.func,renderTimeout:k.default.func};exports.CREDENTIAL_KIND_ACCESS_TOKEN=oe;exports.EmbeddedAuthorizationContext=Y;exports.MMEmbeddableZone=be;exports.MMEmbeddableZoneContext=Q;exports.MMEmbeddableZoneProvider=de;exports.isCrossSite=N;exports.normalizeCredential=J;exports.popupAuthorizationLauncher=ue;exports.unsupportedCopy=fe;exports.useEmbeddedAuthorizations=Ce;exports.useEmbeddedCredential=ae;exports.useEmbeddedEffect=H;exports.useEmbeddedOriginEpoch=ie;exports.useEmbeddedUnsupported=le;
|