@account-kit/signer 4.31.2 → 4.33.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/esm/base.d.ts +11 -8
- package/dist/esm/base.js +141 -38
- package/dist/esm/base.js.map +1 -1
- package/dist/esm/client/base.d.ts +132 -9
- package/dist/esm/client/base.js +34 -4
- package/dist/esm/client/base.js.map +1 -1
- package/dist/esm/client/index.d.ts +36 -14
- package/dist/esm/client/index.js +36 -18
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/types.d.ts +19 -0
- package/dist/esm/client/types.js.map +1 -1
- package/dist/esm/signer.d.ts +88 -33
- package/dist/esm/signer.js +28 -3
- package/dist/esm/signer.js.map +1 -1
- package/dist/esm/solanaSigner.d.ts +3 -3
- package/dist/esm/solanaSigner.js +1 -1
- package/dist/esm/solanaSigner.js.map +1 -1
- package/dist/esm/types.d.ts +1 -0
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/base.d.ts +11 -8
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/client/base.d.ts +132 -9
- package/dist/types/client/base.d.ts.map +1 -1
- package/dist/types/client/index.d.ts +36 -14
- package/dist/types/client/index.d.ts.map +1 -1
- package/dist/types/client/types.d.ts +19 -0
- package/dist/types/client/types.d.ts.map +1 -1
- package/dist/types/signer.d.ts +88 -33
- package/dist/types/signer.d.ts.map +1 -1
- package/dist/types/solanaSigner.d.ts +3 -3
- package/dist/types/solanaSigner.d.ts.map +1 -1
- package/dist/types/types.d.ts +1 -0
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/package.json +6 -7
- package/src/base.ts +191 -63
- package/src/client/base.ts +36 -7
- package/src/client/index.ts +41 -18
- package/src/client/types.ts +21 -0
- package/src/signer.ts +36 -3
- package/src/solanaSigner.ts +4 -4
- package/src/types.ts +1 -0
- package/src/version.ts +1 -1
package/dist/esm/base.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { type SmartAccountAuthenticator } from "@aa-sdk/core";
|
|
2
|
-
import { type GetTransactionType, type Hex, type IsNarrowable, type LocalAccount, type SerializeTransactionFn, type SignableMessage, type TransactionSerializable, type TransactionSerialized, type TypedData, type TypedDataDefinition } from "viem";
|
|
3
|
-
import { type Authorization } from "viem/experimental";
|
|
1
|
+
import { type SmartAccountAuthenticator, type AuthorizationRequest } from "@aa-sdk/core";
|
|
2
|
+
import { type GetTransactionType, type Hex, type IsNarrowable, type LocalAccount, type SerializeTransactionFn, type SignableMessage, type SignedAuthorization, type TransactionSerializable, type TransactionSerialized, type TypedData, type TypedDataDefinition } from "viem";
|
|
4
3
|
import type { BaseSignerClient } from "./client/base";
|
|
5
|
-
import type
|
|
4
|
+
import { type MfaFactor, type OauthConfig, type User, type VerifyMfaParams, type AddMfaParams, type AddMfaResult, type RemoveMfaParams, type AuthLinkingPrompt } from "./client/types.js";
|
|
6
5
|
import { type SessionManagerParams } from "./session/manager.js";
|
|
7
6
|
import type { AuthParams } from "./signer";
|
|
8
7
|
import { SolanaSigner } from "./solanaSigner.js";
|
|
@@ -11,6 +10,7 @@ export interface BaseAlchemySignerParams<TClient extends BaseSignerClient> {
|
|
|
11
10
|
client: TClient;
|
|
12
11
|
sessionConfig?: Omit<SessionManagerParams, "client">;
|
|
13
12
|
initialError?: ErrorInfo;
|
|
13
|
+
initialAuthLinkingPrompt?: AuthLinkingPrompt;
|
|
14
14
|
}
|
|
15
15
|
export type EmailConfig = {
|
|
16
16
|
mode?: "MAGIC_LINK" | "OTP";
|
|
@@ -38,7 +38,7 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
|
|
|
38
38
|
* @param {SessionConfig} param0.sessionConfig Configuration for managing sessions
|
|
39
39
|
* @param {ErrorInfo | undefined} param0.initialError Error already present on the signer when initialized, if any
|
|
40
40
|
*/
|
|
41
|
-
constructor({ client, sessionConfig, initialError, }: BaseAlchemySignerParams<TClient>);
|
|
41
|
+
constructor({ client, sessionConfig, initialError, initialAuthLinkingPrompt, }: BaseAlchemySignerParams<TClient>);
|
|
42
42
|
/**
|
|
43
43
|
* Allows you to subscribe to events emitted by the signer
|
|
44
44
|
*
|
|
@@ -277,10 +277,10 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
|
|
|
277
277
|
* });
|
|
278
278
|
* ```
|
|
279
279
|
*
|
|
280
|
-
* @param {
|
|
281
|
-
* @returns {Promise<
|
|
280
|
+
* @param {AuthorizationRequest<number>} unsignedAuthorization the authorization to be signed
|
|
281
|
+
* @returns {Promise<SignedAuthorization<number>> | undefined} a promise that resolves to the authorization with the signature
|
|
282
282
|
*/
|
|
283
|
-
signAuthorization: (unsignedAuthorization:
|
|
283
|
+
signAuthorization: (unsignedAuthorization: AuthorizationRequest<number>) => Promise<SignedAuthorization<number>>;
|
|
284
284
|
/**
|
|
285
285
|
* Gets the current MFA status
|
|
286
286
|
*
|
|
@@ -450,6 +450,7 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
|
|
|
450
450
|
private authenticateWithPasskey;
|
|
451
451
|
private authenticateWithOauth;
|
|
452
452
|
private authenticateWithOtp;
|
|
453
|
+
private setAwaitingEmailAuth;
|
|
453
454
|
private handleOauthReturn;
|
|
454
455
|
private handleMfaRequired;
|
|
455
456
|
private getExpirationSeconds;
|
|
@@ -613,4 +614,6 @@ export declare abstract class BaseAlchemySigner<TClient extends BaseSignerClient
|
|
|
613
614
|
*/
|
|
614
615
|
getConfig: () => Promise<SignerConfig>;
|
|
615
616
|
protected fetchConfig: () => Promise<SignerConfig>;
|
|
617
|
+
private setAuthLinkingPrompt;
|
|
618
|
+
private waitForConnected;
|
|
616
619
|
}
|
package/dist/esm/base.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { takeBytes } from "@aa-sdk/core";
|
|
1
|
+
import { takeBytes, } from "@aa-sdk/core";
|
|
2
2
|
import { hashMessage, hashTypedData, keccak256, serializeTransaction, } from "viem";
|
|
3
3
|
import { toAccount } from "viem/accounts";
|
|
4
|
-
import { hashAuthorization } from "viem/experimental";
|
|
5
4
|
import { subscribeWithSelector } from "zustand/middleware";
|
|
6
5
|
import { createStore } from "zustand/vanilla";
|
|
6
|
+
import {} from "./client/types.js";
|
|
7
7
|
import { NotAuthenticatedError } from "./errors.js";
|
|
8
8
|
import { SignerLogger } from "./metrics.js";
|
|
9
9
|
import { SessionManager, } from "./session/manager.js";
|
|
10
10
|
import { SolanaSigner } from "./solanaSigner.js";
|
|
11
11
|
import { AlchemySignerStatus, } from "./types.js";
|
|
12
12
|
import { assertNever } from "./utils/typeAssertions.js";
|
|
13
|
+
import { hashAuthorization } from "viem/utils";
|
|
13
14
|
/**
|
|
14
15
|
* Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.
|
|
15
16
|
* Implements the `SmartAccountAuthenticator` interface and handles various signer events.
|
|
@@ -25,7 +26,7 @@ export class BaseAlchemySigner {
|
|
|
25
26
|
* @param {SessionConfig} param0.sessionConfig Configuration for managing sessions
|
|
26
27
|
* @param {ErrorInfo | undefined} param0.initialError Error already present on the signer when initialized, if any
|
|
27
28
|
*/
|
|
28
|
-
constructor({ client, sessionConfig, initialError, }) {
|
|
29
|
+
constructor({ client, sessionConfig, initialError, initialAuthLinkingPrompt, }) {
|
|
29
30
|
Object.defineProperty(this, "signerType", {
|
|
30
31
|
enumerable: true,
|
|
31
32
|
configurable: true,
|
|
@@ -73,22 +74,28 @@ export class BaseAlchemySigner {
|
|
|
73
74
|
// is fired. In the Client and SessionManager we use EventEmitter because it's easier to handle internally
|
|
74
75
|
switch (event) {
|
|
75
76
|
case "connected":
|
|
76
|
-
return this.store
|
|
77
|
-
listener(this.store.getState().user)
|
|
77
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ status }) => status, (status) => status === AlchemySignerStatus.CONNECTED &&
|
|
78
|
+
listener(this.store.getState().user));
|
|
78
79
|
case "disconnected":
|
|
79
|
-
return this.store
|
|
80
|
-
listener()
|
|
80
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ status }) => status, (status) => status === AlchemySignerStatus.DISCONNECTED &&
|
|
81
|
+
listener());
|
|
81
82
|
case "statusChanged":
|
|
82
|
-
return this.store
|
|
83
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ status }) => status, listener);
|
|
83
84
|
case "errorChanged":
|
|
84
|
-
return this.store
|
|
85
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ error }) => error, (error) => listener(error ?? undefined));
|
|
85
86
|
case "newUserSignup":
|
|
86
|
-
return this.store
|
|
87
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ isNewUser }) => isNewUser, (isNewUser) => {
|
|
87
88
|
if (isNewUser)
|
|
88
89
|
listener();
|
|
89
|
-
}
|
|
90
|
+
});
|
|
90
91
|
case "mfaStatusChanged":
|
|
91
|
-
return this.store
|
|
92
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ mfaStatus }) => mfaStatus, (mfaStatus) => listener(mfaStatus));
|
|
93
|
+
case "emailAuthLinkingRequired":
|
|
94
|
+
return subscribeWithDelayedFireImmediately(this.store, ({ authLinkingStatus }) => authLinkingStatus, (authLinkingStatus) => {
|
|
95
|
+
if (authLinkingStatus) {
|
|
96
|
+
listener(authLinkingStatus.email);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
92
99
|
default:
|
|
93
100
|
assertNever(event, `Unknown event type ${event}`);
|
|
94
101
|
}
|
|
@@ -471,8 +478,8 @@ export class BaseAlchemySigner {
|
|
|
471
478
|
* });
|
|
472
479
|
* ```
|
|
473
480
|
*
|
|
474
|
-
* @param {
|
|
475
|
-
* @returns {Promise<
|
|
481
|
+
* @param {AuthorizationRequest<number>} unsignedAuthorization the authorization to be signed
|
|
482
|
+
* @returns {Promise<SignedAuthorization<number>> | undefined} a promise that resolves to the authorization with the signature
|
|
476
483
|
*/
|
|
477
484
|
Object.defineProperty(this, "signAuthorization", {
|
|
478
485
|
enumerable: true,
|
|
@@ -482,7 +489,12 @@ export class BaseAlchemySigner {
|
|
|
482
489
|
const hashedAuthorization = hashAuthorization(unsignedAuthorization);
|
|
483
490
|
const signedAuthorizationHex = await this.inner.signRawMessage(hashedAuthorization);
|
|
484
491
|
const signature = this.unpackSignRawMessageBytes(signedAuthorizationHex);
|
|
485
|
-
|
|
492
|
+
const { address, contractAddress, ...unsignedAuthorizationRest } = unsignedAuthorization;
|
|
493
|
+
return {
|
|
494
|
+
...unsignedAuthorizationRest,
|
|
495
|
+
...signature,
|
|
496
|
+
address: address ?? contractAddress,
|
|
497
|
+
};
|
|
486
498
|
})
|
|
487
499
|
});
|
|
488
500
|
/**
|
|
@@ -731,23 +743,17 @@ export class BaseAlchemySigner {
|
|
|
731
743
|
return this.completeEmailAuth(params);
|
|
732
744
|
}
|
|
733
745
|
const { orgId, otpId, isNewUser } = await this.initOrCreateEmailUser(params.email, params.emailMode, params.multiFactors, params.redirectParams);
|
|
734
|
-
this.
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
this.store.
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
});
|
|
746
|
+
this.setAwaitingEmailAuth({ orgId, otpId, isNewUser });
|
|
747
|
+
// Clear the auth linking status if the email has changed. This would mean
|
|
748
|
+
// that the previously initiated social login is not associated with the
|
|
749
|
+
// email which is now being used to login.
|
|
750
|
+
const { authLinkingStatus } = this.store.getState();
|
|
751
|
+
if (authLinkingStatus && authLinkingStatus.email !== params.email) {
|
|
752
|
+
this.store.setState({ authLinkingStatus: undefined });
|
|
753
|
+
}
|
|
743
754
|
// We wait for the session manager to emit a connected event if
|
|
744
755
|
// cross tab sessions are permitted
|
|
745
|
-
return
|
|
746
|
-
const removeListener = this.sessionManager.on("connected", (session) => {
|
|
747
|
-
resolve(session.user);
|
|
748
|
-
removeListener();
|
|
749
|
-
});
|
|
750
|
-
});
|
|
756
|
+
return this.waitForConnected();
|
|
751
757
|
}
|
|
752
758
|
});
|
|
753
759
|
Object.defineProperty(this, "authenticateWithPasskey", {
|
|
@@ -790,6 +796,7 @@ export class BaseAlchemySigner {
|
|
|
790
796
|
configurable: true,
|
|
791
797
|
writable: true,
|
|
792
798
|
value: async (args) => {
|
|
799
|
+
this.store.setState({ authLinkingStatus: undefined });
|
|
793
800
|
const params = {
|
|
794
801
|
...args,
|
|
795
802
|
expirationSeconds: this.getExpirationSeconds(),
|
|
@@ -797,9 +804,12 @@ export class BaseAlchemySigner {
|
|
|
797
804
|
if (params.mode === "redirect") {
|
|
798
805
|
return this.inner.oauthWithRedirect(params);
|
|
799
806
|
}
|
|
800
|
-
|
|
801
|
-
|
|
807
|
+
const result = await this.inner.oauthWithPopup(params);
|
|
808
|
+
if (!isAuthLinkingPrompt(result)) {
|
|
809
|
+
return result;
|
|
802
810
|
}
|
|
811
|
+
this.setAuthLinkingPrompt(result);
|
|
812
|
+
return this.waitForConnected();
|
|
803
813
|
}
|
|
804
814
|
});
|
|
805
815
|
Object.defineProperty(this, "authenticateWithOtp", {
|
|
@@ -825,12 +835,7 @@ export class BaseAlchemySigner {
|
|
|
825
835
|
});
|
|
826
836
|
if (response.mfaRequired) {
|
|
827
837
|
this.handleMfaRequired(response.encryptedPayload, response.multiFactors);
|
|
828
|
-
return
|
|
829
|
-
const removeListener = this.sessionManager.on("connected", (session) => {
|
|
830
|
-
resolve(session.user);
|
|
831
|
-
removeListener();
|
|
832
|
-
});
|
|
833
|
-
});
|
|
838
|
+
return this.waitForConnected();
|
|
834
839
|
}
|
|
835
840
|
const user = await this.inner.completeAuthWithBundle({
|
|
836
841
|
bundle: response.bundle,
|
|
@@ -845,9 +850,34 @@ export class BaseAlchemySigner {
|
|
|
845
850
|
isNewUser: false,
|
|
846
851
|
});
|
|
847
852
|
}
|
|
853
|
+
const { authLinkingStatus } = this.store.getState();
|
|
854
|
+
if (authLinkingStatus) {
|
|
855
|
+
(async () => {
|
|
856
|
+
this.inner.addOauthProvider({
|
|
857
|
+
providerName: authLinkingStatus.providerName,
|
|
858
|
+
oidcToken: authLinkingStatus.idToken,
|
|
859
|
+
});
|
|
860
|
+
})();
|
|
861
|
+
}
|
|
848
862
|
return user;
|
|
849
863
|
}
|
|
850
864
|
});
|
|
865
|
+
Object.defineProperty(this, "setAwaitingEmailAuth", {
|
|
866
|
+
enumerable: true,
|
|
867
|
+
configurable: true,
|
|
868
|
+
writable: true,
|
|
869
|
+
value: ({ orgId, otpId, isNewUser, }) => {
|
|
870
|
+
this.sessionManager.setTemporarySession({
|
|
871
|
+
orgId,
|
|
872
|
+
isNewUser,
|
|
873
|
+
});
|
|
874
|
+
this.store.setState({
|
|
875
|
+
status: AlchemySignerStatus.AWAITING_EMAIL_AUTH,
|
|
876
|
+
otpId,
|
|
877
|
+
error: null,
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
});
|
|
851
881
|
Object.defineProperty(this, "handleOauthReturn", {
|
|
852
882
|
enumerable: true,
|
|
853
883
|
configurable: true,
|
|
@@ -1111,6 +1141,38 @@ export class BaseAlchemySigner {
|
|
|
1111
1141
|
return this.inner.request("/v1/signer-config", {});
|
|
1112
1142
|
}
|
|
1113
1143
|
});
|
|
1144
|
+
Object.defineProperty(this, "setAuthLinkingPrompt", {
|
|
1145
|
+
enumerable: true,
|
|
1146
|
+
configurable: true,
|
|
1147
|
+
writable: true,
|
|
1148
|
+
value: (prompt) => {
|
|
1149
|
+
this.setAwaitingEmailAuth({
|
|
1150
|
+
orgId: prompt.orgId,
|
|
1151
|
+
otpId: prompt.otpId,
|
|
1152
|
+
isNewUser: false,
|
|
1153
|
+
});
|
|
1154
|
+
this.store.setState({
|
|
1155
|
+
authLinkingStatus: {
|
|
1156
|
+
email: prompt.email,
|
|
1157
|
+
providerName: prompt.providerName,
|
|
1158
|
+
idToken: prompt.idToken,
|
|
1159
|
+
},
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
Object.defineProperty(this, "waitForConnected", {
|
|
1164
|
+
enumerable: true,
|
|
1165
|
+
configurable: true,
|
|
1166
|
+
writable: true,
|
|
1167
|
+
value: () => {
|
|
1168
|
+
return new Promise((resolve) => {
|
|
1169
|
+
const removeListener = this.sessionManager.on("connected", (session) => {
|
|
1170
|
+
resolve(session.user);
|
|
1171
|
+
removeListener();
|
|
1172
|
+
});
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1114
1176
|
this.inner = client;
|
|
1115
1177
|
this.store = createStore(subscribeWithSelector(() => ({
|
|
1116
1178
|
user: null,
|
|
@@ -1133,6 +1195,9 @@ export class BaseAlchemySigner {
|
|
|
1133
1195
|
// then initialize so that we can catch those events
|
|
1134
1196
|
this.sessionManager.initialize();
|
|
1135
1197
|
this.config = this.fetchConfig();
|
|
1198
|
+
if (initialAuthLinkingPrompt) {
|
|
1199
|
+
this.setAuthLinkingPrompt(initialAuthLinkingPrompt);
|
|
1200
|
+
}
|
|
1136
1201
|
}
|
|
1137
1202
|
handleMfaRequired(encryptedPayload, multiFactors) {
|
|
1138
1203
|
// Store complete MFA context in the temporary session
|
|
@@ -1283,4 +1348,42 @@ function toErrorInfo(error) {
|
|
|
1283
1348
|
? { name: error.name, message: error.message }
|
|
1284
1349
|
: { name: "Error", message: "Unknown error" };
|
|
1285
1350
|
}
|
|
1351
|
+
// eslint-disable-next-line jsdoc/require-param, jsdoc/require-returns
|
|
1352
|
+
/**
|
|
1353
|
+
* Zustand's `fireImmediately` option calls the listener before
|
|
1354
|
+
* `store.subscribe` has returned, which breaks listeners which call
|
|
1355
|
+
* unsubscribe, e.g.
|
|
1356
|
+
*
|
|
1357
|
+
* ```ts
|
|
1358
|
+
* const unsubscribe = store.subscribe(
|
|
1359
|
+
* selector,
|
|
1360
|
+
* (update) => {
|
|
1361
|
+
* handleUpdate(update);
|
|
1362
|
+
* unsubscribe();
|
|
1363
|
+
* },
|
|
1364
|
+
* { fireImmediately: true },
|
|
1365
|
+
* )
|
|
1366
|
+
* ```
|
|
1367
|
+
*
|
|
1368
|
+
* since `unsubscribe` is still undefined at the time the listener is called. To
|
|
1369
|
+
* prevent this, if the listener triggers before `subscribe` has returned, delay
|
|
1370
|
+
* the callback to a later run of the event loop.
|
|
1371
|
+
*/
|
|
1372
|
+
function subscribeWithDelayedFireImmediately(store, selector, listener) {
|
|
1373
|
+
let subscribeHasReturned = false;
|
|
1374
|
+
const unsubscribe = store.subscribe(selector, (...args) => {
|
|
1375
|
+
if (subscribeHasReturned) {
|
|
1376
|
+
listener(...args);
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
setTimeout(() => listener(...args), 0);
|
|
1380
|
+
}
|
|
1381
|
+
}, { fireImmediately: true });
|
|
1382
|
+
subscribeHasReturned = true;
|
|
1383
|
+
return unsubscribe;
|
|
1384
|
+
}
|
|
1385
|
+
function isAuthLinkingPrompt(result) {
|
|
1386
|
+
return (result?.status ===
|
|
1387
|
+
"ACCOUNT_LINKING_CONFIRMATION_REQUIRED");
|
|
1388
|
+
}
|
|
1286
1389
|
//# sourceMappingURL=base.js.map
|