zh-web-sdk 2.16.1 → 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.
Files changed (77) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +239 -34
  3. package/dist/__mocks__/@zerohash-sdk/sdk-react-mock.d.ts +1 -0
  4. package/dist/__tests__/explicit-env.test.d.ts +1 -0
  5. package/dist/__tests__/message-router-origins.test.d.ts +1 -0
  6. package/dist/__tests__/sdk-version-attribution.test.d.ts +1 -0
  7. package/dist/__tests__/styles.test.d.ts +1 -0
  8. package/dist/api/convert-token.d.ts +12 -0
  9. package/dist/iframe-container/AppContainer.d.ts +13 -3
  10. package/dist/iframe-container/__tests__/get-new-sdk-env.test.d.ts +1 -0
  11. package/dist/iframe-container/hooks/use-style-updates.d.ts +1 -0
  12. package/dist/index.d.ts +30 -2
  13. package/dist/index.js +56 -54
  14. package/dist/index.js.map +4 -4
  15. package/dist/new-sdk/env.d.ts +35 -0
  16. package/dist/redux/__tests__/set-theme.test.d.ts +1 -0
  17. package/dist/redux/__tests__/set-use-new-sdk.test.d.ts +1 -0
  18. package/dist/redux/actions/index.d.ts +13 -1
  19. package/dist/redux/reducers/constants.d.ts +2 -0
  20. package/dist/redux/reducers/index.d.ts +3 -1
  21. package/dist/redux/reducers/new-sdk-flags.d.ts +11 -0
  22. package/dist/redux/reducers/theme.d.ts +10 -0
  23. package/dist/redux/store/index.d.ts +3 -1
  24. package/dist/styles.d.ts +7 -0
  25. package/dist/types.d.ts +42 -0
  26. package/dist/utils/test-utils.d.ts +48 -48
  27. package/dist/version.d.ts +1 -0
  28. package/package.json +32 -13
  29. package/.eslintrc.js +0 -12
  30. package/.github/CHANGELOG_TEMPLATE.md +0 -73
  31. package/.github/PULL_REQUEST_TEMPLATE.md +0 -10
  32. package/.github/backup/publish-tag.yaml +0 -14
  33. package/.github/workflows/build.yaml +0 -13
  34. package/.github/workflows/pr.yaml +0 -14
  35. package/.github/workflows/publish.yaml +0 -13
  36. package/.github/workflows/security.yml +0 -15
  37. package/.github/workflows/tag.yaml +0 -14
  38. package/RELEASING.md +0 -39
  39. package/jest.config.js +0 -8
  40. package/jest.setup.js +0 -24
  41. package/scripts/build.js +0 -34
  42. package/scripts/zip.js +0 -49
  43. package/src/__tests__/jwt-auth-detection.test.ts +0 -96
  44. package/src/api/convert-token.ts +0 -23
  45. package/src/constants.ts +0 -2
  46. package/src/hooks/__tests__/use-window-size.test.tsx +0 -26
  47. package/src/hooks/use-window-size.ts +0 -19
  48. package/src/iframe-container/AppContainer.tsx +0 -495
  49. package/src/iframe-container/__tests__/AppContainer.test.tsx +0 -300
  50. package/src/iframe-container/hooks/__tests__/use-style-updates.test.ts +0 -430
  51. package/src/iframe-container/hooks/use-style-updates.ts +0 -82
  52. package/src/index.tsx +0 -645
  53. package/src/redux/actions/index.ts +0 -27
  54. package/src/redux/reducers/constants.ts +0 -10
  55. package/src/redux/reducers/crypto-account-link-payouts.ts +0 -60
  56. package/src/redux/reducers/crypto-account-link.ts +0 -60
  57. package/src/redux/reducers/crypto-buy.ts +0 -75
  58. package/src/redux/reducers/crypto-sell.ts +0 -64
  59. package/src/redux/reducers/crypto-withdrawals.ts +0 -64
  60. package/src/redux/reducers/fiat-account-link.ts +0 -60
  61. package/src/redux/reducers/fiat-deposits.ts +0 -64
  62. package/src/redux/reducers/fiat-withdrawals.ts +0 -64
  63. package/src/redux/reducers/fund.ts +0 -75
  64. package/src/redux/reducers/index.ts +0 -35
  65. package/src/redux/reducers/onboarding.ts +0 -74
  66. package/src/redux/reducers/pay.ts +0 -64
  67. package/src/redux/reducers/payouts.ts +0 -64
  68. package/src/redux/reducers/profile.ts +0 -63
  69. package/src/redux/store/index.ts +0 -10
  70. package/src/styles.ts +0 -108
  71. package/src/types.ts +0 -578
  72. package/src/utils/auth-to-fund-mapper.ts +0 -174
  73. package/src/utils/strings.ts +0 -19
  74. package/src/utils/test-utils.tsx +0 -36
  75. package/src/utils/world-app-utils.ts +0 -8
  76. package/src/utils.ts +0 -27
  77. package/tsconfig.json +0 -26
@@ -1,495 +0,0 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import { connect, useSelector } from "react-redux";
3
- import { Auth } from "@connect-xyz/auth-react";
4
- import { createAuthToFundCallbacks } from "../utils/auth-to-fund-mapper";
5
-
6
- import {
7
- containerMediaStyles,
8
- containerStyle,
9
- minWidthMatcher,
10
- screenSizes,
11
- appWrapperStyle as defaultAppWrapperStyle,
12
- modalStyle as defaultModalStyle,
13
- iframeWrapperStyle as defaultIframeWrapperStyle,
14
- iframeStyle as defaultIframeStyle,
15
- } from "../styles";
16
- import { closeModal } from "../redux/actions";
17
- import {
18
- AppIdentifier,
19
- appIdentifierToActionPrefixMap,
20
- AuthSettings,
21
- Filters,
22
- IncomingMessageType,
23
- OnboardingPage,
24
- Page,
25
- } from "../types";
26
- import { useWindowSize } from "../hooks/use-window-size";
27
- import { isInsideWorldApp } from "../utils/world-app-utils";
28
- import {
29
- PayCommandInput,
30
- Tokens,
31
- tokenToDecimals,
32
- } from "@worldcoin/minikit-js";
33
- import { useStyleUpdates } from "./hooks/use-style-updates";
34
-
35
- interface AppContainerProps {
36
- isAppActive?: boolean;
37
- isAppLoaded?: boolean;
38
- jwt?: string;
39
- zeroHashAppURL: string;
40
- appIdentifier: AppIdentifier;
41
- filters?: Filters;
42
- navigate?: Page;
43
- useAuth?: boolean;
44
- authSettings?: AuthSettings;
45
- }
46
-
47
- interface AppContainerMappedProps {
48
- [AppIdentifier.CRYPTO_WITHDRAWALS]: {
49
- isAppActive: boolean;
50
- isAppLoaded: boolean;
51
- jwt: string;
52
- filters?: Filters;
53
- };
54
- [AppIdentifier.ONBOARDING]: {
55
- isAppActive: boolean;
56
- isAppLoaded: boolean;
57
- jwt: string;
58
- filters?: Filters;
59
- navigate?: OnboardingPage;
60
- };
61
- [AppIdentifier.FIAT_DEPOSITS]: {
62
- isAppActive: boolean;
63
- isAppLoaded: boolean;
64
- jwt: string;
65
- filters?: Filters;
66
- };
67
- [AppIdentifier.FIAT_WITHDRAWALS]: {
68
- isAppActive: boolean;
69
- isAppLoaded: boolean;
70
- jwt: string;
71
- filters?: Filters;
72
- };
73
- [AppIdentifier.CRYPTO_BUY]: {
74
- isAppActive: boolean;
75
- isAppLoaded: boolean;
76
- jwt: string;
77
- filters?: Filters;
78
- };
79
- [AppIdentifier.CRYPTO_SELL]: {
80
- isAppActive: boolean;
81
- isAppLoaded: boolean;
82
- jwt: string;
83
- filters?: Filters;
84
- };
85
- [AppIdentifier.CSP_CRYPTO_WITHDRAWALS]: {
86
- isAppActive: boolean;
87
- isAppLoaded: boolean;
88
- jwt: string;
89
- filters?: Filters;
90
- };
91
- [AppIdentifier.CSP_FIAT_WITHDRAWALS]: {
92
- isAppActive: boolean;
93
- isAppLoaded: boolean;
94
- jwt: string;
95
- filters?: Filters;
96
- };
97
- [AppIdentifier.CSP_CRYPTO_SELL]: {
98
- isAppActive: boolean;
99
- isAppLoaded: boolean;
100
- jwt: string;
101
- filters?: Filters;
102
- };
103
- [AppIdentifier.FUND]: {
104
- isAppActive: boolean;
105
- isAppLoaded: boolean;
106
- jwt: string;
107
- filters?: Filters;
108
- useAuth?: boolean;
109
- authSettings?: AuthSettings;
110
- };
111
- [AppIdentifier.PROFILE]: {
112
- isAppActive: boolean;
113
- isAppLoaded: boolean;
114
- jwt: string;
115
- filters?: Filters;
116
- };
117
- [AppIdentifier.CRYPTO_ACCOUNT_LINK]: {
118
- isAppActive: boolean;
119
- isAppLoaded: boolean;
120
- jwt: string;
121
- filters?: Filters;
122
- };
123
- [AppIdentifier.CRYPTO_ACCOUNT_LINK_PAYOUTS]: {
124
- isAppActive: boolean;
125
- isAppLoaded: boolean;
126
- jwt: string;
127
- filters?: Filters;
128
- };
129
- [AppIdentifier.PAYOUTS]: {
130
- isAppActive: boolean;
131
- isAppLoaded: boolean;
132
- jwt: string;
133
- filters?: Filters;
134
- };
135
- [AppIdentifier.PAY]: {
136
- isAppActive: boolean;
137
- isAppLoaded: boolean;
138
- jwt: string;
139
- filters?: Filters;
140
- };
141
- [AppIdentifier.FIAT_ACCOUNT_LINK]: {
142
- isAppActive: boolean;
143
- isAppLoaded: boolean;
144
- jwt: string;
145
- filters?: Filters;
146
- };
147
- }
148
-
149
- const appLoadTime = Date.now();
150
-
151
- const mapAppToTitle = {
152
- [AppIdentifier.ONBOARDING]: "Onboarding",
153
- [AppIdentifier.CRYPTO_WITHDRAWALS]: "Crypto Withdrawals",
154
- [AppIdentifier.FIAT_DEPOSITS]: "Fiat Deposits",
155
- [AppIdentifier.FIAT_WITHDRAWALS]: "Fiat Withdrawals",
156
- [AppIdentifier.CRYPTO_BUY]: "Crypto Buy",
157
- [AppIdentifier.CRYPTO_SELL]: "Crypto Sell",
158
- [AppIdentifier.CSP_CRYPTO_WITHDRAWALS]: "CBP Crypto Withdrawals",
159
- [AppIdentifier.CSP_FIAT_WITHDRAWALS]: "CBP Fiat Withdrawals",
160
- [AppIdentifier.CSP_CRYPTO_SELL]: "Crypto Sell",
161
- [AppIdentifier.FUND]: "Fund",
162
- [AppIdentifier.PROFILE]: "Profile",
163
- [AppIdentifier.CRYPTO_ACCOUNT_LINK]: "Crypto Account Link",
164
- [AppIdentifier.CRYPTO_ACCOUNT_LINK_PAYOUTS]: "Crypto Account Link Payouts",
165
- [AppIdentifier.PAYOUTS]: "Payouts",
166
- [AppIdentifier.PAY]: "Pay",
167
- [AppIdentifier.FIAT_ACCOUNT_LINK]: "Fiat Account Link",
168
- };
169
-
170
- const AppContainer = ({
171
- isAppActive,
172
- isAppLoaded,
173
- jwt,
174
- zeroHashAppURL,
175
- appIdentifier,
176
- navigate,
177
- useAuth,
178
- authSettings,
179
- }: AppContainerProps) => {
180
- const title = mapAppToTitle[appIdentifier];
181
- const hasJwt = !!jwt;
182
- const [container, setContainerStyle] = useState(containerStyle);
183
- const allAppsState = useSelector((state) => state as AppContainerMappedProps);
184
- const { height } = useWindowSize();
185
-
186
- // Styles received from iframe via postMessage
187
- const { styles, stylesLoaded, handleStyleConfig } = useStyleUpdates(
188
- zeroHashAppURL,
189
- {
190
- appWrapperStyle: defaultAppWrapperStyle,
191
- modalStyle: defaultModalStyle,
192
- iframeWrapperStyle: defaultIframeWrapperStyle,
193
- iframeStyle: defaultIframeStyle,
194
- },
195
- );
196
-
197
- // Determine environment from zeroHashAppURL
198
- const authEnv =
199
- zeroHashAppURL.includes("sandbox") || zeroHashAppURL.includes("cert")
200
- ? "sandbox"
201
- : "production";
202
-
203
- /**
204
- * setContainer sets the CSS styles based on the current matching media queries
205
- */
206
- const setContainer = () => {
207
- const sizeId = minWidthMatcher();
208
- const containerMediaStyle = containerMediaStyles[sizeId];
209
- setContainerStyle({ ...containerStyle, ...containerMediaStyle });
210
- };
211
-
212
- const iRef: React.MutableRefObject<HTMLIFrameElement | null> =
213
- useRef<HTMLIFrameElement | null>(null);
214
- useEffect(() => {
215
- // Send events to the iframe when Apps are ready
216
- if (
217
- zeroHashAppURL &&
218
- isAppLoaded &&
219
- hasJwt &&
220
- iRef.current?.contentWindow
221
- ) {
222
- // This loops all registered apps and send events listed below.
223
- Object.keys(allAppsState).forEach((key: string) => {
224
- if (!allAppsState[key as AppIdentifier].jwt) return;
225
-
226
- // Send JWT token
227
- iRef.current?.contentWindow?.postMessage(
228
- {
229
- type: `${appIdentifierToActionPrefixMap.get(
230
- key as AppIdentifier,
231
- )}SEND_JWT_TOKEN`,
232
- jwt: allAppsState[key as AppIdentifier].jwt,
233
- },
234
- zeroHashAppURL,
235
- );
236
-
237
- // If the zh-web-sdk is being run inside the WorldApp, we must send the WorldApp object
238
- // to the iframe.
239
- if (isInsideWorldApp()) {
240
- iRef.current?.contentWindow?.postMessage(
241
- { type: `WORLD_APP_OBJECT`, WorldApp: window.WorldApp },
242
- zeroHashAppURL,
243
- );
244
- }
245
-
246
- // Send filters
247
- if (allAppsState[key as AppIdentifier].filters) {
248
- iRef.current?.contentWindow?.postMessage(
249
- {
250
- type: `${appIdentifierToActionPrefixMap.get(
251
- key as AppIdentifier,
252
- )}SEND_FILTERS`,
253
- filters: allAppsState[key as AppIdentifier].filters,
254
- },
255
- zeroHashAppURL,
256
- );
257
- }
258
- // Send navigate to Onboarding App
259
- if (appIdentifier === AppIdentifier.ONBOARDING && navigate) {
260
- iRef.current?.contentWindow?.postMessage(
261
- {
262
- type: `${appIdentifierToActionPrefixMap.get(
263
- AppIdentifier.ONBOARDING,
264
- )}NAVIGATE`,
265
- navigate,
266
- },
267
- zeroHashAppURL,
268
- );
269
- }
270
- });
271
- }
272
- }, [
273
- appIdentifier,
274
- hasJwt,
275
- isAppLoaded,
276
- jwt,
277
- zeroHashAppURL,
278
- allAppsState,
279
- navigate,
280
- ]);
281
-
282
- useEffect(() => {
283
- // set the styles when the screen size changes
284
- setContainer();
285
- if (window) {
286
- screenSizes.forEach(({ size }) => {
287
- window
288
- .matchMedia(`(min-width: ${size}px)`)
289
- .addEventListener("change", setContainer);
290
- });
291
- return () =>
292
- screenSizes.forEach(({ size }) => {
293
- window
294
- .matchMedia(`(min-width: ${size}px)`)
295
- .removeEventListener("change", setContainer);
296
- });
297
- }
298
- }, []);
299
-
300
- /**
301
- * Handles MiniKit pay command processing
302
- */
303
- const handleMiniKitPayCommand = useCallback(
304
- async (event: MessageEvent) => {
305
- const zhAppsURL = new URL(zeroHashAppURL);
306
- iRef.current?.contentWindow?.postMessage(
307
- {
308
- type: "MINIKIT_PAY_COMMAND_RECEIVED",
309
- payload: {
310
- origin: event.origin,
311
- zhAppsURLOrigin: zhAppsURL.origin,
312
- data: event.data,
313
- },
314
- },
315
- zeroHashAppURL,
316
- );
317
-
318
- if (!window.MiniKit) {
319
- iRef.current?.contentWindow?.postMessage(
320
- {
321
- type: "MINIKIT_PAY_COMMAND_CANCELED",
322
- payload: { reason: "window.Minikit not found" },
323
- },
324
- zeroHashAppURL,
325
- );
326
- return;
327
- }
328
-
329
- try {
330
- if (event.data?.type === "MINIKIT_PAY_COMMAND") {
331
- const payload = event.data.payload;
332
- const minikitPayload: PayCommandInput = {
333
- reference: payload.reference,
334
- to: payload.to,
335
- tokens: [
336
- {
337
- symbol: payload.token as Tokens,
338
- token_amount: tokenToDecimals(
339
- Number(payload.amount),
340
- payload.token,
341
- ).toString(),
342
- },
343
- ],
344
- description: payload.description,
345
- };
346
- iRef.current?.contentWindow?.postMessage(
347
- {
348
- type: "MINIKIT_PAY_COMMAND_SUBMITTING_PAYMENT",
349
- payload: { minikitPayload },
350
- },
351
- zeroHashAppURL,
352
- );
353
- const { finalPayload } =
354
- await window.MiniKit.commandsAsync.pay(minikitPayload);
355
-
356
- iRef.current?.contentWindow?.postMessage(
357
- { type: "MINIKIT_PAY_COMMAND_RESULT", payload: { finalPayload } },
358
- zeroHashAppURL,
359
- );
360
- }
361
- } catch (error) {
362
- iRef.current?.contentWindow?.postMessage(
363
- {
364
- type: "MINIKIT_PAY_COMMAND_ERROR",
365
- payload: { error, status: "error" },
366
- },
367
- zeroHashAppURL,
368
- );
369
- }
370
- },
371
- [zeroHashAppURL],
372
- );
373
-
374
- /**
375
- * Main postMessage event handler that routes messages to appropriate handlers
376
- */
377
- const postMessageEventHandler = useCallback(
378
- async (event: MessageEvent) => {
379
- // Handle style configuration messages
380
- if (event.data.type === IncomingMessageType.StyleConfig) {
381
- handleStyleConfig(event.data, event.origin);
382
- return;
383
- }
384
-
385
- // Handle MiniKit pay commands
386
- await handleMiniKitPayCommand(event);
387
- },
388
- [handleStyleConfig, handleMiniKitPayCommand],
389
- );
390
-
391
- useEffect(() => {
392
- window.addEventListener("message", postMessageEventHandler);
393
- return () => window.removeEventListener("message", postMessageEventHandler);
394
- }, [postMessageEventHandler, zeroHashAppURL]);
395
-
396
- const iframeURL = new URL(zeroHashAppURL);
397
- iframeURL.searchParams.set("name", appLoadTime.toString());
398
- if (window) {
399
- iframeURL.searchParams.set("origin", window.location.origin);
400
- }
401
-
402
- if (!isAppActive) {
403
- return <></>;
404
- }
405
- const { appWrapperStyle, modalStyle, iframeWrapperStyle, iframeStyle } =
406
- styles;
407
-
408
- // If useAuth is true, render Auth component instead of iframe
409
- if (useAuth && hasJwt) {
410
- const authCallbacks = createAuthToFundCallbacks(window.location.origin);
411
- const theme = authSettings?.theme || "auto";
412
-
413
- return (
414
- <div
415
- style={{
416
- ...appWrapperStyle,
417
- maxHeight: CSS.supports("height: 100dvh") ? "100dvh" : `${height}px`,
418
- height: CSS.supports("height: 100dvh") ? "100dvh" : `${height}px`,
419
- }}
420
- onClick={() => closeModal(appIdentifier)}
421
- >
422
- <div
423
- style={{
424
- ...modalStyle,
425
- ...container,
426
- backgroundColor: "transparent",
427
- zIndex: "9999",
428
- opacity: stylesLoaded ? 1 : 0,
429
- }}
430
- onClick={(e) => e.stopPropagation()}
431
- >
432
- <div style={{ ...iframeWrapperStyle, ...iframeStyle }}>
433
- <Auth jwt={jwt} env={authEnv} theme={theme} {...authCallbacks} />
434
- </div>
435
- </div>
436
- </div>
437
- );
438
- }
439
-
440
- return (
441
- <div
442
- style={{
443
- ...appWrapperStyle,
444
- /**
445
- * If browser does not support 100dvh, use height in pixels that is recalculated when
446
- * the window is resized.
447
- */
448
- maxHeight: CSS.supports("height: 100dvh") ? "100dvh" : `${height}px`,
449
- height: CSS.supports("height: 100dvh") ? "100dvh" : `${height}px`,
450
- }}
451
- onClick={() => closeModal(appIdentifier)}
452
- >
453
- <div
454
- style={{ ...modalStyle, ...container, opacity: stylesLoaded ? 1 : 0 }}
455
- >
456
- <div style={iframeWrapperStyle}>
457
- <iframe
458
- ref={iRef}
459
- title={title}
460
- src={iframeURL.toString()}
461
- allow="camera *; fullscreen *; accelerometer *; gyroscope *; magnetometer *; local-network-access *;"
462
- sandbox="allow-downloads allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-top-navigation"
463
- style={iframeStyle}
464
- />
465
- </div>
466
- </div>
467
- </div>
468
- );
469
- };
470
-
471
- const mapStateToProps = (
472
- state: AppContainerMappedProps,
473
- ownProps: AppContainerProps,
474
- ) => {
475
- return {
476
- isAppActive: state[ownProps.appIdentifier].isAppActive,
477
- isAppLoaded: state[ownProps.appIdentifier].isAppLoaded,
478
- jwt: state[ownProps.appIdentifier].jwt,
479
- filters: state[ownProps.appIdentifier].filters,
480
- navigate:
481
- ownProps.appIdentifier === AppIdentifier.ONBOARDING
482
- ? state[ownProps.appIdentifier].navigate
483
- : undefined,
484
- useAuth:
485
- ownProps.appIdentifier === AppIdentifier.FUND
486
- ? state[ownProps.appIdentifier].useAuth
487
- : undefined,
488
- authSettings:
489
- ownProps.appIdentifier === AppIdentifier.FUND
490
- ? state[ownProps.appIdentifier].authSettings
491
- : undefined,
492
- };
493
- };
494
-
495
- export default connect(mapStateToProps)(AppContainer);