@turnkey/core 1.14.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__clients__/core.d.ts +87 -34
- package/dist/__clients__/core.d.ts.map +1 -1
- package/dist/__clients__/core.js +357 -199
- package/dist/__clients__/core.js.map +1 -1
- package/dist/__clients__/core.mjs +358 -200
- package/dist/__clients__/core.mjs.map +1 -1
- package/dist/__generated__/sdk-client-base.d.ts +8 -3
- package/dist/__generated__/sdk-client-base.d.ts.map +1 -1
- package/dist/__generated__/sdk-client-base.js +125 -63
- package/dist/__generated__/sdk-client-base.js.map +1 -1
- package/dist/__generated__/sdk-client-base.mjs +120 -58
- 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/__stampers__/api/base.d.ts +2 -1
- package/dist/__stampers__/api/base.d.ts.map +1 -1
- package/dist/__stampers__/api/mobile/stamper.d.ts +2 -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 +2 -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 +3 -1
- package/dist/__stampers__/passkey/base.d.ts.map +1 -1
- package/dist/__stampers__/passkey/base.js +19 -0
- package/dist/__stampers__/passkey/base.js.map +1 -1
- package/dist/__stampers__/passkey/base.mjs +20 -1
- package/dist/__stampers__/passkey/base.mjs.map +1 -1
- package/dist/__types__/auth.d.ts +2 -41
- package/dist/__types__/auth.d.ts.map +1 -1
- package/dist/__types__/auth.js.map +1 -1
- package/dist/__types__/auth.mjs.map +1 -1
- package/dist/__types__/config.d.ts +3 -2
- package/dist/__types__/config.d.ts.map +1 -1
- package/dist/__types__/enums.d.ts +1 -0
- package/dist/__types__/enums.d.ts.map +1 -1
- package/dist/__types__/enums.js +1 -0
- package/dist/__types__/enums.js.map +1 -1
- package/dist/__types__/enums.mjs +1 -0
- package/dist/__types__/enums.mjs.map +1 -1
- package/dist/__types__/http.d.ts +1 -14
- package/dist/__types__/http.d.ts.map +1 -1
- package/dist/__types__/index.d.ts +0 -1
- package/dist/__types__/index.d.ts.map +1 -1
- package/dist/__types__/method-types/shared.d.ts +28 -13
- package/dist/__types__/method-types/shared.d.ts.map +1 -1
- package/dist/__wallet__/stamper.d.ts +2 -1
- package/dist/__wallet__/stamper.d.ts.map +1 -1
- package/dist/__wallet__/stamper.js.map +1 -1
- package/dist/__wallet__/stamper.mjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -4
- package/dist/index.mjs.map +1 -1
- package/dist/turnkey-helpers.d.ts +4 -0
- package/dist/turnkey-helpers.d.ts.map +1 -1
- package/dist/turnkey-helpers.js +28 -0
- package/dist/turnkey-helpers.js.map +1 -1
- package/dist/turnkey-helpers.mjs +25 -1
- package/dist/turnkey-helpers.mjs.map +1 -1
- package/dist/utils.d.ts +41 -18
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +126 -57
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +100 -38
- package/dist/utils.mjs.map +1 -1
- package/package.json +6 -6
- package/dist/__types__/error.d.ts +0 -13
- package/dist/__types__/error.d.ts.map +0 -1
- package/dist/__types__/error.js +0 -18
- package/dist/__types__/error.js.map +0 -1
- package/dist/__types__/error.mjs +0 -16
- package/dist/__types__/error.mjs.map +0 -1
- package/dist/__types__/http.js +0 -11
- package/dist/__types__/http.js.map +0 -1
- package/dist/__types__/http.mjs +0 -9
- package/dist/__types__/http.mjs.map +0 -1
package/dist/__clients__/core.js
CHANGED
|
@@ -5,6 +5,7 @@ var sdkTypes = require('@turnkey/sdk-types');
|
|
|
5
5
|
var auth = require('../__types__/auth.js');
|
|
6
6
|
var enums = require('../__types__/enums.js');
|
|
7
7
|
var utils = require('../utils.js');
|
|
8
|
+
var crypto = require('@turnkey/crypto');
|
|
8
9
|
var base = require('../__storage__/base.js');
|
|
9
10
|
var base$1 = require('../__stampers__/api/base.js');
|
|
10
11
|
var base$2 = require('../__stampers__/passkey/base.js');
|
|
@@ -12,26 +13,68 @@ var turnkeyHelpers = require('../turnkey-helpers.js');
|
|
|
12
13
|
var jwtDecode = require('jwt-decode');
|
|
13
14
|
var base$3 = require('../__wallet__/base.js');
|
|
14
15
|
var ethers = require('ethers');
|
|
15
|
-
var crypto = require('@turnkey/crypto');
|
|
16
16
|
var apiKeyStamper = require('@turnkey/api-key-stamper');
|
|
17
17
|
var viem = require('viem');
|
|
18
18
|
|
|
19
|
-
const ERC20_TRANSFER_ABI = [
|
|
20
|
-
{
|
|
21
|
-
type: "function",
|
|
22
|
-
name: "transfer",
|
|
23
|
-
stateMutability: "nonpayable",
|
|
24
|
-
inputs: [
|
|
25
|
-
{ name: "to", type: "address" },
|
|
26
|
-
{ name: "amount", type: "uint256" },
|
|
27
|
-
],
|
|
28
|
-
outputs: [{ name: "success", type: "bool" }],
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
19
|
class TurnkeyClient {
|
|
32
20
|
constructor(config,
|
|
33
21
|
// Users can pass in their own stampers, or we will create them. Should we remove this?
|
|
34
22
|
apiKeyStamper$1, passkeyStamper, walletManager) {
|
|
23
|
+
/**
|
|
24
|
+
* Overrides the API key stamper configuration.
|
|
25
|
+
*
|
|
26
|
+
* - Set `temporaryPublicKey` to a non-empty string to override the default API key.
|
|
27
|
+
* - Set `temporaryPublicKey` to an empty string ("") to clear the temporary key and restore default behavior.
|
|
28
|
+
* - Omit `temporaryPublicKey` to leave it unchanged.
|
|
29
|
+
* - Useful for dynamically changing the API key used for signing requests.
|
|
30
|
+
*
|
|
31
|
+
* @param params.temporaryPublicKey - temporary public key to set (non-empty string), clear (empty string), or leave unchanged (omit).
|
|
32
|
+
* @returns A promise that resolves when the stamper has been updated.
|
|
33
|
+
* @throws {TurnkeyError} If the API key stamper is not initialized or if there is an error updating it.
|
|
34
|
+
*/
|
|
35
|
+
this.overrideApiKeyStamper = async (params) => {
|
|
36
|
+
return utils.withTurnkeyErrorHandling(async () => {
|
|
37
|
+
if (!this.apiKeyStamper) {
|
|
38
|
+
throw new sdkTypes.TurnkeyError("API key stamper is not initialized", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
39
|
+
}
|
|
40
|
+
const { temporaryPublicKey } = params;
|
|
41
|
+
// Only process if temporaryPublicKey is explicitly passed
|
|
42
|
+
if (temporaryPublicKey !== undefined) {
|
|
43
|
+
if (temporaryPublicKey === "") {
|
|
44
|
+
this.apiKeyStamper.clearTemporaryPublicKey();
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.apiKeyStamper.setTemporaryPublicKey(temporaryPublicKey);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}, {
|
|
51
|
+
errorMessage: "Failed to override API key stamper",
|
|
52
|
+
errorCode: sdkTypes.TurnkeyErrorCodes.INITIALIZE_API_KEY_STAMPER_ERROR,
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Overrides the passkey stamper with a new configuration.
|
|
57
|
+
*
|
|
58
|
+
* - This function updates the passkey stamper configuration without reinitializing the entire stamper.
|
|
59
|
+
* - Updates the stamper's configuration properties (e.g., allowCredentials, rpId, timeout, userVerification).
|
|
60
|
+
* - Useful for dynamically changing passkey configuration during runtime.
|
|
61
|
+
*
|
|
62
|
+
* @param params.config - new passkey stamper configuration to use.
|
|
63
|
+
* @returns A promise that resolves when the stamper configuration has been updated.
|
|
64
|
+
* @throws {TurnkeyError} If there is an error updating the stamper configuration or if the passkey stamper is not initialized.
|
|
65
|
+
*/
|
|
66
|
+
this.overridePasskeyStamper = async (params) => {
|
|
67
|
+
const { config } = params;
|
|
68
|
+
return utils.withTurnkeyErrorHandling(async () => {
|
|
69
|
+
if (!this.passkeyStamper) {
|
|
70
|
+
throw new sdkTypes.TurnkeyError("Passkey stamper is not initialized", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
71
|
+
}
|
|
72
|
+
this.passkeyStamper.updateConfig(config);
|
|
73
|
+
}, {
|
|
74
|
+
errorMessage: "Failed to override passkey stamper",
|
|
75
|
+
errorCode: sdkTypes.TurnkeyErrorCodes.INITIALIZE_PASSKEY_STAMPER_ERROR,
|
|
76
|
+
});
|
|
77
|
+
};
|
|
35
78
|
/**
|
|
36
79
|
* Creates a new TurnkeySDKClientBase instance with the provided configuration.
|
|
37
80
|
* This method is used internally to create the HTTP client for making API requests,
|
|
@@ -149,14 +192,14 @@ class TurnkeyClient {
|
|
|
149
192
|
if (params?.sessionKey) {
|
|
150
193
|
const session = await this.storageManager.getSession(params.sessionKey);
|
|
151
194
|
this.storageManager.clearSession(params.sessionKey);
|
|
152
|
-
this.
|
|
195
|
+
await this.deleteApiKeyPair({ publicKey: session?.publicKey });
|
|
153
196
|
}
|
|
154
197
|
else {
|
|
155
198
|
const sessionKey = await this.storageManager.getActiveSessionKey();
|
|
156
199
|
const session = await this.storageManager.getActiveSession();
|
|
157
200
|
if (sessionKey) {
|
|
158
201
|
this.storageManager.clearSession(sessionKey);
|
|
159
|
-
this.
|
|
202
|
+
await this.deleteApiKeyPair({ publicKey: session?.publicKey });
|
|
160
203
|
}
|
|
161
204
|
else {
|
|
162
205
|
throw new sdkTypes.TurnkeyError("No active session found to log out from.", sdkTypes.TurnkeyErrorCodes.NO_SESSION_FOUND);
|
|
@@ -180,18 +223,30 @@ class TurnkeyClient {
|
|
|
180
223
|
* @param params.sessionKey - session key to use for session creation (defaults to the default session key).
|
|
181
224
|
* @param params.expirationSeconds - session expiration time in seconds (defaults to the configured default).
|
|
182
225
|
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
226
|
+
* @param params.allowCredentials - optional list of allowed credentials for passkey authentication. This allows you to restrict which passkeys can be used for login.
|
|
183
227
|
* @returns A promise that resolves to a {@link PasskeyAuthResult}, which includes:
|
|
184
228
|
* - `sessionToken`: the signed JWT session token.
|
|
185
229
|
* - `credentialId`: an empty string.
|
|
186
230
|
* @throws {TurnkeyError} If there is an error during the passkey login process or if the user cancels the passkey prompt.
|
|
187
231
|
*/
|
|
188
232
|
this.loginWithPasskey = async (params) => {
|
|
189
|
-
|
|
233
|
+
const shouldOverrideConfig = params?.allowCredentials && this.passkeyStamper;
|
|
234
|
+
const currentConfig = this.config.passkeyConfig;
|
|
235
|
+
const generatedPublicKey = params?.publicKey || (await this.createApiKeyPair());
|
|
190
236
|
return await utils.withTurnkeyErrorHandling(async () => {
|
|
191
|
-
|
|
192
|
-
|
|
237
|
+
if (!this.passkeyStamper) {
|
|
238
|
+
throw new sdkTypes.TurnkeyError("Passkey stamper is not initialized", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
239
|
+
}
|
|
193
240
|
const sessionKey = params?.sessionKey || enums.SessionKey.DefaultSessionkey;
|
|
194
241
|
const expirationSeconds = params?.expirationSeconds || auth.DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
242
|
+
if (shouldOverrideConfig) {
|
|
243
|
+
// Override passkey stamper config to include allowCredentials
|
|
244
|
+
const mergedConfig = {
|
|
245
|
+
...currentConfig,
|
|
246
|
+
allowCredentials: params?.allowCredentials, // Can safely assert non-null due to check above
|
|
247
|
+
};
|
|
248
|
+
await this.overridePasskeyStamper({ config: mergedConfig });
|
|
249
|
+
}
|
|
195
250
|
if (!generatedPublicKey) {
|
|
196
251
|
throw new sdkTypes.TurnkeyError("A publickey could not be found or generated.", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
197
252
|
}
|
|
@@ -204,7 +259,6 @@ class TurnkeyClient {
|
|
|
204
259
|
sessionToken: sessionResponse.session,
|
|
205
260
|
sessionKey,
|
|
206
261
|
});
|
|
207
|
-
generatedPublicKey = undefined; // Key pair was successfully used, set to null to prevent cleanup
|
|
208
262
|
return {
|
|
209
263
|
sessionToken: sessionResponse.session,
|
|
210
264
|
// TODO: can we return the credentialId here?
|
|
@@ -221,15 +275,23 @@ class TurnkeyClient {
|
|
|
221
275
|
code: sdkTypes.TurnkeyErrorCodes.SELECT_PASSKEY_CANCELLED,
|
|
222
276
|
},
|
|
223
277
|
},
|
|
278
|
+
catchFn: async () => {
|
|
279
|
+
try {
|
|
280
|
+
await this.deleteApiKeyPair({ publicKey: generatedPublicKey });
|
|
281
|
+
}
|
|
282
|
+
catch (cleanupError) {
|
|
283
|
+
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
284
|
+
}
|
|
285
|
+
},
|
|
224
286
|
}, {
|
|
225
287
|
finallyFn: async () => {
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
288
|
+
if (shouldOverrideConfig) {
|
|
289
|
+
// we restore previous stamper after login attempt
|
|
290
|
+
await this.overridePasskeyStamper({
|
|
291
|
+
// we can assert this safely, since if this statement runs we are certian the passkey stamper
|
|
292
|
+
// is initialized
|
|
293
|
+
config: currentConfig,
|
|
294
|
+
});
|
|
233
295
|
}
|
|
234
296
|
},
|
|
235
297
|
});
|
|
@@ -248,17 +310,18 @@ class TurnkeyClient {
|
|
|
248
310
|
* @param params.expirationSeconds - session expiration time in seconds (defaults to the configured default).
|
|
249
311
|
* @param params.createSubOrgParams - parameters for creating a sub-organization (e.g., authenticators, user metadata).
|
|
250
312
|
* @param params.sessionKey - session key to use for storing the session (defaults to the default session key).
|
|
251
|
-
* @param params.organizationId - organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
252
313
|
* @returns A promise that resolves to a {@link PasskeyAuthResult}, which includes:
|
|
253
314
|
* - `sessionToken`: the signed JWT session token.
|
|
254
315
|
* - `credentialId`: the credential ID associated with the passkey created.
|
|
255
316
|
* @throws {TurnkeyError} If there is an error during passkey creation, sub-organization creation, or session storage.
|
|
256
317
|
*/
|
|
257
318
|
this.signUpWithPasskey = async (params) => {
|
|
258
|
-
const { passkeyDisplayName, challenge, expirationSeconds = auth.DEFAULT_SESSION_EXPIRATION_IN_SECONDS, createSubOrgParams, sessionKey = enums.SessionKey.DefaultSessionkey,
|
|
259
|
-
|
|
319
|
+
const { passkeyDisplayName, challenge, expirationSeconds = auth.DEFAULT_SESSION_EXPIRATION_IN_SECONDS, createSubOrgParams, sessionKey = enums.SessionKey.DefaultSessionkey, } = params || {};
|
|
320
|
+
const generatedPublicKey = await this.createApiKeyPair();
|
|
260
321
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
261
|
-
|
|
322
|
+
if (!this.passkeyStamper) {
|
|
323
|
+
throw new sdkTypes.TurnkeyError("Passkey stamper is not initialized", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
324
|
+
}
|
|
262
325
|
const passkeyName = passkeyDisplayName || `passkey-${Date.now()}`;
|
|
263
326
|
// A passkey will be created automatically when you call this function. The name is passed in
|
|
264
327
|
const passkey = await this.createPasskey({
|
|
@@ -290,25 +353,23 @@ class TurnkeyClient {
|
|
|
290
353
|
],
|
|
291
354
|
},
|
|
292
355
|
});
|
|
293
|
-
const res = await this.httpClient.
|
|
356
|
+
const res = await this.httpClient.proxySignupV2(signUpBody);
|
|
294
357
|
if (!res) {
|
|
295
358
|
throw new sdkTypes.TurnkeyError(`Sign up failed`, sdkTypes.TurnkeyErrorCodes.PASSKEY_SIGNUP_AUTH_ERROR);
|
|
296
359
|
}
|
|
297
|
-
const newGeneratedKeyPair = await this.
|
|
298
|
-
this.
|
|
360
|
+
const newGeneratedKeyPair = await this.createApiKeyPair();
|
|
361
|
+
await this.overrideApiKeyStamper({
|
|
362
|
+
temporaryPublicKey: generatedPublicKey,
|
|
363
|
+
});
|
|
299
364
|
const sessionResponse = await this.httpClient.stampLogin({
|
|
300
365
|
publicKey: newGeneratedKeyPair,
|
|
301
|
-
organizationId:
|
|
366
|
+
organizationId: res.organizationId,
|
|
302
367
|
expirationSeconds,
|
|
303
368
|
});
|
|
304
|
-
await
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
sessionKey,
|
|
309
|
-
}),
|
|
310
|
-
]);
|
|
311
|
-
generatedPublicKey = undefined; // Key pair was successfully used, set to null to prevent cleanup
|
|
369
|
+
await this.storeSession({
|
|
370
|
+
sessionToken: sessionResponse.session,
|
|
371
|
+
sessionKey,
|
|
372
|
+
});
|
|
312
373
|
return {
|
|
313
374
|
sessionToken: sessionResponse.session,
|
|
314
375
|
appProofs: res.appProofs,
|
|
@@ -319,14 +380,12 @@ class TurnkeyClient {
|
|
|
319
380
|
errorMessage: "Failed to sign up with passkey",
|
|
320
381
|
}, {
|
|
321
382
|
finallyFn: async () => {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
329
|
-
}
|
|
383
|
+
try {
|
|
384
|
+
await this.overrideApiKeyStamper({ temporaryPublicKey: "" });
|
|
385
|
+
await this.deleteApiKeyPair({ publicKey: generatedPublicKey });
|
|
386
|
+
}
|
|
387
|
+
catch (cleanupError) {
|
|
388
|
+
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
330
389
|
}
|
|
331
390
|
},
|
|
332
391
|
});
|
|
@@ -466,13 +525,11 @@ class TurnkeyClient {
|
|
|
466
525
|
this.buildWalletLoginRequest = async (params) => {
|
|
467
526
|
const { walletProvider, publicKey: providedPublicKey } = params;
|
|
468
527
|
const expirationSeconds = params.expirationSeconds || auth.DEFAULT_SESSION_EXPIRATION_IN_SECONDS;
|
|
469
|
-
|
|
528
|
+
const futureSessionPublicKey = providedPublicKey ?? (await this.createApiKeyPair());
|
|
470
529
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
471
530
|
if (!this.walletManager?.stamper) {
|
|
472
531
|
throw new sdkTypes.TurnkeyError("Wallet stamper is not initialized", sdkTypes.TurnkeyErrorCodes.WALLET_MANAGER_COMPONENT_NOT_INITIALIZED);
|
|
473
532
|
}
|
|
474
|
-
const futureSessionPublicKey = providedPublicKey ??
|
|
475
|
-
(generatedPublicKey = await this.apiKeyStamper?.createKeyPair());
|
|
476
533
|
if (!futureSessionPublicKey) {
|
|
477
534
|
throw new sdkTypes.TurnkeyError("Failed to find or generate a public key for building the wallet login request", sdkTypes.TurnkeyErrorCodes.WALLET_BUILD_LOGIN_REQUEST_ERROR);
|
|
478
535
|
}
|
|
@@ -514,9 +571,12 @@ class TurnkeyClient {
|
|
|
514
571
|
errorCode: sdkTypes.TurnkeyErrorCodes.WALLET_BUILD_LOGIN_REQUEST_ERROR,
|
|
515
572
|
errorMessage: "Failed to build wallet login request",
|
|
516
573
|
catchFn: async () => {
|
|
517
|
-
if
|
|
574
|
+
// we only clean up the generated key pair if we created it here
|
|
575
|
+
if (!providedPublicKey) {
|
|
518
576
|
try {
|
|
519
|
-
await this.
|
|
577
|
+
await this.deleteApiKeyPair({
|
|
578
|
+
publicKey: futureSessionPublicKey,
|
|
579
|
+
});
|
|
520
580
|
}
|
|
521
581
|
catch (cleanupError) {
|
|
522
582
|
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
@@ -601,7 +661,7 @@ class TurnkeyClient {
|
|
|
601
661
|
],
|
|
602
662
|
},
|
|
603
663
|
});
|
|
604
|
-
const res = await this.httpClient.
|
|
664
|
+
const res = await this.httpClient.proxySignupV2(signUpBody);
|
|
605
665
|
if (!res) {
|
|
606
666
|
throw new sdkTypes.TurnkeyError(`Sign up failed`, sdkTypes.TurnkeyErrorCodes.WALLET_SIGNUP_AUTH_ERROR);
|
|
607
667
|
}
|
|
@@ -676,7 +736,7 @@ class TurnkeyClient {
|
|
|
676
736
|
],
|
|
677
737
|
},
|
|
678
738
|
});
|
|
679
|
-
signupRes = await this.httpClient.
|
|
739
|
+
signupRes = await this.httpClient.proxySignupV2(signUpBody);
|
|
680
740
|
if (!signupRes) {
|
|
681
741
|
throw new sdkTypes.TurnkeyError(`Sign up failed`, sdkTypes.TurnkeyErrorCodes.WALLET_SIGNUP_AUTH_ERROR);
|
|
682
742
|
}
|
|
@@ -708,21 +768,29 @@ class TurnkeyClient {
|
|
|
708
768
|
*
|
|
709
769
|
* - This function initiates the OTP flow by sending a one-time password (OTP) code to the user's contact information (email address or phone number) via the auth proxy.
|
|
710
770
|
* - Supports both email and SMS OTP types.
|
|
711
|
-
* - Returns an OTP ID
|
|
771
|
+
* - Returns an OTP ID and an encryption target bundle required for subsequent OTP verification.
|
|
772
|
+
* - The `otpEncryptionTargetBundle` must be used to encrypt the OTP code and a client-generated public key before calling `verifyOtp`.
|
|
712
773
|
*
|
|
713
774
|
* @param params.otpType - type of OTP to initialize (OtpType.Email or OtpType.Sms).
|
|
714
775
|
* @param params.contact - contact information for the user (e.g., email address or phone number).
|
|
715
776
|
* @param params.organizationId - optional organization ID to target (defaults to the session's organization ID or the parent organization ID).
|
|
716
|
-
* @returns A promise that resolves to
|
|
777
|
+
* @returns A promise that resolves to an {@link InitOtpResult}, which includes:
|
|
778
|
+
* - `otpId`: the ID of the initiated OTP.
|
|
779
|
+
* - `otpEncryptionTargetBundle`: the signed encryption target bundle for encrypting the OTP code.
|
|
717
780
|
* @throws {TurnkeyError} If there is an error during the OTP initialization process or if the maximum number of OTPs has been reached.
|
|
718
781
|
*/
|
|
719
782
|
this.initOtp = async (params) => {
|
|
720
783
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
721
|
-
const initOtpRes = await this.httpClient.
|
|
722
|
-
if (!initOtpRes ||
|
|
723
|
-
|
|
784
|
+
const initOtpRes = await this.httpClient.proxyInitOtpV2(params);
|
|
785
|
+
if (!initOtpRes ||
|
|
786
|
+
!initOtpRes.otpId ||
|
|
787
|
+
!initOtpRes.otpEncryptionTargetBundle) {
|
|
788
|
+
throw new sdkTypes.TurnkeyError("Failed to initialize OTP: otpId or otpEncryptionTargetBundle is missing", sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR);
|
|
724
789
|
}
|
|
725
|
-
return
|
|
790
|
+
return {
|
|
791
|
+
otpId: initOtpRes.otpId,
|
|
792
|
+
otpEncryptionTargetBundle: initOtpRes.otpEncryptionTargetBundle,
|
|
793
|
+
};
|
|
726
794
|
}, {
|
|
727
795
|
errorMessage: "Failed to initialize OTP",
|
|
728
796
|
errorCode: sdkTypes.TurnkeyErrorCodes.INIT_OTP_ERROR,
|
|
@@ -737,45 +805,38 @@ class TurnkeyClient {
|
|
|
737
805
|
/**
|
|
738
806
|
* Verifies the OTP code sent to the user.
|
|
739
807
|
*
|
|
740
|
-
* -
|
|
741
|
-
* - If verification is successful, it returns
|
|
808
|
+
* - Under the hood, the OTP code and an ephemeral client public key are encrypted to the enclave's target key (from `initOtp`) before being sent for verification.
|
|
809
|
+
* - If verification is successful, it returns a verification token bound to the public key.
|
|
742
810
|
* - The verification token can be used for subsequent login or sign-up flows.
|
|
743
|
-
* - Handles both email and SMS OTP types.
|
|
744
811
|
*
|
|
745
812
|
* @param params.otpId - ID of the OTP to verify (returned from `initOtp`).
|
|
746
|
-
* @param params.otpCode - OTP code entered by the user.
|
|
747
|
-
* @param params.
|
|
748
|
-
* @param params.
|
|
749
|
-
* @param params.publicKey - public key the verification token is bound to for ownership verification (client signature verification during login/signup). This public key is optional; if not provided, a new key pair will be generated.
|
|
813
|
+
* @param params.otpCode - the OTP code entered by the user.
|
|
814
|
+
* @param params.otpEncryptionTargetBundle - the encryption target bundle returned from `initOtp`.
|
|
815
|
+
* @param params.publicKey - optional public key to bind to the verification token. If not provided, a new key pair will be generated via the configured `apiKeyStamper`.
|
|
750
816
|
* @returns A promise that resolves to an object containing:
|
|
751
|
-
* - subOrganizationId: sub-organization ID if the contact is already associated with a sub-organization, or an empty string if not.
|
|
752
817
|
* - verificationToken: verification token to be used for login or sign-up.
|
|
818
|
+
* - publicKey: the public key bound to the verification token (either the one provided or the auto-generated one).
|
|
753
819
|
* @throws {TurnkeyError} If there is an error during the OTP verification process, such as an invalid code or network failure.
|
|
754
820
|
*/
|
|
755
821
|
this.verifyOtp = async (params) => {
|
|
756
|
-
const { otpId, otpCode,
|
|
757
|
-
|
|
822
|
+
const { otpId, otpCode, otpEncryptionTargetBundle } = params;
|
|
823
|
+
// we track auto-generated keys so we can clean them up on errors
|
|
824
|
+
const publicKey = params.publicKey ?? (await this.createApiKeyPair());
|
|
825
|
+
if (!publicKey) {
|
|
826
|
+
throw new sdkTypes.TurnkeyError("No public key available. Either pass a publicKey or ensure apiKeyStamper is configured.", sdkTypes.TurnkeyErrorCodes.INVALID_REQUEST);
|
|
827
|
+
}
|
|
758
828
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
759
|
-
const
|
|
829
|
+
const encryptedOtpBundle = await crypto.encryptOtpCodeToBundle(otpCode, otpEncryptionTargetBundle, publicKey);
|
|
830
|
+
const verifyOtpRes = await this.httpClient.proxyVerifyOtpV2({
|
|
760
831
|
otpId: otpId,
|
|
761
|
-
|
|
762
|
-
publicKey: resolvedPublicKey,
|
|
832
|
+
encryptedOtpBundle: encryptedOtpBundle,
|
|
763
833
|
});
|
|
764
834
|
if (!verifyOtpRes) {
|
|
765
835
|
throw new sdkTypes.TurnkeyError(`OTP verification failed`, sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
766
836
|
}
|
|
767
|
-
const accountRes = await this.httpClient.proxyGetAccount({
|
|
768
|
-
filterType: enums.OtpTypeToFilterTypeMap[otpType],
|
|
769
|
-
filterValue: contact,
|
|
770
|
-
verificationToken: verifyOtpRes.verificationToken,
|
|
771
|
-
});
|
|
772
|
-
if (!accountRes) {
|
|
773
|
-
throw new sdkTypes.TurnkeyError(`Account fetch failed`, sdkTypes.TurnkeyErrorCodes.ACCOUNT_FETCH_ERROR);
|
|
774
|
-
}
|
|
775
|
-
const subOrganizationId = accountRes.organizationId;
|
|
776
837
|
return {
|
|
777
|
-
subOrganizationId: subOrganizationId,
|
|
778
838
|
verificationToken: verifyOtpRes.verificationToken,
|
|
839
|
+
publicKey,
|
|
779
840
|
};
|
|
780
841
|
}, {
|
|
781
842
|
errorMessage: "Failed to verify OTP",
|
|
@@ -786,19 +847,29 @@ class TurnkeyClient {
|
|
|
786
847
|
code: sdkTypes.TurnkeyErrorCodes.INVALID_OTP_CODE,
|
|
787
848
|
},
|
|
788
849
|
},
|
|
850
|
+
catchFn: async () => {
|
|
851
|
+
// we only clean up the generated key pair if we created it here
|
|
852
|
+
if (!params.publicKey) {
|
|
853
|
+
try {
|
|
854
|
+
await this.deleteApiKeyPair({ publicKey });
|
|
855
|
+
}
|
|
856
|
+
catch (cleanupError) {
|
|
857
|
+
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
},
|
|
789
861
|
});
|
|
790
862
|
};
|
|
791
863
|
/**
|
|
792
864
|
* Logs in a user using an OTP verification token.
|
|
793
865
|
*
|
|
794
866
|
* - This function logs in a user using the verification token received after OTP verification (from email or SMS).
|
|
795
|
-
* -
|
|
867
|
+
* - The client signature is always produced using the private key bound to the verification token during `verifyOtp`.
|
|
868
|
+
* - The verification token's embedded key becomes the session public key.
|
|
796
869
|
* - Optionally invalidates any existing sessions for the user if `invalidateExisting` is set to true.
|
|
797
870
|
* - Stores the resulting session token under the specified session key, or the default session key if not provided.
|
|
798
|
-
* - Handles cleanup of unused key pairs if login fails.
|
|
799
871
|
*
|
|
800
872
|
* @param params.verificationToken - verification token received after OTP verification.
|
|
801
|
-
* @param params.publicKey - public key to use for authentication. If not provided, a new key pair will be generated.
|
|
802
873
|
* @param params.organizationId - optional organization ID to target (defaults to the verified subOrg ID linked to the verification token contact).
|
|
803
874
|
* @param params.invalidateExisting - flag to invalidate existing session for the user.
|
|
804
875
|
* @param params.sessionKey - session key to use for session creation (defaults to the default session key).
|
|
@@ -807,34 +878,35 @@ class TurnkeyClient {
|
|
|
807
878
|
* @throws {TurnkeyError} If there is an error during the OTP login process or if key pair cleanup fails.
|
|
808
879
|
*/
|
|
809
880
|
this.loginWithOtp = async (params) => {
|
|
810
|
-
const { verificationToken, invalidateExisting = false,
|
|
881
|
+
const { verificationToken, invalidateExisting = false, organizationId, sessionKey = enums.SessionKey.DefaultSessionkey, } = params;
|
|
811
882
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
812
|
-
const { message, publicKey:
|
|
813
|
-
|
|
814
|
-
|
|
883
|
+
const { message, publicKey: verificationPublicKey } = utils.getClientSignatureMessageForLogin({ verificationToken });
|
|
884
|
+
// we sign with the verification token key. This is the key bound during
|
|
885
|
+
// verifyOtp() and is what Turnkey expects to sign the client signature for login
|
|
886
|
+
const signature = await this.signWithApiKey({
|
|
887
|
+
message,
|
|
888
|
+
publicKey: verificationPublicKey,
|
|
815
889
|
});
|
|
816
|
-
this.apiKeyStamper?.setTemporaryPublicKey(publicKey);
|
|
817
|
-
const signature = await this.apiKeyStamper?.sign(message, apiKeyStamper.SignatureFormat.Raw);
|
|
818
890
|
if (!signature) {
|
|
819
891
|
throw new sdkTypes.TurnkeyError(`Failed to sign client signature for OTP login`, sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
820
892
|
}
|
|
821
893
|
const clientSignature = {
|
|
822
894
|
message: message,
|
|
823
|
-
publicKey:
|
|
895
|
+
publicKey: verificationPublicKey,
|
|
824
896
|
scheme: "CLIENT_SIGNATURE_SCHEME_API_P256",
|
|
825
897
|
signature: signature,
|
|
826
898
|
};
|
|
827
|
-
|
|
899
|
+
// the verification token's public key is also used as the session public key for login
|
|
900
|
+
const loginRes = await this.httpClient.proxyOtpLoginV2({
|
|
828
901
|
verificationToken,
|
|
829
|
-
publicKey:
|
|
830
|
-
invalidateExisting,
|
|
902
|
+
publicKey: verificationPublicKey,
|
|
831
903
|
clientSignature,
|
|
904
|
+
invalidateExisting,
|
|
832
905
|
...(organizationId && { organizationId }),
|
|
833
906
|
});
|
|
834
|
-
if (!
|
|
907
|
+
if (!loginRes) {
|
|
835
908
|
throw new sdkTypes.TurnkeyError(`Auth proxy OTP login failed`, sdkTypes.TurnkeyErrorCodes.OTP_LOGIN_ERROR);
|
|
836
909
|
}
|
|
837
|
-
const loginRes = await res;
|
|
838
910
|
if (!loginRes.session) {
|
|
839
911
|
throw new sdkTypes.TurnkeyError("No session returned from OTP login", sdkTypes.TurnkeyErrorCodes.OTP_LOGIN_ERROR);
|
|
840
912
|
}
|
|
@@ -848,21 +920,6 @@ class TurnkeyClient {
|
|
|
848
920
|
}, {
|
|
849
921
|
errorMessage: "Failed to log in with OTP",
|
|
850
922
|
errorCode: sdkTypes.TurnkeyErrorCodes.OTP_LOGIN_ERROR,
|
|
851
|
-
catchFn: async () => {
|
|
852
|
-
// Clean up the generated key pair if it wasn't successfully used
|
|
853
|
-
if (publicKey) {
|
|
854
|
-
try {
|
|
855
|
-
await this.apiKeyStamper?.deleteKeyPair(publicKey);
|
|
856
|
-
}
|
|
857
|
-
catch (cleanupError) {
|
|
858
|
-
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
},
|
|
862
|
-
}, {
|
|
863
|
-
finallyFn: async () => {
|
|
864
|
-
this.apiKeyStamper?.clearTemporaryPublicKey();
|
|
865
|
-
},
|
|
866
923
|
});
|
|
867
924
|
};
|
|
868
925
|
/**
|
|
@@ -870,7 +927,7 @@ class TurnkeyClient {
|
|
|
870
927
|
*
|
|
871
928
|
* - This function signs up a user using the verification token received after OTP verification (from email or SMS).
|
|
872
929
|
* - Creates a new sub-organization for the user with the provided parameters and associates the contact (email or phone) with the sub-organization.
|
|
873
|
-
* -
|
|
930
|
+
* - The verification token's embedded key becomes the session public key.
|
|
874
931
|
* - Stores the resulting session token under the specified session key, or the default session key if not provided.
|
|
875
932
|
* - Handles both email and SMS OTP types, and supports additional sub-organization creation parameters.
|
|
876
933
|
*
|
|
@@ -885,7 +942,7 @@ class TurnkeyClient {
|
|
|
885
942
|
* @throws {TurnkeyError} If there is an error during the OTP sign-up process or session storage.
|
|
886
943
|
*/
|
|
887
944
|
this.signUpWithOtp = async (params) => {
|
|
888
|
-
const { verificationToken, contact, otpType, createSubOrgParams, invalidateExisting, sessionKey,
|
|
945
|
+
const { verificationToken, contact, otpType, createSubOrgParams, invalidateExisting, sessionKey, } = params;
|
|
889
946
|
// build sign up body without client signature first
|
|
890
947
|
const signUpBody = utils.buildSignUpBody({
|
|
891
948
|
createSubOrgParams: {
|
|
@@ -897,7 +954,7 @@ class TurnkeyClient {
|
|
|
897
954
|
},
|
|
898
955
|
});
|
|
899
956
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
900
|
-
const { message, publicKey:
|
|
957
|
+
const { message, publicKey: verificationPublicKey } = utils.getClientSignatureMessageForSignup({
|
|
901
958
|
verificationToken,
|
|
902
959
|
...(signUpBody.userEmail && { email: signUpBody.userEmail }),
|
|
903
960
|
...(signUpBody.userPhoneNumber && {
|
|
@@ -907,18 +964,22 @@ class TurnkeyClient {
|
|
|
907
964
|
authenticators: signUpBody.authenticators,
|
|
908
965
|
oauthProviders: signUpBody.oauthProviders,
|
|
909
966
|
});
|
|
910
|
-
|
|
911
|
-
|
|
967
|
+
// we sign with the verification token key. This is the key bound during
|
|
968
|
+
// verifyOtp() and is what Turnkey expects to sign the client signature for signup
|
|
969
|
+
const signature = await this.signWithApiKey({
|
|
970
|
+
message,
|
|
971
|
+
publicKey: verificationPublicKey,
|
|
972
|
+
});
|
|
912
973
|
if (!signature) {
|
|
913
974
|
throw new sdkTypes.TurnkeyError(`Failed to sign client signature for OTP sign up`, sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
914
975
|
}
|
|
915
976
|
const clientSignature = {
|
|
916
977
|
message: message,
|
|
917
|
-
publicKey:
|
|
978
|
+
publicKey: verificationPublicKey,
|
|
918
979
|
scheme: "CLIENT_SIGNATURE_SCHEME_API_P256",
|
|
919
980
|
signature: signature,
|
|
920
981
|
};
|
|
921
|
-
const signupRes = await this.httpClient.
|
|
982
|
+
const signupRes = await this.httpClient.proxySignupV2({
|
|
922
983
|
...signUpBody,
|
|
923
984
|
clientSignature,
|
|
924
985
|
});
|
|
@@ -927,7 +988,6 @@ class TurnkeyClient {
|
|
|
927
988
|
}
|
|
928
989
|
const otpRes = await this.loginWithOtp({
|
|
929
990
|
verificationToken,
|
|
930
|
-
publicKey: publicKey,
|
|
931
991
|
...(invalidateExisting && { invalidateExisting }),
|
|
932
992
|
...(sessionKey && { sessionKey }),
|
|
933
993
|
});
|
|
@@ -936,39 +996,26 @@ class TurnkeyClient {
|
|
|
936
996
|
appProofs: signupRes.appProofs,
|
|
937
997
|
};
|
|
938
998
|
}, {
|
|
939
|
-
catchFn: async () => {
|
|
940
|
-
// Clean up the generated key pair if it wasn't successfully used
|
|
941
|
-
if (publicKey) {
|
|
942
|
-
try {
|
|
943
|
-
await this.apiKeyStamper?.deleteKeyPair(publicKey);
|
|
944
|
-
}
|
|
945
|
-
catch (cleanupError) {
|
|
946
|
-
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
},
|
|
950
999
|
errorCode: sdkTypes.TurnkeyErrorCodes.OTP_SIGNUP_ERROR,
|
|
951
1000
|
errorMessage: "Failed to sign up with OTP",
|
|
952
|
-
}, {
|
|
953
|
-
finallyFn: async () => {
|
|
954
|
-
this.apiKeyStamper?.clearTemporaryPublicKey();
|
|
955
|
-
},
|
|
956
1001
|
});
|
|
957
1002
|
};
|
|
958
1003
|
/**
|
|
959
|
-
* Completes the OTP authentication flow by verifying the OTP
|
|
1004
|
+
* Completes the OTP authentication flow by verifying the encrypted OTP bundle and then either signing up or logging in the user.
|
|
960
1005
|
*
|
|
961
|
-
* - This function
|
|
1006
|
+
* - This function encrypts the OTP code and the session public key to the enclave's target key, verifies the OTP, and then either signs up or logs in the user.
|
|
962
1007
|
* - If the contact is not associated with an existing sub-organization, it will automatically create a new sub-organization and complete the sign-up flow.
|
|
963
1008
|
* - If the contact is already associated with a sub-organization, it will complete the login flow.
|
|
964
|
-
* -
|
|
1009
|
+
* - The key bound to the verification token during `verifyOtp` is always reused as the session public key.
|
|
1010
|
+
* - Supports passing a custom public key for binding into the verification token, invalidating existing session, specifying a session key, and providing additional sub-organization creation parameters.
|
|
965
1011
|
* - Handles both email and SMS OTP types.
|
|
966
1012
|
*
|
|
967
1013
|
* @param params.otpId - ID of the OTP to complete (returned from `initOtp`).
|
|
968
|
-
* @param params.otpCode - OTP code entered by the user.
|
|
1014
|
+
* @param params.otpCode - the OTP code entered by the user.
|
|
1015
|
+
* @param params.otpEncryptionTargetBundle - the encryption target bundle returned from `initOtp`.
|
|
969
1016
|
* @param params.contact - contact information for the user (e.g., email address or phone number).
|
|
970
1017
|
* @param params.otpType - type of OTP being completed (OtpType.Email or OtpType.Sms).
|
|
971
|
-
* @param params.publicKey - public key to
|
|
1018
|
+
* @param params.publicKey - public key to bind to the verification token via `verifyOtp`. If not provided, a new key pair will be generated. This key becomes the session public key.
|
|
972
1019
|
* @param params.invalidateExisting - flag to invalidate existing sessions for the user.
|
|
973
1020
|
* @param params.sessionKey - session key to use for session creation (defaults to the default session key).
|
|
974
1021
|
* @param params.createSubOrgParams - parameters for sub-organization creation (e.g., authenticators, user metadata).
|
|
@@ -979,18 +1026,30 @@ class TurnkeyClient {
|
|
|
979
1026
|
* @throws {TurnkeyError} If there is an error during OTP verification, sign-up, or login.
|
|
980
1027
|
*/
|
|
981
1028
|
this.completeOtp = async (params) => {
|
|
982
|
-
const { otpId, otpCode, contact, otpType,
|
|
1029
|
+
const { otpId, otpCode, otpEncryptionTargetBundle, contact, otpType, invalidateExisting = false, sessionKey, createSubOrgParams, } = params;
|
|
1030
|
+
const publicKey = params.publicKey ?? (await this.createApiKeyPair());
|
|
1031
|
+
if (!publicKey) {
|
|
1032
|
+
throw new sdkTypes.TurnkeyError("No public key available. Either pass a publicKey or ensure apiKeyStamper is configured.", sdkTypes.TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1033
|
+
}
|
|
983
1034
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
984
|
-
const {
|
|
985
|
-
otpId
|
|
986
|
-
otpCode
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
publicKey: publicKey,
|
|
1035
|
+
const { verificationToken } = await this.verifyOtp({
|
|
1036
|
+
otpId,
|
|
1037
|
+
otpCode,
|
|
1038
|
+
otpEncryptionTargetBundle,
|
|
1039
|
+
publicKey,
|
|
990
1040
|
});
|
|
991
1041
|
if (!verificationToken) {
|
|
992
1042
|
throw new sdkTypes.TurnkeyError("No verification token returned from OTP verification", sdkTypes.TurnkeyErrorCodes.VERIFY_OTP_ERROR);
|
|
993
1043
|
}
|
|
1044
|
+
const accountRes = await this.httpClient.proxyGetAccount({
|
|
1045
|
+
filterType: enums.OtpTypeToFilterTypeMap[otpType],
|
|
1046
|
+
filterValue: contact,
|
|
1047
|
+
verificationToken: verificationToken,
|
|
1048
|
+
});
|
|
1049
|
+
if (!accountRes) {
|
|
1050
|
+
throw new sdkTypes.TurnkeyError(`Account fetch failed`, sdkTypes.TurnkeyErrorCodes.ACCOUNT_FETCH_ERROR);
|
|
1051
|
+
}
|
|
1052
|
+
const subOrganizationId = accountRes.organizationId;
|
|
994
1053
|
if (!subOrganizationId) {
|
|
995
1054
|
const signUpRes = await this.signUpWithOtp({
|
|
996
1055
|
verificationToken,
|
|
@@ -999,7 +1058,6 @@ class TurnkeyClient {
|
|
|
999
1058
|
...(createSubOrgParams && { createSubOrgParams }),
|
|
1000
1059
|
...(invalidateExisting && { invalidateExisting }),
|
|
1001
1060
|
...(sessionKey && { sessionKey }),
|
|
1002
|
-
publicKey: publicKey,
|
|
1003
1061
|
});
|
|
1004
1062
|
return {
|
|
1005
1063
|
...signUpRes,
|
|
@@ -1010,7 +1068,6 @@ class TurnkeyClient {
|
|
|
1010
1068
|
else {
|
|
1011
1069
|
const loginRes = await this.loginWithOtp({
|
|
1012
1070
|
verificationToken,
|
|
1013
|
-
publicKey: publicKey,
|
|
1014
1071
|
...(invalidateExisting && { invalidateExisting }),
|
|
1015
1072
|
...(sessionKey && { sessionKey }),
|
|
1016
1073
|
});
|
|
@@ -1023,6 +1080,16 @@ class TurnkeyClient {
|
|
|
1023
1080
|
}, {
|
|
1024
1081
|
errorMessage: "Failed to complete OTP process",
|
|
1025
1082
|
errorCode: sdkTypes.TurnkeyErrorCodes.OTP_COMPLETION_ERROR,
|
|
1083
|
+
catchFn: async () => {
|
|
1084
|
+
if (!params.publicKey) {
|
|
1085
|
+
try {
|
|
1086
|
+
await this.deleteApiKeyPair({ publicKey });
|
|
1087
|
+
}
|
|
1088
|
+
catch (cleanupError) {
|
|
1089
|
+
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1026
1093
|
});
|
|
1027
1094
|
};
|
|
1028
1095
|
/**
|
|
@@ -1147,7 +1214,7 @@ class TurnkeyClient {
|
|
|
1147
1214
|
// Clean up the generated key pair if it wasn't successfully used
|
|
1148
1215
|
if (publicKey) {
|
|
1149
1216
|
try {
|
|
1150
|
-
await this.
|
|
1217
|
+
await this.deleteApiKeyPair({ publicKey });
|
|
1151
1218
|
}
|
|
1152
1219
|
catch (cleanupError) {
|
|
1153
1220
|
throw new sdkTypes.TurnkeyError(`Failed to clean up generated key pair`, sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
@@ -1184,10 +1251,11 @@ class TurnkeyClient {
|
|
|
1184
1251
|
providerName,
|
|
1185
1252
|
oidcToken,
|
|
1186
1253
|
},
|
|
1254
|
+
...(createSubOrgParams?.oauthProviders ?? []),
|
|
1187
1255
|
],
|
|
1188
1256
|
},
|
|
1189
1257
|
});
|
|
1190
|
-
const signupRes = await this.httpClient.
|
|
1258
|
+
const signupRes = await this.httpClient.proxySignupV2(signUpBody);
|
|
1191
1259
|
if (!signupRes) {
|
|
1192
1260
|
throw new sdkTypes.TurnkeyError(`Auth proxy OAuth signup failed`, sdkTypes.TurnkeyErrorCodes.OAUTH_SIGNUP_ERROR);
|
|
1193
1261
|
}
|
|
@@ -1766,7 +1834,7 @@ class TurnkeyClient {
|
|
|
1766
1834
|
throw new sdkTypes.TurnkeyError("Invalid ERC20 amount. Use a base-unit integer string.", sdkTypes.TurnkeyErrorCodes.INVALID_REQUEST);
|
|
1767
1835
|
}
|
|
1768
1836
|
const data = viem.encodeFunctionData({
|
|
1769
|
-
abi: ERC20_TRANSFER_ABI,
|
|
1837
|
+
abi: utils.ERC20_TRANSFER_ABI,
|
|
1770
1838
|
functionName: "transfer",
|
|
1771
1839
|
args: [to, parsedAmount],
|
|
1772
1840
|
});
|
|
@@ -2349,37 +2417,71 @@ class TurnkeyClient {
|
|
|
2349
2417
|
});
|
|
2350
2418
|
};
|
|
2351
2419
|
/**
|
|
2352
|
-
* Adds
|
|
2420
|
+
* Adds one or more OAuth provider audiences to the user.
|
|
2353
2421
|
*
|
|
2354
|
-
* -
|
|
2355
|
-
* -
|
|
2356
|
-
* -
|
|
2357
|
-
* - If the user's email is not set or not verified, attempts to update and verify the email using the email from the
|
|
2358
|
-
* -
|
|
2422
|
+
* - Accepts either an `oidcToken`, a list of `oidcClaims`, or both. At least one must be provided.
|
|
2423
|
+
* - The issuer (`iss`) of the `oidcToken` and all `oidcClaims` must match, ensuring they belong to the same OAuth provider.
|
|
2424
|
+
* - Checks for an existing account for the `oidcToken` (if provided) and for each `oidcClaims` entry, and throws if any of them are already associated with a different sub-organization.
|
|
2425
|
+
* - If the user's email is not set or not verified and an `oidcToken` is provided, attempts to update and verify the email using the email from the token.
|
|
2426
|
+
* - Submits a single `createOauthProviders` request containing the token (if any) and all additional claims.
|
|
2359
2427
|
* - Optionally allows stamping the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2360
2428
|
*
|
|
2361
2429
|
* @param params.providerName - name of the OAuth provider to add (e.g., "Google", "Apple").
|
|
2362
|
-
* @param params.oidcToken - OIDC token for the OAuth provider.
|
|
2430
|
+
* @param params.oidcToken - OIDC token for the OAuth provider. Either `oidcToken` or `oidcClaims` (or both) must be provided.
|
|
2431
|
+
* @param params.oidcClaims - additional `iss`/`sub`/`aud` claims to register as additional audiences for the same identity.
|
|
2363
2432
|
* @param params.organizationId - organization ID to specify the sub-organization (defaults to the current session's organizationId).
|
|
2364
2433
|
* @param params.userId - user ID to add the provider for a specific user (defaults to current session's userId).
|
|
2365
2434
|
* @param params.stampWith - parameter to stamp the request with a specific stamper (StamperType.Passkey, StamperType.ApiKey, or StamperType.Wallet).
|
|
2366
2435
|
* @returns A promise that resolves to an array of provider IDs associated with the user.
|
|
2367
|
-
* @throws {TurnkeyError} If there is no active session, if the
|
|
2436
|
+
* @throws {TurnkeyError} If there is no active session, if neither `oidcToken` nor `oidcClaims` was provided, if the issuer claims do not all match, if any of the audiences are already associated with another account, or if there is an error adding the OAuth provider.
|
|
2368
2437
|
*/
|
|
2369
2438
|
this.addOauthProvider = async (params) => {
|
|
2370
|
-
const { providerName, oidcToken, stampWith = this.config.defaultStamperType, } = params;
|
|
2439
|
+
const { providerName, oidcToken, oidcClaims = [], stampWith = this.config.defaultStamperType, } = params;
|
|
2440
|
+
if (!oidcToken && oidcClaims.length === 0) {
|
|
2441
|
+
throw new sdkTypes.TurnkeyError("At least one of `oidcToken` or `oidcClaims` must be provided to add an OAuth provider", sdkTypes.TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2442
|
+
}
|
|
2371
2443
|
const session = await utils.getActiveSessionOrThrowIfRequired(stampWith, this.storageManager.getActiveSession);
|
|
2372
2444
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
if (
|
|
2381
|
-
|
|
2382
|
-
|
|
2445
|
+
// Parse the oidc token so we can get the email/iss. The email is used to update the user's email for social linking.
|
|
2446
|
+
// The iss is used to ensure all passed-in claims share the same issuer.
|
|
2447
|
+
const { email: oidcEmail, iss: tokenIss } = oidcToken
|
|
2448
|
+
? jwtDecode.jwtDecode(oidcToken) || {}
|
|
2449
|
+
: { email: undefined, iss: undefined };
|
|
2450
|
+
// Verify that all passed-in claims share the same issuer (and match the token's issuer if a token was provided).
|
|
2451
|
+
const issuers = new Set();
|
|
2452
|
+
if (tokenIss)
|
|
2453
|
+
issuers.add(tokenIss);
|
|
2454
|
+
for (const claim of oidcClaims) {
|
|
2455
|
+
issuers.add(claim.iss);
|
|
2456
|
+
}
|
|
2457
|
+
if (issuers.size > 1) {
|
|
2458
|
+
throw new sdkTypes.TurnkeyError("All `oidcToken` and `oidcClaims` entries must share the same issuer (`iss`)", sdkTypes.TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2459
|
+
}
|
|
2460
|
+
// Check that none of the audiences are already associated with a different sub-organization.
|
|
2461
|
+
const accountChecks = [];
|
|
2462
|
+
if (oidcToken) {
|
|
2463
|
+
// Look up the sub-organization associated with passed in oidc token
|
|
2464
|
+
accountChecks.push(this.httpClient.proxyGetAccount({
|
|
2465
|
+
filterType: enums.FilterType.OidcToken,
|
|
2466
|
+
filterValue: oidcToken,
|
|
2467
|
+
}));
|
|
2468
|
+
}
|
|
2469
|
+
// Also look up the sub-organization for each oidcClaim
|
|
2470
|
+
for (const claim of oidcClaims) {
|
|
2471
|
+
accountChecks.push(this.httpClient.proxyGetAccount({
|
|
2472
|
+
filterType: enums.FilterType.OidcClaims,
|
|
2473
|
+
filterValue: JSON.stringify(claim),
|
|
2474
|
+
}));
|
|
2475
|
+
}
|
|
2476
|
+
const accountResults = await Promise.all(accountChecks);
|
|
2477
|
+
for (const accountRes of accountResults) {
|
|
2478
|
+
if (!accountRes) {
|
|
2479
|
+
throw new sdkTypes.TurnkeyError(`Account fetch failed`, sdkTypes.TurnkeyErrorCodes.ACCOUNT_FETCH_ERROR);
|
|
2480
|
+
}
|
|
2481
|
+
if (accountRes.organizationId &&
|
|
2482
|
+
accountRes.organizationId !== session?.organizationId) {
|
|
2483
|
+
throw new sdkTypes.TurnkeyError("Account already exists with this OIDC token or claims", sdkTypes.TurnkeyErrorCodes.ACCOUNT_ALREADY_EXISTS);
|
|
2484
|
+
}
|
|
2383
2485
|
}
|
|
2384
2486
|
const userId = params?.userId || session?.userId;
|
|
2385
2487
|
if (!userId) {
|
|
@@ -2389,9 +2491,7 @@ class TurnkeyClient {
|
|
|
2389
2491
|
if (!organizationId) {
|
|
2390
2492
|
throw new sdkTypes.TurnkeyError("Organization ID is required to add OAuth provider", sdkTypes.TurnkeyErrorCodes.INVALID_REQUEST);
|
|
2391
2493
|
}
|
|
2392
|
-
|
|
2393
|
-
const { email: oidcEmail, iss } = jwtDecode.jwtDecode(oidcToken) || {};
|
|
2394
|
-
if (iss === utils.googleISS) {
|
|
2494
|
+
if (oidcToken && tokenIss === utils.googleISS) {
|
|
2395
2495
|
const verifiedSuborg = await this.httpClient.proxyGetAccount({
|
|
2396
2496
|
filterType: "EMAIL",
|
|
2397
2497
|
filterValue: oidcEmail,
|
|
@@ -2424,14 +2524,13 @@ class TurnkeyClient {
|
|
|
2424
2524
|
}, stampWith);
|
|
2425
2525
|
}
|
|
2426
2526
|
}
|
|
2527
|
+
const oauthProviders = [
|
|
2528
|
+
...(oidcToken ? [{ providerName, oidcToken }] : []),
|
|
2529
|
+
...oidcClaims.map((claim) => ({ providerName, oidcClaims: claim })),
|
|
2530
|
+
];
|
|
2427
2531
|
const createProviderRes = await this.httpClient.createOauthProviders({
|
|
2428
2532
|
userId,
|
|
2429
|
-
oauthProviders
|
|
2430
|
-
{
|
|
2431
|
-
providerName,
|
|
2432
|
-
oidcToken,
|
|
2433
|
-
},
|
|
2434
|
-
],
|
|
2533
|
+
oauthProviders,
|
|
2435
2534
|
}, stampWith);
|
|
2436
2535
|
if (!createProviderRes) {
|
|
2437
2536
|
throw new sdkTypes.TurnkeyError("Failed to create OAuth provider", sdkTypes.TurnkeyErrorCodes.ADD_OAUTH_PROVIDER_ERROR);
|
|
@@ -2975,7 +3074,7 @@ class TurnkeyClient {
|
|
|
2975
3074
|
const session = await this.storageManager.getSession(sessionKey);
|
|
2976
3075
|
if (session) {
|
|
2977
3076
|
await Promise.all([
|
|
2978
|
-
this.
|
|
3077
|
+
this.deleteApiKeyPair({ publicKey: session.publicKey }),
|
|
2979
3078
|
this.storageManager.clearSession(sessionKey),
|
|
2980
3079
|
]);
|
|
2981
3080
|
}
|
|
@@ -3043,9 +3142,8 @@ class TurnkeyClient {
|
|
|
3043
3142
|
if (!this.httpClient) {
|
|
3044
3143
|
throw new sdkTypes.TurnkeyError("HTTP client is not initialized. Please initialize the client before refreshing the session.", sdkTypes.TurnkeyErrorCodes.CLIENT_NOT_INITIALIZED);
|
|
3045
3144
|
}
|
|
3046
|
-
|
|
3145
|
+
const keyPair = publicKey ?? (await this.createApiKeyPair());
|
|
3047
3146
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
3048
|
-
keyPair = publicKey ?? (await this.apiKeyStamper?.createKeyPair());
|
|
3049
3147
|
if (!keyPair) {
|
|
3050
3148
|
throw new sdkTypes.TurnkeyError("Failed to create new key pair.", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
3051
3149
|
}
|
|
@@ -3065,6 +3163,17 @@ class TurnkeyClient {
|
|
|
3065
3163
|
}, {
|
|
3066
3164
|
errorMessage: "Failed to refresh session",
|
|
3067
3165
|
errorCode: sdkTypes.TurnkeyErrorCodes.REFRESH_SESSION_ERROR,
|
|
3166
|
+
catchFn: async () => {
|
|
3167
|
+
// we only delete the keypair if we generated it here
|
|
3168
|
+
if (!publicKey) {
|
|
3169
|
+
try {
|
|
3170
|
+
await this.deleteApiKeyPair({ publicKey: keyPair });
|
|
3171
|
+
}
|
|
3172
|
+
catch (cleanupError) {
|
|
3173
|
+
throw new sdkTypes.TurnkeyError("Failed to clean up generated key pair", sdkTypes.TurnkeyErrorCodes.KEY_PAIR_CLEANUP_ERROR, cleanupError);
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
},
|
|
3068
3177
|
});
|
|
3069
3178
|
};
|
|
3070
3179
|
/**
|
|
@@ -3185,7 +3294,7 @@ class TurnkeyClient {
|
|
|
3185
3294
|
for (const publicKey of publicKeys) {
|
|
3186
3295
|
if (!sessionTokensMap[publicKey]) {
|
|
3187
3296
|
try {
|
|
3188
|
-
await this.
|
|
3297
|
+
await this.deleteApiKeyPair({ publicKey });
|
|
3189
3298
|
}
|
|
3190
3299
|
catch (error) {
|
|
3191
3300
|
throw new sdkTypes.TurnkeyError(`Failed to delete unused key pair ${publicKey}`, sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR, error);
|
|
@@ -3200,34 +3309,84 @@ class TurnkeyClient {
|
|
|
3200
3309
|
/**
|
|
3201
3310
|
* Creates a new API key pair and returns the public key.
|
|
3202
3311
|
*
|
|
3203
|
-
* - This function generates a new API key pair and stores it in the underlying key store
|
|
3312
|
+
* - This function generates a new API key pair and stores it in the underlying key store.
|
|
3204
3313
|
* - If an external key pair is provided, it will use that key pair for creation instead of generating a new one.
|
|
3205
|
-
* - If `storeOverride` is set to true, the generated or provided public key will be set as the override key in the API key stamper, making it the active key for subsequent signing operations.
|
|
3206
3314
|
* - Ensures the API key stamper is initialized before proceeding.
|
|
3207
3315
|
* - Handles both native CryptoKeyPair objects and raw key material.
|
|
3208
3316
|
*
|
|
3209
3317
|
* @param params.externalKeyPair - An externally generated key pair (either a CryptoKeyPair or an object with publicKey/privateKey strings) to use instead of generating a new one.
|
|
3210
|
-
* @param params.storeOverride - If true, sets the generated or provided public key as the override key in the API key stamper (defaults to false).
|
|
3211
3318
|
* @return A promise that resolves to the public key of the created or provided API key pair as a string.
|
|
3212
3319
|
* @throws {TurnkeyError} If the API key stamper is not initialized or if there is an error during key pair creation or storage.
|
|
3213
3320
|
*/
|
|
3214
3321
|
this.createApiKeyPair = async (params) => {
|
|
3215
3322
|
return utils.withTurnkeyErrorHandling(async () => {
|
|
3216
3323
|
const externalKeyPair = params?.externalKeyPair;
|
|
3217
|
-
const storeOverride = params?.storeOverride ?? false;
|
|
3218
3324
|
if (!this.apiKeyStamper) {
|
|
3219
3325
|
throw new sdkTypes.TurnkeyError("API Key Stamper is not initialized.", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
3220
3326
|
}
|
|
3221
3327
|
const publicKey = await this.apiKeyStamper.createKeyPair(externalKeyPair ? externalKeyPair : undefined);
|
|
3222
|
-
if (storeOverride && publicKey) {
|
|
3223
|
-
this.apiKeyStamper.setTemporaryPublicKey(publicKey);
|
|
3224
|
-
}
|
|
3225
3328
|
return publicKey;
|
|
3226
3329
|
}, {
|
|
3227
3330
|
errorMessage: "Failed to create API key pair",
|
|
3228
3331
|
errorCode: sdkTypes.TurnkeyErrorCodes.CREATE_API_KEY_PAIR_ERROR,
|
|
3229
3332
|
});
|
|
3230
3333
|
};
|
|
3334
|
+
/**
|
|
3335
|
+
* Deletes an API key pair from persistent storage.
|
|
3336
|
+
*
|
|
3337
|
+
* - This function removes a stored API key pair from the underlying key store (IndexedDB) based on its public key.
|
|
3338
|
+
* - Ensures that the API key stamper is initialized before proceeding with deletion.
|
|
3339
|
+
* - Intended for cleaning up key pairs that are not associated with active sessions, such as after failed authentication attempts where a temporary key pair was created but never used.
|
|
3340
|
+
* - Should NOT be used to delete key pairs that are associated with active sessions; use `clearSession` or `clearAllSessions` instead.
|
|
3341
|
+
*
|
|
3342
|
+
* @param params.publicKey - The public key of the API key pair to delete.
|
|
3343
|
+
* @returns A promise that resolves when the key pair is successfully deleted.
|
|
3344
|
+
* @throws {TurnkeyError} If the API key stamper is not initialized or if there is an error during key pair deletion.
|
|
3345
|
+
*/
|
|
3346
|
+
this.deleteApiKeyPair = async (params) => {
|
|
3347
|
+
const { publicKey } = params;
|
|
3348
|
+
return utils.withTurnkeyErrorHandling(async () => {
|
|
3349
|
+
if (!this.apiKeyStamper) {
|
|
3350
|
+
throw new sdkTypes.TurnkeyError("API Key Stamper is not initialized.", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
3351
|
+
}
|
|
3352
|
+
await this.apiKeyStamper.deleteKeyPair(publicKey);
|
|
3353
|
+
}, {
|
|
3354
|
+
errorMessage: "Failed to delete API key pair",
|
|
3355
|
+
errorCode: sdkTypes.TurnkeyErrorCodes.DELETE_API_KEY_PAIR_ERROR,
|
|
3356
|
+
});
|
|
3357
|
+
};
|
|
3358
|
+
/**
|
|
3359
|
+
* Signs a message using a key pair stored in the API key stamper.
|
|
3360
|
+
*
|
|
3361
|
+
* - This function signs the provided message string with the private key identified by `publicKey`.
|
|
3362
|
+
* - The message is SHA-256 hashed internally before signing (ECDSA P-256).
|
|
3363
|
+
* - Returns a compact hex signature (r || s) suitable for use as a client signature.
|
|
3364
|
+
* - The key pair must already exist in the key store (e.g., created via `createApiKeyPair`).
|
|
3365
|
+
*
|
|
3366
|
+
* @param params.message - the message string to sign.
|
|
3367
|
+
* @param params.publicKey - the public key identifying which key pair to sign with.
|
|
3368
|
+
* @returns A promise that resolves to the compact hex signature string.
|
|
3369
|
+
* @throws {TurnkeyError} If the API key stamper is not initialized or the key pair is not found.
|
|
3370
|
+
*/
|
|
3371
|
+
this.signWithApiKey = async (params) => {
|
|
3372
|
+
const { message, publicKey } = params;
|
|
3373
|
+
let previousTemporaryKey;
|
|
3374
|
+
return utils.withTurnkeyErrorHandling(async () => {
|
|
3375
|
+
if (!this.apiKeyStamper) {
|
|
3376
|
+
throw new sdkTypes.TurnkeyError("API Key Stamper is not initialized.", sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR);
|
|
3377
|
+
}
|
|
3378
|
+
previousTemporaryKey = this.apiKeyStamper.getTemporaryPublicKey();
|
|
3379
|
+
this.apiKeyStamper.setTemporaryPublicKey(publicKey);
|
|
3380
|
+
return await this.apiKeyStamper.sign(message, apiKeyStamper.SignatureFormat.Raw);
|
|
3381
|
+
}, {
|
|
3382
|
+
errorMessage: "Failed to sign with API key",
|
|
3383
|
+
errorCode: sdkTypes.TurnkeyErrorCodes.INTERNAL_ERROR,
|
|
3384
|
+
}, {
|
|
3385
|
+
finallyFn: async () => {
|
|
3386
|
+
this.apiKeyStamper?.setTemporaryPublicKey(previousTemporaryKey);
|
|
3387
|
+
},
|
|
3388
|
+
});
|
|
3389
|
+
};
|
|
3231
3390
|
/**
|
|
3232
3391
|
* Fetches the WalletKit proxy authentication configuration from the auth proxy.
|
|
3233
3392
|
*
|
|
@@ -3400,7 +3559,7 @@ class TurnkeyClient {
|
|
|
3400
3559
|
* @param params.stampWith - Optional stamper to use for polling.
|
|
3401
3560
|
*
|
|
3402
3561
|
* @returns A promise resolving to the transaction status payload if successful.
|
|
3403
|
-
* @throws {
|
|
3562
|
+
* @throws {TurnkeyError} If the transaction fails, is cancelled, or times out.
|
|
3404
3563
|
*/
|
|
3405
3564
|
async pollTransactionStatus(params) {
|
|
3406
3565
|
const { organizationId: organizationIdFromParams, stampWith = this.config.defaultStamperType, sendTransactionStatusId, pollingIntervalMs, } = params;
|
|
@@ -3419,14 +3578,13 @@ class TurnkeyClient {
|
|
|
3419
3578
|
sendTransactionStatusId,
|
|
3420
3579
|
});
|
|
3421
3580
|
const txStatus = resp?.txStatus;
|
|
3422
|
-
const txError = resp?.txError;
|
|
3423
3581
|
if (!txStatus)
|
|
3424
3582
|
return;
|
|
3425
|
-
if (
|
|
3583
|
+
if (txStatus === "FAILED" || txStatus === "CANCELLED") {
|
|
3426
3584
|
// TODO: use API enum in the future
|
|
3427
3585
|
clearInterval(ref);
|
|
3428
3586
|
clearTimeout(timeoutRef);
|
|
3429
|
-
reject(
|
|
3587
|
+
reject(new sdkTypes.TurnkeyError(resp.error?.message || `Transaction ${resp.txStatus}`, sdkTypes.TurnkeyErrorCodes.POLL_TRANSACTION_STATUS_ERROR, resp));
|
|
3430
3588
|
return;
|
|
3431
3589
|
}
|
|
3432
3590
|
if (txStatus === "COMPLETED" || txStatus === "INCLUDED") {
|