@quiltt/core 3.5.4 → 3.5.6
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/CHANGELOG.md +30 -10
- package/README.md +1 -1
- package/dist/SubscriptionLink-client-VkkcO2Yz.js +300 -0
- package/dist/index-client-D55-rzVl.js +561 -0
- package/dist/index.d.ts +402 -15
- package/dist/index.js +284 -11
- package/package.json +18 -19
- package/src/api/graphql/links/BatchHttpLink.ts +4 -2
- package/src/api/graphql/links/HttpLink.ts +4 -2
- package/src/api/graphql/links/actioncable/logger.ts +3 -1
- package/src/api/graphql/links/actioncable/subscription_guarantor.ts +1 -1
- package/src/api/rest/{AuthAPI.ts → auth.ts} +39 -26
- package/src/api/rest/fetchWithRetry.ts +73 -0
- package/src/api/rest/index.ts +1 -1
- package/dist/Storage/index.cjs +0 -10
- package/dist/Storage/index.cjs.map +0 -1
- package/dist/Storage/index.d.ts +0 -2
- package/dist/Storage/index.js +0 -5
- package/dist/Storage/index.js.map +0 -1
- package/dist/api/graphql/index.cjs +0 -49
- package/dist/api/graphql/index.cjs.map +0 -1
- package/dist/api/graphql/index.d.ts +0 -16
- package/dist/api/graphql/index.js +0 -15
- package/dist/api/graphql/index.js.map +0 -1
- package/dist/api/graphql/links/actioncable/index.cjs +0 -18
- package/dist/api/graphql/links/actioncable/index.cjs.map +0 -1
- package/dist/api/graphql/links/actioncable/index.d.ts +0 -62
- package/dist/api/graphql/links/actioncable/index.js +0 -5
- package/dist/api/graphql/links/actioncable/index.js.map +0 -1
- package/dist/api/graphql/links/index.cjs +0 -28
- package/dist/api/graphql/links/index.cjs.map +0 -1
- package/dist/api/graphql/links/index.d.ts +0 -56
- package/dist/api/graphql/links/index.js +0 -14
- package/dist/api/graphql/links/index.js.map +0 -1
- package/dist/api/index.cjs +0 -54
- package/dist/api/index.cjs.map +0 -1
- package/dist/api/index.d.ts +0 -78
- package/dist/api/index.js +0 -16
- package/dist/api/index.js.map +0 -1
- package/dist/api/rest/index.cjs +0 -14
- package/dist/api/rest/index.cjs.map +0 -1
- package/dist/api/rest/index.d.ts +0 -70
- package/dist/api/rest/index.js +0 -7
- package/dist/api/rest/index.js.map +0 -1
- package/dist/consumer-c13efb94.d.ts +0 -78
- package/dist/index-f53b61b3.d.ts +0 -129
- package/dist/index.cjs +0 -67
- package/dist/index.cjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/src/api/rest/axios.ts +0 -52
package/dist/index.js
CHANGED
|
@@ -1,16 +1,289 @@
|
|
|
1
|
+
import { G as GlobalStorage, e as endpointGraphQL, v as version, d as debugging, S as SubscriptionLink, a as endpointAuth } from './SubscriptionLink-client-VkkcO2Yz.js';
|
|
2
|
+
export { L as LocalStorage, M as MemoryStorage, O as Observable, f as Storage, c as cdnBase, b as endpointWebsockets } from './SubscriptionLink-client-VkkcO2Yz.js';
|
|
1
3
|
import { ApolloLink, ApolloClient } from '@apollo/client/index.js';
|
|
2
4
|
export { InMemoryCache, gql, useMutation, useQuery, useSubscription } from '@apollo/client/index.js';
|
|
3
|
-
import { BatchHttpLink } from '@apollo/client/link/batch-http/index.js';
|
|
4
|
-
import
|
|
5
|
+
import { BatchHttpLink as BatchHttpLink$1 } from '@apollo/client/link/batch-http/index.js';
|
|
6
|
+
import crossfetch from 'cross-fetch';
|
|
5
7
|
import { onError } from '@apollo/client/link/error/index.js';
|
|
6
|
-
import { HttpLink } from '@apollo/client/link/http/index.js';
|
|
7
|
-
import { RetryLink } from '@apollo/client/link/retry/index.js';
|
|
8
|
-
import { ApolloLink as ApolloLink$1, Observable } from '@apollo/client/core/index.js';
|
|
9
|
-
import { print } from 'graphql';
|
|
10
|
-
import zt from 'axios';
|
|
8
|
+
import { HttpLink as HttpLink$1 } from '@apollo/client/link/http/index.js';
|
|
9
|
+
import { RetryLink as RetryLink$1 } from '@apollo/client/link/retry/index.js';
|
|
11
10
|
|
|
12
|
-
var vt=Object.defineProperty,St=Object.defineProperties;var xt=Object.getOwnPropertyDescriptors;var H=Object.getOwnPropertySymbols;var yt=Object.prototype.hasOwnProperty,Ct=Object.prototype.propertyIsEnumerable;var P=(o,t,e)=>t in o?vt(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e,l=(o,t)=>{for(var e in t||(t={}))yt.call(t,e)&&P(o,e,t[e]);if(H)for(var e of H(t))Ct.call(t,e)&&P(o,e,t[e]);return o},k=(o,t)=>St(o,xt(t));var n=(o,t,e)=>(P(o,typeof t!="symbol"?t+"":t,e),e);var B="@quiltt/core",z="3.5.4";var kt=(()=>{try{return process.env.QUILTT_API_INSECURE}catch(o){return}})(),V=(()=>{try{return process.env.QUILTT_API_DOMAIN}catch(o){return}})(),Tt=(()=>{try{return !!process.env.QUILTT_DEBUG||process.env.NODE_ENV!=="production"}catch(o){return !1}})(),T=V||"quiltt.io",M=`http${kt?"":"s"}`,At=`ws${V?"":"s"}`,A=Tt,F=`${B}: v${z}`,te=`${M}://cdn.${T}`,f=`${M}://auth.${T}/v1/users/session`,D=`${M}://api.${T}/v1/graphql`,Y=`${At}://api.${T}/websockets`;var Dt=/^(?:[\w-]+\.){2}[\w-]+$/,oe=o=>{if(typeof o=="undefined"||o===null)return o;if(!Dt.test(o)){console.error(`Invalid Session Token: ${o}`);return}let[t,e,r]=o.split(".");try{return {token:o,claims:JSON.parse(atob(e))}}catch(i){console.error(`Invalid Session Token: ${i}`);}};var g=class{constructor(t){n(this,"state");n(this,"observers",[]);n(this,"get",()=>this.state);n(this,"set",t=>{this.state!==t&&(this.state=t,this.observers.forEach(e=>e(t)));});n(this,"subscribe",t=>{this.observers.push(t);});n(this,"unsubscribe",t=>{this.observers=this.observers.filter(e=>e!==t);});this.state=t;}};var O=class{constructor(){n(this,"observers",{});n(this,"isEnabled",()=>{try{return localStorage.setItem("quiltt.ping","pong"),localStorage.removeItem("quiltt.ping"),!0}catch(t){return !1}});n(this,"isDisabled",()=>!this.isEnabled());n(this,"get",t=>{if(!(typeof window=="undefined"||window.expo))try{let e=window.localStorage.getItem(`quiltt.${t}`);return e&&JSON.parse(e)}catch(e){console.warn(`localStorage Error: "quiltt.${t}"`,e);return}});n(this,"set",(t,e)=>{if(!(typeof window=="undefined"||window.expo))try{e?window.localStorage.setItem(`quiltt.${t}`,JSON.stringify(e)):window.localStorage.removeItem(`quiltt.${t}`);}catch(r){console.warn(`localStorage Error: "quiltt.${t}"`,r);}});n(this,"remove",t=>{try{window.localStorage.removeItem(`quiltt.${t}`);}catch(e){console.warn(`localStorage Error: "quiltt.${t}">`,e);}});n(this,"subscribe",(t,e)=>{this.observers[t]||(this.observers[t]=[]),this.observers[t].push(e);});n(this,"unsubscribe",(t,e)=>{var r;this.observers[t]=(r=this.observers[t])==null?void 0:r.filter(i=>i!==e);});n(this,"handleStorageEvent",t=>{if(t.key&&t.key.includes("quiltt.")){let e=t.newValue?JSON.parse(t.newValue):null;this.observers[t.key]&&this.observers[t.key].forEach(r=>r(e));}else Object.entries(this.observers).forEach(([e,r])=>{r.forEach(i=>i(this.get(e)));});});typeof window!="undefined"&&!(window!=null&&window.expo)&&window.addEventListener("storage",this.handleStorageEvent.bind(this));}};var w=class{constructor(){n(this,"observables",{});n(this,"get",t=>{if(this.observables[t])return this.observables[t].get()});n(this,"set",(t,e)=>{this.observables[t]?this.observables[t].set(e):this.observables[t]=new g(e);});n(this,"subscribe",(t,e)=>{this.observables[t]||(this.observables[t]=new g),this.observables[t].subscribe(e);});n(this,"unsubscribe",(t,e)=>{this.observables[t]&&this.observables[t].unsubscribe(e);});}};var $=class{constructor(){n(this,"memoryStore",new w);n(this,"localStore",new O);n(this,"observers",{});n(this,"monitors",new Set);n(this,"get",t=>{this.monitorLocalStorageChanges(t);let e=this.memoryStore.get(t);return e===void 0&&(e=this.localStore.get(t)),e});n(this,"set",(t,e)=>{var r;this.monitorLocalStorageChanges(t),this.localStore.set(t,e),this.memoryStore.set(t,e),(r=this.observers[t])==null||r.forEach(i=>i(e));});n(this,"subscribe",(t,e)=>{this.observers[t]||(this.observers[t]=[]),this.observers[t].push(e);});n(this,"unsubscribe",(t,e)=>{var r;this.observers[t]=(r=this.observers[t])==null?void 0:r.filter(i=>i!==e);});n(this,"monitorLocalStorageChanges",t=>{this.monitors.has(t)||(this.monitors.add(t),this.localStore.subscribe(t,e=>{var c;let r=this.memoryStore.get(t),i=e instanceof Function?e(r):e;this.memoryStore.set(t,i),(c=this.observers[t])==null||c.forEach(p=>p(i));}));});}},m=new $;var X=class{constructor(){n(this,"timeout");n(this,"observers",[]);n(this,"set",(t,e)=>{this.timeout&&clearTimeout(this.timeout),this.observers.push(t),this.timeout=setTimeout(this.broadcast.bind(this),e);});n(this,"clear",t=>{this.observers=this.observers.filter(e=>e!==t);});n(this,"broadcast",()=>{this.observers.length!==0&&this.observers[0](void 0);});}};var Ot=(i=>(i.Load="loaded",i.ExitSuccess="exited.successful",i.ExitAbort="exited.aborted",i.ExitError="exited.errored",i))(Ot||{});var E=class extends ApolloLink{request(t,e){let r=m.get("session");return r?(t.setContext(({headers:i={}})=>({headers:k(l({},i),{authorization:`Bearer ${r}`})})),e(t)):(console.warn("QuilttLink attempted to send an unauthenticated Query"),null)}};var Z=new BatchHttpLink({uri:D,fetch:Rt});var tt=onError(({graphQLErrors:o,networkError:t})=>{o&&o.forEach(({message:e,locations:r,path:i})=>{console.log(`[GraphQL error]: Message: ${e}, Location: ${r}, Path: ${i}`);}),t&&(t.statusCode===401?(console.warn("[Authentication error]:",t),m.set("session",null)):console.warn("[Network error]:",t));});var et=new ApolloLink((o,t)=>t(o));var ot=new HttpLink({uri:D,fetch:Rt});var nt=new RetryLink({attempts:{retryIf:(o,t)=>!!o&&(!o.statusCode||o.statusCode>=500)}});var u={logger:typeof globalThis!="undefined"?globalThis.console:void 0,WebSocket:typeof globalThis!="undefined"?globalThis.WebSocket:void 0};var N=class{constructor(){n(this,"enabled",A);}log(...t){u.logger&&this.enabled&&(t.push(Date.now().toString()),u.logger.log("[ActionCable]",...t));}},Nt=new N,s=Nt;var v=()=>new Date().getTime(),R=o=>(v()-o)/1e3,S=class{constructor(t){this.visibilityDidChange=this.visibilityDidChange.bind(this),this.connection=t,this.reconnectAttempts=0;}start(){this.isRunning()||(this.startedAt=v(),delete this.stoppedAt,this.startPolling(),addEventListener("visibilitychange",this.visibilityDidChange),s.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`));}stop(){this.isRunning()&&(this.stoppedAt=v(),this.stopPolling(),removeEventListener("visibilitychange",this.visibilityDidChange),s.log("ConnectionMonitor stopped"));}isRunning(){return this.startedAt&&!this.stoppedAt}recordPing(){this.pingedAt=v();}recordConnect(){this.reconnectAttempts=0,this.recordPing(),delete this.disconnectedAt,s.log("ConnectionMonitor recorded connect");}recordDisconnect(){this.disconnectedAt=v(),s.log("ConnectionMonitor recorded disconnect");}startPolling(){this.stopPolling(),this.poll();}stopPolling(){clearTimeout(this.pollTimeout);}poll(){this.pollTimeout=setTimeout(()=>{this.reconnectIfStale(),this.poll();},this.getPollInterval());}getPollInterval(){let{staleThreshold:t,reconnectionBackoffRate:e}=this.constructor,r=Math.pow(1+e,Math.min(this.reconnectAttempts,10)),c=(this.reconnectAttempts===0?1:e)*Math.random();return t*1e3*r*(1+c)}reconnectIfStale(){this.connectionIsStale()&&(s.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${R(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`),this.reconnectAttempts++,this.disconnectedRecently()?s.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${R(this.disconnectedAt)} s`):(s.log("ConnectionMonitor reopening"),this.connection.reopen()));}get refreshedAt(){return this.pingedAt?this.pingedAt:this.startedAt}connectionIsStale(){return R(this.refreshedAt)>this.constructor.staleThreshold}disconnectedRecently(){return this.disconnectedAt&&R(this.disconnectedAt)<this.constructor.staleThreshold}visibilityDidChange(){document.visibilityState==="visible"&&setTimeout(()=>{(this.connectionIsStale()||!this.connection.isOpen())&&(s.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`),this.connection.reopen());},200);}};S.staleThreshold=6;S.reconnectionBackoffRate=.15;var rt=S;var qt={message_types:{welcome:"welcome",disconnect:"disconnect",ping:"ping",confirmation:"confirm_subscription",rejection:"reject_subscription"},disconnect_reasons:{unauthorized:"unauthorized",invalid_request:"invalid_request",server_restart:"server_restart",remote:"remote"},default_mount_path:"/cable",protocols:["actioncable-v1-json","actioncable-unsupported"]},L=qt;var{message_types:x,protocols:q}=L,Kt=q.slice(0,q.length-1),it=[].indexOf,y=class{constructor(t){this.open=this.open.bind(this),this.consumer=t,this.subscriptions=this.consumer.subscriptions,this.monitor=new rt(this),this.disconnected=!0;}send(t){return this.isOpen()?(this.webSocket.send(JSON.stringify(t)),!0):!1}open(){if(this.isActive())return s.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`),!1;{let t=[...q,...this.consumer.subprotocols||[]];return s.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${t}`),this.webSocket&&this.uninstallEventHandlers(),this.webSocket=new u.WebSocket(this.consumer.url,t),this.installEventHandlers(),this.monitor.start(),!0}}close({allowReconnect:t}={allowReconnect:!0}){if(t||this.monitor.stop(),this.isOpen())return this.webSocket.close()}reopen(){if(s.log(`Reopening WebSocket, current state is ${this.getState()}`),this.isActive())try{return this.close()}catch(t){s.log("Failed to reopen WebSocket",t);}finally{s.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`),setTimeout(this.open,this.constructor.reopenDelay);}else return this.open()}getProtocol(){if(this.webSocket)return this.webSocket.protocol}isOpen(){return this.isState("open")}isActive(){return this.isState("open","connecting")}triedToReconnect(){return this.monitor.reconnectAttempts>0}isProtocolSupported(){return it.call(Kt,this.getProtocol())>=0}isState(...t){return it.call(t,this.getState())>=0}getState(){if(this.webSocket){for(let t in u.WebSocket)if(u.WebSocket[t]===this.webSocket.readyState)return t.toLowerCase()}return null}installEventHandlers(){for(let t in this.events){let e=this.events[t].bind(this);this.webSocket[`on${t}`]=e;}}uninstallEventHandlers(){for(let t in this.events)this.webSocket[`on${t}`]=function(){};}};y.reopenDelay=500;y.prototype.events={message(o){if(!this.isProtocolSupported())return;let{identifier:t,message:e,reason:r,reconnect:i,type:c}=JSON.parse(o.data);switch(c){case x.welcome:return this.triedToReconnect()&&(this.reconnectAttempted=!0),this.monitor.recordConnect(),this.subscriptions.reload();case x.disconnect:return s.log(`Disconnecting. Reason: ${r}`),this.close({allowReconnect:i});case x.ping:return this.monitor.recordPing();case x.confirmation:return this.subscriptions.confirmSubscription(t),this.reconnectAttempted?(this.reconnectAttempted=!1,this.subscriptions.notify(t,"connected",{reconnected:!0})):this.subscriptions.notify(t,"connected",{reconnected:!1});case x.rejection:return this.subscriptions.reject(t);default:return this.subscriptions.notify(t,"received",e)}},open(){if(s.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`),this.disconnected=!1,!this.isProtocolSupported())return s.log("Protocol is unsupported. Stopping monitor and disconnecting."),this.close({allowReconnect:!1})},close(o){if(s.log("WebSocket onclose event"),!this.disconnected)return this.disconnected=!0,this.monitor.recordDisconnect(),this.subscriptions.notifyAll("disconnected",{willAttemptReconnect:this.monitor.isRunning()})},error(){s.log("WebSocket onerror event");}};var st=y;var jt=function(o,t){if(t!==null)for(let e in t){let r=t[e];o[e]=r;}return o},K=class{constructor(t,e={},r){n(this,"consumer");n(this,"identifier");this.consumer=t,this.identifier=JSON.stringify(e),jt(this,r);}perform(t,e={}){return e.action=t,this.send(e)}send(t){return this.consumer.send({command:"message",identifier:this.identifier,data:JSON.stringify(t)})}unsubscribe(){return this.consumer.subscriptions.remove(this)}},ct=K;var j=class{constructor(t){n(this,"subscriptions");n(this,"pendingSubscriptions");n(this,"retryTimeout");this.subscriptions=t,this.pendingSubscriptions=[];}guarantee(t){this.pendingSubscriptions.indexOf(t)==-1?(s.log(`SubscriptionGuarantor guaranteeing ${t.identifier}`),this.pendingSubscriptions.push(t)):s.log(`SubscriptionGuarantor already guaranteeing ${t.identifier}`),this.startGuaranteeing();}forget(t){s.log(`SubscriptionGuarantor forgetting ${t.identifier}`),this.pendingSubscriptions=this.pendingSubscriptions.filter(e=>e!==t);}startGuaranteeing(){this.stopGuaranteeing(),this.retrySubscribing();}stopGuaranteeing(){clearTimeout(this.retryTimeout);}retrySubscribing(){this.retryTimeout=setTimeout(()=>{this.subscriptions&&typeof this.subscriptions.subscribe=="function"&&this.pendingSubscriptions.map(t=>{s.log(`SubscriptionGuarantor resubscribing ${t.identifier}`),this.subscriptions.subscribe(t);});},500);}},at=j;var _=class{constructor(t){n(this,"consumer");n(this,"guarantor");n(this,"subscriptions");this.consumer=t,this.guarantor=new at(this),this.subscriptions=[];}create(t,e){let r=t,i=typeof r=="object"?r:{channel:r},c=new ct(this.consumer,i,e);return this.add(c)}add(t){return this.subscriptions.push(t),this.consumer.ensureActiveConnection(),this.notify(t,"initialized"),this.subscribe(t),t}remove(t){return this.forget(t),this.findAll(t.identifier).length||this.sendCommand(t,"unsubscribe"),t}reject(t){return this.findAll(t).map(e=>(this.forget(e),this.notify(e,"rejected"),e))}forget(t){return this.guarantor.forget(t),this.subscriptions=this.subscriptions.filter(e=>e!==t),t}findAll(t){return this.subscriptions.filter(e=>e.identifier===t)}reload(){return this.subscriptions.map(t=>this.subscribe(t))}notifyAll(t,...e){return this.subscriptions.map(r=>this.notify(r,t,...e))}notify(t,e,...r){let i;return typeof t=="string"?i=this.findAll(t):i=[t],i.map(c=>typeof c[e]=="function"?c[e](...r):void 0)}subscribe(t){this.sendCommand(t,"subscribe")&&this.guarantor.guarantee(t);}confirmSubscription(t){s.log(`Subscription confirmed ${t}`),this.findAll(t).map(e=>this.guarantor.forget(e));}sendCommand(t,e){let{identifier:r}=t;return this.consumer.send({command:e,identifier:r})}},lt=_;var G=class{constructor(t){n(this,"_url");n(this,"subscriptions");n(this,"connection");n(this,"subprotocols");this._url=t,this.subscriptions=new lt(this),this.connection=new st(this),this.subprotocols=[];}get url(){return pt(this._url)}send(t){return this.connection.send(t)}connect(){return this.connection.open()}disconnect(){return this.connection.close({allowReconnect:!1})}ensureActiveConnection(){if(!this.connection.isActive())return this.connection.open()}addSubProtocol(t){this.subprotocols=[...this.subprotocols,t];}};function pt(o){if(typeof o=="function"&&(o=o()),o&&!/^wss?:/i.test(o)){let t=document.createElement("a");return t.href=o,t.href=t.href,t.protocol=t.protocol.replace("http","ws"),t.href}else return o}var ut=G;function dt(o=_t("url")||L.default_mount_path){return new ut(o)}function _t(o){let t=document.head.querySelector(`meta[name='action-cable-${o}']`);if(t)return t.getAttribute("content")}var U=class extends ApolloLink$1{constructor(e){super();n(this,"cables");n(this,"channelName");n(this,"actionName");n(this,"connectionParams");this.cables={},this.channelName=e.channelName||"GraphqlChannel",this.actionName=e.actionName||"execute",this.connectionParams=e.connectionParams||{};}request(e,r){let i=m.get("session");return i?(this.cables[i]||(this.cables[i]=dt(Y+(i?`?token=${i}`:""))),new Observable(c=>{let p=Math.round(Date.now()+Math.random()*1e5).toString(16),b=this.actionName,h=typeof this.connectionParams=="function"?this.connectionParams(e):this.connectionParams,C=this.cables[i].subscriptions.create(Object.assign({},{channel:this.channelName,channelId:p},h),{connected:()=>{C.perform(b,{query:e.query?print(e.query):null,variables:e.variables,operationId:e.operationId,operationName:e.operationName});},received:a=>{var W,Q;((W=a==null?void 0:a.result)!=null&&W.data||(Q=a==null?void 0:a.result)!=null&&Q.errors)&&c.next(a.result),a.more||c.complete();}});return Object.assign(C,{closed:!1})})):(console.warn("QuilttClient attempted to send an unauthenticated Subscription"),null)}},ht=U;var I=class extends ht{constructor(){super({channelName:"GraphQLChannel"});}};var Do=new ApolloLink(()=>null);var mt=new ApolloLink((o,t)=>(o.setContext(({headers:e={}})=>({headers:k(l({},e),{"Quiltt-Client-Version":F})})),t(o)));var bt=class extends ApolloClient{constructor(t){t.connectToDevTools||(t.connectToDevTools=A);let e=b=>b.query.definitions.some(({kind:h,operation:C})=>h==="OperationDefinition"&&C==="subscription"),r=b=>{var h;return (h=b.getContext().batchable)!=null?h:!0},i=new E,c=new I,p=ApolloLink.from([mt,i,tt,nt]).split(e,c,et).split(r,Z,ot);super(l({link:p},t));}};var Vt=150,ft=10,d=zt.create();d.interceptors.response.use(void 0,o=>{let{config:t,message:e,response:r}=o,i=e.toLowerCase();if(!t||!t.retry||!(i.includes("timeout")||i.includes("network error")||(r==null?void 0:r.status)===429))return Promise.reject(o);if(t.retriesRemaining===void 0)t.retriesRemaining=ft-1;else {if(t.retriesRemaining===1)return Promise.reject(o);t.retriesRemaining-=1;}return new Promise(p=>{setTimeout(()=>p(),Vt*(ft-t.retriesRemaining));}).then(()=>d(t))});var Ft=(e=>(e.Email="email",e.Phone="phone",e))(Ft||{}),gt=class{constructor(t){n(this,"clientId");n(this,"ping",t=>d.get(f,this.config(t)));n(this,"identify",t=>d.post(f,this.body(t),this.config()));n(this,"authenticate",t=>d.put(f,this.body(t),this.config()));n(this,"revoke",t=>d.delete(f,this.config(t)));n(this,"config",t=>{let e={"Content-Type":"application/json",Accept:"application/json"};return t&&(e.Authorization=`Bearer ${t}`),{headers:e,validateStatus:this.validateStatus,retry:!0}});n(this,"validateStatus",t=>t<500);n(this,"body",t=>(this.clientId||console.error("Quiltt Client ID is not set. Unable to identify & authenticate"),{session:l({clientId:this.clientId},t)}));this.clientId=t;}};
|
|
11
|
+
const MATCHER = /^(?:[\w-]+\.){2}[\w-]+$/;
|
|
12
|
+
const JsonWebTokenParse = (token)=>{
|
|
13
|
+
if (typeof token === 'undefined' || token === null) return token;
|
|
14
|
+
if (!MATCHER.test(token)) {
|
|
15
|
+
console.error(`Invalid Session Token: ${token}`);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const [_header, payload, _signature] = token.split('.');
|
|
19
|
+
try {
|
|
20
|
+
return {
|
|
21
|
+
token: token,
|
|
22
|
+
claims: JSON.parse(atob(payload))
|
|
23
|
+
};
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(`Invalid Session Token: ${error}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
13
28
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
29
|
+
/**
|
|
30
|
+
* This is designed to support singletons to timeouts that can broadcast
|
|
31
|
+
* to any observers, preventing race conditions with multiple timeouts.
|
|
32
|
+
*/ class Timeoutable {
|
|
33
|
+
constructor(){
|
|
34
|
+
this.observers = [];
|
|
35
|
+
this.set = (callback, delay)=>{
|
|
36
|
+
if (this.timeout) {
|
|
37
|
+
clearTimeout(this.timeout);
|
|
38
|
+
}
|
|
39
|
+
this.observers.push(callback);
|
|
40
|
+
this.timeout = setTimeout(this.broadcast.bind(this), delay);
|
|
41
|
+
};
|
|
42
|
+
this.clear = (observer)=>{
|
|
43
|
+
this.observers = this.observers.filter((callback)=>callback !== observer);
|
|
44
|
+
};
|
|
45
|
+
// Only sends to the 1st listener, but ensures that someone is notified
|
|
46
|
+
this.broadcast = ()=>{
|
|
47
|
+
if (this.observers.length === 0) return;
|
|
48
|
+
this.observers[0](undefined);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
var ConnectorSDKEventType;
|
|
54
|
+
(function(ConnectorSDKEventType) {
|
|
55
|
+
ConnectorSDKEventType["Load"] = "loaded";
|
|
56
|
+
ConnectorSDKEventType["ExitSuccess"] = "exited.successful";
|
|
57
|
+
ConnectorSDKEventType["ExitAbort"] = "exited.aborted";
|
|
58
|
+
ConnectorSDKEventType["ExitError"] = "exited.errored";
|
|
59
|
+
})(ConnectorSDKEventType || (ConnectorSDKEventType = {}));
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* unauthorizedCallback only triggers in the event the token is present, and
|
|
63
|
+
* returns the token; This allows sessions to be forgotten without race conditions
|
|
64
|
+
* causing null sessions to kill valid sessions, or invalid sessions for killing
|
|
65
|
+
* valid sessions during rotation and networking weirdness.
|
|
66
|
+
*/ class AuthLink extends ApolloLink {
|
|
67
|
+
request(operation, forward) {
|
|
68
|
+
const token = GlobalStorage.get('session');
|
|
69
|
+
if (!token) {
|
|
70
|
+
console.warn(`QuilttLink attempted to send an unauthenticated Query`);
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
operation.setContext(({ headers = {} })=>({
|
|
74
|
+
headers: {
|
|
75
|
+
...headers,
|
|
76
|
+
authorization: `Bearer ${token}`
|
|
77
|
+
}
|
|
78
|
+
}));
|
|
79
|
+
return forward(operation);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
84
|
+
const effectiveFetch$2 = typeof fetch === 'undefined' ? crossfetch : fetch;
|
|
85
|
+
const BatchHttpLink = new BatchHttpLink$1({
|
|
86
|
+
uri: endpointGraphQL,
|
|
87
|
+
fetch: effectiveFetch$2
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const ErrorLink = onError(({ graphQLErrors, networkError })=>{
|
|
91
|
+
if (graphQLErrors) {
|
|
92
|
+
graphQLErrors.forEach(({ message, locations, path })=>{
|
|
93
|
+
console.log(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (networkError) {
|
|
97
|
+
if (networkError.statusCode === 401) {
|
|
98
|
+
console.warn('[Authentication error]:', networkError);
|
|
99
|
+
GlobalStorage.set('session', null);
|
|
100
|
+
} else {
|
|
101
|
+
console.warn('[Network error]:', networkError);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const ForwardableLink = new ApolloLink((operation, forward)=>forward(operation));
|
|
107
|
+
|
|
108
|
+
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
109
|
+
const effectiveFetch$1 = typeof fetch === 'undefined' ? crossfetch : fetch;
|
|
110
|
+
const HttpLink = new HttpLink$1({
|
|
111
|
+
uri: endpointGraphQL,
|
|
112
|
+
fetch: effectiveFetch$1
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const RetryLink = new RetryLink$1({
|
|
116
|
+
attempts: {
|
|
117
|
+
retryIf: (error, _operation)=>!!error && (!error.statusCode || error.statusCode >= 500)
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const TerminatingLink = new ApolloLink(()=>null);
|
|
122
|
+
|
|
123
|
+
const VersionLink = new ApolloLink((operation, forward)=>{
|
|
124
|
+
operation.setContext(({ headers = {} })=>({
|
|
125
|
+
headers: {
|
|
126
|
+
...headers,
|
|
127
|
+
'Quiltt-Client-Version': version
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
return forward(operation);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
class QuilttClient extends ApolloClient {
|
|
134
|
+
constructor(options){
|
|
135
|
+
if (!options.connectToDevTools) options.connectToDevTools = debugging;
|
|
136
|
+
const isSubscriptionOperation = (operation)=>{
|
|
137
|
+
return operation.query.definitions.some(// @ts-ignore
|
|
138
|
+
({ kind, operation })=>kind === 'OperationDefinition' && operation === 'subscription');
|
|
139
|
+
};
|
|
140
|
+
const isBatchable = (operation)=>{
|
|
141
|
+
return operation.getContext().batchable ?? true;
|
|
142
|
+
};
|
|
143
|
+
const authLink = new AuthLink();
|
|
144
|
+
const subscriptionsLink = new SubscriptionLink();
|
|
145
|
+
const quilttLink = ApolloLink.from([
|
|
146
|
+
VersionLink,
|
|
147
|
+
authLink,
|
|
148
|
+
ErrorLink,
|
|
149
|
+
RetryLink
|
|
150
|
+
]).split(isSubscriptionOperation, subscriptionsLink, ForwardableLink).split(isBatchable, BatchHttpLink, HttpLink);
|
|
151
|
+
super({
|
|
152
|
+
link: quilttLink,
|
|
153
|
+
...options
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
159
|
+
const effectiveFetch = typeof fetch === 'undefined' ? crossfetch : fetch;
|
|
160
|
+
const RETRY_DELAY = 150 // ms
|
|
161
|
+
;
|
|
162
|
+
const RETRIES = 10 // 150, 300, 450, 600, 750, 900, 1050, 1200, 1350, 1500 = 8.250s
|
|
163
|
+
;
|
|
164
|
+
/**
|
|
165
|
+
* A wrapper around the native `fetch` function that adds automatic retries on failure, including network errors and HTTP 429 responses.
|
|
166
|
+
* Now treats any response with status < 500 as valid.
|
|
167
|
+
*/ const fetchWithRetry = async (url, options = {
|
|
168
|
+
retry: false
|
|
169
|
+
})=>{
|
|
170
|
+
const { retry, retriesRemaining, validateStatus = (status)=>status >= 200 && status < 300, ...fetchOptions } = options;
|
|
171
|
+
try {
|
|
172
|
+
const response = await effectiveFetch(url, fetchOptions);
|
|
173
|
+
const isResponseOk = validateStatus(response.status);
|
|
174
|
+
if (isResponseOk) {
|
|
175
|
+
return {
|
|
176
|
+
data: await response.json().catch(()=>null),
|
|
177
|
+
status: response.status,
|
|
178
|
+
statusText: response.statusText,
|
|
179
|
+
headers: response.headers,
|
|
180
|
+
ok: isResponseOk
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
// If validateStatus fails, and retry is enabled, prepare to retry for eligible status codes
|
|
184
|
+
if (retry && (response.status >= 500 || response.status === 429)) {
|
|
185
|
+
throw new Error('Retryable failure');
|
|
186
|
+
}
|
|
187
|
+
throw new Error('HTTP error with status ' + response.status);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
if (retry) {
|
|
190
|
+
const currentRetriesRemaining = retriesRemaining !== undefined ? retriesRemaining : RETRIES;
|
|
191
|
+
if (currentRetriesRemaining > 0) {
|
|
192
|
+
const delayTime = RETRY_DELAY * (RETRIES - currentRetriesRemaining);
|
|
193
|
+
await new Promise((resolve)=>setTimeout(resolve, delayTime));
|
|
194
|
+
return fetchWithRetry(url, {
|
|
195
|
+
...options,
|
|
196
|
+
retriesRemaining: currentRetriesRemaining - 1
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return Promise.reject(error);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
var AuthStrategies;
|
|
205
|
+
(function(AuthStrategies) {
|
|
206
|
+
AuthStrategies["Email"] = "email";
|
|
207
|
+
AuthStrategies["Phone"] = "phone";
|
|
208
|
+
})(AuthStrategies || (AuthStrategies = {}));
|
|
209
|
+
// https://www.quiltt.dev/api-reference/rest/auth#
|
|
210
|
+
class AuthAPI {
|
|
211
|
+
constructor(clientId){
|
|
212
|
+
/**
|
|
213
|
+
* Response Statuses:
|
|
214
|
+
* - 200: OK -> Session is Valid
|
|
215
|
+
* - 401: Unauthorized -> Session is Invalid
|
|
216
|
+
*/ this.ping = async (token)=>{
|
|
217
|
+
const response = await fetchWithRetry(endpointAuth, {
|
|
218
|
+
method: 'GET',
|
|
219
|
+
...this.config(token)
|
|
220
|
+
});
|
|
221
|
+
return response;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Response Statuses:
|
|
225
|
+
* - 201: Created -> Profile Created, New Session Returned
|
|
226
|
+
* - 202: Accepted -> Profile Found, MFA Code Sent for `authenticate`
|
|
227
|
+
* - 422: Unprocessable Entity -> Invalid Payload
|
|
228
|
+
*/ this.identify = async (payload)=>{
|
|
229
|
+
const response = await fetchWithRetry(endpointAuth, {
|
|
230
|
+
method: 'POST',
|
|
231
|
+
body: JSON.stringify(this.body(payload)),
|
|
232
|
+
...this.config()
|
|
233
|
+
});
|
|
234
|
+
return response;
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* Response Statuses:
|
|
238
|
+
* - 201: Created -> MFA Validated, New Session Returned
|
|
239
|
+
* - 401: Unauthorized -> MFA Invalid
|
|
240
|
+
* - 422: Unprocessable Entity -> Invalid Payload
|
|
241
|
+
*/ this.authenticate = async (payload)=>{
|
|
242
|
+
const response = await fetchWithRetry(endpointAuth, {
|
|
243
|
+
method: 'PUT',
|
|
244
|
+
body: JSON.stringify(this.body(payload)),
|
|
245
|
+
...this.config()
|
|
246
|
+
});
|
|
247
|
+
return response;
|
|
248
|
+
};
|
|
249
|
+
/**
|
|
250
|
+
* Response Statuses:
|
|
251
|
+
* - 204: No Content -> Session Revoked
|
|
252
|
+
* - 401: Unauthorized -> Session Not Found
|
|
253
|
+
*/ this.revoke = async (token)=>{
|
|
254
|
+
const response = await fetchWithRetry(endpointAuth, {
|
|
255
|
+
method: 'DELETE',
|
|
256
|
+
...this.config(token)
|
|
257
|
+
});
|
|
258
|
+
return response;
|
|
259
|
+
};
|
|
260
|
+
this.config = (token)=>{
|
|
261
|
+
const headers = new Headers();
|
|
262
|
+
headers.set('Content-Type', 'application/json');
|
|
263
|
+
headers.set('Accept', 'application/json');
|
|
264
|
+
if (token) {
|
|
265
|
+
headers.set('Authorization', `Bearer ${token}`);
|
|
266
|
+
}
|
|
267
|
+
return {
|
|
268
|
+
headers,
|
|
269
|
+
validateStatus: this.validateStatus,
|
|
270
|
+
retry: true
|
|
271
|
+
};
|
|
272
|
+
};
|
|
273
|
+
this.validateStatus = (status)=>status < 500 && status !== 429;
|
|
274
|
+
this.body = (payload)=>{
|
|
275
|
+
if (!this.clientId) {
|
|
276
|
+
console.error('Quiltt Client ID is not set. Unable to identify & authenticate');
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
session: {
|
|
280
|
+
clientId: this.clientId,
|
|
281
|
+
...payload
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
};
|
|
285
|
+
this.clientId = clientId;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export { AuthAPI, AuthLink, AuthStrategies, BatchHttpLink, ConnectorSDKEventType, ErrorLink, ForwardableLink, GlobalStorage, HttpLink, JsonWebTokenParse, QuilttClient, RetryLink, SubscriptionLink, TerminatingLink, Timeoutable, VersionLink, debugging, endpointAuth, endpointGraphQL, version };
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quiltt/core",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.6",
|
|
4
4
|
"description": "Javascript API client and utilities for Quiltt",
|
|
5
|
-
"repository": {
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "https://github.com/quiltt/quiltt-public.git",
|
|
8
|
-
"directory": "packages/core"
|
|
9
|
-
},
|
|
10
|
-
"homepage": "https://github.com/quiltt/quiltt-public/tree/main/packages/core#readme",
|
|
11
5
|
"keywords": [
|
|
12
6
|
"quiltt",
|
|
13
7
|
"typescript"
|
|
14
8
|
],
|
|
9
|
+
"homepage": "https://github.com/quiltt/quiltt-js/tree/main/packages/core#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/quiltt/quiltt-js.git",
|
|
13
|
+
"directory": "packages/core"
|
|
14
|
+
},
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"sideEffects": [
|
|
17
17
|
"./src/Storage/Local.ts",
|
|
@@ -21,11 +21,10 @@
|
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"import": "./dist/index.js",
|
|
24
|
-
"require": "./dist/index.cjs",
|
|
25
24
|
"types": "./dist/index.d.ts"
|
|
26
25
|
}
|
|
27
26
|
},
|
|
28
|
-
"main": "./dist/index.
|
|
27
|
+
"main": "./dist/index.js",
|
|
29
28
|
"module": "./dist/index.js",
|
|
30
29
|
"types": "./dist/index.d.ts",
|
|
31
30
|
"files": [
|
|
@@ -34,32 +33,32 @@
|
|
|
34
33
|
"CHANGELOG.md"
|
|
35
34
|
],
|
|
36
35
|
"dependencies": {
|
|
37
|
-
"@apollo/client": "^3.
|
|
38
|
-
"
|
|
39
|
-
"cross-fetch": "^3.1.8",
|
|
36
|
+
"@apollo/client": "^3.9.9",
|
|
37
|
+
"cross-fetch": "^4.0.0",
|
|
40
38
|
"graphql": "^16.8.1",
|
|
41
|
-
"graphql-ruby-client": "^1.
|
|
39
|
+
"graphql-ruby-client": "^1.13.3"
|
|
42
40
|
},
|
|
43
41
|
"devDependencies": {
|
|
44
42
|
"@trivago/prettier-plugin-sort-imports": "4.1.1",
|
|
45
|
-
"@types/node": "20.
|
|
46
|
-
"@types/react": "18.2.
|
|
43
|
+
"@types/node": "20.12.2",
|
|
44
|
+
"@types/react": "18.2.73",
|
|
47
45
|
"@typescript-eslint/eslint-plugin": "5.60.1",
|
|
48
46
|
"@typescript-eslint/parser": "5.60.1",
|
|
47
|
+
"bunchee": "4.4.8",
|
|
49
48
|
"eslint": "8.43.0",
|
|
50
49
|
"eslint-config-prettier": "8.8.0",
|
|
51
50
|
"eslint-plugin-prettier": "4.2.1",
|
|
52
51
|
"prettier": "2.8.8",
|
|
53
|
-
"
|
|
54
|
-
"typescript": "5.
|
|
52
|
+
"rimraf": "5.0.5",
|
|
53
|
+
"typescript": "5.4.3"
|
|
55
54
|
},
|
|
56
55
|
"publishConfig": {
|
|
57
56
|
"access": "public"
|
|
58
57
|
},
|
|
59
58
|
"scripts": {
|
|
60
|
-
"build": "
|
|
59
|
+
"build": "bunchee",
|
|
61
60
|
"clean": "rimraf .turbo dist",
|
|
62
|
-
"dev": "
|
|
61
|
+
"dev": "bunchee --watch",
|
|
63
62
|
"lint": "TIMING=1 eslint --ext .js,.jsx,.ts,.tsx src/ --fix",
|
|
64
63
|
"typecheck": "tsc --project tsconfig.json --noEmit"
|
|
65
64
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { BatchHttpLink as ApolloHttpLink } from '@apollo/client/link/batch-http/index.js'
|
|
2
|
+
import crossfetch from 'cross-fetch'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
5
|
+
const effectiveFetch = typeof fetch === 'undefined' ? crossfetch : fetch
|
|
4
6
|
|
|
5
7
|
import { endpointGraphQL } from '../../../configuration'
|
|
6
8
|
|
|
7
9
|
export const BatchHttpLink = new ApolloHttpLink({
|
|
8
10
|
uri: endpointGraphQL,
|
|
9
|
-
fetch,
|
|
11
|
+
fetch: effectiveFetch,
|
|
10
12
|
})
|
|
11
13
|
|
|
12
14
|
export default BatchHttpLink
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { HttpLink as ApolloHttpLink } from '@apollo/client/link/http/index.js'
|
|
2
|
+
import crossfetch from 'cross-fetch'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
5
|
+
const effectiveFetch = typeof fetch === 'undefined' ? crossfetch : fetch
|
|
4
6
|
|
|
5
7
|
import { endpointGraphQL } from '../../../configuration'
|
|
6
8
|
|
|
7
9
|
export const HttpLink = new ApolloHttpLink({
|
|
8
10
|
uri: endpointGraphQL,
|
|
9
|
-
fetch,
|
|
11
|
+
fetch: effectiveFetch,
|
|
10
12
|
})
|
|
11
13
|
|
|
12
14
|
export default HttpLink
|
|
@@ -16,7 +16,7 @@ class SubscriptionGuarantor {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
guarantee(subscription: Subscription) {
|
|
19
|
-
if (this.pendingSubscriptions.indexOf(subscription)
|
|
19
|
+
if (this.pendingSubscriptions.indexOf(subscription) === -1) {
|
|
20
20
|
logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`)
|
|
21
21
|
this.pendingSubscriptions.push(subscription)
|
|
22
22
|
} else {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import { endpointAuth } from '../../configuration'
|
|
1
|
+
import { endpointAuth } from '@/configuration'
|
|
2
|
+
import type { FetchResponse } from './fetchWithRetry'
|
|
3
|
+
import { fetchWithRetry } from './fetchWithRetry'
|
|
5
4
|
|
|
6
5
|
export enum AuthStrategies {
|
|
7
6
|
Email = 'email',
|
|
@@ -22,7 +21,7 @@ export type UsernamePayload = EmailInput | PhoneInput
|
|
|
22
21
|
export type PasscodePayload = UsernamePayload & { passcode: string }
|
|
23
22
|
|
|
24
23
|
type SessionData = { token: string }
|
|
25
|
-
type NoContentData =
|
|
24
|
+
type NoContentData = null
|
|
26
25
|
type UnauthorizedData = { message: string; instruction: string }
|
|
27
26
|
export type UnprocessableData = { [attribute: string]: Array<string> }
|
|
28
27
|
|
|
@@ -31,8 +30,8 @@ type Identify = SessionData | NoContentData | UnprocessableData
|
|
|
31
30
|
type Authenticate = SessionData | UnauthorizedData | UnprocessableData
|
|
32
31
|
type Revoke = NoContentData | UnauthorizedData
|
|
33
32
|
|
|
34
|
-
export type SessionResponse =
|
|
35
|
-
export type UnprocessableResponse =
|
|
33
|
+
export type SessionResponse = FetchResponse<SessionData>
|
|
34
|
+
export type UnprocessableResponse = FetchResponse<UnprocessableData>
|
|
36
35
|
|
|
37
36
|
// https://www.quiltt.dev/api-reference/rest/auth#
|
|
38
37
|
export class AuthAPI {
|
|
@@ -47,8 +46,12 @@ export class AuthAPI {
|
|
|
47
46
|
* - 200: OK -> Session is Valid
|
|
48
47
|
* - 401: Unauthorized -> Session is Invalid
|
|
49
48
|
*/
|
|
50
|
-
ping = (token: string) => {
|
|
51
|
-
|
|
49
|
+
ping = async (token: string) => {
|
|
50
|
+
const response = await fetchWithRetry<Ping>(endpointAuth, {
|
|
51
|
+
method: 'GET',
|
|
52
|
+
...this.config(token),
|
|
53
|
+
})
|
|
54
|
+
return response
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
/**
|
|
@@ -57,8 +60,13 @@ export class AuthAPI {
|
|
|
57
60
|
* - 202: Accepted -> Profile Found, MFA Code Sent for `authenticate`
|
|
58
61
|
* - 422: Unprocessable Entity -> Invalid Payload
|
|
59
62
|
*/
|
|
60
|
-
identify = (payload: UsernamePayload) => {
|
|
61
|
-
|
|
63
|
+
identify = async (payload: UsernamePayload) => {
|
|
64
|
+
const response = await fetchWithRetry<Identify>(endpointAuth, {
|
|
65
|
+
method: 'POST',
|
|
66
|
+
body: JSON.stringify(this.body(payload)),
|
|
67
|
+
...this.config(),
|
|
68
|
+
})
|
|
69
|
+
return response
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
/**
|
|
@@ -67,8 +75,13 @@ export class AuthAPI {
|
|
|
67
75
|
* - 401: Unauthorized -> MFA Invalid
|
|
68
76
|
* - 422: Unprocessable Entity -> Invalid Payload
|
|
69
77
|
*/
|
|
70
|
-
authenticate = (payload: PasscodePayload) => {
|
|
71
|
-
|
|
78
|
+
authenticate = async (payload: PasscodePayload): Promise<FetchResponse<Authenticate>> => {
|
|
79
|
+
const response = await fetchWithRetry<Authenticate>(endpointAuth, {
|
|
80
|
+
method: 'PUT',
|
|
81
|
+
body: JSON.stringify(this.body(payload)),
|
|
82
|
+
...this.config(),
|
|
83
|
+
})
|
|
84
|
+
return response
|
|
72
85
|
}
|
|
73
86
|
|
|
74
87
|
/**
|
|
@@ -76,28 +89,30 @@ export class AuthAPI {
|
|
|
76
89
|
* - 204: No Content -> Session Revoked
|
|
77
90
|
* - 401: Unauthorized -> Session Not Found
|
|
78
91
|
*/
|
|
79
|
-
revoke = (token: string) => {
|
|
80
|
-
|
|
92
|
+
revoke = async (token: string): Promise<FetchResponse<Revoke>> => {
|
|
93
|
+
const response = await fetchWithRetry<Revoke>(endpointAuth, {
|
|
94
|
+
method: 'DELETE',
|
|
95
|
+
...this.config(token),
|
|
96
|
+
})
|
|
97
|
+
return response
|
|
81
98
|
}
|
|
82
99
|
|
|
83
|
-
private config = (token?: string)
|
|
84
|
-
const headers
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
100
|
+
private config = (token?: string) => {
|
|
101
|
+
const headers = new Headers()
|
|
102
|
+
headers.set('Content-Type', 'application/json')
|
|
103
|
+
headers.set('Accept', 'application/json')
|
|
88
104
|
|
|
89
105
|
if (token) {
|
|
90
|
-
headers.Authorization
|
|
106
|
+
headers.set('Authorization', `Bearer ${token}`)
|
|
91
107
|
}
|
|
92
108
|
|
|
93
109
|
return {
|
|
94
|
-
headers
|
|
110
|
+
headers,
|
|
95
111
|
validateStatus: this.validateStatus,
|
|
96
112
|
retry: true,
|
|
97
113
|
}
|
|
98
114
|
}
|
|
99
|
-
|
|
100
|
-
private validateStatus = (status: number) => status < 500
|
|
115
|
+
private validateStatus = (status: number) => status < 500 && status !== 429
|
|
101
116
|
|
|
102
117
|
private body = (payload: any) => {
|
|
103
118
|
if (!this.clientId) {
|
|
@@ -112,5 +127,3 @@ export class AuthAPI {
|
|
|
112
127
|
}
|
|
113
128
|
}
|
|
114
129
|
}
|
|
115
|
-
|
|
116
|
-
export default AuthAPI
|