@dynamic-labs/utils 3.0.0-alpha.13 → 3.0.0-alpha.14

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
@@ -1,4 +1,41 @@
1
1
 
2
+ ## [3.0.0-alpha.14](https://github.com/dynamic-labs/DynamicAuth/compare/v3.0.0-alpha.13...v3.0.0-alpha.14) (2024-07-09)
3
+
4
+
5
+ ### ⚠ BREAKING CHANGES
6
+
7
+ * remove setPrimaryWallet in favor of useSwitchWallet (#6212)
8
+ * move getBalance method to wallet so it can be fetched for any wallet not just the active one (#6200)
9
+ * make Wallet a class instead of just a type (#6094)
10
+
11
+ ### Features
12
+
13
+ * add @dynamic-labs/solana-extension ([#6140](https://github.com/dynamic-labs/DynamicAuth/issues/6140)) ([c0e2a06](https://github.com/dynamic-labs/DynamicAuth/commit/c0e2a067dd83163094b58a15696df8654da47c65))
14
+ * add solana support for multi-asset ([#6222](https://github.com/dynamic-labs/DynamicAuth/issues/6222)) ([9660d79](https://github.com/dynamic-labs/DynamicAuth/commit/9660d7962f1fb01011d68397bb367fdfc5335ca9))
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * allow closing re-connect wallet modal ([#6250](https://github.com/dynamic-labs/DynamicAuth/issues/6250)) ([55ba25b](https://github.com/dynamic-labs/DynamicAuth/commit/55ba25bd3e907629aaa26e788885bfa38f8fe350))
20
+ * move getBalance method to wallet so it can be fetched for any wallet not just the active one ([#6200](https://github.com/dynamic-labs/DynamicAuth/issues/6200)) ([ee94773](https://github.com/dynamic-labs/DynamicAuth/commit/ee94773df9b31462a325666760fcf1fc70dec68a))
21
+ * move getNameService method to wallet so name service data can be fetched for any wallet ([#6205](https://github.com/dynamic-labs/DynamicAuth/issues/6205)) ([6671ae9](https://github.com/dynamic-labs/DynamicAuth/commit/6671ae92532ffc1889e24519e75f47d336ac0da6))
22
+ * relax phone number length validation ([#6226](https://github.com/dynamic-labs/DynamicAuth/issues/6226)) ([f0969b4](https://github.com/dynamic-labs/DynamicAuth/commit/f0969b4fbdafde07125cddecb16b4bfd011ea65e))
23
+ * sdkHasLoaded flipping back to false with otp ([#6242](https://github.com/dynamic-labs/DynamicAuth/issues/6242)) ([32ad9dd](https://github.com/dynamic-labs/DynamicAuth/commit/32ad9dd2dae7775f494506773fb343fe1a249c65))
24
+ * send transaction demo undefined address/value ([#6248](https://github.com/dynamic-labs/DynamicAuth/issues/6248)) ([036a511](https://github.com/dynamic-labs/DynamicAuth/commit/036a511fb848ef461edd9b7a5d79d478b0f1cf23))
25
+ * set last active account on accountChange request ([#6218](https://github.com/dynamic-labs/DynamicAuth/issues/6218)) ([05797d2](https://github.com/dynamic-labs/DynamicAuth/commit/05797d292aab8b4de02555594d4d1bbd4c9543eb))
26
+ * show ledger toggle when linking wallet ([#6202](https://github.com/dynamic-labs/DynamicAuth/issues/6202)) ([a449c0b](https://github.com/dynamic-labs/DynamicAuth/commit/a449c0bfc4e3a75ccd7084b930c48fbd6c14f691))
27
+ * show user wallet in profile view on single wallet mode even if it's not primary ([#6187](https://github.com/dynamic-labs/DynamicAuth/issues/6187)) ([ffaaeb2](https://github.com/dynamic-labs/DynamicAuth/commit/ffaaeb2c6cbb2868a381d85451ae5574024156bb))
28
+ * stop auto-switching to connected secondary wallet if primary wallet is not connected ([#6196](https://github.com/dynamic-labs/DynamicAuth/issues/6196)) ([4e8bcd2](https://github.com/dynamic-labs/DynamicAuth/commit/4e8bcd2d02d3fca54a0ed29c45b386ae99266b84))
29
+ * stop coinbase and solflare popups when secondary ([#6225](https://github.com/dynamic-labs/DynamicAuth/issues/6225)) ([7e9c104](https://github.com/dynamic-labs/DynamicAuth/commit/7e9c1049a09c9fd513c9a2a746d6baac916f1bf4))
30
+ * stop sending double sign request on network switch ([e325709](https://github.com/dynamic-labs/DynamicAuth/commit/e325709bb5d2d1331fe16cc705398fc7b1cc292a))
31
+ * tunrkey solana signer accept uint8array message ([#6137](https://github.com/dynamic-labs/DynamicAuth/issues/6137)) ([70f89ce](https://github.com/dynamic-labs/DynamicAuth/commit/70f89ce0dafa4c99b318c9c5adce59083cd6d284))
32
+ * update formatting of phantom bitcoin publickey ([#6210](https://github.com/dynamic-labs/DynamicAuth/issues/6210)) ([f58cea9](https://github.com/dynamic-labs/DynamicAuth/commit/f58cea99333fd7c6af8f56f637ee32f1f7ce8d76))
33
+ * use white color in farcaster qr code when in dark mode ([#6245](https://github.com/dynamic-labs/DynamicAuth/issues/6245)) ([a91958d](https://github.com/dynamic-labs/DynamicAuth/commit/a91958d8773be138da8f54791c4c67866257bbad))
34
+
35
+
36
+ * make Wallet a class instead of just a type ([#6094](https://github.com/dynamic-labs/DynamicAuth/issues/6094)) ([6dc4672](https://github.com/dynamic-labs/DynamicAuth/commit/6dc4672951cfadc22a6c569e74eae3485bd472f3))
37
+ * remove setPrimaryWallet in favor of useSwitchWallet ([#6212](https://github.com/dynamic-labs/DynamicAuth/issues/6212)) ([de125e1](https://github.com/dynamic-labs/DynamicAuth/commit/de125e1ebbc20507e4ec07f337f5f5fd13aabcbe))
38
+
2
39
  ## [3.0.0-alpha.13](https://github.com/dynamic-labs/DynamicAuth/compare/v3.0.0-alpha.12...v3.0.0-alpha.13) (2024-06-27)
3
40
 
4
41
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/utils",
3
- "version": "3.0.0-alpha.13",
3
+ "version": "3.0.0-alpha.14",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/dynamic-labs/dynamic-auth.git",
@@ -28,8 +28,8 @@
28
28
  "dependencies": {
29
29
  "@dynamic-labs/sdk-api-core": "0.0.470",
30
30
  "tldts": "6.0.16",
31
- "@dynamic-labs/logger": "3.0.0-alpha.13",
32
- "@dynamic-labs/types": "3.0.0-alpha.13",
31
+ "@dynamic-labs/logger": "3.0.0-alpha.14",
32
+ "@dynamic-labs/types": "3.0.0-alpha.14",
33
33
  "buffer": "6.0.3",
34
34
  "stream": "0.0.2"
35
35
  },
@@ -0,0 +1,17 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var DynamicError = require('./DynamicError.cjs');
7
+
8
+ class WalletAddressMismatchError extends DynamicError.DynamicError {
9
+ constructor(message, { activeAddress, expectedAddress, walletName, }) {
10
+ super(message, 'wallet_address_mismatch_error');
11
+ this.expectedAddress = expectedAddress;
12
+ this.activeAddress = activeAddress;
13
+ this.walletName = walletName;
14
+ }
15
+ }
16
+
17
+ exports.WalletAddressMismatchError = WalletAddressMismatchError;
@@ -0,0 +1,11 @@
1
+ import { DynamicError } from './DynamicError';
2
+ export declare class WalletAddressMismatchError extends DynamicError {
3
+ expectedAddress: string | undefined;
4
+ activeAddress: string | undefined;
5
+ walletName: string | undefined;
6
+ constructor(message: string, { activeAddress, expectedAddress, walletName, }: {
7
+ activeAddress?: string;
8
+ expectedAddress?: string;
9
+ walletName?: string;
10
+ });
11
+ }
@@ -0,0 +1,13 @@
1
+ 'use client'
2
+ import { DynamicError } from './DynamicError.js';
3
+
4
+ class WalletAddressMismatchError extends DynamicError {
5
+ constructor(message, { activeAddress, expectedAddress, walletName, }) {
6
+ super(message, 'wallet_address_mismatch_error');
7
+ this.expectedAddress = expectedAddress;
8
+ this.activeAddress = activeAddress;
9
+ this.walletName = walletName;
10
+ }
11
+ }
12
+
13
+ export { WalletAddressMismatchError };
@@ -30,3 +30,4 @@ export * from './AccessBlockedError';
30
30
  export * from './EmbeddedWalletException';
31
31
  export * from './MfaInvalidOtpError';
32
32
  export * from './ExternalAuthError';
33
+ export * from './WalletAddressMismatchError';
@@ -10,6 +10,9 @@ var isMobile = require('../isMobile.cjs');
10
10
  require('../../_virtual/_tslib.cjs');
11
11
  require('../bufferPolyfill.cjs');
12
12
  require('tldts');
13
+ require('../services/Oauth2Service/Oauth2Service.cjs');
14
+ require('@dynamic-labs/types');
15
+ require('@dynamic-labs/sdk-api-core');
13
16
 
14
17
  const handleMobileWalletRedirect = ({ nativeLink, universalLink, }) => {
15
18
  const url = encodeURIComponent(window.location.toString());
@@ -6,6 +6,9 @@ import { isSamsungBrowser } from '../isMobile.js';
6
6
  import '../../_virtual/_tslib.js';
7
7
  import '../bufferPolyfill.js';
8
8
  import 'tldts';
9
+ import '../services/Oauth2Service/Oauth2Service.js';
10
+ import '@dynamic-labs/types';
11
+ import '@dynamic-labs/sdk-api-core';
9
12
 
10
13
  const handleMobileWalletRedirect = ({ nativeLink, universalLink, }) => {
11
14
  const url = encodeURIComponent(window.location.toString());
package/src/index.cjs CHANGED
@@ -36,6 +36,7 @@ var AccessBlockedError = require('./errors/AccessBlockedError.cjs');
36
36
  var EmbeddedWalletException = require('./errors/EmbeddedWalletException.cjs');
37
37
  var MfaInvalidOtpError = require('./errors/MfaInvalidOtpError.cjs');
38
38
  var ExternalAuthError = require('./errors/ExternalAuthError.cjs');
39
+ var WalletAddressMismatchError = require('./errors/WalletAddressMismatchError.cjs');
39
40
  var CancellablePromise = require('./CancellablePromise/CancellablePromise.cjs');
40
41
  var isFunction = require('./isFunction/isFunction.cjs');
41
42
  var isMobile = require('./isMobile.cjs');
@@ -60,6 +61,8 @@ var runSafe = require('./runSafe/runSafe.cjs');
60
61
  var PlatformService = require('./services/PlatformService/PlatformService.cjs');
61
62
  var createBrowserPlatformService = require('./services/PlatformService/createBrowserPlatformService/createBrowserPlatformService.cjs');
62
63
  var FetchService = require('./services/FetchService/FetchService.cjs');
64
+ var Oauth2Service = require('./services/Oauth2Service/Oauth2Service.cjs');
65
+ var createWindowOauth2Service = require('./services/Oauth2Service/createWindowOauth2Service/createWindowOauth2Service.cjs');
63
66
  var template = require('./template/template.cjs');
64
67
  var get = require('./get/get.cjs');
65
68
  var hexToString = require('./hexToString/hexToString.cjs');
@@ -100,6 +103,7 @@ exports.AccessBlockedError = AccessBlockedError.AccessBlockedError;
100
103
  exports.EmbeddedWalletException = EmbeddedWalletException.EmbeddedWalletException;
101
104
  exports.MfaInvalidOtpError = MfaInvalidOtpError.MfaInvalidOtpError;
102
105
  exports.ExternalAuthError = ExternalAuthError.ExternalAuthError;
106
+ exports.WalletAddressMismatchError = WalletAddressMismatchError.WalletAddressMismatchError;
103
107
  exports.CancellablePromise = CancellablePromise.CancellablePromise;
104
108
  exports.isFunction = isFunction.isFunction;
105
109
  exports.getAndroidVersion = isMobile.getAndroidVersion;
@@ -137,6 +141,8 @@ exports.runSafe = runSafe.runSafe;
137
141
  exports.PlatformService = PlatformService.PlatformService;
138
142
  exports.createBrowserPlatformService = createBrowserPlatformService.createBrowserPlatformService;
139
143
  exports.FetchService = FetchService.FetchService;
144
+ exports.Oauth2Service = Oauth2Service.Oauth2Service;
145
+ exports.createWindowOauth2Service = createWindowOauth2Service.createWindowOauth2Service;
140
146
  exports.template = template.template;
141
147
  exports.get = get.get;
142
148
  exports.hexToString = hexToString.hexToString;
package/src/index.d.ts CHANGED
@@ -24,6 +24,7 @@ export * from './eip6963';
24
24
  export { runSafe } from './runSafe';
25
25
  export { PlatformService, createBrowserPlatformService, type IPlatformService, } from './services/PlatformService';
26
26
  export { FetchService } from './services/FetchService';
27
+ export { Oauth2Service, type GetOauthCodeError, type GetOauthCodeProps, type IOauth2Service, createWindowOauth2Service, } from './services/Oauth2Service';
27
28
  export { template } from './template';
28
29
  export { get } from './get';
29
30
  export { hexToString } from './hexToString';
package/src/index.js CHANGED
@@ -32,6 +32,7 @@ export { AccessBlockedError } from './errors/AccessBlockedError.js';
32
32
  export { EmbeddedWalletException } from './errors/EmbeddedWalletException.js';
33
33
  export { MfaInvalidOtpError } from './errors/MfaInvalidOtpError.js';
34
34
  export { ExternalAuthError } from './errors/ExternalAuthError.js';
35
+ export { WalletAddressMismatchError } from './errors/WalletAddressMismatchError.js';
35
36
  export { CancellablePromise } from './CancellablePromise/CancellablePromise.js';
36
37
  export { isFunction } from './isFunction/isFunction.js';
37
38
  export { getAndroidVersion, isAndroid, isIOS, isIPad, isIPhone, isIPhone8OrEarlier, isLegacySafari, isMobile, isSamsungBrowser, isWindows } from './isMobile.js';
@@ -56,6 +57,8 @@ export { runSafe } from './runSafe/runSafe.js';
56
57
  export { PlatformService } from './services/PlatformService/PlatformService.js';
57
58
  export { createBrowserPlatformService } from './services/PlatformService/createBrowserPlatformService/createBrowserPlatformService.js';
58
59
  export { FetchService } from './services/FetchService/FetchService.js';
60
+ export { Oauth2Service } from './services/Oauth2Service/Oauth2Service.js';
61
+ export { createWindowOauth2Service } from './services/Oauth2Service/createWindowOauth2Service/createWindowOauth2Service.js';
59
62
  export { template } from './template/template.js';
60
63
  export { get } from './get/get.js';
61
64
  export { hexToString } from './hexToString/hexToString.js';
@@ -10,6 +10,9 @@ require('./logger/logger.cjs');
10
10
  require('./bufferPolyfill.cjs');
11
11
  var sleep = require('./sleep/sleep.cjs');
12
12
  require('tldts');
13
+ require('./services/Oauth2Service/Oauth2Service.cjs');
14
+ require('@dynamic-labs/types');
15
+ require('@dynamic-labs/sdk-api-core');
13
16
 
14
17
  const FALLBACK_UNDEFINED = 'FALLBACK_UNDEFINED';
15
18
  const retryableFn = (fn_1, ...args_1) => _tslib.__awaiter(void 0, [fn_1, ...args_1], void 0, function* (fn, options = {}) {
@@ -6,6 +6,9 @@ import './logger/logger.js';
6
6
  import './bufferPolyfill.js';
7
7
  import { sleep } from './sleep/sleep.js';
8
8
  import 'tldts';
9
+ import './services/Oauth2Service/Oauth2Service.js';
10
+ import '@dynamic-labs/types';
11
+ import '@dynamic-labs/sdk-api-core';
9
12
 
10
13
  const FALLBACK_UNDEFINED = 'FALLBACK_UNDEFINED';
11
14
  const retryableFn = (fn_1, ...args_1) => __awaiter(void 0, [fn_1, ...args_1], void 0, function* (fn, options = {}) {
@@ -0,0 +1,34 @@
1
+ 'use client'
2
+ 'use strict';
3
+
4
+ Object.defineProperty(exports, '__esModule', { value: true });
5
+
6
+ var types = require('@dynamic-labs/types');
7
+ var createWindowOauth2Service = require('./createWindowOauth2Service/createWindowOauth2Service.cjs');
8
+
9
+ /**
10
+ * Class implementing the fetch service with a configurable fetch implementation.
11
+ */
12
+ class Oauth2Service {
13
+ static get implementation() {
14
+ if (!Oauth2Service._implementation) {
15
+ return createWindowOauth2Service.createWindowOauth2Service();
16
+ }
17
+ return Oauth2Service._implementation;
18
+ }
19
+ static setImplementation(implementation) {
20
+ Oauth2Service._implementation = implementation;
21
+ }
22
+ static get getOauthCode() {
23
+ return Oauth2Service.implementation.getOauthCode;
24
+ }
25
+ }
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(types.SocialOAuthErrorCode).includes(error.code) &&
31
+ 'message' in error &&
32
+ typeof error.message === 'string');
33
+
34
+ exports.Oauth2Service = Oauth2Service;
@@ -0,0 +1,30 @@
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
+ state: string;
10
+ oauthLoginUrl: URL;
11
+ sessionTimeout: number;
12
+ isMobile?: boolean;
13
+ };
14
+ export type IOauth2Service = {
15
+ getOauthCode: (props: GetOauthCodeProps) => Promise<string>;
16
+ };
17
+ export type GetOauthCodeError = 'user-cancelled' | {
18
+ code: SocialOAuthErrorCode;
19
+ message: string;
20
+ };
21
+ /**
22
+ * Class implementing the fetch service with a configurable fetch implementation.
23
+ */
24
+ export declare class Oauth2Service {
25
+ static _implementation: IOauth2Service;
26
+ static get implementation(): IOauth2Service;
27
+ static setImplementation(implementation: IOauth2Service): void;
28
+ static get getOauthCode(): (props: GetOauthCodeProps) => Promise<string>;
29
+ static isGetOauthCodeError: (error: any) => error is GetOauthCodeError;
30
+ }
@@ -0,0 +1,30 @@
1
+ 'use client'
2
+ import { SocialOAuthErrorCode } from '@dynamic-labs/types';
3
+ import { createWindowOauth2Service } from './createWindowOauth2Service/createWindowOauth2Service.js';
4
+
5
+ /**
6
+ * Class implementing the fetch service with a configurable fetch implementation.
7
+ */
8
+ class Oauth2Service {
9
+ static get implementation() {
10
+ if (!Oauth2Service._implementation) {
11
+ return createWindowOauth2Service();
12
+ }
13
+ return Oauth2Service._implementation;
14
+ }
15
+ static setImplementation(implementation) {
16
+ Oauth2Service._implementation = implementation;
17
+ }
18
+ static get getOauthCode() {
19
+ return Oauth2Service.implementation.getOauthCode;
20
+ }
21
+ }
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ Oauth2Service.isGetOauthCodeError = (error) => error === 'user-cancelled' ||
24
+ (typeof error === 'object' &&
25
+ 'code' in error &&
26
+ Object.values(SocialOAuthErrorCode).includes(error.code) &&
27
+ 'message' in error &&
28
+ typeof error.message === 'string');
29
+
30
+ export { Oauth2Service };
@@ -0,0 +1,170 @@
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 sdkApiCore = require('@dynamic-labs/sdk-api-core');
9
+ var logger = require('../../../logger/logger.cjs');
10
+
11
+ const providersWithoutWindowOpenerReference = ['twitter'];
12
+ let authWindowInterval;
13
+ const createWindowOauth2Service = () => ({
14
+ getOauthCode: ({ apiProvider, provider, setIsProcessing, state, oauthLoginUrl, getOAuthResultFromApi, sessionTimeout, isMobile, onSettled, }) => new Promise((resolve, _reject) => {
15
+ // When we catch this error we assume it follows this type, so we must enforce it
16
+ // here to ensure the assumption is correct
17
+ const typedReject = (params) => _reject(params);
18
+ // Clear any potential pending timeouts and intervals
19
+ clearInterval(authWindowInterval);
20
+ const providersWaitingOauthMessage = {};
21
+ let shouldPool = false;
22
+ const authWindow = window.open('', '_blank', 'width=500,height=600');
23
+ const clearListeners = () => {
24
+ window.removeEventListener('message', handleWindowMessage);
25
+ providersWaitingOauthMessage[provider] = false;
26
+ };
27
+ const handleWindowMessage = (event) => _tslib.__awaiter(void 0, void 0, void 0, function* () {
28
+ const message = event.data;
29
+ if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
30
+ return;
31
+ }
32
+ let expectedOrigin = window.location.origin;
33
+ if (!providersWithoutWindowOpenerReference.includes(provider)) {
34
+ try {
35
+ const redirectUri = new URL(apiProvider.redirectUrl);
36
+ expectedOrigin = redirectUri.origin;
37
+ }
38
+ catch (e) {
39
+ logger.logger.error('Failed to parse social provider redirect url', {
40
+ error: e,
41
+ });
42
+ return;
43
+ }
44
+ }
45
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'origin_check' && authWindow) {
46
+ logger.logger.debug('Origin check message received. Sending response now.', {
47
+ data: message,
48
+ expectedOrigin,
49
+ });
50
+ authWindow.postMessage('origin_check_response', expectedOrigin);
51
+ return;
52
+ }
53
+ const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
54
+ if (isAuthorizationMessage) {
55
+ logger.logger.debug('Message received', { data: message });
56
+ }
57
+ const isExpectedOrigin = event.origin === expectedOrigin;
58
+ const isValidMessage = isAuthorizationMessage &&
59
+ (message === null || message === void 0 ? void 0 : message.provider) === provider &&
60
+ isExpectedOrigin;
61
+ // don't process invalid messages for provider
62
+ if (!isValidMessage) {
63
+ return;
64
+ }
65
+ setIsProcessing(true);
66
+ if (!providersWaitingOauthMessage[provider]) {
67
+ typedReject({
68
+ code: types.SocialOAuthErrorCode.SESSION_TIMEOUT,
69
+ message: `Connecting ${provider} account session timeout.`,
70
+ });
71
+ return;
72
+ }
73
+ clearListeners();
74
+ const { code, error, state: authState } = message;
75
+ if (error && error !== 'undefined') {
76
+ typedReject({
77
+ code: types.SocialOAuthErrorCode.OAUTH_ERROR,
78
+ message: `Failed to connect ${provider} social account: ${error}`,
79
+ });
80
+ return;
81
+ }
82
+ // check that the state we receive from message is the same state we calculated earlier
83
+ // this could be an attack
84
+ // this state check is used only by providers with an open window opener reference (eg, not twitter)
85
+ if (!providersWithoutWindowOpenerReference.includes(provider) &&
86
+ state !== authState) {
87
+ typedReject({
88
+ code: types.SocialOAuthErrorCode.OAUTH_ERROR,
89
+ message: `Failed to connect ${provider} social account: Invalid random state`,
90
+ });
91
+ return;
92
+ }
93
+ if (!code) {
94
+ typedReject({
95
+ code: types.SocialOAuthErrorCode.NO_AUTH_CODE,
96
+ message: `Failed to connect ${provider} social account: no authorization code`,
97
+ });
98
+ return;
99
+ }
100
+ resolve(code);
101
+ setIsProcessing(false);
102
+ });
103
+ if (!providersWaitingOauthMessage[provider]) {
104
+ window.addEventListener('message', handleWindowMessage);
105
+ providersWaitingOauthMessage[provider] = true;
106
+ }
107
+ authWindow === null || authWindow === void 0 ? void 0 : authWindow.location.assign(oauthLoginUrl);
108
+ if (!providersWithoutWindowOpenerReference.includes(provider)) {
109
+ // For provider that support window.opener, we need to clear all states/listeners when the window is closed
110
+ authWindowInterval = setInterval(() => {
111
+ if (!(authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed))
112
+ return;
113
+ clearInterval(authWindowInterval);
114
+ setIsProcessing(false);
115
+ // user didn't complete oauth
116
+ if (providersWaitingOauthMessage[provider])
117
+ typedReject('user-cancelled');
118
+ }, 2000);
119
+ }
120
+ else {
121
+ // For provider that don't support window.opener, we need to use a timeout to pool the oauth result
122
+ // If we don't get a valid result in {async sessionTimeout} ms, we'll assume the user closed the window
123
+ // and we'll clear all states/listeners
124
+ const poolOauthResult = () => _tslib.__awaiter(void 0, void 0, void 0, function* () {
125
+ if (!shouldPool)
126
+ return;
127
+ const result = yield getOAuthResultFromApi();
128
+ if (!shouldPool)
129
+ return;
130
+ if ((result === null || result === void 0 ? void 0 : result.status) !== sdkApiCore.OauthResultStatus.Completed) {
131
+ authWindowInterval = setTimeout(() => {
132
+ poolOauthResult();
133
+ }, 1000);
134
+ return;
135
+ }
136
+ shouldPool = false;
137
+ const authMessage = {
138
+ code: result === null || result === void 0 ? void 0 : result.code,
139
+ error: result === null || result === void 0 ? void 0 : result.error,
140
+ provider,
141
+ type: 'authorization_response',
142
+ };
143
+ window.postMessage(authMessage, '*');
144
+ });
145
+ // start pooling oauth result
146
+ shouldPool = true;
147
+ poolOauthResult();
148
+ // if this is mobile, set a longer timeout to allow the user to login to the provider in the browser
149
+ let authWindowTimeout = sessionTimeout;
150
+ if (isMobile) {
151
+ authWindowTimeout = authWindowTimeout * 3;
152
+ }
153
+ authWindowInterval = setTimeout(() => _tslib.__awaiter(void 0, void 0, void 0, function* () {
154
+ shouldPool = false;
155
+ // clear all states/listeners, assuming user closed the window before completing oauth
156
+ if (providersWaitingOauthMessage[provider]) {
157
+ clearListeners();
158
+ typedReject({
159
+ code: types.SocialOAuthErrorCode.OAUTH_WINDOW_TIMEOUT,
160
+ message: `Connecting ${provider} account window timeout.`,
161
+ });
162
+ }
163
+ setIsProcessing(false);
164
+ onSettled === null || onSettled === void 0 ? void 0 : onSettled();
165
+ }), authWindowTimeout);
166
+ }
167
+ }),
168
+ });
169
+
170
+ exports.createWindowOauth2Service = createWindowOauth2Service;
@@ -0,0 +1,2 @@
1
+ import { IOauth2Service } from '../Oauth2Service';
2
+ export declare const createWindowOauth2Service: () => IOauth2Service;
@@ -0,0 +1,166 @@
1
+ 'use client'
2
+ import { __awaiter } from '../../../../_virtual/_tslib.js';
3
+ import { SocialOAuthErrorCode } from '@dynamic-labs/types';
4
+ import { OauthResultStatus } from '@dynamic-labs/sdk-api-core';
5
+ import { logger } from '../../../logger/logger.js';
6
+
7
+ const providersWithoutWindowOpenerReference = ['twitter'];
8
+ let authWindowInterval;
9
+ const createWindowOauth2Service = () => ({
10
+ getOauthCode: ({ apiProvider, provider, setIsProcessing, state, oauthLoginUrl, getOAuthResultFromApi, sessionTimeout, isMobile, onSettled, }) => new Promise((resolve, _reject) => {
11
+ // When we catch this error we assume it follows this type, so we must enforce it
12
+ // here to ensure the assumption is correct
13
+ const typedReject = (params) => _reject(params);
14
+ // Clear any potential pending timeouts and intervals
15
+ clearInterval(authWindowInterval);
16
+ const providersWaitingOauthMessage = {};
17
+ let shouldPool = false;
18
+ const authWindow = window.open('', '_blank', 'width=500,height=600');
19
+ const clearListeners = () => {
20
+ window.removeEventListener('message', handleWindowMessage);
21
+ providersWaitingOauthMessage[provider] = false;
22
+ };
23
+ const handleWindowMessage = (event) => __awaiter(void 0, void 0, void 0, function* () {
24
+ const message = event.data;
25
+ if (!(apiProvider === null || apiProvider === void 0 ? void 0 : apiProvider.redirectUrl)) {
26
+ return;
27
+ }
28
+ let expectedOrigin = window.location.origin;
29
+ if (!providersWithoutWindowOpenerReference.includes(provider)) {
30
+ try {
31
+ const redirectUri = new URL(apiProvider.redirectUrl);
32
+ expectedOrigin = redirectUri.origin;
33
+ }
34
+ catch (e) {
35
+ logger.error('Failed to parse social provider redirect url', {
36
+ error: e,
37
+ });
38
+ return;
39
+ }
40
+ }
41
+ if ((message === null || message === void 0 ? void 0 : message.type) === 'origin_check' && authWindow) {
42
+ logger.debug('Origin check message received. Sending response now.', {
43
+ data: message,
44
+ expectedOrigin,
45
+ });
46
+ authWindow.postMessage('origin_check_response', expectedOrigin);
47
+ return;
48
+ }
49
+ const isAuthorizationMessage = (message === null || message === void 0 ? void 0 : message.type) === 'authorization_response';
50
+ if (isAuthorizationMessage) {
51
+ logger.debug('Message received', { data: message });
52
+ }
53
+ const isExpectedOrigin = event.origin === expectedOrigin;
54
+ const isValidMessage = isAuthorizationMessage &&
55
+ (message === null || message === void 0 ? void 0 : message.provider) === provider &&
56
+ isExpectedOrigin;
57
+ // don't process invalid messages for provider
58
+ if (!isValidMessage) {
59
+ return;
60
+ }
61
+ setIsProcessing(true);
62
+ if (!providersWaitingOauthMessage[provider]) {
63
+ typedReject({
64
+ code: SocialOAuthErrorCode.SESSION_TIMEOUT,
65
+ message: `Connecting ${provider} account session timeout.`,
66
+ });
67
+ return;
68
+ }
69
+ clearListeners();
70
+ const { code, error, state: authState } = message;
71
+ if (error && error !== 'undefined') {
72
+ typedReject({
73
+ code: SocialOAuthErrorCode.OAUTH_ERROR,
74
+ message: `Failed to connect ${provider} social account: ${error}`,
75
+ });
76
+ return;
77
+ }
78
+ // check that the state we receive from message is the same state we calculated earlier
79
+ // this could be an attack
80
+ // this state check is used only by providers with an open window opener reference (eg, not twitter)
81
+ if (!providersWithoutWindowOpenerReference.includes(provider) &&
82
+ state !== authState) {
83
+ typedReject({
84
+ code: SocialOAuthErrorCode.OAUTH_ERROR,
85
+ message: `Failed to connect ${provider} social account: Invalid random state`,
86
+ });
87
+ return;
88
+ }
89
+ if (!code) {
90
+ typedReject({
91
+ code: SocialOAuthErrorCode.NO_AUTH_CODE,
92
+ message: `Failed to connect ${provider} social account: no authorization code`,
93
+ });
94
+ return;
95
+ }
96
+ resolve(code);
97
+ setIsProcessing(false);
98
+ });
99
+ if (!providersWaitingOauthMessage[provider]) {
100
+ window.addEventListener('message', handleWindowMessage);
101
+ providersWaitingOauthMessage[provider] = true;
102
+ }
103
+ authWindow === null || authWindow === void 0 ? void 0 : authWindow.location.assign(oauthLoginUrl);
104
+ if (!providersWithoutWindowOpenerReference.includes(provider)) {
105
+ // For provider that support window.opener, we need to clear all states/listeners when the window is closed
106
+ authWindowInterval = setInterval(() => {
107
+ if (!(authWindow === null || authWindow === void 0 ? void 0 : authWindow.closed))
108
+ return;
109
+ clearInterval(authWindowInterval);
110
+ setIsProcessing(false);
111
+ // user didn't complete oauth
112
+ if (providersWaitingOauthMessage[provider])
113
+ typedReject('user-cancelled');
114
+ }, 2000);
115
+ }
116
+ else {
117
+ // For provider that don't support window.opener, we need to use a timeout to pool the oauth result
118
+ // If we don't get a valid result in {async sessionTimeout} ms, we'll assume the user closed the window
119
+ // and we'll clear all states/listeners
120
+ const poolOauthResult = () => __awaiter(void 0, void 0, void 0, function* () {
121
+ if (!shouldPool)
122
+ return;
123
+ const result = yield getOAuthResultFromApi();
124
+ if (!shouldPool)
125
+ return;
126
+ if ((result === null || result === void 0 ? void 0 : result.status) !== OauthResultStatus.Completed) {
127
+ authWindowInterval = setTimeout(() => {
128
+ poolOauthResult();
129
+ }, 1000);
130
+ return;
131
+ }
132
+ shouldPool = false;
133
+ const authMessage = {
134
+ code: result === null || result === void 0 ? void 0 : result.code,
135
+ error: result === null || result === void 0 ? void 0 : result.error,
136
+ provider,
137
+ type: 'authorization_response',
138
+ };
139
+ window.postMessage(authMessage, '*');
140
+ });
141
+ // start pooling oauth result
142
+ shouldPool = true;
143
+ poolOauthResult();
144
+ // if this is mobile, set a longer timeout to allow the user to login to the provider in the browser
145
+ let authWindowTimeout = sessionTimeout;
146
+ if (isMobile) {
147
+ authWindowTimeout = authWindowTimeout * 3;
148
+ }
149
+ authWindowInterval = setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
150
+ shouldPool = false;
151
+ // clear all states/listeners, assuming user closed the window before completing oauth
152
+ if (providersWaitingOauthMessage[provider]) {
153
+ clearListeners();
154
+ typedReject({
155
+ code: SocialOAuthErrorCode.OAUTH_WINDOW_TIMEOUT,
156
+ message: `Connecting ${provider} account window timeout.`,
157
+ });
158
+ }
159
+ setIsProcessing(false);
160
+ onSettled === null || onSettled === void 0 ? void 0 : onSettled();
161
+ }), authWindowTimeout);
162
+ }
163
+ }),
164
+ });
165
+
166
+ export { createWindowOauth2Service };
@@ -0,0 +1 @@
1
+ export * from './createWindowOauth2Service';
@@ -0,0 +1,2 @@
1
+ export * from './Oauth2Service';
2
+ export * from './createWindowOauth2Service';