@zerohash-sdk/travel-rule-react 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/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @zerohash-sdk/travel-rule-react
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Running unit tests
6
+
7
+ Run `nx test @zerohash-sdk/travel-rule-react` to execute the unit tests via [Vitest](https://vitest.dev/).
@@ -0,0 +1,168 @@
1
+ import { default as default_2 } from 'react';
2
+
3
+ /**
4
+ * Generic app event structure
5
+ * @template TType - Event type string
6
+ * @template TData - Event data payload
7
+ */
8
+ declare type AppEvent<TType extends string = string, TData = Record<string, unknown>> = {
9
+ /** The type of event that occurred */
10
+ type: TType;
11
+ /** Data associated with the event */
12
+ data: TData;
13
+ };
14
+
15
+ /**
16
+ * Available environments for the Zerohash Travel Rule service.
17
+ *
18
+ * - `"local"` - Local development environment (http://localhost:4211)
19
+ * - `"dev"` - Development environment for early-stage testing
20
+ * - `"cert"` - Certificate/staging environment for integration testing
21
+ * - `"prod"` - Live production environment for real applications
22
+ */
23
+ declare type Environment = 'local' | 'dev' | 'cert' | 'prod';
24
+
25
+ /**
26
+ * Generic error codes for all Connect applications
27
+ */
28
+ declare enum ErrorCode {
29
+ /** Network connectivity error */
30
+ NETWORK_ERROR = 'network_error',
31
+ /** Authentication or session expired error */
32
+ AUTH_ERROR = 'auth_error',
33
+ /** Resource not found error */
34
+ NOT_FOUND_ERROR = 'not_found_error',
35
+ /** Validation error from user input */
36
+ VALIDATION_ERROR = 'validation_error',
37
+ /** Server error (5xx) */
38
+ SERVER_ERROR = 'server_error',
39
+ /** Client error (4xx) */
40
+ CLIENT_ERROR = 'client_error',
41
+ /** Unknown or unexpected error */
42
+ UNKNOWN_ERROR = 'unknown_error',
43
+ }
44
+
45
+ /**
46
+ * Generic error payload structure for error callbacks
47
+ */
48
+ declare type ErrorPayload = {
49
+ /** Error code indicating the type of error */
50
+ errorCode: ErrorCode;
51
+ /** Human-readable reason for the error */
52
+ reason: string;
53
+ };
54
+
55
+ /**
56
+ * Theme mode for the Zerohash Travel Rule interface.
57
+ *
58
+ * - `"auto"` - Automatically detect system preference (light/dark mode)
59
+ * - `"light"` - Force light theme
60
+ * - `"dark"` - Force dark theme
61
+ */
62
+ declare type Theme = 'auto' | 'light' | 'dark';
63
+
64
+ /**
65
+ * A React wrapper component for the Zerohash Travel Rule product.
66
+ *
67
+ * @param props - Component properties
68
+ * @param jwt - JWT token for authentication (required)
69
+ * @param depositId - Deposit id the submission is tied to (required, TRD §4.1)
70
+ * @param env - Target environment ("local" | "dev" | "cert" | "prod", defaults to "prod")
71
+ * @param theme - Theme mode ("auto" | "light" | "dark", defaults to "auto")
72
+ * @param onCompleted - Callback invoked when the flow is successfully completed
73
+ * @param onError - Callback invoked when an error occurs
74
+ * @param onClose - Callback invoked when the user closes the widget
75
+ * @param onLoaded - Callback invoked when the widget has finished loading
76
+ * @param onEvent - Callback invoked for general application events
77
+ *
78
+ * @returns React component that renders the Zerohash Travel Rule interface
79
+ */
80
+ export declare const TravelRule: default_2.FC<TravelRuleProps>;
81
+
82
+ declare type TravelRuleCompletedData = {
83
+ /** Deposit id the travel-rule submission is tied to */
84
+ deposit_id: string;
85
+ /** ISO-8601 timestamp of the travel-rule submission */
86
+ submitted_at: string;
87
+ };
88
+
89
+ /**
90
+ * Travel Rule event structure
91
+ */
92
+ declare type TravelRuleEvent = AppEvent<TravelRuleEventType>;
93
+
94
+ /**
95
+ * Travel Rule event type literals
96
+ */
97
+ declare type TravelRuleEventType = string;
98
+
99
+ declare interface TravelRuleProps {
100
+ /**
101
+ * JWT token used for authentication with the Zerohash Travel Rule service.
102
+ * This token should be obtained from your backend and contain the necessary
103
+ * claims for user identification and authorization.
104
+ *
105
+ * @example "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
106
+ */
107
+ jwt: string;
108
+ /**
109
+ * Deposit id the travel-rule submission is tied to. Required — every
110
+ * travel-rule submission is scoped to a specific deposit (TRD §4.1 host
111
+ * handoff contract). Init-only: post-mount changes are ignored, matching
112
+ * the behaviour of `env`.
113
+ *
114
+ * @example "deposit-abc123"
115
+ */
116
+ depositId: string;
117
+ /**
118
+ * Target environment for the Zerohash Travel Rule service.
119
+ *
120
+ * @default "prod"
121
+ *
122
+ * Available environments:
123
+ * - `"local"` - Local development environment
124
+ * - `"dev"` - Development environment
125
+ * - `"cert"` - Certificate/staging environment for integration testing
126
+ * - `"prod"` - Live production environment for real applications
127
+ */
128
+ env?: Environment;
129
+ /**
130
+ * Theme mode for the Zerohash Travel Rule interface.
131
+ *
132
+ * @default "auto"
133
+ *
134
+ * Available themes:
135
+ * - `"auto"` - Automatically detect system preference (light/dark mode)
136
+ * - `"light"` - Force light theme
137
+ * - `"dark"` - Force dark theme
138
+ */
139
+ theme?: Theme;
140
+ /**
141
+ * Callback invoked when the travel-rule flow is successfully completed.
142
+ *
143
+ * @param data - Details about the completed submission, including deposit_id and submitted_at
144
+ */
145
+ onCompleted?: (data: TravelRuleCompletedData) => void;
146
+ /**
147
+ * Callback invoked when an error occurs during the travel-rule flow.
148
+ *
149
+ * @param error - Error details including error code and reason
150
+ */
151
+ onError?: (error: ErrorPayload) => void;
152
+ /**
153
+ * Callback invoked when the user closes the travel-rule widget.
154
+ */
155
+ onClose?: () => void;
156
+ /**
157
+ * Callback invoked when the travel-rule widget has finished loading and is ready.
158
+ */
159
+ onLoaded?: () => void;
160
+ /**
161
+ * Callback invoked for general application events during the travel-rule flow.
162
+ *
163
+ * @param event - Event object containing the event type and associated data
164
+ */
165
+ onEvent?: (event: TravelRuleEvent) => void;
166
+ }
167
+
168
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,253 @@
1
+ import { jsxs as W, jsx as _ } from "react/jsx-runtime";
2
+ import j, { useEffect as B, useState as z, useCallback as D, useRef as M } from "react";
3
+ const $ = {
4
+ dev: "https://grafana-faro-collector.dev.0hash.com/collect",
5
+ cert: "https://grafana-faro-collector.cert.zerohash.com/collect",
6
+ prod: "https://grafana-faro-collector.zerohash.com/collect",
7
+ "eu-cert": "https://grafana-faro-collector.cert.zerohash.eu/collect",
8
+ "eu-prod": "https://grafana-faro-collector.zerohash.eu/collect",
9
+ sandbox: "https://grafana-faro-collector.cert.zerohash.com/collect",
10
+ production: "https://grafana-faro-collector.zerohash.com/collect"
11
+ }, V = (e) => {
12
+ if (!e || typeof e != "string")
13
+ return null;
14
+ const t = e.split(".");
15
+ if (t.length < 2)
16
+ return null;
17
+ try {
18
+ const o = t[1].replace(/-/g, "+").replace(/_/g, "/"), r = o + "===".slice(0, (4 - o.length % 4) % 4), a = typeof atob < "u" ? atob(r) : Buffer.from(r, "base64").toString("utf-8"), c = JSON.parse(a)?.payload?.region;
19
+ if (typeof c != "string")
20
+ return null;
21
+ const n = c.toLowerCase();
22
+ return n === "us" || n === "eu" ? n : null;
23
+ } catch {
24
+ return null;
25
+ }
26
+ }, U = (e, t) => V(t) !== "eu" ? e : e === "cert" ? "eu-cert" : e === "prod" ? "eu-prod" : e, P = (e) => {
27
+ if (!e || typeof e != "string")
28
+ return {};
29
+ const t = e.split(".");
30
+ if (t.length < 2)
31
+ return {};
32
+ try {
33
+ const o = t[1].replace(/-/g, "+").replace(/_/g, "/"), r = o + "===".slice(0, (4 - o.length % 4) % 4), a = typeof atob < "u" ? atob(r) : Buffer.from(r, "base64").toString("utf-8"), l = JSON.parse(a), c = l?.payload ?? {}, n = (s) => typeof s == "string" && s.length > 0 ? s : void 0;
34
+ return {
35
+ participantCode: n(c.participant_code),
36
+ platformName: n(c.platform_name),
37
+ platformCode: n(l.platform_code),
38
+ region: n(c.region)
39
+ };
40
+ } catch {
41
+ return {};
42
+ }
43
+ }, L = (e, t, o) => {
44
+ const r = U(t, o);
45
+ return e[r] ?? e[t] ?? e.prod;
46
+ }, J = (e, t, o) => {
47
+ const r = U(t, o);
48
+ return e[r] ?? e[t];
49
+ }, x = () => {
50
+ }, H = () => {
51
+ const e = new Uint8Array(8);
52
+ return globalThis.crypto.getRandomValues(e), Array.from(e, (t) => t.toString(16).padStart(2, "0")).join("");
53
+ }, K = (e, t) => {
54
+ const o = H(), r = globalThis.__ZH_WEB_SDK_VERSION__, a = {};
55
+ e.claims.participantCode && (a.participant_code = e.claims.participantCode), e.claims.platformName && (a.platform_name = e.claims.platformName), e.claims.platformCode && (a.platform_code = e.claims.platformCode), e.claims.region && (a.region = e.claims.region), r && (a.zh_web_sdk_version = r);
56
+ const l = {
57
+ meta: {
58
+ app: { name: e.appName, version: t ?? "unknown", environment: e.env },
59
+ session: { id: o, attributes: a },
60
+ browser: typeof navigator < "u" ? { userAgent: navigator.userAgent } : void 0,
61
+ page: typeof window < "u" ? { url: window.location.origin } : void 0
62
+ },
63
+ logs: [
64
+ {
65
+ message: `Failed to load the script for ${e.webComponentTag} from ${e.env} environment.`,
66
+ level: "error",
67
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
68
+ context: {
69
+ web_component: e.webComponentTag,
70
+ script_url: e.scriptUrl,
71
+ reason: e.reason,
72
+ tried_fallback: String(e.triedFallback),
73
+ elapsed_ms: String(e.elapsedMs)
74
+ }
75
+ }
76
+ ]
77
+ };
78
+ return { sessionId: o, payload: l };
79
+ }, G = (e, t, o) => {
80
+ if (!e || typeof fetch > "u")
81
+ return;
82
+ const { sessionId: r, payload: a } = K(t, o);
83
+ try {
84
+ fetch(e, {
85
+ method: "POST",
86
+ headers: { "Content-Type": "application/json", "x-faro-session-id": r },
87
+ body: JSON.stringify(a),
88
+ keepalive: !0
89
+ }).catch(() => {
90
+ });
91
+ } catch {
92
+ }
93
+ }, Z = (e) => {
94
+ const { webComponentTag: t, appName: o, appVersion: r, scriptUrls: a, fallbackScriptUrls: l, collectorUrls: c, env: n, jwt: s, timeoutMs: m = 15e3, onLoad: g, onError: h } = e;
95
+ if (typeof document > "u")
96
+ return x;
97
+ const d = `${t}-script-${n}`;
98
+ if (customElements.get(t) || document.getElementById(d))
99
+ return x;
100
+ const S = P(s), v = e.report ?? ((p) => G(c && J(c, n, s), p, r));
101
+ let f = !1, w = 0, C;
102
+ const R = () => {
103
+ C !== void 0 && clearTimeout(C);
104
+ }, k = (p, y, i) => {
105
+ if (f)
106
+ return;
107
+ const I = Math.round(performance.now() - w), N = {
108
+ webComponentTag: t,
109
+ appName: o,
110
+ env: n,
111
+ scriptUrl: y,
112
+ reason: p,
113
+ triedFallback: i,
114
+ elapsedMs: I,
115
+ claims: S
116
+ };
117
+ v(N);
118
+ const O = i ? void 0 : L(l ?? {}, n, s);
119
+ if (O && O !== y) {
120
+ E(O, !0);
121
+ return;
122
+ }
123
+ f = !0, R(), document.getElementById(d)?.remove(), h?.(N);
124
+ }, E = (p, y) => {
125
+ R(), w = performance.now();
126
+ const i = document.createElement("script");
127
+ i.id = d, i.src = p, i.type = "module", i.async = !0, i.onload = () => {
128
+ setTimeout(() => {
129
+ f || (customElements.get(t) ? (f = !0, R(), g?.()) : k("not-defined", p, y));
130
+ }, 0);
131
+ }, i.onerror = () => k("network", p, y), C = setTimeout(() => k("timeout", p, y), m), document.getElementById(d)?.remove(), document.head.appendChild(i);
132
+ }, T = L(a, n, s);
133
+ return T ? (E(T, !1), () => {
134
+ f = !0, R();
135
+ }) : x;
136
+ }, u = {
137
+ local: "http://localhost:5173",
138
+ dev: "https://sdk-cdn.dev.0hash.com",
139
+ cert: "https://sdk-cdn.cert.zerohash.com",
140
+ prod: "https://sdk-cdn.zerohash.com",
141
+ "eu-cert": "https://sdk-cdn.cert.zerohash.eu",
142
+ "eu-prod": "https://sdk-cdn.zerohash.eu"
143
+ }, q = (e, t, o = {}) => {
144
+ const { eu: r = !1, legacyAliases: a = !1, local: l = u.local } = o, c = (s) => `${s}/${e}/${t}`, n = {
145
+ local: c(l),
146
+ dev: c(u.dev),
147
+ cert: c(u.cert),
148
+ prod: c(u.prod)
149
+ };
150
+ return a && (n.sandbox = c(u.cert), n.production = c(u.prod)), r && (n["eu-cert"] = c(u["eu-cert"]), n["eu-prod"] = c(u["eu-prod"])), n;
151
+ };
152
+ var F;
153
+ (function(e) {
154
+ e.NETWORK_ERROR = "network_error", e.AUTH_ERROR = "auth_error", e.NOT_FOUND_ERROR = "not_found_error", e.VALIDATION_ERROR = "validation_error", e.SERVER_ERROR = "server_error", e.CLIENT_ERROR = "client_error", e.UNKNOWN_ERROR = "unknown_error";
155
+ })(F || (F = {}));
156
+ const b = {
157
+ evergreen: "#00381D",
158
+ green: "#CCFFD0",
159
+ offBlack: "#1C1B1C",
160
+ grayLight: "#EBEBE9"
161
+ }, Q = ({ onRetry: e }) => W("div", { role: "alert", style: {
162
+ display: "flex",
163
+ flexDirection: "column",
164
+ alignItems: "center",
165
+ gap: "8px",
166
+ maxWidth: "360px",
167
+ margin: "0 auto",
168
+ padding: "32px 24px",
169
+ textAlign: "center",
170
+ fontFamily: "inherit",
171
+ color: b.offBlack,
172
+ background: "#FFFFFF",
173
+ border: `1px solid ${b.grayLight}`,
174
+ borderRadius: "12px"
175
+ }, children: [_("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _("path", { d: "M12 9v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z", stroke: b.evergreen, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }), _("p", { style: { margin: 0, fontSize: "16px", fontWeight: 600 }, children: "Something went wrong" }), _("p", { style: { margin: 0, fontSize: "14px", opacity: 0.75 }, children: "We couldn't load this content. Please check your internet connection and try again." }), _("button", { type: "button", onClick: e, style: {
176
+ marginTop: "8px",
177
+ padding: "8px 20px",
178
+ fontSize: "14px",
179
+ fontWeight: 600,
180
+ fontFamily: "inherit",
181
+ color: b.green,
182
+ background: b.evergreen,
183
+ border: "none",
184
+ borderRadius: "8px",
185
+ cursor: "pointer"
186
+ }, children: "Try again" })] }), X = (e, t) => {
187
+ B(() => {
188
+ const o = e.current;
189
+ if (o)
190
+ for (const [r, a] of Object.entries(t))
191
+ a !== void 0 && (o[r] = a);
192
+ });
193
+ }, Y = (e) => {
194
+ const { webComponentTag: t, appName: o, appVersion: r, scriptUrls: a, fallbackScriptUrls: l, collectorUrls: c, env: n, jwt: s, timeoutMs: m } = e, [g, h] = z(!1), [d, S] = z(0);
195
+ B(() => (h(!1), Z({
196
+ webComponentTag: t,
197
+ appName: o ?? t,
198
+ appVersion: r,
199
+ scriptUrls: a,
200
+ fallbackScriptUrls: l,
201
+ collectorUrls: c ?? $,
202
+ env: n,
203
+ jwt: s,
204
+ timeoutMs: m,
205
+ onError: () => h(!0)
206
+ })), [
207
+ t,
208
+ o,
209
+ r,
210
+ a,
211
+ l,
212
+ c,
213
+ n,
214
+ s,
215
+ m,
216
+ d
217
+ ]);
218
+ const v = D(() => S((f) => f + 1), []);
219
+ return { loadFailed: g, retry: v };
220
+ }, ee = q("travel-rule-web", "index.js", { eu: !0 }), A = "zerohash-travel-rule", re = ({
221
+ jwt: e,
222
+ depositId: t,
223
+ env: o = "prod",
224
+ theme: r,
225
+ onCompleted: a,
226
+ onError: l,
227
+ onClose: c,
228
+ onLoaded: n,
229
+ onEvent: s,
230
+ ...m
231
+ }) => {
232
+ const g = M(null);
233
+ X(g, { theme: r, depositId: t, onCompleted: a, onError: l, onClose: c, onLoaded: n, onEvent: s });
234
+ const { loadFailed: h, retry: d } = Y({
235
+ webComponentTag: A,
236
+ scriptUrls: ee,
237
+ env: o,
238
+ jwt: e
239
+ });
240
+ return h ? /* @__PURE__ */ _(Q, { onRetry: d }) : j.createElement(A, {
241
+ ref: g,
242
+ jwt: e,
243
+ env: o,
244
+ theme: r,
245
+ // Also mirror the kebab-case attribute so pre-mount seeding works even
246
+ // if the browser upgrades the element before the property setter runs.
247
+ "deposit-id": t,
248
+ ...m
249
+ });
250
+ };
251
+ export {
252
+ re as TravelRule
253
+ };
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@zerohash-sdk/travel-rule-react",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "license": "MIT",
10
+ "exports": {
11
+ "./package.json": "./package.json",
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "!**/*.tsbuildinfo"
21
+ ],
22
+ "nx": {
23
+ "name": "travel-rule-react"
24
+ },
25
+ "peerDependencies": {
26
+ "react": ">=18.0.0",
27
+ "react-dom": ">=18.0.0"
28
+ }
29
+ }