@turnkey/core 1.0.0-beta.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.MD +3 -1
- package/dist/__clients__/core.d.ts +196 -324
- package/dist/__clients__/core.d.ts.map +1 -1
- package/dist/__clients__/core.js +571 -271
- package/dist/__clients__/core.js.map +1 -1
- package/dist/__clients__/core.mjs +522 -222
- package/dist/__clients__/core.mjs.map +1 -1
- package/dist/__generated__/sdk-client-base.d.ts +8 -2
- package/dist/__generated__/sdk-client-base.d.ts.map +1 -1
- package/dist/__generated__/sdk-client-base.js +95 -6
- package/dist/__generated__/sdk-client-base.js.map +1 -1
- package/dist/__generated__/sdk-client-base.mjs +90 -1
- package/dist/__generated__/sdk-client-base.mjs.map +1 -1
- package/dist/__generated__/version.d.ts +1 -1
- package/dist/__generated__/version.d.ts.map +1 -1
- package/dist/__generated__/version.js +1 -1
- package/dist/__generated__/version.mjs +1 -1
- package/dist/__inputs__/public_api.types.d.ts +163 -26
- package/dist/__inputs__/public_api.types.d.ts.map +1 -1
- package/dist/__polyfills__/window.js.map +1 -1
- package/dist/__polyfills__/window.mjs.map +1 -1
- package/dist/__stampers__/api/base.d.ts +1 -1
- package/dist/__stampers__/api/base.d.ts.map +1 -1
- package/dist/__stampers__/api/base.js.map +1 -1
- package/dist/__stampers__/api/base.mjs.map +1 -1
- package/dist/__stampers__/api/mobile/stamper.d.ts +1 -1
- package/dist/__stampers__/api/mobile/stamper.d.ts.map +1 -1
- package/dist/__stampers__/api/mobile/stamper.js.map +1 -1
- package/dist/__stampers__/api/mobile/stamper.mjs.map +1 -1
- package/dist/__stampers__/api/web/stamper.d.ts +1 -1
- package/dist/__stampers__/api/web/stamper.d.ts.map +1 -1
- package/dist/__stampers__/api/web/stamper.js.map +1 -1
- package/dist/__stampers__/api/web/stamper.mjs.map +1 -1
- package/dist/__stampers__/passkey/base.d.ts +1 -1
- package/dist/__stampers__/passkey/base.d.ts.map +1 -1
- package/dist/__stampers__/passkey/base.js.map +1 -1
- package/dist/__stampers__/passkey/base.mjs.map +1 -1
- package/dist/__storage__/base.d.ts +1 -1
- package/dist/__storage__/base.d.ts.map +1 -1
- package/dist/__storage__/base.js.map +1 -1
- package/dist/__storage__/base.mjs.map +1 -1
- package/dist/__storage__/mobile/storage.d.ts +1 -1
- package/dist/__storage__/mobile/storage.d.ts.map +1 -1
- package/dist/__storage__/mobile/storage.js +4 -3
- package/dist/__storage__/mobile/storage.js.map +1 -1
- package/dist/__storage__/mobile/storage.mjs +2 -1
- package/dist/__storage__/mobile/storage.mjs.map +1 -1
- package/dist/__storage__/web/storage.d.ts +1 -1
- package/dist/__storage__/web/storage.d.ts.map +1 -1
- package/dist/__storage__/web/storage.js +4 -3
- package/dist/__storage__/web/storage.js.map +1 -1
- package/dist/__storage__/web/storage.mjs +2 -1
- package/dist/__storage__/web/storage.mjs.map +1 -1
- package/dist/__typedoc-entry__/index.d.ts +3 -0
- package/dist/__typedoc-entry__/index.d.ts.map +1 -0
- package/dist/__types__/auth.d.ts +150 -0
- package/dist/__types__/auth.d.ts.map +1 -0
- package/dist/__types__/auth.js +43 -0
- package/dist/__types__/auth.js.map +1 -0
- package/dist/__types__/auth.mjs +40 -0
- package/dist/__types__/auth.mjs.map +1 -0
- package/dist/__types__/config.d.ts +140 -0
- package/dist/__types__/config.d.ts.map +1 -0
- package/dist/__types__/error.d.ts +13 -0
- package/dist/__types__/error.d.ts.map +1 -0
- package/dist/__types__/error.js +18 -0
- package/dist/__types__/error.js.map +1 -0
- package/dist/__types__/error.mjs +16 -0
- package/dist/__types__/error.mjs.map +1 -0
- package/dist/__types__/export.d.ts +10 -0
- package/dist/__types__/export.d.ts.map +1 -0
- package/dist/__types__/external-wallets.d.ts +202 -0
- package/dist/__types__/external-wallets.d.ts.map +1 -0
- package/dist/__types__/external-wallets.js +35 -0
- package/dist/__types__/external-wallets.js.map +1 -0
- package/dist/__types__/external-wallets.mjs +35 -0
- package/dist/__types__/external-wallets.mjs.map +1 -0
- package/dist/__types__/index.d.ts +7 -0
- package/dist/__types__/index.d.ts.map +1 -0
- package/dist/__types__/method-types.d.ts +314 -0
- package/dist/__types__/method-types.d.ts.map +1 -0
- package/dist/__wallet__/base.d.ts +1 -1
- package/dist/__wallet__/base.d.ts.map +1 -1
- package/dist/__wallet__/base.js +6 -6
- package/dist/__wallet__/base.js.map +1 -1
- package/dist/__wallet__/base.mjs +2 -2
- package/dist/__wallet__/base.mjs.map +1 -1
- package/dist/__wallet__/connector.d.ts +3 -3
- package/dist/__wallet__/connector.d.ts.map +1 -1
- package/dist/__wallet__/connector.js +5 -4
- package/dist/__wallet__/connector.js.map +1 -1
- package/dist/__wallet__/connector.mjs +4 -3
- package/dist/__wallet__/connector.mjs.map +1 -1
- package/dist/__wallet__/mobile/manager.d.ts +1 -1
- package/dist/__wallet__/mobile/manager.d.ts.map +1 -1
- package/dist/__wallet__/mobile/manager.js +5 -4
- package/dist/__wallet__/mobile/manager.js.map +1 -1
- package/dist/__wallet__/mobile/manager.mjs +2 -1
- package/dist/__wallet__/mobile/manager.mjs.map +1 -1
- package/dist/__wallet__/stamper.d.ts +1 -1
- package/dist/__wallet__/stamper.d.ts.map +1 -1
- package/dist/__wallet__/stamper.js +9 -8
- package/dist/__wallet__/stamper.js.map +1 -1
- package/dist/__wallet__/stamper.mjs +2 -1
- package/dist/__wallet__/stamper.mjs.map +1 -1
- package/dist/__wallet__/wallet-connect/base.d.ts +4 -2
- package/dist/__wallet__/wallet-connect/base.d.ts.map +1 -1
- package/dist/__wallet__/wallet-connect/base.js +74 -32
- package/dist/__wallet__/wallet-connect/base.js.map +1 -1
- package/dist/__wallet__/wallet-connect/base.mjs +55 -13
- package/dist/__wallet__/wallet-connect/base.mjs.map +1 -1
- package/dist/__wallet__/wallet-connect/client.d.ts +30 -9
- package/dist/__wallet__/wallet-connect/client.d.ts.map +1 -1
- package/dist/__wallet__/wallet-connect/client.js +73 -11
- package/dist/__wallet__/wallet-connect/client.js.map +1 -1
- package/dist/__wallet__/wallet-connect/client.mjs +73 -11
- package/dist/__wallet__/wallet-connect/client.mjs.map +1 -1
- package/dist/__wallet__/web/manager.d.ts +1 -1
- package/dist/__wallet__/web/manager.d.ts.map +1 -1
- package/dist/__wallet__/web/manager.js +11 -10
- package/dist/__wallet__/web/manager.js.map +1 -1
- package/dist/__wallet__/web/manager.mjs +2 -1
- package/dist/__wallet__/web/manager.mjs.map +1 -1
- package/dist/__wallet__/web/native/ethereum.d.ts +3 -3
- package/dist/__wallet__/web/native/ethereum.d.ts.map +1 -1
- package/dist/__wallet__/web/native/ethereum.js +11 -10
- package/dist/__wallet__/web/native/ethereum.js.map +1 -1
- package/dist/__wallet__/web/native/ethereum.mjs +4 -3
- package/dist/__wallet__/web/native/ethereum.mjs.map +1 -1
- package/dist/__wallet__/web/native/solana.d.ts +3 -3
- package/dist/__wallet__/web/native/solana.d.ts.map +1 -1
- package/dist/__wallet__/web/native/solana.js +13 -13
- package/dist/__wallet__/web/native/solana.js.map +1 -1
- package/dist/__wallet__/web/native/solana.mjs +8 -8
- 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 +29 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +4 -2
- package/dist/index.mjs.map +1 -1
- package/dist/turnkey-helpers.js.map +1 -1
- package/dist/turnkey-helpers.mjs.map +1 -1
- package/dist/utils.d.ts +11 -23
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +120 -45
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +102 -30
- package/dist/utils.mjs.map +1 -1
- package/package.json +8 -9
- package/dist/__types__/base.d.ts +0 -527
- package/dist/__types__/base.d.ts.map +0 -1
- package/dist/__types__/base.js +0 -89
- package/dist/__types__/base.js.map +0 -1
- package/dist/__types__/base.mjs +0 -85
- package/dist/__types__/base.mjs.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { TurnkeySDKClientBase } from '../__generated__/sdk-client-base.mjs';
|
|
2
2
|
import { TurnkeyErrorCodes, TurnkeyError, TurnkeyNetworkError, AuthAction } from '@turnkey/sdk-types';
|
|
3
|
-
import { SessionKey, DEFAULT_SESSION_EXPIRATION_IN_SECONDS, StamperType,
|
|
4
|
-
import {
|
|
3
|
+
import { SessionKey, DEFAULT_SESSION_EXPIRATION_IN_SECONDS, StamperType, FilterType, OtpTypeToFilterTypeMap, OtpType } from '../__types__/auth.mjs';
|
|
4
|
+
import { WalletSource, Chain, Curve, SignIntent } from '../__types__/external-wallets.mjs';
|
|
5
|
+
import { withTurnkeyErrorHandling, isValidPasskeyName, isWeb, isReactNative, buildSignUpBody, findWalletProviderFromAddress, addressFromPublicKey, getCurveTypeFromProvider, getPublicKeyFromStampHeader, mapAccountsToWallet, toExternalTimestamp, getAuthenticatorAddresses, isEthereumProvider, isSolanaProvider, getActiveSessionOrThrowIfRequired, getHashFunction, getEncodingType, getEncodedMessage, splitSignature, broadcastTransaction, getPolicySignature, googleISS, isWalletAccountArray, generateWalletAccountsFromAddressFormat } from '../utils.mjs';
|
|
5
6
|
import { createStorageManager } from '../__storage__/base.mjs';
|
|
6
7
|
import { CrossPlatformApiKeyStamper } from '../__stampers__/api/base.mjs';
|
|
7
8
|
import { CrossPlatformPasskeyStamper } from '../__stampers__/passkey/base.mjs';
|
|
@@ -22,29 +23,30 @@ class TurnkeyClient {
|
|
|
22
23
|
* - The resulting attestation and challenge can be used to register the passkey with Turnkey.
|
|
23
24
|
*
|
|
24
25
|
* @param params.name - display name for the passkey (defaults to a generated name based on the current timestamp).
|
|
25
|
-
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
26
26
|
* @param params.challenge - challenge string to use for passkey registration. If not provided, a new challenge will be generated.
|
|
27
|
-
* @returns A promise that resolves to
|
|
28
|
-
* - attestation: attestation object returned from the passkey creation process.
|
|
29
|
-
* - encodedChallenge: encoded challenge string used for passkey registration.
|
|
27
|
+
* @returns A promise that resolves to {@link CreatePasskeyResult}
|
|
30
28
|
* @throws {TurnkeyError} If there is an error during passkey creation, or if the platform is unsupported.
|
|
31
29
|
*/
|
|
32
30
|
this.createPasskey = async (params) => {
|
|
31
|
+
const { name: nameFromParams, challenge } = params || {};
|
|
33
32
|
return withTurnkeyErrorHandling(async () => {
|
|
34
|
-
|
|
33
|
+
if (!this.passkeyStamper) {
|
|
34
|
+
throw new TurnkeyError("Passkey stamper is not initialized", TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
35
|
+
}
|
|
36
|
+
const name = isValidPasskeyName(nameFromParams || `passkey-${Date.now()}`);
|
|
35
37
|
let passkey;
|
|
36
38
|
if (isWeb()) {
|
|
37
|
-
const res = await this.passkeyStamper
|
|
39
|
+
const res = await this.passkeyStamper.createWebPasskey({
|
|
38
40
|
publicKey: {
|
|
39
41
|
user: {
|
|
40
42
|
name,
|
|
41
43
|
displayName: name,
|
|
42
44
|
},
|
|
43
|
-
...(
|
|
45
|
+
...(challenge && { challenge }),
|
|
44
46
|
},
|
|
45
47
|
});
|
|
46
48
|
if (!res) {
|
|
47
|
-
throw new TurnkeyError("Failed to create
|
|
49
|
+
throw new TurnkeyError("Failed to create Web passkey", TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
48
50
|
}
|
|
49
51
|
passkey = {
|
|
50
52
|
encodedChallenge: res?.encodedChallenge,
|
|
@@ -52,7 +54,7 @@ class TurnkeyClient {
|
|
|
52
54
|
};
|
|
53
55
|
}
|
|
54
56
|
else if (isReactNative()) {
|
|
55
|
-
const res = await this.passkeyStamper
|
|
57
|
+
const res = await this.passkeyStamper.createReactNativePasskey({
|
|
56
58
|
name,
|
|
57
59
|
displayName: name,
|
|
58
60
|
});
|
|
@@ -71,7 +73,7 @@ class TurnkeyClient {
|
|
|
71
73
|
}, {
|
|
72
74
|
errorMessage: "Failed to create passkey",
|
|
73
75
|
errorCode: TurnkeyErrorCodes.CREATE_PASSKEY_ERROR,
|
|
74
|
-
|
|
76
|
+
customErrorsByMessages: {
|
|
75
77
|
"timed out or was not allowed": {
|
|
76
78
|
message: "Passkey creation was cancelled by the user.",
|
|
77
79
|
code: TurnkeyErrorCodes.SELECT_PASSKEY_CANCELLED,
|
|
@@ -125,6 +127,7 @@ class TurnkeyClient {
|
|
|
125
127
|
* @param params.publicKey - public key to use for authentication. If not provided, a new key pair will be generated.
|
|
126
128
|
* @param params.sessionKey - session key to use for session creation (defaults to the default session key).
|
|
127
129
|
* @param params.expirationSeconds - session expiration time in seconds (defaults to the configured default).
|
|
130
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
128
131
|
* @returns A promise that resolves to a {@link PasskeyAuthResult}, which includes:
|
|
129
132
|
* - `sessionToken`: the signed JWT session token.
|
|
130
133
|
* - `credentialId`: an empty string.
|
|
@@ -142,7 +145,7 @@ class TurnkeyClient {
|
|
|
142
145
|
}
|
|
143
146
|
const sessionResponse = await this.httpClient.stampLogin({
|
|
144
147
|
publicKey: generatedPublicKey,
|
|
145
|
-
organizationId: this.config.organizationId,
|
|
148
|
+
organizationId: params?.organizationId ?? this.config.organizationId,
|
|
146
149
|
expirationSeconds,
|
|
147
150
|
}, StamperType.Passkey);
|
|
148
151
|
await this.storeSession({
|
|
@@ -160,7 +163,7 @@ class TurnkeyClient {
|
|
|
160
163
|
}, {
|
|
161
164
|
errorMessage: "Unable to log in with the provided passkey",
|
|
162
165
|
errorCode: TurnkeyErrorCodes.PASSKEY_LOGIN_AUTH_ERROR,
|
|
163
|
-
|
|
166
|
+
customErrorsByMessages: {
|
|
164
167
|
"timed out or was not allowed": {
|
|
165
168
|
message: "Passkey login was cancelled by the user.",
|
|
166
169
|
code: TurnkeyErrorCodes.SELECT_PASSKEY_CANCELLED,
|
|
@@ -193,13 +196,14 @@ class TurnkeyClient {
|
|
|
193
196
|
* @param params.sessionKey - session key to use for storing the session (defaults to the default session key).
|
|
194
197
|
* @param params.expirationSeconds - session expiration time in seconds (defaults to the configured default).
|
|
195
198
|
* @param params.challenge - challenge string to use for passkey registration. If not provided, a new challenge will be generated.
|
|
199
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
196
200
|
* @returns A promise that resolves to a {@link PasskeyAuthResult}, which includes:
|
|
197
201
|
* - `sessionToken`: the signed JWT session token.
|
|
198
202
|
* - `credentialId`: the credential ID associated with the passkey created.
|
|
199
203
|
* @throws {TurnkeyError} If there is an error during passkey creation, sub-organization creation, or session storage.
|
|
200
204
|
*/
|
|
201
205
|
this.signUpWithPasskey = async (params) => {
|
|
202
|
-
const { createSubOrgParams, passkeyDisplayName, sessionKey = SessionKey.DefaultSessionkey, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, } = params || {};
|
|
206
|
+
const { createSubOrgParams, passkeyDisplayName, sessionKey = SessionKey.DefaultSessionkey, expirationSeconds = DEFAULT_SESSION_EXPIRATION_IN_SECONDS, organizationId, } = params || {};
|
|
203
207
|
let generatedPublicKey = undefined;
|
|
204
208
|
return withTurnkeyErrorHandling(async () => {
|
|
205
209
|
generatedPublicKey = await this.apiKeyStamper?.createKeyPair();
|
|
@@ -242,7 +246,7 @@ class TurnkeyClient {
|
|
|
242
246
|
this.apiKeyStamper?.setTemporaryPublicKey(generatedPublicKey);
|
|
243
247
|
const sessionResponse = await this.httpClient.stampLogin({
|
|
244
248
|
publicKey: newGeneratedKeyPair,
|
|
245
|
-
organizationId: this.config.organizationId,
|
|
249
|
+
organizationId: organizationId ?? this.config.organizationId,
|
|
246
250
|
expirationSeconds,
|
|
247
251
|
});
|
|
248
252
|
await this.apiKeyStamper?.deleteKeyPair(generatedPublicKey);
|
|
@@ -282,7 +286,7 @@ class TurnkeyClient {
|
|
|
282
286
|
* @returns A promise that resolves to an array of wallet providers.
|
|
283
287
|
* @throws {TurnkeyError} If the wallet manager is uninitialized or provider retrieval fails.
|
|
284
288
|
*/
|
|
285
|
-
this.
|
|
289
|
+
this.fetchWalletProviders = async (chain) => {
|
|
286
290
|
return withTurnkeyErrorHandling(async () => {
|
|
287
291
|
if (!this.walletManager) {
|
|
288
292
|
throw new TurnkeyError("Wallet manager is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
@@ -299,7 +303,7 @@ class TurnkeyClient {
|
|
|
299
303
|
* - Requires the wallet manager and its connector to be initialized.
|
|
300
304
|
*
|
|
301
305
|
* @param walletProvider - wallet provider to connect.
|
|
302
|
-
* @returns A promise that resolves
|
|
306
|
+
* @returns A promise that resolves with the connected wallet's address.
|
|
303
307
|
* @throws {TurnkeyError} If the wallet manager is uninitialized or the connection fails.
|
|
304
308
|
*/
|
|
305
309
|
this.connectWalletAccount = async (walletProvider) => {
|
|
@@ -307,7 +311,7 @@ class TurnkeyClient {
|
|
|
307
311
|
if (!this.walletManager?.connector) {
|
|
308
312
|
throw new TurnkeyError("Wallet connector is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
309
313
|
}
|
|
310
|
-
await this.walletManager.connector.connectWalletAccount(walletProvider);
|
|
314
|
+
return await this.walletManager.connector.connectWalletAccount(walletProvider);
|
|
311
315
|
}, {
|
|
312
316
|
errorMessage: "Unable to connect wallet account",
|
|
313
317
|
errorCode: TurnkeyErrorCodes.CONNECT_WALLET_ACCOUNT_ERROR,
|
|
@@ -344,7 +348,7 @@ class TurnkeyClient {
|
|
|
344
348
|
*
|
|
345
349
|
* @param params.walletAccount - The wallet account whose provider should be switched.
|
|
346
350
|
* @param params.chainOrId - The target chain, specified as a chain ID string or a SwitchableChain object.
|
|
347
|
-
* @param params.walletProviders - Optional list of wallet providers to search; falls back to `
|
|
351
|
+
* @param params.walletProviders - Optional list of wallet providers to search; falls back to `fetchWalletProviders()` if omitted.
|
|
348
352
|
* @returns A promise that resolves once the chain switch is complete.
|
|
349
353
|
*
|
|
350
354
|
* @throws {TurnkeyError} If the wallet manager is uninitialized, the provider is not connected, or the switch fails.
|
|
@@ -358,7 +362,7 @@ class TurnkeyClient {
|
|
|
358
362
|
if (walletAccount.source === WalletSource.Embedded) {
|
|
359
363
|
throw new TurnkeyError("You can only switch chains for connected wallet accounts", TurnkeyErrorCodes.NOT_FOUND);
|
|
360
364
|
}
|
|
361
|
-
const providers = walletProviders ?? (await this.
|
|
365
|
+
const providers = walletProviders ?? (await this.fetchWalletProviders());
|
|
362
366
|
const walletProvider = findWalletProviderFromAddress(walletAccount.address, providers);
|
|
363
367
|
if (!walletProvider) {
|
|
364
368
|
throw new TurnkeyError("Wallet provider not found", TurnkeyErrorCodes.SWITCH_WALLET_CHAIN_ERROR);
|
|
@@ -386,6 +390,7 @@ class TurnkeyClient {
|
|
|
386
390
|
* @param params.publicKey - optional public key to associate with the session (generated if not provided).
|
|
387
391
|
* @param params.sessionKey - optional key to store the session under (defaults to the default session key).
|
|
388
392
|
* @param params.expirationSeconds - optional session expiration time in seconds (defaults to the configured default).
|
|
393
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
389
394
|
* @returns A promise that resolves to a {@link WalletAuthResult}, which includes:
|
|
390
395
|
* - `sessionToken`: the signed JWT session token.
|
|
391
396
|
* - `address`: the authenticated wallet address.
|
|
@@ -406,7 +411,7 @@ class TurnkeyClient {
|
|
|
406
411
|
this.walletManager.stamper.setProvider(walletProvider.interfaceType, walletProvider);
|
|
407
412
|
const sessionResponse = await this.httpClient.stampLogin({
|
|
408
413
|
publicKey,
|
|
409
|
-
organizationId: this.config.organizationId,
|
|
414
|
+
organizationId: params?.organizationId ?? this.config.organizationId,
|
|
410
415
|
expirationSeconds,
|
|
411
416
|
}, StamperType.Wallet);
|
|
412
417
|
await this.storeSession({
|
|
@@ -450,6 +455,7 @@ class TurnkeyClient {
|
|
|
450
455
|
* @param params.createSubOrgParams - parameters for creating a sub-organization (e.g., authenticators, user metadata).
|
|
451
456
|
* @param params.sessionKey - session key to use for storing the session (defaults to the default session key).
|
|
452
457
|
* @param params.expirationSeconds - session expiration time in seconds (defaults to the configured default).
|
|
458
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
453
459
|
* @returns A promise that resolves to a {@link WalletAuthResult}, which includes:
|
|
454
460
|
* - `sessionToken`: the signed JWT session token.
|
|
455
461
|
* - `address`: the authenticated wallet address.
|
|
@@ -541,6 +547,7 @@ class TurnkeyClient {
|
|
|
541
547
|
* @param params.createSubOrgParams - optional parameters for creating a sub-organization (e.g., authenticators, user metadata).
|
|
542
548
|
* @param params.sessionKey - session key to use for storing the session (defaults to the default session key).
|
|
543
549
|
* @param params.expirationSeconds - session expiration time in seconds (defaults to the configured default).
|
|
550
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
544
551
|
* @returns A promise that resolves to an object containing:
|
|
545
552
|
* - `sessionToken`: the signed JWT session token.
|
|
546
553
|
* - `address`: the authenticated wallet address.
|
|
@@ -571,7 +578,11 @@ class TurnkeyClient {
|
|
|
571
578
|
}, {
|
|
572
579
|
errorMessage: "Failed to create stamped request for wallet login",
|
|
573
580
|
errorCode: TurnkeyErrorCodes.WALLET_LOGIN_OR_SIGNUP_ERROR,
|
|
574
|
-
|
|
581
|
+
customErrorsByMessages: {
|
|
582
|
+
"WalletConnect: The connection request has expired. Please scan the QR code again.": {
|
|
583
|
+
message: "Your WalletConnect session expired. Please scan the QR code again.",
|
|
584
|
+
code: TurnkeyErrorCodes.WALLET_CONNECT_EXPIRED,
|
|
585
|
+
},
|
|
575
586
|
"Failed to sign the message": {
|
|
576
587
|
message: "Wallet auth was cancelled by the user.",
|
|
577
588
|
code: TurnkeyErrorCodes.CONNECT_WALLET_CANCELLED,
|
|
@@ -682,6 +693,7 @@ class TurnkeyClient {
|
|
|
682
693
|
*
|
|
683
694
|
* @param params.otpType - type of OTP to initialize (OtpType.Email or OtpType.Sms).
|
|
684
695
|
* @param params.contact - contact information for the user (e.g., email address or phone number).
|
|
696
|
+
* @param params.organizationId - optional organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
685
697
|
* @returns A promise that resolves to the OTP ID required for verification.
|
|
686
698
|
* @throws {TurnkeyError} If there is an error during the OTP initialization process or if the maximum number of OTPs has been reached.
|
|
687
699
|
*/
|
|
@@ -695,7 +707,7 @@ class TurnkeyClient {
|
|
|
695
707
|
}, {
|
|
696
708
|
errorMessage: "Failed to initialize OTP",
|
|
697
709
|
errorCode: TurnkeyErrorCodes.INIT_OTP_ERROR,
|
|
698
|
-
|
|
710
|
+
customErrorsByMessages: {
|
|
699
711
|
"Max number of OTPs have been initiated": {
|
|
700
712
|
message: "Maximum number of OTPs has been reached for this contact.",
|
|
701
713
|
code: TurnkeyErrorCodes.MAX_OTP_INITIATED_ERROR,
|
|
@@ -745,7 +757,7 @@ class TurnkeyClient {
|
|
|
745
757
|
}, {
|
|
746
758
|
errorMessage: "Failed to verify OTP",
|
|
747
759
|
errorCode: TurnkeyErrorCodes.VERIFY_OTP_ERROR,
|
|
748
|
-
|
|
760
|
+
customErrorsByMessages: {
|
|
749
761
|
"Invalid OTP code": {
|
|
750
762
|
message: "The provided OTP code is invalid.",
|
|
751
763
|
code: TurnkeyErrorCodes.INVALID_OTP_CODE,
|
|
@@ -944,7 +956,7 @@ class TurnkeyClient {
|
|
|
944
956
|
* @throws {TurnkeyError} If there is an error during the OAuth completion process, such as account lookup, sign-up, or login.
|
|
945
957
|
*/
|
|
946
958
|
this.completeOauth = async (params) => {
|
|
947
|
-
const { oidcToken, publicKey, createSubOrgParams, providerName = "OpenID Connect Provider" + Date.now(), sessionKey = SessionKey.DefaultSessionkey, invalidateExisting = false, } = params;
|
|
959
|
+
const { oidcToken, publicKey, createSubOrgParams, providerName = "OpenID Connect Provider" + " " + Date.now(), sessionKey = SessionKey.DefaultSessionkey, invalidateExisting = false, } = params;
|
|
948
960
|
return withTurnkeyErrorHandling(async () => {
|
|
949
961
|
const accountRes = await this.httpClient.proxyGetAccount({
|
|
950
962
|
filterType: "OIDC_TOKEN",
|
|
@@ -1027,7 +1039,7 @@ class TurnkeyClient {
|
|
|
1027
1039
|
}, {
|
|
1028
1040
|
errorMessage: "Failed to complete OAuth login",
|
|
1029
1041
|
errorCode: TurnkeyErrorCodes.OAUTH_LOGIN_ERROR,
|
|
1030
|
-
|
|
1042
|
+
customErrorsByMessages: {
|
|
1031
1043
|
"OAUTH disallowed": {
|
|
1032
1044
|
message: "OAuth is disabled on the dashboard for this organization.",
|
|
1033
1045
|
code: TurnkeyErrorCodes.AUTH_METHOD_NOT_ENABLED,
|
|
@@ -1100,39 +1112,64 @@ class TurnkeyClient {
|
|
|
1100
1112
|
* - Returns both embedded and connected wallets in a single array, each with their respective accounts populated.
|
|
1101
1113
|
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1102
1114
|
*
|
|
1103
|
-
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1104
1115
|
* @param params.walletProviders - array of wallet providers to use for fetching wallets.
|
|
1116
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID).
|
|
1117
|
+
* @param params.userId - user ID to target (defaults to the session's user ID).
|
|
1118
|
+
* @param params.connectedOnly - if true, fetches only connected wallets; if false or undefined, fetches both embedded and connected wallets.
|
|
1119
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1105
1120
|
* @returns A promise that resolves to an array of `Wallet` objects.
|
|
1106
1121
|
* @throws {TurnkeyError} If no active session is found or if there is an error fetching wallets.
|
|
1107
1122
|
*/
|
|
1108
1123
|
this.fetchWallets = async (params) => {
|
|
1109
|
-
const { stampWith,
|
|
1124
|
+
const { walletProviders, organizationId: organizationIdFromParams, userId: userIdFromParams, connectedOnly, stampWith, } = params || {};
|
|
1110
1125
|
const session = await this.storageManager.getActiveSession();
|
|
1111
|
-
if (!session) {
|
|
1112
|
-
throw new TurnkeyError("No active session found.
|
|
1126
|
+
if (!session && !connectedOnly) {
|
|
1127
|
+
throw new TurnkeyError("No active session found. Fetching embedded wallets requires a valid session. If you only need connected wallets, set the 'connectedOnly' parameter to true.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1128
|
+
}
|
|
1129
|
+
// if `connectedOnly` is true, we need to make sure the walletManager is initialized
|
|
1130
|
+
// or else we can't fetch connected wallets, and we throw an error
|
|
1131
|
+
if (connectedOnly && !this.walletManager?.connector) {
|
|
1132
|
+
throw new TurnkeyError("Wallet connector is not initialized", TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
1113
1133
|
}
|
|
1114
1134
|
return withTurnkeyErrorHandling(async () => {
|
|
1115
|
-
|
|
1116
|
-
if
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1135
|
+
let embedded = [];
|
|
1136
|
+
// if connectedOnly is true, we skip fetching embedded wallets
|
|
1137
|
+
if (!connectedOnly) {
|
|
1138
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
1139
|
+
if (!organizationId) {
|
|
1140
|
+
throw new TurnkeyError("No organization ID provided and no active session found. Please log in first or pass in an organization ID.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1141
|
+
}
|
|
1142
|
+
const userId = userIdFromParams || session?.userId;
|
|
1143
|
+
if (!userId) {
|
|
1144
|
+
throw new TurnkeyError("No user ID provided and no active session found. Please log in first or pass in a user ID.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1145
|
+
}
|
|
1146
|
+
const res = await this.httpClient.getWalletAccounts({
|
|
1147
|
+
organizationId,
|
|
1148
|
+
includeWalletDetails: true,
|
|
1149
|
+
}, stampWith);
|
|
1150
|
+
const walletsRes = await this.httpClient.getWallets({
|
|
1151
|
+
organizationId,
|
|
1152
|
+
}, stampWith);
|
|
1153
|
+
if (!res || !res.accounts) {
|
|
1154
|
+
throw new TurnkeyError("No wallet accounts found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1155
|
+
}
|
|
1156
|
+
// create a map of walletId to EmbeddedWallet for easy lookup
|
|
1157
|
+
const walletMap = new Map(walletsRes.wallets.map((wallet) => [
|
|
1158
|
+
wallet.walletId,
|
|
1159
|
+
{
|
|
1160
|
+
...wallet,
|
|
1161
|
+
source: WalletSource.Embedded,
|
|
1162
|
+
accounts: [],
|
|
1163
|
+
},
|
|
1164
|
+
]));
|
|
1165
|
+
// map the accounts to their respective wallets
|
|
1166
|
+
embedded = mapAccountsToWallet(res.accounts, walletMap);
|
|
1167
|
+
}
|
|
1132
1168
|
// if wallet connecting is disabled we return only embedded wallets
|
|
1169
|
+
// this will never be hit if `connectedOnly` is true because of the check above
|
|
1133
1170
|
if (!this.walletManager?.connector)
|
|
1134
1171
|
return embedded;
|
|
1135
|
-
const providers = walletProviders ?? (await this.
|
|
1172
|
+
const providers = walletProviders ?? (await this.fetchWalletProviders());
|
|
1136
1173
|
const groupedProviders = new Map();
|
|
1137
1174
|
for (const provider of providers) {
|
|
1138
1175
|
// connected wallets don't all have some uuid we can use for the walletId
|
|
@@ -1143,7 +1180,11 @@ class TurnkeyClient {
|
|
|
1143
1180
|
group.push(provider);
|
|
1144
1181
|
groupedProviders.set(walletId, group);
|
|
1145
1182
|
}
|
|
1146
|
-
|
|
1183
|
+
// has to be done in a for of loop so we can await each fetchWalletAccounts call individually
|
|
1184
|
+
// otherwise await Promise.all would cause them all to fire at once breaking passkey only set ups
|
|
1185
|
+
// (multiple wallet fetches at once causing "OperationError: A request is already pending.")
|
|
1186
|
+
let connected = [];
|
|
1187
|
+
for (const [walletId, grouped] of groupedProviders.entries()) {
|
|
1147
1188
|
const timestamp = toExternalTimestamp();
|
|
1148
1189
|
const wallet = {
|
|
1149
1190
|
source: WalletSource.Connected,
|
|
@@ -1159,10 +1200,16 @@ class TurnkeyClient {
|
|
|
1159
1200
|
wallet,
|
|
1160
1201
|
walletProviders: grouped,
|
|
1161
1202
|
...(stampWith !== undefined && { stampWith }),
|
|
1203
|
+
...(organizationIdFromParams !== undefined && {
|
|
1204
|
+
organizationId: organizationIdFromParams,
|
|
1205
|
+
}),
|
|
1206
|
+
...(userIdFromParams !== undefined && { userId: userIdFromParams }),
|
|
1162
1207
|
});
|
|
1163
1208
|
wallet.accounts = accounts;
|
|
1164
|
-
|
|
1165
|
-
|
|
1209
|
+
if (wallet.accounts.length > 0) {
|
|
1210
|
+
connected.push(wallet);
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1166
1213
|
return [...embedded, ...connected];
|
|
1167
1214
|
}, {
|
|
1168
1215
|
errorMessage: "Failed to fetch wallets",
|
|
@@ -1182,22 +1229,30 @@ class TurnkeyClient {
|
|
|
1182
1229
|
* @param params.walletProviders - list of wallet providers to filter by (used for connected wallets).
|
|
1183
1230
|
* @param params.paginationOptions - pagination options for embedded wallets.
|
|
1184
1231
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1232
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID).
|
|
1233
|
+
* @param params.userId - user ID to target (defaults to the session's user ID).
|
|
1234
|
+
*
|
|
1185
1235
|
* @returns A promise that resolves to an array of `v1WalletAccount` objects.
|
|
1186
1236
|
* @throws {TurnkeyError} If no active session is found or if there is an error fetching wallet accounts.
|
|
1187
1237
|
*/
|
|
1188
1238
|
this.fetchWalletAccounts = async (params) => {
|
|
1189
1239
|
const { wallet, stampWith, walletProviders, paginationOptions } = params;
|
|
1190
1240
|
const session = await this.storageManager.getActiveSession();
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
}
|
|
1241
|
+
const organizationId = params?.organizationId || session?.organizationId;
|
|
1242
|
+
const userId = params?.userId || session?.userId;
|
|
1194
1243
|
return withTurnkeyErrorHandling(async () => {
|
|
1195
1244
|
// this is an embedded wallet so we fetch accounts from Turnkey
|
|
1196
1245
|
if (wallet.source === WalletSource.Embedded) {
|
|
1197
1246
|
const embedded = [];
|
|
1247
|
+
if (!organizationId) {
|
|
1248
|
+
throw new TurnkeyError("No organization ID provided and no active session found. Please log in first or pass in an organization ID.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1249
|
+
}
|
|
1250
|
+
if (!userId) {
|
|
1251
|
+
throw new TurnkeyError("No user ID provided and no active session found. Please log in first or pass in a user ID.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1252
|
+
}
|
|
1198
1253
|
const res = await this.httpClient.getWalletAccounts({
|
|
1199
1254
|
walletId: wallet.walletId,
|
|
1200
|
-
organizationId
|
|
1255
|
+
organizationId,
|
|
1201
1256
|
paginationOptions: paginationOptions || { limit: "100" },
|
|
1202
1257
|
}, stampWith);
|
|
1203
1258
|
if (!res || !res.accounts) {
|
|
@@ -1217,7 +1272,7 @@ class TurnkeyClient {
|
|
|
1217
1272
|
if (!this.walletManager?.connector)
|
|
1218
1273
|
return [];
|
|
1219
1274
|
const connected = [];
|
|
1220
|
-
const providers = walletProviders ?? (await this.
|
|
1275
|
+
const providers = walletProviders ?? (await this.fetchWalletProviders());
|
|
1221
1276
|
// Context: connected wallets don't all have some uuid we can use for the walletId so what
|
|
1222
1277
|
// we do is we use a normalized version of the name for the wallet, like "metamask"
|
|
1223
1278
|
// or "phantom-wallet"
|
|
@@ -1228,17 +1283,26 @@ class TurnkeyClient {
|
|
|
1228
1283
|
const matching = providers.filter((p) => p.info?.name?.toLowerCase().replace(/\s+/g, "-") ===
|
|
1229
1284
|
wallet.walletId && p.connectedAddresses.length > 0);
|
|
1230
1285
|
const sign = this.walletManager.connector.sign.bind(this.walletManager.connector);
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1286
|
+
let ethereumAddresses = [];
|
|
1287
|
+
let solanaAddresses = [];
|
|
1288
|
+
// we only fetch the user if we have to the organizationId and userId
|
|
1289
|
+
// if not that means `isAuthenticator` will always be false
|
|
1290
|
+
if (organizationId && userId) {
|
|
1291
|
+
const user = await this.fetchUser({
|
|
1292
|
+
userId,
|
|
1293
|
+
organizationId,
|
|
1294
|
+
stampWith,
|
|
1295
|
+
});
|
|
1296
|
+
({ ethereum: ethereumAddresses, solana: solanaAddresses } =
|
|
1297
|
+
getAuthenticatorAddresses(user));
|
|
1298
|
+
}
|
|
1235
1299
|
for (const provider of matching) {
|
|
1236
1300
|
const timestamp = toExternalTimestamp();
|
|
1237
1301
|
for (const address of provider.connectedAddresses) {
|
|
1238
1302
|
if (isEthereumProvider(provider)) {
|
|
1239
1303
|
const evmAccount = {
|
|
1240
1304
|
walletAccountId: `${wallet.walletId}-${provider.interfaceType}-${address}`,
|
|
1241
|
-
organizationId:
|
|
1305
|
+
organizationId: organizationId ?? "",
|
|
1242
1306
|
walletId: wallet.walletId,
|
|
1243
1307
|
pathFormat: "PATH_FORMAT_BIP32",
|
|
1244
1308
|
path: WalletSource.Connected,
|
|
@@ -1260,7 +1324,7 @@ class TurnkeyClient {
|
|
|
1260
1324
|
if (isSolanaProvider(provider)) {
|
|
1261
1325
|
const solAccount = {
|
|
1262
1326
|
walletAccountId: `${wallet.walletId}-${provider.interfaceType}-${address}`,
|
|
1263
|
-
organizationId:
|
|
1327
|
+
organizationId: organizationId ?? "",
|
|
1264
1328
|
walletId: wallet.walletId,
|
|
1265
1329
|
pathFormat: "PATH_FORMAT_BIP32",
|
|
1266
1330
|
path: WalletSource.Connected,
|
|
@@ -1296,17 +1360,19 @@ class TurnkeyClient {
|
|
|
1296
1360
|
* - Supports stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1297
1361
|
*
|
|
1298
1362
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1363
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID).
|
|
1299
1364
|
* @returns A promise that resolves to an array of `v1PrivateKey` objects.
|
|
1300
1365
|
* @throws {TurnkeyError} If no active session is found or if there is an error fetching private keys.
|
|
1301
1366
|
*/
|
|
1302
1367
|
this.fetchPrivateKeys = async (params) => {
|
|
1303
1368
|
const { stampWith } = params || {};
|
|
1304
|
-
const session = await this.storageManager.getActiveSession
|
|
1305
|
-
|
|
1306
|
-
|
|
1369
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1370
|
+
const organizationId = params?.organizationId || session?.organizationId;
|
|
1371
|
+
if (!organizationId) {
|
|
1372
|
+
throw new TurnkeyError("No organization ID provided and no active session found. Please log in first or pass in an organization ID.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1307
1373
|
}
|
|
1308
1374
|
return withTurnkeyErrorHandling(async () => {
|
|
1309
|
-
const res = await this.httpClient.getPrivateKeys({ organizationId
|
|
1375
|
+
const res = await this.httpClient.getPrivateKeys({ organizationId }, stampWith);
|
|
1310
1376
|
if (!res) {
|
|
1311
1377
|
throw new TurnkeyError("Failed to fetch private keys", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1312
1378
|
}
|
|
@@ -1319,33 +1385,43 @@ class TurnkeyClient {
|
|
|
1319
1385
|
/**
|
|
1320
1386
|
* Signs a message using the specified wallet account.
|
|
1321
1387
|
*
|
|
1322
|
-
*
|
|
1323
|
-
*
|
|
1388
|
+
* Behavior differs depending on the wallet type:
|
|
1389
|
+
*
|
|
1390
|
+
* - **Connected wallets**
|
|
1324
1391
|
* - Delegates signing to the wallet provider’s native signing method.
|
|
1325
|
-
* -
|
|
1326
|
-
* The
|
|
1327
|
-
*
|
|
1328
|
-
* or broadcast on-chain.
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1392
|
+
* - *Ethereum*: signatures always follow [EIP-191](https://eips.ethereum.org/EIPS/eip-191).
|
|
1393
|
+
* - The wallet automatically prefixes messages with
|
|
1394
|
+
* `"\x19Ethereum Signed Message:\n" + message length` before signing.
|
|
1395
|
+
* - As a result, these signatures cannot be used as raw transaction signatures or broadcast on-chain.
|
|
1396
|
+
* - If `addEthereumPrefix` is set to `false`, an error is thrown because connected Ethereum wallets always prefix.
|
|
1397
|
+
* - *Other chains*: follows the native connected wallet behavior.
|
|
1398
|
+
*
|
|
1399
|
+
* - **Embedded wallets**
|
|
1400
|
+
* - Uses the Turnkey API to sign the message directly.
|
|
1401
|
+
* - Supports optional `addEthereumPrefix`:
|
|
1402
|
+
* - If `true` (default for Ethereum), the message is prefixed before signing.
|
|
1403
|
+
* - If `false`, the raw message is signed without any prefix.
|
|
1404
|
+
*
|
|
1405
|
+
* Additional details:
|
|
1406
|
+
* - Automatically handles encoding and hashing based on the wallet account’s address format,
|
|
1331
1407
|
* unless explicitly overridden.
|
|
1408
|
+
* - Optionally allows stamping with a specific stamper
|
|
1409
|
+
* (`StamperType.Passkey`, `StamperType.ApiKey`, or `StamperType.Wallet`).
|
|
1332
1410
|
*
|
|
1333
|
-
* @param params.message - message to sign.
|
|
1411
|
+
* @param params.message - plaintext (UTF-8) message to sign.
|
|
1334
1412
|
* @param params.walletAccount - wallet account to use for signing.
|
|
1335
|
-
* @param params.encoding - override for
|
|
1336
|
-
* @param params.hashFunction - override for
|
|
1337
|
-
* @param params.stampWith - stamper
|
|
1338
|
-
* @param params.addEthereumPrefix - whether to prefix the message with Ethereum
|
|
1339
|
-
*
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1342
|
-
*
|
|
1343
|
-
*
|
|
1344
|
-
* @returns A promise resolving to a `v1SignRawPayloadResult` containing the signature and metadata.
|
|
1345
|
-
* @throws {TurnkeyError} If signing fails, if the wallet account does not support signing, or if the response is invalid.
|
|
1413
|
+
* @param params.encoding - override for payload encoding (defaults to the encoding appropriate for the address format).
|
|
1414
|
+
* @param params.hashFunction - override for hash function (defaults to the function appropriate for the address format).
|
|
1415
|
+
* @param params.stampWith - optional stamper for the signing request.
|
|
1416
|
+
* @param params.addEthereumPrefix - whether to prefix the message with Ethereum’s
|
|
1417
|
+
* `"\x19Ethereum Signed Message:\n"` string (default: `true` for Ethereum).
|
|
1418
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID).
|
|
1419
|
+
*
|
|
1420
|
+
* @returns A promise that resolves to a `v1SignRawPayloadResult` containing the signature and metadata.
|
|
1421
|
+
* @throws {TurnkeyError} If signing fails, the wallet type does not support message signing, or the response is invalid.
|
|
1346
1422
|
*/
|
|
1347
1423
|
this.signMessage = async (params) => {
|
|
1348
|
-
const { message, walletAccount, stampWith, addEthereumPrefix } = params;
|
|
1424
|
+
const { message, walletAccount, stampWith, addEthereumPrefix, organizationId, } = params;
|
|
1349
1425
|
const hashFunction = params.hashFunction || getHashFunction(walletAccount.addressFormat);
|
|
1350
1426
|
const payloadEncoding = params.encoding || getEncodingType(walletAccount.addressFormat);
|
|
1351
1427
|
return withTurnkeyErrorHandling(async () => {
|
|
@@ -1357,23 +1433,29 @@ class TurnkeyClient {
|
|
|
1357
1433
|
}
|
|
1358
1434
|
let encodedMessage = message;
|
|
1359
1435
|
if (isEthereum) {
|
|
1360
|
-
|
|
1436
|
+
const msgBytes = toUtf8Bytes(message);
|
|
1437
|
+
encodedMessage = getEncodedMessage(payloadEncoding, msgBytes);
|
|
1361
1438
|
}
|
|
1362
1439
|
const sigHex = await walletAccount.signMessage(encodedMessage);
|
|
1363
1440
|
return splitSignature(sigHex, walletAccount.addressFormat);
|
|
1364
1441
|
}
|
|
1365
1442
|
// this is an embedded wallet
|
|
1366
|
-
let
|
|
1443
|
+
let msgBytes = toUtf8Bytes(message);
|
|
1367
1444
|
if (addEthereumPrefix && isEthereum) {
|
|
1368
|
-
const prefix = `\x19Ethereum Signed Message:\n${
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1445
|
+
const prefix = `\x19Ethereum Signed Message:\n${msgBytes.length}`;
|
|
1446
|
+
const prefixBytes = toUtf8Bytes(prefix);
|
|
1447
|
+
const combined = new Uint8Array(prefixBytes.length + msgBytes.length);
|
|
1448
|
+
combined.set(prefixBytes, 0);
|
|
1449
|
+
combined.set(msgBytes, prefixBytes.length);
|
|
1450
|
+
msgBytes = combined;
|
|
1451
|
+
}
|
|
1452
|
+
const encodedMessage = getEncodedMessage(payloadEncoding, msgBytes);
|
|
1372
1453
|
const response = await this.httpClient.signRawPayload({
|
|
1373
1454
|
signWith: walletAccount.address,
|
|
1374
1455
|
payload: encodedMessage,
|
|
1375
1456
|
encoding: payloadEncoding,
|
|
1376
1457
|
hashFunction,
|
|
1458
|
+
...(organizationId && { organizationId }),
|
|
1377
1459
|
}, stampWith);
|
|
1378
1460
|
if (response.activity.failure) {
|
|
1379
1461
|
throw new TurnkeyError("Failed to sign message, no signed payload returned", TurnkeyErrorCodes.SIGN_MESSAGE_ERROR);
|
|
@@ -1388,21 +1470,29 @@ class TurnkeyClient {
|
|
|
1388
1470
|
/**
|
|
1389
1471
|
* Signs a transaction using the specified wallet account.
|
|
1390
1472
|
*
|
|
1391
|
-
*
|
|
1392
|
-
*
|
|
1393
|
-
* -
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1473
|
+
* Behavior differs depending on the type of wallet:
|
|
1474
|
+
*
|
|
1475
|
+
* - **Connected wallets**
|
|
1476
|
+
* - Ethereum: does not support raw transaction signing. Calling this function will throw an error instructing you to use `signAndSendTransaction` instead.
|
|
1477
|
+
* - Solana: supports raw transaction signing via the connected wallet provider.
|
|
1478
|
+
* - Other chains: not supported; will throw an error.
|
|
1396
1479
|
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1480
|
+
* - **Embedded wallets**
|
|
1481
|
+
* - Delegates signing to the Turnkey API, which returns the signed transaction.
|
|
1482
|
+
* - Supports all Turnkey-supported transaction types (e.g., Ethereum, Solana, Tron).
|
|
1483
|
+
* - Optionally allows stamping with a specific stamper (`StamperType.Passkey`, `StamperType.ApiKey`, or `StamperType.Wallet`).
|
|
1484
|
+
*
|
|
1485
|
+
* @param params.walletAccount - wallet account to use for signing.
|
|
1486
|
+
* @param params.unsignedTransaction - unsigned transaction data as a serialized
|
|
1487
|
+
* string in the canonical encoding for the given `transactionType`.
|
|
1399
1488
|
* @param params.transactionType - type of transaction (e.g., "TRANSACTION_TYPE_ETHEREUM", "TRANSACTION_TYPE_SOLANA", "TRANSACTION_TYPE_TRON").
|
|
1400
|
-
* @param params.stampWith -
|
|
1401
|
-
* @
|
|
1402
|
-
* @
|
|
1489
|
+
* @param params.stampWith - stamper to use for signing (`StamperType.Passkey`, `StamperType.ApiKey`, or `StamperType.Wallet`).
|
|
1490
|
+
* @param params.organizationId - organization ID to target (defaults to the session's organization ID).
|
|
1491
|
+
* @returns A promise that resolves to the signed transaction string.
|
|
1492
|
+
* @throws {TurnkeyError} If the wallet type is unsupported, signing fails, or the response is invalid.
|
|
1403
1493
|
*/
|
|
1404
1494
|
this.signTransaction = async (params) => {
|
|
1405
|
-
const { walletAccount, unsignedTransaction, transactionType, stampWith } = params;
|
|
1495
|
+
const { walletAccount, unsignedTransaction, transactionType, stampWith, organizationId, } = params;
|
|
1406
1496
|
return withTurnkeyErrorHandling(async () => {
|
|
1407
1497
|
if (walletAccount.source === WalletSource.Connected) {
|
|
1408
1498
|
switch (walletAccount.chainInfo.namespace) {
|
|
@@ -1421,6 +1511,7 @@ class TurnkeyClient {
|
|
|
1421
1511
|
signWith: walletAccount.address,
|
|
1422
1512
|
unsignedTransaction,
|
|
1423
1513
|
type: transactionType,
|
|
1514
|
+
...(organizationId && { organizationId }),
|
|
1424
1515
|
}, stampWith);
|
|
1425
1516
|
return signTransaction.signedTransaction;
|
|
1426
1517
|
}, {
|
|
@@ -1431,25 +1522,32 @@ class TurnkeyClient {
|
|
|
1431
1522
|
/**
|
|
1432
1523
|
* Signs and broadcasts a transaction using the specified wallet account.
|
|
1433
1524
|
*
|
|
1434
|
-
*
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
1525
|
+
* Behavior differs depending on the type of wallet:
|
|
1526
|
+
*
|
|
1527
|
+
* - **Connected wallets**
|
|
1528
|
+
* - *Ethereum*: delegates to the wallet’s native `signAndSendTransaction` method.
|
|
1529
|
+
* - Does **not** require an `rpcUrl` (the wallet handles broadcasting).
|
|
1530
|
+
* - *Solana*: signs the transaction locally with the connected wallet, but requires an `rpcUrl` to broadcast it.
|
|
1531
|
+
* - Other chains: not supported; will throw an error.
|
|
1437
1532
|
*
|
|
1438
|
-
* -
|
|
1533
|
+
* - **Embedded wallets**
|
|
1439
1534
|
* - Signs the transaction using the Turnkey API.
|
|
1440
|
-
* - Requires an `rpcUrl` to broadcast the transaction.
|
|
1441
|
-
* - Broadcasts the transaction using a JSON-RPC client.
|
|
1442
|
-
*
|
|
1443
|
-
*
|
|
1444
|
-
* @param params.
|
|
1445
|
-
* @param params.
|
|
1446
|
-
*
|
|
1447
|
-
* @param params.
|
|
1535
|
+
* - Requires an `rpcUrl` to broadcast the signed transaction, since Turnkey does not broadcast directly.
|
|
1536
|
+
* - Broadcasts the transaction using a JSON-RPC client and returns the resulting transaction hash/signature.
|
|
1537
|
+
* - Optionally allows stamping with a specific stamper (`StamperType.Passkey`, `StamperType.ApiKey`, or `StamperType.Wallet`).
|
|
1538
|
+
*
|
|
1539
|
+
* @param params.walletAccount - wallet account to use for signing and broadcasting.
|
|
1540
|
+
* @param params.unsignedTransaction - unsigned transaction data as a serialized
|
|
1541
|
+
* string in the canonical encoding for the given `transactionType`.
|
|
1542
|
+
* @param params.transactionType - type of transaction (e.g., `"TRANSACTION_TYPE_SOLANA"`, `"TRANSACTION_TYPE_ETHEREUM"`).
|
|
1543
|
+
* @param params.rpcUrl - JSON-RPC endpoint used for broadcasting (required for Solana connected wallets and all embedded wallets).
|
|
1544
|
+
* @param params.stampWith - optional stamper to use when signing (`StamperType.Passkey`, `StamperType.ApiKey`, or `StamperType.Wallet`).
|
|
1545
|
+
* @param params.organizationId - **Only for Turnkey embedded wallets**: organization ID to target (defaults to the session's organization ID).
|
|
1448
1546
|
* @returns A promise that resolves to a transaction signature or hash.
|
|
1449
|
-
* @throws {TurnkeyError} If
|
|
1547
|
+
* @throws {TurnkeyError} If the wallet type is unsupported, or if signing/broadcasting fails.
|
|
1450
1548
|
*/
|
|
1451
1549
|
this.signAndSendTransaction = async (params) => {
|
|
1452
|
-
const { walletAccount, unsignedTransaction, transactionType, rpcUrl, stampWith, } = params;
|
|
1550
|
+
const { walletAccount, unsignedTransaction, transactionType, rpcUrl, stampWith, organizationId, } = params;
|
|
1453
1551
|
return withTurnkeyErrorHandling(async () => {
|
|
1454
1552
|
if (walletAccount.source === WalletSource.Connected) {
|
|
1455
1553
|
// this is a connected wallet account
|
|
@@ -1484,6 +1582,7 @@ class TurnkeyClient {
|
|
|
1484
1582
|
signWith: walletAccount.address,
|
|
1485
1583
|
unsignedTransaction,
|
|
1486
1584
|
type: transactionType,
|
|
1585
|
+
...(organizationId && { organizationId }),
|
|
1487
1586
|
}, stampWith);
|
|
1488
1587
|
const signedTx = signTransactionResponse.signedTransaction;
|
|
1489
1588
|
const txHash = await broadcastTransaction({
|
|
@@ -1513,16 +1612,16 @@ class TurnkeyClient {
|
|
|
1513
1612
|
* @throws {TurnkeyError} If there is no active session, if there is no userId, or if there is an error fetching user details.
|
|
1514
1613
|
*/
|
|
1515
1614
|
this.fetchUser = async (params) => {
|
|
1516
|
-
const { stampWith } = params || {};
|
|
1517
|
-
const session = await this.storageManager.getActiveSession
|
|
1518
|
-
|
|
1519
|
-
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1520
|
-
}
|
|
1521
|
-
const userId = params?.userId || session.userId;
|
|
1615
|
+
const { organizationId: organizationIdFromParams, userId: userIdFromParams, stampWith, } = params || {};
|
|
1616
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1617
|
+
const userId = userIdFromParams || session?.userId;
|
|
1522
1618
|
if (!userId) {
|
|
1523
1619
|
throw new TurnkeyError("User ID must be provided to fetch user", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1524
1620
|
}
|
|
1525
|
-
const organizationId =
|
|
1621
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
1622
|
+
if (!organizationId) {
|
|
1623
|
+
throw new TurnkeyError("Organization ID must be provided to fetch user", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1624
|
+
}
|
|
1526
1625
|
return withTurnkeyErrorHandling(async () => {
|
|
1527
1626
|
const userResponse = await this.httpClient.getUser({ organizationId, userId }, stampWith);
|
|
1528
1627
|
if (!userResponse || !userResponse.user) {
|
|
@@ -1534,6 +1633,170 @@ class TurnkeyClient {
|
|
|
1534
1633
|
errorCode: TurnkeyErrorCodes.FETCH_USER_ERROR,
|
|
1535
1634
|
});
|
|
1536
1635
|
};
|
|
1636
|
+
/**
|
|
1637
|
+
* Fetches an existing user by P-256 API key public key, or creates a new one if none exists.
|
|
1638
|
+
*
|
|
1639
|
+
* - This function is idempotent: multiple calls with the same `publicKey` will always return the same user.
|
|
1640
|
+
* - Attempts to find a user whose API keys include the given P-256 public key.
|
|
1641
|
+
* - If a matching user is found, it is returned as-is.
|
|
1642
|
+
* - If no matching user is found, a new user is created with the given public key as a P-256 API key.
|
|
1643
|
+
*
|
|
1644
|
+
* @param params.publicKey - the P-256 public key to use for lookup and creation.
|
|
1645
|
+
* @param params.createParams.userName - optional username to assign if creating a new user (defaults to `"Public Key User"`).
|
|
1646
|
+
* @param params.createParams.apiKeyName - optional API key name to assign if creating a new API key (defaults to `public-key-user-${publicKey}`).
|
|
1647
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1648
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1649
|
+
* @returns A promise that resolves to the existing or newly created {@link v1User}.
|
|
1650
|
+
* @throws {TurnkeyError} If there is no active session, if the input is invalid, if user retrieval fails, or if user creation fails.
|
|
1651
|
+
*/
|
|
1652
|
+
this.fetchOrCreateP256ApiKeyUser = async (params) => {
|
|
1653
|
+
const { publicKey, createParams, stampWith, organizationId: organizationIdFromParams, } = params;
|
|
1654
|
+
return withTurnkeyErrorHandling(async () => {
|
|
1655
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1656
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
1657
|
+
if (!organizationId) {
|
|
1658
|
+
throw new TurnkeyError("Organization ID is required to fetch or create P-256 API key user.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1659
|
+
}
|
|
1660
|
+
// we validate their input
|
|
1661
|
+
if (!publicKey?.trim()) {
|
|
1662
|
+
throw new TurnkeyError("'publicKey' is required and cannot be empty.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1663
|
+
}
|
|
1664
|
+
const usersResponse = await this.httpClient.getUsers({
|
|
1665
|
+
organizationId,
|
|
1666
|
+
}, stampWith);
|
|
1667
|
+
if (!usersResponse || !usersResponse.users) {
|
|
1668
|
+
throw new TurnkeyError("No users found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
1669
|
+
}
|
|
1670
|
+
const userWithPublicKey = usersResponse.users.find((user) => user.apiKeys.some((apiKey) => apiKey.credential.publicKey === publicKey &&
|
|
1671
|
+
apiKey.credential.type === "CREDENTIAL_TYPE_API_KEY_P256"));
|
|
1672
|
+
// the user already exists, so we return it
|
|
1673
|
+
if (userWithPublicKey) {
|
|
1674
|
+
return userWithPublicKey;
|
|
1675
|
+
}
|
|
1676
|
+
// at this point we know the user doesn't exist, so we create it
|
|
1677
|
+
const userName = createParams?.userName?.trim() || "Public Key User";
|
|
1678
|
+
const apiKeyName = createParams?.apiKeyName?.trim() || `public-key-user-${publicKey}`;
|
|
1679
|
+
const createUserResp = await this.httpClient.createUsers({
|
|
1680
|
+
organizationId,
|
|
1681
|
+
users: [
|
|
1682
|
+
{
|
|
1683
|
+
userName: userName,
|
|
1684
|
+
userTags: [],
|
|
1685
|
+
apiKeys: [
|
|
1686
|
+
{
|
|
1687
|
+
apiKeyName: apiKeyName,
|
|
1688
|
+
curveType: "API_KEY_CURVE_P256",
|
|
1689
|
+
publicKey,
|
|
1690
|
+
},
|
|
1691
|
+
],
|
|
1692
|
+
authenticators: [],
|
|
1693
|
+
oauthProviders: [],
|
|
1694
|
+
},
|
|
1695
|
+
],
|
|
1696
|
+
}, stampWith);
|
|
1697
|
+
if (!createUserResp?.userIds ||
|
|
1698
|
+
createUserResp.userIds.length === 0 ||
|
|
1699
|
+
!createUserResp.userIds[0]) {
|
|
1700
|
+
throw new TurnkeyError("Failed to create P-256 API key user", TurnkeyErrorCodes.CREATE_USERS_ERROR);
|
|
1701
|
+
}
|
|
1702
|
+
const newUserId = createUserResp.userIds[0];
|
|
1703
|
+
return await this.fetchUser({
|
|
1704
|
+
organizationId,
|
|
1705
|
+
userId: newUserId,
|
|
1706
|
+
stampWith,
|
|
1707
|
+
});
|
|
1708
|
+
}, {
|
|
1709
|
+
errorMessage: "Failed to get or create P-256 API key user",
|
|
1710
|
+
errorCode: TurnkeyErrorCodes.CREATE_USERS_ERROR,
|
|
1711
|
+
});
|
|
1712
|
+
};
|
|
1713
|
+
/**
|
|
1714
|
+
* Fetches each requested policy if it exists, or creates it if it does not.
|
|
1715
|
+
*
|
|
1716
|
+
* - This function is idempotent: multiple calls with the same policies will not create duplicates.
|
|
1717
|
+
* - For every policy in the request:
|
|
1718
|
+
* - If it already exists, it is returned with its `policyId`.
|
|
1719
|
+
* - If it does not exist, it is created and returned with its new `policyId`.
|
|
1720
|
+
*
|
|
1721
|
+
* @param params.policies - the list of policies to fetch or create.
|
|
1722
|
+
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1723
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1724
|
+
* @returns A promise that resolves to an array of objects, each containing:
|
|
1725
|
+
* - `policyId`: the unique identifier of the policy.
|
|
1726
|
+
* - `policyName`: human-readable name of the policy.
|
|
1727
|
+
* - `effect`: the instruction to DENY or ALLOW an activity.
|
|
1728
|
+
* - `condition`: (optional) the condition expression that triggers the effect.
|
|
1729
|
+
* - `consensus`: (optional) the consensus expression that triggers the effect.
|
|
1730
|
+
* - `notes`: (optional) developer notes or description for the policy.
|
|
1731
|
+
* @throws {TurnkeyError} If there is no active session, if the input is invalid,
|
|
1732
|
+
* if fetching policies fails, or if creating policies fails.
|
|
1733
|
+
*/
|
|
1734
|
+
this.fetchOrCreatePolicies = async (params) => {
|
|
1735
|
+
const { policies, stampWith } = params;
|
|
1736
|
+
return await withTurnkeyErrorHandling(async () => {
|
|
1737
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1738
|
+
if (!Array.isArray(policies) || policies.length === 0) {
|
|
1739
|
+
throw new TurnkeyError("'policies' must be a non-empty array of policy definitions.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1740
|
+
}
|
|
1741
|
+
const organizationId = params?.organizationId ?? session?.organizationId;
|
|
1742
|
+
if (!organizationId) {
|
|
1743
|
+
throw new TurnkeyError("Organization ID is required to fetch or create policies.", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1744
|
+
}
|
|
1745
|
+
// we first fetch existing policies
|
|
1746
|
+
const existingPoliciesResponse = await this.httpClient.getPolicies({
|
|
1747
|
+
organizationId,
|
|
1748
|
+
}, stampWith);
|
|
1749
|
+
const existingPolicies = existingPoliciesResponse.policies || [];
|
|
1750
|
+
// we create a map of existing policies by their signature
|
|
1751
|
+
// where the policySignature maps to its policyId
|
|
1752
|
+
const existingPoliciesSignatureMap = {};
|
|
1753
|
+
for (const existingPolicy of existingPolicies) {
|
|
1754
|
+
const signature = getPolicySignature(existingPolicy);
|
|
1755
|
+
existingPoliciesSignatureMap[signature] = existingPolicy.policyId;
|
|
1756
|
+
}
|
|
1757
|
+
// we go through each requested policy and check if it already exists
|
|
1758
|
+
// if it exists, we add it to the alreadyExistingPolicies list
|
|
1759
|
+
// if it doesn't exist, we add it to the missingPolicies list
|
|
1760
|
+
const alreadyExistingPolicies = [];
|
|
1761
|
+
const missingPolicies = [];
|
|
1762
|
+
for (const policy of policies) {
|
|
1763
|
+
const existingId = existingPoliciesSignatureMap[getPolicySignature(policy)];
|
|
1764
|
+
if (existingId) {
|
|
1765
|
+
alreadyExistingPolicies.push({ ...policy, policyId: existingId });
|
|
1766
|
+
}
|
|
1767
|
+
else {
|
|
1768
|
+
missingPolicies.push(policy);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
// if there are no missing policies, that means we're done
|
|
1772
|
+
// so we return them with their respective IDs
|
|
1773
|
+
if (missingPolicies.length === 0) {
|
|
1774
|
+
return alreadyExistingPolicies;
|
|
1775
|
+
}
|
|
1776
|
+
// at this point we know there is at least one missing policy.
|
|
1777
|
+
// so we create the missing policies and then return the full list
|
|
1778
|
+
const createPoliciesResponse = await this.httpClient.createPolicies({
|
|
1779
|
+
organizationId,
|
|
1780
|
+
policies: missingPolicies,
|
|
1781
|
+
}, stampWith);
|
|
1782
|
+
// assign returned IDs back to the missing ones in order
|
|
1783
|
+
if (!createPoliciesResponse || !createPoliciesResponse.policyIds) {
|
|
1784
|
+
throw new TurnkeyError("Failed to create missing policies", TurnkeyErrorCodes.CREATE_POLICY_ERROR);
|
|
1785
|
+
}
|
|
1786
|
+
const newlyCreatedPolicies = missingPolicies.map((p, idx) => ({
|
|
1787
|
+
...p,
|
|
1788
|
+
// we can safely assert the ID exists because we know Turnkey's api
|
|
1789
|
+
// will return one ID for each created policy or throw an error
|
|
1790
|
+
policyId: createPoliciesResponse.policyIds[idx],
|
|
1791
|
+
}));
|
|
1792
|
+
// we return the full list of policies, both existing and the newly created
|
|
1793
|
+
// which includes each of their respective IDs
|
|
1794
|
+
return [...alreadyExistingPolicies, ...newlyCreatedPolicies];
|
|
1795
|
+
}, {
|
|
1796
|
+
errorMessage: "Failed to get or create policies",
|
|
1797
|
+
errorCode: TurnkeyErrorCodes.CREATE_USERS_ERROR,
|
|
1798
|
+
});
|
|
1799
|
+
};
|
|
1537
1800
|
/**
|
|
1538
1801
|
* Updates the user's email address.
|
|
1539
1802
|
*
|
|
@@ -1547,16 +1810,17 @@ class TurnkeyClient {
|
|
|
1547
1810
|
* @param params.verificationToken - verification token from OTP email verification (required if verifying the email).
|
|
1548
1811
|
* @param params.userId - user ID to update a specific user's email (defaults to the current session's userId).
|
|
1549
1812
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1813
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1550
1814
|
* @returns A promise that resolves to the userId of the updated user.
|
|
1551
1815
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error updating or verifying the user email.
|
|
1552
1816
|
*/
|
|
1553
1817
|
this.updateUserEmail = async (params) => {
|
|
1554
|
-
const { verificationToken, email, stampWith } = params;
|
|
1555
|
-
const session = await this.storageManager.getActiveSession
|
|
1556
|
-
|
|
1557
|
-
|
|
1818
|
+
const { verificationToken, email, stampWith, organizationId } = params;
|
|
1819
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1820
|
+
const userId = params?.userId || session?.userId;
|
|
1821
|
+
if (!userId) {
|
|
1822
|
+
throw new TurnkeyError("User ID must be provided to update user email", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1558
1823
|
}
|
|
1559
|
-
const userId = params?.userId || session.userId;
|
|
1560
1824
|
return withTurnkeyErrorHandling(async () => {
|
|
1561
1825
|
const existingUser = await this.httpClient.proxyGetAccount({
|
|
1562
1826
|
filterType: FilterType.Email,
|
|
@@ -1569,6 +1833,7 @@ class TurnkeyClient {
|
|
|
1569
1833
|
userId: userId,
|
|
1570
1834
|
userEmail: email,
|
|
1571
1835
|
...(verificationToken && { verificationToken }),
|
|
1836
|
+
...(organizationId && { organizationId }),
|
|
1572
1837
|
}, stampWith);
|
|
1573
1838
|
if (!res || !res.userId) {
|
|
1574
1839
|
throw new TurnkeyError("No user ID found in the update user email response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -1589,20 +1854,22 @@ class TurnkeyClient {
|
|
|
1589
1854
|
*
|
|
1590
1855
|
* @param params.userId - user ID to remove a specific user's email address (defaults to the current session's userId).
|
|
1591
1856
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1857
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1592
1858
|
* @returns A promise that resolves to the userId of the user whose email was removed.
|
|
1593
1859
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error removing the user email.
|
|
1594
1860
|
*/
|
|
1595
1861
|
this.removeUserEmail = async (params) => {
|
|
1596
|
-
const { stampWith } = params || {};
|
|
1597
|
-
const session = await this.storageManager.getActiveSession
|
|
1598
|
-
if (!session) {
|
|
1599
|
-
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1600
|
-
}
|
|
1862
|
+
const { stampWith, organizationId } = params || {};
|
|
1863
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1601
1864
|
return withTurnkeyErrorHandling(async () => {
|
|
1602
|
-
const userId = params?.userId || session
|
|
1865
|
+
const userId = params?.userId || session?.userId;
|
|
1866
|
+
if (!userId) {
|
|
1867
|
+
throw new TurnkeyError("User ID must be provided to remove user email", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1868
|
+
}
|
|
1603
1869
|
const res = await this.httpClient.updateUserEmail({
|
|
1604
1870
|
userId: userId,
|
|
1605
1871
|
userEmail: "",
|
|
1872
|
+
...(organizationId && { organizationId }),
|
|
1606
1873
|
}, stampWith);
|
|
1607
1874
|
if (!res || !res.userId) {
|
|
1608
1875
|
throw new TurnkeyError("No user ID found in the remove user email response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -1626,21 +1893,23 @@ class TurnkeyClient {
|
|
|
1626
1893
|
* @param params.verificationToken - verification token from OTP phone verification (required if verifying the phone number).
|
|
1627
1894
|
* @param params.userId - user ID to update a specific user's phone number (defaults to the current session's userId).
|
|
1628
1895
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1896
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1629
1897
|
* @returns A promise that resolves to the userId of the updated user.
|
|
1630
1898
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error updating or verifying the user phone number.
|
|
1631
1899
|
*/
|
|
1632
1900
|
this.updateUserPhoneNumber = async (params) => {
|
|
1633
|
-
const { verificationToken, phoneNumber, stampWith } = params;
|
|
1634
|
-
const session = await this.storageManager.getActiveSession
|
|
1635
|
-
|
|
1636
|
-
|
|
1901
|
+
const { verificationToken, phoneNumber, stampWith, organizationId } = params;
|
|
1902
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1903
|
+
const userId = params?.userId || session?.userId;
|
|
1904
|
+
if (!userId) {
|
|
1905
|
+
throw new TurnkeyError("User ID must be provided to update user phone number", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1637
1906
|
}
|
|
1638
|
-
const userId = params?.userId || session.userId;
|
|
1639
1907
|
return withTurnkeyErrorHandling(async () => {
|
|
1640
1908
|
const res = await this.httpClient.updateUserPhoneNumber({
|
|
1641
1909
|
userId,
|
|
1642
1910
|
userPhoneNumber: phoneNumber,
|
|
1643
1911
|
...(verificationToken && { verificationToken }),
|
|
1912
|
+
...(organizationId && { organizationId }),
|
|
1644
1913
|
}, stampWith);
|
|
1645
1914
|
if (!res || !res.userId) {
|
|
1646
1915
|
throw new TurnkeyError("Failed to update user phone number", TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR);
|
|
@@ -1661,20 +1930,22 @@ class TurnkeyClient {
|
|
|
1661
1930
|
*
|
|
1662
1931
|
* @param params.userId - user ID to remove a specific user's phone number (defaults to the current session's userId).
|
|
1663
1932
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1933
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1664
1934
|
* @returns A promise that resolves to the userId of the user whose phone number was removed.
|
|
1665
1935
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error removing the user phone number.
|
|
1666
1936
|
*/
|
|
1667
1937
|
this.removeUserPhoneNumber = async (params) => {
|
|
1668
|
-
const { stampWith } = params || {};
|
|
1669
|
-
const session = await this.storageManager.getActiveSession
|
|
1670
|
-
|
|
1671
|
-
|
|
1938
|
+
const { stampWith, organizationId } = params || {};
|
|
1939
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1940
|
+
const userId = params?.userId || session?.userId;
|
|
1941
|
+
if (!userId) {
|
|
1942
|
+
throw new TurnkeyError("User ID must be provided to remove user phone number", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1672
1943
|
}
|
|
1673
|
-
const userId = params?.userId || session.userId;
|
|
1674
1944
|
return withTurnkeyErrorHandling(async () => {
|
|
1675
1945
|
const res = await this.httpClient.updateUserPhoneNumber({
|
|
1676
1946
|
userId,
|
|
1677
1947
|
userPhoneNumber: "",
|
|
1948
|
+
...(organizationId && { organizationId }),
|
|
1678
1949
|
}, stampWith);
|
|
1679
1950
|
if (!res || !res.userId) {
|
|
1680
1951
|
throw new TurnkeyError("Failed to remove user phone number", TurnkeyErrorCodes.UPDATE_USER_PHONE_NUMBER_ERROR);
|
|
@@ -1697,20 +1968,22 @@ class TurnkeyClient {
|
|
|
1697
1968
|
* @param params.userName - new name to set for the user.
|
|
1698
1969
|
* @param params.userId - user ID to update a specific user's name (defaults to the current session's userId).
|
|
1699
1970
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1971
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1700
1972
|
* @returns A promise that resolves to the userId of the updated user.
|
|
1701
1973
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error updating the user name.
|
|
1702
1974
|
*/
|
|
1703
1975
|
this.updateUserName = async (params) => {
|
|
1704
|
-
const { userName, stampWith } = params;
|
|
1705
|
-
const session = await this.storageManager.getActiveSession
|
|
1706
|
-
|
|
1707
|
-
|
|
1976
|
+
const { userName, stampWith, organizationId } = params;
|
|
1977
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1978
|
+
const userId = params?.userId || session?.userId;
|
|
1979
|
+
if (!userId) {
|
|
1980
|
+
throw new TurnkeyError("User ID must be provided to update user name", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1708
1981
|
}
|
|
1709
|
-
const userId = params?.userId || session.userId;
|
|
1710
1982
|
return withTurnkeyErrorHandling(async () => {
|
|
1711
1983
|
const res = await this.httpClient.updateUserName({
|
|
1712
1984
|
userId,
|
|
1713
1985
|
userName,
|
|
1986
|
+
...(organizationId && { organizationId }),
|
|
1714
1987
|
}, stampWith);
|
|
1715
1988
|
if (!res || !res.userId) {
|
|
1716
1989
|
throw new TurnkeyError("No user ID found in the update user name response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -1733,6 +2006,7 @@ class TurnkeyClient {
|
|
|
1733
2006
|
*
|
|
1734
2007
|
* @param params.providerName - name of the OAuth provider to add (e.g., "Google", "Apple").
|
|
1735
2008
|
* @param params.oidcToken - OIDC token for the OAuth provider.
|
|
2009
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1736
2010
|
* @param params.userId - user ID to add the provider for a specific user (defaults to current session's userId).
|
|
1737
2011
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
1738
2012
|
* @returns A promise that resolves to an array of provider IDs associated with the user.
|
|
@@ -1740,29 +2014,34 @@ class TurnkeyClient {
|
|
|
1740
2014
|
*/
|
|
1741
2015
|
this.addOauthProvider = async (params) => {
|
|
1742
2016
|
const { providerName, oidcToken, stampWith } = params;
|
|
1743
|
-
const session = await this.storageManager.getActiveSession
|
|
1744
|
-
if (!session) {
|
|
1745
|
-
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
1746
|
-
}
|
|
2017
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
1747
2018
|
return withTurnkeyErrorHandling(async () => {
|
|
1748
2019
|
const accountRes = await this.httpClient.proxyGetAccount({
|
|
1749
2020
|
filterType: "OIDC_TOKEN",
|
|
1750
2021
|
filterValue: oidcToken,
|
|
1751
2022
|
});
|
|
1752
2023
|
if (!accountRes) {
|
|
1753
|
-
throw new TurnkeyError(`Account fetch failed
|
|
2024
|
+
throw new TurnkeyError(`Account fetch failed`, TurnkeyErrorCodes.ACCOUNT_FETCH_ERROR);
|
|
1754
2025
|
}
|
|
1755
2026
|
if (accountRes.organizationId) {
|
|
1756
2027
|
throw new TurnkeyError("Account already exists with this OIDC token", TurnkeyErrorCodes.ACCOUNT_ALREADY_EXISTS);
|
|
1757
2028
|
}
|
|
1758
|
-
const userId = params?.userId || session
|
|
1759
|
-
|
|
2029
|
+
const userId = params?.userId || session?.userId;
|
|
2030
|
+
if (!userId) {
|
|
2031
|
+
throw new TurnkeyError("User ID must be provided to add OAuth provider", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2032
|
+
}
|
|
2033
|
+
const organizationId = params?.organizationId ?? session?.organizationId;
|
|
2034
|
+
if (!organizationId) {
|
|
2035
|
+
throw new TurnkeyError("Organization ID is required to add OAuth provider", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2036
|
+
}
|
|
2037
|
+
// parse the oidc token so we can get the email. Pass it in to updateUser then call createOauthProviders. This will be verified by Turnkey.
|
|
2038
|
+
const { email: oidcEmail, iss } = jwtDecode(oidcToken) || {};
|
|
1760
2039
|
if (iss === googleISS) {
|
|
1761
2040
|
const verifiedSuborg = await this.httpClient.proxyGetAccount({
|
|
1762
2041
|
filterType: "EMAIL",
|
|
1763
2042
|
filterValue: oidcEmail,
|
|
1764
2043
|
});
|
|
1765
|
-
const isVerified = verifiedSuborg.organizationId ===
|
|
2044
|
+
const isVerified = verifiedSuborg.organizationId === organizationId;
|
|
1766
2045
|
const user = await this.fetchUser({
|
|
1767
2046
|
userId,
|
|
1768
2047
|
stampWith,
|
|
@@ -1805,20 +2084,22 @@ class TurnkeyClient {
|
|
|
1805
2084
|
* @param params.providerIds - IDs of the OAuth providers to remove.
|
|
1806
2085
|
* @param params.userId - user ID to remove the provider for a specific user (defaults to the current session's userId).
|
|
1807
2086
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2087
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1808
2088
|
* @returns A promise that resolves to an array of provider IDs that were removed.
|
|
1809
2089
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error removing the OAuth provider.
|
|
1810
2090
|
*/
|
|
1811
2091
|
this.removeOauthProviders = async (params) => {
|
|
1812
|
-
const { providerIds, stampWith } = params;
|
|
1813
|
-
const session = await this.storageManager.getActiveSession
|
|
1814
|
-
|
|
1815
|
-
|
|
2092
|
+
const { providerIds, stampWith, organizationId } = params;
|
|
2093
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2094
|
+
const userId = params?.userId || session?.userId;
|
|
2095
|
+
if (!userId) {
|
|
2096
|
+
throw new TurnkeyError("User ID must be provided to remove OAuth provider", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1816
2097
|
}
|
|
1817
|
-
const userId = params?.userId || session.userId;
|
|
1818
2098
|
return withTurnkeyErrorHandling(async () => {
|
|
1819
2099
|
const res = await this.httpClient.deleteOauthProviders({
|
|
1820
2100
|
userId,
|
|
1821
2101
|
providerIds,
|
|
2102
|
+
...(organizationId && { organizationId }),
|
|
1822
2103
|
}, stampWith);
|
|
1823
2104
|
if (!res) {
|
|
1824
2105
|
throw new TurnkeyError("Failed to remove OAuth provider", TurnkeyErrorCodes.REMOVE_OAUTH_PROVIDER_ERROR);
|
|
@@ -1842,21 +2123,21 @@ class TurnkeyClient {
|
|
|
1842
2123
|
* @param params.displayName - display name of the passkey (defaults to the value of `name`).
|
|
1843
2124
|
* @param params.userId - user ID to add the passkey for a specific user (defaults to the current session's userId).
|
|
1844
2125
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2126
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1845
2127
|
* @returns A promise that resolves to an array of authenticator IDs for the newly added passkey(s).
|
|
1846
2128
|
* @throws {TurnkeyError} If there is no active session, if passkey creation fails, or if there is an error adding the passkey.
|
|
1847
2129
|
*/
|
|
1848
2130
|
this.addPasskey = async (params) => {
|
|
1849
|
-
const { stampWith } = params || {};
|
|
2131
|
+
const { stampWith, organizationId } = params || {};
|
|
1850
2132
|
const name = params?.name || `Turnkey Passkey-${Date.now()}`;
|
|
1851
2133
|
return withTurnkeyErrorHandling(async () => {
|
|
1852
|
-
const session = await this.storageManager.getActiveSession
|
|
1853
|
-
|
|
1854
|
-
|
|
2134
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2135
|
+
const userId = params?.userId || session?.userId;
|
|
2136
|
+
if (!userId) {
|
|
2137
|
+
throw new TurnkeyError("User ID must be provided to add passkey", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1855
2138
|
}
|
|
1856
|
-
const userId = params?.userId || session.userId;
|
|
1857
2139
|
const { encodedChallenge, attestation } = await this.createPasskey({
|
|
1858
2140
|
name,
|
|
1859
|
-
...(stampWith && { stampWith }),
|
|
1860
2141
|
});
|
|
1861
2142
|
if (!attestation || !encodedChallenge) {
|
|
1862
2143
|
throw new TurnkeyError("Failed to create passkey challenge and attestation", TurnkeyErrorCodes.CREATE_PASSKEY_ERROR);
|
|
@@ -1870,6 +2151,7 @@ class TurnkeyClient {
|
|
|
1870
2151
|
attestation,
|
|
1871
2152
|
},
|
|
1872
2153
|
],
|
|
2154
|
+
...(organizationId && { organizationId }),
|
|
1873
2155
|
}, stampWith);
|
|
1874
2156
|
return res?.authenticatorIds || [];
|
|
1875
2157
|
}, {
|
|
@@ -1889,20 +2171,22 @@ class TurnkeyClient {
|
|
|
1889
2171
|
* @param params.authenticatorIds - IDs of the authenticators (passkeys) to remove.
|
|
1890
2172
|
* @param params.userId - user ID to remove the passkeys for a specific user (defaults to the current session's userId).
|
|
1891
2173
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2174
|
+
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
1892
2175
|
* @returns A promise that resolves to an array of authenticator IDs that were removed.
|
|
1893
2176
|
* @throws {TurnkeyError} If there is no active session, if the userId is missing, or if there is an error removing the passkeys.
|
|
1894
2177
|
*/
|
|
1895
2178
|
this.removePasskeys = async (params) => {
|
|
1896
|
-
const { authenticatorIds, stampWith } = params;
|
|
1897
|
-
const session = await this.storageManager.getActiveSession
|
|
1898
|
-
|
|
1899
|
-
|
|
2179
|
+
const { authenticatorIds, stampWith, organizationId } = params;
|
|
2180
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2181
|
+
const userId = params?.userId || session?.userId;
|
|
2182
|
+
if (!userId) {
|
|
2183
|
+
throw new TurnkeyError("User ID must be provided to remove passkey", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1900
2184
|
}
|
|
1901
|
-
const userId = params?.userId || session.userId;
|
|
1902
2185
|
return withTurnkeyErrorHandling(async () => {
|
|
1903
2186
|
const res = await this.httpClient.deleteAuthenticators({
|
|
1904
2187
|
userId,
|
|
1905
2188
|
authenticatorIds,
|
|
2189
|
+
...(organizationId && { organizationId }),
|
|
1906
2190
|
}, stampWith);
|
|
1907
2191
|
if (!res) {
|
|
1908
2192
|
throw new TurnkeyError("No response found in the remove passkey response", TurnkeyErrorCodes.REMOVE_PASSKEY_ERROR);
|
|
@@ -1933,10 +2217,11 @@ class TurnkeyClient {
|
|
|
1933
2217
|
* @throws {TurnkeyError} If there is no active session or if there is an error creating the wallet.
|
|
1934
2218
|
*/
|
|
1935
2219
|
this.createWallet = async (params) => {
|
|
1936
|
-
const { walletName, accounts, organizationId, mnemonicLength, stampWith } = params;
|
|
1937
|
-
const session = await this.storageManager.getActiveSession
|
|
1938
|
-
|
|
1939
|
-
|
|
2220
|
+
const { walletName, accounts, organizationId: organizationIdFromParams, mnemonicLength, stampWith, } = params;
|
|
2221
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2222
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2223
|
+
if (!organizationId) {
|
|
2224
|
+
throw new TurnkeyError("Organization ID must be provided to create wallet", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1940
2225
|
}
|
|
1941
2226
|
let walletAccounts = [];
|
|
1942
2227
|
if (accounts && !isWalletAccountArray(accounts)) {
|
|
@@ -1952,7 +2237,7 @@ class TurnkeyClient {
|
|
|
1952
2237
|
}
|
|
1953
2238
|
return withTurnkeyErrorHandling(async () => {
|
|
1954
2239
|
const res = await this.httpClient.createWallet({
|
|
1955
|
-
organizationId: organizationId
|
|
2240
|
+
organizationId: organizationId,
|
|
1956
2241
|
walletName,
|
|
1957
2242
|
accounts: walletAccounts,
|
|
1958
2243
|
mnemonicLength: mnemonicLength || 12,
|
|
@@ -1984,10 +2269,11 @@ class TurnkeyClient {
|
|
|
1984
2269
|
* @throws {TurnkeyError} If there is no active session, if the wallet does not exist, or if there is an error creating the wallet accounts.
|
|
1985
2270
|
*/
|
|
1986
2271
|
this.createWalletAccounts = async (params) => {
|
|
1987
|
-
const { accounts, walletId, organizationId, stampWith } = params;
|
|
1988
|
-
const session = await this.storageManager.getActiveSession
|
|
1989
|
-
|
|
1990
|
-
|
|
2272
|
+
const { accounts, walletId, organizationId: organizationIdFromParams, stampWith, } = params;
|
|
2273
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2274
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2275
|
+
if (!organizationId) {
|
|
2276
|
+
throw new TurnkeyError("Organization ID must be provided to create wallet accounts", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1991
2277
|
}
|
|
1992
2278
|
return withTurnkeyErrorHandling(async () => {
|
|
1993
2279
|
let walletAccounts = [];
|
|
@@ -1995,7 +2281,7 @@ class TurnkeyClient {
|
|
|
1995
2281
|
// Query existing wallet accounts to avoid duplicates
|
|
1996
2282
|
const existingWalletAccounts = await this.httpClient.getWalletAccounts({
|
|
1997
2283
|
walletId,
|
|
1998
|
-
organizationId: organizationId
|
|
2284
|
+
organizationId: organizationId,
|
|
1999
2285
|
paginationOptions: { limit: "100" },
|
|
2000
2286
|
}, stampWith);
|
|
2001
2287
|
walletAccounts = generateWalletAccountsFromAddressFormat({
|
|
@@ -2007,7 +2293,7 @@ class TurnkeyClient {
|
|
|
2007
2293
|
walletAccounts = accounts;
|
|
2008
2294
|
}
|
|
2009
2295
|
const res = await this.httpClient.createWalletAccounts({
|
|
2010
|
-
organizationId: organizationId
|
|
2296
|
+
organizationId: organizationId,
|
|
2011
2297
|
walletId,
|
|
2012
2298
|
accounts: walletAccounts,
|
|
2013
2299
|
}, stampWith);
|
|
@@ -2038,16 +2324,17 @@ class TurnkeyClient {
|
|
|
2038
2324
|
* @throws {TurnkeyError} If there is no active session, if the targetPublicKey is missing, or if there is an error exporting the wallet.
|
|
2039
2325
|
*/
|
|
2040
2326
|
this.exportWallet = async (params) => {
|
|
2041
|
-
const { walletId, targetPublicKey, stampWith, organizationId } = params;
|
|
2042
|
-
const session = await this.storageManager.getActiveSession
|
|
2043
|
-
|
|
2044
|
-
|
|
2327
|
+
const { walletId, targetPublicKey, stampWith, organizationId: organizationIdFromParams, } = params;
|
|
2328
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2329
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2330
|
+
if (!organizationId) {
|
|
2331
|
+
throw new TurnkeyError("Organization ID must be provided to export wallet", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2045
2332
|
}
|
|
2046
2333
|
return withTurnkeyErrorHandling(async () => {
|
|
2047
2334
|
const res = await this.httpClient.exportWallet({
|
|
2048
2335
|
walletId,
|
|
2049
2336
|
targetPublicKey,
|
|
2050
|
-
organizationId: organizationId
|
|
2337
|
+
organizationId: organizationId,
|
|
2051
2338
|
}, stampWith);
|
|
2052
2339
|
if (!res.exportBundle) {
|
|
2053
2340
|
throw new TurnkeyError("No export bundle found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -2075,16 +2362,17 @@ class TurnkeyClient {
|
|
|
2075
2362
|
* @throws {TurnkeyError} If there is no active session, if the targetPublicKey is missing, or if there is an error exporting the private key.
|
|
2076
2363
|
*/
|
|
2077
2364
|
this.exportPrivateKey = async (params) => {
|
|
2078
|
-
const { privateKeyId, targetPublicKey, stampWith, organizationId } = params;
|
|
2079
|
-
const session = await this.storageManager.getActiveSession
|
|
2080
|
-
|
|
2081
|
-
|
|
2365
|
+
const { privateKeyId, targetPublicKey, stampWith, organizationId: organizationIdFromParams, } = params;
|
|
2366
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2367
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2368
|
+
if (!organizationId) {
|
|
2369
|
+
throw new TurnkeyError("Organization ID must be provided to export private key", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2082
2370
|
}
|
|
2083
2371
|
return withTurnkeyErrorHandling(async () => {
|
|
2084
2372
|
const res = await this.httpClient.exportPrivateKey({
|
|
2085
2373
|
privateKeyId,
|
|
2086
2374
|
targetPublicKey,
|
|
2087
|
-
organizationId: organizationId
|
|
2375
|
+
organizationId: organizationId,
|
|
2088
2376
|
}, stampWith);
|
|
2089
2377
|
if (!res.exportBundle) {
|
|
2090
2378
|
throw new TurnkeyError("No export bundle found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -2113,16 +2401,17 @@ class TurnkeyClient {
|
|
|
2113
2401
|
*
|
|
2114
2402
|
*/
|
|
2115
2403
|
this.exportWalletAccount = async (params) => {
|
|
2116
|
-
const { address, targetPublicKey, stampWith, organizationId } = params;
|
|
2117
|
-
const session = await this.storageManager.getActiveSession
|
|
2118
|
-
|
|
2119
|
-
|
|
2404
|
+
const { address, targetPublicKey, stampWith, organizationId: organizationIdFromParams, } = params;
|
|
2405
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2406
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2407
|
+
if (!organizationId) {
|
|
2408
|
+
throw new TurnkeyError("Organization ID must be provided to export wallet account", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2120
2409
|
}
|
|
2121
2410
|
return withTurnkeyErrorHandling(async () => {
|
|
2122
2411
|
const res = await this.httpClient.exportWalletAccount({
|
|
2123
2412
|
address,
|
|
2124
2413
|
targetPublicKey,
|
|
2125
|
-
organizationId: organizationId
|
|
2414
|
+
organizationId: organizationId,
|
|
2126
2415
|
}, stampWith);
|
|
2127
2416
|
if (!res.exportBundle) {
|
|
2128
2417
|
throw new TurnkeyError("No export bundle found in the response", TurnkeyErrorCodes.BAD_RESPONSE);
|
|
@@ -2146,21 +2435,27 @@ class TurnkeyClient {
|
|
|
2146
2435
|
* @param params.encryptedBundle - encrypted bundle containing the wallet seed phrase and metadata.
|
|
2147
2436
|
* @param params.walletName - name of the wallet to create upon import.
|
|
2148
2437
|
* @param params.accounts - array of account parameters to create in the imported wallet (defaults to standard Ethereum and Solana accounts).
|
|
2438
|
+
* @param params.organizationId - organization ID to import the wallet under a specific sub-organization (wallet will be associated with the sub-organization).
|
|
2149
2439
|
* @param params.userId - user ID to import the wallet for a specific user (defaults to the current session's userId).
|
|
2150
2440
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2151
2441
|
* @returns A promise that resolves to the ID of the imported wallet.
|
|
2152
2442
|
* @throws {TurnkeyError} If there is no active session, if the encrypted bundle is invalid, or if there is an error importing the wallet.
|
|
2153
2443
|
*/
|
|
2154
2444
|
this.importWallet = async (params) => {
|
|
2155
|
-
const { encryptedBundle, accounts, walletName, userId, stampWith } = params;
|
|
2156
|
-
const session = await this.storageManager.getActiveSession
|
|
2157
|
-
|
|
2158
|
-
|
|
2445
|
+
const { encryptedBundle, accounts, walletName, organizationId: organizationIdFromParams, userId: userIdFromParams, stampWith, } = params;
|
|
2446
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2447
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2448
|
+
if (!organizationId) {
|
|
2449
|
+
throw new TurnkeyError("Organization ID must be provided to import wallet", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2450
|
+
}
|
|
2451
|
+
const userId = userIdFromParams || session?.userId;
|
|
2452
|
+
if (!userId) {
|
|
2453
|
+
throw new TurnkeyError("User ID must be provided to import wallet", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2159
2454
|
}
|
|
2160
2455
|
return withTurnkeyErrorHandling(async () => {
|
|
2161
2456
|
const res = await this.httpClient.importWallet({
|
|
2162
|
-
organizationId:
|
|
2163
|
-
userId: userId
|
|
2457
|
+
organizationId: organizationId,
|
|
2458
|
+
userId: userId,
|
|
2164
2459
|
encryptedBundle,
|
|
2165
2460
|
walletName,
|
|
2166
2461
|
accounts: accounts || [
|
|
@@ -2175,7 +2470,7 @@ class TurnkeyClient {
|
|
|
2175
2470
|
}, {
|
|
2176
2471
|
errorMessage: "Failed to import wallet",
|
|
2177
2472
|
errorCode: TurnkeyErrorCodes.IMPORT_WALLET_ERROR,
|
|
2178
|
-
|
|
2473
|
+
customErrorsByMessages: {
|
|
2179
2474
|
"invalid mnemonic": {
|
|
2180
2475
|
message: "Invalid mnemonic input",
|
|
2181
2476
|
code: TurnkeyErrorCodes.BAD_REQUEST,
|
|
@@ -2198,21 +2493,27 @@ class TurnkeyClient {
|
|
|
2198
2493
|
* @param params.privateKeyName - name of the private key to create upon import.
|
|
2199
2494
|
* @param params.curve - the cryptographic curve used to generate a given private key
|
|
2200
2495
|
* @param params.addressFormat - address format of the private key to import.
|
|
2496
|
+
* @param params.organizationId - organization ID to import the private key under a specific sub-organization (private key will be associated with the sub-organization).
|
|
2201
2497
|
* @param params.userId - user ID to import the wallet for a specific user (defaults to the current session's userId).
|
|
2202
2498
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2203
2499
|
* @returns A promise that resolves to the ID of the imported wallet.
|
|
2204
2500
|
* @throws {TurnkeyError} If there is no active session, if the encrypted bundle is invalid, or if there is an error importing the wallet.
|
|
2205
2501
|
*/
|
|
2206
2502
|
this.importPrivateKey = async (params) => {
|
|
2207
|
-
const { encryptedBundle, privateKeyName, addressFormats, curve, userId, stampWith, } = params;
|
|
2208
|
-
const session = await this.storageManager.getActiveSession
|
|
2209
|
-
|
|
2210
|
-
|
|
2503
|
+
const { encryptedBundle, privateKeyName, addressFormats, curve, organizationId: organizationIdFromParams, userId: userIdFromParams, stampWith, } = params;
|
|
2504
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2505
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2506
|
+
if (!organizationId) {
|
|
2507
|
+
throw new TurnkeyError("Organization ID must be provided to import private key", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2508
|
+
}
|
|
2509
|
+
const userId = userIdFromParams || session?.userId;
|
|
2510
|
+
if (!userId) {
|
|
2511
|
+
throw new TurnkeyError("User ID must be provided to import private key", TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2211
2512
|
}
|
|
2212
2513
|
return withTurnkeyErrorHandling(async () => {
|
|
2213
2514
|
const res = await this.httpClient.importPrivateKey({
|
|
2214
|
-
organizationId
|
|
2215
|
-
userId
|
|
2515
|
+
organizationId,
|
|
2516
|
+
userId,
|
|
2216
2517
|
encryptedBundle,
|
|
2217
2518
|
privateKeyName,
|
|
2218
2519
|
curve,
|
|
@@ -2225,7 +2526,7 @@ class TurnkeyClient {
|
|
|
2225
2526
|
}, {
|
|
2226
2527
|
errorMessage: "Failed to import wallet",
|
|
2227
2528
|
errorCode: TurnkeyErrorCodes.IMPORT_WALLET_ERROR,
|
|
2228
|
-
|
|
2529
|
+
customErrorsByMessages: {
|
|
2229
2530
|
"invalid mnemonic": {
|
|
2230
2531
|
message: "Invalid mnemonic input",
|
|
2231
2532
|
code: TurnkeyErrorCodes.BAD_REQUEST,
|
|
@@ -2243,18 +2544,17 @@ class TurnkeyClient {
|
|
|
2243
2544
|
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2244
2545
|
*
|
|
2245
2546
|
* @param params.deleteWithoutExport - flag to delete the sub-organization without requiring all wallets to be exported first (defaults to false).
|
|
2547
|
+
* @param params.organizationId - organization ID to delete a specific sub-organization (defaults to the current session's organizationId).
|
|
2246
2548
|
* @param params.stampWith - parameter to stamp the request with a specific stamper.
|
|
2247
2549
|
* @returns A promise that resolves to a `TDeleteSubOrganizationResponse` object containing the result of the deletion.
|
|
2248
2550
|
* @throws {TurnkeyError} If there is no active session or if there is an error deleting the sub-organization.
|
|
2249
2551
|
*/
|
|
2250
2552
|
this.deleteSubOrganization = async (params) => {
|
|
2251
|
-
const { deleteWithoutExport = false, stampWith } = params || {};
|
|
2252
|
-
const session = await this.storageManager.getActiveSession
|
|
2253
|
-
|
|
2254
|
-
throw new TurnkeyError("No active session found. Please log in first.", TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
2255
|
-
}
|
|
2553
|
+
const { deleteWithoutExport = false, organizationId: organizationIdFromParams, stampWith, } = params || {};
|
|
2554
|
+
const session = await getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2555
|
+
const organizationId = organizationIdFromParams || session?.organizationId;
|
|
2256
2556
|
return withTurnkeyErrorHandling(async () => {
|
|
2257
|
-
return await this.httpClient.deleteSubOrganization({ deleteWithoutExport }, stampWith);
|
|
2557
|
+
return await this.httpClient.deleteSubOrganization({ deleteWithoutExport, ...(organizationId && { organizationId }) }, stampWith);
|
|
2258
2558
|
}, {
|
|
2259
2559
|
errorMessage: "Failed to delete sub-organization",
|
|
2260
2560
|
errorCode: TurnkeyErrorCodes.DELETE_SUB_ORGANIZATION_ERROR,
|