@turnkey/core 1.0.0-beta.2 → 1.0.0-beta.5
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/dist/__clients__/core.d.ts +92 -9
- package/dist/__clients__/core.d.ts.map +1 -1
- package/dist/__clients__/core.js +699 -535
- package/dist/__clients__/core.js.map +1 -1
- package/dist/__clients__/core.mjs +702 -538
- package/dist/__clients__/core.mjs.map +1 -1
- package/dist/__generated__/sdk-client-base.d.ts +1 -1
- package/dist/__generated__/sdk-client-base.d.ts.map +1 -1
- package/dist/__generated__/sdk-client-base.js +156 -253
- package/dist/__generated__/sdk-client-base.js.map +1 -1
- package/dist/__generated__/sdk-client-base.mjs +156 -253
- package/dist/__generated__/sdk-client-base.mjs.map +1 -1
- package/dist/__generated__/version.d.ts +1 -1
- package/dist/__generated__/version.js +1 -1
- package/dist/__generated__/version.mjs +1 -1
- package/dist/__inputs__/public_api.types.d.ts +377 -504
- package/dist/__inputs__/public_api.types.d.ts.map +1 -1
- package/dist/__types__/base.d.ts +193 -75
- package/dist/__types__/base.d.ts.map +1 -1
- package/dist/__types__/base.js +14 -13
- package/dist/__types__/base.js.map +1 -1
- package/dist/__types__/base.mjs +15 -14
- package/dist/__types__/base.mjs.map +1 -1
- package/dist/__wallet__/base.d.ts +11 -0
- package/dist/__wallet__/base.d.ts.map +1 -1
- package/dist/__wallet__/base.js +12 -1
- package/dist/__wallet__/base.js.map +1 -1
- package/dist/__wallet__/base.mjs +12 -1
- package/dist/__wallet__/base.mjs.map +1 -1
- package/dist/__wallet__/connector.d.ts +31 -4
- package/dist/__wallet__/connector.d.ts.map +1 -1
- package/dist/__wallet__/connector.js +35 -5
- package/dist/__wallet__/connector.js.map +1 -1
- package/dist/__wallet__/connector.mjs +35 -5
- package/dist/__wallet__/connector.mjs.map +1 -1
- package/dist/__wallet__/mobile/manager.d.ts +21 -5
- package/dist/__wallet__/mobile/manager.d.ts.map +1 -1
- package/dist/__wallet__/mobile/manager.js +28 -11
- package/dist/__wallet__/mobile/manager.js.map +1 -1
- package/dist/__wallet__/mobile/manager.mjs +28 -11
- package/dist/__wallet__/mobile/manager.mjs.map +1 -1
- package/dist/__wallet__/stamper.d.ts +73 -2
- package/dist/__wallet__/stamper.d.ts.map +1 -1
- package/dist/__wallet__/stamper.js +81 -15
- package/dist/__wallet__/stamper.js.map +1 -1
- package/dist/__wallet__/stamper.mjs +82 -16
- package/dist/__wallet__/stamper.mjs.map +1 -1
- package/dist/__wallet__/wallet-connect/base.d.ts +102 -19
- package/dist/__wallet__/wallet-connect/base.d.ts.map +1 -1
- package/dist/__wallet__/wallet-connect/base.js +198 -77
- package/dist/__wallet__/wallet-connect/base.js.map +1 -1
- package/dist/__wallet__/wallet-connect/base.mjs +198 -77
- package/dist/__wallet__/wallet-connect/base.mjs.map +1 -1
- package/dist/__wallet__/wallet-connect/client.d.ts +50 -17
- package/dist/__wallet__/wallet-connect/client.d.ts.map +1 -1
- package/dist/__wallet__/wallet-connect/client.js +76 -19
- package/dist/__wallet__/wallet-connect/client.js.map +1 -1
- package/dist/__wallet__/wallet-connect/client.mjs +76 -19
- package/dist/__wallet__/wallet-connect/client.mjs.map +1 -1
- package/dist/__wallet__/web/manager.d.ts +20 -12
- package/dist/__wallet__/web/manager.d.ts.map +1 -1
- package/dist/__wallet__/web/manager.js +29 -21
- package/dist/__wallet__/web/manager.js.map +1 -1
- package/dist/__wallet__/web/manager.mjs +29 -21
- package/dist/__wallet__/web/manager.mjs.map +1 -1
- package/dist/__wallet__/web/native/ethereum.d.ts +45 -11
- package/dist/__wallet__/web/native/ethereum.d.ts.map +1 -1
- package/dist/__wallet__/web/native/ethereum.js +58 -17
- package/dist/__wallet__/web/native/ethereum.js.map +1 -1
- package/dist/__wallet__/web/native/ethereum.mjs +58 -17
- package/dist/__wallet__/web/native/ethereum.mjs.map +1 -1
- package/dist/__wallet__/web/native/solana.d.ts +56 -3
- package/dist/__wallet__/web/native/solana.d.ts.map +1 -1
- package/dist/__wallet__/web/native/solana.js +95 -36
- package/dist/__wallet__/web/native/solana.js.map +1 -1
- package/dist/__wallet__/web/native/solana.mjs +95 -36
- package/dist/__wallet__/web/native/solana.mjs.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -10
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/utils.d.ts +59 -13
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +105 -30
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +103 -29
- package/dist/utils.mjs.map +1 -1
- package/package.json +8 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TurnkeySDKClientBase } from '../__generated__/sdk-client-base.mjs';
|
|
2
|
-
import {
|
|
3
|
-
import { SessionKey, DEFAULT_SESSION_EXPIRATION_IN_SECONDS, StamperType, Chain, FilterType, OtpTypeToFilterTypeMap,
|
|
4
|
-
import { isWeb, isReactNative, buildSignUpBody,
|
|
2
|
+
import { TurnkeyErrorCodes, TurnkeyError, TurnkeyNetworkError } from '@turnkey/sdk-types';
|
|
3
|
+
import { SessionKey, DEFAULT_SESSION_EXPIRATION_IN_SECONDS, StamperType, WalletSource, Chain, FilterType, OtpTypeToFilterTypeMap, OtpType, Curve, SignIntent } from '../__types__/base.mjs';
|
|
4
|
+
import { withTurnkeyErrorHandling, isWeb, isReactNative, buildSignUpBody, findWalletProviderFromAddress, isEthereumProvider, getPublicKeyFromStampHeader, toExternalTimestamp, isSolanaProvider, getHashFunction, getEncodingType, getEncodedMessage, splitSignature, broadcastTransaction, googleISS, isWalletAccountArray, generateWalletAccountsFromAddressFormat } from '../utils.mjs';
|
|
5
5
|
import { createStorageManager } from '../__storage__/base.mjs';
|
|
6
6
|
import { CrossPlatformApiKeyStamper } from '../__stampers__/api/base.mjs';
|
|
7
7
|
import { CrossPlatformPasskeyStamper } from '../__stampers__/passkey/base.mjs';
|
|
@@ -30,7 +30,7 @@ class TurnkeyClient {
|
|
|
30
30
|
* @throws {TurnkeyError} If there is an error during passkey creation, or if the platform is unsupported.
|
|
31
31
|
*/
|
|
32
32
|
this.createPasskey = async (params) => {
|
|
33
|
-
|
|
33
|
+
return withTurnkeyErrorHandling(async () => {
|
|
34
34
|
const name = params?.name || "A Passkey";
|
|
35
35
|
const displayName = params?.displayName || "A Passkey";
|
|
36
36
|
let passkey;
|
|
@@ -68,16 +68,16 @@ class TurnkeyClient {
|
|
|
68
68
|
throw new TurnkeyError("Unsupported platform for passkey creation", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
69
69
|
}
|
|
70
70
|
return passkey;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
71
|
+
}, {
|
|
72
|
+
errorMessage: "Failed to create passkey",
|
|
73
|
+
errorCode: TurnkeyErrorCodes.CREATE_PASSKEY_ERROR,
|
|
74
|
+
customMessageByMessages: {
|
|
75
|
+
"timed out or was not allowed": {
|
|
76
|
+
message: "Passkey creation was cancelled by the user.",
|
|
77
|
+
code: TurnkeyErrorCodes.SELECT_PASSKEY_CANCELLED,
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
81
|
};
|
|
82
82
|
/**
|
|
83
83
|
* Logs out the current client session.
|
|
@@ -91,7 +91,7 @@ class TurnkeyClient {
|
|
|
91
91
|
* @throws {TurnkeyError} If there is no active session or if there is an error during the logout process.
|
|
92
92
|
*/
|
|
93
93
|
this.logout = async (params) => {
|
|
94
|
-
|
|
94
|
+
withTurnkeyErrorHandling(async () => {
|
|
95
95
|
if (params?.sessionKey) {
|
|
96
96
|
const session = await this.storageManager.getSession(params.sessionKey);
|
|
97
97
|
this.storageManager.clearSession(params.sessionKey);
|
|
@@ -108,12 +108,10 @@ class TurnkeyClient {
|
|
|
108
108
|
throw new TurnkeyError("No active session found to log out from.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
throw new TurnkeyError(`Failed to log out`, TurnkeyErrorCodes.LOGOUT_ERROR, error);
|
|
116
|
-
}
|
|
111
|
+
}, {
|
|
112
|
+
errorMessage: "Failed to log out",
|
|
113
|
+
errorCode: TurnkeyErrorCodes.LOGOUT_ERROR,
|
|
114
|
+
});
|
|
117
115
|
};
|
|
118
116
|
/**
|
|
119
117
|
* Logs in a user using a passkey, optionally specifying the public key, session key, and session expiration.
|
|
@@ -131,16 +129,17 @@ class TurnkeyClient {
|
|
|
131
129
|
* @throws {TurnkeyError} If there is an error during the passkey login process or if the user cancels the passkey prompt.
|
|
132
130
|
*/
|
|
133
131
|
this.loginWithPasskey = async (params) => {
|
|
134
|
-
let generatedKeyPair =
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
let generatedKeyPair = undefined;
|
|
133
|
+
return await withTurnkeyErrorHandling(async () => {
|
|
134
|
+
generatedKeyPair =
|
|
135
|
+
params?.publicKey || (await this.apiKeyStamper?.createKeyPair());
|
|
137
136
|
const sessionKey = params?.sessionKey || SessionKey.DefaultSessionkey;
|
|
138
137
|
const expirationSeconds = params?.expirationSeconds || DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
139
|
-
if (!
|
|
138
|
+
if (!generatedKeyPair) {
|
|
140
139
|
throw new TurnkeyError("A publickey could not be found or generated.", TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
141
140
|
}
|
|
142
141
|
const sessionResponse = await this.httpClient.stampLogin({
|
|
143
|
-
publicKey,
|
|
142
|
+
publicKey: generatedKeyPair,
|
|
144
143
|
organizationId: this.config.organizationId,
|
|
145
144
|
expirationSeconds,
|
|
146
145
|
}, StamperType.Passkey);
|
|
@@ -148,28 +147,29 @@ class TurnkeyClient {
|
|
|
148
147
|
sessionToken: sessionResponse.session,
|
|
149
148
|
sessionKey,
|
|
150
149
|
});
|
|
151
|
-
// Key pair was successfully used, set to null to prevent cleanup
|
|
152
|
-
generatedKeyPair = null;
|
|
150
|
+
generatedKeyPair = undefined; // Key pair was successfully used, set to null to prevent cleanup
|
|
153
151
|
return sessionResponse.session;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
152
|
+
}, {
|
|
153
|
+
errorMessage: "Unable to log in with the provided passkey",
|
|
154
|
+
errorCode: TurnkeyErrorCodes.PASSKEY_LOGIN_AUTH_ERROR,
|
|
155
|
+
customMessageByMessages: {
|
|
156
|
+
"timed out or was not allowed": {
|
|
157
|
+
message: "Passkey login was cancelled by the user.",
|
|
158
|
+
code: TurnkeyErrorCodes.SELECT_PASSKEY_CANCELLED,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
}, {
|
|
162
|
+
finallyFn: async () => {
|
|
163
|
+
if (generatedKeyPair) {
|
|
164
|
+
try {
|
|
165
|
+
await this.apiKeyStamper?.deleteKeyPair(generatedKeyPair);
|
|
166
|
+
}
|
|
167
|
+
catch (cleanupError) {
|
|
168
|
+
throw new TurnkeyError(`Failed to clean up generated key pair`, TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
169
|
+
}
|
|
170
170
|
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
173
|
};
|
|
174
174
|
/**
|
|
175
175
|
* Signs up a user using a passkey, creating a new sub-organization and session.
|
|
@@ -189,8 +189,8 @@ class TurnkeyClient {
|
|
|
189
189
|
*/
|
|
190
190
|
this.signUpWithPasskey = async (params) => {
|
|
191
191
|
const { createSubOrgParams, passkeyDisplayName, sessionKey = SessionKey.DefaultSessionkey, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, } = params || {};
|
|
192
|
-
let generatedKeyPair =
|
|
193
|
-
|
|
192
|
+
let generatedKeyPair = undefined;
|
|
193
|
+
return withTurnkeyErrorHandling(async () => {
|
|
194
194
|
generatedKeyPair = await this.apiKeyStamper?.createKeyPair();
|
|
195
195
|
const passkeyName = passkeyDisplayName || `passkey-${Date.now()}`;
|
|
196
196
|
// A passkey will be created automatically when you call this function. The name is passed in
|
|
@@ -239,26 +239,24 @@ class TurnkeyClient {
|
|
|
239
239
|
sessionToken: sessionResponse.session,
|
|
240
240
|
sessionKey,
|
|
241
241
|
});
|
|
242
|
-
generatedKeyPair =
|
|
242
|
+
generatedKeyPair = undefined; // Key pair was successfully used, set to null to prevent cleanup
|
|
243
243
|
return sessionResponse.session;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
catch (cleanupError) {
|
|
258
|
-
throw new TurnkeyError(`Failed to clean up generated key pair`, TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
244
|
+
}, {
|
|
245
|
+
errorCode: TurnkeyErrorCodes.PASSKEY_SIGNUP_AUTH_ERROR,
|
|
246
|
+
errorMessage: "Failed to sign up with passkey",
|
|
247
|
+
}, {
|
|
248
|
+
finallyFn: async () => {
|
|
249
|
+
this.apiKeyStamper?.clearPublicKeyOverride();
|
|
250
|
+
if (generatedKeyPair) {
|
|
251
|
+
try {
|
|
252
|
+
await this.apiKeyStamper?.deleteKeyPair(generatedKeyPair);
|
|
253
|
+
}
|
|
254
|
+
catch (cleanupError) {
|
|
255
|
+
throw new TurnkeyError(`Failed to clean up generated key pair`, TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
256
|
+
}
|
|
259
257
|
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
258
|
+
},
|
|
259
|
+
});
|
|
262
260
|
};
|
|
263
261
|
/**
|
|
264
262
|
* Retrieves wallet providers from the initialized wallet manager.
|
|
@@ -271,15 +269,15 @@ class TurnkeyClient {
|
|
|
271
269
|
* @throws {TurnkeyError} If the wallet manager is uninitialized or provider retrieval fails.
|
|
272
270
|
*/
|
|
273
271
|
this.getWalletProviders = async (chain) => {
|
|
274
|
-
|
|
272
|
+
return withTurnkeyErrorHandling(async () => {
|
|
275
273
|
if (!this.walletManager) {
|
|
276
274
|
throw new TurnkeyError("Wallet manager is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
277
275
|
}
|
|
278
276
|
return await this.walletManager.getProviders(chain);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
277
|
+
}, {
|
|
278
|
+
errorMessage: "Unable to get wallet providers",
|
|
279
|
+
errorCode: TurnkeyErrorCodes.FETCH_WALLETS_ERROR,
|
|
280
|
+
});
|
|
283
281
|
};
|
|
284
282
|
/**
|
|
285
283
|
* Connects the specified wallet account.
|
|
@@ -291,15 +289,15 @@ class TurnkeyClient {
|
|
|
291
289
|
* @throws {TurnkeyError} If the wallet manager is uninitialized or the connection fails.
|
|
292
290
|
*/
|
|
293
291
|
this.connectWalletAccount = async (walletProvider) => {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
292
|
+
return withTurnkeyErrorHandling(async () => {
|
|
293
|
+
if (!this.walletManager?.connector) {
|
|
294
|
+
throw new TurnkeyError("Wallet connector is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
295
|
+
}
|
|
298
296
|
await this.walletManager.connector.connectWalletAccount(walletProvider);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
}
|
|
297
|
+
}, {
|
|
298
|
+
errorMessage: "Unable to connect wallet account",
|
|
299
|
+
errorCode: TurnkeyErrorCodes.CONNECT_WALLET_ACCOUNT_ERROR,
|
|
300
|
+
});
|
|
303
301
|
};
|
|
304
302
|
/**
|
|
305
303
|
* Disconnects the specified wallet account.
|
|
@@ -311,45 +309,55 @@ class TurnkeyClient {
|
|
|
311
309
|
* @throws {TurnkeyError} If the wallet manager is uninitialized or the disconnection fails.
|
|
312
310
|
*/
|
|
313
311
|
this.disconnectWalletAccount = async (walletProvider) => {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
312
|
+
return withTurnkeyErrorHandling(async () => {
|
|
313
|
+
if (!this.walletManager?.connector) {
|
|
314
|
+
throw new TurnkeyError("Wallet connector is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
315
|
+
}
|
|
318
316
|
await this.walletManager.connector.disconnectWalletAccount(walletProvider);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
317
|
+
}, {
|
|
318
|
+
errorMessage: "Unable to disconnect wallet account",
|
|
319
|
+
errorCode: TurnkeyErrorCodes.DISCONNECT_WALLET_ACCOUNT_ERROR,
|
|
320
|
+
});
|
|
323
321
|
};
|
|
324
322
|
/**
|
|
325
|
-
* Switches the
|
|
323
|
+
* Switches the wallet provider associated with a given wallet account
|
|
324
|
+
* to a different chain.
|
|
326
325
|
*
|
|
327
|
-
* - Requires the wallet manager and its connector to be initialized
|
|
328
|
-
* -
|
|
329
|
-
* -
|
|
326
|
+
* - Requires the wallet manager and its connector to be initialized
|
|
327
|
+
* - Only works for connected wallet accounts
|
|
328
|
+
* - Looks up the provider for the given account address
|
|
329
|
+
* - Does nothing if the provider is already on the desired chain.
|
|
330
330
|
*
|
|
331
|
-
* @param
|
|
332
|
-
* @param chainOrId - target chain as a chain ID string or SwitchableChain object.
|
|
331
|
+
* @param params.walletAccount - The wallet account whose provider should be switched.
|
|
332
|
+
* @param params.chainOrId - The target chain, specified as a chain ID string or a SwitchableChain object.
|
|
333
|
+
* @param params.walletProviders - Optional list of wallet providers to search; falls back to `getWalletProviders()` if omitted.
|
|
333
334
|
* @returns A promise that resolves once the chain switch is complete.
|
|
335
|
+
*
|
|
334
336
|
* @throws {TurnkeyError} If the wallet manager is uninitialized, the provider is not connected, or the switch fails.
|
|
335
337
|
*/
|
|
336
|
-
this.
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
338
|
+
this.switchWalletAccountChain = async (params) => {
|
|
339
|
+
const { walletAccount, chainOrId, walletProviders } = params;
|
|
340
|
+
return withTurnkeyErrorHandling(async () => {
|
|
341
|
+
if (!this.walletManager?.connector) {
|
|
342
|
+
throw new TurnkeyError("Wallet connector is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
343
|
+
}
|
|
344
|
+
if (walletAccount.source === WalletSource.Embedded) {
|
|
345
|
+
throw new TurnkeyError("You can only switch chains for connected wallet accounts", TurnkeyErrorCodes.NOT_FOUND);
|
|
346
|
+
}
|
|
347
|
+
const providers = walletProviders ?? (await this.getWalletProviders());
|
|
348
|
+
const walletProvider = findWalletProviderFromAddress(walletAccount.address, providers);
|
|
349
|
+
if (!walletProvider) {
|
|
350
|
+
throw new TurnkeyError("Wallet provider not found", TurnkeyErrorCodes.SWITCH_WALLET_CHAIN_ERROR);
|
|
351
|
+
}
|
|
352
|
+
// if the wallet provider is already on the desired chain, do nothing
|
|
353
|
+
if (walletProvider.chainInfo.namespace === chainOrId) {
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
348
356
|
await this.walletManager.connector.switchChain(walletProvider, chainOrId);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
357
|
+
}, {
|
|
358
|
+
errorMessage: "Unable to switch wallet account chain",
|
|
359
|
+
errorCode: TurnkeyErrorCodes.SWITCH_WALLET_CHAIN_ERROR,
|
|
360
|
+
});
|
|
353
361
|
};
|
|
354
362
|
/**
|
|
355
363
|
* Logs in a user using the specified wallet provider.
|
|
@@ -368,11 +376,11 @@ class TurnkeyClient {
|
|
|
368
376
|
* @throws {TurnkeyError} If the wallet stamper is uninitialized, a public key cannot be found or generated, or login fails.
|
|
369
377
|
*/
|
|
370
378
|
this.loginWithWallet = async (params) => {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
379
|
+
let publicKey = params.publicKey || (await this.apiKeyStamper?.createKeyPair());
|
|
380
|
+
return withTurnkeyErrorHandling(async () => {
|
|
381
|
+
if (!this.walletManager?.stamper) {
|
|
382
|
+
throw new TurnkeyError("Wallet stamper is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
383
|
+
}
|
|
376
384
|
const sessionKey = params.sessionKey || SessionKey.DefaultSessionkey;
|
|
377
385
|
const walletProvider = params.walletProvider;
|
|
378
386
|
const expirationSeconds = params?.expirationSeconds || DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
@@ -390,12 +398,23 @@ class TurnkeyClient {
|
|
|
390
398
|
sessionKey,
|
|
391
399
|
});
|
|
392
400
|
return sessionResponse.session;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
401
|
+
}, {
|
|
402
|
+
errorMessage: "Unable to log in with the provided wallet",
|
|
403
|
+
errorCode: TurnkeyErrorCodes.WALLET_LOGIN_AUTH_ERROR,
|
|
404
|
+
}, {
|
|
405
|
+
finallyFn: async () => {
|
|
406
|
+
// Clean up the generated key pair if it wasn't successfully used
|
|
407
|
+
this.apiKeyStamper?.clearPublicKeyOverride();
|
|
408
|
+
if (publicKey) {
|
|
409
|
+
try {
|
|
410
|
+
await this.apiKeyStamper?.deleteKeyPair(publicKey);
|
|
411
|
+
}
|
|
412
|
+
catch (cleanupError) {
|
|
413
|
+
throw new TurnkeyError("Failed to clean up generated key pair", TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
});
|
|
399
418
|
};
|
|
400
419
|
/**
|
|
401
420
|
* Signs up a user using a wallet, creating a new sub-organization and session.
|
|
@@ -415,11 +434,11 @@ class TurnkeyClient {
|
|
|
415
434
|
*/
|
|
416
435
|
this.signUpWithWallet = async (params) => {
|
|
417
436
|
const { walletProvider, createSubOrgParams, sessionKey = SessionKey.DefaultSessionkey, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, } = params;
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
437
|
+
let generatedKeyPair = undefined;
|
|
438
|
+
return withTurnkeyErrorHandling(async () => {
|
|
439
|
+
if (!this.walletManager?.stamper) {
|
|
440
|
+
throw new TurnkeyError("Wallet stamper is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
441
|
+
}
|
|
423
442
|
generatedKeyPair = await this.apiKeyStamper?.createKeyPair();
|
|
424
443
|
this.walletManager.stamper.setProvider(walletProvider.interfaceType, walletProvider);
|
|
425
444
|
const publicKey = await this.walletManager.stamper.getPublicKey(walletProvider.interfaceType, walletProvider);
|
|
@@ -433,7 +452,7 @@ class TurnkeyClient {
|
|
|
433
452
|
{
|
|
434
453
|
apiKeyName: `wallet-auth:${publicKey}`,
|
|
435
454
|
publicKey: publicKey,
|
|
436
|
-
curveType:
|
|
455
|
+
curveType: isEthereumProvider(walletProvider)
|
|
437
456
|
? "API_KEY_CURVE_SECP256K1"
|
|
438
457
|
: "API_KEY_CURVE_ED25519",
|
|
439
458
|
},
|
|
@@ -462,24 +481,25 @@ class TurnkeyClient {
|
|
|
462
481
|
sessionToken: sessionResponse.session,
|
|
463
482
|
sessionKey,
|
|
464
483
|
});
|
|
465
|
-
generatedKeyPair =
|
|
484
|
+
generatedKeyPair = undefined; // Key pair was successfully used, set to null to prevent cleanup
|
|
466
485
|
return sessionResponse.session;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
486
|
+
}, {
|
|
487
|
+
errorMessage: "Failed to sign up with wallet",
|
|
488
|
+
errorCode: TurnkeyErrorCodes.WALLET_SIGNUP_AUTH_ERROR,
|
|
489
|
+
}, {
|
|
490
|
+
finallyFn: async () => {
|
|
491
|
+
// Clean up the generated key pair if it wasn't successfully used
|
|
492
|
+
this.apiKeyStamper?.clearPublicKeyOverride();
|
|
493
|
+
if (generatedKeyPair) {
|
|
494
|
+
try {
|
|
495
|
+
await this.apiKeyStamper?.deleteKeyPair(generatedKeyPair);
|
|
496
|
+
}
|
|
497
|
+
catch (cleanupError) {
|
|
498
|
+
throw new TurnkeyError("Failed to clean up generated key pair", TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
499
|
+
}
|
|
480
500
|
}
|
|
481
|
-
}
|
|
482
|
-
}
|
|
501
|
+
},
|
|
502
|
+
});
|
|
483
503
|
};
|
|
484
504
|
/**
|
|
485
505
|
* Logs in an existing user or signs up a new user using a wallet, creating a new sub-organization if needed.
|
|
@@ -499,25 +519,36 @@ class TurnkeyClient {
|
|
|
499
519
|
* @throws {TurnkeyError} If there is an error during wallet authentication, sub-organization creation, or session storage.
|
|
500
520
|
*/
|
|
501
521
|
this.loginOrSignupWithWallet = async (params) => {
|
|
502
|
-
if (!this.walletManager?.stamper) {
|
|
503
|
-
throw new TurnkeyError("Wallet stamper is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
504
|
-
}
|
|
505
522
|
const createSubOrgParams = params.createSubOrgParams;
|
|
506
523
|
const sessionKey = params.sessionKey || SessionKey.DefaultSessionkey;
|
|
507
524
|
const walletProvider = params.walletProvider;
|
|
508
525
|
const expirationSeconds = params.expirationSeconds || DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
509
|
-
let generatedKeyPair =
|
|
510
|
-
|
|
526
|
+
let generatedKeyPair = undefined;
|
|
527
|
+
return withTurnkeyErrorHandling(async () => {
|
|
528
|
+
if (!this.walletManager?.stamper) {
|
|
529
|
+
throw new TurnkeyError("Wallet stamper is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
530
|
+
}
|
|
511
531
|
generatedKeyPair = await this.apiKeyStamper?.createKeyPair();
|
|
512
532
|
this.walletManager.stamper.setProvider(walletProvider.interfaceType, walletProvider);
|
|
513
533
|
// here we sign the request with the wallet, but we don't send it to the Turnkey yet
|
|
514
534
|
// this is because we need to check if the subOrg exists first, and create one if it doesn't
|
|
515
535
|
// once we have the subOrg for the publicKey, we then can send the request to the Turnkey
|
|
516
|
-
const signedRequest = await
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
536
|
+
const signedRequest = await withTurnkeyErrorHandling(async () => {
|
|
537
|
+
return this.httpClient.stampStampLogin({
|
|
538
|
+
publicKey: generatedKeyPair,
|
|
539
|
+
organizationId: this.config.organizationId,
|
|
540
|
+
expirationSeconds,
|
|
541
|
+
}, StamperType.Wallet);
|
|
542
|
+
}, {
|
|
543
|
+
errorMessage: "Failed to create stamped request for wallet login",
|
|
544
|
+
errorCode: TurnkeyErrorCodes.WALLET_LOGIN_OR_SIGNUP_ERROR,
|
|
545
|
+
customMessageByMessages: {
|
|
546
|
+
"Failed to sign the message": {
|
|
547
|
+
message: "Wallet auth was cancelled by the user.",
|
|
548
|
+
code: TurnkeyErrorCodes.CONNECT_WALLET_CANCELLED,
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
});
|
|
521
552
|
if (!signedRequest) {
|
|
522
553
|
throw new TurnkeyError("Failed to create stamped request for wallet login", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
523
554
|
}
|
|
@@ -559,7 +590,7 @@ class TurnkeyClient {
|
|
|
559
590
|
{
|
|
560
591
|
apiKeyName: `wallet-auth:${publicKey}`,
|
|
561
592
|
publicKey: publicKey,
|
|
562
|
-
curveType:
|
|
593
|
+
curveType: isEthereumProvider(walletProvider)
|
|
563
594
|
? "API_KEY_CURVE_SECP256K1"
|
|
564
595
|
: "API_KEY_CURVE_ED25519",
|
|
565
596
|
},
|
|
@@ -595,10 +626,20 @@ class TurnkeyClient {
|
|
|
595
626
|
sessionKey,
|
|
596
627
|
});
|
|
597
628
|
return sessionToken;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
629
|
+
}, {
|
|
630
|
+
errorCode: TurnkeyErrorCodes.WALLET_LOGIN_OR_SIGNUP_ERROR,
|
|
631
|
+
errorMessage: "Failed to log in or sign up with wallet",
|
|
632
|
+
catchFn: async () => {
|
|
633
|
+
if (generatedKeyPair) {
|
|
634
|
+
try {
|
|
635
|
+
await this.apiKeyStamper?.deleteKeyPair(generatedKeyPair);
|
|
636
|
+
}
|
|
637
|
+
catch (cleanupError) {
|
|
638
|
+
throw new TurnkeyError(`Failed to clean up generated key pair`, TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
},
|
|
642
|
+
});
|
|
602
643
|
};
|
|
603
644
|
/**
|
|
604
645
|
* Initializes the OTP process by sending an OTP code to the provided contact.
|
|
@@ -613,23 +654,22 @@ class TurnkeyClient {
|
|
|
613
654
|
* @throws {TurnkeyError} If there is an error during the OTP initialization process or if the maximum number of OTPs has been reached.
|
|
614
655
|
*/
|
|
615
656
|
this.initOtp = async (params) => {
|
|
616
|
-
|
|
657
|
+
return withTurnkeyErrorHandling(async () => {
|
|
617
658
|
const initOtpRes = await this.httpClient.proxyInitOtp(params);
|
|
618
659
|
if (!initOtpRes || !initOtpRes.otpId) {
|
|
619
660
|
throw new TurnkeyError("Failed to initialize OTP: otpId is missing", TurnkeyErrorCodes.INIT_OTP_ERROR);
|
|
620
661
|
}
|
|
621
662
|
return initOtpRes.otpId;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
}
|
|
663
|
+
}, {
|
|
664
|
+
errorMessage: "Failed to initialize OTP",
|
|
665
|
+
errorCode: TurnkeyErrorCodes.INIT_OTP_ERROR,
|
|
666
|
+
customMessageByMessages: {
|
|
667
|
+
"Max number of OTPs have been initiated": {
|
|
668
|
+
message: "Maximum number of OTPs has been reached for this contact.",
|
|
669
|
+
code: TurnkeyErrorCodes.MAX_OTP_INITIATED_ERROR,
|
|
670
|
+
},
|
|
671
|
+
},
|
|
672
|
+
});
|
|
633
673
|
};
|
|
634
674
|
/**
|
|
635
675
|
* Verifies the OTP code sent to the user.
|
|
@@ -650,7 +690,7 @@ class TurnkeyClient {
|
|
|
650
690
|
*/
|
|
651
691
|
this.verifyOtp = async (params) => {
|
|
652
692
|
const { otpId, otpCode, contact, otpType } = params;
|
|
653
|
-
|
|
693
|
+
return withTurnkeyErrorHandling(async () => {
|
|
654
694
|
const verifyOtpRes = await this.httpClient.proxyVerifyOtp({
|
|
655
695
|
otpId: otpId,
|
|
656
696
|
otpCode: otpCode,
|
|
@@ -670,16 +710,16 @@ class TurnkeyClient {
|
|
|
670
710
|
subOrganizationId: subOrganizationId,
|
|
671
711
|
verificationToken: verifyOtpRes.verificationToken,
|
|
672
712
|
};
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
713
|
+
}, {
|
|
714
|
+
errorMessage: "Failed to verify OTP",
|
|
715
|
+
errorCode: TurnkeyErrorCodes.VERIFY_OTP_ERROR,
|
|
716
|
+
customMessageByMessages: {
|
|
717
|
+
"Invalid OTP code": {
|
|
718
|
+
message: "The provided OTP code is invalid.",
|
|
719
|
+
code: TurnkeyErrorCodes.INVALID_OTP_CODE,
|
|
720
|
+
},
|
|
721
|
+
},
|
|
722
|
+
});
|
|
683
723
|
};
|
|
684
724
|
/**
|
|
685
725
|
* Logs in a user using an OTP verification token.
|
|
@@ -699,7 +739,7 @@ class TurnkeyClient {
|
|
|
699
739
|
*/
|
|
700
740
|
this.loginWithOtp = async (params) => {
|
|
701
741
|
const { verificationToken, invalidateExisting = false, publicKey = await this.apiKeyStamper?.createKeyPair(), sessionKey = SessionKey.DefaultSessionkey, } = params;
|
|
702
|
-
|
|
742
|
+
return withTurnkeyErrorHandling(async () => {
|
|
703
743
|
const res = await this.httpClient.proxyOtpLogin({
|
|
704
744
|
verificationToken,
|
|
705
745
|
publicKey: publicKey,
|
|
@@ -717,21 +757,21 @@ class TurnkeyClient {
|
|
|
717
757
|
sessionKey,
|
|
718
758
|
});
|
|
719
759
|
return loginRes.session;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
760
|
+
}, {
|
|
761
|
+
errorMessage: "Failed to log in with OTP",
|
|
762
|
+
errorCode: TurnkeyErrorCodes.OTP_LOGIN_ERROR,
|
|
763
|
+
catchFn: async () => {
|
|
764
|
+
// Clean up the generated key pair if it wasn't successfully used
|
|
765
|
+
if (publicKey) {
|
|
766
|
+
try {
|
|
767
|
+
await this.apiKeyStamper?.deleteKeyPair(publicKey);
|
|
768
|
+
}
|
|
769
|
+
catch (cleanupError) {
|
|
770
|
+
throw new TurnkeyError(`Failed to clean up generated key pair`, TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
771
|
+
}
|
|
731
772
|
}
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
}
|
|
773
|
+
},
|
|
774
|
+
});
|
|
735
775
|
};
|
|
736
776
|
/**
|
|
737
777
|
* Signs up a user using an OTP verification token.
|
|
@@ -762,8 +802,8 @@ class TurnkeyClient {
|
|
|
762
802
|
verificationToken,
|
|
763
803
|
},
|
|
764
804
|
});
|
|
765
|
-
|
|
766
|
-
|
|
805
|
+
return withTurnkeyErrorHandling(async () => {
|
|
806
|
+
const generatedKeyPair = await this.apiKeyStamper?.createKeyPair();
|
|
767
807
|
const res = await this.httpClient.proxySignup(signUpBody);
|
|
768
808
|
if (!res) {
|
|
769
809
|
throw new TurnkeyError(`Auth proxy OTP sign up failed`, TurnkeyErrorCodes.OTP_SIGNUP_ERROR);
|
|
@@ -774,12 +814,10 @@ class TurnkeyClient {
|
|
|
774
814
|
...(invalidateExisting && { invalidateExisting }),
|
|
775
815
|
...(sessionKey && { sessionKey }),
|
|
776
816
|
});
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
throw new TurnkeyError(`Failed to sign up with OTP`, TurnkeyErrorCodes.OTP_SIGNUP_ERROR, error);
|
|
782
|
-
}
|
|
817
|
+
}, {
|
|
818
|
+
errorCode: TurnkeyErrorCodes.OTP_SIGNUP_ERROR,
|
|
819
|
+
errorMessage: "Failed to sign up with OTP",
|
|
820
|
+
});
|
|
783
821
|
};
|
|
784
822
|
/**
|
|
785
823
|
* Completes the OTP authentication flow by verifying the OTP code and then either signing up or logging in the user.
|
|
@@ -803,7 +841,7 @@ class TurnkeyClient {
|
|
|
803
841
|
*/
|
|
804
842
|
this.completeOtp = async (params) => {
|
|
805
843
|
const { otpId, otpCode, contact, otpType, publicKey, invalidateExisting = false, sessionKey, createSubOrgParams, } = params;
|
|
806
|
-
|
|
844
|
+
return withTurnkeyErrorHandling(async () => {
|
|
807
845
|
const { subOrganizationId, verificationToken } = await this.verifyOtp({
|
|
808
846
|
otpId: otpId,
|
|
809
847
|
otpCode: otpCode,
|
|
@@ -833,12 +871,10 @@ class TurnkeyClient {
|
|
|
833
871
|
...(sessionKey && { sessionKey }),
|
|
834
872
|
});
|
|
835
873
|
}
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
throw new TurnkeyError(`Failed to complete OTP process`, TurnkeyErrorCodes.OTP_COMPLETION_ERROR, error);
|
|
841
|
-
}
|
|
874
|
+
}, {
|
|
875
|
+
errorMessage: "Failed to complete OTP process",
|
|
876
|
+
errorCode: TurnkeyErrorCodes.OTP_COMPLETION_ERROR,
|
|
877
|
+
});
|
|
842
878
|
};
|
|
843
879
|
/**
|
|
844
880
|
* Completes the OAuth authentication flow by either signing up or logging in the user, depending on whether a sub-organization already exists for the provided OIDC token.
|
|
@@ -860,7 +896,7 @@ class TurnkeyClient {
|
|
|
860
896
|
*/
|
|
861
897
|
this.completeOauth = async (params) => {
|
|
862
898
|
const { oidcToken, publicKey, createSubOrgParams, providerName = "OpenID Connect Provider" + Date.now(), sessionKey = SessionKey.DefaultSessionkey, invalidateExisting = false, } = params;
|
|
863
|
-
|
|
899
|
+
return withTurnkeyErrorHandling(async () => {
|
|
864
900
|
const accountRes = await this.httpClient.proxyGetAccount({
|
|
865
901
|
filterType: "OIDC_TOKEN",
|
|
866
902
|
filterValue: oidcToken,
|
|
@@ -887,12 +923,10 @@ class TurnkeyClient {
|
|
|
887
923
|
}),
|
|
888
924
|
});
|
|
889
925
|
}
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
throw new TurnkeyError(`Failed to handle Google OAuth login`, TurnkeyErrorCodes.OAUTH_LOGIN_ERROR, error);
|
|
895
|
-
}
|
|
926
|
+
}, {
|
|
927
|
+
errorMessage: "Failed to complete OAuth process",
|
|
928
|
+
errorCode: TurnkeyErrorCodes.OAUTH_LOGIN_ERROR,
|
|
929
|
+
});
|
|
896
930
|
};
|
|
897
931
|
/**
|
|
898
932
|
* Logs in a user using OAuth authentication.
|
|
@@ -911,10 +945,10 @@ class TurnkeyClient {
|
|
|
911
945
|
*/
|
|
912
946
|
this.loginWithOauth = async (params) => {
|
|
913
947
|
const { oidcToken, invalidateExisting = false, publicKey, sessionKey = SessionKey.DefaultSessionkey, } = params;
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
948
|
+
return withTurnkeyErrorHandling(async () => {
|
|
949
|
+
if (!publicKey) {
|
|
950
|
+
throw new TurnkeyError("Public key must be provided to log in with OAuth. Please create a key pair first.", TurnkeyErrorCodes.MISSING_PARAMS);
|
|
951
|
+
}
|
|
918
952
|
const loginRes = await this.httpClient.proxyOAuthLogin({
|
|
919
953
|
oidcToken,
|
|
920
954
|
publicKey,
|
|
@@ -931,21 +965,27 @@ class TurnkeyClient {
|
|
|
931
965
|
sessionKey,
|
|
932
966
|
});
|
|
933
967
|
return loginRes.session;
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
968
|
+
}, {
|
|
969
|
+
errorMessage: "Failed to complete OAuth login",
|
|
970
|
+
errorCode: TurnkeyErrorCodes.OAUTH_LOGIN_ERROR,
|
|
971
|
+
customMessageByMessages: {
|
|
972
|
+
"OAUTH disallowed": {
|
|
973
|
+
message: "OAuth is disabled on the dashboard for this organization.",
|
|
974
|
+
code: TurnkeyErrorCodes.AUTH_METHOD_NOT_ENABLED,
|
|
975
|
+
},
|
|
976
|
+
},
|
|
977
|
+
catchFn: async () => {
|
|
978
|
+
// Clean up the generated key pair if it wasn't successfully used
|
|
979
|
+
if (publicKey) {
|
|
980
|
+
try {
|
|
981
|
+
await this.apiKeyStamper?.deleteKeyPair(publicKey);
|
|
982
|
+
}
|
|
983
|
+
catch (cleanupError) {
|
|
984
|
+
throw new TurnkeyError(`Failed to clean up generated key pair`, TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
985
|
+
}
|
|
945
986
|
}
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
}
|
|
987
|
+
},
|
|
988
|
+
});
|
|
949
989
|
};
|
|
950
990
|
/**
|
|
951
991
|
* Signs up a user using OAuth authentication.
|
|
@@ -965,7 +1005,7 @@ class TurnkeyClient {
|
|
|
965
1005
|
*/
|
|
966
1006
|
this.signUpWithOauth = async (params) => {
|
|
967
1007
|
const { oidcToken, publicKey, providerName, createSubOrgParams } = params;
|
|
968
|
-
|
|
1008
|
+
return withTurnkeyErrorHandling(async () => {
|
|
969
1009
|
const signUpBody = buildSignUpBody({
|
|
970
1010
|
createSubOrgParams: {
|
|
971
1011
|
...createSubOrgParams,
|
|
@@ -985,12 +1025,10 @@ class TurnkeyClient {
|
|
|
985
1025
|
oidcToken,
|
|
986
1026
|
publicKey: publicKey,
|
|
987
1027
|
});
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
throw new TurnkeyError(`Failed to sign up with OAuth`, TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR, error);
|
|
993
|
-
}
|
|
1028
|
+
}, {
|
|
1029
|
+
errorMessage: "Failed to sign up with OAuth",
|
|
1030
|
+
errorCode: TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR,
|
|
1031
|
+
});
|
|
994
1032
|
};
|
|
995
1033
|
/**
|
|
996
1034
|
* Fetches all wallets for the current user, including both embedded and connected wallets.
|
|
@@ -1006,12 +1044,12 @@ class TurnkeyClient {
|
|
|
1006
1044
|
* @throws {TurnkeyError} If no active session is found or if there is an error fetching wallets.
|
|
1007
1045
|
*/
|
|
1008
1046
|
this.fetchWallets = async (params) => {
|
|
1009
|
-
const { stampWith } = params || {};
|
|
1047
|
+
const { stampWith, walletProviders } = params || {};
|
|
1010
1048
|
const session = await this.storageManager.getActiveSession();
|
|
1011
1049
|
if (!session) {
|
|
1012
1050
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1013
1051
|
}
|
|
1014
|
-
|
|
1052
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1015
1053
|
const res = await this.httpClient.getWallets({ organizationId: session.organizationId }, stampWith);
|
|
1016
1054
|
if (!res || !res.wallets) {
|
|
1017
1055
|
throw new TurnkeyError("No wallets found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -1032,10 +1070,11 @@ class TurnkeyClient {
|
|
|
1032
1070
|
// if wallet connecting is disabled we return only embedded wallets
|
|
1033
1071
|
if (!this.walletManager?.connector)
|
|
1034
1072
|
return embedded;
|
|
1035
|
-
const providers = await this.getWalletProviders();
|
|
1073
|
+
const providers = walletProviders ?? (await this.getWalletProviders());
|
|
1036
1074
|
const groupedProviders = new Map();
|
|
1037
1075
|
for (const provider of providers) {
|
|
1038
|
-
const walletId = provider.info?.name?.toLowerCase().replace(/\s+/g, "-") ||
|
|
1076
|
+
const walletId = provider.info?.name?.toLowerCase().replace(/\s+/g, "-") ||
|
|
1077
|
+
"unknown";
|
|
1039
1078
|
const group = groupedProviders.get(walletId) || [];
|
|
1040
1079
|
group.push(provider);
|
|
1041
1080
|
groupedProviders.set(walletId, group);
|
|
@@ -1061,12 +1100,10 @@ class TurnkeyClient {
|
|
|
1061
1100
|
return wallet;
|
|
1062
1101
|
}))).filter((wallet) => wallet.accounts.length > 0);
|
|
1063
1102
|
return [...embedded, ...connected];
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
throw new TurnkeyError("Failed to fetch wallets", TurnkeyErrorCodes.FETCH_WALLETS_ERROR, error);
|
|
1069
|
-
}
|
|
1103
|
+
}, {
|
|
1104
|
+
errorMessage: "Failed to fetch wallets",
|
|
1105
|
+
errorCode: TurnkeyErrorCodes.FETCH_WALLETS_ERROR,
|
|
1106
|
+
});
|
|
1070
1107
|
};
|
|
1071
1108
|
/**
|
|
1072
1109
|
* Fetches all accounts for a specific wallet, including both embedded and connected wallet accounts.
|
|
@@ -1090,58 +1127,90 @@ class TurnkeyClient {
|
|
|
1090
1127
|
if (!session) {
|
|
1091
1128
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1092
1129
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
organizationId: session.organizationId,
|
|
1099
|
-
paginationOptions: paginationOptions || { limit: "100" },
|
|
1100
|
-
}, stampWith);
|
|
1101
|
-
if (!res || !res.accounts) {
|
|
1102
|
-
throw new TurnkeyError("No wallet accounts found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1103
|
-
}
|
|
1104
|
-
for (const account of res.accounts) {
|
|
1105
|
-
embedded.push({
|
|
1106
|
-
...account,
|
|
1107
|
-
source: WalletSource.Embedded,
|
|
1108
|
-
});
|
|
1109
|
-
}
|
|
1110
|
-
return embedded;
|
|
1111
|
-
}
|
|
1112
|
-
// this is an external wallet so we fetch accounts from the connected wallet provider
|
|
1113
|
-
// if wallet connecting is disabled we return only embedded wallets
|
|
1114
|
-
// we should never reach this point if wallet connecting is disabled
|
|
1115
|
-
if (!this.walletManager?.connector)
|
|
1116
|
-
return [];
|
|
1117
|
-
const connected = [];
|
|
1118
|
-
const providers = walletProviders ?? (await this.getWalletProviders());
|
|
1119
|
-
const matching = providers.filter((p) => p.info?.name?.toLowerCase().replace(/\s+/g, "-") === wallet.walletId &&
|
|
1120
|
-
p.connectedAddresses.length > 0);
|
|
1121
|
-
for (const provider of matching) {
|
|
1122
|
-
const timestamp = toExternalTimestamp();
|
|
1123
|
-
for (const address of provider.connectedAddresses) {
|
|
1124
|
-
const account = {
|
|
1125
|
-
walletAccountId: `${wallet.walletId}-${provider.interfaceType}-${address}`,
|
|
1126
|
-
organizationId: session.organizationId,
|
|
1130
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1131
|
+
// this is an embedded wallet so we fetch accounts from Turnkey
|
|
1132
|
+
if (wallet.source === WalletSource.Embedded) {
|
|
1133
|
+
const embedded = [];
|
|
1134
|
+
const res = await this.httpClient.getWalletAccounts({
|
|
1127
1135
|
walletId: wallet.walletId,
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
connected.push(account);
|
|
1136
|
+
organizationId: session.organizationId,
|
|
1137
|
+
paginationOptions: paginationOptions || { limit: "100" },
|
|
1138
|
+
}, stampWith);
|
|
1139
|
+
if (!res || !res.accounts) {
|
|
1140
|
+
throw new TurnkeyError("No wallet accounts found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1141
|
+
}
|
|
1142
|
+
for (const account of res.accounts) {
|
|
1143
|
+
embedded.push({
|
|
1144
|
+
...account,
|
|
1145
|
+
source: WalletSource.Embedded,
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
return embedded;
|
|
1142
1149
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1150
|
+
// this is an external wallet so we fetch accounts from the connected wallet provider
|
|
1151
|
+
// if wallet connecting is disabled we return only embedded wallets
|
|
1152
|
+
// we should never reach this point if wallet connecting is disabled
|
|
1153
|
+
if (!this.walletManager?.connector)
|
|
1154
|
+
return [];
|
|
1155
|
+
const connected = [];
|
|
1156
|
+
const providers = walletProviders ?? (await this.getWalletProviders());
|
|
1157
|
+
const matching = providers.filter((p) => p.info?.name?.toLowerCase().replace(/\s+/g, "-") ===
|
|
1158
|
+
wallet.walletId && p.connectedAddresses.length > 0);
|
|
1159
|
+
const sign = this.walletManager.connector.sign.bind(this.walletManager.connector);
|
|
1160
|
+
for (const provider of matching) {
|
|
1161
|
+
const timestamp = toExternalTimestamp();
|
|
1162
|
+
for (const address of provider.connectedAddresses) {
|
|
1163
|
+
if (isEthereumProvider(provider)) {
|
|
1164
|
+
const evmAccount = {
|
|
1165
|
+
walletAccountId: `${wallet.walletId}-${provider.interfaceType}-${address}`,
|
|
1166
|
+
organizationId: session.organizationId,
|
|
1167
|
+
walletId: wallet.walletId,
|
|
1168
|
+
pathFormat: "PATH_FORMAT_BIP32",
|
|
1169
|
+
path: WalletSource.Connected,
|
|
1170
|
+
source: WalletSource.Connected,
|
|
1171
|
+
address,
|
|
1172
|
+
createdAt: timestamp,
|
|
1173
|
+
updatedAt: timestamp,
|
|
1174
|
+
// ethereum specific
|
|
1175
|
+
curve: Curve.SECP256K1,
|
|
1176
|
+
addressFormat: "ADDRESS_FORMAT_ETHEREUM",
|
|
1177
|
+
chainInfo: provider.chainInfo,
|
|
1178
|
+
signMessage: (msg) => sign(msg, provider, SignIntent.SignMessage),
|
|
1179
|
+
signAndSendTransaction: (tx) => sign(tx, provider, SignIntent.SignAndSendTransaction),
|
|
1180
|
+
};
|
|
1181
|
+
connected.push(evmAccount);
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (isSolanaProvider(provider)) {
|
|
1185
|
+
const solAccount = {
|
|
1186
|
+
walletAccountId: `${wallet.walletId}-${provider.interfaceType}-${address}`,
|
|
1187
|
+
organizationId: session.organizationId,
|
|
1188
|
+
walletId: wallet.walletId,
|
|
1189
|
+
pathFormat: "PATH_FORMAT_BIP32",
|
|
1190
|
+
path: WalletSource.Connected,
|
|
1191
|
+
source: WalletSource.Connected,
|
|
1192
|
+
address,
|
|
1193
|
+
createdAt: timestamp,
|
|
1194
|
+
updatedAt: timestamp,
|
|
1195
|
+
// solana specific
|
|
1196
|
+
publicKey: address,
|
|
1197
|
+
curve: Curve.ED25519,
|
|
1198
|
+
addressFormat: "ADDRESS_FORMAT_SOLANA",
|
|
1199
|
+
chainInfo: provider.chainInfo,
|
|
1200
|
+
signMessage: (msg) => sign(msg, provider, SignIntent.SignMessage),
|
|
1201
|
+
signTransaction: (tx) => sign(tx, provider, SignIntent.SignTransaction),
|
|
1202
|
+
};
|
|
1203
|
+
connected.push(solAccount);
|
|
1204
|
+
continue;
|
|
1205
|
+
}
|
|
1206
|
+
throw new Error(`Unsupported wallet chain: ${provider.chainInfo}. Supported chains are Ethereum and Solana.`);
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
return connected;
|
|
1210
|
+
}, {
|
|
1211
|
+
errorMessage: "Failed to fetch wallet accounts",
|
|
1212
|
+
errorCode: TurnkeyErrorCodes.FETCH_WALLET_ACCOUNTS_ERROR,
|
|
1213
|
+
});
|
|
1145
1214
|
};
|
|
1146
1215
|
/**
|
|
1147
1216
|
* Signs a message using the specified wallet account.
|
|
@@ -1175,7 +1244,7 @@ class TurnkeyClient {
|
|
|
1175
1244
|
const { message, walletAccount, stampWith, addEthereumPrefix } = params;
|
|
1176
1245
|
const hashFunction = params.hashFunction || getHashFunction(walletAccount.addressFormat);
|
|
1177
1246
|
const payloadEncoding = params.encoding || getEncodingType(walletAccount.addressFormat);
|
|
1178
|
-
|
|
1247
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1179
1248
|
const isEthereum = walletAccount.addressFormat === "ADDRESS_FORMAT_ETHEREUM";
|
|
1180
1249
|
if (walletAccount.source === WalletSource.Connected) {
|
|
1181
1250
|
// this is a connected wallet
|
|
@@ -1207,12 +1276,10 @@ class TurnkeyClient {
|
|
|
1207
1276
|
}
|
|
1208
1277
|
return response.activity.result
|
|
1209
1278
|
.signRawPayloadResult;
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
throw new TurnkeyError(`Failed to sign message - ${error?.message ? error.message : "Unknown error"}`, TurnkeyErrorCodes.SIGN_MESSAGE_ERROR);
|
|
1215
|
-
}
|
|
1279
|
+
}, {
|
|
1280
|
+
errorMessage: "Failed to sign message",
|
|
1281
|
+
errorCode: TurnkeyErrorCodes.SIGN_MESSAGE_ERROR,
|
|
1282
|
+
});
|
|
1216
1283
|
};
|
|
1217
1284
|
/**
|
|
1218
1285
|
* Signs a transaction using the specified wallet account.
|
|
@@ -1232,17 +1299,18 @@ class TurnkeyClient {
|
|
|
1232
1299
|
*/
|
|
1233
1300
|
this.signTransaction = async (params) => {
|
|
1234
1301
|
const { walletAccount, unsignedTransaction, transactionType, stampWith } = params;
|
|
1235
|
-
|
|
1302
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1236
1303
|
if (walletAccount.source === WalletSource.Connected) {
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1304
|
+
switch (walletAccount.chainInfo.namespace) {
|
|
1305
|
+
case Chain.Ethereum:
|
|
1306
|
+
throw new TurnkeyError("Ethereum connected wallets do not support raw transaction signing. Use signAndSendTransaction instead.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1307
|
+
case Chain.Solana:
|
|
1308
|
+
// not sure why typescript isn't inferring the type here
|
|
1309
|
+
// if namespace is Chain.Solana, then it must be a ConnectedSolanaWalletAccount
|
|
1310
|
+
return walletAccount.signTransaction(unsignedTransaction);
|
|
1311
|
+
default:
|
|
1312
|
+
throw new TurnkeyError("Unsupported connected wallet type.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1244
1313
|
}
|
|
1245
|
-
return await walletAccount?.signTransaction(unsignedTransaction);
|
|
1246
1314
|
}
|
|
1247
1315
|
// this is an embedded wallet account
|
|
1248
1316
|
const signTransaction = await this.httpClient.signTransaction({
|
|
@@ -1251,12 +1319,10 @@ class TurnkeyClient {
|
|
|
1251
1319
|
type: transactionType,
|
|
1252
1320
|
}, stampWith);
|
|
1253
1321
|
return signTransaction.signedTransaction;
|
|
1254
|
-
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
throw new TurnkeyError(`Failed to sign transaction`, TurnkeyErrorCodes.SIGN_TRANSACTION_ERROR, error);
|
|
1259
|
-
}
|
|
1322
|
+
}, {
|
|
1323
|
+
errorMessage: "Failed to sign transaction",
|
|
1324
|
+
errorCode: TurnkeyErrorCodes.SIGN_TRANSACTION_ERROR,
|
|
1325
|
+
});
|
|
1260
1326
|
};
|
|
1261
1327
|
/**
|
|
1262
1328
|
* Signs and broadcasts a transaction using the specified wallet account.
|
|
@@ -1280,22 +1346,20 @@ class TurnkeyClient {
|
|
|
1280
1346
|
*/
|
|
1281
1347
|
this.signAndSendTransaction = async (params) => {
|
|
1282
1348
|
const { walletAccount, unsignedTransaction, transactionType, rpcUrl, stampWith, } = params;
|
|
1283
|
-
|
|
1349
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1284
1350
|
if (walletAccount.source === WalletSource.Connected) {
|
|
1285
1351
|
// this is a connected wallet account
|
|
1286
|
-
switch (
|
|
1287
|
-
case
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
}
|
|
1352
|
+
switch (walletAccount.chainInfo.namespace) {
|
|
1353
|
+
case Chain.Ethereum:
|
|
1354
|
+
// not sure why typescript isn't inferring the type here
|
|
1355
|
+
// if namespace is Chain.Ethereum, then it must be a ConnectedEthereumWalletAccount
|
|
1291
1356
|
return await walletAccount.signAndSendTransaction(unsignedTransaction);
|
|
1292
|
-
case
|
|
1357
|
+
case Chain.Solana:
|
|
1293
1358
|
if (!rpcUrl) {
|
|
1294
1359
|
throw new TurnkeyError("Missing rpcUrl: connected Solana wallets require an RPC URL to broadcast transactions.", TurnkeyErrorCodes.SIGN_AND_SEND_TRANSACTION_ERROR);
|
|
1295
1360
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
}
|
|
1361
|
+
// not sure why typescript isn't inferring the type here
|
|
1362
|
+
// if namespace is Chain.Solana, then it must be a ConnectedSolanaWalletAccount
|
|
1299
1363
|
const signature = await walletAccount.signTransaction(unsignedTransaction);
|
|
1300
1364
|
return await broadcastTransaction({
|
|
1301
1365
|
signedTransaction: signature,
|
|
@@ -1324,12 +1388,10 @@ class TurnkeyClient {
|
|
|
1324
1388
|
transactionType,
|
|
1325
1389
|
});
|
|
1326
1390
|
return txHash;
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
throw new TurnkeyError(`Failed to sign and send transaction`, TurnkeyErrorCodes.SIGN_AND_SEND_TRANSACTION_ERROR, error);
|
|
1332
|
-
}
|
|
1391
|
+
}, {
|
|
1392
|
+
errorMessage: "Failed to sign and send transaction",
|
|
1393
|
+
errorCode: TurnkeyErrorCodes.SIGN_AND_SEND_TRANSACTION_ERROR,
|
|
1394
|
+
});
|
|
1333
1395
|
};
|
|
1334
1396
|
/**
|
|
1335
1397
|
* Fetches the user details for the current session or a specified user.
|
|
@@ -1357,18 +1419,16 @@ class TurnkeyClient {
|
|
|
1357
1419
|
throw new TurnkeyError("User ID must be provided to fetch user", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1358
1420
|
}
|
|
1359
1421
|
const organizationId = params?.organizationId || session.organizationId;
|
|
1360
|
-
|
|
1422
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1361
1423
|
const userResponse = await this.httpClient.getUser({ organizationId, userId }, stampWith);
|
|
1362
1424
|
if (!userResponse || !userResponse.user) {
|
|
1363
1425
|
throw new TurnkeyError("No user found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1364
1426
|
}
|
|
1365
1427
|
return userResponse.user;
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
throw new TurnkeyError(`Failed to fetch user`, TurnkeyErrorCodes.FETCH_USER_ERROR, error);
|
|
1371
|
-
}
|
|
1428
|
+
}, {
|
|
1429
|
+
errorMessage: "Failed to fetch user",
|
|
1430
|
+
errorCode: TurnkeyErrorCodes.FETCH_USER_ERROR,
|
|
1431
|
+
});
|
|
1372
1432
|
};
|
|
1373
1433
|
/**
|
|
1374
1434
|
* Updates the user's email address.
|
|
@@ -1393,7 +1453,7 @@ class TurnkeyClient {
|
|
|
1393
1453
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1394
1454
|
}
|
|
1395
1455
|
const userId = params?.userId || session.userId;
|
|
1396
|
-
|
|
1456
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1397
1457
|
const existingUser = await this.httpClient.proxyGetAccount({
|
|
1398
1458
|
filterType: FilterType.Email,
|
|
1399
1459
|
filterValue: email,
|
|
@@ -1410,12 +1470,10 @@ class TurnkeyClient {
|
|
|
1410
1470
|
throw new TurnkeyError("No user ID found in the update user email response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1411
1471
|
}
|
|
1412
1472
|
return res.userId;
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
throw new TurnkeyError(`Failed to update user email`, TurnkeyErrorCodes.UPDATE_USER_EMAIL_ERROR, error);
|
|
1418
|
-
}
|
|
1473
|
+
}, {
|
|
1474
|
+
errorMessage: "Failed to update user email",
|
|
1475
|
+
errorCode: TurnkeyErrorCodes.UPDATE_USER_EMAIL_ERROR,
|
|
1476
|
+
});
|
|
1419
1477
|
};
|
|
1420
1478
|
/**
|
|
1421
1479
|
* Removes the user's email address.
|
|
@@ -1436,15 +1494,20 @@ class TurnkeyClient {
|
|
|
1436
1494
|
if (!session) {
|
|
1437
1495
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1438
1496
|
}
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1497
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1498
|
+
const userId = params?.userId || session.userId;
|
|
1499
|
+
const res = await this.httpClient.updateUserEmail({
|
|
1500
|
+
userId: userId,
|
|
1501
|
+
userEmail: "",
|
|
1502
|
+
}, stampWith);
|
|
1503
|
+
if (!res || !res.userId) {
|
|
1504
|
+
throw new TurnkeyError("No user ID found in the remove user email response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1505
|
+
}
|
|
1506
|
+
return res.userId;
|
|
1507
|
+
}, {
|
|
1508
|
+
errorMessage: "Failed to remove user email",
|
|
1509
|
+
errorCode: TurnkeyErrorCodes.UPDATE_USER_EMAIL_ERROR,
|
|
1510
|
+
});
|
|
1448
1511
|
};
|
|
1449
1512
|
/**
|
|
1450
1513
|
* Updates the user's phone number.
|
|
@@ -1469,7 +1532,7 @@ class TurnkeyClient {
|
|
|
1469
1532
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1470
1533
|
}
|
|
1471
1534
|
const userId = params?.userId || session.userId;
|
|
1472
|
-
|
|
1535
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1473
1536
|
const res = await this.httpClient.updateUserPhoneNumber({
|
|
1474
1537
|
userId,
|
|
1475
1538
|
userPhoneNumber: phoneNumber,
|
|
@@ -1479,12 +1542,10 @@ class TurnkeyClient {
|
|
|
1479
1542
|
throw new TurnkeyError("Failed to update user phone number", TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR);
|
|
1480
1543
|
}
|
|
1481
1544
|
return res.userId;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
throw new TurnkeyError(`Failed to update user phone number`, TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR, error);
|
|
1487
|
-
}
|
|
1545
|
+
}, {
|
|
1546
|
+
errorMessage: "Failed to update user phone number",
|
|
1547
|
+
errorCode: TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR,
|
|
1548
|
+
});
|
|
1488
1549
|
};
|
|
1489
1550
|
/**
|
|
1490
1551
|
* Removes the user's phone number.
|
|
@@ -1506,14 +1567,19 @@ class TurnkeyClient {
|
|
|
1506
1567
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1507
1568
|
}
|
|
1508
1569
|
const userId = params?.userId || session.userId;
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1570
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1571
|
+
const res = await this.httpClient.updateUserPhoneNumber({
|
|
1572
|
+
userId,
|
|
1573
|
+
userPhoneNumber: "",
|
|
1574
|
+
}, stampWith);
|
|
1575
|
+
if (!res || !res.userId) {
|
|
1576
|
+
throw new TurnkeyError("Failed to remove user phone number", TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR);
|
|
1577
|
+
}
|
|
1578
|
+
return res.userId;
|
|
1579
|
+
}, {
|
|
1580
|
+
errorMessage: "Failed to remove user phone number",
|
|
1581
|
+
errorCode: TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR,
|
|
1582
|
+
});
|
|
1517
1583
|
};
|
|
1518
1584
|
/**
|
|
1519
1585
|
* Updates the user's name.
|
|
@@ -1537,7 +1603,7 @@ class TurnkeyClient {
|
|
|
1537
1603
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1538
1604
|
}
|
|
1539
1605
|
const userId = params?.userId || session.userId;
|
|
1540
|
-
|
|
1606
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1541
1607
|
const res = await this.httpClient.updateUserName({
|
|
1542
1608
|
userId,
|
|
1543
1609
|
userName,
|
|
@@ -1546,12 +1612,10 @@ class TurnkeyClient {
|
|
|
1546
1612
|
throw new TurnkeyError("No user ID found in the update user name response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1547
1613
|
}
|
|
1548
1614
|
return res.userId;
|
|
1549
|
-
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
throw new TurnkeyError(`Failed to update user name`, TurnkeyErrorCodes.UPDATE_USER_NAME_ERROR, error);
|
|
1554
|
-
}
|
|
1615
|
+
}, {
|
|
1616
|
+
errorMessage: "Failed to update user name",
|
|
1617
|
+
errorCode: TurnkeyErrorCodes.UPDATE_USER_NAME_ERROR,
|
|
1618
|
+
});
|
|
1555
1619
|
};
|
|
1556
1620
|
/**
|
|
1557
1621
|
* Adds an OAuth provider to the user.
|
|
@@ -1576,7 +1640,7 @@ class TurnkeyClient {
|
|
|
1576
1640
|
if (!session) {
|
|
1577
1641
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1578
1642
|
}
|
|
1579
|
-
|
|
1643
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1580
1644
|
const accountRes = await this.httpClient.proxyGetAccount({
|
|
1581
1645
|
filterType: "OIDC_TOKEN",
|
|
1582
1646
|
filterValue: oidcToken,
|
|
@@ -1620,12 +1684,10 @@ class TurnkeyClient {
|
|
|
1620
1684
|
throw new TurnkeyError("Failed to create OAuth provider", TurnkeyErrorCodes.ADD_OAUTH_PROVIDER_ERROR);
|
|
1621
1685
|
}
|
|
1622
1686
|
return createProviderRes?.providerIds || [];
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
throw new TurnkeyError(`Failed to fetch account for OAuth provider`, TurnkeyErrorCodes.ACCOUNT_FETCH_ERROR, error);
|
|
1628
|
-
}
|
|
1687
|
+
}, {
|
|
1688
|
+
errorMessage: "Failed to add OAuth provider",
|
|
1689
|
+
errorCode: TurnkeyErrorCodes.ADD_OAUTH_PROVIDER_ERROR,
|
|
1690
|
+
});
|
|
1629
1691
|
};
|
|
1630
1692
|
/**
|
|
1631
1693
|
* Removes a list of OAuth providers from the user.
|
|
@@ -1649,14 +1711,19 @@ class TurnkeyClient {
|
|
|
1649
1711
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1650
1712
|
}
|
|
1651
1713
|
const userId = params?.userId || session.userId;
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1714
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1715
|
+
const res = await this.httpClient.deleteOauthProviders({
|
|
1716
|
+
userId,
|
|
1717
|
+
providerIds,
|
|
1718
|
+
}, stampWith);
|
|
1719
|
+
if (!res) {
|
|
1720
|
+
throw new TurnkeyError("Failed to remove OAuth provider", TurnkeyErrorCodes.REMOVE_OAUTH_PROVIDER_ERROR);
|
|
1721
|
+
}
|
|
1722
|
+
return res.providerIds;
|
|
1723
|
+
}, {
|
|
1724
|
+
errorMessage: "Failed to remove OAuth provider",
|
|
1725
|
+
errorCode: TurnkeyErrorCodes.REMOVE_OAUTH_PROVIDER_ERROR,
|
|
1726
|
+
});
|
|
1660
1727
|
};
|
|
1661
1728
|
/**
|
|
1662
1729
|
* Adds a new passkey authenticator for the user.
|
|
@@ -1678,7 +1745,7 @@ class TurnkeyClient {
|
|
|
1678
1745
|
const { stampWith } = params || {};
|
|
1679
1746
|
const name = params?.name || `Turnkey Passkey-${Date.now()}`;
|
|
1680
1747
|
const displayName = params?.displayName || name;
|
|
1681
|
-
|
|
1748
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1682
1749
|
const session = await this.storageManager.getActiveSession();
|
|
1683
1750
|
if (!session) {
|
|
1684
1751
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
@@ -1703,12 +1770,10 @@ class TurnkeyClient {
|
|
|
1703
1770
|
],
|
|
1704
1771
|
}, stampWith);
|
|
1705
1772
|
return res?.authenticatorIds || [];
|
|
1706
|
-
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
throw new TurnkeyError(`Failed to add passkey`, TurnkeyErrorCodes.ADD_PASSKEY_ERROR, error);
|
|
1711
|
-
}
|
|
1773
|
+
}, {
|
|
1774
|
+
errorMessage: "Failed to add passkey",
|
|
1775
|
+
errorCode: TurnkeyErrorCodes.ADD_PASSKEY_ERROR,
|
|
1776
|
+
});
|
|
1712
1777
|
};
|
|
1713
1778
|
/**
|
|
1714
1779
|
* Removes passkeys (authenticator) from the user.
|
|
@@ -1732,14 +1797,19 @@ class TurnkeyClient {
|
|
|
1732
1797
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1733
1798
|
}
|
|
1734
1799
|
const userId = params?.userId || session.userId;
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1800
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1801
|
+
const res = await this.httpClient.deleteAuthenticators({
|
|
1802
|
+
userId,
|
|
1803
|
+
authenticatorIds,
|
|
1804
|
+
}, stampWith);
|
|
1805
|
+
if (!res) {
|
|
1806
|
+
throw new TurnkeyError("No response found in the remove passkey response", TurnkeyErrorCodes.REMOVE_PASSKEY_ERROR);
|
|
1807
|
+
}
|
|
1808
|
+
return res.authenticatorIds;
|
|
1809
|
+
}, {
|
|
1810
|
+
errorMessage: "Failed to remove passkey",
|
|
1811
|
+
errorCode: TurnkeyErrorCodes.REMOVE_PASSKEY_ERROR,
|
|
1812
|
+
});
|
|
1743
1813
|
};
|
|
1744
1814
|
/**
|
|
1745
1815
|
* Creates a new wallet for sub-organization.
|
|
@@ -1778,7 +1848,7 @@ class TurnkeyClient {
|
|
|
1778
1848
|
...DEFAULT_SOLANA_ACCOUNTS,
|
|
1779
1849
|
];
|
|
1780
1850
|
}
|
|
1781
|
-
|
|
1851
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1782
1852
|
const res = await this.httpClient.createWallet({
|
|
1783
1853
|
organizationId: organizationId || session.organizationId,
|
|
1784
1854
|
walletName,
|
|
@@ -1789,12 +1859,10 @@ class TurnkeyClient {
|
|
|
1789
1859
|
throw new TurnkeyError("No wallet found in the create wallet response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1790
1860
|
}
|
|
1791
1861
|
return res.walletId;
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
throw new TurnkeyError(`Failed to create wallet`, TurnkeyErrorCodes.CREATE_WALLET_ERROR, error);
|
|
1797
|
-
}
|
|
1862
|
+
}, {
|
|
1863
|
+
errorMessage: "Failed to create wallet",
|
|
1864
|
+
errorCode: TurnkeyErrorCodes.CREATE_WALLET_ERROR,
|
|
1865
|
+
});
|
|
1798
1866
|
};
|
|
1799
1867
|
/**
|
|
1800
1868
|
* Creates new accounts in the specified wallet.
|
|
@@ -1819,7 +1887,7 @@ class TurnkeyClient {
|
|
|
1819
1887
|
if (!session) {
|
|
1820
1888
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1821
1889
|
}
|
|
1822
|
-
|
|
1890
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1823
1891
|
let walletAccounts = [];
|
|
1824
1892
|
if (accounts && !isWalletAccountArray(accounts)) {
|
|
1825
1893
|
// Query existing wallet accounts to avoid duplicates
|
|
@@ -1845,12 +1913,10 @@ class TurnkeyClient {
|
|
|
1845
1913
|
throw new TurnkeyError("No account found in the create wallet account response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1846
1914
|
}
|
|
1847
1915
|
return res.addresses;
|
|
1848
|
-
}
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
throw new TurnkeyError(`Failed to create wallet account`, TurnkeyErrorCodes.CREATE_WALLET_ACCOUNT_ERROR, error);
|
|
1853
|
-
}
|
|
1916
|
+
}, {
|
|
1917
|
+
errorMessage: "Failed to create wallet account",
|
|
1918
|
+
errorCode: TurnkeyErrorCodes.CREATE_WALLET_ACCOUNT_ERROR,
|
|
1919
|
+
});
|
|
1854
1920
|
};
|
|
1855
1921
|
/**
|
|
1856
1922
|
* Exports a wallet as an encrypted bundle.
|
|
@@ -1875,7 +1941,7 @@ class TurnkeyClient {
|
|
|
1875
1941
|
if (!session) {
|
|
1876
1942
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1877
1943
|
}
|
|
1878
|
-
|
|
1944
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1879
1945
|
const res = await this.httpClient.exportWallet({
|
|
1880
1946
|
walletId,
|
|
1881
1947
|
targetPublicKey,
|
|
@@ -1885,12 +1951,85 @@ class TurnkeyClient {
|
|
|
1885
1951
|
throw new TurnkeyError("No export bundle found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1886
1952
|
}
|
|
1887
1953
|
return res.exportBundle;
|
|
1954
|
+
}, {
|
|
1955
|
+
errorMessage: "Failed to export wallet",
|
|
1956
|
+
errorCode: TurnkeyErrorCodes.EXPORT_WALLET_ERROR,
|
|
1957
|
+
});
|
|
1958
|
+
};
|
|
1959
|
+
/**
|
|
1960
|
+
* Exports a private key as an encrypted bundle.
|
|
1961
|
+
*
|
|
1962
|
+
* - This function exports the specified private key as an encrypted bundle, suitable for backup or transfer.
|
|
1963
|
+
* - The exported bundle contains the private key's key material, encrypted to the provided target public key.
|
|
1964
|
+
* - If a targetPublicKey is provided, the bundle will be encrypted to that public key; otherwise, an error will be thrown.
|
|
1965
|
+
* - If an organizationId is provided, the private key will be exported under that sub-organization; otherwise, the current session's organizationId is used.
|
|
1966
|
+
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1967
|
+
*
|
|
1968
|
+
* @param params.privateKeyId - ID of the private key to export.
|
|
1969
|
+
* @param params.targetPublicKey - public key to encrypt the bundle to (required).
|
|
1970
|
+
* @param params.organizationId - organization ID to export the private key under a specific sub
|
|
1971
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1972
|
+
* @returns A promise that resolves to an `ExportBundle` object containing the encrypted private key and metadata.
|
|
1973
|
+
* @throws {TurnkeyError} If there is no active session, if the targetPublicKey is missing, or if there is an error exporting the private key.
|
|
1974
|
+
*/
|
|
1975
|
+
this.exportPrivateKey = async (params) => {
|
|
1976
|
+
const { privateKeyId, targetPublicKey, stampWith, organizationId } = params;
|
|
1977
|
+
const session = await this.storageManager.getActiveSession();
|
|
1978
|
+
if (!session) {
|
|
1979
|
+
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1888
1980
|
}
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1981
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1982
|
+
const res = await this.httpClient.exportPrivateKey({
|
|
1983
|
+
privateKeyId,
|
|
1984
|
+
targetPublicKey,
|
|
1985
|
+
organizationId: organizationId || session.organizationId,
|
|
1986
|
+
}, stampWith);
|
|
1987
|
+
if (!res.exportBundle) {
|
|
1988
|
+
throw new TurnkeyError("No export bundle found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1989
|
+
}
|
|
1990
|
+
return res.exportBundle;
|
|
1991
|
+
}, {
|
|
1992
|
+
errorMessage: "Failed to export private key",
|
|
1993
|
+
errorCode: TurnkeyErrorCodes.EXPORT_PRIVATE_KEY_ERROR,
|
|
1994
|
+
});
|
|
1995
|
+
};
|
|
1996
|
+
/**
|
|
1997
|
+
* Exports a wallet account as an encrypted bundle.
|
|
1998
|
+
*
|
|
1999
|
+
* - This function exports the specified wallet account as an encrypted bundle, suitable for backup or transfer.
|
|
2000
|
+
* - The exported bundle contains the wallet account's key material, encrypted to the provided target public key.
|
|
2001
|
+
* - If a targetPublicKey is provided, the bundle will be encrypted to that public key; otherwise, an error will be thrown.
|
|
2002
|
+
* - If an organizationId is provided, the wallet account will be exported under that sub-organization; otherwise, the current session's organizationId is used.
|
|
2003
|
+
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2004
|
+
*
|
|
2005
|
+
* @param params.address - address of the wallet account to export.
|
|
2006
|
+
* @param params.targetPublicKey - public key to encrypt the bundle to.
|
|
2007
|
+
* @param params.organizationId - organization ID to export the wallet account under a specific sub-organization.
|
|
2008
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2009
|
+
* @returns A promise that resolves to an `ExportBundle` object containing the encrypted wallet account and metadata.
|
|
2010
|
+
* @throws {TurnkeyError} If there is no active session, if the targetPublicKey is missing, or if there is an error exporting the wallet account.
|
|
2011
|
+
*
|
|
2012
|
+
*/
|
|
2013
|
+
this.exportWalletAccount = async (params) => {
|
|
2014
|
+
const { address, targetPublicKey, stampWith, organizationId } = params;
|
|
2015
|
+
const session = await this.storageManager.getActiveSession();
|
|
2016
|
+
if (!session) {
|
|
2017
|
+
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1893
2018
|
}
|
|
2019
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2020
|
+
const res = await this.httpClient.exportWalletAccount({
|
|
2021
|
+
address,
|
|
2022
|
+
targetPublicKey,
|
|
2023
|
+
organizationId: organizationId || session.organizationId,
|
|
2024
|
+
}, stampWith);
|
|
2025
|
+
if (!res.exportBundle) {
|
|
2026
|
+
throw new TurnkeyError("No export bundle found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
2027
|
+
}
|
|
2028
|
+
return res.exportBundle;
|
|
2029
|
+
}, {
|
|
2030
|
+
errorMessage: "Failed to export wallet account",
|
|
2031
|
+
errorCode: TurnkeyErrorCodes.EXPORT_WALLET_ACCOUNT_ERROR,
|
|
2032
|
+
});
|
|
1894
2033
|
};
|
|
1895
2034
|
/**
|
|
1896
2035
|
* Imports a wallet from an encrypted bundle.
|
|
@@ -1898,7 +2037,7 @@ class TurnkeyClient {
|
|
|
1898
2037
|
* - This function imports a wallet using the provided encrypted bundle and creates accounts based on the provided parameters.
|
|
1899
2038
|
* - If a userId is provided, the wallet will be imported for that specific user; otherwise, it uses the current session's userId.
|
|
1900
2039
|
* - If an accounts array is provided, those accounts will be created in the imported wallet; otherwise, default Ethereum and Solana accounts will be created.
|
|
1901
|
-
* - The encrypted
|
|
2040
|
+
* - The encrypted bundle MUST be encrypted to
|
|
1902
2041
|
* - Automatically ensures an active session exists before making the request.
|
|
1903
2042
|
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1904
2043
|
*
|
|
@@ -1916,7 +2055,7 @@ class TurnkeyClient {
|
|
|
1916
2055
|
if (!session) {
|
|
1917
2056
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1918
2057
|
}
|
|
1919
|
-
|
|
2058
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1920
2059
|
const res = await this.httpClient.importWallet({
|
|
1921
2060
|
organizationId: session.organizationId,
|
|
1922
2061
|
userId: userId || session.userId,
|
|
@@ -1931,12 +2070,66 @@ class TurnkeyClient {
|
|
|
1931
2070
|
throw new TurnkeyError("No wallet ID found in the import response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1932
2071
|
}
|
|
1933
2072
|
return res.walletId;
|
|
2073
|
+
}, {
|
|
2074
|
+
errorMessage: "Failed to import wallet",
|
|
2075
|
+
errorCode: TurnkeyErrorCodes.IMPORT_WALLET_ERROR,
|
|
2076
|
+
customMessageByMessages: {
|
|
2077
|
+
"invalid mnemonic": {
|
|
2078
|
+
message: "Invalid mnemonic input",
|
|
2079
|
+
code: TurnkeyErrorCodes.BAD_REQUEST,
|
|
2080
|
+
},
|
|
2081
|
+
},
|
|
2082
|
+
});
|
|
2083
|
+
};
|
|
2084
|
+
/**
|
|
2085
|
+
* Imports a private key from an encrypted bundle.
|
|
2086
|
+
*
|
|
2087
|
+
* - This function imports a private key using the provided encrypted bundle.
|
|
2088
|
+
* - If a userId is provided, the private key will be imported for that specific user; otherwise, it uses the current session's userId.
|
|
2089
|
+
* - Requires address formats to
|
|
2090
|
+
* - Automatically infers the cryptographic curve used to generate the private key based on the address format (can be optionally overriden if needed).
|
|
2091
|
+
* - The encrypted bundle MUST be encrypted to ensure security.
|
|
2092
|
+
* - Automatically ensures an active session exists before making the request.
|
|
2093
|
+
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2094
|
+
*
|
|
2095
|
+
* @param params.encryptedBundle - encrypted bundle containing the private key key material and metadata.
|
|
2096
|
+
* @param params.privateKeyName - name of the private key to create upon import.
|
|
2097
|
+
* @param params.curve - the cryptographic curve used to generate a given private key
|
|
2098
|
+
* @param params.addressFormat - address format of the private key to import.
|
|
2099
|
+
* @param params.userId - user ID to import the wallet for a specific user (defaults to the current session's userId).
|
|
2100
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2101
|
+
* @returns A promise that resolves to the ID of the imported wallet.
|
|
2102
|
+
* @throws {TurnkeyError} If there is no active session, if the encrypted bundle is invalid, or if there is an error importing the wallet.
|
|
2103
|
+
*/
|
|
2104
|
+
this.importPrivateKey = async (params) => {
|
|
2105
|
+
const { encryptedBundle, privateKeyName, addressFormats, curve, userId, stampWith, } = params;
|
|
2106
|
+
const session = await this.storageManager.getActiveSession();
|
|
2107
|
+
if (!session) {
|
|
2108
|
+
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1934
2109
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2110
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2111
|
+
const res = await this.httpClient.importPrivateKey({
|
|
2112
|
+
organizationId: session.organizationId,
|
|
2113
|
+
userId: userId || session.userId,
|
|
2114
|
+
encryptedBundle,
|
|
2115
|
+
privateKeyName,
|
|
2116
|
+
curve,
|
|
2117
|
+
addressFormats,
|
|
2118
|
+
}, stampWith);
|
|
2119
|
+
if (!res || !res.privateKeyId) {
|
|
2120
|
+
throw new TurnkeyError("No wallet ID found in the import response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
2121
|
+
}
|
|
2122
|
+
return res.privateKeyId;
|
|
2123
|
+
}, {
|
|
2124
|
+
errorMessage: "Failed to import wallet",
|
|
2125
|
+
errorCode: TurnkeyErrorCodes.IMPORT_WALLET_ERROR,
|
|
2126
|
+
customMessageByMessages: {
|
|
2127
|
+
"invalid mnemonic": {
|
|
2128
|
+
message: "Invalid mnemonic input",
|
|
2129
|
+
code: TurnkeyErrorCodes.BAD_REQUEST,
|
|
2130
|
+
},
|
|
2131
|
+
},
|
|
2132
|
+
});
|
|
1940
2133
|
};
|
|
1941
2134
|
/**
|
|
1942
2135
|
* Deletes the current sub-organization (sub-org) for the active session.
|
|
@@ -1958,14 +2151,12 @@ class TurnkeyClient {
|
|
|
1958
2151
|
if (!session) {
|
|
1959
2152
|
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1960
2153
|
}
|
|
1961
|
-
|
|
2154
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1962
2155
|
return await this.httpClient.deleteSubOrganization({ deleteWithoutExport }, stampWith);
|
|
1963
|
-
}
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
throw new TurnkeyError(`Failed to delete sub-organization`, TurnkeyErrorCodes.DELETE_SUB_ORGANIZATION_ERROR, error);
|
|
1968
|
-
}
|
|
2156
|
+
}, {
|
|
2157
|
+
errorMessage: "Failed to delete sub-organization",
|
|
2158
|
+
errorCode: TurnkeyErrorCodes.DELETE_SUB_ORGANIZATION_ERROR,
|
|
2159
|
+
});
|
|
1969
2160
|
};
|
|
1970
2161
|
/**
|
|
1971
2162
|
* Stores a session token and updates the session associated with the specified session key, or by default the active session.
|
|
@@ -1985,21 +2176,14 @@ class TurnkeyClient {
|
|
|
1985
2176
|
const { sessionToken, sessionKey = SessionKey.DefaultSessionkey } = params;
|
|
1986
2177
|
if (!sessionToken)
|
|
1987
2178
|
return;
|
|
1988
|
-
|
|
1989
|
-
const sessionToReplace = await this.storageManager.getSession(sessionKey);
|
|
2179
|
+
withTurnkeyErrorHandling(async () => {
|
|
1990
2180
|
await this.storageManager.storeSession(sessionToken, sessionKey);
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
}
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
throw error;
|
|
1998
|
-
throw new TurnkeyError(`Failed to store session`, TurnkeyErrorCodes.STORE_SESSION_ERROR, error);
|
|
1999
|
-
}
|
|
2000
|
-
finally {
|
|
2001
|
-
await this.clearUnusedKeyPairs();
|
|
2002
|
-
}
|
|
2181
|
+
}, {
|
|
2182
|
+
errorMessage: "Failed to store session",
|
|
2183
|
+
errorCode: TurnkeyErrorCodes.STORE_SESSION_ERROR,
|
|
2184
|
+
}, {
|
|
2185
|
+
finallyFn: async () => await this.clearUnusedKeyPairs(),
|
|
2186
|
+
});
|
|
2003
2187
|
};
|
|
2004
2188
|
/**
|
|
2005
2189
|
* Clears the session associated with the specified session key, or the active session by default.
|
|
@@ -2015,7 +2199,7 @@ class TurnkeyClient {
|
|
|
2015
2199
|
*/
|
|
2016
2200
|
this.clearSession = async (params) => {
|
|
2017
2201
|
const { sessionKey = SessionKey.DefaultSessionkey } = params || {};
|
|
2018
|
-
|
|
2202
|
+
withTurnkeyErrorHandling(async () => {
|
|
2019
2203
|
const session = await this.storageManager.getSession(sessionKey);
|
|
2020
2204
|
if (session) {
|
|
2021
2205
|
await this.apiKeyStamper?.deleteKeyPair(session.publicKey);
|
|
@@ -2024,12 +2208,10 @@ class TurnkeyClient {
|
|
|
2024
2208
|
else {
|
|
2025
2209
|
throw new TurnkeyError(`No session found with key: ${sessionKey}`, TurnkeyErrorCodes.NOT_FOUND);
|
|
2026
2210
|
}
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
throw new TurnkeyError(`Failed to delete session`, TurnkeyErrorCodes.CLEAR_SESSION_ERROR, error);
|
|
2032
|
-
}
|
|
2211
|
+
}, {
|
|
2212
|
+
errorMessage: "Failed to delete session",
|
|
2213
|
+
errorCode: TurnkeyErrorCodes.CLEAR_SESSION_ERROR,
|
|
2214
|
+
});
|
|
2033
2215
|
};
|
|
2034
2216
|
/**
|
|
2035
2217
|
* Clears all sessions and resets the active session state.
|
|
@@ -2043,7 +2225,7 @@ class TurnkeyClient {
|
|
|
2043
2225
|
* @throws {TurnkeyError} If no sessions exist or if there is an error clearing all sessions.
|
|
2044
2226
|
*/
|
|
2045
2227
|
this.clearAllSessions = async () => {
|
|
2046
|
-
|
|
2228
|
+
withTurnkeyErrorHandling(async () => {
|
|
2047
2229
|
const sessionKeys = await this.storageManager.listSessionKeys();
|
|
2048
2230
|
if (sessionKeys.length === 0) {
|
|
2049
2231
|
throw new TurnkeyError("No sessions found to clear.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
@@ -2051,12 +2233,10 @@ class TurnkeyClient {
|
|
|
2051
2233
|
for (const sessionKey of sessionKeys) {
|
|
2052
2234
|
this.clearSession({ sessionKey });
|
|
2053
2235
|
}
|
|
2054
|
-
}
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
throw new TurnkeyError(`Failed to clear all sessions`, TurnkeyErrorCodes.CLEAR_ALL_SESSIONS_ERROR, error);
|
|
2059
|
-
}
|
|
2236
|
+
}, {
|
|
2237
|
+
errorMessage: "Failed to clear all sessions",
|
|
2238
|
+
errorCode: TurnkeyErrorCodes.CLEAR_ALL_SESSIONS_ERROR,
|
|
2239
|
+
});
|
|
2060
2240
|
};
|
|
2061
2241
|
/**
|
|
2062
2242
|
* Refreshes the session associated with the specified session key, or the active session by default.
|
|
@@ -2091,7 +2271,7 @@ class TurnkeyClient {
|
|
|
2091
2271
|
throw new TurnkeyError("HTTP client is not initialized. Please initialize the client before refreshing the session.", TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
2092
2272
|
}
|
|
2093
2273
|
let keyPair;
|
|
2094
|
-
|
|
2274
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2095
2275
|
keyPair = publicKey ?? (await this.apiKeyStamper?.createKeyPair());
|
|
2096
2276
|
if (!keyPair) {
|
|
2097
2277
|
throw new TurnkeyError("Failed to create new key pair.", TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
@@ -2109,12 +2289,10 @@ class TurnkeyClient {
|
|
|
2109
2289
|
...(sessionKey && { sessionKey }),
|
|
2110
2290
|
});
|
|
2111
2291
|
return res;
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
throw new TurnkeyError(`Failed to refresh session`, TurnkeyErrorCodes.REFRESH_SESSION_ERROR, error);
|
|
2117
|
-
}
|
|
2292
|
+
}, {
|
|
2293
|
+
errorMessage: "Failed to refresh session",
|
|
2294
|
+
errorCode: TurnkeyErrorCodes.REFRESH_SESSION_ERROR,
|
|
2295
|
+
});
|
|
2118
2296
|
};
|
|
2119
2297
|
/**
|
|
2120
2298
|
* Retrieves the session associated with the specified session key, or the active session by default.
|
|
@@ -2128,15 +2306,13 @@ class TurnkeyClient {
|
|
|
2128
2306
|
* @throws {TurnkeyError} If there is an error retrieving the session from storage.
|
|
2129
2307
|
*/
|
|
2130
2308
|
this.getSession = async (params) => {
|
|
2131
|
-
|
|
2309
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2132
2310
|
const { sessionKey = await this.storageManager.getActiveSessionKey() } = params || {};
|
|
2133
2311
|
return this.storageManager.getSession(sessionKey);
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
throw new TurnkeyError(`Failed to get session with key`, TurnkeyErrorCodes.GET_SESSION_ERROR, error);
|
|
2139
|
-
}
|
|
2312
|
+
}, {
|
|
2313
|
+
errorMessage: "Failed to get session with key " + params?.sessionKey,
|
|
2314
|
+
errorCode: TurnkeyErrorCodes.GET_SESSION_ERROR,
|
|
2315
|
+
});
|
|
2140
2316
|
};
|
|
2141
2317
|
/**
|
|
2142
2318
|
* Retrieves all sessions stored in persistent storage.
|
|
@@ -2150,7 +2326,7 @@ class TurnkeyClient {
|
|
|
2150
2326
|
* @throws {TurnkeyError} If there is an error retrieving sessions from storage.
|
|
2151
2327
|
*/
|
|
2152
2328
|
this.getAllSessions = async () => {
|
|
2153
|
-
|
|
2329
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2154
2330
|
const sessionKeys = await this.storageManager.listSessionKeys();
|
|
2155
2331
|
if (!sessionKeys || sessionKeys.length === 0) {
|
|
2156
2332
|
return undefined;
|
|
@@ -2162,13 +2338,11 @@ class TurnkeyClient {
|
|
|
2162
2338
|
sessions[sessionKey] = session;
|
|
2163
2339
|
}
|
|
2164
2340
|
}
|
|
2165
|
-
return sessions;
|
|
2166
|
-
}
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
throw new TurnkeyError(`Failed to get all sessions`, TurnkeyErrorCodes.GET_ALL_SESSIONS_ERROR, error);
|
|
2171
|
-
}
|
|
2341
|
+
return sessions || undefined;
|
|
2342
|
+
}, {
|
|
2343
|
+
errorMessage: "Failed to get all sessions",
|
|
2344
|
+
errorCode: TurnkeyErrorCodes.GET_ALL_SESSIONS_ERROR,
|
|
2345
|
+
});
|
|
2172
2346
|
};
|
|
2173
2347
|
/**
|
|
2174
2348
|
* Sets the active session to the specified session key.
|
|
@@ -2184,14 +2358,12 @@ class TurnkeyClient {
|
|
|
2184
2358
|
*/
|
|
2185
2359
|
this.setActiveSession = async (params) => {
|
|
2186
2360
|
const { sessionKey } = params;
|
|
2187
|
-
|
|
2361
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2188
2362
|
await this.storageManager.setActiveSessionKey(sessionKey);
|
|
2189
|
-
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
throw new TurnkeyError(`Failed to set active session`, TurnkeyErrorCodes.SET_ACTIVE_SESSION_ERROR, error);
|
|
2194
|
-
}
|
|
2363
|
+
}, {
|
|
2364
|
+
errorMessage: "Failed to set active session",
|
|
2365
|
+
errorCode: TurnkeyErrorCodes.SET_ACTIVE_SESSION_ERROR,
|
|
2366
|
+
});
|
|
2195
2367
|
};
|
|
2196
2368
|
/**
|
|
2197
2369
|
* Retrieves the active session key currently set in persistent storage.
|
|
@@ -2205,14 +2377,12 @@ class TurnkeyClient {
|
|
|
2205
2377
|
* @throws {TurnkeyError} If there is an error retrieving the active session key from storage.
|
|
2206
2378
|
*/
|
|
2207
2379
|
this.getActiveSessionKey = async () => {
|
|
2208
|
-
|
|
2380
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2209
2381
|
return await this.storageManager.getActiveSessionKey();
|
|
2210
|
-
}
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
throw new TurnkeyError(`Failed to get active session key`, TurnkeyErrorCodes.GET_ACTIVE_SESSION_KEY_ERROR, error);
|
|
2215
|
-
}
|
|
2382
|
+
}, {
|
|
2383
|
+
errorMessage: "Failed to get active session key",
|
|
2384
|
+
errorCode: TurnkeyErrorCodes.GET_ACTIVE_SESSION_KEY_ERROR,
|
|
2385
|
+
});
|
|
2216
2386
|
};
|
|
2217
2387
|
/**
|
|
2218
2388
|
* Clears any unused API key pairs from persistent storage.
|
|
@@ -2226,7 +2396,7 @@ class TurnkeyClient {
|
|
|
2226
2396
|
* @throws {TurnkeyError} If there is an error listing, checking, or deleting unused key pairs.
|
|
2227
2397
|
*/
|
|
2228
2398
|
this.clearUnusedKeyPairs = async () => {
|
|
2229
|
-
|
|
2399
|
+
withTurnkeyErrorHandling(async () => {
|
|
2230
2400
|
const publicKeys = await this.apiKeyStamper?.listKeyPairs();
|
|
2231
2401
|
if (!publicKeys || publicKeys.length === 0) {
|
|
2232
2402
|
return;
|
|
@@ -2249,12 +2419,10 @@ class TurnkeyClient {
|
|
|
2249
2419
|
}
|
|
2250
2420
|
}
|
|
2251
2421
|
}
|
|
2252
|
-
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
throw new TurnkeyError(`Failed to clear unused key pairs`, TurnkeyErrorCodes.CLEAR_UNUSED_KEY_PAIRS_ERROR, error);
|
|
2257
|
-
}
|
|
2422
|
+
}, {
|
|
2423
|
+
errorMessage: "Failed to clear unused key pairs",
|
|
2424
|
+
errorCode: TurnkeyErrorCodes.CLEAR_UNUSED_KEY_PAIRS_ERROR,
|
|
2425
|
+
});
|
|
2258
2426
|
};
|
|
2259
2427
|
/**
|
|
2260
2428
|
* Creates a new API key pair and returns the public key.
|
|
@@ -2271,23 +2439,21 @@ class TurnkeyClient {
|
|
|
2271
2439
|
* @throws {TurnkeyError} If the API key stamper is not initialized or if there is an error during key pair creation or storage.
|
|
2272
2440
|
*/
|
|
2273
2441
|
this.createApiKeyPair = async (params) => {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2442
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2443
|
+
const externalKeyPair = params?.externalKeyPair;
|
|
2444
|
+
const storeOverride = params?.storeOverride ?? false;
|
|
2445
|
+
if (!this.apiKeyStamper) {
|
|
2446
|
+
throw new TurnkeyError("API Key Stamper is not initialized.", TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
2447
|
+
}
|
|
2280
2448
|
const publicKey = await this.apiKeyStamper.createKeyPair(externalKeyPair ? externalKeyPair : undefined);
|
|
2281
2449
|
if (storeOverride && publicKey) {
|
|
2282
2450
|
await this.apiKeyStamper.setPublicKeyOverride(publicKey);
|
|
2283
2451
|
}
|
|
2284
2452
|
return publicKey;
|
|
2285
|
-
}
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
throw new TurnkeyError(`Failed to create API key pair`, TurnkeyErrorCodes.CREATE_API_KEY_PAIR_ERROR, error);
|
|
2290
|
-
}
|
|
2453
|
+
}, {
|
|
2454
|
+
errorMessage: "Failed to create API key pair",
|
|
2455
|
+
errorCode: TurnkeyErrorCodes.CREATE_API_KEY_PAIR_ERROR,
|
|
2456
|
+
});
|
|
2291
2457
|
};
|
|
2292
2458
|
/**
|
|
2293
2459
|
* Fetches the WalletKit proxy authentication configuration from the auth proxy.
|
|
@@ -2301,18 +2467,16 @@ class TurnkeyClient {
|
|
|
2301
2467
|
* @throws {TurnkeyError} If there is an error retrieving the proxy authentication configuration from the auth proxy.
|
|
2302
2468
|
*/
|
|
2303
2469
|
this.getProxyAuthConfig = async () => {
|
|
2304
|
-
|
|
2470
|
+
return withTurnkeyErrorHandling(async () => {
|
|
2305
2471
|
const res = await this.httpClient.proxyGetWalletKitConfig({});
|
|
2306
2472
|
if (!res) {
|
|
2307
2473
|
throw new TurnkeyError(`Failed to fetch auth proxy config`, TurnkeyErrorCodes.GET_PROXY_AUTH_CONFIG_ERROR);
|
|
2308
2474
|
}
|
|
2309
2475
|
return res;
|
|
2310
|
-
}
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
throw new TurnkeyError(`Failed to get auth proxy config`, TurnkeyErrorCodes.GET_PROXY_AUTH_CONFIG_ERROR, error);
|
|
2315
|
-
}
|
|
2476
|
+
}, {
|
|
2477
|
+
errorMessage: "Failed to get auth proxy config",
|
|
2478
|
+
errorCode: TurnkeyErrorCodes.GET_PROXY_AUTH_CONFIG_ERROR,
|
|
2479
|
+
});
|
|
2316
2480
|
};
|
|
2317
2481
|
this.config = config;
|
|
2318
2482
|
// Just store any explicitly provided stampers
|