@hakit/core
Version:
A collection of React hooks and helpers for Home Assistant to easily communicate with the Home Assistant WebSocket API.
3 lines (2 loc) • 9.84 kB
JavaScript
;const Se=require("react/jsx-runtime"),a=require("react"),Ce=require("@emotion/cache"),M=require("@emotion/utils"),pe=require("@emotion/serialize"),Re=require("react-is"),f=require("home-assistant-js-websocket"),$=require("lodash"),A=require("./cjs/HassConnect/token-storage.js"),Te=require("use-debounce"),i=require("./cjs/HassConnect/HassContext.js");function ee(r){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(r){for(const s in r)if(s!=="default"){const n=Object.getOwnPropertyDescriptor(r,s);Object.defineProperty(t,s,n.get?n:{enumerable:!0,get:()=>r[s]})}}return t.default=r,Object.freeze(t)}const x=ee(Se),T=ee(a);var F,Z;function me(){if(Z)return F;Z=1;var r=Re,t={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},s={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},n={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},c={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},d={};d[r.ForwardRef]=n,d[r.Memo]=c;function o(S){return r.isMemo(S)?c:d[S.$$typeof]||t}var g=Object.defineProperty,v=Object.getOwnPropertyNames,E=Object.getOwnPropertySymbols,C=Object.getOwnPropertyDescriptor,m=Object.getPrototypeOf,u=Object.prototype;function N(S,p,_){if(typeof p!="string"){if(u){var H=m(p);H&&H!==u&&N(S,H,_)}var y=v(p);E&&(y=y.concat(E(p)));for(var L=o(S),w=o(p),b=0;b<y.length;++b){var R=y[b];if(!s[R]&&!(_&&_[R])&&!(w&&w[R])&&!(L&&L[R])){var I=C(p,R);try{g(S,R,I)}catch{}}}}return S}return F=N,F}me();var _e=function(t){return t()},be=T.useInsertionEffect?T.useInsertionEffect:!1,Oe=be||_e,te=T.createContext(typeof HTMLElement<"u"?Ce({key:"css"}):null);te.Provider;var Ne=function(t){return a.forwardRef(function(s,n){var c=a.useContext(te);return t(s,c,n)})},we=T.createContext({}),D={}.hasOwnProperty,z="__EMOTION_TYPE_PLEASE_DO_NOT_USE__",re=function(t,s){var n={};for(var c in s)D.call(s,c)&&(n[c]=s[c]);return n[z]=t,n},Pe=function(t){var s=t.cache,n=t.serialized,c=t.isStringTag;return M.registerStyles(s,n,c),Oe(function(){return M.insertStyles(s,n,c)}),null},Ae=Ne(function(r,t,s){var n=r.css;typeof n=="string"&&t.registered[n]!==void 0&&(n=t.registered[n]);var c=r[z],d=[n],o="";typeof r.className=="string"?o=M.getRegisteredStyles(t.registered,d,r.className):r.className!=null&&(o=r.className+" ");var g=pe.serializeStyles(d,void 0,T.useContext(we));o+=t.key+"-"+g.name;var v={};for(var E in r)D.call(r,E)&&E!=="css"&&E!==z&&(v[E]=r[E]);return v.className=o,s&&(v.ref=s),T.createElement(T.Fragment,null,T.createElement(Pe,{cache:t,serialized:g,isStringTag:typeof c=="string"}),T.createElement(c,v))}),ne=Ae,He=x.Fragment,W=function(t,s,n){return D.call(s,"css")?x.jsx(ne,re(t,s),n):x.jsx(t,s,n)},se=function(t,s,n){return D.call(s,"css")?x.jsxs(ne,re(t,s),n):x.jsxs(t,s,n)};function k(r,t){const n=(()=>{switch(r){case f.ERR_INVALID_AUTH:return`ERR_INVALID_AUTH: Invalid authentication. ${t?'Check your "Long-Lived Access Token".':""}`;case f.ERR_CANNOT_CONNECT:return"ERR_CANNOT_CONNECT: Unable to connect";case f.ERR_CONNECTION_LOST:return"ERR_CONNECTION_LOST: Lost connection to home assistant.";case f.ERR_HASS_HOST_REQUIRED:return"ERR_HASS_HOST_REQUIRED: Please enter a Home Assistant URL.";case f.ERR_INVALID_HTTPS_TO_HTTP:return'ERR_INVALID_HTTPS_TO_HTTP: Cannot connect to Home Assistant instances over "http://".';default:return null}})();return n!==null?n:r?.error||r?.message||`Unknown Error (${r})`}function oe(){try{return window.top?.hassConnection}catch(r){console.error("Error getting inherited connection",r);return}}function Ie(r,t){const s=location&&location.search.includes("auth_callback=1"),n=!!oe(),c=!!t,d=!!A.loadTokens(r,!1);switch(!0){case s:return"auth-callback";case n:return"inherited-auth";case c:return"provided-token";case d:return"saved-tokens";default:return"user-request"}}const ae=async(r,t)=>{const s=Ie(r,t);if(s==="inherited-auth")try{const{auth:o,conn:g}=await oe();return{type:"success",connection:g,auth:o}}catch(o){return{type:"error",error:k(o,t)}}if(s==="provided-token"&&t)try{const o=await f.createLongLivedTokenAuth(r,t);return{type:"success",connection:await f.createConnection({auth:o}),auth:o}}catch(o){return{type:"error",error:k(o,t)}}const n={saveTokens:A.saveTokens,loadTokens:()=>Promise.resolve(A.loadTokens(r))};if(r&&s==="user-request"){if(n.hassUrl=r,n.hassUrl==="")return{type:"error",error:"Please enter a Home Assistant URL."};if(n.hassUrl.indexOf("://")===-1)return{type:"error",error:"Please enter your full URL, including the protocol part (https://)."};try{new URL(n.hassUrl)}catch(o){return console.error("Error:",o),{type:"error",error:"Invalid URL"}}}let c;try{c=await f.getAuth(n)}catch(o){return o?.error==="invalid_grant"?(A.clearTokens(),ae(r,t)):s==="saved-tokens"&&o===f.ERR_CANNOT_CONNECT?{type:"failed",cannotConnect:!0}:{type:"error",error:k(o,t)}}finally{location&&location.search.includes("auth_callback=1")&&history.replaceState(null,"",location.pathname)}let d;try{d=await f.createConnection({auth:c})}catch(o){if(s==="saved-tokens"){if(o===f.ERR_CANNOT_CONNECT)return{type:"failed",cannotConnect:!0};o===f.ERR_INVALID_AUTH&&A.saveTokens(null)}return{type:"error",error:k(o,t)}}return{type:"success",connection:d,auth:c}};function je({children:r,hassUrl:t,hassToken:s,portalRoot:n,windowContext:c}){const d=a.useRef(null),o=a.useRef(!1),g=a.useRef(null),v=i.useStore(e=>e.setHash),E=i.useStore(e=>e.hash),C=i.useStore(e=>e.routes),m=i.useStore(e=>e.setRoutes),u=i.useStore(e=>e.connection),N=i.useStore(e=>e.setConnection),S=a.useRef(null),p=i.useStore(e=>e.entities),_=i.useStore(e=>e.setEntities),H=i.useStore(e=>e.error),y=i.useStore(e=>e.setError),L=i.useStore(e=>e.cannotConnect),w=i.useStore(e=>e.setCannotConnect),b=i.useStore(e=>e.setAuth),R=i.useStore(e=>e.triggerOnDisconnect),I=i.useStore(e=>e.ready),j=i.useStore(e=>e.setUser),V=i.useStore(e=>e.setReady),U=i.useStore(e=>e.setConfig),J=i.useStore(e=>e.setHassUrl),Q=i.useStore(e=>e.setPortalRoot),X=i.useStore(e=>e.setWindowContext),ce=a.useCallback(async()=>u===null?null:await f.getStates(u),[u]),ie=a.useCallback(async()=>u===null?null:await f.getServices(u),[u]),ue=a.useCallback(async()=>u===null?null:await f.getConfig(u),[u]),le=a.useCallback(async()=>u===null?null:await f.getUser(u),[u]);a.useEffect(()=>{n&&Q(n)},[n,Q]),a.useEffect(()=>{c&&X(c)},[c,X]);const O=a.useCallback(()=>{b(null),N(null),S.current=null,_({}),U(null),y(null),w(!1),V(!1),m([]),j(null),o.current=!1,g.current&&(g.current(),g.current=null),d.current&&(d.current(),d.current=null)},[b,j,w,U,N,_,y,V,m]),Y=a.useCallback(async()=>{try{O(),A.clearTokens(),location&&location.reload()}catch(e){console.error("Error:",e),y("Unable to log out!")}},[O,y]),B=a.useCallback(async()=>{const e=await ae(t,s);e.type==="error"?(o.current=!1,y(e.error)):e.type==="failed"?(o.current=!1,w(!0)):e.type==="success"&&(b(e.auth),N(e.connection),d.current=f.subscribeEntities(e.connection,l=>{_(l)}),g.current=f.subscribeConfig(e.connection,l=>{U(l)}),e.connection.addEventListener("disconnected",()=>{console.error("Disconnected from Home Assistant, reconnecting..."),R(),O(),B()}),e.connection.addEventListener("reconnect-error",(l,h)=>{console.error("Reconnection error:",h),O()}),S.current=e.connection,f.getUser(e.connection).then(l=>{j(l)}))},[t,s,R,y,j,w,b,N,_,U,O]);a.useEffect(()=>{J(t)},[t,J]);const fe=a.useCallback(e=>new URL(e,u?.options.auth?.data.hassUrl).toString(),[u]);async function de(e,l){try{const h=await fetch(`${t}/api${e}`,{method:"GET",...l??{},headers:{Authorization:"Bearer "+u?.options.auth?.accessToken,"Content-type":"application/json;charset=UTF-8",...l?.headers??{}}});return h.status===200?{status:"success",data:await h.json()}:{status:"error",data:h.statusText}}catch(h){return console.error("API Error:",h),{status:"error",data:`API Request failed for endpoint "${e}", follow instructions here: https://shannonhochkins.github.io/ha-component-kit/?path=/docs/core-hooks-usehass-hass-callapi--docs.`}}}a.useEffect(()=>{location.hash!==""&&location.hash.replace("#","")!==E&&v(location.hash)},[v,E]),a.useEffect(()=>{function e(){m(C.map(l=>l.hash===location.hash.replace("#","")?{...l,active:!0}:{...l,active:!1})),v(location.hash)}return window.addEventListener("hashchange",e),()=>{window.removeEventListener("hashchange",e)}},[C,v,m]);const he=a.useCallback(e=>{if(!(C.find(h=>h.hash===e.hash)!==void 0)&&typeof window<"u"){const h=window.location.hash.replace("#",""),P=h!==""&&h===e.hash;m([...C,{...e,active:P}])}},[C,m]),ge=a.useCallback(e=>C.find(h=>h.hash===e)||null,[C]),ye=a.useCallback(()=>p,[p]),ve=a.useCallback(async({domain:e,service:l,serviceData:h,target:P,returnResponse:K})=>{const Ee=typeof P=="string"||$.isArray(P)?{entity_id:P}:P;if(typeof l!="string")throw new Error("service must be a string");if(u&&I)try{const q=await f.callService(u,$.snakeCase(e),$.snakeCase(l),h,Ee,K);return K?q:void 0}catch(q){console.log("Error:",q)}},[u,I]);a.useEffect(()=>()=>{O()},[O]);const G=Te.useDebouncedCallback(async()=>{try{o.current&&O(),o.current=!0,await B()}catch(e){const l=k(e);y(`Unable to connect to Home Assistant, please check the URL: "${l}"`)}},25,{leading:!0,trailing:!1});return a.useEffect(()=>{G()},[G]),L?se("p",{children:["Unable to connect to $",A.loadTokens(t).hassUrl,", refresh the page and try again, or ",W("a",{onClick:Y,children:"Logout"}),"."]}):W(i.HassContext.Provider,{value:{useStore:i.useStore,logout:Y,addRoute:he,getRoute:ge,getStates:ce,getServices:ie,getConfig:ue,getUser:le,callApi:de,getAllEntities:ye,callService:ve,joinHassUrl:fe},children:H===null?r(I):H})}exports.Fragment=He;exports.HassProvider=je;exports.jsx=W;exports.jsxs=se;
//# sourceMappingURL=Provider-CYRAeT2G.cjs.map