@dynamic-labs/sdk-react-core 2.5.3 → 2.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/package.cjs +2 -2
  3. package/package.js +2 -2
  4. package/package.json +14 -14
  5. package/src/lib/components/QRCode/QRCode.d.ts +15 -0
  6. package/src/lib/components/UserProfile/parts/UserProfileSocialAccount/UserProfileSocialAccount.cjs +1 -1
  7. package/src/lib/components/UserProfile/parts/UserProfileSocialAccount/UserProfileSocialAccount.js +1 -1
  8. package/src/lib/config/ApiEndpoint.cjs +6 -20
  9. package/src/lib/config/ApiEndpoint.d.ts +1 -2
  10. package/src/lib/config/ApiEndpoint.js +6 -20
  11. package/src/lib/context/DynamicContext/DynamicContext.cjs +2 -0
  12. package/src/lib/context/DynamicContext/DynamicContext.d.ts +2 -0
  13. package/src/lib/context/DynamicContext/DynamicContext.js +2 -0
  14. package/src/lib/context/DynamicContext/types/SocialSettings.d.ts +7 -0
  15. package/src/lib/context/DynamicContext/types/index.d.ts +2 -0
  16. package/src/lib/context/SocialRedirectContext/SocialRedirectContext.cjs +4 -0
  17. package/src/lib/context/SocialRedirectContext/SocialRedirectContext.js +4 -0
  18. package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/index.d.ts +1 -0
  19. package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.cjs +150 -0
  20. package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.d.ts +7 -0
  21. package/src/lib/context/SocialRedirectContext/hooks/useRedirectSocialHandler/useRedirectSocialHandler.js +146 -0
  22. package/src/lib/data/api/embeddedWallets/embeddedWallets.cjs +1 -1
  23. package/src/lib/data/api/embeddedWallets/embeddedWallets.js +1 -1
  24. package/src/lib/data/api/oauth/oauth.cjs +13 -0
  25. package/src/lib/data/api/oauth/oauth.d.ts +2 -1
  26. package/src/lib/data/api/oauth/oauth.js +13 -1
  27. package/src/lib/shared/utils/hooks/index.d.ts +1 -0
  28. package/src/lib/shared/utils/hooks/useEffectOnceCondition/index.d.ts +1 -0
  29. package/src/lib/shared/utils/hooks/useEffectOnceCondition/useEffectOnceCondition.cjs +26 -0
  30. package/src/lib/shared/utils/hooks/useEffectOnceCondition/useEffectOnceCondition.d.ts +7 -0
  31. package/src/lib/shared/utils/hooks/useEffectOnceCondition/useEffectOnceCondition.js +22 -0
  32. package/src/lib/styles/index.shadow.cjs +1 -1
  33. package/src/lib/styles/index.shadow.js +1 -1
  34. package/src/lib/utils/functions/index.d.ts +1 -0
  35. package/src/lib/utils/functions/socialStorage/index.d.ts +1 -0
  36. package/src/lib/utils/functions/socialStorage/socialStorage.cjs +36 -0
  37. package/src/lib/utils/functions/socialStorage/socialStorage.d.ts +17 -0
  38. package/src/lib/utils/functions/socialStorage/socialStorage.js +29 -0
  39. package/src/lib/utils/hooks/useSocialAuth/apple/connectWithAppleId.cjs +26 -0
  40. package/src/lib/utils/hooks/useSocialAuth/apple/connectWithAppleId.d.ts +7 -0
  41. package/src/lib/utils/hooks/useSocialAuth/apple/connectWithAppleId.js +22 -0
  42. package/src/lib/utils/hooks/useSocialAuth/apple/loadAppleId.cjs +34 -0
  43. package/src/lib/utils/hooks/useSocialAuth/apple/loadAppleId.d.ts +1 -0
  44. package/src/lib/utils/hooks/useSocialAuth/apple/loadAppleId.js +30 -0
  45. package/src/lib/utils/hooks/useSocialAuth/index.d.ts +1 -1
  46. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.cjs +85 -27
  47. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.d.ts +9 -1
  48. package/src/lib/utils/hooks/useSocialAuth/useSocialAuth.js +90 -32
  49. package/src/lib/widgets/DynamicEmbeddedWidget/DynamicEmbeddedAuthFlow/DynamicEmbeddedAuthFlow.cjs +1 -2
  50. package/src/lib/widgets/DynamicEmbeddedWidget/DynamicEmbeddedAuthFlow/DynamicEmbeddedAuthFlow.js +1 -2
@@ -1,9 +1,9 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../../../../../_virtual/_tslib.js';
3
- import { useState, useRef } from 'react';
3
+ import { useMemo, useState, useRef } from 'react';
4
4
  import { ProviderEnum } from '@dynamic-labs/sdk-api-core';
5
5
  import { SocialOAuthErrorCode } from '@dynamic-labs/types';
6
- import { PlatformService, isMobile, SocialAccountAlreadyExistsError } from '@dynamic-labs/utils';
6
+ import { isSafariBrowser, isIOS, PlatformService, isMobile, SocialAccountAlreadyExistsError } from '@dynamic-labs/utils';
7
7
  import '../../../context/DynamicContext/DynamicContext.js';
8
8
  import { logger } from '../../../shared/logger.js';
9
9
  import '@dynamic-labs/iconic';
@@ -31,8 +31,9 @@ import 'viem';
31
31
  import 'viem/chains';
32
32
  import '../../../config/ApiEndpoint.js';
33
33
  import '@dynamic-labs/store';
34
- import { signInOAuth, verifyOAuth, farcasterSignIn, farcasterVerify } from '../../../data/api/oauth/oauth.js';
34
+ import { initAuth, signInOAuth, verifyOAuth, farcasterSignIn, farcasterVerify } from '../../../data/api/oauth/oauth.js';
35
35
  import '../../../locale/locale.js';
36
+ import { setSocialStorageFor } from '../../functions/socialStorage/socialStorage.js';
36
37
  import '../../../context/AccessDeniedContext/AccessDeniedContext.js';
37
38
  import '../../../context/AccountExistsContext/AccountExistsContext.js';
38
39
  import '../../../context/UserWalletsContext/UserWalletsContext.js';
@@ -43,6 +44,7 @@ import '../../../context/ThemeContext/ThemeContext.js';
43
44
  import '../useUserUpdateRequest/useUpdateUser/userFieldsSchema.js';
44
45
  import { useUserAuth } from '../useUserAuth/useUserAuth.js';
45
46
  import { connect, watchStatus } from './farcaster.js';
47
+ import { connectWithAppleId } from './apple/connectWithAppleId.js';
46
48
  import 'yup';
47
49
  import '../../../context/MockContext/MockContext.js';
48
50
  import '../../../views/CollectUserDataView/useFields.js';
@@ -101,9 +103,13 @@ const socialProviders = [
101
103
  const providersRequiringPkce = ['twitter', 'github'];
102
104
  // Hook to handle common social auth logic (for social linking and social sign in)
103
105
  const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, }) => {
104
- const { environmentId, setShowAuthFlow, projectSettings, consumeNonce, redirectUrl, } = useInternalDynamicContext();
106
+ const { environmentId, setShowAuthFlow, projectSettings, consumeNonce, socialSettings, redirectUrl, } = useInternalDynamicContext();
107
+ /**
108
+ * Represents if the SDK will use a popup or redirect for social auth
109
+ */
110
+ const strategy = useMemo(() => (socialSettings === null || socialSettings === void 0 ? void 0 : socialSettings.strategy) || 'popup', [socialSettings]);
105
111
  const { setErrorMessage, setError: setContextError } = useErrorContext();
106
- const { initAuth } = useUserAuth({
112
+ const { initAuth: initAuth$1 } = useUserAuth({
107
113
  authMethod: 'social',
108
114
  });
109
115
  const [isProcessing, setIsProcessing] = useState(false);
@@ -159,7 +165,7 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
159
165
  }
160
166
  });
161
167
  const signInAccount = (provider, apiCall) => __awaiter(void 0, void 0, void 0, function* () {
162
- yield initAuth({
168
+ yield initAuth$1({
163
169
  onError: () => handleError(provider, SocialOAuthErrorCode.SIGNIN_ERROR, `Failed to sign-in with social account: ${provider}`, { raiseAuthFailure: true }),
164
170
  onSettled,
165
171
  options: { provider },
@@ -167,7 +173,7 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
167
173
  });
168
174
  });
169
175
  const connectSocialAccount = (_a) => __awaiter(void 0, [_a], void 0, function* ({ authMode, provider, validator, captchaToken, }) {
170
- var _b, _c;
176
+ var _b, _c, _d;
171
177
  clearInterval(authWindowInterval.current);
172
178
  clearError();
173
179
  setIsProcessing(true);
@@ -189,17 +195,40 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
189
195
  });
190
196
  if (provider === ProviderEnum.Farcaster)
191
197
  return connectWithFarcaster(authMode, { captchaToken });
192
- const authWindow = window.open('', '_blank', 'width=500,height=600');
198
+ let authWindow = null;
193
199
  const state = randomString(32);
194
200
  const verifier = randomString(43);
201
+ const apiProvider = getProviderByType((_b = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _b !== void 0 ? _b : [], provider);
202
+ const loginUrl = getOauthLoginUrl((_c = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _c !== void 0 ? _c : [], provider);
203
+ // Whether we will use PKCE (code verifier/challenge) for this provider
204
+ const usingPkce = providersRequiringPkce.includes(provider);
205
+ setSocialStorageFor(provider, {
206
+ captchaToken,
207
+ codeVerifier: verifier,
208
+ state,
209
+ });
210
+ if (provider === ProviderEnum.Apple &&
211
+ (isSafariBrowser() || isIOS() || strategy === 'redirect')) {
212
+ yield initAuth(environmentId, provider, {
213
+ // When we set the redirectUrl, the backend gives preference to a redirect
214
+ // experience, which is only desired for mobile
215
+ redirectUrl: removeDynamicOauthParamsFromUrl(redirectUrl || window.location.href),
216
+ state,
217
+ });
218
+ yield connectWithAppleId({
219
+ clientId: apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.clientId,
220
+ oauthLoginUrl: new URL(loginUrl),
221
+ state,
222
+ });
223
+ return;
224
+ }
195
225
  const clearListeners = () => {
196
226
  window.removeEventListener('message', handleAuthWindowMessage);
197
227
  providersWaitingOauthMessage.current = Object.assign(Object.assign({}, providersWaitingOauthMessage.current), { [provider]: false });
198
228
  };
199
229
  const handleAuthWindowMessage = (event) => __awaiter(void 0, void 0, void 0, function* () {
200
- var _d, _e;
230
+ var _e;
201
231
  const message = event.data;
202
- const apiProvider = getProviderByType((_d = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _d !== void 0 ? _d : [], provider);
203
232
  if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
204
233
  return;
205
234
  }
@@ -256,31 +285,20 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
256
285
  handleError(provider, SocialOAuthErrorCode.NO_AUTH_CODE, `Failed to connect ${provider} social account: no authorization code`, { raiseAuthFailure: authMode === 'signin' });
257
286
  return;
258
287
  }
259
- if (authMode === 'signin') {
260
- const apiCall = () => signInOAuth(environmentId, provider, {
261
- captchaToken,
262
- code,
263
- codeVerifier: verifier,
264
- state,
265
- });
266
- yield signInAccount(provider, apiCall);
267
- }
268
- else {
269
- const apiCall = () => verifyOAuth(environmentId, provider, {
270
- code,
271
- codeVerifier: verifier,
272
- state,
273
- });
274
- yield linkAccount(provider, apiCall);
275
- }
276
- setIsProcessing(false);
288
+ yield completeConnection({
289
+ authCode: code,
290
+ authMode,
291
+ captchaToken,
292
+ provider,
293
+ state,
294
+ verifier,
295
+ });
277
296
  });
278
- const loginUrl = getOauthLoginUrl((_b = projectSettings === null || projectSettings === void 0 ? void 0 : projectSettings.providers) !== null && _b !== void 0 ? _b : [], provider);
279
297
  if (!loginUrl) {
280
298
  handleError(provider, SocialOAuthErrorCode.NO_OAUTH_URL, `Failed to get login url to connect social account: ${provider}`, { raiseAuthFailure: authMode === 'signin' });
281
299
  return;
282
300
  }
283
- if (!((_c = providersWaitingOauthMessage.current) === null || _c === void 0 ? void 0 : _c[provider])) {
301
+ if (!((_d = providersWaitingOauthMessage.current) === null || _d === void 0 ? void 0 : _d[provider])) {
284
302
  window.addEventListener('message', handleAuthWindowMessage);
285
303
  providersWaitingOauthMessage.current = Object.assign(Object.assign({}, providersWaitingOauthMessage.current), { [provider]: true });
286
304
  }
@@ -290,7 +308,7 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
290
308
  });
291
309
  let oauthLoginUrl = `${loginUrl}&${stateParam}`;
292
310
  // only add pkce params for providers that support/require it
293
- if (providersRequiringPkce.includes(provider)) {
311
+ if (usingPkce) {
294
312
  const digest = yield digestSHA256(verifier);
295
313
  const pkceParams = stringifyURIQuery({
296
314
  code_challenge: encodeBase64URL(digest),
@@ -298,6 +316,19 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
298
316
  });
299
317
  oauthLoginUrl = `${oauthLoginUrl}&${pkceParams}`;
300
318
  }
319
+ yield initAuth(environmentId, provider, {
320
+ // When we set the redirectUrl, the backend gives preference to a redirect
321
+ // experience, which is only desired for mobile
322
+ redirectUrl: strategy === 'redirect'
323
+ ? removeDynamicOauthParamsFromUrl(redirectUrl || window.location.href)
324
+ : undefined,
325
+ state,
326
+ });
327
+ if (strategy === 'redirect') {
328
+ window.location.assign(oauthLoginUrl);
329
+ return;
330
+ }
331
+ authWindow = window.open('', '_blank', 'width=500,height=600');
301
332
  authWindow === null || authWindow === void 0 ? void 0 : authWindow.location.assign(oauthLoginUrl);
302
333
  // For provider that support window.opener, we need to clear all states/listeners when the window is closed
303
334
  authWindowInterval.current = setInterval(() => {
@@ -313,7 +344,27 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
313
344
  }
314
345
  }, 2000);
315
346
  });
316
- const connectWithFarcaster = (authMode_1, _f) => __awaiter(void 0, [authMode_1, _f], void 0, function* (authMode, { captchaToken }) {
347
+ const completeConnection = (_f) => __awaiter(void 0, [_f], void 0, function* ({ authMode, provider, state, authCode, verifier, captchaToken, }) {
348
+ if (authMode === 'signin') {
349
+ const apiCall = () => signInOAuth(environmentId, provider, {
350
+ captchaToken,
351
+ code: authCode,
352
+ codeVerifier: verifier,
353
+ state,
354
+ });
355
+ yield signInAccount(provider, apiCall);
356
+ }
357
+ else {
358
+ const apiCall = () => verifyOAuth(environmentId, provider, {
359
+ code: authCode,
360
+ codeVerifier: verifier,
361
+ state,
362
+ });
363
+ yield linkAccount(provider, apiCall);
364
+ }
365
+ setIsProcessing(false);
366
+ });
367
+ const connectWithFarcaster = (authMode_1, _g) => __awaiter(void 0, [authMode_1, _g], void 0, function* (authMode, { captchaToken }) {
317
368
  const dynamicNonce = consumeNonce();
318
369
  const domain = PlatformService.getHost();
319
370
  const data = yield connect({
@@ -382,6 +433,7 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
382
433
  });
383
434
  return {
384
435
  checkValidProvider,
436
+ completeConnection,
385
437
  connectSocialAccount,
386
438
  error,
387
439
  handleError,
@@ -390,5 +442,11 @@ const useSocialAuth = ({ sessionTimeout, onSettled, onError, onFarcasterUrl, })
390
442
  setIsProcessing,
391
443
  };
392
444
  };
445
+ const removeDynamicOauthParamsFromUrl = (url) => {
446
+ const urlObject = new URL(url);
447
+ urlObject.searchParams.delete('dynamicOauthState');
448
+ urlObject.searchParams.delete('dynamicOauthCode');
449
+ return urlObject.toString();
450
+ };
393
451
 
394
452
  export { useSocialAuth };
@@ -78,7 +78,6 @@ var PopperContext = require('../../../components/Popper/PopperContext/PopperCont
78
78
  require('qrcode');
79
79
  var RenderView = require('../../../components/RenderView/RenderView.cjs');
80
80
  var SandboxIndicatorWrapper = require('../../../components/SandboxIndicatorWrapper/SandboxIndicatorWrapper.cjs');
81
- var SocialRedirectContext = require('../../../context/SocialRedirectContext/SocialRedirectContext.cjs');
82
81
 
83
82
  const DynamicEmbeddedAuthFlow = ({ background = 'none', className, style, }) => {
84
83
  const hide = useIsLoggedIn.useIsLoggedIn();
@@ -109,7 +108,7 @@ const DynamicEmbeddedAuthFlow = ({ background = 'none', className, style, }) =>
109
108
  if (hide)
110
109
  return null;
111
110
  const content = (jsxRuntime.jsx(DynamicAuthLayout.DynamicAuthLayout, { className: className, style: style, projectSettings: projectSettings, children: jsxRuntime.jsx(RenderView.RenderView, {}) }));
112
- return (jsxRuntime.jsx(ShadowDOM.ShadowDOM, { className: 'embedded-widget', children: jsxRuntime.jsx(PopperContext.PopperProvider, { children: jsxRuntime.jsx(SocialRedirectContext.SocialRedirectContextProvider, { children: jsxRuntime.jsx(index.FooterAnimationContextProvider, { children: jsxRuntime.jsx(SandboxIndicatorWrapper.SandboxIndicatorWrapper, { children: background === 'none' ? (content) : (jsxRuntime.jsx(ModalCard.ModalCard, { border: background === 'with-border', sharpBottomRadiusOnMobile: false, children: content })) }) }) }) }) }));
111
+ return (jsxRuntime.jsx(ShadowDOM.ShadowDOM, { className: 'embedded-widget', children: jsxRuntime.jsx(PopperContext.PopperProvider, { children: jsxRuntime.jsx(index.FooterAnimationContextProvider, { children: jsxRuntime.jsx(SandboxIndicatorWrapper.SandboxIndicatorWrapper, { children: background === 'none' ? (content) : (jsxRuntime.jsx(ModalCard.ModalCard, { border: background === 'with-border', sharpBottomRadiusOnMobile: false, children: content })) }) }) }) }));
113
112
  };
114
113
 
115
114
  exports.DynamicEmbeddedAuthFlow = DynamicEmbeddedAuthFlow;
@@ -74,7 +74,6 @@ import { PopperProvider } from '../../../components/Popper/PopperContext/PopperC
74
74
  import 'qrcode';
75
75
  import { RenderView } from '../../../components/RenderView/RenderView.js';
76
76
  import { SandboxIndicatorWrapper } from '../../../components/SandboxIndicatorWrapper/SandboxIndicatorWrapper.js';
77
- import { SocialRedirectContextProvider } from '../../../context/SocialRedirectContext/SocialRedirectContext.js';
78
77
 
79
78
  const DynamicEmbeddedAuthFlow = ({ background = 'none', className, style, }) => {
80
79
  const hide = useIsLoggedIn();
@@ -105,7 +104,7 @@ const DynamicEmbeddedAuthFlow = ({ background = 'none', className, style, }) =>
105
104
  if (hide)
106
105
  return null;
107
106
  const content = (jsx(DynamicAuthLayout, { className: className, style: style, projectSettings: projectSettings, children: jsx(RenderView, {}) }));
108
- return (jsx(ShadowDOM, { className: 'embedded-widget', children: jsx(PopperProvider, { children: jsx(SocialRedirectContextProvider, { children: jsx(FooterAnimationContextProvider, { children: jsx(SandboxIndicatorWrapper, { children: background === 'none' ? (content) : (jsx(ModalCard, { border: background === 'with-border', sharpBottomRadiusOnMobile: false, children: content })) }) }) }) }) }));
107
+ return (jsx(ShadowDOM, { className: 'embedded-widget', children: jsx(PopperProvider, { children: jsx(FooterAnimationContextProvider, { children: jsx(SandboxIndicatorWrapper, { children: background === 'none' ? (content) : (jsx(ModalCard, { border: background === 'with-border', sharpBottomRadiusOnMobile: false, children: content })) }) }) }) }));
109
108
  };
110
109
 
111
110
  export { DynamicEmbeddedAuthFlow };