@dynamic-labs/utils 3.0.0-alpha.9 → 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 (73) hide show
  1. package/CHANGELOG.md +620 -0
  2. package/_virtual/_tslib.cjs +15 -0
  3. package/_virtual/_tslib.js +14 -1
  4. package/package.json +5 -4
  5. package/src/cloneObjectWithOverrides/cloneObjectWithOverrides.cjs +37 -0
  6. package/src/cloneObjectWithOverrides/cloneObjectWithOverrides.d.ts +11 -0
  7. package/src/cloneObjectWithOverrides/cloneObjectWithOverrides.js +33 -0
  8. package/src/cloneObjectWithOverrides/index.d.ts +1 -0
  9. package/src/errors/MfaInvalidOtpError.cjs +1 -1
  10. package/src/errors/MfaInvalidOtpError.js +1 -1
  11. package/src/errors/MfaRateLimitedError.cjs +14 -0
  12. package/src/errors/MfaRateLimitedError.d.ts +4 -0
  13. package/src/errors/MfaRateLimitedError.js +10 -0
  14. package/src/errors/NoAccessError.cjs +3 -1
  15. package/src/errors/NoAccessError.d.ts +5 -1
  16. package/src/errors/NoAccessError.js +3 -1
  17. package/src/errors/SandboxMaximumThresholdReachedError.cjs +15 -0
  18. package/src/errors/SandboxMaximumThresholdReachedError.d.ts +5 -0
  19. package/src/errors/SandboxMaximumThresholdReachedError.js +11 -0
  20. package/src/errors/UserRejectedRequestError.cjs +14 -0
  21. package/src/errors/UserRejectedRequestError.d.ts +4 -0
  22. package/src/errors/UserRejectedRequestError.js +10 -0
  23. package/src/errors/WalletAddressMismatchError.cjs +17 -0
  24. package/src/errors/WalletAddressMismatchError.d.ts +11 -0
  25. package/src/errors/WalletAddressMismatchError.js +13 -0
  26. package/src/errors/index.d.ts +4 -0
  27. package/src/handleMobileWalletRedirect/handleMobileWalletRedirect.cjs +0 -6
  28. package/src/handleMobileWalletRedirect/handleMobileWalletRedirect.js +0 -6
  29. package/src/index.cjs +21 -0
  30. package/src/index.d.ts +4 -0
  31. package/src/index.js +11 -1
  32. package/src/isMobile.cjs +11 -0
  33. package/src/isMobile.d.ts +1 -0
  34. package/src/isMobile.js +11 -1
  35. package/src/nativeMobileOauthStateParam.cjs +13 -0
  36. package/src/nativeMobileOauthStateParam.d.ts +14 -0
  37. package/src/nativeMobileOauthStateParam.js +9 -0
  38. package/src/retryableFn.cjs +1 -5
  39. package/src/retryableFn.js +1 -5
  40. package/src/services/FetchService/FetchService.cjs +10 -5
  41. package/src/services/FetchService/FetchService.d.ts +2 -2
  42. package/src/services/FetchService/FetchService.js +10 -5
  43. package/src/services/Oauth2Service/Oauth2Service.cjs +38 -0
  44. package/src/services/Oauth2Service/Oauth2Service.d.ts +41 -0
  45. package/src/services/Oauth2Service/Oauth2Service.js +34 -0
  46. package/src/services/Oauth2Service/createWindowOauth2Service/createWindowOauth2Service.cjs +176 -0
  47. package/src/services/Oauth2Service/createWindowOauth2Service/createWindowOauth2Service.d.ts +2 -0
  48. package/src/services/Oauth2Service/createWindowOauth2Service/createWindowOauth2Service.js +172 -0
  49. package/src/services/Oauth2Service/createWindowOauth2Service/index.d.ts +1 -0
  50. package/src/services/Oauth2Service/index.d.ts +2 -0
  51. package/src/services/Oauth2Service/utils/connectWithAppleId/connectWithAppleId.cjs +26 -0
  52. package/src/services/Oauth2Service/utils/connectWithAppleId/connectWithAppleId.d.ts +7 -0
  53. package/src/services/Oauth2Service/utils/connectWithAppleId/connectWithAppleId.js +22 -0
  54. package/src/services/Oauth2Service/utils/connectWithAppleId/index.d.ts +1 -0
  55. package/src/services/Oauth2Service/utils/loadAppleId/index.d.ts +1 -0
  56. package/src/services/Oauth2Service/utils/loadAppleId/loadAppleId.cjs +34 -0
  57. package/src/services/Oauth2Service/utils/loadAppleId/loadAppleId.d.ts +1 -0
  58. package/src/services/Oauth2Service/utils/loadAppleId/loadAppleId.js +30 -0
  59. package/src/services/PlatformService/PlatformService.cjs +46 -13
  60. package/src/services/PlatformService/PlatformService.d.ts +31 -3
  61. package/src/services/PlatformService/PlatformService.js +46 -13
  62. package/src/services/PlatformService/createBrowserPlatformService/createBrowserPlatformService.cjs +2 -3
  63. package/src/services/PlatformService/createBrowserPlatformService/createBrowserPlatformService.js +2 -3
  64. package/src/services/PlatformService/types.d.ts +11 -4
  65. package/src/services/StorageService/StorageService.cjs +59 -0
  66. package/src/services/StorageService/StorageService.d.ts +30 -0
  67. package/src/services/StorageService/StorageService.js +51 -0
  68. package/src/services/StorageService/createStorageService/createStorageService.cjs +46 -0
  69. package/src/services/StorageService/createStorageService/createStorageService.d.ts +7 -0
  70. package/src/services/StorageService/createStorageService/createStorageService.js +42 -0
  71. package/src/services/StorageService/createStorageService/index.d.ts +1 -0
  72. package/src/services/StorageService/index.d.ts +3 -0
  73. package/src/services/StorageService/types.d.ts +6 -0
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Represents the value that separates the random string from the
3
+ * mobile deeplink URL in the state param from the oauth messages
4
+ * emitted from native mobile apps.
5
+ */
6
+ export declare const nativeMobileOauthStateParam = "_client-redirect:";
7
+ /**
8
+ * Represents the format of the state variable exchanged in oauth2 messages
9
+ * by native mobile devices.
10
+ *
11
+ * It has a random state string followed byt the client redirect URL as configured
12
+ * in the Client.
13
+ */
14
+ export type NativeMobileOauthState = `${string}${typeof nativeMobileOauthStateParam}${string}`;
@@ -0,0 +1,9 @@
1
+ 'use client'
2
+ /**
3
+ * Represents the value that separates the random string from the
4
+ * mobile deeplink URL in the state param from the oauth messages
5
+ * emitted from native mobile apps.
6
+ */
7
+ const nativeMobileOauthStateParam = '_client-redirect:';
8
+
9
+ export { nativeMobileOauthStateParam };
@@ -4,12 +4,7 @@
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
6
  var _tslib = require('../_virtual/_tslib.cjs');
7
- require('./errors/InsufficientFundsError.cjs');
8
- require('./errors/TransactionGasCannotBeSponsoredError.cjs');
9
- require('./logger/logger.cjs');
10
- require('./bufferPolyfill.cjs');
11
7
  var sleep = require('./sleep/sleep.cjs');
12
- require('tldts');
13
8
 
14
9
  const FALLBACK_UNDEFINED = 'FALLBACK_UNDEFINED';
15
10
  const retryableFn = (fn_1, ...args_1) => _tslib.__awaiter(void 0, [fn_1, ...args_1], void 0, function* (fn, options = {}) {
@@ -67,6 +62,7 @@ const retryableFn = (fn_1, ...args_1) => _tslib.__awaiter(void 0, [fn_1, ...args
67
62
  fallbackValue,
68
63
  logger,
69
64
  maxRetries,
65
+ retryIntervalMs,
70
66
  retryStrategy,
71
67
  timeoutMs,
72
68
  });
@@ -1,11 +1,6 @@
1
1
  'use client'
2
2
  import { __awaiter } from '../_virtual/_tslib.js';
3
- import './errors/InsufficientFundsError.js';
4
- import './errors/TransactionGasCannotBeSponsoredError.js';
5
- import './logger/logger.js';
6
- import './bufferPolyfill.js';
7
3
  import { sleep } from './sleep/sleep.js';
8
- import 'tldts';
9
4
 
10
5
  const FALLBACK_UNDEFINED = 'FALLBACK_UNDEFINED';
11
6
  const retryableFn = (fn_1, ...args_1) => __awaiter(void 0, [fn_1, ...args_1], void 0, function* (fn, options = {}) {
@@ -63,6 +58,7 @@ const retryableFn = (fn_1, ...args_1) => __awaiter(void 0, [fn_1, ...args_1], vo
63
58
  fallbackValue,
64
59
  logger,
65
60
  maxRetries,
61
+ retryIntervalMs,
66
62
  retryStrategy,
67
63
  timeoutMs,
68
64
  });
@@ -3,22 +3,27 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
+ var _tslib = require('../../../_virtual/_tslib.cjs');
7
+
8
+ var _a, _FetchService_implementation;
6
9
  /**
7
10
  * Class implementing the fetch service with a configurable fetch implementation.
8
11
  */
9
12
  class FetchService {
10
13
  static get implementation() {
11
- if (!FetchService._implementation) {
14
+ if (!_tslib.__classPrivateFieldGet(_a, _a, "f", _FetchService_implementation)) {
12
15
  return { fetch: window.fetch.bind(window) };
13
16
  }
14
- return FetchService._implementation;
17
+ return _tslib.__classPrivateFieldGet(_a, _a, "f", _FetchService_implementation);
15
18
  }
16
- static setImplementation(implementation) {
17
- FetchService._implementation = implementation;
19
+ static set implementation(implementation) {
20
+ _tslib.__classPrivateFieldSet(_a, _a, implementation, "f", _FetchService_implementation);
18
21
  }
19
22
  static get fetch() {
20
- return FetchService.implementation.fetch;
23
+ return _a.implementation.fetch;
21
24
  }
22
25
  }
26
+ _a = FetchService;
27
+ _FetchService_implementation = { value: void 0 };
23
28
 
24
29
  exports.FetchService = FetchService;
@@ -3,8 +3,8 @@ import { IFetchService } from './types';
3
3
  * Class implementing the fetch service with a configurable fetch implementation.
4
4
  */
5
5
  export declare class FetchService {
6
- static _implementation: IFetchService;
6
+ #private;
7
7
  static get implementation(): IFetchService;
8
- static setImplementation(implementation: IFetchService): void;
8
+ static set implementation(implementation: IFetchService);
9
9
  static get fetch(): (input: RequestInfo, init?: RequestInit | undefined) => Promise<Response>;
10
10
  }
@@ -1,20 +1,25 @@
1
1
  'use client'
2
+ import { __classPrivateFieldGet, __classPrivateFieldSet } from '../../../_virtual/_tslib.js';
3
+
4
+ var _a, _FetchService_implementation;
2
5
  /**
3
6
  * Class implementing the fetch service with a configurable fetch implementation.
4
7
  */
5
8
  class FetchService {
6
9
  static get implementation() {
7
- if (!FetchService._implementation) {
10
+ if (!__classPrivateFieldGet(_a, _a, "f", _FetchService_implementation)) {
8
11
  return { fetch: window.fetch.bind(window) };
9
12
  }
10
- return FetchService._implementation;
13
+ return __classPrivateFieldGet(_a, _a, "f", _FetchService_implementation);
11
14
  }
12
- static setImplementation(implementation) {
13
- FetchService._implementation = implementation;
15
+ static set implementation(implementation) {
16
+ __classPrivateFieldSet(_a, _a, implementation, "f", _FetchService_implementation);
14
17
  }
15
18
  static get fetch() {
16
- return FetchService.implementation.fetch;
19
+ return _a.implementation.fetch;
17
20
  }
18
21
  }
22
+ _a = FetchService;
23
+ _FetchService_implementation = { value: void 0 };
19
24
 
20
25
  export { FetchService };
@@ -0,0 +1,38 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../../../_virtual/_tslib.cjs');
7
+ var types = require('@dynamic-labs/types');
8
+ var createWindowOauth2Service = require('./createWindowOauth2Service/createWindowOauth2Service.cjs');
9
+
10
+ var _a, _Oauth2Service_implementation;
11
+ /**
12
+ * Class implementing the fetch service with a configurable fetch implementation.
13
+ */
14
+ class Oauth2Service {
15
+ static get implementation() {
16
+ if (!_tslib.__classPrivateFieldGet(_a, _a, "f", _Oauth2Service_implementation)) {
17
+ return createWindowOauth2Service.createWindowOauth2Service();
18
+ }
19
+ return _tslib.__classPrivateFieldGet(_a, _a, "f", _Oauth2Service_implementation);
20
+ }
21
+ static set implementation(implementation) {
22
+ _tslib.__classPrivateFieldSet(_a, _a, implementation, "f", _Oauth2Service_implementation);
23
+ }
24
+ static get getOauthCode() {
25
+ return _a.implementation.getOauthCode;
26
+ }
27
+ }
28
+ _a = Oauth2Service;
29
+ _Oauth2Service_implementation = { value: void 0 };
30
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
+ Oauth2Service.isGetOauthCodeError = (error) => error === 'user-cancelled' ||
32
+ (typeof error === 'object' &&
33
+ 'code' in error &&
34
+ Object.values(types.SocialOAuthErrorCode).includes(error.code) &&
35
+ 'message' in error &&
36
+ typeof error.message === 'string');
37
+
38
+ exports.Oauth2Service = Oauth2Service;
@@ -0,0 +1,41 @@
1
+ import { OauthResultResponse, Provider, ProviderEnum } from '@dynamic-labs/sdk-api-core';
2
+ import { SocialOAuthErrorCode } from '@dynamic-labs/types';
3
+ export type GetOauthCodeProps = {
4
+ provider: ProviderEnum;
5
+ apiProvider: Provider | undefined;
6
+ setIsProcessing: (value: boolean) => void;
7
+ onSettled?: VoidFunction;
8
+ getOAuthResultFromApi: () => Promise<OauthResultResponse | undefined>;
9
+ initWebAuth: (options?: {
10
+ redirectUrl?: string;
11
+ }) => Promise<void>;
12
+ state: string;
13
+ oauthLoginUrl: URL;
14
+ /**
15
+ * The preferred strategy to use for the OAuth2 flow.
16
+ */
17
+ strategy: 'popup' | 'redirect';
18
+ sessionTimeout: number;
19
+ /**
20
+ * Overrides the default redirectUrl coming from the DynamicContextProvider
21
+ */
22
+ redirectUrl?: string;
23
+ isMobile?: boolean;
24
+ };
25
+ export type IOauth2Service = {
26
+ getOauthCode: (props: GetOauthCodeProps) => Promise<string>;
27
+ };
28
+ export type GetOauthCodeError = 'user-cancelled' | {
29
+ code: SocialOAuthErrorCode;
30
+ message: string;
31
+ };
32
+ /**
33
+ * Class implementing the fetch service with a configurable fetch implementation.
34
+ */
35
+ export declare class Oauth2Service {
36
+ #private;
37
+ static get implementation(): IOauth2Service;
38
+ static set implementation(implementation: IOauth2Service);
39
+ static get getOauthCode(): (props: GetOauthCodeProps) => Promise<string>;
40
+ static isGetOauthCodeError: (error: any) => error is GetOauthCodeError;
41
+ }
@@ -0,0 +1,34 @@
1
+ 'use client'
2
+ import { __classPrivateFieldGet, __classPrivateFieldSet } from '../../../_virtual/_tslib.js';
3
+ import { SocialOAuthErrorCode } from '@dynamic-labs/types';
4
+ import { createWindowOauth2Service } from './createWindowOauth2Service/createWindowOauth2Service.js';
5
+
6
+ var _a, _Oauth2Service_implementation;
7
+ /**
8
+ * Class implementing the fetch service with a configurable fetch implementation.
9
+ */
10
+ class Oauth2Service {
11
+ static get implementation() {
12
+ if (!__classPrivateFieldGet(_a, _a, "f", _Oauth2Service_implementation)) {
13
+ return createWindowOauth2Service();
14
+ }
15
+ return __classPrivateFieldGet(_a, _a, "f", _Oauth2Service_implementation);
16
+ }
17
+ static set implementation(implementation) {
18
+ __classPrivateFieldSet(_a, _a, implementation, "f", _Oauth2Service_implementation);
19
+ }
20
+ static get getOauthCode() {
21
+ return _a.implementation.getOauthCode;
22
+ }
23
+ }
24
+ _a = Oauth2Service;
25
+ _Oauth2Service_implementation = { value: void 0 };
26
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
+ Oauth2Service.isGetOauthCodeError = (error) => error === 'user-cancelled' ||
28
+ (typeof error === 'object' &&
29
+ 'code' in error &&
30
+ Object.values(SocialOAuthErrorCode).includes(error.code) &&
31
+ 'message' in error &&
32
+ typeof error.message === 'string');
33
+
34
+ export { Oauth2Service };
@@ -0,0 +1,176 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../../../../_virtual/_tslib.cjs');
7
+ var types = require('@dynamic-labs/types');
8
+ var logger = require('../../../logger/logger.cjs');
9
+ var connectWithAppleId = require('../utils/connectWithAppleId/connectWithAppleId.cjs');
10
+ var isMobile = require('../../../isMobile.cjs');
11
+
12
+ let authWindowInterval;
13
+ const createWindowOauth2Service = () => ({
14
+ getOauthCode: ({ apiProvider, provider, redirectUrl, setIsProcessing, state, oauthLoginUrl, initWebAuth, strategy, }) => new Promise((resolve, _reject) => {
15
+ /**
16
+ * Use AppleID SDK for Apple provider on mobile
17
+ * It should use the strategy setting, but on ios or safari
18
+ * it should use the appleId always as it is the best experience
19
+ */
20
+ if (provider === types.ProviderEnum.Apple &&
21
+ (isMobile.isSafariBrowser() || isMobile.isIOS() || strategy === 'redirect')) {
22
+ initWebAuth({
23
+ redirectUrl: redirectUrl || window.location.href,
24
+ }).then(() => connectWithAppleId.connectWithAppleId({
25
+ clientId: apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.clientId,
26
+ oauthLoginUrl,
27
+ state,
28
+ }).catch(_reject));
29
+ return;
30
+ }
31
+ /**
32
+ * Use redirect flow on mobile for all providers except Telegram
33
+ */
34
+ if (strategy === 'redirect' && provider !== types.ProviderEnum.Telegram) {
35
+ initWebAuth({
36
+ redirectUrl: redirectUrl || window.location.href,
37
+ }).then(() => {
38
+ window.location.assign(oauthLoginUrl);
39
+ });
40
+ return;
41
+ }
42
+ // When we catch this error we assume it follows this type, so we must enforce it
43
+ // here to ensure the assumption is correct
44
+ const typedReject = (params) => _reject(params);
45
+ // Clear any potential pending timeouts and intervals
46
+ clearInterval(authWindowInterval);
47
+ const providersWaitingOauthMessage = {};
48
+ const authWindow = window.open('', '_blank', 'width=500,height=600');
49
+ const clearListeners = () => {
50
+ window.removeEventListener('message', handleWindowMessage);
51
+ providersWaitingOauthMessage[provider] = false;
52
+ };
53
+ const handleWindowMessage = (event) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
54
+ const message = event.data;
55
+ const expectedOrigin = getExpectedOrigin(apiProvider);
56
+ if (!expectedOrigin) {
57
+ return;
58
+ }
59
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'origin_check' && authWindow) {
60
+ logger.logger.debug('Origin check message received. Sending response now.', {
61
+ data: message,
62
+ expectedOrigin,
63
+ });
64
+ authWindow.postMessage('origin_check_response', expectedOrigin);
65
+ return;
66
+ }
67
+ const isTelegramCompletedMessage = (message === null || message === void 0 ? void 0 : message.type) === 'telegram_completed';
68
+ const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
69
+ if (isAuthorizationMessage || isTelegramCompletedMessage) {
70
+ logger.logger.debug('Message received', { data: message });
71
+ }
72
+ const isExpectedOrigin = event.origin === expectedOrigin;
73
+ const isValidMessage = ((isAuthorizationMessage && (message === null || message === void 0 ? void 0 : message.provider) === provider) ||
74
+ isTelegramCompletedMessage) &&
75
+ isExpectedOrigin;
76
+ // don't process invalid messages for provider
77
+ if (!isValidMessage) {
78
+ return;
79
+ }
80
+ setIsProcessing(true);
81
+ if (!providersWaitingOauthMessage[provider]) {
82
+ typedReject({
83
+ code: types.SocialOAuthErrorCode.SESSION_TIMEOUT,
84
+ message: `Connecting ${provider} account session timeout.`,
85
+ });
86
+ return;
87
+ }
88
+ clearListeners();
89
+ if (isTelegramCompletedMessage) {
90
+ handleTelegramCompletionMessage(message, state);
91
+ return;
92
+ }
93
+ handleAuthorizationMessage(message, provider, state);
94
+ });
95
+ const getExpectedOrigin = (apiProvider) => {
96
+ if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
97
+ return;
98
+ }
99
+ try {
100
+ const redirectUri = new URL(apiProvider.redirectUrl);
101
+ return redirectUri.origin;
102
+ }
103
+ catch (e) {
104
+ logger.logger.error('Failed to parse social provider redirect url', {
105
+ error: e,
106
+ });
107
+ return;
108
+ }
109
+ };
110
+ const handleTelegramCompletionMessage = (message, state) => {
111
+ logger.logger.debug('Telegram completion message received', {
112
+ data: message,
113
+ });
114
+ const { code, state: authState } = message;
115
+ // check that the state we receive from message is the same state we calculated earlier
116
+ // this could be an attack
117
+ if (state !== authState) {
118
+ typedReject({
119
+ code: types.SocialOAuthErrorCode.OAUTH_ERROR,
120
+ message: 'Failed to connect telegram account: Invalid random state',
121
+ });
122
+ return;
123
+ }
124
+ resolve(code);
125
+ setIsProcessing(false);
126
+ };
127
+ const handleAuthorizationMessage = (message, provider, state) => {
128
+ const { code, error, state: authState } = message;
129
+ if (error && error !== 'undefined') {
130
+ typedReject({
131
+ code: types.SocialOAuthErrorCode.OAUTH_ERROR,
132
+ message: `Failed to connect ${provider} social account: ${error}`,
133
+ });
134
+ return;
135
+ }
136
+ // check that the state we receive from message is the same state we calculated earlier
137
+ // this could be an attack
138
+ // this state check is used only by providers with an open window opener reference (eg, not twitter)
139
+ if (state !== authState) {
140
+ typedReject({
141
+ code: types.SocialOAuthErrorCode.OAUTH_ERROR,
142
+ message: `Failed to connect ${provider} social account: Invalid random state`,
143
+ });
144
+ return;
145
+ }
146
+ if (!code) {
147
+ typedReject({
148
+ code: types.SocialOAuthErrorCode.NO_AUTH_CODE,
149
+ message: `Failed to connect ${provider} social account: no authorization code`,
150
+ });
151
+ return;
152
+ }
153
+ resolve(code);
154
+ setIsProcessing(false);
155
+ };
156
+ if (!providersWaitingOauthMessage[provider]) {
157
+ window.addEventListener('message', handleWindowMessage);
158
+ providersWaitingOauthMessage[provider] = true;
159
+ }
160
+ // First we store the state in backend
161
+ initWebAuth().then(() => {
162
+ authWindow === null || authWindow === void 0 ? void 0 : authWindow.location.assign(oauthLoginUrl);
163
+ authWindowInterval = setInterval(() => {
164
+ if (!(authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed))
165
+ return;
166
+ clearInterval(authWindowInterval);
167
+ setIsProcessing(false);
168
+ // user didn't complete oauth
169
+ if (providersWaitingOauthMessage[provider])
170
+ typedReject('user-cancelled');
171
+ }, 2000);
172
+ });
173
+ }),
174
+ });
175
+
176
+ exports.createWindowOauth2Service = createWindowOauth2Service;
@@ -0,0 +1,2 @@
1
+ import { IOauth2Service } from '../Oauth2Service';
2
+ export declare const createWindowOauth2Service: () => IOauth2Service;
@@ -0,0 +1,172 @@
1
+ 'use client'
2
+ import { __awaiter } from '../../../../_virtual/_tslib.js';
3
+ import { ProviderEnum, SocialOAuthErrorCode } from '@dynamic-labs/types';
4
+ import { logger } from '../../../logger/logger.js';
5
+ import { connectWithAppleId } from '../utils/connectWithAppleId/connectWithAppleId.js';
6
+ import { isSafariBrowser, isIOS } from '../../../isMobile.js';
7
+
8
+ let authWindowInterval;
9
+ const createWindowOauth2Service = () => ({
10
+ getOauthCode: ({ apiProvider, provider, redirectUrl, setIsProcessing, state, oauthLoginUrl, initWebAuth, strategy, }) => new Promise((resolve, _reject) => {
11
+ /**
12
+ * Use AppleID SDK for Apple provider on mobile
13
+ * It should use the strategy setting, but on ios or safari
14
+ * it should use the appleId always as it is the best experience
15
+ */
16
+ if (provider === ProviderEnum.Apple &&
17
+ (isSafariBrowser() || isIOS() || strategy === 'redirect')) {
18
+ initWebAuth({
19
+ redirectUrl: redirectUrl || window.location.href,
20
+ }).then(() => connectWithAppleId({
21
+ clientId: apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.clientId,
22
+ oauthLoginUrl,
23
+ state,
24
+ }).catch(_reject));
25
+ return;
26
+ }
27
+ /**
28
+ * Use redirect flow on mobile for all providers except Telegram
29
+ */
30
+ if (strategy === 'redirect' && provider !== ProviderEnum.Telegram) {
31
+ initWebAuth({
32
+ redirectUrl: redirectUrl || window.location.href,
33
+ }).then(() => {
34
+ window.location.assign(oauthLoginUrl);
35
+ });
36
+ return;
37
+ }
38
+ // When we catch this error we assume it follows this type, so we must enforce it
39
+ // here to ensure the assumption is correct
40
+ const typedReject = (params) => _reject(params);
41
+ // Clear any potential pending timeouts and intervals
42
+ clearInterval(authWindowInterval);
43
+ const providersWaitingOauthMessage = {};
44
+ const authWindow = window.open('', '_blank', 'width=500,height=600');
45
+ const clearListeners = () => {
46
+ window.removeEventListener('message', handleWindowMessage);
47
+ providersWaitingOauthMessage[provider] = false;
48
+ };
49
+ const handleWindowMessage = (event) => __awaiter(void 0, void 0, void 0, function* () {
50
+ const message = event.data;
51
+ const expectedOrigin = getExpectedOrigin(apiProvider);
52
+ if (!expectedOrigin) {
53
+ return;
54
+ }
55
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'origin_check' && authWindow) {
56
+ logger.debug('Origin check message received. Sending response now.', {
57
+ data: message,
58
+ expectedOrigin,
59
+ });
60
+ authWindow.postMessage('origin_check_response', expectedOrigin);
61
+ return;
62
+ }
63
+ const isTelegramCompletedMessage = (message === null || message === void 0 ? void 0 : message.type) === 'telegram_completed';
64
+ const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
65
+ if (isAuthorizationMessage || isTelegramCompletedMessage) {
66
+ logger.debug('Message received', { data: message });
67
+ }
68
+ const isExpectedOrigin = event.origin === expectedOrigin;
69
+ const isValidMessage = ((isAuthorizationMessage && (message === null || message === void 0 ? void 0 : message.provider) === provider) ||
70
+ isTelegramCompletedMessage) &&
71
+ isExpectedOrigin;
72
+ // don't process invalid messages for provider
73
+ if (!isValidMessage) {
74
+ return;
75
+ }
76
+ setIsProcessing(true);
77
+ if (!providersWaitingOauthMessage[provider]) {
78
+ typedReject({
79
+ code: SocialOAuthErrorCode.SESSION_TIMEOUT,
80
+ message: `Connecting ${provider} account session timeout.`,
81
+ });
82
+ return;
83
+ }
84
+ clearListeners();
85
+ if (isTelegramCompletedMessage) {
86
+ handleTelegramCompletionMessage(message, state);
87
+ return;
88
+ }
89
+ handleAuthorizationMessage(message, provider, state);
90
+ });
91
+ const getExpectedOrigin = (apiProvider) => {
92
+ if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
93
+ return;
94
+ }
95
+ try {
96
+ const redirectUri = new URL(apiProvider.redirectUrl);
97
+ return redirectUri.origin;
98
+ }
99
+ catch (e) {
100
+ logger.error('Failed to parse social provider redirect url', {
101
+ error: e,
102
+ });
103
+ return;
104
+ }
105
+ };
106
+ const handleTelegramCompletionMessage = (message, state) => {
107
+ logger.debug('Telegram completion message received', {
108
+ data: message,
109
+ });
110
+ const { code, state: authState } = message;
111
+ // check that the state we receive from message is the same state we calculated earlier
112
+ // this could be an attack
113
+ if (state !== authState) {
114
+ typedReject({
115
+ code: SocialOAuthErrorCode.OAUTH_ERROR,
116
+ message: 'Failed to connect telegram account: Invalid random state',
117
+ });
118
+ return;
119
+ }
120
+ resolve(code);
121
+ setIsProcessing(false);
122
+ };
123
+ const handleAuthorizationMessage = (message, provider, state) => {
124
+ const { code, error, state: authState } = message;
125
+ if (error && error !== 'undefined') {
126
+ typedReject({
127
+ code: SocialOAuthErrorCode.OAUTH_ERROR,
128
+ message: `Failed to connect ${provider} social account: ${error}`,
129
+ });
130
+ return;
131
+ }
132
+ // check that the state we receive from message is the same state we calculated earlier
133
+ // this could be an attack
134
+ // this state check is used only by providers with an open window opener reference (eg, not twitter)
135
+ if (state !== authState) {
136
+ typedReject({
137
+ code: SocialOAuthErrorCode.OAUTH_ERROR,
138
+ message: `Failed to connect ${provider} social account: Invalid random state`,
139
+ });
140
+ return;
141
+ }
142
+ if (!code) {
143
+ typedReject({
144
+ code: SocialOAuthErrorCode.NO_AUTH_CODE,
145
+ message: `Failed to connect ${provider} social account: no authorization code`,
146
+ });
147
+ return;
148
+ }
149
+ resolve(code);
150
+ setIsProcessing(false);
151
+ };
152
+ if (!providersWaitingOauthMessage[provider]) {
153
+ window.addEventListener('message', handleWindowMessage);
154
+ providersWaitingOauthMessage[provider] = true;
155
+ }
156
+ // First we store the state in backend
157
+ initWebAuth().then(() => {
158
+ authWindow === null || authWindow === void 0 ? void 0 : authWindow.location.assign(oauthLoginUrl);
159
+ authWindowInterval = setInterval(() => {
160
+ if (!(authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed))
161
+ return;
162
+ clearInterval(authWindowInterval);
163
+ setIsProcessing(false);
164
+ // user didn't complete oauth
165
+ if (providersWaitingOauthMessage[provider])
166
+ typedReject('user-cancelled');
167
+ }, 2000);
168
+ });
169
+ }),
170
+ });
171
+
172
+ export { createWindowOauth2Service };
@@ -0,0 +1 @@
1
+ export * from './createWindowOauth2Service';
@@ -0,0 +1,2 @@
1
+ export * from './Oauth2Service';
2
+ export * from './createWindowOauth2Service';
@@ -0,0 +1,26 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var _tslib = require('../../../../../_virtual/_tslib.cjs');
7
+ var loadAppleId = require('../loadAppleId/loadAppleId.cjs');
8
+
9
+ const connectWithAppleId = (_a) => _tslib.__awaiter(void 0, [_a], void 0, function* ({ clientId, oauthLoginUrl, state, }) {
10
+ yield loadAppleId.loadAppleId();
11
+ // Because the AppleID is loaded from a script tag, there is not type for it
12
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
13
+ // @ts-ignore
14
+ AppleID.auth.init({
15
+ clientId,
16
+ redirectURI: oauthLoginUrl.searchParams.get('redirect_uri'),
17
+ scope: 'name email',
18
+ state,
19
+ usePopup: false,
20
+ });
21
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
22
+ // @ts-ignore
23
+ AppleID.auth.signIn();
24
+ });
25
+
26
+ exports.connectWithAppleId = connectWithAppleId;
@@ -0,0 +1,7 @@
1
+ type ConnectWithAppleIdOptions = {
2
+ clientId: string | undefined;
3
+ oauthLoginUrl: URL;
4
+ state: string;
5
+ };
6
+ export declare const connectWithAppleId: ({ clientId, oauthLoginUrl, state, }: ConnectWithAppleIdOptions) => Promise<void>;
7
+ export {};