valyd-verify-js 0.1.0
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/LICENSE +21 -0
- package/README.md +89 -0
- package/dist/index.cjs +195 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.global.js +197 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +174 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Valyd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# valyd-verify-js
|
|
2
|
+
|
|
3
|
+
Browser SDK for **Valyd Verify** — launch hosted identity verification in a **modal** or **popup** and get the result via a callback. No full-page redirect.
|
|
4
|
+
|
|
5
|
+
- Zero dependencies, ~3 kB
|
|
6
|
+
- Works via npm (`import`) or a `<script>` tag (CDN)
|
|
7
|
+
- The API key stays on **your server** — this SDK only opens the hosted page
|
|
8
|
+
|
|
9
|
+
## How it fits together
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Your server ── valyd-verify-sdk ──> POST /api/v2/session ──> { url }
|
|
13
|
+
│
|
|
14
|
+
└── sends session.url to the browser
|
|
15
|
+
Your browser ── valyd-verify-js ──> ValydVerify.open({ url }) ──> onComplete({ sessionId, status })
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The webhook + `sessions.decision(id)` (server-side) remain the source of truth; the browser result is a UX signal.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm i valyd-verify-js
|
|
24
|
+
```
|
|
25
|
+
or via CDN:
|
|
26
|
+
```html
|
|
27
|
+
<script src="https://unpkg.com/valyd-verify-js"></script>
|
|
28
|
+
<!-- exposes window.ValydVerify -->
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { open } from "valyd-verify-js";
|
|
35
|
+
|
|
36
|
+
// `url` comes from your server: const { url } = await verify.sessions.create({ workflowId })
|
|
37
|
+
await open({
|
|
38
|
+
url,
|
|
39
|
+
mode: "modal", // "modal" (default) | "popup"
|
|
40
|
+
onComplete: ({ sessionId, status }) => {
|
|
41
|
+
// confirm server-side via the webhook or sessions.decision(sessionId)
|
|
42
|
+
console.log("done", status);
|
|
43
|
+
},
|
|
44
|
+
onClose: () => console.log("user closed"),
|
|
45
|
+
onError: (e) => console.error(e.message),
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Script-tag equivalent:
|
|
50
|
+
```html
|
|
51
|
+
<button id="verify">Verify</button>
|
|
52
|
+
<script src="https://unpkg.com/valyd-verify-js"></script>
|
|
53
|
+
<script>
|
|
54
|
+
document.getElementById("verify").onclick = async () => {
|
|
55
|
+
const url = await fetch("/api/create-verify-session").then(r => r.json()).then(d => d.url);
|
|
56
|
+
ValydVerify.open({ url, onComplete: (r) => alert("Verification " + r.status) });
|
|
57
|
+
};
|
|
58
|
+
</script>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
> Open it from a user click so popups aren't blocked (modal mode is unaffected).
|
|
62
|
+
|
|
63
|
+
## API
|
|
64
|
+
|
|
65
|
+
- `open(options) => Promise<{ sessionId, status }>` — resolves on completion; rejects with `Error("closed" | "popup_blocked" | …)` otherwise. Prefer the callbacks for UX.
|
|
66
|
+
- `modal(url, opts?)` / `popup(url, opts?)` — shorthands.
|
|
67
|
+
|
|
68
|
+
### Options
|
|
69
|
+
| Field | | |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| `url` | string | **required** — the hosted session URL from `sessions.create` |
|
|
72
|
+
| `mode` | `"modal"` \| `"popup"` | default `"modal"` |
|
|
73
|
+
| `onReady` | fn | hosted page loaded |
|
|
74
|
+
| `onComplete` | `({ sessionId, status }) => void` | verification finished |
|
|
75
|
+
| `onClose` | `() => void` | user closed/abandoned |
|
|
76
|
+
| `onError` | `({ message }) => void` | error opening/running |
|
|
77
|
+
|
|
78
|
+
## Modes
|
|
79
|
+
|
|
80
|
+
- **modal** — an in-page overlay with an `<iframe allow="camera">` of the hosted page. The user stays on your site. Clicking the backdrop closes it.
|
|
81
|
+
- **popup** — opens the hosted page in a separate `window.open` window; result returned via `window.opener`.
|
|
82
|
+
|
|
83
|
+
## Security
|
|
84
|
+
|
|
85
|
+
The SDK appends `&origin=<your origin>` to the URL; the hosted page posts results only to that origin. Inbound messages are accepted only when `event.origin` matches the Valyd host **and** `event.source` is the window the SDK opened.
|
|
86
|
+
|
|
87
|
+
## License
|
|
88
|
+
|
|
89
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
default: () => index_default,
|
|
24
|
+
modal: () => modal,
|
|
25
|
+
open: () => open,
|
|
26
|
+
popup: () => popup
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
var MESSAGE_SOURCE = "valyd-verify";
|
|
30
|
+
var OVERLAY_ID = "valyd-verify-overlay";
|
|
31
|
+
function buildUrl(rawUrl, mode) {
|
|
32
|
+
const u = new URL(rawUrl, window.location.href);
|
|
33
|
+
u.searchParams.set("display", mode);
|
|
34
|
+
u.searchParams.set("origin", window.location.origin);
|
|
35
|
+
return u.toString();
|
|
36
|
+
}
|
|
37
|
+
function buildModal(url) {
|
|
38
|
+
const overlay = document.createElement("div");
|
|
39
|
+
overlay.id = OVERLAY_ID;
|
|
40
|
+
Object.assign(overlay.style, {
|
|
41
|
+
position: "fixed",
|
|
42
|
+
inset: "0",
|
|
43
|
+
background: "rgba(15, 23, 42, 0.6)",
|
|
44
|
+
display: "flex",
|
|
45
|
+
alignItems: "center",
|
|
46
|
+
justifyContent: "center",
|
|
47
|
+
padding: "16px",
|
|
48
|
+
zIndex: "2147483647"
|
|
49
|
+
});
|
|
50
|
+
const frame = document.createElement("div");
|
|
51
|
+
Object.assign(frame.style, {
|
|
52
|
+
position: "relative",
|
|
53
|
+
width: "100%",
|
|
54
|
+
maxWidth: "440px",
|
|
55
|
+
height: "100%",
|
|
56
|
+
maxHeight: "760px",
|
|
57
|
+
borderRadius: "16px",
|
|
58
|
+
overflow: "hidden",
|
|
59
|
+
boxShadow: "0 24px 64px rgba(0,0,0,0.35)",
|
|
60
|
+
background: "#fff"
|
|
61
|
+
});
|
|
62
|
+
const iframe = document.createElement("iframe");
|
|
63
|
+
iframe.src = url;
|
|
64
|
+
iframe.allow = "camera; microphone; fullscreen";
|
|
65
|
+
iframe.setAttribute("title", "Valyd Verify");
|
|
66
|
+
Object.assign(iframe.style, {
|
|
67
|
+
width: "100%",
|
|
68
|
+
height: "100%",
|
|
69
|
+
border: "0"
|
|
70
|
+
});
|
|
71
|
+
frame.appendChild(iframe);
|
|
72
|
+
overlay.appendChild(frame);
|
|
73
|
+
return { overlay, iframe };
|
|
74
|
+
}
|
|
75
|
+
function open(options) {
|
|
76
|
+
var _a;
|
|
77
|
+
const mode = (_a = options.mode) != null ? _a : "modal";
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
var _a2;
|
|
80
|
+
if (typeof window === "undefined") {
|
|
81
|
+
reject(new Error("valyd-verify-js must run in a browser"));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const url = buildUrl(options.url, mode);
|
|
85
|
+
const expectedOrigin = new URL(url).origin;
|
|
86
|
+
let settled = false;
|
|
87
|
+
let sourceWindow = null;
|
|
88
|
+
let teardown = () => {
|
|
89
|
+
};
|
|
90
|
+
const finish = (cb) => {
|
|
91
|
+
if (settled) return;
|
|
92
|
+
settled = true;
|
|
93
|
+
window.removeEventListener("message", onMessage);
|
|
94
|
+
teardown();
|
|
95
|
+
cb();
|
|
96
|
+
};
|
|
97
|
+
const onMessage = (event) => {
|
|
98
|
+
var _a3, _b, _c;
|
|
99
|
+
if (event.origin !== expectedOrigin) return;
|
|
100
|
+
const data = event.data;
|
|
101
|
+
if (!data || data.source !== MESSAGE_SOURCE) return;
|
|
102
|
+
if (sourceWindow && event.source !== sourceWindow) return;
|
|
103
|
+
switch (data.type) {
|
|
104
|
+
case "ready":
|
|
105
|
+
(_a3 = options.onReady) == null ? void 0 : _a3.call(options);
|
|
106
|
+
break;
|
|
107
|
+
case "complete": {
|
|
108
|
+
const result = { sessionId: (_b = data.sessionId) != null ? _b : "", status: (_c = data.status) != null ? _c : "" };
|
|
109
|
+
finish(() => {
|
|
110
|
+
var _a4;
|
|
111
|
+
(_a4 = options.onComplete) == null ? void 0 : _a4.call(options, result);
|
|
112
|
+
resolve(result);
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "close":
|
|
117
|
+
finish(() => {
|
|
118
|
+
var _a4;
|
|
119
|
+
(_a4 = options.onClose) == null ? void 0 : _a4.call(options);
|
|
120
|
+
reject(new Error("closed"));
|
|
121
|
+
});
|
|
122
|
+
break;
|
|
123
|
+
case "error":
|
|
124
|
+
finish(() => {
|
|
125
|
+
var _a4, _b2;
|
|
126
|
+
const err = { message: (_a4 = data.message) != null ? _a4 : "verification_error" };
|
|
127
|
+
(_b2 = options.onError) == null ? void 0 : _b2.call(options, err);
|
|
128
|
+
reject(new Error(err.message));
|
|
129
|
+
});
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
window.addEventListener("message", onMessage);
|
|
134
|
+
if (mode === "popup") {
|
|
135
|
+
const w = 480;
|
|
136
|
+
const h = 760;
|
|
137
|
+
const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
|
|
138
|
+
const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
|
|
139
|
+
const popup2 = window.open(
|
|
140
|
+
url,
|
|
141
|
+
"valyd-verify",
|
|
142
|
+
`width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`
|
|
143
|
+
);
|
|
144
|
+
if (!popup2) {
|
|
145
|
+
window.removeEventListener("message", onMessage);
|
|
146
|
+
const err = { message: "popup_blocked" };
|
|
147
|
+
(_a2 = options.onError) == null ? void 0 : _a2.call(options, err);
|
|
148
|
+
reject(new Error(err.message));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
sourceWindow = popup2;
|
|
152
|
+
const poll = window.setInterval(() => {
|
|
153
|
+
if (popup2.closed) finish(() => {
|
|
154
|
+
var _a3;
|
|
155
|
+
(_a3 = options.onClose) == null ? void 0 : _a3.call(options);
|
|
156
|
+
reject(new Error("closed"));
|
|
157
|
+
});
|
|
158
|
+
}, 500);
|
|
159
|
+
teardown = () => {
|
|
160
|
+
window.clearInterval(poll);
|
|
161
|
+
try {
|
|
162
|
+
if (!popup2.closed) popup2.close();
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
} else {
|
|
167
|
+
const existing = document.getElementById(OVERLAY_ID);
|
|
168
|
+
if (existing) existing.remove();
|
|
169
|
+
const { overlay, iframe } = buildModal(url);
|
|
170
|
+
overlay.addEventListener("click", (e) => {
|
|
171
|
+
if (e.target === overlay) finish(() => {
|
|
172
|
+
var _a3;
|
|
173
|
+
(_a3 = options.onClose) == null ? void 0 : _a3.call(options);
|
|
174
|
+
reject(new Error("closed"));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
document.body.appendChild(overlay);
|
|
178
|
+
const prevOverflow = document.body.style.overflow;
|
|
179
|
+
document.body.style.overflow = "hidden";
|
|
180
|
+
sourceWindow = iframe.contentWindow;
|
|
181
|
+
teardown = () => {
|
|
182
|
+
overlay.remove();
|
|
183
|
+
document.body.style.overflow = prevOverflow;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function modal(url, opts = {}) {
|
|
189
|
+
return open({ ...opts, url, mode: "modal" });
|
|
190
|
+
}
|
|
191
|
+
function popup(url, opts = {}) {
|
|
192
|
+
return open({ ...opts, url, mode: "popup" });
|
|
193
|
+
}
|
|
194
|
+
var index_default = { open, modal, popup };
|
|
195
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * valyd-verify-js — launch Valyd Verify hosted verification in a modal or popup,\n * with the result delivered via callback/Promise (no full-page redirect).\n *\n * The API key stays on YOUR server: create the session server-side with\n * `valyd-verify-sdk` (`sessions.create`), then pass the returned `session.url`\n * to `ValydVerify.open({ url })` in the browser.\n */\n\nexport type VerifyMode = \"modal\" | \"popup\";\n\nexport interface VerifyResult {\n sessionId: string;\n status: string;\n}\n\nexport interface OpenOptions {\n /** The hosted session URL returned by sessions.create (contains the token). */\n url: string;\n /** \"modal\" (in-page iframe overlay, default) or \"popup\" (separate window). */\n mode?: VerifyMode;\n onReady?: () => void;\n onComplete?: (result: VerifyResult) => void;\n /** Fired when the user closes/abandons the flow. */\n onClose?: () => void;\n onError?: (error: { message: string }) => void;\n}\n\ninterface EmbedInbound {\n source?: string;\n type?: \"ready\" | \"complete\" | \"close\" | \"error\";\n sessionId?: string;\n status?: string;\n message?: string;\n}\n\nconst MESSAGE_SOURCE = \"valyd-verify\";\nconst OVERLAY_ID = \"valyd-verify-overlay\";\n\nfunction buildUrl(rawUrl: string, mode: VerifyMode): string {\n const u = new URL(rawUrl, window.location.href);\n u.searchParams.set(\"display\", mode);\n u.searchParams.set(\"origin\", window.location.origin);\n return u.toString();\n}\n\nfunction buildModal(url: string): { overlay: HTMLDivElement; iframe: HTMLIFrameElement } {\n const overlay = document.createElement(\"div\");\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(15, 23, 42, 0.6)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n zIndex: \"2147483647\",\n });\n\n const frame = document.createElement(\"div\");\n Object.assign(frame.style, {\n position: \"relative\",\n width: \"100%\",\n maxWidth: \"440px\",\n height: \"100%\",\n maxHeight: \"760px\",\n borderRadius: \"16px\",\n overflow: \"hidden\",\n boxShadow: \"0 24px 64px rgba(0,0,0,0.35)\",\n background: \"#fff\",\n });\n\n const iframe = document.createElement(\"iframe\");\n iframe.src = url;\n iframe.allow = \"camera; microphone; fullscreen\";\n iframe.setAttribute(\"title\", \"Valyd Verify\");\n Object.assign(iframe.style, {\n width: \"100%\",\n height: \"100%\",\n border: \"0\",\n });\n\n frame.appendChild(iframe);\n overlay.appendChild(frame);\n return { overlay, iframe };\n}\n\n/**\n * Open the hosted verification flow. Resolves with the result on completion;\n * rejects with an Error (`code` on `.message`: \"closed\" | \"popup_blocked\" | …)\n * when the user closes it or an error occurs. Prefer the callbacks for UX.\n */\nexport function open(options: OpenOptions): Promise<VerifyResult> {\n const mode: VerifyMode = options.mode ?? \"modal\";\n\n return new Promise<VerifyResult>((resolve, reject) => {\n if (typeof window === \"undefined\") {\n reject(new Error(\"valyd-verify-js must run in a browser\"));\n return;\n }\n\n const url = buildUrl(options.url, mode);\n const expectedOrigin = new URL(url).origin;\n\n let settled = false;\n let sourceWindow: Window | null = null;\n let teardown: () => void = () => {};\n\n const finish = (cb: () => void) => {\n if (settled) return;\n settled = true;\n window.removeEventListener(\"message\", onMessage);\n teardown();\n cb();\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) return;\n const data = event.data as EmbedInbound | null;\n if (!data || data.source !== MESSAGE_SOURCE) return;\n // Only trust messages from the window we opened.\n if (sourceWindow && event.source !== sourceWindow) return;\n\n switch (data.type) {\n case \"ready\":\n options.onReady?.();\n break;\n case \"complete\": {\n const result: VerifyResult = { sessionId: data.sessionId ?? \"\", status: data.status ?? \"\" };\n finish(() => {\n options.onComplete?.(result);\n resolve(result);\n });\n break;\n }\n case \"close\":\n finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n break;\n case \"error\":\n finish(() => {\n const err = { message: data.message ?? \"verification_error\" };\n options.onError?.(err);\n reject(new Error(err.message));\n });\n break;\n }\n };\n\n window.addEventListener(\"message\", onMessage);\n\n if (mode === \"popup\") {\n const w = 480;\n const h = 760;\n const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);\n const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);\n const popup = window.open(\n url,\n \"valyd-verify\",\n `width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`,\n );\n if (!popup) {\n window.removeEventListener(\"message\", onMessage);\n const err = { message: \"popup_blocked\" };\n options.onError?.(err);\n reject(new Error(err.message));\n return;\n }\n sourceWindow = popup;\n const poll = window.setInterval(() => {\n if (popup.closed) finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n }, 500);\n teardown = () => {\n window.clearInterval(poll);\n try {\n if (!popup.closed) popup.close();\n } catch {\n /* ignore */\n }\n };\n } else {\n const existing = document.getElementById(OVERLAY_ID);\n if (existing) existing.remove();\n const { overlay, iframe } = buildModal(url);\n // Click on the dark backdrop (outside the frame) closes the flow.\n overlay.addEventListener(\"click\", (e) => {\n if (e.target === overlay) finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n });\n document.body.appendChild(overlay);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n sourceWindow = iframe.contentWindow;\n teardown = () => {\n overlay.remove();\n document.body.style.overflow = prevOverflow;\n };\n }\n });\n}\n\nexport function modal(url: string, opts: Omit<OpenOptions, \"url\" | \"mode\"> = {}): Promise<VerifyResult> {\n return open({ ...opts, url, mode: \"modal\" });\n}\n\nexport function popup(url: string, opts: Omit<OpenOptions, \"url\" | \"mode\"> = {}): Promise<VerifyResult> {\n return open({ ...opts, url, mode: \"popup\" });\n}\n\nexport default { open, modal, popup };\n"],"mappings":"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","names":["_a","_b","popup"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* valyd-verify-js — launch Valyd Verify hosted verification in a modal or popup,
|
|
3
|
+
* with the result delivered via callback/Promise (no full-page redirect).
|
|
4
|
+
*
|
|
5
|
+
* The API key stays on YOUR server: create the session server-side with
|
|
6
|
+
* `valyd-verify-sdk` (`sessions.create`), then pass the returned `session.url`
|
|
7
|
+
* to `ValydVerify.open({ url })` in the browser.
|
|
8
|
+
*/
|
|
9
|
+
type VerifyMode = "modal" | "popup";
|
|
10
|
+
interface VerifyResult {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
status: string;
|
|
13
|
+
}
|
|
14
|
+
interface OpenOptions {
|
|
15
|
+
/** The hosted session URL returned by sessions.create (contains the token). */
|
|
16
|
+
url: string;
|
|
17
|
+
/** "modal" (in-page iframe overlay, default) or "popup" (separate window). */
|
|
18
|
+
mode?: VerifyMode;
|
|
19
|
+
onReady?: () => void;
|
|
20
|
+
onComplete?: (result: VerifyResult) => void;
|
|
21
|
+
/** Fired when the user closes/abandons the flow. */
|
|
22
|
+
onClose?: () => void;
|
|
23
|
+
onError?: (error: {
|
|
24
|
+
message: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Open the hosted verification flow. Resolves with the result on completion;
|
|
29
|
+
* rejects with an Error (`code` on `.message`: "closed" | "popup_blocked" | …)
|
|
30
|
+
* when the user closes it or an error occurs. Prefer the callbacks for UX.
|
|
31
|
+
*/
|
|
32
|
+
declare function open(options: OpenOptions): Promise<VerifyResult>;
|
|
33
|
+
declare function modal(url: string, opts?: Omit<OpenOptions, "url" | "mode">): Promise<VerifyResult>;
|
|
34
|
+
declare function popup(url: string, opts?: Omit<OpenOptions, "url" | "mode">): Promise<VerifyResult>;
|
|
35
|
+
declare const _default: {
|
|
36
|
+
open: typeof open;
|
|
37
|
+
modal: typeof modal;
|
|
38
|
+
popup: typeof popup;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { type OpenOptions, type VerifyMode, type VerifyResult, _default as default, modal, open, popup };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* valyd-verify-js — launch Valyd Verify hosted verification in a modal or popup,
|
|
3
|
+
* with the result delivered via callback/Promise (no full-page redirect).
|
|
4
|
+
*
|
|
5
|
+
* The API key stays on YOUR server: create the session server-side with
|
|
6
|
+
* `valyd-verify-sdk` (`sessions.create`), then pass the returned `session.url`
|
|
7
|
+
* to `ValydVerify.open({ url })` in the browser.
|
|
8
|
+
*/
|
|
9
|
+
type VerifyMode = "modal" | "popup";
|
|
10
|
+
interface VerifyResult {
|
|
11
|
+
sessionId: string;
|
|
12
|
+
status: string;
|
|
13
|
+
}
|
|
14
|
+
interface OpenOptions {
|
|
15
|
+
/** The hosted session URL returned by sessions.create (contains the token). */
|
|
16
|
+
url: string;
|
|
17
|
+
/** "modal" (in-page iframe overlay, default) or "popup" (separate window). */
|
|
18
|
+
mode?: VerifyMode;
|
|
19
|
+
onReady?: () => void;
|
|
20
|
+
onComplete?: (result: VerifyResult) => void;
|
|
21
|
+
/** Fired when the user closes/abandons the flow. */
|
|
22
|
+
onClose?: () => void;
|
|
23
|
+
onError?: (error: {
|
|
24
|
+
message: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Open the hosted verification flow. Resolves with the result on completion;
|
|
29
|
+
* rejects with an Error (`code` on `.message`: "closed" | "popup_blocked" | …)
|
|
30
|
+
* when the user closes it or an error occurs. Prefer the callbacks for UX.
|
|
31
|
+
*/
|
|
32
|
+
declare function open(options: OpenOptions): Promise<VerifyResult>;
|
|
33
|
+
declare function modal(url: string, opts?: Omit<OpenOptions, "url" | "mode">): Promise<VerifyResult>;
|
|
34
|
+
declare function popup(url: string, opts?: Omit<OpenOptions, "url" | "mode">): Promise<VerifyResult>;
|
|
35
|
+
declare const _default: {
|
|
36
|
+
open: typeof open;
|
|
37
|
+
modal: typeof modal;
|
|
38
|
+
popup: typeof popup;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export { type OpenOptions, type VerifyMode, type VerifyResult, _default as default, modal, open, popup };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var ValydVerify = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
default: () => index_default,
|
|
25
|
+
modal: () => modal,
|
|
26
|
+
open: () => open,
|
|
27
|
+
popup: () => popup
|
|
28
|
+
});
|
|
29
|
+
var MESSAGE_SOURCE = "valyd-verify";
|
|
30
|
+
var OVERLAY_ID = "valyd-verify-overlay";
|
|
31
|
+
function buildUrl(rawUrl, mode) {
|
|
32
|
+
const u = new URL(rawUrl, window.location.href);
|
|
33
|
+
u.searchParams.set("display", mode);
|
|
34
|
+
u.searchParams.set("origin", window.location.origin);
|
|
35
|
+
return u.toString();
|
|
36
|
+
}
|
|
37
|
+
function buildModal(url) {
|
|
38
|
+
const overlay = document.createElement("div");
|
|
39
|
+
overlay.id = OVERLAY_ID;
|
|
40
|
+
Object.assign(overlay.style, {
|
|
41
|
+
position: "fixed",
|
|
42
|
+
inset: "0",
|
|
43
|
+
background: "rgba(15, 23, 42, 0.6)",
|
|
44
|
+
display: "flex",
|
|
45
|
+
alignItems: "center",
|
|
46
|
+
justifyContent: "center",
|
|
47
|
+
padding: "16px",
|
|
48
|
+
zIndex: "2147483647"
|
|
49
|
+
});
|
|
50
|
+
const frame = document.createElement("div");
|
|
51
|
+
Object.assign(frame.style, {
|
|
52
|
+
position: "relative",
|
|
53
|
+
width: "100%",
|
|
54
|
+
maxWidth: "440px",
|
|
55
|
+
height: "100%",
|
|
56
|
+
maxHeight: "760px",
|
|
57
|
+
borderRadius: "16px",
|
|
58
|
+
overflow: "hidden",
|
|
59
|
+
boxShadow: "0 24px 64px rgba(0,0,0,0.35)",
|
|
60
|
+
background: "#fff"
|
|
61
|
+
});
|
|
62
|
+
const iframe = document.createElement("iframe");
|
|
63
|
+
iframe.src = url;
|
|
64
|
+
iframe.allow = "camera; microphone; fullscreen";
|
|
65
|
+
iframe.setAttribute("title", "Valyd Verify");
|
|
66
|
+
Object.assign(iframe.style, {
|
|
67
|
+
width: "100%",
|
|
68
|
+
height: "100%",
|
|
69
|
+
border: "0"
|
|
70
|
+
});
|
|
71
|
+
frame.appendChild(iframe);
|
|
72
|
+
overlay.appendChild(frame);
|
|
73
|
+
return { overlay, iframe };
|
|
74
|
+
}
|
|
75
|
+
function open(options) {
|
|
76
|
+
var _a;
|
|
77
|
+
const mode = (_a = options.mode) != null ? _a : "modal";
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
var _a2;
|
|
80
|
+
if (typeof window === "undefined") {
|
|
81
|
+
reject(new Error("valyd-verify-js must run in a browser"));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const url = buildUrl(options.url, mode);
|
|
85
|
+
const expectedOrigin = new URL(url).origin;
|
|
86
|
+
let settled = false;
|
|
87
|
+
let sourceWindow = null;
|
|
88
|
+
let teardown = () => {
|
|
89
|
+
};
|
|
90
|
+
const finish = (cb) => {
|
|
91
|
+
if (settled) return;
|
|
92
|
+
settled = true;
|
|
93
|
+
window.removeEventListener("message", onMessage);
|
|
94
|
+
teardown();
|
|
95
|
+
cb();
|
|
96
|
+
};
|
|
97
|
+
const onMessage = (event) => {
|
|
98
|
+
var _a3, _b, _c;
|
|
99
|
+
if (event.origin !== expectedOrigin) return;
|
|
100
|
+
const data = event.data;
|
|
101
|
+
if (!data || data.source !== MESSAGE_SOURCE) return;
|
|
102
|
+
if (sourceWindow && event.source !== sourceWindow) return;
|
|
103
|
+
switch (data.type) {
|
|
104
|
+
case "ready":
|
|
105
|
+
(_a3 = options.onReady) == null ? void 0 : _a3.call(options);
|
|
106
|
+
break;
|
|
107
|
+
case "complete": {
|
|
108
|
+
const result = { sessionId: (_b = data.sessionId) != null ? _b : "", status: (_c = data.status) != null ? _c : "" };
|
|
109
|
+
finish(() => {
|
|
110
|
+
var _a4;
|
|
111
|
+
(_a4 = options.onComplete) == null ? void 0 : _a4.call(options, result);
|
|
112
|
+
resolve(result);
|
|
113
|
+
});
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case "close":
|
|
117
|
+
finish(() => {
|
|
118
|
+
var _a4;
|
|
119
|
+
(_a4 = options.onClose) == null ? void 0 : _a4.call(options);
|
|
120
|
+
reject(new Error("closed"));
|
|
121
|
+
});
|
|
122
|
+
break;
|
|
123
|
+
case "error":
|
|
124
|
+
finish(() => {
|
|
125
|
+
var _a4, _b2;
|
|
126
|
+
const err = { message: (_a4 = data.message) != null ? _a4 : "verification_error" };
|
|
127
|
+
(_b2 = options.onError) == null ? void 0 : _b2.call(options, err);
|
|
128
|
+
reject(new Error(err.message));
|
|
129
|
+
});
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
window.addEventListener("message", onMessage);
|
|
134
|
+
if (mode === "popup") {
|
|
135
|
+
const w = 480;
|
|
136
|
+
const h = 760;
|
|
137
|
+
const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
|
|
138
|
+
const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
|
|
139
|
+
const popup2 = window.open(
|
|
140
|
+
url,
|
|
141
|
+
"valyd-verify",
|
|
142
|
+
`width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`
|
|
143
|
+
);
|
|
144
|
+
if (!popup2) {
|
|
145
|
+
window.removeEventListener("message", onMessage);
|
|
146
|
+
const err = { message: "popup_blocked" };
|
|
147
|
+
(_a2 = options.onError) == null ? void 0 : _a2.call(options, err);
|
|
148
|
+
reject(new Error(err.message));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
sourceWindow = popup2;
|
|
152
|
+
const poll = window.setInterval(() => {
|
|
153
|
+
if (popup2.closed) finish(() => {
|
|
154
|
+
var _a3;
|
|
155
|
+
(_a3 = options.onClose) == null ? void 0 : _a3.call(options);
|
|
156
|
+
reject(new Error("closed"));
|
|
157
|
+
});
|
|
158
|
+
}, 500);
|
|
159
|
+
teardown = () => {
|
|
160
|
+
window.clearInterval(poll);
|
|
161
|
+
try {
|
|
162
|
+
if (!popup2.closed) popup2.close();
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
} else {
|
|
167
|
+
const existing = document.getElementById(OVERLAY_ID);
|
|
168
|
+
if (existing) existing.remove();
|
|
169
|
+
const { overlay, iframe } = buildModal(url);
|
|
170
|
+
overlay.addEventListener("click", (e) => {
|
|
171
|
+
if (e.target === overlay) finish(() => {
|
|
172
|
+
var _a3;
|
|
173
|
+
(_a3 = options.onClose) == null ? void 0 : _a3.call(options);
|
|
174
|
+
reject(new Error("closed"));
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
document.body.appendChild(overlay);
|
|
178
|
+
const prevOverflow = document.body.style.overflow;
|
|
179
|
+
document.body.style.overflow = "hidden";
|
|
180
|
+
sourceWindow = iframe.contentWindow;
|
|
181
|
+
teardown = () => {
|
|
182
|
+
overlay.remove();
|
|
183
|
+
document.body.style.overflow = prevOverflow;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
function modal(url, opts = {}) {
|
|
189
|
+
return open({ ...opts, url, mode: "modal" });
|
|
190
|
+
}
|
|
191
|
+
function popup(url, opts = {}) {
|
|
192
|
+
return open({ ...opts, url, mode: "popup" });
|
|
193
|
+
}
|
|
194
|
+
var index_default = { open, modal, popup };
|
|
195
|
+
return __toCommonJS(index_exports);
|
|
196
|
+
})();
|
|
197
|
+
//# sourceMappingURL=index.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * valyd-verify-js — launch Valyd Verify hosted verification in a modal or popup,\n * with the result delivered via callback/Promise (no full-page redirect).\n *\n * The API key stays on YOUR server: create the session server-side with\n * `valyd-verify-sdk` (`sessions.create`), then pass the returned `session.url`\n * to `ValydVerify.open({ url })` in the browser.\n */\n\nexport type VerifyMode = \"modal\" | \"popup\";\n\nexport interface VerifyResult {\n sessionId: string;\n status: string;\n}\n\nexport interface OpenOptions {\n /** The hosted session URL returned by sessions.create (contains the token). */\n url: string;\n /** \"modal\" (in-page iframe overlay, default) or \"popup\" (separate window). */\n mode?: VerifyMode;\n onReady?: () => void;\n onComplete?: (result: VerifyResult) => void;\n /** Fired when the user closes/abandons the flow. */\n onClose?: () => void;\n onError?: (error: { message: string }) => void;\n}\n\ninterface EmbedInbound {\n source?: string;\n type?: \"ready\" | \"complete\" | \"close\" | \"error\";\n sessionId?: string;\n status?: string;\n message?: string;\n}\n\nconst MESSAGE_SOURCE = \"valyd-verify\";\nconst OVERLAY_ID = \"valyd-verify-overlay\";\n\nfunction buildUrl(rawUrl: string, mode: VerifyMode): string {\n const u = new URL(rawUrl, window.location.href);\n u.searchParams.set(\"display\", mode);\n u.searchParams.set(\"origin\", window.location.origin);\n return u.toString();\n}\n\nfunction buildModal(url: string): { overlay: HTMLDivElement; iframe: HTMLIFrameElement } {\n const overlay = document.createElement(\"div\");\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(15, 23, 42, 0.6)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n zIndex: \"2147483647\",\n });\n\n const frame = document.createElement(\"div\");\n Object.assign(frame.style, {\n position: \"relative\",\n width: \"100%\",\n maxWidth: \"440px\",\n height: \"100%\",\n maxHeight: \"760px\",\n borderRadius: \"16px\",\n overflow: \"hidden\",\n boxShadow: \"0 24px 64px rgba(0,0,0,0.35)\",\n background: \"#fff\",\n });\n\n const iframe = document.createElement(\"iframe\");\n iframe.src = url;\n iframe.allow = \"camera; microphone; fullscreen\";\n iframe.setAttribute(\"title\", \"Valyd Verify\");\n Object.assign(iframe.style, {\n width: \"100%\",\n height: \"100%\",\n border: \"0\",\n });\n\n frame.appendChild(iframe);\n overlay.appendChild(frame);\n return { overlay, iframe };\n}\n\n/**\n * Open the hosted verification flow. Resolves with the result on completion;\n * rejects with an Error (`code` on `.message`: \"closed\" | \"popup_blocked\" | …)\n * when the user closes it or an error occurs. Prefer the callbacks for UX.\n */\nexport function open(options: OpenOptions): Promise<VerifyResult> {\n const mode: VerifyMode = options.mode ?? \"modal\";\n\n return new Promise<VerifyResult>((resolve, reject) => {\n if (typeof window === \"undefined\") {\n reject(new Error(\"valyd-verify-js must run in a browser\"));\n return;\n }\n\n const url = buildUrl(options.url, mode);\n const expectedOrigin = new URL(url).origin;\n\n let settled = false;\n let sourceWindow: Window | null = null;\n let teardown: () => void = () => {};\n\n const finish = (cb: () => void) => {\n if (settled) return;\n settled = true;\n window.removeEventListener(\"message\", onMessage);\n teardown();\n cb();\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) return;\n const data = event.data as EmbedInbound | null;\n if (!data || data.source !== MESSAGE_SOURCE) return;\n // Only trust messages from the window we opened.\n if (sourceWindow && event.source !== sourceWindow) return;\n\n switch (data.type) {\n case \"ready\":\n options.onReady?.();\n break;\n case \"complete\": {\n const result: VerifyResult = { sessionId: data.sessionId ?? \"\", status: data.status ?? \"\" };\n finish(() => {\n options.onComplete?.(result);\n resolve(result);\n });\n break;\n }\n case \"close\":\n finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n break;\n case \"error\":\n finish(() => {\n const err = { message: data.message ?? \"verification_error\" };\n options.onError?.(err);\n reject(new Error(err.message));\n });\n break;\n }\n };\n\n window.addEventListener(\"message\", onMessage);\n\n if (mode === \"popup\") {\n const w = 480;\n const h = 760;\n const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);\n const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);\n const popup = window.open(\n url,\n \"valyd-verify\",\n `width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`,\n );\n if (!popup) {\n window.removeEventListener(\"message\", onMessage);\n const err = { message: \"popup_blocked\" };\n options.onError?.(err);\n reject(new Error(err.message));\n return;\n }\n sourceWindow = popup;\n const poll = window.setInterval(() => {\n if (popup.closed) finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n }, 500);\n teardown = () => {\n window.clearInterval(poll);\n try {\n if (!popup.closed) popup.close();\n } catch {\n /* ignore */\n }\n };\n } else {\n const existing = document.getElementById(OVERLAY_ID);\n if (existing) existing.remove();\n const { overlay, iframe } = buildModal(url);\n // Click on the dark backdrop (outside the frame) closes the flow.\n overlay.addEventListener(\"click\", (e) => {\n if (e.target === overlay) finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n });\n document.body.appendChild(overlay);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n sourceWindow = iframe.contentWindow;\n teardown = () => {\n overlay.remove();\n document.body.style.overflow = prevOverflow;\n };\n }\n });\n}\n\nexport function modal(url: string, opts: Omit<OpenOptions, \"url\" | \"mode\"> = {}): Promise<VerifyResult> {\n return open({ ...opts, url, mode: \"modal\" });\n}\n\nexport function popup(url: string, opts: Omit<OpenOptions, \"url\" | \"mode\"> = {}): Promise<VerifyResult> {\n return open({ ...opts, url, mode: \"popup\" });\n}\n\nexport default { open, modal, popup };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoCA,MAAM,iBAAiB;AACvB,MAAM,aAAa;AAEnB,WAAS,SAAS,QAAgB,MAA0B;AAC1D,UAAM,IAAI,IAAI,IAAI,QAAQ,OAAO,SAAS,IAAI;AAC9C,MAAE,aAAa,IAAI,WAAW,IAAI;AAClC,MAAE,aAAa,IAAI,UAAU,OAAO,SAAS,MAAM;AACnD,WAAO,EAAE,SAAS;AAAA,EACpB;AAEA,WAAS,WAAW,KAAqE;AACvF,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,KAAK;AACb,WAAO,OAAO,QAAQ,OAAO;AAAA,MAC3B,UAAU;AAAA,MACV,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,WAAO,OAAO,MAAM,OAAO;AAAA,MACzB,UAAU;AAAA,MACV,OAAO;AAAA,MACP,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,cAAc;AAAA,MACd,UAAU;AAAA,MACV,WAAW;AAAA,MACX,YAAY;AAAA,IACd,CAAC;AAED,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,MAAM;AACb,WAAO,QAAQ;AACf,WAAO,aAAa,SAAS,cAAc;AAC3C,WAAO,OAAO,OAAO,OAAO;AAAA,MAC1B,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,YAAY,MAAM;AACxB,YAAQ,YAAY,KAAK;AACzB,WAAO,EAAE,SAAS,OAAO;AAAA,EAC3B;AAOO,WAAS,KAAK,SAA6C;AA7FlE;AA8FE,UAAM,QAAmB,aAAQ,SAAR,YAAgB;AAEzC,WAAO,IAAI,QAAsB,CAAC,SAAS,WAAW;AAhGxD,UAAAA;AAiGI,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO,IAAI,MAAM,uCAAuC,CAAC;AACzD;AAAA,MACF;AAEA,YAAM,MAAM,SAAS,QAAQ,KAAK,IAAI;AACtC,YAAM,iBAAiB,IAAI,IAAI,GAAG,EAAE;AAEpC,UAAI,UAAU;AACd,UAAI,eAA8B;AAClC,UAAI,WAAuB,MAAM;AAAA,MAAC;AAElC,YAAM,SAAS,CAAC,OAAmB;AACjC,YAAI,QAAS;AACb,kBAAU;AACV,eAAO,oBAAoB,WAAW,SAAS;AAC/C,iBAAS;AACT,WAAG;AAAA,MACL;AAEA,YAAM,YAAY,CAAC,UAAwB;AArH/C,YAAAA,KAAA;AAsHM,YAAI,MAAM,WAAW,eAAgB;AACrC,cAAM,OAAO,MAAM;AACnB,YAAI,CAAC,QAAQ,KAAK,WAAW,eAAgB;AAE7C,YAAI,gBAAgB,MAAM,WAAW,aAAc;AAEnD,gBAAQ,KAAK,MAAM;AAAA,UACjB,KAAK;AACH,aAAAA,MAAA,QAAQ,YAAR,gBAAAA,IAAA;AACA;AAAA,UACF,KAAK,YAAY;AACf,kBAAM,SAAuB,EAAE,YAAW,UAAK,cAAL,YAAkB,IAAI,SAAQ,UAAK,WAAL,YAAe,GAAG;AAC1F,mBAAO,MAAM;AAlIvB,kBAAAA;AAmIY,eAAAA,MAAA,QAAQ,eAAR,gBAAAA,IAAA,cAAqB;AACrB,sBAAQ,MAAM;AAAA,YAChB,CAAC;AACD;AAAA,UACF;AAAA,UACA,KAAK;AACH,mBAAO,MAAM;AAzIvB,kBAAAA;AA0IY,eAAAA,MAAA,QAAQ,YAAR,gBAAAA,IAAA;AACA,qBAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,YAC5B,CAAC;AACD;AAAA,UACF,KAAK;AACH,mBAAO,MAAM;AA/IvB,kBAAAA,KAAAC;AAgJY,oBAAM,MAAM,EAAE,UAASD,MAAA,KAAK,YAAL,OAAAA,MAAgB,qBAAqB;AAC5D,eAAAC,MAAA,QAAQ,YAAR,gBAAAA,IAAA,cAAkB;AAClB,qBAAO,IAAI,MAAM,IAAI,OAAO,CAAC;AAAA,YAC/B,CAAC;AACD;AAAA,QACJ;AAAA,MACF;AAEA,aAAO,iBAAiB,WAAW,SAAS;AAE5C,UAAI,SAAS,SAAS;AACpB,cAAM,IAAI;AACV,cAAM,IAAI;AACV,cAAM,OAAO,OAAO,UAAU,KAAK,IAAI,IAAI,OAAO,aAAa,KAAK,CAAC;AACrE,cAAM,MAAM,OAAO,UAAU,KAAK,IAAI,IAAI,OAAO,cAAc,KAAK,CAAC;AACrE,cAAMC,SAAQ,OAAO;AAAA,UACnB;AAAA,UACA;AAAA,UACA,SAAS,CAAC,WAAW,CAAC,SAAS,IAAI,QAAQ,GAAG;AAAA,QAChD;AACA,YAAI,CAACA,QAAO;AACV,iBAAO,oBAAoB,WAAW,SAAS;AAC/C,gBAAM,MAAM,EAAE,SAAS,gBAAgB;AACvC,WAAAF,MAAA,QAAQ,YAAR,gBAAAA,IAAA,cAAkB;AAClB,iBAAO,IAAI,MAAM,IAAI,OAAO,CAAC;AAC7B;AAAA,QACF;AACA,uBAAeE;AACf,cAAM,OAAO,OAAO,YAAY,MAAM;AACpC,cAAIA,OAAM,OAAQ,QAAO,MAAM;AA7KvC,gBAAAF;AA8KU,aAAAA,MAAA,QAAQ,YAAR,gBAAAA,IAAA;AACA,mBAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,UAC5B,CAAC;AAAA,QACH,GAAG,GAAG;AACN,mBAAW,MAAM;AACf,iBAAO,cAAc,IAAI;AACzB,cAAI;AACF,gBAAI,CAACE,OAAM,OAAQ,CAAAA,OAAM,MAAM;AAAA,UACjC,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF,OAAO;AACL,cAAM,WAAW,SAAS,eAAe,UAAU;AACnD,YAAI,SAAU,UAAS,OAAO;AAC9B,cAAM,EAAE,SAAS,OAAO,IAAI,WAAW,GAAG;AAE1C,gBAAQ,iBAAiB,SAAS,CAAC,MAAM;AACvC,cAAI,EAAE,WAAW,QAAS,QAAO,MAAM;AAhM/C,gBAAAF;AAiMU,aAAAA,MAAA,QAAQ,YAAR,gBAAAA,IAAA;AACA,mBAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,UAC5B,CAAC;AAAA,QACH,CAAC;AACD,iBAAS,KAAK,YAAY,OAAO;AACjC,cAAM,eAAe,SAAS,KAAK,MAAM;AACzC,iBAAS,KAAK,MAAM,WAAW;AAC/B,uBAAe,OAAO;AACtB,mBAAW,MAAM;AACf,kBAAQ,OAAO;AACf,mBAAS,KAAK,MAAM,WAAW;AAAA,QACjC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAEO,WAAS,MAAM,KAAa,OAA0C,CAAC,GAA0B;AACtG,WAAO,KAAK,EAAE,GAAG,MAAM,KAAK,MAAM,QAAQ,CAAC;AAAA,EAC7C;AAEO,WAAS,MAAM,KAAa,OAA0C,CAAC,GAA0B;AACtG,WAAO,KAAK,EAAE,GAAG,MAAM,KAAK,MAAM,QAAQ,CAAC;AAAA,EAC7C;AAEA,MAAO,gBAAQ,EAAE,MAAM,OAAO,MAAM;","names":["_a","_b","popup"]}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
var MESSAGE_SOURCE = "valyd-verify";
|
|
3
|
+
var OVERLAY_ID = "valyd-verify-overlay";
|
|
4
|
+
function buildUrl(rawUrl, mode) {
|
|
5
|
+
const u = new URL(rawUrl, window.location.href);
|
|
6
|
+
u.searchParams.set("display", mode);
|
|
7
|
+
u.searchParams.set("origin", window.location.origin);
|
|
8
|
+
return u.toString();
|
|
9
|
+
}
|
|
10
|
+
function buildModal(url) {
|
|
11
|
+
const overlay = document.createElement("div");
|
|
12
|
+
overlay.id = OVERLAY_ID;
|
|
13
|
+
Object.assign(overlay.style, {
|
|
14
|
+
position: "fixed",
|
|
15
|
+
inset: "0",
|
|
16
|
+
background: "rgba(15, 23, 42, 0.6)",
|
|
17
|
+
display: "flex",
|
|
18
|
+
alignItems: "center",
|
|
19
|
+
justifyContent: "center",
|
|
20
|
+
padding: "16px",
|
|
21
|
+
zIndex: "2147483647"
|
|
22
|
+
});
|
|
23
|
+
const frame = document.createElement("div");
|
|
24
|
+
Object.assign(frame.style, {
|
|
25
|
+
position: "relative",
|
|
26
|
+
width: "100%",
|
|
27
|
+
maxWidth: "440px",
|
|
28
|
+
height: "100%",
|
|
29
|
+
maxHeight: "760px",
|
|
30
|
+
borderRadius: "16px",
|
|
31
|
+
overflow: "hidden",
|
|
32
|
+
boxShadow: "0 24px 64px rgba(0,0,0,0.35)",
|
|
33
|
+
background: "#fff"
|
|
34
|
+
});
|
|
35
|
+
const iframe = document.createElement("iframe");
|
|
36
|
+
iframe.src = url;
|
|
37
|
+
iframe.allow = "camera; microphone; fullscreen";
|
|
38
|
+
iframe.setAttribute("title", "Valyd Verify");
|
|
39
|
+
Object.assign(iframe.style, {
|
|
40
|
+
width: "100%",
|
|
41
|
+
height: "100%",
|
|
42
|
+
border: "0"
|
|
43
|
+
});
|
|
44
|
+
frame.appendChild(iframe);
|
|
45
|
+
overlay.appendChild(frame);
|
|
46
|
+
return { overlay, iframe };
|
|
47
|
+
}
|
|
48
|
+
function open(options) {
|
|
49
|
+
var _a;
|
|
50
|
+
const mode = (_a = options.mode) != null ? _a : "modal";
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
var _a2;
|
|
53
|
+
if (typeof window === "undefined") {
|
|
54
|
+
reject(new Error("valyd-verify-js must run in a browser"));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const url = buildUrl(options.url, mode);
|
|
58
|
+
const expectedOrigin = new URL(url).origin;
|
|
59
|
+
let settled = false;
|
|
60
|
+
let sourceWindow = null;
|
|
61
|
+
let teardown = () => {
|
|
62
|
+
};
|
|
63
|
+
const finish = (cb) => {
|
|
64
|
+
if (settled) return;
|
|
65
|
+
settled = true;
|
|
66
|
+
window.removeEventListener("message", onMessage);
|
|
67
|
+
teardown();
|
|
68
|
+
cb();
|
|
69
|
+
};
|
|
70
|
+
const onMessage = (event) => {
|
|
71
|
+
var _a3, _b, _c;
|
|
72
|
+
if (event.origin !== expectedOrigin) return;
|
|
73
|
+
const data = event.data;
|
|
74
|
+
if (!data || data.source !== MESSAGE_SOURCE) return;
|
|
75
|
+
if (sourceWindow && event.source !== sourceWindow) return;
|
|
76
|
+
switch (data.type) {
|
|
77
|
+
case "ready":
|
|
78
|
+
(_a3 = options.onReady) == null ? void 0 : _a3.call(options);
|
|
79
|
+
break;
|
|
80
|
+
case "complete": {
|
|
81
|
+
const result = { sessionId: (_b = data.sessionId) != null ? _b : "", status: (_c = data.status) != null ? _c : "" };
|
|
82
|
+
finish(() => {
|
|
83
|
+
var _a4;
|
|
84
|
+
(_a4 = options.onComplete) == null ? void 0 : _a4.call(options, result);
|
|
85
|
+
resolve(result);
|
|
86
|
+
});
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
case "close":
|
|
90
|
+
finish(() => {
|
|
91
|
+
var _a4;
|
|
92
|
+
(_a4 = options.onClose) == null ? void 0 : _a4.call(options);
|
|
93
|
+
reject(new Error("closed"));
|
|
94
|
+
});
|
|
95
|
+
break;
|
|
96
|
+
case "error":
|
|
97
|
+
finish(() => {
|
|
98
|
+
var _a4, _b2;
|
|
99
|
+
const err = { message: (_a4 = data.message) != null ? _a4 : "verification_error" };
|
|
100
|
+
(_b2 = options.onError) == null ? void 0 : _b2.call(options, err);
|
|
101
|
+
reject(new Error(err.message));
|
|
102
|
+
});
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
window.addEventListener("message", onMessage);
|
|
107
|
+
if (mode === "popup") {
|
|
108
|
+
const w = 480;
|
|
109
|
+
const h = 760;
|
|
110
|
+
const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
|
|
111
|
+
const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
|
|
112
|
+
const popup2 = window.open(
|
|
113
|
+
url,
|
|
114
|
+
"valyd-verify",
|
|
115
|
+
`width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`
|
|
116
|
+
);
|
|
117
|
+
if (!popup2) {
|
|
118
|
+
window.removeEventListener("message", onMessage);
|
|
119
|
+
const err = { message: "popup_blocked" };
|
|
120
|
+
(_a2 = options.onError) == null ? void 0 : _a2.call(options, err);
|
|
121
|
+
reject(new Error(err.message));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
sourceWindow = popup2;
|
|
125
|
+
const poll = window.setInterval(() => {
|
|
126
|
+
if (popup2.closed) finish(() => {
|
|
127
|
+
var _a3;
|
|
128
|
+
(_a3 = options.onClose) == null ? void 0 : _a3.call(options);
|
|
129
|
+
reject(new Error("closed"));
|
|
130
|
+
});
|
|
131
|
+
}, 500);
|
|
132
|
+
teardown = () => {
|
|
133
|
+
window.clearInterval(poll);
|
|
134
|
+
try {
|
|
135
|
+
if (!popup2.closed) popup2.close();
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
} else {
|
|
140
|
+
const existing = document.getElementById(OVERLAY_ID);
|
|
141
|
+
if (existing) existing.remove();
|
|
142
|
+
const { overlay, iframe } = buildModal(url);
|
|
143
|
+
overlay.addEventListener("click", (e) => {
|
|
144
|
+
if (e.target === overlay) finish(() => {
|
|
145
|
+
var _a3;
|
|
146
|
+
(_a3 = options.onClose) == null ? void 0 : _a3.call(options);
|
|
147
|
+
reject(new Error("closed"));
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
document.body.appendChild(overlay);
|
|
151
|
+
const prevOverflow = document.body.style.overflow;
|
|
152
|
+
document.body.style.overflow = "hidden";
|
|
153
|
+
sourceWindow = iframe.contentWindow;
|
|
154
|
+
teardown = () => {
|
|
155
|
+
overlay.remove();
|
|
156
|
+
document.body.style.overflow = prevOverflow;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
function modal(url, opts = {}) {
|
|
162
|
+
return open({ ...opts, url, mode: "modal" });
|
|
163
|
+
}
|
|
164
|
+
function popup(url, opts = {}) {
|
|
165
|
+
return open({ ...opts, url, mode: "popup" });
|
|
166
|
+
}
|
|
167
|
+
var index_default = { open, modal, popup };
|
|
168
|
+
export {
|
|
169
|
+
index_default as default,
|
|
170
|
+
modal,
|
|
171
|
+
open,
|
|
172
|
+
popup
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * valyd-verify-js — launch Valyd Verify hosted verification in a modal or popup,\n * with the result delivered via callback/Promise (no full-page redirect).\n *\n * The API key stays on YOUR server: create the session server-side with\n * `valyd-verify-sdk` (`sessions.create`), then pass the returned `session.url`\n * to `ValydVerify.open({ url })` in the browser.\n */\n\nexport type VerifyMode = \"modal\" | \"popup\";\n\nexport interface VerifyResult {\n sessionId: string;\n status: string;\n}\n\nexport interface OpenOptions {\n /** The hosted session URL returned by sessions.create (contains the token). */\n url: string;\n /** \"modal\" (in-page iframe overlay, default) or \"popup\" (separate window). */\n mode?: VerifyMode;\n onReady?: () => void;\n onComplete?: (result: VerifyResult) => void;\n /** Fired when the user closes/abandons the flow. */\n onClose?: () => void;\n onError?: (error: { message: string }) => void;\n}\n\ninterface EmbedInbound {\n source?: string;\n type?: \"ready\" | \"complete\" | \"close\" | \"error\";\n sessionId?: string;\n status?: string;\n message?: string;\n}\n\nconst MESSAGE_SOURCE = \"valyd-verify\";\nconst OVERLAY_ID = \"valyd-verify-overlay\";\n\nfunction buildUrl(rawUrl: string, mode: VerifyMode): string {\n const u = new URL(rawUrl, window.location.href);\n u.searchParams.set(\"display\", mode);\n u.searchParams.set(\"origin\", window.location.origin);\n return u.toString();\n}\n\nfunction buildModal(url: string): { overlay: HTMLDivElement; iframe: HTMLIFrameElement } {\n const overlay = document.createElement(\"div\");\n overlay.id = OVERLAY_ID;\n Object.assign(overlay.style, {\n position: \"fixed\",\n inset: \"0\",\n background: \"rgba(15, 23, 42, 0.6)\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"16px\",\n zIndex: \"2147483647\",\n });\n\n const frame = document.createElement(\"div\");\n Object.assign(frame.style, {\n position: \"relative\",\n width: \"100%\",\n maxWidth: \"440px\",\n height: \"100%\",\n maxHeight: \"760px\",\n borderRadius: \"16px\",\n overflow: \"hidden\",\n boxShadow: \"0 24px 64px rgba(0,0,0,0.35)\",\n background: \"#fff\",\n });\n\n const iframe = document.createElement(\"iframe\");\n iframe.src = url;\n iframe.allow = \"camera; microphone; fullscreen\";\n iframe.setAttribute(\"title\", \"Valyd Verify\");\n Object.assign(iframe.style, {\n width: \"100%\",\n height: \"100%\",\n border: \"0\",\n });\n\n frame.appendChild(iframe);\n overlay.appendChild(frame);\n return { overlay, iframe };\n}\n\n/**\n * Open the hosted verification flow. Resolves with the result on completion;\n * rejects with an Error (`code` on `.message`: \"closed\" | \"popup_blocked\" | …)\n * when the user closes it or an error occurs. Prefer the callbacks for UX.\n */\nexport function open(options: OpenOptions): Promise<VerifyResult> {\n const mode: VerifyMode = options.mode ?? \"modal\";\n\n return new Promise<VerifyResult>((resolve, reject) => {\n if (typeof window === \"undefined\") {\n reject(new Error(\"valyd-verify-js must run in a browser\"));\n return;\n }\n\n const url = buildUrl(options.url, mode);\n const expectedOrigin = new URL(url).origin;\n\n let settled = false;\n let sourceWindow: Window | null = null;\n let teardown: () => void = () => {};\n\n const finish = (cb: () => void) => {\n if (settled) return;\n settled = true;\n window.removeEventListener(\"message\", onMessage);\n teardown();\n cb();\n };\n\n const onMessage = (event: MessageEvent) => {\n if (event.origin !== expectedOrigin) return;\n const data = event.data as EmbedInbound | null;\n if (!data || data.source !== MESSAGE_SOURCE) return;\n // Only trust messages from the window we opened.\n if (sourceWindow && event.source !== sourceWindow) return;\n\n switch (data.type) {\n case \"ready\":\n options.onReady?.();\n break;\n case \"complete\": {\n const result: VerifyResult = { sessionId: data.sessionId ?? \"\", status: data.status ?? \"\" };\n finish(() => {\n options.onComplete?.(result);\n resolve(result);\n });\n break;\n }\n case \"close\":\n finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n break;\n case \"error\":\n finish(() => {\n const err = { message: data.message ?? \"verification_error\" };\n options.onError?.(err);\n reject(new Error(err.message));\n });\n break;\n }\n };\n\n window.addEventListener(\"message\", onMessage);\n\n if (mode === \"popup\") {\n const w = 480;\n const h = 760;\n const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);\n const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);\n const popup = window.open(\n url,\n \"valyd-verify\",\n `width=${w},height=${h},left=${left},top=${top},resizable,scrollbars`,\n );\n if (!popup) {\n window.removeEventListener(\"message\", onMessage);\n const err = { message: \"popup_blocked\" };\n options.onError?.(err);\n reject(new Error(err.message));\n return;\n }\n sourceWindow = popup;\n const poll = window.setInterval(() => {\n if (popup.closed) finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n }, 500);\n teardown = () => {\n window.clearInterval(poll);\n try {\n if (!popup.closed) popup.close();\n } catch {\n /* ignore */\n }\n };\n } else {\n const existing = document.getElementById(OVERLAY_ID);\n if (existing) existing.remove();\n const { overlay, iframe } = buildModal(url);\n // Click on the dark backdrop (outside the frame) closes the flow.\n overlay.addEventListener(\"click\", (e) => {\n if (e.target === overlay) finish(() => {\n options.onClose?.();\n reject(new Error(\"closed\"));\n });\n });\n document.body.appendChild(overlay);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n sourceWindow = iframe.contentWindow;\n teardown = () => {\n overlay.remove();\n document.body.style.overflow = prevOverflow;\n };\n }\n });\n}\n\nexport function modal(url: string, opts: Omit<OpenOptions, \"url\" | \"mode\"> = {}): Promise<VerifyResult> {\n return open({ ...opts, url, mode: \"modal\" });\n}\n\nexport function popup(url: string, opts: Omit<OpenOptions, \"url\" | \"mode\"> = {}): Promise<VerifyResult> {\n return open({ ...opts, url, mode: \"popup\" });\n}\n\nexport default { open, modal, popup };\n"],"mappings":"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","names":["_a","_b","popup"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "valyd-verify-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Browser SDK for Valyd Verify — launch hosted identity verification in a modal or popup (no redirect) and get the result via callback.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Valyd",
|
|
7
|
+
"homepage": "https://docs.valyd.id/verify",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/valyd/verify-js.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/valyd/verify-js/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"valyd",
|
|
17
|
+
"verify",
|
|
18
|
+
"identity-verification",
|
|
19
|
+
"kyc",
|
|
20
|
+
"browser",
|
|
21
|
+
"modal",
|
|
22
|
+
"popup",
|
|
23
|
+
"widget"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"unpkg": "./dist/index.global.js",
|
|
30
|
+
"jsdelivr": "./dist/index.global.js",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.js",
|
|
35
|
+
"require": "./dist/index.cjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"files": [
|
|
39
|
+
"dist",
|
|
40
|
+
"README.md",
|
|
41
|
+
"LICENSE"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"dev": "tsup --watch",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"prepublishOnly": "npm run build"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"tsup": "^8.3.5",
|
|
51
|
+
"typescript": "^5.7.2"
|
|
52
|
+
}
|
|
53
|
+
}
|