zh-web-sdk 2.17.0 → 3.0.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/CHANGELOG.md CHANGED
@@ -6,6 +6,29 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
 
9
+ ## [3.0.0] - 2026-05-21
10
+
11
+ Major version bump signaling the rollout of the next-generation SDK rendering path. The integrator-facing API is unchanged for cert/prod consumers; the only public-type change is the narrowing of `env` (see Changed).
12
+
13
+ ### Changed
14
+ - **Breaking (TypeScript surface):** Narrowed the public `Environment` type from `'dev' | 'cert' | 'prod'` to `'cert' | 'prod'`. The `'dev'` value targeted Zero Hash internal CDNs and was never intended for integrator use; it has been moved to a separate `InternalEnvironment` type used by our QA tooling. Integrators on cert or prod do not need to make any changes.
15
+
16
+ ### Added
17
+ - Opt-in next-generation rendering for ZeroHash apps, delivering improved performance and UX across Crypto Buy/Sell, Onboarding, Fiat Deposits/Withdrawals, Crypto Withdrawals, Fund, Pay, Payouts, Profile, and Account Link flows [#97]
18
+ - Rolled out gradually and controlled server-side — no integration changes required
19
+ - Flows not yet migrated continue to render in the existing iframe
20
+ - SDK version is now attached to embedded-app logs to make support investigations faster [#97]
21
+ - New `theme` option on the SDK constructor (`'light' | 'dark' | 'auto'`, defaults to `'light'`) and `sdk.setTheme({ theme })` method to control the appearance of next-generation flows; legacy iframe and Connect Auth (Fund) appearance is unchanged [#97]
22
+ - New `env` option on the SDK constructor (`'cert' | 'prod'`) for explicit environment selection. When set, it takes precedence over hostname inference from `zeroHashAppsURL` and is the recommended way to target a specific deployment going forward [#97]
23
+
24
+ ### Fixed
25
+ - Expanded the URL-based environment-inference allowlist to cover the full set of Zero Hash hostnames used by integrators (cert/dev, US/EU, `0hash.com`/`zerohash.com`/`zerohash.eu`/`sandbox.connect.xyz`/`gating.0hash.com`). Previously, only `web-sdk.cert.0hash.com`, `web-sdk.sandbox.connect.xyz`, and `web-sdk.dev.0hash.com` were recognized — every other Zero Hash host silently fell back to `prod`, causing cert sessions to load the production CDN. Integrators on hosts outside this list should still pass the new `env` option explicitly [#97]
26
+ - Removed the wrong-theme flash when opening a next-generation flow with `theme: 'dark'` or `'auto'`. The wrapper modal no longer paints a white background before the inner SDK renders, and it now becomes visible as soon as the SDK component reports it has loaded instead of waiting on a multi-second fallback. Light-mode and legacy iframe flows are unchanged [#97]
27
+ - Fixed Fund's Connect Auth flow targeting the wrong Connect API on non-prod hosts. The Auth env was previously inferred via a substring check against `zeroHashAppsURL` and silently fell back to `production` for dev hosts (e.g. `web-sdk.dev.0hash.com`) and partner-hosted URLs, causing the Fund modal to call `api.connect.xyz` instead of `api.sandbox.connect.xyz`. The Auth env is now resolved from the same source as the new-SDK components — explicit `env` from the SDK constructor when provided, otherwise the hostname allowlist [#97]
28
+
29
+ ### Security
30
+ - Hardened the Connect Auth issuer check to use a strict hostname allowlist, replacing the previous substring match [#97]
31
+
9
32
  ## [2.16.0] - 2026-02-20
10
33
 
11
34
  ### Added
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # ZeroHash Web SDK
2
2
 
3
- The ZeroHash Web SDK enables platforms to integrate ZeroHash financial services on web and mobile applications. Access various UI flows including Crypto Buy, Crypto Sell, Crypto Withdrawals, Fiat Deposits, Fiat Withdrawals, and Onboarding through a single SDK instance.
3
+ The ZeroHash Web SDK enables platforms to integrate ZeroHash financial services on web and mobile applications. Access various UI flows including Fund, Onboarding, Crypto Buy, Crypto Sell, Crypto Withdrawals, Fiat Deposits, and Fiat Withdrawals through a single SDK instance.
4
4
 
5
5
  ## Installation
6
6
 
@@ -25,19 +25,21 @@ import ZeroHashSDK, { AppIdentifier } from 'zh-web-sdk';
25
25
  const App = () => {
26
26
  // Create SDK instance once - not on every render
27
27
  const sdk = useMemo(() => new ZeroHashSDK({
28
- zeroHashAppsURL: "https://web-sdk.zerohash.com"
28
+ zeroHashAppsURL: "https://web-sdk.zerohash.com",
29
+ env: "prod",
30
+ theme: "light"
29
31
  }), []);
30
32
 
31
- const handleOpenCryptoBuy = () => {
33
+ const handleOpenFund = () => {
32
34
  sdk.openModal({
33
- appIdentifier: AppIdentifier.CRYPTO_BUY,
35
+ appIdentifier: AppIdentifier.FUND,
34
36
  jwt: "<JWT_TOKEN_HERE>"
35
37
  });
36
38
  };
37
39
 
38
40
  return (
39
- <button onClick={handleOpenCryptoBuy}>
40
- Buy Crypto
41
+ <button onClick={handleOpenFund}>
42
+ Fund Account
41
43
  </button>
42
44
  );
43
45
  };
@@ -52,45 +54,52 @@ import ZeroHashSDK, { AppIdentifier } from 'zh-web-sdk';
52
54
 
53
55
  // Initialize SDK once
54
56
  const sdk = new ZeroHashSDK({
55
- zeroHashAppsURL: "https://web-sdk.zerohash.com"
57
+ zeroHashAppsURL: "https://web-sdk.zerohash.com",
58
+ env: "prod",
59
+ theme: "light"
56
60
  });
57
61
 
58
62
  // Open a modal
59
63
  sdk.openModal({
60
- appIdentifier: AppIdentifier.CRYPTO_BUY,
64
+ appIdentifier: AppIdentifier.FUND,
61
65
  jwt: "<JWT_TOKEN_HERE>"
62
66
  });
63
67
 
64
68
  // Close when done
65
- sdk.closeModal(AppIdentifier.CRYPTO_BUY);
69
+ sdk.closeModal(AppIdentifier.FUND);
66
70
  ```
67
71
 
68
72
  ## Environments
69
73
 
70
- The SDK supports multiple environments:
71
-
72
- - **Production**: `https://web-sdk.zerohash.com`
73
- - **Certification/Sandbox**: `https://web-sdk.cert.zerohash.com`
74
+ Pass `env` to select the deployment the SDK should target. Accepted values are `'cert'` and `'prod'`. When set, `env` is the source of truth for environment resolution and overrides hostname-based inference from `zeroHashAppsURL`.
74
75
 
75
76
  ```typescript
76
77
  const sdk = new ZeroHashSDK({
77
- zeroHashAppsURL: "https://web-sdk.cert.zerohash.com" // Use cert environment
78
+ zeroHashAppsURL: "https://web-sdk.cert.zerohash.com",
79
+ env: "cert"
78
80
  });
79
81
  ```
80
82
 
83
+ Default URLs per environment:
84
+
85
+ - **Production**: `https://web-sdk.zerohash.com`
86
+ - **Certification/Sandbox**: `https://web-sdk.cert.zerohash.com`
87
+
88
+ If `env` is omitted, the SDK falls back to inferring the environment from the hostname of `zeroHashAppsURL`. Hosts outside the recognized Zero Hash list resolve to `'prod'` — pass `env` explicitly when integrating from a partner-hosted domain.
89
+
81
90
  ## Available App Identifiers
82
91
 
83
92
  The SDK supports the following application flows:
84
93
 
85
94
  | AppIdentifier | Description |
86
95
  |--------------|-------------|
96
+ | `FUND` | Fund account operations |
87
97
  | `ONBOARDING` | User onboarding and KYC |
88
98
  | `CRYPTO_BUY` | Purchase cryptocurrency |
89
99
  | `CRYPTO_SELL` | Sell cryptocurrency |
90
100
  | `CRYPTO_WITHDRAWALS` | Withdraw crypto to external wallets |
91
101
  | `FIAT_DEPOSITS` | Deposit fiat currency |
92
102
  | `FIAT_WITHDRAWALS` | Withdraw fiat currency |
93
- | `FUND` | Fund account operations |
94
103
  | `PROFILE` | User profile management |
95
104
  | `CRYPTO_ACCOUNT_LINK` | Link cryptocurrency accounts |
96
105
  | `CRYPTO_ACCOUNT_LINK_PAYOUTS` | Link crypto accounts for payouts |
@@ -110,7 +119,9 @@ new ZeroHashSDK(config: IInitializeParameters)
110
119
 
111
120
  ```typescript
112
121
  {
113
- zeroHashAppsURL: string; // Required: Base URL for ZeroHash apps
122
+ zeroHashAppsURL: string; // Required: Base URL for ZeroHash apps
123
+ env?: 'cert' | 'prod'; // Optional: Explicit environment selection
124
+ theme?: 'light' | 'dark' | 'auto'; // Optional: Appearance for next-gen flows (defaults to 'light')
114
125
  rootQuerySelector?: string; // Optional: Custom DOM element selector
115
126
 
116
127
  // Optional: Set JWTs during initialization
@@ -138,7 +149,7 @@ Opens a modal for the specified app.
138
149
 
139
150
  ```typescript
140
151
  sdk.openModal({
141
- appIdentifier: AppIdentifier.CRYPTO_BUY,
152
+ appIdentifier: AppIdentifier.FUND,
142
153
  jwt?: string, // Optional: Set or update JWT
143
154
  filters?: Filters, // Optional: Filter options
144
155
  navigate?: Page // Optional: Navigation parameters
@@ -150,7 +161,7 @@ sdk.openModal({
150
161
  Closes the modal for the specified app.
151
162
 
152
163
  ```typescript
153
- sdk.closeModal(AppIdentifier.CRYPTO_BUY);
164
+ sdk.closeModal(AppIdentifier.FUND);
154
165
  ```
155
166
 
156
167
  #### `setJWT(params)`
@@ -160,7 +171,7 @@ Set or update the JWT for a specific app.
160
171
  ```typescript
161
172
  sdk.setJWT({
162
173
  jwt: "<JWT_TOKEN>",
163
- appIdentifier: AppIdentifier.CRYPTO_BUY
174
+ appIdentifier: AppIdentifier.FUND
164
175
  });
165
176
  ```
166
177
 
@@ -169,7 +180,7 @@ sdk.setJWT({
169
180
  Check if a modal is currently open.
170
181
 
171
182
  ```typescript
172
- const isOpen = sdk.isModalOpen(AppIdentifier.CRYPTO_BUY);
183
+ const isOpen = sdk.isModalOpen(AppIdentifier.FUND);
173
184
  ```
174
185
 
175
186
  #### `setFilters(params)`
@@ -178,7 +189,7 @@ Set filters for a specific app.
178
189
 
179
190
  ```typescript
180
191
  sdk.setFilters({
181
- appIdentifier: AppIdentifier.CRYPTO_BUY,
192
+ appIdentifier: AppIdentifier.FUND,
182
193
  filters: {
183
194
  getAssets: {
184
195
  stablecoin: true
@@ -187,6 +198,14 @@ sdk.setFilters({
187
198
  });
188
199
  ```
189
200
 
201
+ #### `setTheme(params)`
202
+
203
+ Update the theme forwarded to the next-generation `@zerohash-sdk/*-react` flows and Connect Auth (Fund). Has no effect on the legacy iframe.
204
+
205
+ ```typescript
206
+ sdk.setTheme({ theme: "dark" }); // 'light' | 'dark' | 'auto'
207
+ ```
208
+
190
209
  ## JWT Authentication
191
210
 
192
211
  **⚠️ Security Note**: JWTs should be obtained from your backend server using the ZeroHash API with your API key. Never expose your API key or perform JWT exchanges on the client side.
@@ -197,14 +216,15 @@ sdk.setFilters({
197
216
  ```typescript
198
217
  const sdk = new ZeroHashSDK({
199
218
  zeroHashAppsURL: "https://web-sdk.zerohash.com",
200
- cryptoBuyJWT: jwt
219
+ env: "prod",
220
+ fundJWT: jwt
201
221
  });
202
222
  ```
203
223
 
204
224
  **2. When opening a modal:**
205
225
  ```typescript
206
226
  sdk.openModal({
207
- appIdentifier: AppIdentifier.CRYPTO_BUY,
227
+ appIdentifier: AppIdentifier.FUND,
208
228
  jwt: jwt
209
229
  });
210
230
  ```
@@ -213,7 +233,7 @@ sdk.openModal({
213
233
  ```typescript
214
234
  sdk.setJWT({
215
235
  jwt: newJwt,
216
- appIdentifier: AppIdentifier.CRYPTO_BUY
236
+ appIdentifier: AppIdentifier.FUND
217
237
  });
218
238
  ```
219
239
 
@@ -230,14 +250,6 @@ import ZeroHashSDK, {
230
250
  } from 'zh-web-sdk';
231
251
  ```
232
252
 
233
- ## Versioning
234
-
235
- The ZeroHash SDK uses [Semantic Versioning 2.0.0](https://semver.org/). Version numbers follow the `MAJOR.MINOR.PATCH` format:
236
-
237
- - **MAJOR** version increments for incompatible API changes (e.g., `1.0.0` to `2.0.0`)
238
- - **MINOR** version increments for backward-compatible new features (e.g., `1.0.0` to `1.1.0`)
239
- - **PATCH** version increments for backward-compatible bug fixes (e.g., `1.0.0` to `1.0.1`)
240
-
241
253
  ## Documentation & Support
242
254
 
243
255
  - **Full Documentation**: [ZeroHash SDK Documentation](https://docs.zerohash.com/reference/sdk-overview)
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ import "../index";
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,18 @@
1
+ export interface FundWithdrawalDetails {
2
+ quoted_asset?: string;
3
+ withdrawal_request_amount?: string | number;
4
+ external_account_id?: string;
5
+ }
1
6
  export interface JWTPayload {
2
7
  auth_embedded?: boolean;
3
8
  reference_id?: string;
9
+ payload?: {
10
+ use_new_sdk?: boolean;
11
+ withdrawal_details?: FundWithdrawalDetails;
12
+ [key: string]: unknown;
13
+ };
4
14
  [key: string]: unknown;
5
15
  }
6
16
  export declare function decodeJWT(token: string): JWTPayload | null;
17
+ export declare const ALLOWED_CONNECT_ISSUER_HOSTNAMES: readonly string[];
18
+ export declare function isConnectIssuer(iss: unknown): boolean;
@@ -1,4 +1,4 @@
1
- import { AppIdentifier, AuthSettings, Filters, Page } from "../types";
1
+ import { AppIdentifier, AuthSettings, Environment, InternalEnvironment, Filters, Page, Theme } from "../types";
2
2
  interface AppContainerProps {
3
3
  isAppActive?: boolean;
4
4
  isAppLoaded?: boolean;
@@ -9,10 +9,18 @@ interface AppContainerProps {
9
9
  navigate?: Page;
10
10
  useAuth?: boolean;
11
11
  authSettings?: AuthSettings;
12
+ useNewSdk?: boolean;
13
+ theme?: Theme;
14
+ /**
15
+ * Explicit environment forwarded by `ZeroHashSDK`. When provided, it is
16
+ * preferred over hostname inference from `zeroHashAppURL`.
17
+ */
18
+ env?: Environment | InternalEnvironment;
12
19
  }
13
- declare const _default: import("react-redux").ConnectedComponent<({ isAppActive, isAppLoaded, jwt, zeroHashAppURL, appIdentifier, navigate, useAuth, authSettings, }: AppContainerProps) => import("react/jsx-runtime").JSX.Element, {
14
- zeroHashAppURL: string;
20
+ declare const _default: import("react-redux").ConnectedComponent<({ isAppActive, isAppLoaded, jwt, zeroHashAppURL, appIdentifier, navigate, useAuth, authSettings, useNewSdk, theme, env: explicitEnv, }: AppContainerProps) => import("react/jsx-runtime").JSX.Element, {
15
21
  appIdentifier: AppIdentifier;
22
+ zeroHashAppURL: string;
23
+ env?: (Environment | InternalEnvironment) | undefined;
16
24
  isAppActive?: boolean | undefined;
17
25
  isAppLoaded?: boolean | undefined;
18
26
  jwt?: string | undefined;
@@ -20,6 +28,8 @@ declare const _default: import("react-redux").ConnectedComponent<({ isAppActive,
20
28
  navigate?: Page | undefined;
21
29
  useAuth?: boolean | undefined;
22
30
  authSettings?: AuthSettings | undefined;
31
+ useNewSdk?: boolean | undefined;
32
+ theme?: Theme | undefined;
23
33
  context?: import("react-redux/es/components/Context").ReactReduxContextInstance | undefined;
24
34
  store?: import("redux").Store | undefined;
25
35
  }>;
@@ -22,4 +22,5 @@ export declare const useStyleUpdates: (zeroHashAppURL: string, defaultStyles: St
22
22
  styles: StyleConfig;
23
23
  stylesLoaded: boolean;
24
24
  handleStyleConfig: (incomingStyles: Partial<StyleConfig>, eventOrigin: string) => boolean;
25
+ markStylesLoaded: () => void;
25
26
  };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,15 @@
1
- import { AppIdentifier, IInitializeParameters, IOpenModalParameters, IOpenOnboardingModalParameters, ISetFiltersParameters, ISetJWTParameters, ISetNavigateParameters, ISetUserOnboardingJWTParameters, IZeroHashSDK } from "./types";
1
+ import { AppIdentifier, IInitializeParameters, IOpenModalParameters, IOpenOnboardingModalParameters, ISetFiltersParameters, ISetJWTParameters, ISetNavigateParameters, ISetThemeParameters, ISetUserOnboardingJWTParameters, IZeroHashSDK } from "./types";
2
+ declare global {
3
+ interface Window {
4
+ /**
5
+ * Version of zh-web-sdk loaded on the host page. Embedded
6
+ * `@zerohash-sdk/*` web components read this and forward it to their
7
+ * iframe Faro logs as `zh_web_sdk_version`. Absent when the new SDKs
8
+ * are embedded directly without zh-web-sdk.
9
+ */
10
+ __ZH_WEB_SDK_VERSION__?: string;
11
+ }
12
+ }
2
13
  export declare class ZeroHashSDK implements IZeroHashSDK {
3
14
  private rootQuerySelector;
4
15
  private onboardingInitialized;
@@ -12,7 +23,7 @@ export declare class ZeroHashSDK implements IZeroHashSDK {
12
23
  *
13
24
  * For more information, see {@code IInitializeParameters}
14
25
  */
15
- constructor({ zeroHashOnboardingURL, rootQuerySelector, userOnboardingJWT, cryptoWithdrawalsJWT, fiatDepositsJWT, fiatWithdrawalsJWT, cryptoBuyJWT, cryptoSellJWT, fundJWT, profileJWT, cryptoAccountLinkJWT, cryptoAccountLinkPayoutsJWT, payoutsJWT, payJWT, fiatAccountLinkJWT, zeroHashAppsURL, }: IInitializeParameters);
26
+ constructor({ zeroHashOnboardingURL, rootQuerySelector, userOnboardingJWT, cryptoWithdrawalsJWT, fiatDepositsJWT, fiatWithdrawalsJWT, cryptoBuyJWT, cryptoSellJWT, fundJWT, profileJWT, cryptoAccountLinkJWT, cryptoAccountLinkPayoutsJWT, payoutsJWT, payJWT, fiatAccountLinkJWT, zeroHashAppsURL, env, theme, }: IInitializeParameters);
16
27
  /**
17
28
  * setJWT sets the JWT for the appIdentifier provided.
18
29
  * The JWT should be the JWT provided by ZeroHash via the platform
@@ -31,6 +42,12 @@ export declare class ZeroHashSDK implements IZeroHashSDK {
31
42
  * specific to Onboarding and is used to navigate to a specific page within the App.
32
43
  */
33
44
  setNavigate({ appIdentifier, navigate }: ISetNavigateParameters): void;
45
+ /**
46
+ * setTheme updates the theme forwarded to new @zerohash-sdk/*-react
47
+ * components. Accepts 'light', 'dark', or 'auto'. Has no effect on the
48
+ * legacy iframe path or the Connect Auth (Fund) component.
49
+ */
50
+ setTheme({ theme }: ISetThemeParameters): void;
34
51
  /**
35
52
  * setUserOnboardingJWT sets the JWT to be whatever value is provided.
36
53
  * The JWT should be the UserJWT provided by ZeroHash via the platform
@@ -61,6 +78,11 @@ export declare class ZeroHashSDK implements IZeroHashSDK {
61
78
  closeModal(appIdentifier: AppIdentifier): void;
62
79
  /**
63
80
  * openModal opens the modal for the appIdentifier provided.
81
+ *
82
+ * When the JWT payload contains `use_new_sdk: true`, the modal renders
83
+ * the corresponding `@zerohash-sdk/*-react` npm package instead of the
84
+ * legacy iframe. Apps that don't yet have a published React package
85
+ * (e.g. crypto-account-link) fall back to the iframe automatically.
64
86
  */
65
87
  openModal({ jwt, appIdentifier, filters, navigate, }: IOpenModalParameters): void;
66
88
  /**
@@ -74,5 +96,11 @@ export declare class ZeroHashSDK implements IZeroHashSDK {
74
96
  */
75
97
  closeOnboardingModal(): void;
76
98
  }
99
+ /**
100
+ * Test-only: clear the set-once `_newSdkOrigin` pin so suites that
101
+ * construct `ZeroHashSDK` multiple times can exercise different envs in
102
+ * isolation. Not exported from the package; tests import it directly.
103
+ */
104
+ export declare function _resetNewSdkOriginForTests(): void;
77
105
  export default ZeroHashSDK;
78
106
  export * from "./types";