@account-kit/signer 4.15.3 → 4.16.1-alpha.3

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.
Files changed (70) hide show
  1. package/dist/esm/base.d.ts +59 -1
  2. package/dist/esm/base.js +159 -55
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +38 -3
  5. package/dist/esm/client/base.js +10 -3
  6. package/dist/esm/client/base.js.map +1 -1
  7. package/dist/esm/client/index.d.ts +40 -1
  8. package/dist/esm/client/index.js +164 -7
  9. package/dist/esm/client/index.js.map +1 -1
  10. package/dist/esm/client/types.d.ts +69 -1
  11. package/dist/esm/client/types.js.map +1 -1
  12. package/dist/esm/errors.d.ts +6 -0
  13. package/dist/esm/errors.js +18 -0
  14. package/dist/esm/errors.js.map +1 -1
  15. package/dist/esm/index.d.ts +2 -1
  16. package/dist/esm/index.js +1 -1
  17. package/dist/esm/index.js.map +1 -1
  18. package/dist/esm/session/manager.d.ts +1 -0
  19. package/dist/esm/session/manager.js.map +1 -1
  20. package/dist/esm/signer.d.ts +3 -1
  21. package/dist/esm/signer.js.map +1 -1
  22. package/dist/esm/solanaSigner.d.ts +12 -0
  23. package/dist/esm/solanaSigner.js +67 -0
  24. package/dist/esm/solanaSigner.js.map +1 -0
  25. package/dist/esm/types.d.ts +8 -0
  26. package/dist/esm/types.js +5 -0
  27. package/dist/esm/types.js.map +1 -1
  28. package/dist/esm/utils/parseMfaError.d.ts +2 -0
  29. package/dist/esm/utils/parseMfaError.js +15 -0
  30. package/dist/esm/utils/parseMfaError.js.map +1 -0
  31. package/dist/esm/version.d.ts +1 -1
  32. package/dist/esm/version.js +1 -1
  33. package/dist/esm/version.js.map +1 -1
  34. package/dist/types/base.d.ts +59 -1
  35. package/dist/types/base.d.ts.map +1 -1
  36. package/dist/types/client/base.d.ts +38 -3
  37. package/dist/types/client/base.d.ts.map +1 -1
  38. package/dist/types/client/index.d.ts +40 -1
  39. package/dist/types/client/index.d.ts.map +1 -1
  40. package/dist/types/client/types.d.ts +69 -1
  41. package/dist/types/client/types.d.ts.map +1 -1
  42. package/dist/types/errors.d.ts +6 -0
  43. package/dist/types/errors.d.ts.map +1 -1
  44. package/dist/types/index.d.ts +2 -1
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/types/session/manager.d.ts +1 -0
  47. package/dist/types/session/manager.d.ts.map +1 -1
  48. package/dist/types/signer.d.ts +3 -1
  49. package/dist/types/signer.d.ts.map +1 -1
  50. package/dist/types/solanaSigner.d.ts +13 -0
  51. package/dist/types/solanaSigner.d.ts.map +1 -0
  52. package/dist/types/types.d.ts +8 -0
  53. package/dist/types/types.d.ts.map +1 -1
  54. package/dist/types/utils/parseMfaError.d.ts +3 -0
  55. package/dist/types/utils/parseMfaError.d.ts.map +1 -0
  56. package/dist/types/version.d.ts +1 -1
  57. package/dist/types/version.d.ts.map +1 -1
  58. package/package.json +5 -4
  59. package/src/base.ts +206 -62
  60. package/src/client/base.ts +59 -4
  61. package/src/client/index.ts +174 -7
  62. package/src/client/types.ts +79 -1
  63. package/src/errors.ts +11 -1
  64. package/src/index.ts +6 -1
  65. package/src/session/manager.ts +5 -1
  66. package/src/signer.ts +6 -1
  67. package/src/solanaSigner.ts +83 -0
  68. package/src/types.ts +9 -0
  69. package/src/utils/parseMfaError.ts +15 -0
  70. package/src/version.ts +1 -1
@@ -17,9 +17,23 @@ import type {
17
17
  OauthConfig,
18
18
  OtpParams,
19
19
  User,
20
+ MfaFactor,
21
+ EnableMfaParams,
22
+ EnableMfaResult,
23
+ VerifyMfaParams,
24
+ RemoveMfaParams,
20
25
  } from "./types.js";
26
+ import { MfaRequiredError, NotAuthenticatedError } from "../errors.js";
27
+ import { parseMfaError } from "../utils/parseMfaError.js";
21
28
 
22
29
  const CHECK_CLOSE_INTERVAL = 500;
30
+ const MFA_PAYLOAD = {
31
+ GET: "get_mfa",
32
+ ADD: "add_mfa",
33
+ DELETE: "delete_mfas",
34
+ VERIFY: "verify_mfa",
35
+ LIST: "list_mfas",
36
+ };
23
37
 
24
38
  export const AlchemySignerClientParamsSchema = z.object({
25
39
  connection: ConnectionConfigSchema,
@@ -198,13 +212,25 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
198
212
  const { email, emailMode, expirationSeconds } = params;
199
213
  const publicKey = await this.initIframeStamper();
200
214
 
201
- return this.request("/v1/auth", {
202
- email,
203
- emailMode,
204
- targetPublicKey: publicKey,
205
- expirationSeconds,
206
- redirectParams: params.redirectParams?.toString(),
207
- });
215
+ try {
216
+ return await this.request("/v1/auth", {
217
+ email,
218
+ emailMode,
219
+ targetPublicKey: publicKey,
220
+ expirationSeconds,
221
+ redirectParams: params.redirectParams?.toString(),
222
+ multiFactors: params.multiFactors,
223
+ });
224
+ } catch (error) {
225
+ const multiFactors = parseMfaError(error);
226
+
227
+ // If MFA is required, and emailMode is Magic Link, the user must submit mfa with the request or
228
+ // the the server will return an error with the required mfa factors.
229
+ if (multiFactors) {
230
+ throw new MfaRequiredError(multiFactors);
231
+ }
232
+ throw error;
233
+ }
208
234
  };
209
235
 
210
236
  /**
@@ -242,6 +268,12 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
242
268
  ...args,
243
269
  targetPublicKey,
244
270
  });
271
+
272
+ if (!credentialBundle) {
273
+ throw new Error(
274
+ "Failed to submit OTP code. Check if multiFactor is required."
275
+ );
276
+ }
245
277
  return { bundle: credentialBundle };
246
278
  }
247
279
 
@@ -670,6 +702,141 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
670
702
  const nonce = this.getOauthNonce(publicKey);
671
703
  return this.request("/v1/prepare-oauth", { nonce });
672
704
  };
705
+
706
+ /**
707
+ * Retrieves the list of MFA factors configured for the current user.
708
+ *
709
+ * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to an array of configured MFA factors
710
+ * @throws {NotAuthenticatedError} If no user is authenticated
711
+ */
712
+ public override getMfaFactors = async (): Promise<{
713
+ multiFactors: MfaFactor[];
714
+ }> => {
715
+ if (!this.user) {
716
+ throw new NotAuthenticatedError();
717
+ }
718
+
719
+ const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
720
+ organizationId: this.user.orgId,
721
+ type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
722
+ timestampMs: Date.now().toString(),
723
+ parameters: {
724
+ encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
725
+ hashFunction: "HASH_FUNCTION_NO_OP",
726
+ payload: MFA_PAYLOAD.LIST,
727
+ signWith: this.user.address,
728
+ },
729
+ });
730
+
731
+ return this.request("/v1/auth-list-multi-factors", {
732
+ stampedRequest,
733
+ });
734
+ };
735
+
736
+ /**
737
+ * Initiates the setup of a new MFA factor for the current user. Mfa will need to be verified before it is active.
738
+ *
739
+ * @param {EnableMfaParams} params The parameters required to enable a new MFA factor
740
+ * @returns {Promise<EnableMfaResult>} A promise that resolves to the factor setup information
741
+ * @throws {NotAuthenticatedError} If no user is authenticated
742
+ * @throws {Error} If an unsupported factor type is provided
743
+ */
744
+ public override addMfa = async (
745
+ params: EnableMfaParams
746
+ ): Promise<EnableMfaResult> => {
747
+ if (!this.user) {
748
+ throw new NotAuthenticatedError();
749
+ }
750
+
751
+ const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
752
+ organizationId: this.user.orgId,
753
+ type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
754
+ timestampMs: Date.now().toString(),
755
+ parameters: {
756
+ encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
757
+ hashFunction: "HASH_FUNCTION_NO_OP",
758
+ payload: MFA_PAYLOAD.ADD,
759
+ signWith: this.user.address,
760
+ },
761
+ });
762
+
763
+ switch (params.multiFactorType) {
764
+ case "totp":
765
+ return this.request("/v1/auth-request-multi-factor", {
766
+ stampedRequest,
767
+ multiFactorType: params.multiFactorType,
768
+ });
769
+ default:
770
+ throw new Error(
771
+ `Unsupported MFA factor type: ${params.multiFactorType}`
772
+ );
773
+ }
774
+ };
775
+
776
+ /**
777
+ * Verifies a newly created MFA factor to complete the setup process.
778
+ *
779
+ * @param {VerifyMfaParams} params The parameters required to verify the MFA factor
780
+ * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
781
+ * @throws {NotAuthenticatedError} If no user is authenticated
782
+ */
783
+ public override verifyMfa = async (
784
+ params: VerifyMfaParams
785
+ ): Promise<{ multiFactors: MfaFactor[] }> => {
786
+ if (!this.user) {
787
+ throw new NotAuthenticatedError();
788
+ }
789
+
790
+ const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
791
+ organizationId: this.user.orgId,
792
+ type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
793
+ timestampMs: Date.now().toString(),
794
+ parameters: {
795
+ encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
796
+ hashFunction: "HASH_FUNCTION_NO_OP",
797
+ payload: MFA_PAYLOAD.VERIFY,
798
+ signWith: this.user.address,
799
+ },
800
+ });
801
+
802
+ return this.request("/v1/auth-verify-multi-factor", {
803
+ stampedRequest,
804
+ multiFactorId: params.multiFactorId,
805
+ multiFactorCode: params.multiFactorCode,
806
+ });
807
+ };
808
+
809
+ /**
810
+ * Removes existing MFA factors by ID.
811
+ *
812
+ * @param {RemoveMfaParams} params The parameters specifying which factors to disable
813
+ * @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
814
+ * @throws {NotAuthenticatedError} If no user is authenticated
815
+ */
816
+ public override removeMfa = async (
817
+ params: RemoveMfaParams
818
+ ): Promise<{ multiFactors: MfaFactor[] }> => {
819
+ if (!this.user) {
820
+ throw new NotAuthenticatedError();
821
+ }
822
+
823
+ const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
824
+ organizationId: this.user.orgId,
825
+ type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
826
+ timestampMs: Date.now().toString(),
827
+ parameters: {
828
+ encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
829
+ hashFunction: "HASH_FUNCTION_NO_OP",
830
+ payload: MFA_PAYLOAD.DELETE,
831
+ signWith: this.user.address,
832
+ },
833
+ });
834
+
835
+ return this.request("/v1/auth-delete-multi-factors", {
836
+ stampedRequest,
837
+ multiFactorIds: params.multiFactorIds,
838
+ });
839
+ };
673
840
  }
674
841
 
675
842
  /**
@@ -13,6 +13,7 @@ export type User = {
13
13
  orgId: string;
14
14
  userId: string;
15
15
  address: Address;
16
+ solanaAddress?: string;
16
17
  credentialId?: string;
17
18
  idToken?: string;
18
19
  claims?: Record<string, unknown>;
@@ -51,6 +52,7 @@ export type EmailAuthParams = {
51
52
  expirationSeconds?: number;
52
53
  targetPublicKey: string;
53
54
  redirectParams?: URLSearchParams;
55
+ multiFactors?: VerifyMfaParams[];
54
56
  };
55
57
 
56
58
  export type OauthParams = Extract<AuthParams, { type: "oauth" }> & {
@@ -63,6 +65,7 @@ export type OtpParams = {
63
65
  otpCode: string;
64
66
  targetPublicKey: string;
65
67
  expirationSeconds?: number;
68
+ multiFactors?: VerifyMfaParams[];
66
69
  };
67
70
 
68
71
  export type SignupResponse = {
@@ -121,10 +124,12 @@ export type SignerEndpoints = [
121
124
  Route: "/v1/auth";
122
125
  Body: Omit<EmailAuthParams, "redirectParams"> & {
123
126
  redirectParams?: string;
127
+ multiFactors?: VerifyMfaParams[];
124
128
  };
125
129
  Response: {
126
130
  orgId: string;
127
131
  otpId?: string;
132
+ multiFactors?: MfaFactor[];
128
133
  };
129
134
  },
130
135
  {
@@ -155,7 +160,45 @@ export type SignerEndpoints = [
155
160
  {
156
161
  Route: "/v1/otp";
157
162
  Body: OtpParams;
158
- Response: { credentialBundle: string };
163
+ Response: {
164
+ credentialBundle: string | null;
165
+ };
166
+ },
167
+ {
168
+ Route: "/v1/auth-list-multi-factors";
169
+ Body: {
170
+ stampedRequest: TSignedRequest;
171
+ };
172
+ Response: {
173
+ multiFactors: MfaFactor[];
174
+ };
175
+ },
176
+ {
177
+ Route: "/v1/auth-delete-multi-factors";
178
+ Body: {
179
+ stampedRequest: TSignedRequest;
180
+ multiFactorIds: string[];
181
+ };
182
+ Response: {
183
+ multiFactors: MfaFactor[];
184
+ };
185
+ },
186
+ {
187
+ Route: "/v1/auth-request-multi-factor";
188
+ Body: {
189
+ stampedRequest: TSignedRequest;
190
+ multiFactorType: MultiFactorType;
191
+ };
192
+ Response: EnableMfaResult;
193
+ },
194
+ {
195
+ Route: "/v1/auth-verify-multi-factor";
196
+ Body: VerifyMfaParams & {
197
+ stampedRequest: TSignedRequest;
198
+ };
199
+ Response: {
200
+ multiFactors: MfaFactor[];
201
+ };
159
202
  }
160
203
  ];
161
204
 
@@ -199,3 +242,38 @@ export type GetOauthProviderUrlArgs = {
199
242
  oauthConfig?: OauthConfig;
200
243
  usesRelativeUrl?: boolean;
201
244
  };
245
+
246
+ export type MfaFactor = {
247
+ multiFactorId: string;
248
+ multiFactorType: string;
249
+ };
250
+
251
+ type MultiFactorType = "totp";
252
+
253
+ export type EnableMfaParams = {
254
+ multiFactorType: MultiFactorType;
255
+ };
256
+
257
+ export type EnableMfaResult = {
258
+ multiFactorType: MultiFactorType;
259
+ multiFactorId: string;
260
+ multiFactorTotpUrl: string;
261
+ };
262
+
263
+ export type VerifyMfaParams = {
264
+ multiFactorId: string;
265
+ multiFactorCode: string;
266
+ };
267
+
268
+ export type RemoveMfaParams = {
269
+ multiFactorIds: string[];
270
+ };
271
+
272
+ export type MfaChallenge = {
273
+ multiFactorId: string;
274
+ multiFactorChallenge:
275
+ | {
276
+ code: string;
277
+ }
278
+ | Record<string, any>;
279
+ };
package/src/errors.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { BaseError } from "@aa-sdk/core";
2
-
2
+ import type { MfaFactor } from "./client/types";
3
3
  export class NotAuthenticatedError extends BaseError {
4
4
  override name = "NotAuthenticatedError";
5
5
  constructor() {
@@ -23,3 +23,13 @@ export class OAuthProvidersError extends BaseError {
23
23
  });
24
24
  }
25
25
  }
26
+
27
+ export class MfaRequiredError extends BaseError {
28
+ override name = "MfaRequiredError";
29
+ public multiFactors: MfaFactor[];
30
+
31
+ constructor(multiFactors: MfaFactor[]) {
32
+ super("MFA is required for this user");
33
+ this.multiFactors = multiFactors;
34
+ }
35
+ }
package/src/index.ts CHANGED
@@ -6,12 +6,17 @@ export {
6
6
  OauthFailedError,
7
7
  } from "./client/index.js";
8
8
  export type * from "./client/types.js";
9
+ export {
10
+ NotAuthenticatedError,
11
+ OAuthProvidersError,
12
+ MfaRequiredError,
13
+ } from "./errors.js";
9
14
  export {
10
15
  DEFAULT_SESSION_MS,
11
16
  SessionManagerParamsSchema,
12
17
  } from "./session/manager.js";
13
18
  export type * from "./signer.js";
14
19
  export { AlchemyWebSigner } from "./signer.js";
20
+ export type * from "./solanaSigner.js";
15
21
  export type * from "./types.js";
16
22
  export { AlchemySignerStatus } from "./types.js";
17
- export { OAuthProvidersError, NotAuthenticatedError } from "./errors.js";
@@ -43,7 +43,11 @@ type Store = Mutate<
43
43
  [["zustand/subscribeWithSelector", never], ["zustand/persist", SessionState]]
44
44
  >;
45
45
 
46
- type TemporarySession = { orgId: string; isNewUser?: boolean };
46
+ type TemporarySession = {
47
+ orgId: string;
48
+ isNewUser?: boolean;
49
+ isMfaRequired?: boolean;
50
+ };
47
51
 
48
52
  export class SessionManager {
49
53
  private sessionKey: string;
package/src/signer.ts CHANGED
@@ -4,7 +4,10 @@ import {
4
4
  AlchemySignerClientParamsSchema,
5
5
  AlchemySignerWebClient,
6
6
  } from "./client/index.js";
7
- import type { CredentialCreationOptionOverrides } from "./client/types.js";
7
+ import type {
8
+ CredentialCreationOptionOverrides,
9
+ VerifyMfaParams,
10
+ } from "./client/types.js";
8
11
  import { SessionManagerParamsSchema } from "./session/manager.js";
9
12
 
10
13
  export type AuthParams =
@@ -13,6 +16,7 @@ export type AuthParams =
13
16
  email: string;
14
17
  emailMode?: "magicLink" | "otp";
15
18
  redirectParams?: URLSearchParams;
19
+ multiFactors?: VerifyMfaParams[];
16
20
  }
17
21
  | { type: "email"; bundle: string; orgId?: string; isNewUser?: boolean }
18
22
  | {
@@ -46,6 +50,7 @@ export type AuthParams =
46
50
  | {
47
51
  type: "otp";
48
52
  otpCode: string;
53
+ multiFactors?: VerifyMfaParams[];
49
54
  };
50
55
 
51
56
  export type OauthProviderConfig =
@@ -0,0 +1,83 @@
1
+ import {
2
+ PublicKey,
3
+ Transaction,
4
+ type VersionedTransaction,
5
+ } from "@solana/web3.js";
6
+ import { size, slice, toBytes, toHex, type ByteArray, type Hex } from "viem";
7
+ import type { BaseSignerClient } from "./client/base";
8
+ import { NotAuthenticatedError } from "./errors.js";
9
+
10
+ // TODO: I don't want this to be a class so that the flow is closer to how we do this for `toViemAccount`
11
+ export class SolanaSigner {
12
+ private alchemyClient: BaseSignerClient;
13
+ public address: string;
14
+
15
+ constructor(client: BaseSignerClient) {
16
+ this.alchemyClient = client;
17
+ if (!client.getUser()) throw new Error("Must be authenticated!");
18
+
19
+ // TODO: also throw here
20
+ this.address = client.getUser()!.solanaAddress!;
21
+ }
22
+
23
+ async addSignature(
24
+ tx: Transaction | VersionedTransaction
25
+ ): Promise<Transaction | VersionedTransaction> {
26
+ const user = this.alchemyClient.getUser();
27
+ if (!user) {
28
+ throw new NotAuthenticatedError();
29
+ }
30
+
31
+ if (!user.solanaAddress) {
32
+ throw new Error("no solana address");
33
+ }
34
+
35
+ const fromKey = new PublicKey(user.solanaAddress);
36
+ const messageToSign = this.getMessageToSign(tx);
37
+ const signature = await this.alchemyClient.signRawMessage(
38
+ messageToSign,
39
+ "SOLANA"
40
+ );
41
+
42
+ tx.addSignature(
43
+ fromKey,
44
+ Buffer.from(toBytes(this.formatSignatureForSolana(signature)))
45
+ );
46
+ return tx;
47
+ }
48
+
49
+ async signMessage(message: Uint8Array): Promise<ByteArray> {
50
+ const user = this.alchemyClient.getUser();
51
+ if (!user) {
52
+ throw new NotAuthenticatedError();
53
+ }
54
+
55
+ if (!user.solanaAddress) {
56
+ throw new Error("no solana address");
57
+ }
58
+
59
+ const messageToSign = toHex(message);
60
+ const signature = await this.alchemyClient.signRawMessage(
61
+ messageToSign,
62
+ "SOLANA"
63
+ );
64
+
65
+ return toBytes(this.formatSignatureForSolana(signature));
66
+ }
67
+
68
+ private formatSignatureForSolana(signature: Hex): Hex {
69
+ if (size(signature) === 64) return signature;
70
+
71
+ return slice(signature, 0, 64);
72
+ }
73
+
74
+ private getMessageToSign(tx: Transaction | VersionedTransaction): Hex {
75
+ let messageToSign;
76
+ if (tx instanceof Transaction) {
77
+ messageToSign = tx.serializeMessage();
78
+ } else {
79
+ messageToSign = Buffer.from(tx.message.serialize());
80
+ }
81
+ return toHex(messageToSign);
82
+ }
83
+ }
package/src/types.ts CHANGED
@@ -6,6 +6,10 @@ export type AlchemySignerEvents = {
6
6
  disconnected(): void;
7
7
  statusChanged(status: AlchemySignerStatus): void;
8
8
  errorChanged(error: ErrorInfo | undefined): void;
9
+ mfaStatusChanged(mfaStatus: {
10
+ mfaRequired: boolean;
11
+ mfaFactorId?: string;
12
+ }): void;
9
13
  };
10
14
 
11
15
  export type AlchemySignerEvent = keyof AlchemySignerEvents;
@@ -21,6 +25,11 @@ export enum AlchemySignerStatus {
21
25
  AWAITING_OTP_AUTH = "AWAITING_OTP_AUTH",
22
26
  }
23
27
 
28
+ export enum AlchemyMfaStatus {
29
+ NOT_REQUIRED = "not_required",
30
+ REQUIRED = "required",
31
+ }
32
+
24
33
  export interface ErrorInfo {
25
34
  name: string;
26
35
  message: string;
@@ -0,0 +1,15 @@
1
+ import type { MfaFactor } from "../client/types.js";
2
+
3
+ export function parseMfaError(error: unknown): MfaFactor[] | null {
4
+ if (error instanceof Error) {
5
+ try {
6
+ const parsed = JSON.parse(error.message);
7
+ if (parsed?.data?.multiFactors) {
8
+ return parsed.data.multiFactors;
9
+ }
10
+ } catch {
11
+ // ignore JSON parse failures
12
+ }
13
+ }
14
+ return null;
15
+ }
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file is autogenerated by inject-version.ts. Any changes will be
2
2
  // overwritten on commit!
3
- export const VERSION = "4.15.3";
3
+ export const VERSION = "4.16.1-alpha.3";