@tryfinch/react-connect 4.1.0 → 5.0.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/README.md +87 -5
- package/dist/core.d.ts +11 -0
- package/dist/index-with-react.d.ts +2 -0
- package/dist/index.d.ts +12 -46
- package/dist/index.es.js +161 -98
- package/dist/index.js +150 -128
- package/dist/react.d.ts +6 -0
- package/dist/react.es.js +182 -0
- package/dist/types.d.ts +57 -0
- package/dist/umd.d.ts +2 -0
- package/dist/utils.d.ts +11 -0
- package/package.json +45 -27
- package/.eslintignore +0 -5
- package/.eslintrc.js +0 -62
- package/.github/pull_request_template.md +0 -66
- package/.github/workflows/pr.yml +0 -92
- package/.github/workflows/release.yml +0 -80
- package/.nvmrc +0 -1
- package/.prettierrc.js +0 -5
- package/CHANGELOG.md +0 -11
- package/LICENSE +0 -21
- package/dist/index.d.ts.map +0 -1
- package/dist/index.es.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/example/README.md +0 -2026
- package/example/package-lock.json +0 -31464
- package/example/package.json +0 -35
- package/example/public/index.html +0 -20
- package/example/public/manifest.json +0 -8
- package/example/src/App.css +0 -49
- package/example/src/App.tsx +0 -80
- package/example/src/Result.tsx +0 -26
- package/example/src/index.css +0 -11
- package/example/src/index.js +0 -7
- package/example/src/react-app-env.d.ts +0 -1
- package/example/tsconfig.json +0 -26
- package/jest.config.js +0 -7
- package/rollup.config.js +0 -22
- package/src/index.test.ts +0 -111
- package/src/index.ts +0 -253
- package/tsconfig.json +0 -15
package/example/package.json
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "react-finch-connect-example",
|
|
3
|
-
"homepage": "https://.github.io/react-finch-connect",
|
|
4
|
-
"version": "0.0.0",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"private": true,
|
|
7
|
-
"dependencies": {
|
|
8
|
-
"@tryfinch/react-connect": "file:..",
|
|
9
|
-
"@types/react": "^17.0.37",
|
|
10
|
-
"prop-types": "^15.6.2",
|
|
11
|
-
"react": "file:../node_modules/react",
|
|
12
|
-
"react-dom": "^16.9.0"
|
|
13
|
-
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"start": "react-scripts start",
|
|
16
|
-
"build": "react-scripts build",
|
|
17
|
-
"test": "react-scripts test --env=jsdom",
|
|
18
|
-
"eject": "react-scripts eject"
|
|
19
|
-
},
|
|
20
|
-
"eslintConfig": {
|
|
21
|
-
"extends": [
|
|
22
|
-
"react-app",
|
|
23
|
-
"react-app/jest"
|
|
24
|
-
]
|
|
25
|
-
},
|
|
26
|
-
"browserslist": [
|
|
27
|
-
">0.2%",
|
|
28
|
-
"not dead",
|
|
29
|
-
"not ie <= 11",
|
|
30
|
-
"not op_mini all"
|
|
31
|
-
],
|
|
32
|
-
"devDependencies": {
|
|
33
|
-
"react-scripts": "^5.0.1"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
6
|
-
<meta name="theme-color" content="#000000">
|
|
7
|
-
|
|
8
|
-
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
|
9
|
-
|
|
10
|
-
<title>react-finch-connect</title>
|
|
11
|
-
</head>
|
|
12
|
-
|
|
13
|
-
<body>
|
|
14
|
-
<noscript>
|
|
15
|
-
You need to enable JavaScript to run this app.
|
|
16
|
-
</noscript>
|
|
17
|
-
|
|
18
|
-
<div id="root"></div>
|
|
19
|
-
</body>
|
|
20
|
-
</html>
|
package/example/src/App.css
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
.container {
|
|
2
|
-
text-align: center;
|
|
3
|
-
background-color: #282c34;
|
|
4
|
-
min-height: 100vh;
|
|
5
|
-
display: flex;
|
|
6
|
-
flex-direction: column;
|
|
7
|
-
align-items: center;
|
|
8
|
-
justify-content: center;
|
|
9
|
-
font-size: calc(7px + 2vmin);
|
|
10
|
-
color: white;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
a {
|
|
14
|
-
color: white;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
.actions {
|
|
18
|
-
background-color: #4f4f4f;
|
|
19
|
-
padding: 1em;
|
|
20
|
-
border-radius: 10px;
|
|
21
|
-
margin: 1em 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.cta {
|
|
25
|
-
font-size: calc(7px + 2vmin);
|
|
26
|
-
padding: .5em;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.row {
|
|
30
|
-
margin: 2em 0;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
.top-label {
|
|
34
|
-
display: block;
|
|
35
|
-
margin-bottom: .2em;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
input[type=checkbox] {
|
|
39
|
-
width: 2em;
|
|
40
|
-
height: 2em;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
.results {
|
|
44
|
-
background-color: #4f4f4f;
|
|
45
|
-
padding: 1em;
|
|
46
|
-
border-radius: 10px;
|
|
47
|
-
text-align: left;
|
|
48
|
-
margin: 1em 0;
|
|
49
|
-
}
|
package/example/src/App.tsx
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import { useFinchConnect, SuccessEvent, ErrorEvent } from '@tryfinch/react-connect';
|
|
3
|
-
|
|
4
|
-
import Result, { ResultContainer } from './Result';
|
|
5
|
-
|
|
6
|
-
import './App.css';
|
|
7
|
-
|
|
8
|
-
const App = () => {
|
|
9
|
-
const [sessionId, setSessionId] = useState<string>('');
|
|
10
|
-
const [sendState, setSendState] = useState<boolean>(false);
|
|
11
|
-
const [result, setResult] = useState<ResultContainer>();
|
|
12
|
-
|
|
13
|
-
// Define callbacks
|
|
14
|
-
const onSuccess = (value: SuccessEvent) => setResult({ kind: 'success', value });
|
|
15
|
-
const onError = (value: ErrorEvent) => setResult({ kind: 'error', value });
|
|
16
|
-
const onClose = () => setResult({ kind: 'closed' });
|
|
17
|
-
|
|
18
|
-
// Initialize the FinchConnect hook
|
|
19
|
-
const { open } = useFinchConnect({
|
|
20
|
-
onSuccess,
|
|
21
|
-
onError,
|
|
22
|
-
onClose,
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
// Call the open method when submitting the form
|
|
26
|
-
const submissionHandler: React.FormEventHandler<HTMLFormElement> = (e) => {
|
|
27
|
-
e.preventDefault();
|
|
28
|
-
open({
|
|
29
|
-
// Generate a session ID using the /connect/sessions endpoint on the Finch API
|
|
30
|
-
// See the docs here https://developer.tryfinch.com/api-reference/connect/new-session#create-a-new-connect-session
|
|
31
|
-
sessionId: sessionId.trim(),
|
|
32
|
-
// An optional state parameter can be passed
|
|
33
|
-
// https://datatracker.ietf.org/doc/html/rfc6749#section-10.12
|
|
34
|
-
...(sendState ? { state: new Date().toISOString() } : {}),
|
|
35
|
-
// An optional value for the z-index of the Finch Connect iframe
|
|
36
|
-
// Defaults to 999 if not provided
|
|
37
|
-
// zIndex: 998,
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
return (
|
|
42
|
-
<div className="container">
|
|
43
|
-
<h2>
|
|
44
|
-
<a href="https://www.npmjs.com/package/@tryfinch/react-connect">@tryfinch/react-connect</a>{' '}
|
|
45
|
-
Example App
|
|
46
|
-
</h2>
|
|
47
|
-
<form className="actions" onSubmit={submissionHandler}>
|
|
48
|
-
<div className="row">
|
|
49
|
-
<label className="top-label">Session UUID:</label>
|
|
50
|
-
<input
|
|
51
|
-
type="text"
|
|
52
|
-
placeholder="Enter session UUID"
|
|
53
|
-
value={sessionId}
|
|
54
|
-
onChange={(e) => setSessionId(e.target.value)}
|
|
55
|
-
/>
|
|
56
|
-
</div>
|
|
57
|
-
<div className="row">
|
|
58
|
-
<label className="top-label">Include State:</label>
|
|
59
|
-
<input
|
|
60
|
-
type="checkbox"
|
|
61
|
-
checked={sendState}
|
|
62
|
-
onChange={() => setSendState((prev) => !prev)}
|
|
63
|
-
/>
|
|
64
|
-
</div>
|
|
65
|
-
<div className="row">
|
|
66
|
-
<button className="cta" type="submit">
|
|
67
|
-
Open Finch Connect
|
|
68
|
-
</button>
|
|
69
|
-
</div>
|
|
70
|
-
</form>
|
|
71
|
-
<div className="results">
|
|
72
|
-
{!result && (
|
|
73
|
-
<p>Complete a Finch Connect session and the success event will be displayed here</p>
|
|
74
|
-
)}
|
|
75
|
-
{result && <Result result={result} />}
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
export default App;
|
package/example/src/Result.tsx
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { SuccessEvent, ErrorEvent } from '@tryfinch/react-connect';
|
|
2
|
-
|
|
3
|
-
export type ResultContainer = {
|
|
4
|
-
kind: 'success';
|
|
5
|
-
value: SuccessEvent;
|
|
6
|
-
} | {
|
|
7
|
-
kind: 'error';
|
|
8
|
-
value: ErrorEvent;
|
|
9
|
-
} | {
|
|
10
|
-
kind: 'closed',
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
const Result = ({ result }: { result: ResultContainer }) => {
|
|
14
|
-
if (result.kind === 'closed') {
|
|
15
|
-
return <>
|
|
16
|
-
<p>Closed!</p>
|
|
17
|
-
</>;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return <>
|
|
21
|
-
<p>{ result.kind === 'error' ? 'Error' : 'Success' }:</p>
|
|
22
|
-
<pre>{ JSON.stringify(result.value, null, 2) }</pre>
|
|
23
|
-
</>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default Result
|
package/example/src/index.css
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
body {
|
|
2
|
-
margin: 0;
|
|
3
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
|
|
4
|
-
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
5
|
-
-webkit-font-smoothing: antialiased;
|
|
6
|
-
-moz-osx-font-smoothing: grayscale;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
code {
|
|
10
|
-
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
|
|
11
|
-
}
|
package/example/src/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
/// <reference types="react-scripts" />
|
package/example/tsconfig.json
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es5",
|
|
4
|
-
"lib": [
|
|
5
|
-
"dom",
|
|
6
|
-
"dom.iterable",
|
|
7
|
-
"esnext"
|
|
8
|
-
],
|
|
9
|
-
"allowJs": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"allowSyntheticDefaultImports": true,
|
|
13
|
-
"strict": true,
|
|
14
|
-
"forceConsistentCasingInFileNames": true,
|
|
15
|
-
"module": "esnext",
|
|
16
|
-
"moduleResolution": "node",
|
|
17
|
-
"resolveJsonModule": true,
|
|
18
|
-
"isolatedModules": true,
|
|
19
|
-
"noEmit": true,
|
|
20
|
-
"jsx": "react-jsx",
|
|
21
|
-
"noFallthroughCasesInSwitch": true
|
|
22
|
-
},
|
|
23
|
-
"include": [
|
|
24
|
-
"src"
|
|
25
|
-
]
|
|
26
|
-
}
|
package/jest.config.js
DELETED
package/rollup.config.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import external from 'rollup-plugin-peer-deps-external';
|
|
2
|
-
import replace from '@rollup/plugin-replace';
|
|
3
|
-
import typescript from '@rollup/plugin-typescript';
|
|
4
|
-
|
|
5
|
-
import pkg from './package.json';
|
|
6
|
-
|
|
7
|
-
const plugins = [
|
|
8
|
-
external(),
|
|
9
|
-
replace({ SDK_VERSION: pkg.version }),
|
|
10
|
-
typescript({ sourceRoot: '.' }),
|
|
11
|
-
];
|
|
12
|
-
|
|
13
|
-
export default [
|
|
14
|
-
{
|
|
15
|
-
input: 'src/index.ts',
|
|
16
|
-
output: [
|
|
17
|
-
{ file: pkg.main, format: 'cjs', sourcemap: true },
|
|
18
|
-
{ file: pkg.module, format: 'es', sourcemap: true },
|
|
19
|
-
],
|
|
20
|
-
plugins,
|
|
21
|
-
},
|
|
22
|
-
];
|
package/src/index.test.ts
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { constructAuthUrl, constructPreviewUrl } from './index';
|
|
2
|
-
|
|
3
|
-
const NOOP_CALLBACKS = {
|
|
4
|
-
onSuccess: jest.fn(),
|
|
5
|
-
onError: jest.fn(),
|
|
6
|
-
onClose: jest.fn(),
|
|
7
|
-
zIndex: 999,
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
describe('Finch React SDK', () => {
|
|
11
|
-
describe('constructAuthUrl', () => {
|
|
12
|
-
it('adds the session parameter', () => {
|
|
13
|
-
const authUrl = constructAuthUrl({
|
|
14
|
-
sessionId: 'test-session-id',
|
|
15
|
-
});
|
|
16
|
-
expect(authUrl).toContain('session=test-session-id');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('adds all the expected base parameters to the auth URL', () => {
|
|
20
|
-
const expectedParameters = {
|
|
21
|
-
app_type: 'spa',
|
|
22
|
-
sdk_host_url: encodeURIComponent('http://localhost'),
|
|
23
|
-
mode: 'employer',
|
|
24
|
-
sdk_version: 'react-SDK_VERSION',
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const authUrl = constructAuthUrl({
|
|
28
|
-
sessionId: 'test-session-id',
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
Object.entries(expectedParameters).forEach(([key, value]) => {
|
|
32
|
-
expect(authUrl).toContain(`${key}=${value}`);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('adds the state parameter if it is provided', () => {
|
|
37
|
-
const testOptions = { sessionId: 'test-session-id', state: 'test-state', ...NOOP_CALLBACKS };
|
|
38
|
-
const authUrl = constructAuthUrl(testOptions);
|
|
39
|
-
|
|
40
|
-
expect(authUrl).toContain('state=test-state');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('uses the provided connectUrl if provided', () => {
|
|
44
|
-
const authUrl = constructAuthUrl({
|
|
45
|
-
sessionId: '123',
|
|
46
|
-
apiConfig: {
|
|
47
|
-
connectUrl: 'https://cool.site',
|
|
48
|
-
},
|
|
49
|
-
...NOOP_CALLBACKS,
|
|
50
|
-
});
|
|
51
|
-
expect(authUrl.startsWith('https://cool.site/authorize?')).toBe(true);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
describe('constructPreviewUrl', () => {
|
|
56
|
-
it('sets the preview parameter to true', () => {
|
|
57
|
-
const previewUrl = constructPreviewUrl({
|
|
58
|
-
clientId: 'test-client-id',
|
|
59
|
-
products: ['test-product'],
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(previewUrl).toContain('preview=true');
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('sets the client ID parameter', () => {
|
|
66
|
-
const previewUrl = constructPreviewUrl({
|
|
67
|
-
clientId: 'test-client-id',
|
|
68
|
-
products: ['test-product'],
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
expect(previewUrl).toContain('client_id=test-client-id');
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
it('sets the products parameter', () => {
|
|
75
|
-
const previewUrl = constructPreviewUrl({
|
|
76
|
-
clientId: 'test-client-id',
|
|
77
|
-
products: ['test-product', 'test-product-2'],
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
expect(previewUrl).toContain('products=test-product+test-product-2');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('sets a default redirect URI', () => {
|
|
84
|
-
const expectedRedirectUri = encodeURIComponent('https://www.tryfinch.com');
|
|
85
|
-
const previewUrl = constructPreviewUrl({
|
|
86
|
-
clientId: 'test-client-id',
|
|
87
|
-
products: ['test-product'],
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
expect(previewUrl).toContain(`redirect_uri=${expectedRedirectUri}`);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('adds all the expected base parameters to the auth URL', () => {
|
|
94
|
-
const expectedParameters = {
|
|
95
|
-
app_type: 'spa',
|
|
96
|
-
sdk_host_url: encodeURIComponent('http://localhost'),
|
|
97
|
-
mode: 'employer',
|
|
98
|
-
sdk_version: 'react-SDK_VERSION',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const authUrl = constructPreviewUrl({
|
|
102
|
-
clientId: 'test-client-id',
|
|
103
|
-
products: ['test-product'],
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
Object.entries(expectedParameters).forEach(([key, value]) => {
|
|
107
|
-
expect(authUrl).toContain(`${key}=${value}`);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
});
|
package/src/index.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { useEffect, useRef } from 'react';
|
|
2
|
-
|
|
3
|
-
export type SuccessEvent = {
|
|
4
|
-
code: string;
|
|
5
|
-
state?: string;
|
|
6
|
-
idpRedirectUri?: string;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
type ErrorType = 'validation_error' | 'employer_connection_error';
|
|
10
|
-
export type ErrorEvent = {
|
|
11
|
-
errorMessage: string;
|
|
12
|
-
errorType?: ErrorType;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
type ApiConfig = {
|
|
16
|
-
connectUrl: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
export type ConnectInitializeArgs = {
|
|
20
|
-
onSuccess: (e: SuccessEvent) => void;
|
|
21
|
-
onError: (e: ErrorEvent) => void;
|
|
22
|
-
onClose: () => void;
|
|
23
|
-
apiConfig?: ApiConfig;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export type ConnectLaunchArgs = {
|
|
27
|
-
sessionId: string;
|
|
28
|
-
state?: string;
|
|
29
|
-
zIndex?: number;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export type ConnectPreviewLaunchArgs = {
|
|
33
|
-
clientId: string;
|
|
34
|
-
products: string[];
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
type OpenFn = (args: ConnectLaunchArgs) => void;
|
|
38
|
-
|
|
39
|
-
type OpenPreviewFn = (args: ConnectPreviewLaunchArgs) => void;
|
|
40
|
-
|
|
41
|
-
const POST_MESSAGE_NAME = 'finch-auth-message-v2' as const;
|
|
42
|
-
|
|
43
|
-
type FinchConnectAuthMessage = { name: typeof POST_MESSAGE_NAME } & (
|
|
44
|
-
| {
|
|
45
|
-
kind: 'closed';
|
|
46
|
-
}
|
|
47
|
-
| {
|
|
48
|
-
kind: 'success';
|
|
49
|
-
code: string;
|
|
50
|
-
state?: string;
|
|
51
|
-
idpRedirectUri?: string;
|
|
52
|
-
}
|
|
53
|
-
| {
|
|
54
|
-
kind: 'error';
|
|
55
|
-
error: { shouldClose: boolean; message: string; type: ErrorType };
|
|
56
|
-
}
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
interface FinchConnectPostMessage {
|
|
60
|
-
data: FinchConnectAuthMessage;
|
|
61
|
-
origin: string;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const BASE_FINCH_CONNECT_URI = 'https://connect.tryfinch.com';
|
|
65
|
-
|
|
66
|
-
const FINCH_CONNECT_IFRAME_ID = 'finch-connect-iframe';
|
|
67
|
-
|
|
68
|
-
const appendBaseParams = (url: URL) => {
|
|
69
|
-
url.searchParams.append('app_type', 'spa');
|
|
70
|
-
// The host URL of the SDK. This is used to store the referrer for postMessage purposes
|
|
71
|
-
url.searchParams.append('sdk_host_url', window.location.origin);
|
|
72
|
-
url.searchParams.append('mode', 'employer');
|
|
73
|
-
// replace with actual SDK version by rollup
|
|
74
|
-
url.searchParams.append('sdk_version', 'react-SDK_VERSION');
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
export const constructAuthUrl = ({
|
|
78
|
-
sessionId,
|
|
79
|
-
state,
|
|
80
|
-
apiConfig,
|
|
81
|
-
}: {
|
|
82
|
-
sessionId: string;
|
|
83
|
-
state?: string;
|
|
84
|
-
apiConfig?: ApiConfig;
|
|
85
|
-
}) => {
|
|
86
|
-
const CONNECT_URL = apiConfig?.connectUrl || BASE_FINCH_CONNECT_URI;
|
|
87
|
-
|
|
88
|
-
const authUrl = new URL(`${CONNECT_URL}/authorize`);
|
|
89
|
-
|
|
90
|
-
authUrl.searchParams.append('session', sessionId);
|
|
91
|
-
if (state) authUrl.searchParams.append('state', state);
|
|
92
|
-
|
|
93
|
-
appendBaseParams(authUrl);
|
|
94
|
-
|
|
95
|
-
return authUrl.href;
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
export const constructPreviewUrl = ({
|
|
99
|
-
clientId,
|
|
100
|
-
products,
|
|
101
|
-
apiConfig,
|
|
102
|
-
}: {
|
|
103
|
-
clientId: string;
|
|
104
|
-
products: string[];
|
|
105
|
-
apiConfig?: ApiConfig;
|
|
106
|
-
}) => {
|
|
107
|
-
const CONNECT_URL = apiConfig?.connectUrl || BASE_FINCH_CONNECT_URI;
|
|
108
|
-
|
|
109
|
-
const previewUrl = new URL(`${CONNECT_URL}/authorize`);
|
|
110
|
-
|
|
111
|
-
previewUrl.searchParams.append('preview', 'true');
|
|
112
|
-
previewUrl.searchParams.append('client_id', clientId);
|
|
113
|
-
previewUrl.searchParams.append('products', (products ?? []).join(' '));
|
|
114
|
-
// This will be replaced by a universally allowed redirect URI in the backend
|
|
115
|
-
// We won't ever redirect to anything in preview mode, so we just need a value to pass validation
|
|
116
|
-
previewUrl.searchParams.append('redirect_uri', 'https://www.tryfinch.com');
|
|
117
|
-
|
|
118
|
-
appendBaseParams(previewUrl);
|
|
119
|
-
|
|
120
|
-
return previewUrl.href;
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
let isUseFinchConnectInitialized = false;
|
|
124
|
-
|
|
125
|
-
export const useFinchConnect = (
|
|
126
|
-
initializeArgs: ConnectInitializeArgs
|
|
127
|
-
): { open: OpenFn; openPreview: OpenPreviewFn } => {
|
|
128
|
-
const isHookMounted = useRef(false);
|
|
129
|
-
|
|
130
|
-
useEffect(() => {
|
|
131
|
-
if (!isHookMounted.current) {
|
|
132
|
-
if (isUseFinchConnectInitialized) {
|
|
133
|
-
console.error(
|
|
134
|
-
'One useFinchConnect hook has already been registered. Please ensure to only call useFinchConnect once to avoid your event callbacks getting called more than once. You can pass in override options to the open function if you so require.'
|
|
135
|
-
);
|
|
136
|
-
} else {
|
|
137
|
-
isUseFinchConnectInitialized = true;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
isHookMounted.current = true;
|
|
141
|
-
}
|
|
142
|
-
}, []);
|
|
143
|
-
|
|
144
|
-
const createAndAttachIFrame = ({
|
|
145
|
-
src,
|
|
146
|
-
zIndexOverride,
|
|
147
|
-
}: {
|
|
148
|
-
src: string;
|
|
149
|
-
zIndexOverride?: number;
|
|
150
|
-
}) => {
|
|
151
|
-
if (!document.getElementById(FINCH_CONNECT_IFRAME_ID)) {
|
|
152
|
-
const iframe = document.createElement('iframe');
|
|
153
|
-
iframe.src = src;
|
|
154
|
-
iframe.frameBorder = '0';
|
|
155
|
-
iframe.id = FINCH_CONNECT_IFRAME_ID;
|
|
156
|
-
iframe.style.position = 'fixed';
|
|
157
|
-
iframe.style.zIndex = zIndexOverride?.toString() || '999';
|
|
158
|
-
iframe.style.height = '100%';
|
|
159
|
-
iframe.style.width = '100%';
|
|
160
|
-
iframe.style.top = '0';
|
|
161
|
-
iframe.style.backgroundColor = 'none transparent';
|
|
162
|
-
iframe.style.border = 'none';
|
|
163
|
-
iframe.allow = 'clipboard-write; clipboard-read';
|
|
164
|
-
document.body.prepend(iframe);
|
|
165
|
-
document.body.style.overflow = 'hidden';
|
|
166
|
-
}
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
const open: OpenFn = (launchArgs) => {
|
|
170
|
-
const iframeSrc = constructAuthUrl({
|
|
171
|
-
sessionId: launchArgs.sessionId,
|
|
172
|
-
state: launchArgs.state,
|
|
173
|
-
apiConfig: initializeArgs.apiConfig,
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
createAndAttachIFrame({
|
|
177
|
-
src: iframeSrc,
|
|
178
|
-
zIndexOverride: launchArgs.zIndex,
|
|
179
|
-
});
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
const openPreview: OpenPreviewFn = (launchArgs) => {
|
|
183
|
-
const iframeSrc = constructPreviewUrl({
|
|
184
|
-
clientId: launchArgs.clientId,
|
|
185
|
-
products: launchArgs.products,
|
|
186
|
-
apiConfig: initializeArgs.apiConfig,
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
createAndAttachIFrame({
|
|
190
|
-
src: iframeSrc,
|
|
191
|
-
});
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
const close = () => {
|
|
195
|
-
const frameToRemove = document.getElementById(FINCH_CONNECT_IFRAME_ID);
|
|
196
|
-
if (frameToRemove) {
|
|
197
|
-
frameToRemove.parentNode?.removeChild(frameToRemove);
|
|
198
|
-
document.body.style.overflow = 'inherit';
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
useEffect(() => {
|
|
203
|
-
function handleFinchAuth(event: FinchConnectPostMessage) {
|
|
204
|
-
const CONNECT_URL = initializeArgs.apiConfig?.connectUrl || BASE_FINCH_CONNECT_URI;
|
|
205
|
-
|
|
206
|
-
if (!event.data) return;
|
|
207
|
-
if (event.data.name !== POST_MESSAGE_NAME) return;
|
|
208
|
-
if (!event.origin.startsWith(CONNECT_URL)) return;
|
|
209
|
-
|
|
210
|
-
if (event.data.kind !== 'error') close();
|
|
211
|
-
|
|
212
|
-
switch (event.data.kind) {
|
|
213
|
-
case 'closed':
|
|
214
|
-
initializeArgs.onClose();
|
|
215
|
-
break;
|
|
216
|
-
case 'error':
|
|
217
|
-
if (event.data.error?.shouldClose) close();
|
|
218
|
-
|
|
219
|
-
initializeArgs.onError({
|
|
220
|
-
errorMessage: event.data.error?.message,
|
|
221
|
-
errorType: event.data.error?.type,
|
|
222
|
-
});
|
|
223
|
-
break;
|
|
224
|
-
case 'success':
|
|
225
|
-
initializeArgs.onSuccess({
|
|
226
|
-
code: event.data.code,
|
|
227
|
-
state: event.data.state,
|
|
228
|
-
idpRedirectUri: event.data.idpRedirectUri,
|
|
229
|
-
});
|
|
230
|
-
break;
|
|
231
|
-
default: {
|
|
232
|
-
// This case should never happen, if it does it should be reported to us
|
|
233
|
-
initializeArgs.onError({
|
|
234
|
-
errorMessage: `Report to developers@tryfinch.com: unable to handle window.postMessage for: ${JSON.stringify(
|
|
235
|
-
event.data
|
|
236
|
-
)}`,
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
window.addEventListener('message', handleFinchAuth);
|
|
243
|
-
return () => {
|
|
244
|
-
window.removeEventListener('message', handleFinchAuth);
|
|
245
|
-
isUseFinchConnectInitialized = false;
|
|
246
|
-
};
|
|
247
|
-
}, [initializeArgs.onClose, initializeArgs.onError, initializeArgs.onSuccess]);
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
open,
|
|
251
|
-
openPreview,
|
|
252
|
-
};
|
|
253
|
-
};
|
package/tsconfig.json
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es2016",
|
|
4
|
-
"module": "esnext",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"declarationMap": true,
|
|
7
|
-
"sourceMap": true,
|
|
8
|
-
"outDir": "./",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"forceConsistentCasingInFileNames": true,
|
|
11
|
-
"strict": true
|
|
12
|
-
},
|
|
13
|
-
"include": ["src/**/*"],
|
|
14
|
-
"exclude": ["node_modules", "example/**/*"]
|
|
15
|
-
}
|