@quiltt/react-native 3.4.0 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @quiltt/react-native
2
2
 
3
+ ## 3.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#200](https://github.com/quiltt/quiltt-public/pull/200) [`0a07431`](https://github.com/quiltt/quiltt-public/commit/0a07431ff936e6cd4fd3aeee66bba1fec21f6624) Thanks [@sirwolfgang](https://github.com/sirwolfgang)! - Fix release
8
+
9
+ - Updated dependencies [[`0a07431`](https://github.com/quiltt/quiltt-public/commit/0a07431ff936e6cd4fd3aeee66bba1fec21f6624)]:
10
+ - @quiltt/react@3.5.1
11
+ - @quiltt/core@3.5.1
12
+
13
+ ## 3.5.0
14
+
15
+ ### Patch Changes
16
+
17
+ - Updated dependencies [[`c65d87a`](https://github.com/quiltt/quiltt-public/commit/c65d87a8316dbec82635a0c4108714de7bbd082b)]:
18
+ - @quiltt/react@3.5.0
19
+ - @quiltt/core@3.5.0
20
+
21
+ ## 3.4.1
22
+
23
+ ### Patch Changes
24
+
25
+ - [#195](https://github.com/quiltt/quiltt-public/pull/195) [`6c36908`](https://github.com/quiltt/quiltt-public/commit/6c36908678cb46d5f6a0c7438e0ed48889cabf79) Thanks [@tom-quiltt](https://github.com/tom-quiltt)! - Report preflight error before sending connectorUrl to webview
26
+
27
+ - Updated dependencies [[`6c36908`](https://github.com/quiltt/quiltt-public/commit/6c36908678cb46d5f6a0c7438e0ed48889cabf79)]:
28
+ - @quiltt/react@3.4.1
29
+ - @quiltt/core@3.4.1
30
+
3
31
  ## 3.4.0
4
32
 
5
33
  ### Minor Changes
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
- "use strict";var S=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var M=Object.prototype.hasOwnProperty;var I=(a,o)=>{for(var i in o)S(a,i,{get:o[i],enumerable:!0})},J=(a,o,i,r)=>{if(o&&typeof o=="object"||typeof o=="function")for(let c of j(o))!M.call(a,c)&&c!==i&&S(a,c,{get:()=>o[c],enumerable:!(r=K(o,c))||r.enumerable});return a};var H=a=>J(S({},"__esModule",{value:!0}),a);var N={};I(N,{QuilttConnector:()=>g,default:()=>B});module.exports=H(N);var U=require("base-64");var n=require("@quiltt/core"),d=require("react"),L=require("react-native"),O=require("react-native-webview"),k=require("react-native-url-polyfill");var l=require("react-native"),R=require("react/jsx-runtime"),A=({children:a})=>(0,R.jsx)(l.SafeAreaView,{style:_.AndroidSafeArea,children:a}),_=l.StyleSheet.create({AndroidSafeArea:{flex:1,backgroundColor:"white",paddingTop:l.Platform.OS==="android"?l.StatusBar.currentHeight:0}});var P=require("@quiltt/react");var q="3.4.0";var w=require("react/jsx-runtime"),v=({connectorId:a,connectionId:o,oauthRedirectUrl:i,onEvent:r,onLoad:c,onExit:s,onExitSuccess:u,onExitAbort:f,onExitError:m})=>{let h=(0,d.useRef)(null),{session:p}=(0,P.useQuilttSession)();i=encodeURIComponent(i);let V=`https://${a}.quiltt.app/?mode=webview&oauth_redirect_url=${i}&agent=react-native-${q}`,Q=(0,d.useCallback)(()=>{var e;let t=` const options = { source: 'quiltt', type: 'Options', token: '${p==null?void 0:p.token}', connectorId: '${a}', connectionId: '${o}', }; const compactedOptions = Object.keys(options).reduce((acc, key) => { if (options[key] !== 'undefined') { acc[key] = options[key]; } return acc; }, {}); window.postMessage(compactedOptions); `;(e=h.current)==null||e.injectJavaScript(t)},[o,a,p==null?void 0:p.token]),W=["quiltt.app","quiltt.dev","moneydesktop.com","cdn.plaid.com/link/v2/stable/link.html"],$=t=>C(t)?!1:W.some(e=>t.href.includes(e)),D=t=>{let e=new k.URL(t.url);return C(e)?(T(e),!1):$(e)?!0:(y(e),!1)},b=()=>{var e;let t="localStorage.clear();";(e=h.current)==null||e.injectJavaScript(t)},C=t=>t.protocol==="quilttconnector:",T=t=>{t.searchParams.delete("source"),t.searchParams.append("connectorId",a);let e=Object.fromEntries(t.searchParams);switch(t.host){case"Load":Q(),r==null||r(n.ConnectorSDKEventType.Load,e),c==null||c(e);break;case"ExitAbort":b(),r==null||r(n.ConnectorSDKEventType.ExitAbort,e),s==null||s(n.ConnectorSDKEventType.ExitAbort,e),f==null||f(e);break;case"ExitError":b(),r==null||r(n.ConnectorSDKEventType.ExitError,e),s==null||s(n.ConnectorSDKEventType.ExitError,e),m==null||m(e);break;case"ExitSuccess":b(),r==null||r(n.ConnectorSDKEventType.ExitSuccess,e),s==null||s(n.ConnectorSDKEventType.ExitSuccess,e),u==null||u(e);break;case"Authenticate":break;case"OauthRequested":y(new k.URL(t.searchParams.get("oauthUrl")));break;default:console.log("unhandled event",t);break}},y=t=>{if(t.protocol!=="https:"){console.log(`handleOAuthUrl - Skipping non https url - ${t.href}`);return}L.Linking.openURL(t.href)};return(0,w.jsx)(A,{children:(0,w.jsx)(O.WebView,{ref:h,originWhitelist:["https://*","quilttconnector://*"],source:{uri:V},onShouldStartLoadWithRequest:D,javaScriptEnabled:!0,domStorageEnabled:!0,webviewDebuggingEnabled:!0})})},g=v;global.atob||(global.atob=U.decode);var B=g;0&&(module.exports={QuilttConnector});
1
+ "use strict";var D=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var ie=Object.getOwnPropertyNames;var ne=Object.prototype.hasOwnProperty;var ce=(r,e,i)=>e in r?D(r,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):r[e]=i;var le=(r,e)=>{for(var i in e)D(r,i,{get:e[i],enumerable:!0})},pe=(r,e,i,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of ie(e))!ne.call(r,o)&&o!==i&&D(r,o,{get:()=>e[o],enumerable:!(n=se(e,o))||n.enumerable});return r};var de=r=>pe(D({},"__esModule",{value:!0}),r);var g=(r,e,i)=>(ce(r,typeof e!="symbol"?e+"":e,i),i);var w=(r,e,i)=>new Promise((n,o)=>{var l=s=>{try{d(i.next(s))}catch(b){o(b)}},h=s=>{try{d(i.throw(s))}catch(b){o(b)}},d=s=>s.done?n(s.value):Promise.resolve(s.value).then(l,h);d((i=i.apply(r,e)).next())});var be={};le(be,{QuilttConnector:()=>I,default:()=>me});module.exports=de(be);var ee=require("base-64");var m=require("@quiltt/core"),c=require("react"),U=require("react-native"),Z=require("react-native-webview"),_=require("react-native-url-polyfill");var u=require("react-native"),J=require("react/jsx-runtime"),A=({children:r})=>(0,J.jsx)(u.SafeAreaView,{style:fe.AndroidSafeArea,children:r}),fe=u.StyleSheet.create({AndroidSafeArea:{flex:1,backgroundColor:"white",paddingTop:u.Platform.OS==="android"?u.StatusBar.currentHeight:0}});var E=require("@quiltt/react");var R=require("@honeybadger-io/core/build/src/util");var B={honeybadger_api_key:"undefined"};var C="3.5.1";var he={name:"Quiltt React Native SDK Reporter",url:"https://www.quiltt.dev/guides/connector/react-native",version:C},O=class{constructor(e){g(this,"noticeUrl");g(this,"apiKey");g(this,"clientName");g(this,"clientVersion");g(this,"platform");g(this,"logger");g(this,"userAgent");this.noticeUrl="https://api.honeybadger.io/v1/notices",this.apiKey=B.honeybadger_api_key,this.clientName="react-native-sdk",this.clientVersion=C,this.platform=e,this.logger=console,this.userAgent=`${this.clientName} ${this.clientVersion}; ${this.platform}`}send(e,i){return w(this,null,function*(){let n={"X-API-Key":this.apiKey,"Content-Type":"application/json",Accept:"application/json","User-Agent":`${this.clientName} ${this.clientVersion}; ${this.platform}`},o=yield this.buildPayload(e,i),l="POST",h=JSON.stringify(o),d="cors";fetch(this.noticeUrl,{headers:n,method:l,body:h,mode:d}).then(s=>{if(s.status!==201){this.logger.warn(`Error report failed: unknown response from server. code=${s.status}`);return}return s.json()}).then(s=>{s&&this.logger.info(`Error report sent \u26A1 https://app.honeybadger.io/notice/${s==null?void 0:s.id}`)})})}buildPayload(n){return w(this,arguments,function*(e,i={}){let o=e;return o.stack=(0,R.generateStackTrace)(),o.backtrace=(0,R.makeBacktrace)(o.stack),{notifier:he,error:{class:o.name,message:o.message,backtrace:o.backtrace,tags:o.tags||[],causes:(0,R.getCauses)(o,this.logger)},request:{url:o.url,component:o.component,action:o.action,context:i||{},cgi_data:{},params:{},session:{}},server:{project_root:o.projectRoot,environment_name:this.userAgent,revision:C,hostname:this.platform,time:new Date().toUTCString()},details:o.details||{}}})}};var G=(r,e)=>e?`An error occurred while checking the connector URL: ${e==null?void 0:e.name}
2
+ ${e==null?void 0:e.message}`:r?`The URL is not routable. Response status: ${r}`:"An error occurred while checking the connector URL";var N=require("react-native");var q=require("react/jsx-runtime"),X=()=>(0,q.jsx)(A,{children:(0,q.jsx)(N.View,{style:{flex:1,justifyContent:"center",alignItems:"center"},children:(0,q.jsx)(N.ActivityIndicator,{size:"large",color:"#0000ff"})})});var p=require("react-native");var f=require("react/jsx-runtime"),Y=({error:r,cta:e})=>(0,f.jsx)(A,{children:(0,f.jsxs)(p.View,{style:[P.container,P.padding],children:[(0,f.jsxs)(p.View,{style:{flex:1,justifyContent:"center"},children:[(0,f.jsx)(p.View,{style:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginVertical:10},children:(0,f.jsx)(p.Text,{style:[P.title],children:"Cannot connect to the internet."})}),(0,f.jsx)(p.Text,{style:[P.subtitle],children:r})]}),(0,f.jsx)(p.Pressable,{style:[P.pressable],onPress:e,children:(0,f.jsx)(p.Text,{style:[P.pressableText],children:"Exit"})})]})}),P=p.StyleSheet.create({container:{flex:1,flexDirection:"column",justifyContent:"flex-start",alignItems:"stretch",backgroundColor:"#F3F4F6"},title:{color:"#1F2937",fontSize:30,fontWeight:"bold"},subtitle:{color:"rgba(107, 114, 128, 1)"},padding:{paddingHorizontal:16,paddingVertical:24},pressable:{marginTop:20,backgroundColor:"#1F2937",padding:10,paddingHorizontal:25,borderRadius:5},pressableText:{color:"#fff",textAlign:"center"}});var $=require("react/jsx-runtime"),x=new O(`${U.Platform.OS} ${U.Platform.Version}`),ge=3,ue=({connectorId:r,connectionId:e,oauthRedirectUrl:i,onEvent:n,onLoad:o,onExit:l,onExitSuccess:h,onExitAbort:d,onExitError:s})=>{let b=(0,c.useRef)(null),{session:k}=(0,E.useQuilttSession)();i=encodeURIComponent(i);let y=`https://${r}.quiltt.app/?mode=webview&oauth_redirect_url=${i}&agent=react-native-${C}`;console.log("connectorUrl",y);let[T,te]=(0,c.useState)({checked:!1}),j=(0,c.useCallback)((a=0)=>w(void 0,null,function*(){let t,V,K=!1;try{let S=yield fetch(y);if(!S.ok)console.error(`The URL ${y} is not routable.`),t=S.status,K=!0;else return console.log(`The URL ${y} is routable.`),{checked:!0}}catch(S){V=S,console.error(`An error occurred while checking the connector URL: ${V}`),K=!0}if(K&&a<ge)return yield new Promise(S=>setTimeout(S,50*a)),console.log(`Retrying... Attempt number ${a+1}`),j(a+1);let z=G(t,V),oe=V||new Error(z),ae={connectorUrl:y,responseStatus:t};return t!==404&&x.send(oe,ae),{checked:!0,error:z}}),[y]);(0,c.useEffect)(()=>{if(T.checked)return;(()=>w(void 0,null,function*(){let t=yield j();te(t)}))()},[j,T]);let Q=(0,c.useCallback)(()=>{var t;let a=` const options = { source: 'quiltt', type: 'Options', token: '${k==null?void 0:k.token}', connectorId: '${r}', connectionId: '${e}', }; const compactedOptions = Object.keys(options).reduce((acc, key) => { if (options[key] !== 'undefined') { acc[key] = options[key]; } return acc; }, {}); window.postMessage(compactedOptions); `;(t=b.current)==null||t.injectJavaScript(a)},[e,r,k==null?void 0:k.token]),W=(0,c.useMemo)(()=>["quiltt.app","quiltt.dev","moneydesktop.com","cdn.plaid.com/link/v2/stable/link.html"],[]),v=(0,c.useCallback)(a=>a.protocol==="quilttconnector:",[]),H=(0,c.useCallback)(a=>{if(v(a))return!1;if(a.protocol!=="https:"){let t=new Error(`Invalid url leaked ${a.href}`);return x.send(t),!1}return W.some(t=>a.href.includes(t))},[W,v]),F=()=>{var t;let a="localStorage.clear();";(t=b.current)==null||t.injectJavaScript(a)},L=(0,c.useCallback)(a=>{if(a.protocol!=="https:"){console.log(`handleOAuthUrl - Skipping non https url - ${a.href}`);return}U.Linking.openURL(a.href)},[]),M=(0,c.useCallback)(a=>{a.searchParams.delete("source"),a.searchParams.append("connectorId",r);let t=Object.fromEntries(a.searchParams);switch(a.host){case"Load":Q(),n==null||n(m.ConnectorSDKEventType.Load,t),o==null||o(t);break;case"ExitAbort":F(),n==null||n(m.ConnectorSDKEventType.ExitAbort,t),l==null||l(m.ConnectorSDKEventType.ExitAbort,t),d==null||d(t);break;case"ExitError":F(),n==null||n(m.ConnectorSDKEventType.ExitError,t),l==null||l(m.ConnectorSDKEventType.ExitError,t),s==null||s(t);break;case"ExitSuccess":F(),n==null||n(m.ConnectorSDKEventType.ExitSuccess,t),l==null||l(m.ConnectorSDKEventType.ExitSuccess,t),h==null||h(t);break;case"Authenticate":break;case"OauthRequested":L(new _.URL(a.searchParams.get("oauthUrl")));break;default:console.log("unhandled event",a);break}},[r,L,Q,n,l,d,s,h,o]),re=(0,c.useCallback)(a=>{let t=new _.URL(a.url);return v(t)?(M(t),!1):H(t)?!0:(L(t),!1)},[L,M,v,H]);return T.checked?T.error?(0,$.jsx)(Y,{error:T.error,cta:()=>s==null?void 0:s({connectorId:r})}):(0,$.jsx)(A,{children:(0,$.jsx)(Z.WebView,{ref:b,originWhitelist:["https://*","quilttconnector://*"],source:{uri:y},onShouldStartLoadWithRequest:re,javaScriptEnabled:!0,domStorageEnabled:!0,webviewDebuggingEnabled:!0})}):(0,$.jsx)(X,{})},I=ue;global.atob||(global.atob=ee.decode);var me=I;0&&(module.exports={QuilttConnector});
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/QuilttConnector.tsx","../src/components/AndroidSafeAreaView.tsx","../src/version.ts"],"sourcesContent":["// Hermes doesn't have atob\n// https://github.com/facebook/hermes/issues/1178\nimport { decode } from 'base-64'\nif (!global.atob) {\n global.atob = decode\n}\nimport QuilttConnector from './components/QuilttConnector'\n\nexport { QuilttConnector }\nexport default QuilttConnector\n","import {\n ConnectorSDKCallbackMetadata,\n ConnectorSDKCallbacks,\n ConnectorSDKEventType,\n} from '@quiltt/core'\nimport { useCallback, useRef } from 'react'\nimport { Linking } from 'react-native'\nimport { WebView } from 'react-native-webview'\n// React Native's URL implementation is incomplete\n// https://github.com/facebook/react-native/issues/16434\nimport { URL } from 'react-native-url-polyfill'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\nimport type { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes'\nimport { useQuilttSession } from '@quiltt/react'\nimport { version } from '../version'\n\ntype QuilttConnectorProps = {\n connectorId: string\n connectionId?: string\n oauthRedirectUrl: string\n} & ConnectorSDKCallbacks\n\nexport const QuilttConnector = ({\n connectorId,\n connectionId,\n oauthRedirectUrl,\n onEvent,\n onLoad,\n onExit,\n onExitSuccess,\n onExitAbort,\n onExitError,\n}: QuilttConnectorProps) => {\n const webViewRef = useRef<WebView>(null)\n const { session } = useQuilttSession()\n oauthRedirectUrl = encodeURIComponent(oauthRedirectUrl)\n const connectorUrl = `https://${connectorId}.quiltt.app/?mode=webview&oauth_redirect_url=${oauthRedirectUrl}&agent=react-native-${version}`\n\n const initInjectedJavaScript = useCallback(() => {\n const script = `\\\n const options = {\\\n source: 'quiltt',\\\n type: 'Options',\\\n token: '${session?.token}',\\\n connectorId: '${connectorId}',\\\n connectionId: '${connectionId}',\\\n };\\\n const compactedOptions = Object.keys(options).reduce((acc, key) => {\\\n if (options[key] !== 'undefined') {\\\n acc[key] = options[key];\\\n }\\\n return acc;\\\n }, {});\\\n window.postMessage(compactedOptions);\\\n `\n webViewRef.current?.injectJavaScript(script)\n }, [connectionId, connectorId, session?.token])\n\n // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview\n // For other urls, we assume those are bank urls, which needs to be handle in external browser.\n // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.\n const allowedListUrl = [\n 'quiltt.app',\n 'quiltt.dev',\n 'moneydesktop.com',\n 'cdn.plaid.com/link/v2/stable/link.html',\n ]\n const shouldRender = (url: URL) => {\n if (isQuilttEvent(url)) return false\n return allowedListUrl.some((href) => url.href.includes(href))\n }\n\n const requestHandler = (request: ShouldStartLoadRequest) => {\n const url = new URL(request.url)\n if (isQuilttEvent(url)) {\n handleQuilttEvent(url)\n return false\n }\n if (shouldRender(url)) return true\n // Plaid set oauth url by doing window.location.href = url\n // This is the only way I know to handle this.\n handleOAuthUrl(url)\n return false\n }\n\n const clearLocalStorage = () => {\n const script = 'localStorage.clear();'\n webViewRef.current?.injectJavaScript(script)\n }\n\n const isQuilttEvent = (url: URL) => url.protocol === 'quilttconnector:'\n\n const handleQuilttEvent = (url: URL) => {\n url.searchParams.delete('source')\n url.searchParams.append('connectorId', connectorId)\n const metadata = Object.fromEntries(url.searchParams) as ConnectorSDKCallbackMetadata\n\n const eventType = url.host\n switch (eventType) {\n case 'Load':\n initInjectedJavaScript()\n onEvent?.(ConnectorSDKEventType.Load, metadata)\n onLoad?.(metadata)\n break\n case 'ExitAbort':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExit?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExitAbort?.(metadata)\n break\n case 'ExitError':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitError, metadata)\n onExit?.(ConnectorSDKEventType.ExitError, metadata)\n onExitError?.(metadata)\n break\n case 'ExitSuccess':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExitSuccess?.(metadata)\n break\n case 'Authenticate':\n // @todo handle Authenticate\n break\n case 'OauthRequested':\n handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))\n break\n default:\n console.log('unhandled event', url)\n break\n }\n }\n\n const handleOAuthUrl = (oauthUrl: URL) => {\n if (oauthUrl.protocol !== 'https:') {\n console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`)\n return\n }\n Linking.openURL(oauthUrl.href)\n }\n\n return (\n <AndroidSafeAreaView>\n <WebView\n ref={webViewRef}\n originWhitelist={['https://*', 'quilttconnector://*']} // Maybe relax this to *?\n source={{ uri: connectorUrl }}\n onShouldStartLoadWithRequest={requestHandler}\n javaScriptEnabled\n domStorageEnabled // To enable localStorage in Android webview\n webviewDebuggingEnabled // Not sure if this works\n />\n </AndroidSafeAreaView>\n )\n}\n\nexport default QuilttConnector\n","import { SafeAreaView, StyleSheet, Platform, StatusBar } from 'react-native'\nimport { PropsWithChildren } from 'react'\n\nexport const AndroidSafeAreaView = ({ children }: PropsWithChildren) => (\n <SafeAreaView style={styles.AndroidSafeArea}>{children}</SafeAreaView>\n)\n\nconst styles = StyleSheet.create({\n AndroidSafeArea: {\n flex: 1,\n backgroundColor: 'white',\n paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,\n },\n})\n","// Generated by genversion.\nexport const version = '3.4.0'\n"],"mappings":"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","names":["src_exports","__export","QuilttConnector_default","src_default","__toCommonJS","import_base_64","import_core","import_react","import_react_native","import_react_native_webview","import_react_native_url_polyfill","import_react_native","import_jsx_runtime","AndroidSafeAreaView","children","styles","import_react","version","import_jsx_runtime","QuilttConnector","connectorId","connectionId","oauthRedirectUrl","onEvent","onLoad","onExit","onExitSuccess","onExitAbort","onExitError","webViewRef","session","connectorUrl","version","initInjectedJavaScript","_a","script","allowedListUrl","shouldRender","url","isQuilttEvent","href","requestHandler","request","handleQuilttEvent","handleOAuthUrl","clearLocalStorage","metadata","oauthUrl","AndroidSafeAreaView","QuilttConnector_default","src_default","QuilttConnector_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/QuilttConnector.tsx","../src/components/AndroidSafeAreaView.tsx","../src/utils/ErrorReporter.ts","../src/utils/ErrorReporterConfig.ts","../src/version.ts","../src/utils/getErrorMessage.ts","../src/components/LoadingScreen.tsx","../src/components/ErrorScreen.tsx"],"sourcesContent":["// Hermes doesn't have atob\n// https://github.com/facebook/hermes/issues/1178\nimport { decode } from 'base-64'\nif (!global.atob) {\n global.atob = decode\n}\nimport QuilttConnector from './components/QuilttConnector'\n\nexport { QuilttConnector }\nexport default QuilttConnector\n","import {\n ConnectorSDKCallbackMetadata,\n ConnectorSDKCallbacks,\n ConnectorSDKEventType,\n} from '@quiltt/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Linking, Platform } from 'react-native'\nimport { WebView } from 'react-native-webview'\n// React Native's URL implementation is incomplete\n// https://github.com/facebook/react-native/issues/16434\nimport { URL } from 'react-native-url-polyfill'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\nimport type { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes'\nimport { useQuilttSession } from '@quiltt/react'\nimport { ErrorReporter, getErrorMessage } from '../utils/'\n\nimport { version } from '../version'\nimport { LoadingScreen } from './LoadingScreen'\nimport { ErrorScreen } from './ErrorScreen'\n\nconst errorReporter = new ErrorReporter(`${Platform.OS} ${Platform.Version}`)\n\ntype QuilttConnectorProps = {\n connectorId: string\n connectionId?: string\n oauthRedirectUrl: string\n} & ConnectorSDKCallbacks\n\ntype PreFlightCheck = {\n checked: boolean\n error?: string\n}\n\nconst PREFLIGHT_RETRY_COUNT = 3\n\nexport const QuilttConnector = ({\n connectorId,\n connectionId,\n oauthRedirectUrl,\n onEvent,\n onLoad,\n onExit,\n onExitSuccess,\n onExitAbort,\n onExitError,\n}: QuilttConnectorProps) => {\n const webViewRef = useRef<WebView>(null)\n const { session } = useQuilttSession()\n oauthRedirectUrl = encodeURIComponent(oauthRedirectUrl)\n const connectorUrl = `https://${connectorId}.quiltt.app/?mode=webview&oauth_redirect_url=${oauthRedirectUrl}&agent=react-native-${version}`\n console.log('connectorUrl', connectorUrl)\n const [preFlightCheck, setPreFlightCheck] = useState<PreFlightCheck>({ checked: false })\n\n const checkConnectorUrl = useCallback(\n async (retryCount = 0): Promise<PreFlightCheck> => {\n let responseStatus\n let error\n let errorOccurred = false\n try {\n const response = await fetch(connectorUrl)\n if (!response.ok) {\n console.error(`The URL ${connectorUrl} is not routable.`)\n responseStatus = response.status\n errorOccurred = true\n } else {\n console.log(`The URL ${connectorUrl} is routable.`)\n return { checked: true }\n }\n } catch (e) {\n error = e\n console.error(`An error occurred while checking the connector URL: ${error}`)\n errorOccurred = true\n }\n\n // Retry logic in case of error or response not OK\n if (errorOccurred && retryCount < PREFLIGHT_RETRY_COUNT) {\n await new Promise((resolve) => setTimeout(resolve, 50 * retryCount)) // delay for 50ms for each retry\n console.log(`Retrying... Attempt number ${retryCount + 1}`)\n return checkConnectorUrl(retryCount + 1)\n }\n\n const errorMessage = getErrorMessage(responseStatus, error as Error)\n const errorToSend = (error as Error) || new Error(errorMessage)\n const context = { connectorUrl, responseStatus }\n if (responseStatus !== 404) errorReporter.send(errorToSend, context)\n return { checked: true, error: errorMessage }\n },\n [connectorUrl]\n )\n\n useEffect(() => {\n if (preFlightCheck.checked) return\n const fetchDataAndSetState = async () => {\n const connectorUrlStatus = await checkConnectorUrl()\n setPreFlightCheck(connectorUrlStatus)\n }\n fetchDataAndSetState()\n }, [checkConnectorUrl, preFlightCheck])\n\n const initInjectedJavaScript = useCallback(() => {\n const script = `\\\n const options = {\\\n source: 'quiltt',\\\n type: 'Options',\\\n token: '${session?.token}',\\\n connectorId: '${connectorId}',\\\n connectionId: '${connectionId}',\\\n };\\\n const compactedOptions = Object.keys(options).reduce((acc, key) => {\\\n if (options[key] !== 'undefined') {\\\n acc[key] = options[key];\\\n }\\\n return acc;\\\n }, {});\\\n window.postMessage(compactedOptions);\\\n `\n webViewRef.current?.injectJavaScript(script)\n }, [connectionId, connectorId, session?.token])\n\n // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview\n // For other urls, we assume those are bank urls, which needs to be handle in external browser.\n // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.\n const allowedListUrl = useMemo(\n () => [\n 'quiltt.app',\n 'quiltt.dev',\n 'moneydesktop.com',\n 'cdn.plaid.com/link/v2/stable/link.html',\n ],\n []\n )\n\n const isQuilttEvent = useCallback((url: URL) => url.protocol === 'quilttconnector:', [])\n\n const shouldRender = useCallback(\n (url: URL) => {\n if (isQuilttEvent(url)) return false\n if (url.protocol !== 'https:') {\n const err = new Error(`Invalid url leaked ${url.href}`)\n errorReporter.send(err)\n return false\n }\n return allowedListUrl.some((href) => url.href.includes(href))\n },\n [allowedListUrl, isQuilttEvent]\n )\n\n const clearLocalStorage = () => {\n const script = 'localStorage.clear();'\n webViewRef.current?.injectJavaScript(script)\n }\n\n const handleOAuthUrl = useCallback((oauthUrl: URL) => {\n if (oauthUrl.protocol !== 'https:') {\n console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`)\n return\n }\n Linking.openURL(oauthUrl.href)\n }, [])\n\n const handleQuilttEvent = useCallback(\n (url: URL) => {\n url.searchParams.delete('source')\n url.searchParams.append('connectorId', connectorId)\n const metadata = Object.fromEntries(url.searchParams) as ConnectorSDKCallbackMetadata\n\n const eventType = url.host\n switch (eventType) {\n case 'Load':\n initInjectedJavaScript()\n onEvent?.(ConnectorSDKEventType.Load, metadata)\n onLoad?.(metadata)\n break\n case 'ExitAbort':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExit?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExitAbort?.(metadata)\n break\n case 'ExitError':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitError, metadata)\n onExit?.(ConnectorSDKEventType.ExitError, metadata)\n onExitError?.(metadata)\n break\n case 'ExitSuccess':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExitSuccess?.(metadata)\n break\n case 'Authenticate':\n // @todo handle Authenticate\n break\n case 'OauthRequested':\n handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))\n break\n default:\n console.log('unhandled event', url)\n break\n }\n },\n [\n connectorId,\n handleOAuthUrl,\n initInjectedJavaScript,\n onEvent,\n onExit,\n onExitAbort,\n onExitError,\n onExitSuccess,\n onLoad,\n ]\n )\n\n const requestHandler = useCallback(\n (request: ShouldStartLoadRequest) => {\n const url = new URL(request.url)\n\n if (isQuilttEvent(url)) {\n handleQuilttEvent(url)\n return false\n }\n if (shouldRender(url)) return true\n // Plaid set oauth url by doing window.location.href = url\n // So we use `handleOAuthUrl` as a catch all and assume all url got to this step is Plaid OAuth url\n handleOAuthUrl(url)\n return false\n },\n [handleOAuthUrl, handleQuilttEvent, isQuilttEvent, shouldRender]\n )\n\n if (!preFlightCheck.checked) return <LoadingScreen />\n if (preFlightCheck.error)\n return <ErrorScreen error={preFlightCheck.error} cta={() => onExitError?.({ connectorId })} />\n\n return (\n <AndroidSafeAreaView>\n <WebView\n ref={webViewRef}\n originWhitelist={['https://*', 'quilttconnector://*']} // Guard against other non SDK needed url\n source={{ uri: connectorUrl }}\n onShouldStartLoadWithRequest={requestHandler}\n javaScriptEnabled\n domStorageEnabled // To enable localStorage in Android webview\n webviewDebuggingEnabled\n />\n </AndroidSafeAreaView>\n )\n}\n\nexport default QuilttConnector\n","import { SafeAreaView, StyleSheet, Platform, StatusBar } from 'react-native'\nimport { PropsWithChildren } from 'react'\n\nexport const AndroidSafeAreaView = ({ children }: PropsWithChildren) => (\n <SafeAreaView style={styles.AndroidSafeArea}>{children}</SafeAreaView>\n)\n\nconst styles = StyleSheet.create({\n AndroidSafeArea: {\n flex: 1,\n backgroundColor: 'white',\n paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,\n },\n})\n","// Quick hack to send error to Honeybadger to debug why the connector is not routable\n\nimport type { Notice, NoticeTransportPayload } from '@honeybadger-io/core/build/src/types'\nimport { generateStackTrace, getCauses, makeBacktrace } from '@honeybadger-io/core/build/src/util'\n\nimport { ErrorReporterConfig } from './ErrorReporterConfig'\nimport { version } from '../version'\n\nconst notifier = {\n name: 'Quiltt React Native SDK Reporter',\n url: 'https://www.quiltt.dev/guides/connector/react-native',\n version: version,\n}\n\ntype HoneybadgerResponseData = {\n id: string\n}\n\nclass ErrorReporter {\n private noticeUrl: string\n private apiKey: string\n private clientName: string\n private clientVersion: string\n private platform: string\n private logger: Console\n private userAgent: string\n\n constructor(platform: string) {\n this.noticeUrl = 'https://api.honeybadger.io/v1/notices'\n this.apiKey = ErrorReporterConfig.honeybadger_api_key\n this.clientName = 'react-native-sdk'\n this.clientVersion = version\n this.platform = platform\n this.logger = console\n this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`\n }\n\n async send(error: Error, context?: any): Promise<void> {\n const headers = {\n 'X-API-Key': this.apiKey,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`,\n }\n\n const payload = await this.buildPayload(error, context)\n const method = 'POST'\n const body = JSON.stringify(payload)\n const mode = 'cors'\n\n fetch(this.noticeUrl, { headers, method, body, mode })\n .then((response) => {\n if (response.status !== 201) {\n this.logger.warn(\n `Error report failed: unknown response from server. code=${response.status}`\n )\n return\n }\n return response.json()\n })\n .then((data: HoneybadgerResponseData) => {\n if (data) {\n this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`)\n }\n })\n }\n\n async buildPayload(error: Error, localContext = {}): Promise<Partial<NoticeTransportPayload>> {\n const notice: Notice = error as Notice\n notice.stack = generateStackTrace()\n\n notice.backtrace = makeBacktrace(notice.stack)\n\n return {\n notifier,\n error: {\n class: notice.name as string,\n message: notice.message as string,\n backtrace: notice.backtrace,\n // fingerprint: this.calculateFingerprint(notice),\n tags: notice.tags || [],\n causes: getCauses(notice, this.logger),\n },\n request: {\n url: notice.url,\n component: notice.component,\n action: notice.action,\n context: localContext || {},\n cgi_data: {},\n params: {},\n session: {},\n },\n server: {\n project_root: notice.projectRoot,\n environment_name: this.userAgent,\n revision: version,\n hostname: this.platform,\n time: new Date().toUTCString(),\n },\n details: notice.details || {},\n }\n }\n}\n\nexport { ErrorReporter }","\nexport const ErrorReporterConfig = {\n honeybadger_api_key: 'undefined',\n}\n","// Generated by genversion.\nexport const version = '3.5.1'\n","const getErrorMessage = (responseStatus?: number, error?: Error): string => {\n if (error) return `An error occurred while checking the connector URL: ${error?.name} \\n${error?.message}`\n return responseStatus\n ? `The URL is not routable. Response status: ${responseStatus}`\n : 'An error occurred while checking the connector URL'\n}\n\nexport { getErrorMessage }\n","import { ActivityIndicator, View } from 'react-native'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\n\nexport const LoadingScreen = () => (\n <AndroidSafeAreaView>\n <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>\n <ActivityIndicator size=\"large\" color=\"#0000ff\" />\n </View>\n </AndroidSafeAreaView>\n)\n","import { View, Text, Pressable, StyleSheet } from 'react-native'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\n\ntype ErrorScreenProp = {\n error: string\n cta: () => void\n}\n\nexport const ErrorScreen = ({ error, cta }: ErrorScreenProp) => (\n <AndroidSafeAreaView>\n <View style={[styles.container, styles.padding]}>\n <View style={{ flex: 1, justifyContent: 'center' }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginVertical: 10,\n }}\n >\n <Text style={[styles.title]}>Cannot connect to the internet.</Text>\n </View>\n <Text style={[styles.subtitle]}>{error}</Text>\n </View>\n <Pressable style={[styles.pressable]} onPress={cta}>\n <Text style={[styles.pressableText]}>Exit</Text>\n </Pressable>\n </View>\n </AndroidSafeAreaView>\n)\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n flexDirection: 'column',\n justifyContent: 'flex-start',\n alignItems: 'stretch',\n backgroundColor: '#F3F4F6',\n },\n title: {\n color: '#1F2937',\n fontSize: 30,\n fontWeight: 'bold',\n },\n subtitle: {\n color: 'rgba(107, 114, 128, 1)',\n },\n padding: {\n paddingHorizontal: 16, // sm:px-4\n paddingVertical: 24, // sm:py-6\n },\n pressable: {\n marginTop: 20,\n backgroundColor: '#1F2937',\n padding: 10,\n paddingHorizontal: 25,\n borderRadius: 5,\n },\n pressableText: {\n color: '#fff',\n textAlign: 'center',\n },\n})\n"],"mappings":"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","names":["src_exports","__export","QuilttConnector_default","src_default","__toCommonJS","import_base_64","import_core","import_react","import_react_native","import_react_native_webview","import_react_native_url_polyfill","import_react_native","import_jsx_runtime","AndroidSafeAreaView","children","styles","import_react","import_util","ErrorReporterConfig","version","notifier","version","ErrorReporter","platform","__publicField","ErrorReporterConfig","error","context","__async","headers","payload","method","body","mode","response","data","_0","localContext","notice","getErrorMessage","responseStatus","error","import_react_native","import_jsx_runtime","LoadingScreen","AndroidSafeAreaView","import_react_native","import_jsx_runtime","ErrorScreen","error","cta","AndroidSafeAreaView","styles","import_jsx_runtime","errorReporter","ErrorReporter","PREFLIGHT_RETRY_COUNT","QuilttConnector","connectorId","connectionId","oauthRedirectUrl","onEvent","onLoad","onExit","onExitSuccess","onExitAbort","onExitError","webViewRef","session","connectorUrl","version","preFlightCheck","setPreFlightCheck","checkConnectorUrl","retryCount","__async","responseStatus","error","errorOccurred","response","e","resolve","errorMessage","getErrorMessage","errorToSend","context","connectorUrlStatus","initInjectedJavaScript","_a","script","allowedListUrl","isQuilttEvent","url","shouldRender","err","href","clearLocalStorage","handleOAuthUrl","oauthUrl","handleQuilttEvent","metadata","requestHandler","request","ErrorScreen","AndroidSafeAreaView","LoadingScreen","QuilttConnector_default","src_default","QuilttConnector_default"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,3 @@
1
- import{decode as J}from"base-64";import{ConnectorSDKEventType as o}from"@quiltt/core";import{useCallback as D,useRef as T}from"react";import{Linking as K}from"react-native";import{WebView as j}from"react-native-webview";import{URL as w}from"react-native-url-polyfill";import{SafeAreaView as P,StyleSheet as U,Platform as V,StatusBar as Q}from"react-native";import{jsx as $}from"react/jsx-runtime";var S=({children:c})=>$(P,{style:W.AndroidSafeArea,children:c}),W=U.create({AndroidSafeArea:{flex:1,backgroundColor:"white",paddingTop:V.OS==="android"?Q.currentHeight:0}});import{useQuilttSession as M}from"@quiltt/react";var k="3.4.0";import{jsx as g}from"react/jsx-runtime";var I=({connectorId:c,connectionId:m,oauthRedirectUrl:i,onEvent:r,onLoad:l,onExit:a,onExitSuccess:n,onExitAbort:p,onExitError:d})=>{let u=T(null),{session:s}=M();i=encodeURIComponent(i);let y=`https://${c}.quiltt.app/?mode=webview&oauth_redirect_url=${i}&agent=react-native-${k}`,A=D(()=>{var e;let t=` const options = { source: 'quiltt', type: 'Options', token: '${s==null?void 0:s.token}', connectorId: '${c}', connectionId: '${m}', }; const compactedOptions = Object.keys(options).reduce((acc, key) => { if (options[key] !== 'undefined') { acc[key] = options[key]; } return acc; }, {}); window.postMessage(compactedOptions); `;(e=u.current)==null||e.injectJavaScript(t)},[m,c,s==null?void 0:s.token]),R=["quiltt.app","quiltt.dev","moneydesktop.com","cdn.plaid.com/link/v2/stable/link.html"],q=t=>h(t)?!1:R.some(e=>t.href.includes(e)),L=t=>{let e=new w(t.url);return h(e)?(O(e),!1):q(e)?!0:(b(e),!1)},f=()=>{var e;let t="localStorage.clear();";(e=u.current)==null||e.injectJavaScript(t)},h=t=>t.protocol==="quilttconnector:",O=t=>{t.searchParams.delete("source"),t.searchParams.append("connectorId",c);let e=Object.fromEntries(t.searchParams);switch(t.host){case"Load":A(),r==null||r(o.Load,e),l==null||l(e);break;case"ExitAbort":f(),r==null||r(o.ExitAbort,e),a==null||a(o.ExitAbort,e),p==null||p(e);break;case"ExitError":f(),r==null||r(o.ExitError,e),a==null||a(o.ExitError,e),d==null||d(e);break;case"ExitSuccess":f(),r==null||r(o.ExitSuccess,e),a==null||a(o.ExitSuccess,e),n==null||n(e);break;case"Authenticate":break;case"OauthRequested":b(new w(t.searchParams.get("oauthUrl")));break;default:console.log("unhandled event",t);break}},b=t=>{if(t.protocol!=="https:"){console.log(`handleOAuthUrl - Skipping non https url - ${t.href}`);return}K.openURL(t.href)};return g(S,{children:g(j,{ref:u,originWhitelist:["https://*","quilttconnector://*"],source:{uri:y},onShouldStartLoadWithRequest:L,javaScriptEnabled:!0,domStorageEnabled:!0,webviewDebuggingEnabled:!0})})},C=I;global.atob||(global.atob=J);var se=C;export{C as QuilttConnector,se as default};
1
+ var E=Object.defineProperty;var ee=(s,r,i)=>r in s?E(s,r,{enumerable:!0,configurable:!0,writable:!0,value:i}):s[r]=i;var d=(s,r,i)=>(ee(s,typeof r!="symbol"?r+"":r,i),i);var y=(s,r,i)=>new Promise((n,a)=>{var c=o=>{try{l(i.next(o))}catch(f){a(f)}},p=o=>{try{l(i.throw(o))}catch(f){a(f)}},l=o=>o.done?n(o.value):Promise.resolve(o.value).then(c,p);l((i=i.apply(s,r)).next())});import{decode as Re}from"base-64";import{ConnectorSDKEventType as g}from"@quiltt/core";import{useCallback as u,useEffect as ue,useMemo as me,useRef as be,useState as ye}from"react";import{Linking as ke,Platform as z}from"react-native";import{WebView as Se}from"react-native-webview";import{URL as J}from"react-native-url-polyfill";import{SafeAreaView as te,StyleSheet as re,Platform as oe,StatusBar as ae}from"react-native";import{jsx as ie}from"react/jsx-runtime";var k=({children:s})=>ie(te,{style:se.AndroidSafeArea,children:s}),se=re.create({AndroidSafeArea:{flex:1,backgroundColor:"white",paddingTop:oe.OS==="android"?ae.currentHeight:0}});import{useQuilttSession as we}from"@quiltt/react";import{generateStackTrace as ne,getCauses as ce,makeBacktrace as le}from"@honeybadger-io/core/build/src/util";var I={honeybadger_api_key:"undefined"};var S="3.5.1";var pe={name:"Quiltt React Native SDK Reporter",url:"https://www.quiltt.dev/guides/connector/react-native",version:S},V=class{constructor(r){d(this,"noticeUrl");d(this,"apiKey");d(this,"clientName");d(this,"clientVersion");d(this,"platform");d(this,"logger");d(this,"userAgent");this.noticeUrl="https://api.honeybadger.io/v1/notices",this.apiKey=I.honeybadger_api_key,this.clientName="react-native-sdk",this.clientVersion=S,this.platform=r,this.logger=console,this.userAgent=`${this.clientName} ${this.clientVersion}; ${this.platform}`}send(r,i){return y(this,null,function*(){let n={"X-API-Key":this.apiKey,"Content-Type":"application/json",Accept:"application/json","User-Agent":`${this.clientName} ${this.clientVersion}; ${this.platform}`},a=yield this.buildPayload(r,i),c="POST",p=JSON.stringify(a),l="cors";fetch(this.noticeUrl,{headers:n,method:c,body:p,mode:l}).then(o=>{if(o.status!==201){this.logger.warn(`Error report failed: unknown response from server. code=${o.status}`);return}return o.json()}).then(o=>{o&&this.logger.info(`Error report sent \u26A1 https://app.honeybadger.io/notice/${o==null?void 0:o.id}`)})})}buildPayload(n){return y(this,arguments,function*(r,i={}){let a=r;return a.stack=ne(),a.backtrace=le(a.stack),{notifier:pe,error:{class:a.name,message:a.message,backtrace:a.backtrace,tags:a.tags||[],causes:ce(a,this.logger)},request:{url:a.url,component:a.component,action:a.action,context:i||{},cgi_data:{},params:{},session:{}},server:{project_root:a.projectRoot,environment_name:this.userAgent,revision:S,hostname:this.platform,time:new Date().toUTCString()},details:a.details||{}}})}};var Q=(s,r)=>r?`An error occurred while checking the connector URL: ${r==null?void 0:r.name}
2
+ ${r==null?void 0:r.message}`:s?`The URL is not routable. Response status: ${s}`:"An error occurred while checking the connector URL";import{ActivityIndicator as de,View as fe}from"react-native";import{jsx as D}from"react/jsx-runtime";var W=()=>D(k,{children:D(fe,{style:{flex:1,justifyContent:"center",alignItems:"center"},children:D(de,{size:"large",color:"#0000ff"})})});import{View as O,Text as q,Pressable as he,StyleSheet as ge}from"react-native";import{jsx as A,jsxs as H}from"react/jsx-runtime";var M=({error:s,cta:r})=>A(k,{children:H(O,{style:[w.container,w.padding],children:[H(O,{style:{flex:1,justifyContent:"center"},children:[A(O,{style:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginVertical:10},children:A(q,{style:[w.title],children:"Cannot connect to the internet."})}),A(q,{style:[w.subtitle],children:s})]}),A(he,{style:[w.pressable],onPress:r,children:A(q,{style:[w.pressableText],children:"Exit"})})]})}),w=ge.create({container:{flex:1,flexDirection:"column",justifyContent:"flex-start",alignItems:"stretch",backgroundColor:"#F3F4F6"},title:{color:"#1F2937",fontSize:30,fontWeight:"bold"},subtitle:{color:"rgba(107, 114, 128, 1)"},padding:{paddingHorizontal:16,paddingVertical:24},pressable:{marginTop:20,backgroundColor:"#1F2937",padding:10,paddingHorizontal:25,borderRadius:5},pressableText:{color:"#fff",textAlign:"center"}});import{jsx as $}from"react/jsx-runtime";var B=new V(`${z.OS} ${z.Version}`),Ae=3,Ce=({connectorId:s,connectionId:r,oauthRedirectUrl:i,onEvent:n,onLoad:a,onExit:c,onExitSuccess:p,onExitAbort:l,onExitError:o})=>{let f=be(null),{session:m}=we();i=encodeURIComponent(i);let h=`https://${s}.quiltt.app/?mode=webview&oauth_redirect_url=${i}&agent=react-native-${S}`;console.log("connectorUrl",h);let[C,X]=ye({checked:!1}),U=u((t=0)=>y(void 0,null,function*(){let e,R,L=!1;try{let b=yield fetch(h);if(!b.ok)console.error(`The URL ${h} is not routable.`),e=b.status,L=!0;else return console.log(`The URL ${h} is routable.`),{checked:!0}}catch(b){R=b,console.error(`An error occurred while checking the connector URL: ${R}`),L=!0}if(L&&t<Ae)return yield new Promise(b=>setTimeout(b,50*t)),console.log(`Retrying... Attempt number ${t+1}`),U(t+1);let _=Q(e,R),x=R||new Error(_),Z={connectorUrl:h,responseStatus:e};return e!==404&&B.send(x,Z),{checked:!0,error:_}}),[h]);ue(()=>{if(C.checked)return;(()=>y(void 0,null,function*(){let e=yield U();X(e)}))()},[U,C]);let N=u(()=>{var e;let t=` const options = { source: 'quiltt', type: 'Options', token: '${m==null?void 0:m.token}', connectorId: '${s}', connectionId: '${r}', }; const compactedOptions = Object.keys(options).reduce((acc, key) => { if (options[key] !== 'undefined') { acc[key] = options[key]; } return acc; }, {}); window.postMessage(compactedOptions); `;(e=f.current)==null||e.injectJavaScript(t)},[r,s,m==null?void 0:m.token]),j=me(()=>["quiltt.app","quiltt.dev","moneydesktop.com","cdn.plaid.com/link/v2/stable/link.html"],[]),P=u(t=>t.protocol==="quilttconnector:",[]),F=u(t=>{if(P(t))return!1;if(t.protocol!=="https:"){let e=new Error(`Invalid url leaked ${t.href}`);return B.send(e),!1}return j.some(e=>t.href.includes(e))},[j,P]),v=()=>{var e;let t="localStorage.clear();";(e=f.current)==null||e.injectJavaScript(t)},T=u(t=>{if(t.protocol!=="https:"){console.log(`handleOAuthUrl - Skipping non https url - ${t.href}`);return}ke.openURL(t.href)},[]),K=u(t=>{t.searchParams.delete("source"),t.searchParams.append("connectorId",s);let e=Object.fromEntries(t.searchParams);switch(t.host){case"Load":N(),n==null||n(g.Load,e),a==null||a(e);break;case"ExitAbort":v(),n==null||n(g.ExitAbort,e),c==null||c(g.ExitAbort,e),l==null||l(e);break;case"ExitError":v(),n==null||n(g.ExitError,e),c==null||c(g.ExitError,e),o==null||o(e);break;case"ExitSuccess":v(),n==null||n(g.ExitSuccess,e),c==null||c(g.ExitSuccess,e),p==null||p(e);break;case"Authenticate":break;case"OauthRequested":T(new J(t.searchParams.get("oauthUrl")));break;default:console.log("unhandled event",t);break}},[s,T,N,n,c,l,o,p,a]),Y=u(t=>{let e=new J(t.url);return P(e)?(K(e),!1):F(e)?!0:(T(e),!1)},[T,K,P,F]);return C.checked?C.error?$(M,{error:C.error,cta:()=>o==null?void 0:o({connectorId:s})}):$(k,{children:$(Se,{ref:f,originWhitelist:["https://*","quilttconnector://*"],source:{uri:h},onShouldStartLoadWithRequest:Y,javaScriptEnabled:!0,domStorageEnabled:!0,webviewDebuggingEnabled:!0})}):$(W,{})},G=Ce;global.atob||(global.atob=Re);var ft=G;export{G as QuilttConnector,ft as default};
2
3
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/QuilttConnector.tsx","../src/components/AndroidSafeAreaView.tsx","../src/version.ts"],"sourcesContent":["// Hermes doesn't have atob\n// https://github.com/facebook/hermes/issues/1178\nimport { decode } from 'base-64'\nif (!global.atob) {\n global.atob = decode\n}\nimport QuilttConnector from './components/QuilttConnector'\n\nexport { QuilttConnector }\nexport default QuilttConnector\n","import {\n ConnectorSDKCallbackMetadata,\n ConnectorSDKCallbacks,\n ConnectorSDKEventType,\n} from '@quiltt/core'\nimport { useCallback, useRef } from 'react'\nimport { Linking } from 'react-native'\nimport { WebView } from 'react-native-webview'\n// React Native's URL implementation is incomplete\n// https://github.com/facebook/react-native/issues/16434\nimport { URL } from 'react-native-url-polyfill'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\nimport type { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes'\nimport { useQuilttSession } from '@quiltt/react'\nimport { version } from '../version'\n\ntype QuilttConnectorProps = {\n connectorId: string\n connectionId?: string\n oauthRedirectUrl: string\n} & ConnectorSDKCallbacks\n\nexport const QuilttConnector = ({\n connectorId,\n connectionId,\n oauthRedirectUrl,\n onEvent,\n onLoad,\n onExit,\n onExitSuccess,\n onExitAbort,\n onExitError,\n}: QuilttConnectorProps) => {\n const webViewRef = useRef<WebView>(null)\n const { session } = useQuilttSession()\n oauthRedirectUrl = encodeURIComponent(oauthRedirectUrl)\n const connectorUrl = `https://${connectorId}.quiltt.app/?mode=webview&oauth_redirect_url=${oauthRedirectUrl}&agent=react-native-${version}`\n\n const initInjectedJavaScript = useCallback(() => {\n const script = `\\\n const options = {\\\n source: 'quiltt',\\\n type: 'Options',\\\n token: '${session?.token}',\\\n connectorId: '${connectorId}',\\\n connectionId: '${connectionId}',\\\n };\\\n const compactedOptions = Object.keys(options).reduce((acc, key) => {\\\n if (options[key] !== 'undefined') {\\\n acc[key] = options[key];\\\n }\\\n return acc;\\\n }, {});\\\n window.postMessage(compactedOptions);\\\n `\n webViewRef.current?.injectJavaScript(script)\n }, [connectionId, connectorId, session?.token])\n\n // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview\n // For other urls, we assume those are bank urls, which needs to be handle in external browser.\n // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.\n const allowedListUrl = [\n 'quiltt.app',\n 'quiltt.dev',\n 'moneydesktop.com',\n 'cdn.plaid.com/link/v2/stable/link.html',\n ]\n const shouldRender = (url: URL) => {\n if (isQuilttEvent(url)) return false\n return allowedListUrl.some((href) => url.href.includes(href))\n }\n\n const requestHandler = (request: ShouldStartLoadRequest) => {\n const url = new URL(request.url)\n if (isQuilttEvent(url)) {\n handleQuilttEvent(url)\n return false\n }\n if (shouldRender(url)) return true\n // Plaid set oauth url by doing window.location.href = url\n // This is the only way I know to handle this.\n handleOAuthUrl(url)\n return false\n }\n\n const clearLocalStorage = () => {\n const script = 'localStorage.clear();'\n webViewRef.current?.injectJavaScript(script)\n }\n\n const isQuilttEvent = (url: URL) => url.protocol === 'quilttconnector:'\n\n const handleQuilttEvent = (url: URL) => {\n url.searchParams.delete('source')\n url.searchParams.append('connectorId', connectorId)\n const metadata = Object.fromEntries(url.searchParams) as ConnectorSDKCallbackMetadata\n\n const eventType = url.host\n switch (eventType) {\n case 'Load':\n initInjectedJavaScript()\n onEvent?.(ConnectorSDKEventType.Load, metadata)\n onLoad?.(metadata)\n break\n case 'ExitAbort':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExit?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExitAbort?.(metadata)\n break\n case 'ExitError':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitError, metadata)\n onExit?.(ConnectorSDKEventType.ExitError, metadata)\n onExitError?.(metadata)\n break\n case 'ExitSuccess':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExitSuccess?.(metadata)\n break\n case 'Authenticate':\n // @todo handle Authenticate\n break\n case 'OauthRequested':\n handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))\n break\n default:\n console.log('unhandled event', url)\n break\n }\n }\n\n const handleOAuthUrl = (oauthUrl: URL) => {\n if (oauthUrl.protocol !== 'https:') {\n console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`)\n return\n }\n Linking.openURL(oauthUrl.href)\n }\n\n return (\n <AndroidSafeAreaView>\n <WebView\n ref={webViewRef}\n originWhitelist={['https://*', 'quilttconnector://*']} // Maybe relax this to *?\n source={{ uri: connectorUrl }}\n onShouldStartLoadWithRequest={requestHandler}\n javaScriptEnabled\n domStorageEnabled // To enable localStorage in Android webview\n webviewDebuggingEnabled // Not sure if this works\n />\n </AndroidSafeAreaView>\n )\n}\n\nexport default QuilttConnector\n","import { SafeAreaView, StyleSheet, Platform, StatusBar } from 'react-native'\nimport { PropsWithChildren } from 'react'\n\nexport const AndroidSafeAreaView = ({ children }: PropsWithChildren) => (\n <SafeAreaView style={styles.AndroidSafeArea}>{children}</SafeAreaView>\n)\n\nconst styles = StyleSheet.create({\n AndroidSafeArea: {\n flex: 1,\n backgroundColor: 'white',\n paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,\n },\n})\n","// Generated by genversion.\nexport const version = '3.4.0'\n"],"mappings":"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","names":["decode","ConnectorSDKEventType","useCallback","useRef","Linking","WebView","URL","SafeAreaView","StyleSheet","Platform","StatusBar","jsx","AndroidSafeAreaView","children","styles","useQuilttSession","version","jsx","QuilttConnector","connectorId","connectionId","oauthRedirectUrl","onEvent","onLoad","onExit","onExitSuccess","onExitAbort","onExitError","webViewRef","useRef","session","useQuilttSession","connectorUrl","version","initInjectedJavaScript","useCallback","_a","script","allowedListUrl","shouldRender","url","isQuilttEvent","href","requestHandler","request","URL","handleQuilttEvent","handleOAuthUrl","clearLocalStorage","metadata","ConnectorSDKEventType","oauthUrl","Linking","AndroidSafeAreaView","WebView","QuilttConnector_default","decode","src_default","QuilttConnector_default"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/QuilttConnector.tsx","../src/components/AndroidSafeAreaView.tsx","../src/utils/ErrorReporter.ts","../src/utils/ErrorReporterConfig.ts","../src/version.ts","../src/utils/getErrorMessage.ts","../src/components/LoadingScreen.tsx","../src/components/ErrorScreen.tsx"],"sourcesContent":["// Hermes doesn't have atob\n// https://github.com/facebook/hermes/issues/1178\nimport { decode } from 'base-64'\nif (!global.atob) {\n global.atob = decode\n}\nimport QuilttConnector from './components/QuilttConnector'\n\nexport { QuilttConnector }\nexport default QuilttConnector\n","import {\n ConnectorSDKCallbackMetadata,\n ConnectorSDKCallbacks,\n ConnectorSDKEventType,\n} from '@quiltt/core'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { Linking, Platform } from 'react-native'\nimport { WebView } from 'react-native-webview'\n// React Native's URL implementation is incomplete\n// https://github.com/facebook/react-native/issues/16434\nimport { URL } from 'react-native-url-polyfill'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\nimport type { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes'\nimport { useQuilttSession } from '@quiltt/react'\nimport { ErrorReporter, getErrorMessage } from '../utils/'\n\nimport { version } from '../version'\nimport { LoadingScreen } from './LoadingScreen'\nimport { ErrorScreen } from './ErrorScreen'\n\nconst errorReporter = new ErrorReporter(`${Platform.OS} ${Platform.Version}`)\n\ntype QuilttConnectorProps = {\n connectorId: string\n connectionId?: string\n oauthRedirectUrl: string\n} & ConnectorSDKCallbacks\n\ntype PreFlightCheck = {\n checked: boolean\n error?: string\n}\n\nconst PREFLIGHT_RETRY_COUNT = 3\n\nexport const QuilttConnector = ({\n connectorId,\n connectionId,\n oauthRedirectUrl,\n onEvent,\n onLoad,\n onExit,\n onExitSuccess,\n onExitAbort,\n onExitError,\n}: QuilttConnectorProps) => {\n const webViewRef = useRef<WebView>(null)\n const { session } = useQuilttSession()\n oauthRedirectUrl = encodeURIComponent(oauthRedirectUrl)\n const connectorUrl = `https://${connectorId}.quiltt.app/?mode=webview&oauth_redirect_url=${oauthRedirectUrl}&agent=react-native-${version}`\n console.log('connectorUrl', connectorUrl)\n const [preFlightCheck, setPreFlightCheck] = useState<PreFlightCheck>({ checked: false })\n\n const checkConnectorUrl = useCallback(\n async (retryCount = 0): Promise<PreFlightCheck> => {\n let responseStatus\n let error\n let errorOccurred = false\n try {\n const response = await fetch(connectorUrl)\n if (!response.ok) {\n console.error(`The URL ${connectorUrl} is not routable.`)\n responseStatus = response.status\n errorOccurred = true\n } else {\n console.log(`The URL ${connectorUrl} is routable.`)\n return { checked: true }\n }\n } catch (e) {\n error = e\n console.error(`An error occurred while checking the connector URL: ${error}`)\n errorOccurred = true\n }\n\n // Retry logic in case of error or response not OK\n if (errorOccurred && retryCount < PREFLIGHT_RETRY_COUNT) {\n await new Promise((resolve) => setTimeout(resolve, 50 * retryCount)) // delay for 50ms for each retry\n console.log(`Retrying... Attempt number ${retryCount + 1}`)\n return checkConnectorUrl(retryCount + 1)\n }\n\n const errorMessage = getErrorMessage(responseStatus, error as Error)\n const errorToSend = (error as Error) || new Error(errorMessage)\n const context = { connectorUrl, responseStatus }\n if (responseStatus !== 404) errorReporter.send(errorToSend, context)\n return { checked: true, error: errorMessage }\n },\n [connectorUrl]\n )\n\n useEffect(() => {\n if (preFlightCheck.checked) return\n const fetchDataAndSetState = async () => {\n const connectorUrlStatus = await checkConnectorUrl()\n setPreFlightCheck(connectorUrlStatus)\n }\n fetchDataAndSetState()\n }, [checkConnectorUrl, preFlightCheck])\n\n const initInjectedJavaScript = useCallback(() => {\n const script = `\\\n const options = {\\\n source: 'quiltt',\\\n type: 'Options',\\\n token: '${session?.token}',\\\n connectorId: '${connectorId}',\\\n connectionId: '${connectionId}',\\\n };\\\n const compactedOptions = Object.keys(options).reduce((acc, key) => {\\\n if (options[key] !== 'undefined') {\\\n acc[key] = options[key];\\\n }\\\n return acc;\\\n }, {});\\\n window.postMessage(compactedOptions);\\\n `\n webViewRef.current?.injectJavaScript(script)\n }, [connectionId, connectorId, session?.token])\n\n // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview\n // For other urls, we assume those are bank urls, which needs to be handle in external browser.\n // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.\n const allowedListUrl = useMemo(\n () => [\n 'quiltt.app',\n 'quiltt.dev',\n 'moneydesktop.com',\n 'cdn.plaid.com/link/v2/stable/link.html',\n ],\n []\n )\n\n const isQuilttEvent = useCallback((url: URL) => url.protocol === 'quilttconnector:', [])\n\n const shouldRender = useCallback(\n (url: URL) => {\n if (isQuilttEvent(url)) return false\n if (url.protocol !== 'https:') {\n const err = new Error(`Invalid url leaked ${url.href}`)\n errorReporter.send(err)\n return false\n }\n return allowedListUrl.some((href) => url.href.includes(href))\n },\n [allowedListUrl, isQuilttEvent]\n )\n\n const clearLocalStorage = () => {\n const script = 'localStorage.clear();'\n webViewRef.current?.injectJavaScript(script)\n }\n\n const handleOAuthUrl = useCallback((oauthUrl: URL) => {\n if (oauthUrl.protocol !== 'https:') {\n console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`)\n return\n }\n Linking.openURL(oauthUrl.href)\n }, [])\n\n const handleQuilttEvent = useCallback(\n (url: URL) => {\n url.searchParams.delete('source')\n url.searchParams.append('connectorId', connectorId)\n const metadata = Object.fromEntries(url.searchParams) as ConnectorSDKCallbackMetadata\n\n const eventType = url.host\n switch (eventType) {\n case 'Load':\n initInjectedJavaScript()\n onEvent?.(ConnectorSDKEventType.Load, metadata)\n onLoad?.(metadata)\n break\n case 'ExitAbort':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExit?.(ConnectorSDKEventType.ExitAbort, metadata)\n onExitAbort?.(metadata)\n break\n case 'ExitError':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitError, metadata)\n onExit?.(ConnectorSDKEventType.ExitError, metadata)\n onExitError?.(metadata)\n break\n case 'ExitSuccess':\n clearLocalStorage()\n onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)\n onExitSuccess?.(metadata)\n break\n case 'Authenticate':\n // @todo handle Authenticate\n break\n case 'OauthRequested':\n handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))\n break\n default:\n console.log('unhandled event', url)\n break\n }\n },\n [\n connectorId,\n handleOAuthUrl,\n initInjectedJavaScript,\n onEvent,\n onExit,\n onExitAbort,\n onExitError,\n onExitSuccess,\n onLoad,\n ]\n )\n\n const requestHandler = useCallback(\n (request: ShouldStartLoadRequest) => {\n const url = new URL(request.url)\n\n if (isQuilttEvent(url)) {\n handleQuilttEvent(url)\n return false\n }\n if (shouldRender(url)) return true\n // Plaid set oauth url by doing window.location.href = url\n // So we use `handleOAuthUrl` as a catch all and assume all url got to this step is Plaid OAuth url\n handleOAuthUrl(url)\n return false\n },\n [handleOAuthUrl, handleQuilttEvent, isQuilttEvent, shouldRender]\n )\n\n if (!preFlightCheck.checked) return <LoadingScreen />\n if (preFlightCheck.error)\n return <ErrorScreen error={preFlightCheck.error} cta={() => onExitError?.({ connectorId })} />\n\n return (\n <AndroidSafeAreaView>\n <WebView\n ref={webViewRef}\n originWhitelist={['https://*', 'quilttconnector://*']} // Guard against other non SDK needed url\n source={{ uri: connectorUrl }}\n onShouldStartLoadWithRequest={requestHandler}\n javaScriptEnabled\n domStorageEnabled // To enable localStorage in Android webview\n webviewDebuggingEnabled\n />\n </AndroidSafeAreaView>\n )\n}\n\nexport default QuilttConnector\n","import { SafeAreaView, StyleSheet, Platform, StatusBar } from 'react-native'\nimport { PropsWithChildren } from 'react'\n\nexport const AndroidSafeAreaView = ({ children }: PropsWithChildren) => (\n <SafeAreaView style={styles.AndroidSafeArea}>{children}</SafeAreaView>\n)\n\nconst styles = StyleSheet.create({\n AndroidSafeArea: {\n flex: 1,\n backgroundColor: 'white',\n paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,\n },\n})\n","// Quick hack to send error to Honeybadger to debug why the connector is not routable\n\nimport type { Notice, NoticeTransportPayload } from '@honeybadger-io/core/build/src/types'\nimport { generateStackTrace, getCauses, makeBacktrace } from '@honeybadger-io/core/build/src/util'\n\nimport { ErrorReporterConfig } from './ErrorReporterConfig'\nimport { version } from '../version'\n\nconst notifier = {\n name: 'Quiltt React Native SDK Reporter',\n url: 'https://www.quiltt.dev/guides/connector/react-native',\n version: version,\n}\n\ntype HoneybadgerResponseData = {\n id: string\n}\n\nclass ErrorReporter {\n private noticeUrl: string\n private apiKey: string\n private clientName: string\n private clientVersion: string\n private platform: string\n private logger: Console\n private userAgent: string\n\n constructor(platform: string) {\n this.noticeUrl = 'https://api.honeybadger.io/v1/notices'\n this.apiKey = ErrorReporterConfig.honeybadger_api_key\n this.clientName = 'react-native-sdk'\n this.clientVersion = version\n this.platform = platform\n this.logger = console\n this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`\n }\n\n async send(error: Error, context?: any): Promise<void> {\n const headers = {\n 'X-API-Key': this.apiKey,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`,\n }\n\n const payload = await this.buildPayload(error, context)\n const method = 'POST'\n const body = JSON.stringify(payload)\n const mode = 'cors'\n\n fetch(this.noticeUrl, { headers, method, body, mode })\n .then((response) => {\n if (response.status !== 201) {\n this.logger.warn(\n `Error report failed: unknown response from server. code=${response.status}`\n )\n return\n }\n return response.json()\n })\n .then((data: HoneybadgerResponseData) => {\n if (data) {\n this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`)\n }\n })\n }\n\n async buildPayload(error: Error, localContext = {}): Promise<Partial<NoticeTransportPayload>> {\n const notice: Notice = error as Notice\n notice.stack = generateStackTrace()\n\n notice.backtrace = makeBacktrace(notice.stack)\n\n return {\n notifier,\n error: {\n class: notice.name as string,\n message: notice.message as string,\n backtrace: notice.backtrace,\n // fingerprint: this.calculateFingerprint(notice),\n tags: notice.tags || [],\n causes: getCauses(notice, this.logger),\n },\n request: {\n url: notice.url,\n component: notice.component,\n action: notice.action,\n context: localContext || {},\n cgi_data: {},\n params: {},\n session: {},\n },\n server: {\n project_root: notice.projectRoot,\n environment_name: this.userAgent,\n revision: version,\n hostname: this.platform,\n time: new Date().toUTCString(),\n },\n details: notice.details || {},\n }\n }\n}\n\nexport { ErrorReporter }","\nexport const ErrorReporterConfig = {\n honeybadger_api_key: 'undefined',\n}\n","// Generated by genversion.\nexport const version = '3.5.1'\n","const getErrorMessage = (responseStatus?: number, error?: Error): string => {\n if (error) return `An error occurred while checking the connector URL: ${error?.name} \\n${error?.message}`\n return responseStatus\n ? `The URL is not routable. Response status: ${responseStatus}`\n : 'An error occurred while checking the connector URL'\n}\n\nexport { getErrorMessage }\n","import { ActivityIndicator, View } from 'react-native'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\n\nexport const LoadingScreen = () => (\n <AndroidSafeAreaView>\n <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>\n <ActivityIndicator size=\"large\" color=\"#0000ff\" />\n </View>\n </AndroidSafeAreaView>\n)\n","import { View, Text, Pressable, StyleSheet } from 'react-native'\nimport { AndroidSafeAreaView } from './AndroidSafeAreaView'\n\ntype ErrorScreenProp = {\n error: string\n cta: () => void\n}\n\nexport const ErrorScreen = ({ error, cta }: ErrorScreenProp) => (\n <AndroidSafeAreaView>\n <View style={[styles.container, styles.padding]}>\n <View style={{ flex: 1, justifyContent: 'center' }}>\n <View\n style={{\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginVertical: 10,\n }}\n >\n <Text style={[styles.title]}>Cannot connect to the internet.</Text>\n </View>\n <Text style={[styles.subtitle]}>{error}</Text>\n </View>\n <Pressable style={[styles.pressable]} onPress={cta}>\n <Text style={[styles.pressableText]}>Exit</Text>\n </Pressable>\n </View>\n </AndroidSafeAreaView>\n)\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n flexDirection: 'column',\n justifyContent: 'flex-start',\n alignItems: 'stretch',\n backgroundColor: '#F3F4F6',\n },\n title: {\n color: '#1F2937',\n fontSize: 30,\n fontWeight: 'bold',\n },\n subtitle: {\n color: 'rgba(107, 114, 128, 1)',\n },\n padding: {\n paddingHorizontal: 16, // sm:px-4\n paddingVertical: 24, // sm:py-6\n },\n pressable: {\n marginTop: 20,\n backgroundColor: '#1F2937',\n padding: 10,\n paddingHorizontal: 25,\n borderRadius: 5,\n },\n pressableText: {\n color: '#fff',\n textAlign: 'center',\n },\n})\n"],"mappings":"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","names":["decode","ConnectorSDKEventType","useCallback","useEffect","useMemo","useRef","useState","Linking","Platform","WebView","URL","SafeAreaView","StyleSheet","Platform","StatusBar","jsx","AndroidSafeAreaView","children","styles","useQuilttSession","generateStackTrace","getCauses","makeBacktrace","ErrorReporterConfig","version","notifier","version","ErrorReporter","platform","__publicField","ErrorReporterConfig","error","context","__async","headers","payload","method","body","mode","response","data","_0","localContext","notice","generateStackTrace","makeBacktrace","getCauses","getErrorMessage","responseStatus","error","ActivityIndicator","View","jsx","LoadingScreen","AndroidSafeAreaView","View","ActivityIndicator","View","Text","Pressable","StyleSheet","jsx","jsxs","ErrorScreen","error","cta","AndroidSafeAreaView","View","styles","Text","Pressable","StyleSheet","jsx","errorReporter","ErrorReporter","Platform","PREFLIGHT_RETRY_COUNT","QuilttConnector","connectorId","connectionId","oauthRedirectUrl","onEvent","onLoad","onExit","onExitSuccess","onExitAbort","onExitError","webViewRef","useRef","session","useQuilttSession","connectorUrl","version","preFlightCheck","setPreFlightCheck","useState","checkConnectorUrl","useCallback","retryCount","__async","responseStatus","error","errorOccurred","response","e","resolve","errorMessage","getErrorMessage","errorToSend","context","useEffect","connectorUrlStatus","initInjectedJavaScript","_a","script","allowedListUrl","useMemo","isQuilttEvent","url","shouldRender","err","href","clearLocalStorage","handleOAuthUrl","oauthUrl","Linking","handleQuilttEvent","metadata","ConnectorSDKEventType","URL","requestHandler","request","ErrorScreen","AndroidSafeAreaView","WebView","LoadingScreen","QuilttConnector_default","decode","src_default","QuilttConnector_default"]}
@@ -0,0 +1,18 @@
1
+ import { NoticeTransportPayload } from '@honeybadger-io/core/build/src/types';
2
+
3
+ declare class ErrorReporter {
4
+ private noticeUrl;
5
+ private apiKey;
6
+ private clientName;
7
+ private clientVersion;
8
+ private platform;
9
+ private logger;
10
+ private userAgent;
11
+ constructor(platform: string);
12
+ send(error: Error, context?: any): Promise<void>;
13
+ buildPayload(error: Error, localContext?: {}): Promise<Partial<NoticeTransportPayload>>;
14
+ }
15
+
16
+ declare const getErrorMessage: (responseStatus?: number, error?: Error) => string;
17
+
18
+ export { ErrorReporter, getErrorMessage };
@@ -0,0 +1,3 @@
1
+ "use strict";var p=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var k=(o,e,r)=>e in o?p(o,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):o[e]=r;var N=(o,e)=>{for(var r in e)p(o,r,{get:e[r],enumerable:!0})},$=(o,e,r,s)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of v(e))!b.call(o,t)&&t!==r&&p(o,t,{get:()=>e[t],enumerable:!(s=f(e,t))||s.enumerable});return o};var R=o=>$(p({},"__esModule",{value:!0}),o);var n=(o,e,r)=>(k(o,typeof e!="symbol"?e+"":e,r),r);var d=(o,e,r)=>new Promise((s,t)=>{var l=i=>{try{c(r.next(i))}catch(m){t(m)}},h=i=>{try{c(r.throw(i))}catch(m){t(m)}},c=i=>i.done?s(i.value):Promise.resolve(i.value).then(l,h);c((r=r.apply(o,e)).next())});var A={};N(A,{ErrorReporter:()=>u,getErrorMessage:()=>P});module.exports=R(A);var a=require("@honeybadger-io/core/build/src/util");var y={honeybadger_api_key:"undefined"};var g="3.5.1";var w={name:"Quiltt React Native SDK Reporter",url:"https://www.quiltt.dev/guides/connector/react-native",version:g},u=class{constructor(e){n(this,"noticeUrl");n(this,"apiKey");n(this,"clientName");n(this,"clientVersion");n(this,"platform");n(this,"logger");n(this,"userAgent");this.noticeUrl="https://api.honeybadger.io/v1/notices",this.apiKey=y.honeybadger_api_key,this.clientName="react-native-sdk",this.clientVersion=g,this.platform=e,this.logger=console,this.userAgent=`${this.clientName} ${this.clientVersion}; ${this.platform}`}send(e,r){return d(this,null,function*(){let s={"X-API-Key":this.apiKey,"Content-Type":"application/json",Accept:"application/json","User-Agent":`${this.clientName} ${this.clientVersion}; ${this.platform}`},t=yield this.buildPayload(e,r),l="POST",h=JSON.stringify(t),c="cors";fetch(this.noticeUrl,{headers:s,method:l,body:h,mode:c}).then(i=>{if(i.status!==201){this.logger.warn(`Error report failed: unknown response from server. code=${i.status}`);return}return i.json()}).then(i=>{i&&this.logger.info(`Error report sent \u26A1 https://app.honeybadger.io/notice/${i==null?void 0:i.id}`)})})}buildPayload(s){return d(this,arguments,function*(e,r={}){let t=e;return t.stack=(0,a.generateStackTrace)(),t.backtrace=(0,a.makeBacktrace)(t.stack),{notifier:w,error:{class:t.name,message:t.message,backtrace:t.backtrace,tags:t.tags||[],causes:(0,a.getCauses)(t,this.logger)},request:{url:t.url,component:t.component,action:t.action,context:r||{},cgi_data:{},params:{},session:{}},server:{project_root:t.projectRoot,environment_name:this.userAgent,revision:g,hostname:this.platform,time:new Date().toUTCString()},details:t.details||{}}})}};var P=(o,e)=>e?`An error occurred while checking the connector URL: ${e==null?void 0:e.name}
2
+ ${e==null?void 0:e.message}`:o?`The URL is not routable. Response status: ${o}`:"An error occurred while checking the connector URL";0&&(module.exports={ErrorReporter,getErrorMessage});
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/index.ts","../../src/utils/ErrorReporter.ts","../../src/utils/ErrorReporterConfig.ts","../../src/version.ts","../../src/utils/getErrorMessage.ts"],"sourcesContent":["export * from './ErrorReporter'\nexport * from './getErrorMessage'\n","// Quick hack to send error to Honeybadger to debug why the connector is not routable\n\nimport type { Notice, NoticeTransportPayload } from '@honeybadger-io/core/build/src/types'\nimport { generateStackTrace, getCauses, makeBacktrace } from '@honeybadger-io/core/build/src/util'\n\nimport { ErrorReporterConfig } from './ErrorReporterConfig'\nimport { version } from '../version'\n\nconst notifier = {\n name: 'Quiltt React Native SDK Reporter',\n url: 'https://www.quiltt.dev/guides/connector/react-native',\n version: version,\n}\n\ntype HoneybadgerResponseData = {\n id: string\n}\n\nclass ErrorReporter {\n private noticeUrl: string\n private apiKey: string\n private clientName: string\n private clientVersion: string\n private platform: string\n private logger: Console\n private userAgent: string\n\n constructor(platform: string) {\n this.noticeUrl = 'https://api.honeybadger.io/v1/notices'\n this.apiKey = ErrorReporterConfig.honeybadger_api_key\n this.clientName = 'react-native-sdk'\n this.clientVersion = version\n this.platform = platform\n this.logger = console\n this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`\n }\n\n async send(error: Error, context?: any): Promise<void> {\n const headers = {\n 'X-API-Key': this.apiKey,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`,\n }\n\n const payload = await this.buildPayload(error, context)\n const method = 'POST'\n const body = JSON.stringify(payload)\n const mode = 'cors'\n\n fetch(this.noticeUrl, { headers, method, body, mode })\n .then((response) => {\n if (response.status !== 201) {\n this.logger.warn(\n `Error report failed: unknown response from server. code=${response.status}`\n )\n return\n }\n return response.json()\n })\n .then((data: HoneybadgerResponseData) => {\n if (data) {\n this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`)\n }\n })\n }\n\n async buildPayload(error: Error, localContext = {}): Promise<Partial<NoticeTransportPayload>> {\n const notice: Notice = error as Notice\n notice.stack = generateStackTrace()\n\n notice.backtrace = makeBacktrace(notice.stack)\n\n return {\n notifier,\n error: {\n class: notice.name as string,\n message: notice.message as string,\n backtrace: notice.backtrace,\n // fingerprint: this.calculateFingerprint(notice),\n tags: notice.tags || [],\n causes: getCauses(notice, this.logger),\n },\n request: {\n url: notice.url,\n component: notice.component,\n action: notice.action,\n context: localContext || {},\n cgi_data: {},\n params: {},\n session: {},\n },\n server: {\n project_root: notice.projectRoot,\n environment_name: this.userAgent,\n revision: version,\n hostname: this.platform,\n time: new Date().toUTCString(),\n },\n details: notice.details || {},\n }\n }\n}\n\nexport { ErrorReporter }","\nexport const ErrorReporterConfig = {\n honeybadger_api_key: 'undefined',\n}\n","// Generated by genversion.\nexport const version = '3.5.1'\n","const getErrorMessage = (responseStatus?: number, error?: Error): string => {\n if (error) return `An error occurred while checking the connector URL: ${error?.name} \\n${error?.message}`\n return responseStatus\n ? `The URL is not routable. Response status: ${responseStatus}`\n : 'An error occurred while checking the connector URL'\n}\n\nexport { getErrorMessage }\n"],"mappings":"kwBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,mBAAAE,EAAA,oBAAAC,IAAA,eAAAC,EAAAJ,GCGA,IAAAK,EAA6D,+CCFtD,IAAMC,EAAsB,CACjC,oBAAqB,WACvB,ECFO,IAAMC,EAAU,QFOvB,IAAMC,EAAW,CACf,KAAM,mCACN,IAAK,uDACL,QAASC,CACX,EAMMC,EAAN,KAAoB,CASlB,YAAYC,EAAkB,CAR9BC,EAAA,KAAQ,aACRA,EAAA,KAAQ,UACRA,EAAA,KAAQ,cACRA,EAAA,KAAQ,iBACRA,EAAA,KAAQ,YACRA,EAAA,KAAQ,UACRA,EAAA,KAAQ,aAGN,KAAK,UAAY,wCACjB,KAAK,OAASC,EAAoB,oBAClC,KAAK,WAAa,mBAClB,KAAK,cAAgBJ,EACrB,KAAK,SAAWE,EAChB,KAAK,OAAS,QACd,KAAK,UAAY,GAAG,KAAK,cAAc,KAAK,kBAAkB,KAAK,UACrE,CAEM,KAAKG,EAAcC,EAA8B,QAAAC,EAAA,sBACrD,IAAMC,EAAU,CACd,YAAa,KAAK,OAClB,eAAgB,mBAChB,OAAQ,mBACR,aAAc,GAAG,KAAK,cAAc,KAAK,kBAAkB,KAAK,UAClE,EAEMC,EAAU,MAAM,KAAK,aAAaJ,EAAOC,CAAO,EAChDI,EAAS,OACTC,EAAO,KAAK,UAAUF,CAAO,EAC7BG,EAAO,OAEb,MAAM,KAAK,UAAW,CAAE,QAAAJ,EAAS,OAAAE,EAAQ,KAAAC,EAAM,KAAAC,CAAK,CAAC,EAClD,KAAMC,GAAa,CAClB,GAAIA,EAAS,SAAW,IAAK,CAC3B,KAAK,OAAO,KACV,2DAA2DA,EAAS,QACtE,EACA,OAEF,OAAOA,EAAS,KAAK,CACvB,CAAC,EACA,KAAMC,GAAkC,CACnCA,GACF,KAAK,OAAO,KAAK,8DAAyDA,GAAA,YAAAA,EAAM,IAAI,CAExF,CAAC,CACL,GAEM,aAAaC,EAA2E,QAAAR,EAAA,yBAA3EF,EAAcW,EAAe,CAAC,EAA6C,CAC5F,IAAMC,EAAiBZ,EACvB,OAAAY,EAAO,SAAQ,sBAAmB,EAElCA,EAAO,aAAY,iBAAcA,EAAO,KAAK,EAEtC,CACL,SAAAlB,EACA,MAAO,CACL,MAAOkB,EAAO,KACd,QAASA,EAAO,QAChB,UAAWA,EAAO,UAElB,KAAMA,EAAO,MAAQ,CAAC,EACtB,UAAQ,aAAUA,EAAQ,KAAK,MAAM,CACvC,EACA,QAAS,CACP,IAAKA,EAAO,IACZ,UAAWA,EAAO,UAClB,OAAQA,EAAO,OACf,QAASD,GAAgB,CAAC,EAC1B,SAAU,CAAC,EACX,OAAQ,CAAC,EACT,QAAS,CAAC,CACZ,EACA,OAAQ,CACN,aAAcC,EAAO,YACrB,iBAAkB,KAAK,UACvB,SAAUjB,EACV,SAAU,KAAK,SACf,KAAM,IAAI,KAAK,EAAE,YAAY,CAC/B,EACA,QAASiB,EAAO,SAAW,CAAC,CAC9B,CACF,GACF,EGtGA,IAAMC,EAAkB,CAACC,EAAyBC,IAC5CA,EAAc,uDAAuDA,GAAA,YAAAA,EAAO;AAAA,EAAUA,GAAA,YAAAA,EAAO,UAC1FD,EACH,6CAA6CA,IAC7C","names":["utils_exports","__export","ErrorReporter","getErrorMessage","__toCommonJS","import_util","ErrorReporterConfig","version","notifier","version","ErrorReporter","platform","__publicField","ErrorReporterConfig","error","context","__async","headers","payload","method","body","mode","response","data","_0","localContext","notice","getErrorMessage","responseStatus","error"]}
@@ -0,0 +1,3 @@
1
+ var u=Object.defineProperty;var y=(i,e,r)=>e in i?u(i,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):i[e]=r;var n=(i,e,r)=>(y(i,typeof e!="symbol"?e+"":e,r),r);var h=(i,e,r)=>new Promise((c,t)=>{var p=o=>{try{s(r.next(o))}catch(l){t(l)}},g=o=>{try{s(r.throw(o))}catch(l){t(l)}},s=o=>o.done?c(o.value):Promise.resolve(o.value).then(p,g);s((r=r.apply(i,e)).next())});import{generateStackTrace as f,getCauses as v,makeBacktrace as b}from"@honeybadger-io/core/build/src/util";var m={honeybadger_api_key:"undefined"};var a="3.5.1";var k={name:"Quiltt React Native SDK Reporter",url:"https://www.quiltt.dev/guides/connector/react-native",version:a},d=class{constructor(e){n(this,"noticeUrl");n(this,"apiKey");n(this,"clientName");n(this,"clientVersion");n(this,"platform");n(this,"logger");n(this,"userAgent");this.noticeUrl="https://api.honeybadger.io/v1/notices",this.apiKey=m.honeybadger_api_key,this.clientName="react-native-sdk",this.clientVersion=a,this.platform=e,this.logger=console,this.userAgent=`${this.clientName} ${this.clientVersion}; ${this.platform}`}send(e,r){return h(this,null,function*(){let c={"X-API-Key":this.apiKey,"Content-Type":"application/json",Accept:"application/json","User-Agent":`${this.clientName} ${this.clientVersion}; ${this.platform}`},t=yield this.buildPayload(e,r),p="POST",g=JSON.stringify(t),s="cors";fetch(this.noticeUrl,{headers:c,method:p,body:g,mode:s}).then(o=>{if(o.status!==201){this.logger.warn(`Error report failed: unknown response from server. code=${o.status}`);return}return o.json()}).then(o=>{o&&this.logger.info(`Error report sent \u26A1 https://app.honeybadger.io/notice/${o==null?void 0:o.id}`)})})}buildPayload(c){return h(this,arguments,function*(e,r={}){let t=e;return t.stack=f(),t.backtrace=b(t.stack),{notifier:k,error:{class:t.name,message:t.message,backtrace:t.backtrace,tags:t.tags||[],causes:v(t,this.logger)},request:{url:t.url,component:t.component,action:t.action,context:r||{},cgi_data:{},params:{},session:{}},server:{project_root:t.projectRoot,environment_name:this.userAgent,revision:a,hostname:this.platform,time:new Date().toUTCString()},details:t.details||{}}})}};var E=(i,e)=>e?`An error occurred while checking the connector URL: ${e==null?void 0:e.name}
2
+ ${e==null?void 0:e.message}`:i?`The URL is not routable. Response status: ${i}`:"An error occurred while checking the connector URL";export{d as ErrorReporter,E as getErrorMessage};
3
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/ErrorReporter.ts","../../src/utils/ErrorReporterConfig.ts","../../src/version.ts","../../src/utils/getErrorMessage.ts"],"sourcesContent":["// Quick hack to send error to Honeybadger to debug why the connector is not routable\n\nimport type { Notice, NoticeTransportPayload } from '@honeybadger-io/core/build/src/types'\nimport { generateStackTrace, getCauses, makeBacktrace } from '@honeybadger-io/core/build/src/util'\n\nimport { ErrorReporterConfig } from './ErrorReporterConfig'\nimport { version } from '../version'\n\nconst notifier = {\n name: 'Quiltt React Native SDK Reporter',\n url: 'https://www.quiltt.dev/guides/connector/react-native',\n version: version,\n}\n\ntype HoneybadgerResponseData = {\n id: string\n}\n\nclass ErrorReporter {\n private noticeUrl: string\n private apiKey: string\n private clientName: string\n private clientVersion: string\n private platform: string\n private logger: Console\n private userAgent: string\n\n constructor(platform: string) {\n this.noticeUrl = 'https://api.honeybadger.io/v1/notices'\n this.apiKey = ErrorReporterConfig.honeybadger_api_key\n this.clientName = 'react-native-sdk'\n this.clientVersion = version\n this.platform = platform\n this.logger = console\n this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`\n }\n\n async send(error: Error, context?: any): Promise<void> {\n const headers = {\n 'X-API-Key': this.apiKey,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`,\n }\n\n const payload = await this.buildPayload(error, context)\n const method = 'POST'\n const body = JSON.stringify(payload)\n const mode = 'cors'\n\n fetch(this.noticeUrl, { headers, method, body, mode })\n .then((response) => {\n if (response.status !== 201) {\n this.logger.warn(\n `Error report failed: unknown response from server. code=${response.status}`\n )\n return\n }\n return response.json()\n })\n .then((data: HoneybadgerResponseData) => {\n if (data) {\n this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`)\n }\n })\n }\n\n async buildPayload(error: Error, localContext = {}): Promise<Partial<NoticeTransportPayload>> {\n const notice: Notice = error as Notice\n notice.stack = generateStackTrace()\n\n notice.backtrace = makeBacktrace(notice.stack)\n\n return {\n notifier,\n error: {\n class: notice.name as string,\n message: notice.message as string,\n backtrace: notice.backtrace,\n // fingerprint: this.calculateFingerprint(notice),\n tags: notice.tags || [],\n causes: getCauses(notice, this.logger),\n },\n request: {\n url: notice.url,\n component: notice.component,\n action: notice.action,\n context: localContext || {},\n cgi_data: {},\n params: {},\n session: {},\n },\n server: {\n project_root: notice.projectRoot,\n environment_name: this.userAgent,\n revision: version,\n hostname: this.platform,\n time: new Date().toUTCString(),\n },\n details: notice.details || {},\n }\n }\n}\n\nexport { ErrorReporter }","\nexport const ErrorReporterConfig = {\n honeybadger_api_key: 'undefined',\n}\n","// Generated by genversion.\nexport const version = '3.5.1'\n","const getErrorMessage = (responseStatus?: number, error?: Error): string => {\n if (error) return `An error occurred while checking the connector URL: ${error?.name} \\n${error?.message}`\n return responseStatus\n ? `The URL is not routable. Response status: ${responseStatus}`\n : 'An error occurred while checking the connector URL'\n}\n\nexport { getErrorMessage }\n"],"mappings":"qXAGA,OAAS,sBAAAA,EAAoB,aAAAC,EAAW,iBAAAC,MAAqB,sCCFtD,IAAMC,EAAsB,CACjC,oBAAqB,WACvB,ECFO,IAAMC,EAAU,QFOvB,IAAMC,EAAW,CACf,KAAM,mCACN,IAAK,uDACL,QAASC,CACX,EAMMC,EAAN,KAAoB,CASlB,YAAYC,EAAkB,CAR9BC,EAAA,KAAQ,aACRA,EAAA,KAAQ,UACRA,EAAA,KAAQ,cACRA,EAAA,KAAQ,iBACRA,EAAA,KAAQ,YACRA,EAAA,KAAQ,UACRA,EAAA,KAAQ,aAGN,KAAK,UAAY,wCACjB,KAAK,OAASC,EAAoB,oBAClC,KAAK,WAAa,mBAClB,KAAK,cAAgBJ,EACrB,KAAK,SAAWE,EAChB,KAAK,OAAS,QACd,KAAK,UAAY,GAAG,KAAK,cAAc,KAAK,kBAAkB,KAAK,UACrE,CAEM,KAAKG,EAAcC,EAA8B,QAAAC,EAAA,sBACrD,IAAMC,EAAU,CACd,YAAa,KAAK,OAClB,eAAgB,mBAChB,OAAQ,mBACR,aAAc,GAAG,KAAK,cAAc,KAAK,kBAAkB,KAAK,UAClE,EAEMC,EAAU,MAAM,KAAK,aAAaJ,EAAOC,CAAO,EAChDI,EAAS,OACTC,EAAO,KAAK,UAAUF,CAAO,EAC7BG,EAAO,OAEb,MAAM,KAAK,UAAW,CAAE,QAAAJ,EAAS,OAAAE,EAAQ,KAAAC,EAAM,KAAAC,CAAK,CAAC,EAClD,KAAMC,GAAa,CAClB,GAAIA,EAAS,SAAW,IAAK,CAC3B,KAAK,OAAO,KACV,2DAA2DA,EAAS,QACtE,EACA,OAEF,OAAOA,EAAS,KAAK,CACvB,CAAC,EACA,KAAMC,GAAkC,CACnCA,GACF,KAAK,OAAO,KAAK,8DAAyDA,GAAA,YAAAA,EAAM,IAAI,CAExF,CAAC,CACL,GAEM,aAAaC,EAA2E,QAAAR,EAAA,yBAA3EF,EAAcW,EAAe,CAAC,EAA6C,CAC5F,IAAMC,EAAiBZ,EACvB,OAAAY,EAAO,MAAQC,EAAmB,EAElCD,EAAO,UAAYE,EAAcF,EAAO,KAAK,EAEtC,CACL,SAAAlB,EACA,MAAO,CACL,MAAOkB,EAAO,KACd,QAASA,EAAO,QAChB,UAAWA,EAAO,UAElB,KAAMA,EAAO,MAAQ,CAAC,EACtB,OAAQG,EAAUH,EAAQ,KAAK,MAAM,CACvC,EACA,QAAS,CACP,IAAKA,EAAO,IACZ,UAAWA,EAAO,UAClB,OAAQA,EAAO,OACf,QAASD,GAAgB,CAAC,EAC1B,SAAU,CAAC,EACX,OAAQ,CAAC,EACT,QAAS,CAAC,CACZ,EACA,OAAQ,CACN,aAAcC,EAAO,YACrB,iBAAkB,KAAK,UACvB,SAAUjB,EACV,SAAU,KAAK,SACf,KAAM,IAAI,KAAK,EAAE,YAAY,CAC/B,EACA,QAASiB,EAAO,SAAW,CAAC,CAC9B,CACF,GACF,EGtGA,IAAMI,EAAkB,CAACC,EAAyBC,IAC5CA,EAAc,uDAAuDA,GAAA,YAAAA,EAAO;AAAA,EAAUA,GAAA,YAAAA,EAAO,UAC1FD,EACH,6CAA6CA,IAC7C","names":["generateStackTrace","getCauses","makeBacktrace","ErrorReporterConfig","version","notifier","version","ErrorReporter","platform","__publicField","ErrorReporterConfig","error","context","__async","headers","payload","method","body","mode","response","data","_0","localContext","notice","generateStackTrace","makeBacktrace","getCauses","getErrorMessage","responseStatus","error"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quiltt/react-native",
3
- "version": "3.4.0",
3
+ "version": "3.5.1",
4
4
  "description": "React Native components for Quiltt Connector",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -24,8 +24,9 @@
24
24
  "react-native-url-polyfill": "*"
25
25
  },
26
26
  "dependencies": {
27
- "@quiltt/core": "3.4.0",
28
- "@quiltt/react": "3.4.0"
27
+ "@honeybadger-io/core": "6.5.1",
28
+ "@quiltt/react": "3.5.1",
29
+ "@quiltt/core": "3.5.1"
29
30
  },
30
31
  "devDependencies": {
31
32
  "@apollo/client": "3.7.16",
@@ -52,10 +53,11 @@
52
53
  "access": "public"
53
54
  },
54
55
  "scripts": {
55
- "build": "pnpm run addVersion && tsup",
56
+ "build": "pnpm run addApiKey && pnpm run addVersion && tsup",
56
57
  "clean": "rimraf .turbo dist",
57
58
  "dev": "tsup --watch",
58
59
  "addVersion": "genversion --esm -f src/version.ts",
60
+ "addApiKey": "node scripts/addApiKey.js",
59
61
  "lint": "TIMING=1 eslint --ext .js,.jsx,.ts,.tsx src/ --fix",
60
62
  "typecheck": "tsc --project tsconfig.json --noEmit"
61
63
  }
@@ -0,0 +1,63 @@
1
+ import { View, Text, Pressable, StyleSheet } from 'react-native'
2
+ import { AndroidSafeAreaView } from './AndroidSafeAreaView'
3
+
4
+ type ErrorScreenProp = {
5
+ error: string
6
+ cta: () => void
7
+ }
8
+
9
+ export const ErrorScreen = ({ error, cta }: ErrorScreenProp) => (
10
+ <AndroidSafeAreaView>
11
+ <View style={[styles.container, styles.padding]}>
12
+ <View style={{ flex: 1, justifyContent: 'center' }}>
13
+ <View
14
+ style={{
15
+ flexDirection: 'row',
16
+ justifyContent: 'space-between',
17
+ alignItems: 'center',
18
+ marginVertical: 10,
19
+ }}
20
+ >
21
+ <Text style={[styles.title]}>Cannot connect to the internet.</Text>
22
+ </View>
23
+ <Text style={[styles.subtitle]}>{error}</Text>
24
+ </View>
25
+ <Pressable style={[styles.pressable]} onPress={cta}>
26
+ <Text style={[styles.pressableText]}>Exit</Text>
27
+ </Pressable>
28
+ </View>
29
+ </AndroidSafeAreaView>
30
+ )
31
+
32
+ const styles = StyleSheet.create({
33
+ container: {
34
+ flex: 1,
35
+ flexDirection: 'column',
36
+ justifyContent: 'flex-start',
37
+ alignItems: 'stretch',
38
+ backgroundColor: '#F3F4F6',
39
+ },
40
+ title: {
41
+ color: '#1F2937',
42
+ fontSize: 30,
43
+ fontWeight: 'bold',
44
+ },
45
+ subtitle: {
46
+ color: 'rgba(107, 114, 128, 1)',
47
+ },
48
+ padding: {
49
+ paddingHorizontal: 16, // sm:px-4
50
+ paddingVertical: 24, // sm:py-6
51
+ },
52
+ pressable: {
53
+ marginTop: 20,
54
+ backgroundColor: '#1F2937',
55
+ padding: 10,
56
+ paddingHorizontal: 25,
57
+ borderRadius: 5,
58
+ },
59
+ pressableText: {
60
+ color: '#fff',
61
+ textAlign: 'center',
62
+ },
63
+ })
@@ -0,0 +1,10 @@
1
+ import { ActivityIndicator, View } from 'react-native'
2
+ import { AndroidSafeAreaView } from './AndroidSafeAreaView'
3
+
4
+ export const LoadingScreen = () => (
5
+ <AndroidSafeAreaView>
6
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
7
+ <ActivityIndicator size="large" color="#0000ff" />
8
+ </View>
9
+ </AndroidSafeAreaView>
10
+ )
@@ -3,8 +3,8 @@ import {
3
3
  ConnectorSDKCallbacks,
4
4
  ConnectorSDKEventType,
5
5
  } from '@quiltt/core'
6
- import { useCallback, useRef } from 'react'
7
- import { Linking } from 'react-native'
6
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
7
+ import { Linking, Platform } from 'react-native'
8
8
  import { WebView } from 'react-native-webview'
9
9
  // React Native's URL implementation is incomplete
10
10
  // https://github.com/facebook/react-native/issues/16434
@@ -12,7 +12,13 @@ import { URL } from 'react-native-url-polyfill'
12
12
  import { AndroidSafeAreaView } from './AndroidSafeAreaView'
13
13
  import type { ShouldStartLoadRequest } from 'react-native-webview/lib/WebViewTypes'
14
14
  import { useQuilttSession } from '@quiltt/react'
15
+ import { ErrorReporter, getErrorMessage } from '../utils/'
16
+
15
17
  import { version } from '../version'
18
+ import { LoadingScreen } from './LoadingScreen'
19
+ import { ErrorScreen } from './ErrorScreen'
20
+
21
+ const errorReporter = new ErrorReporter(`${Platform.OS} ${Platform.Version}`)
16
22
 
17
23
  type QuilttConnectorProps = {
18
24
  connectorId: string
@@ -20,6 +26,13 @@ type QuilttConnectorProps = {
20
26
  oauthRedirectUrl: string
21
27
  } & ConnectorSDKCallbacks
22
28
 
29
+ type PreFlightCheck = {
30
+ checked: boolean
31
+ error?: string
32
+ }
33
+
34
+ const PREFLIGHT_RETRY_COUNT = 3
35
+
23
36
  export const QuilttConnector = ({
24
37
  connectorId,
25
38
  connectionId,
@@ -35,6 +48,54 @@ export const QuilttConnector = ({
35
48
  const { session } = useQuilttSession()
36
49
  oauthRedirectUrl = encodeURIComponent(oauthRedirectUrl)
37
50
  const connectorUrl = `https://${connectorId}.quiltt.app/?mode=webview&oauth_redirect_url=${oauthRedirectUrl}&agent=react-native-${version}`
51
+ console.log('connectorUrl', connectorUrl)
52
+ const [preFlightCheck, setPreFlightCheck] = useState<PreFlightCheck>({ checked: false })
53
+
54
+ const checkConnectorUrl = useCallback(
55
+ async (retryCount = 0): Promise<PreFlightCheck> => {
56
+ let responseStatus
57
+ let error
58
+ let errorOccurred = false
59
+ try {
60
+ const response = await fetch(connectorUrl)
61
+ if (!response.ok) {
62
+ console.error(`The URL ${connectorUrl} is not routable.`)
63
+ responseStatus = response.status
64
+ errorOccurred = true
65
+ } else {
66
+ console.log(`The URL ${connectorUrl} is routable.`)
67
+ return { checked: true }
68
+ }
69
+ } catch (e) {
70
+ error = e
71
+ console.error(`An error occurred while checking the connector URL: ${error}`)
72
+ errorOccurred = true
73
+ }
74
+
75
+ // Retry logic in case of error or response not OK
76
+ if (errorOccurred && retryCount < PREFLIGHT_RETRY_COUNT) {
77
+ await new Promise((resolve) => setTimeout(resolve, 50 * retryCount)) // delay for 50ms for each retry
78
+ console.log(`Retrying... Attempt number ${retryCount + 1}`)
79
+ return checkConnectorUrl(retryCount + 1)
80
+ }
81
+
82
+ const errorMessage = getErrorMessage(responseStatus, error as Error)
83
+ const errorToSend = (error as Error) || new Error(errorMessage)
84
+ const context = { connectorUrl, responseStatus }
85
+ if (responseStatus !== 404) errorReporter.send(errorToSend, context)
86
+ return { checked: true, error: errorMessage }
87
+ },
88
+ [connectorUrl]
89
+ )
90
+
91
+ useEffect(() => {
92
+ if (preFlightCheck.checked) return
93
+ const fetchDataAndSetState = async () => {
94
+ const connectorUrlStatus = await checkConnectorUrl()
95
+ setPreFlightCheck(connectorUrlStatus)
96
+ }
97
+ fetchDataAndSetState()
98
+ }, [checkConnectorUrl, preFlightCheck])
38
99
 
39
100
  const initInjectedJavaScript = useCallback(() => {
40
101
  const script = `\
@@ -59,97 +120,130 @@ export const QuilttConnector = ({
59
120
  // allowedListUrl & shouldRender ensure we are only rendering Quiltt, MX and Plaid content in Webview
60
121
  // For other urls, we assume those are bank urls, which needs to be handle in external browser.
61
122
  // @todo Convert it to a list from Quiltt Server to prevent MX/ Plaid changes.
62
- const allowedListUrl = [
63
- 'quiltt.app',
64
- 'quiltt.dev',
65
- 'moneydesktop.com',
66
- 'cdn.plaid.com/link/v2/stable/link.html',
67
- ]
68
- const shouldRender = (url: URL) => {
69
- if (isQuilttEvent(url)) return false
70
- return allowedListUrl.some((href) => url.href.includes(href))
71
- }
123
+ const allowedListUrl = useMemo(
124
+ () => [
125
+ 'quiltt.app',
126
+ 'quiltt.dev',
127
+ 'moneydesktop.com',
128
+ 'cdn.plaid.com/link/v2/stable/link.html',
129
+ ],
130
+ []
131
+ )
72
132
 
73
- const requestHandler = (request: ShouldStartLoadRequest) => {
74
- const url = new URL(request.url)
75
- if (isQuilttEvent(url)) {
76
- handleQuilttEvent(url)
77
- return false
78
- }
79
- if (shouldRender(url)) return true
80
- // Plaid set oauth url by doing window.location.href = url
81
- // This is the only way I know to handle this.
82
- handleOAuthUrl(url)
83
- return false
84
- }
133
+ const isQuilttEvent = useCallback((url: URL) => url.protocol === 'quilttconnector:', [])
134
+
135
+ const shouldRender = useCallback(
136
+ (url: URL) => {
137
+ if (isQuilttEvent(url)) return false
138
+ if (url.protocol !== 'https:') {
139
+ const err = new Error(`Invalid url leaked ${url.href}`)
140
+ errorReporter.send(err)
141
+ return false
142
+ }
143
+ return allowedListUrl.some((href) => url.href.includes(href))
144
+ },
145
+ [allowedListUrl, isQuilttEvent]
146
+ )
85
147
 
86
148
  const clearLocalStorage = () => {
87
149
  const script = 'localStorage.clear();'
88
150
  webViewRef.current?.injectJavaScript(script)
89
151
  }
90
152
 
91
- const isQuilttEvent = (url: URL) => url.protocol === 'quilttconnector:'
92
-
93
- const handleQuilttEvent = (url: URL) => {
94
- url.searchParams.delete('source')
95
- url.searchParams.append('connectorId', connectorId)
96
- const metadata = Object.fromEntries(url.searchParams) as ConnectorSDKCallbackMetadata
97
-
98
- const eventType = url.host
99
- switch (eventType) {
100
- case 'Load':
101
- initInjectedJavaScript()
102
- onEvent?.(ConnectorSDKEventType.Load, metadata)
103
- onLoad?.(metadata)
104
- break
105
- case 'ExitAbort':
106
- clearLocalStorage()
107
- onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)
108
- onExit?.(ConnectorSDKEventType.ExitAbort, metadata)
109
- onExitAbort?.(metadata)
110
- break
111
- case 'ExitError':
112
- clearLocalStorage()
113
- onEvent?.(ConnectorSDKEventType.ExitError, metadata)
114
- onExit?.(ConnectorSDKEventType.ExitError, metadata)
115
- onExitError?.(metadata)
116
- break
117
- case 'ExitSuccess':
118
- clearLocalStorage()
119
- onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)
120
- onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)
121
- onExitSuccess?.(metadata)
122
- break
123
- case 'Authenticate':
124
- // @todo handle Authenticate
125
- break
126
- case 'OauthRequested':
127
- handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))
128
- break
129
- default:
130
- console.log('unhandled event', url)
131
- break
132
- }
133
- }
134
-
135
- const handleOAuthUrl = (oauthUrl: URL) => {
153
+ const handleOAuthUrl = useCallback((oauthUrl: URL) => {
136
154
  if (oauthUrl.protocol !== 'https:') {
137
155
  console.log(`handleOAuthUrl - Skipping non https url - ${oauthUrl.href}`)
138
156
  return
139
157
  }
140
158
  Linking.openURL(oauthUrl.href)
141
- }
159
+ }, [])
160
+
161
+ const handleQuilttEvent = useCallback(
162
+ (url: URL) => {
163
+ url.searchParams.delete('source')
164
+ url.searchParams.append('connectorId', connectorId)
165
+ const metadata = Object.fromEntries(url.searchParams) as ConnectorSDKCallbackMetadata
166
+
167
+ const eventType = url.host
168
+ switch (eventType) {
169
+ case 'Load':
170
+ initInjectedJavaScript()
171
+ onEvent?.(ConnectorSDKEventType.Load, metadata)
172
+ onLoad?.(metadata)
173
+ break
174
+ case 'ExitAbort':
175
+ clearLocalStorage()
176
+ onEvent?.(ConnectorSDKEventType.ExitAbort, metadata)
177
+ onExit?.(ConnectorSDKEventType.ExitAbort, metadata)
178
+ onExitAbort?.(metadata)
179
+ break
180
+ case 'ExitError':
181
+ clearLocalStorage()
182
+ onEvent?.(ConnectorSDKEventType.ExitError, metadata)
183
+ onExit?.(ConnectorSDKEventType.ExitError, metadata)
184
+ onExitError?.(metadata)
185
+ break
186
+ case 'ExitSuccess':
187
+ clearLocalStorage()
188
+ onEvent?.(ConnectorSDKEventType.ExitSuccess, metadata)
189
+ onExit?.(ConnectorSDKEventType.ExitSuccess, metadata)
190
+ onExitSuccess?.(metadata)
191
+ break
192
+ case 'Authenticate':
193
+ // @todo handle Authenticate
194
+ break
195
+ case 'OauthRequested':
196
+ handleOAuthUrl(new URL(url.searchParams.get('oauthUrl') as string))
197
+ break
198
+ default:
199
+ console.log('unhandled event', url)
200
+ break
201
+ }
202
+ },
203
+ [
204
+ connectorId,
205
+ handleOAuthUrl,
206
+ initInjectedJavaScript,
207
+ onEvent,
208
+ onExit,
209
+ onExitAbort,
210
+ onExitError,
211
+ onExitSuccess,
212
+ onLoad,
213
+ ]
214
+ )
215
+
216
+ const requestHandler = useCallback(
217
+ (request: ShouldStartLoadRequest) => {
218
+ const url = new URL(request.url)
219
+
220
+ if (isQuilttEvent(url)) {
221
+ handleQuilttEvent(url)
222
+ return false
223
+ }
224
+ if (shouldRender(url)) return true
225
+ // Plaid set oauth url by doing window.location.href = url
226
+ // So we use `handleOAuthUrl` as a catch all and assume all url got to this step is Plaid OAuth url
227
+ handleOAuthUrl(url)
228
+ return false
229
+ },
230
+ [handleOAuthUrl, handleQuilttEvent, isQuilttEvent, shouldRender]
231
+ )
232
+
233
+ if (!preFlightCheck.checked) return <LoadingScreen />
234
+ if (preFlightCheck.error)
235
+ return <ErrorScreen error={preFlightCheck.error} cta={() => onExitError?.({ connectorId })} />
142
236
 
143
237
  return (
144
238
  <AndroidSafeAreaView>
145
239
  <WebView
146
240
  ref={webViewRef}
147
- originWhitelist={['https://*', 'quilttconnector://*']} // Maybe relax this to *?
241
+ originWhitelist={['https://*', 'quilttconnector://*']} // Guard against other non SDK needed url
148
242
  source={{ uri: connectorUrl }}
149
243
  onShouldStartLoadWithRequest={requestHandler}
150
244
  javaScriptEnabled
151
245
  domStorageEnabled // To enable localStorage in Android webview
152
- webviewDebuggingEnabled // Not sure if this works
246
+ webviewDebuggingEnabled
153
247
  />
154
248
  </AndroidSafeAreaView>
155
249
  )
@@ -0,0 +1,105 @@
1
+ // Quick hack to send error to Honeybadger to debug why the connector is not routable
2
+
3
+ import type { Notice, NoticeTransportPayload } from '@honeybadger-io/core/build/src/types'
4
+ import { generateStackTrace, getCauses, makeBacktrace } from '@honeybadger-io/core/build/src/util'
5
+
6
+ import { ErrorReporterConfig } from './ErrorReporterConfig'
7
+ import { version } from '../version'
8
+
9
+ const notifier = {
10
+ name: 'Quiltt React Native SDK Reporter',
11
+ url: 'https://www.quiltt.dev/guides/connector/react-native',
12
+ version: version,
13
+ }
14
+
15
+ type HoneybadgerResponseData = {
16
+ id: string
17
+ }
18
+
19
+ class ErrorReporter {
20
+ private noticeUrl: string
21
+ private apiKey: string
22
+ private clientName: string
23
+ private clientVersion: string
24
+ private platform: string
25
+ private logger: Console
26
+ private userAgent: string
27
+
28
+ constructor(platform: string) {
29
+ this.noticeUrl = 'https://api.honeybadger.io/v1/notices'
30
+ this.apiKey = ErrorReporterConfig.honeybadger_api_key
31
+ this.clientName = 'react-native-sdk'
32
+ this.clientVersion = version
33
+ this.platform = platform
34
+ this.logger = console
35
+ this.userAgent = `${this.clientName} ${this.clientVersion}; ${this.platform}`
36
+ }
37
+
38
+ async send(error: Error, context?: any): Promise<void> {
39
+ const headers = {
40
+ 'X-API-Key': this.apiKey,
41
+ 'Content-Type': 'application/json',
42
+ Accept: 'application/json',
43
+ 'User-Agent': `${this.clientName} ${this.clientVersion}; ${this.platform}`,
44
+ }
45
+
46
+ const payload = await this.buildPayload(error, context)
47
+ const method = 'POST'
48
+ const body = JSON.stringify(payload)
49
+ const mode = 'cors'
50
+
51
+ fetch(this.noticeUrl, { headers, method, body, mode })
52
+ .then((response) => {
53
+ if (response.status !== 201) {
54
+ this.logger.warn(
55
+ `Error report failed: unknown response from server. code=${response.status}`
56
+ )
57
+ return
58
+ }
59
+ return response.json()
60
+ })
61
+ .then((data: HoneybadgerResponseData) => {
62
+ if (data) {
63
+ this.logger.info(`Error report sent ⚡ https://app.honeybadger.io/notice/${data?.id}`)
64
+ }
65
+ })
66
+ }
67
+
68
+ async buildPayload(error: Error, localContext = {}): Promise<Partial<NoticeTransportPayload>> {
69
+ const notice: Notice = error as Notice
70
+ notice.stack = generateStackTrace()
71
+
72
+ notice.backtrace = makeBacktrace(notice.stack)
73
+
74
+ return {
75
+ notifier,
76
+ error: {
77
+ class: notice.name as string,
78
+ message: notice.message as string,
79
+ backtrace: notice.backtrace,
80
+ // fingerprint: this.calculateFingerprint(notice),
81
+ tags: notice.tags || [],
82
+ causes: getCauses(notice, this.logger),
83
+ },
84
+ request: {
85
+ url: notice.url,
86
+ component: notice.component,
87
+ action: notice.action,
88
+ context: localContext || {},
89
+ cgi_data: {},
90
+ params: {},
91
+ session: {},
92
+ },
93
+ server: {
94
+ project_root: notice.projectRoot,
95
+ environment_name: this.userAgent,
96
+ revision: version,
97
+ hostname: this.platform,
98
+ time: new Date().toUTCString(),
99
+ },
100
+ details: notice.details || {},
101
+ }
102
+ }
103
+ }
104
+
105
+ export { ErrorReporter }
@@ -0,0 +1,4 @@
1
+
2
+ export const ErrorReporterConfig = {
3
+ honeybadger_api_key: 'undefined',
4
+ }
@@ -0,0 +1,8 @@
1
+ const getErrorMessage = (responseStatus?: number, error?: Error): string => {
2
+ if (error) return `An error occurred while checking the connector URL: ${error?.name} \n${error?.message}`
3
+ return responseStatus
4
+ ? `The URL is not routable. Response status: ${responseStatus}`
5
+ : 'An error occurred while checking the connector URL'
6
+ }
7
+
8
+ export { getErrorMessage }
@@ -0,0 +1,2 @@
1
+ export * from './ErrorReporter'
2
+ export * from './getErrorMessage'
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '3.4.0'
2
+ export const version = '3.5.1'