@account-kit/signer 4.0.0-beta.1 → 4.0.0-beta.10

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 (77) hide show
  1. package/dist/esm/base.d.ts +42 -5
  2. package/dist/esm/base.js +186 -29
  3. package/dist/esm/base.js.map +1 -1
  4. package/dist/esm/client/base.d.ts +22 -4
  5. package/dist/esm/client/base.js +36 -2
  6. package/dist/esm/client/base.js.map +1 -1
  7. package/dist/esm/client/index.d.ts +108 -7
  8. package/dist/esm/client/index.js +282 -14
  9. package/dist/esm/client/index.js.map +1 -1
  10. package/dist/esm/client/types.d.ts +31 -1
  11. package/dist/esm/client/types.js.map +1 -1
  12. package/dist/esm/index.d.ts +1 -1
  13. package/dist/esm/index.js +1 -1
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/metrics.d.ts +17 -0
  16. package/dist/esm/metrics.js +7 -0
  17. package/dist/esm/metrics.js.map +1 -0
  18. package/dist/esm/oauth.d.ts +19 -0
  19. package/dist/esm/oauth.js +26 -0
  20. package/dist/esm/oauth.js.map +1 -0
  21. package/dist/esm/session/manager.d.ts +3 -2
  22. package/dist/esm/session/manager.js +29 -15
  23. package/dist/esm/session/manager.js.map +1 -1
  24. package/dist/esm/session/types.d.ts +1 -1
  25. package/dist/esm/session/types.js.map +1 -1
  26. package/dist/esm/signer.d.ts +52 -7
  27. package/dist/esm/signer.js +46 -3
  28. package/dist/esm/signer.js.map +1 -1
  29. package/dist/esm/types.d.ts +8 -1
  30. package/dist/esm/types.js +3 -1
  31. package/dist/esm/types.js.map +1 -1
  32. package/dist/esm/utils/typeAssertions.d.ts +1 -0
  33. package/dist/esm/utils/typeAssertions.js +4 -0
  34. package/dist/esm/utils/typeAssertions.js.map +1 -0
  35. package/dist/esm/version.d.ts +1 -1
  36. package/dist/esm/version.js +1 -1
  37. package/dist/esm/version.js.map +1 -1
  38. package/dist/types/base.d.ts +42 -5
  39. package/dist/types/base.d.ts.map +1 -1
  40. package/dist/types/client/base.d.ts +22 -4
  41. package/dist/types/client/base.d.ts.map +1 -1
  42. package/dist/types/client/index.d.ts +108 -7
  43. package/dist/types/client/index.d.ts.map +1 -1
  44. package/dist/types/client/types.d.ts +31 -1
  45. package/dist/types/client/types.d.ts.map +1 -1
  46. package/dist/types/index.d.ts +1 -1
  47. package/dist/types/index.d.ts.map +1 -1
  48. package/dist/types/metrics.d.ts +18 -0
  49. package/dist/types/metrics.d.ts.map +1 -0
  50. package/dist/types/oauth.d.ts +20 -0
  51. package/dist/types/oauth.d.ts.map +1 -0
  52. package/dist/types/session/manager.d.ts +3 -2
  53. package/dist/types/session/manager.d.ts.map +1 -1
  54. package/dist/types/session/types.d.ts +1 -1
  55. package/dist/types/session/types.d.ts.map +1 -1
  56. package/dist/types/signer.d.ts +52 -7
  57. package/dist/types/signer.d.ts.map +1 -1
  58. package/dist/types/types.d.ts +8 -1
  59. package/dist/types/types.d.ts.map +1 -1
  60. package/dist/types/utils/typeAssertions.d.ts +2 -0
  61. package/dist/types/utils/typeAssertions.d.ts.map +1 -0
  62. package/dist/types/version.d.ts +1 -1
  63. package/dist/types/version.d.ts.map +1 -1
  64. package/package.json +6 -5
  65. package/src/base.ts +260 -65
  66. package/src/client/base.ts +49 -4
  67. package/src/client/index.ts +317 -20
  68. package/src/client/types.ts +33 -1
  69. package/src/index.ts +5 -1
  70. package/src/metrics.ts +23 -0
  71. package/src/oauth.ts +36 -0
  72. package/src/session/manager.ts +46 -19
  73. package/src/session/types.ts +1 -1
  74. package/src/signer.ts +91 -4
  75. package/src/types.ts +9 -1
  76. package/src/utils/typeAssertions.ts +3 -0
  77. package/src/version.ts +1 -1
@@ -8,6 +8,7 @@ import {
8
8
  import { createStore, type Mutate, type StoreApi } from "zustand/vanilla";
9
9
  import type { BaseSignerClient } from "../client/base";
10
10
  import type { User } from "../client/types";
11
+ import { assertNever } from "../utils/typeAssertions.js";
11
12
  import type { Session, SessionManagerEvents } from "./types";
12
13
 
13
14
  export const DEFAULT_SESSION_MS = 15 * 60 * 1000; // 15 minutes
@@ -82,11 +83,18 @@ export class SessionManager {
82
83
  }
83
84
 
84
85
  switch (existingSession.type) {
85
- case "email": {
86
+ case "email":
87
+ case "oauth": {
88
+ const connectedEventName =
89
+ existingSession.type === "email"
90
+ ? "connectedEmail"
91
+ : "connectedOauth";
86
92
  const result = await this.client
87
- .completeEmailAuth({
93
+ .completeAuthWithBundle({
88
94
  bundle: existingSession.bundle,
89
95
  orgId: existingSession.user.orgId,
96
+ authenticatingType: existingSession.type,
97
+ connectedEventName,
90
98
  })
91
99
  .catch((e) => {
92
100
  console.warn("Failed to load user from session", e);
@@ -108,7 +116,10 @@ export class SessionManager {
108
116
  return this.client.lookupUserWithPasskey(existingSession.user);
109
117
  }
110
118
  default:
111
- throw new Error("Unknown session type");
119
+ assertNever(
120
+ existingSession,
121
+ `Unknown session type: ${(existingSession as any).type}`
122
+ );
112
123
  }
113
124
  };
114
125
 
@@ -168,7 +179,7 @@ export class SessionManager {
168
179
 
169
180
  private setSession = (
170
181
  session:
171
- | Omit<Extract<Session, { type: "email" }>, "expirationDateMs">
182
+ | Omit<Extract<Session, { type: "email" | "oauth" }>, "expirationDateMs">
172
183
  | Omit<Extract<Session, { type: "passkey" }>, "expirationDateMs">
173
184
  ) => {
174
185
  this.store.setState({
@@ -211,21 +222,9 @@ export class SessionManager {
211
222
 
212
223
  this.client.on("disconnected", () => this.clearSession());
213
224
 
214
- this.client.on("connectedEmail", (user, bundle) => {
215
- const existingSession = this.getSession();
216
- if (
217
- existingSession != null &&
218
- existingSession.type === "email" &&
219
- existingSession.user.userId === user.userId &&
220
- // if the bundle is different, then we've refreshed the session
221
- // so we need to reset the session
222
- existingSession.bundle === bundle
223
- ) {
224
- return;
225
- }
226
-
227
- this.setSession({ type: "email", user, bundle });
228
- });
225
+ this.client.on("connectedEmail", (user, bundle) =>
226
+ this.setSessionWithUserAndBundle({ type: "email", user, bundle })
227
+ );
229
228
 
230
229
  this.client.on("connectedPasskey", (user) => {
231
230
  const existingSession = this.getSession();
@@ -240,10 +239,38 @@ export class SessionManager {
240
239
  this.setSession({ type: "passkey", user });
241
240
  });
242
241
 
242
+ this.client.on("connectedOauth", (user, bundle) =>
243
+ this.setSessionWithUserAndBundle({ type: "oauth", user, bundle })
244
+ );
245
+
243
246
  // sync local state if persisted state has changed from another tab
244
247
  window.addEventListener("focus", () => {
245
248
  this.store.persist.rehydrate();
246
249
  this.initialize();
247
250
  });
248
251
  };
252
+
253
+ private setSessionWithUserAndBundle = ({
254
+ type,
255
+ user,
256
+ bundle,
257
+ }: {
258
+ type: "email" | "oauth";
259
+ user: User;
260
+ bundle: string;
261
+ }) => {
262
+ const existingSession = this.getSession();
263
+ if (
264
+ existingSession != null &&
265
+ existingSession.type === type &&
266
+ existingSession.user.userId === user.userId &&
267
+ // if the bundle is different, then we've refreshed the session
268
+ // so we need to reset the session
269
+ existingSession.bundle === bundle
270
+ ) {
271
+ return;
272
+ }
273
+
274
+ this.setSession({ type, user, bundle });
275
+ };
249
276
  }
@@ -2,7 +2,7 @@ import type { User } from "../client/types";
2
2
 
3
3
  export type Session =
4
4
  | {
5
- type: "email";
5
+ type: "email" | "oauth";
6
6
  bundle: string;
7
7
  expirationDateMs: number;
8
8
  user: User;
package/src/signer.ts CHANGED
@@ -24,8 +24,45 @@ export type AuthParams =
24
24
  createNew: true;
25
25
  username: string;
26
26
  creationOpts?: CredentialCreationOptionOverrides;
27
+ }
28
+ | ({
29
+ type: "oauth";
30
+ scope?: string;
31
+ claims?: string;
32
+ } & OauthProviderConfig &
33
+ OauthRedirectConfig)
34
+ | {
35
+ type: "oauthReturn";
36
+ bundle: string;
37
+ orgId: string;
38
+ idToken: string;
27
39
  };
28
40
 
41
+ export type OauthProviderConfig =
42
+ | {
43
+ authProviderId: "auth0";
44
+ isCustomProvider?: false;
45
+ auth0Connection?: string;
46
+ }
47
+ | {
48
+ authProviderId: KnownAuthProvider;
49
+ isCustomProvider?: false;
50
+ auth0Connection?: never;
51
+ }
52
+ | {
53
+ authProviderId: string;
54
+ isCustomProvider: true;
55
+ auth0Connection?: never;
56
+ };
57
+
58
+ export type OauthRedirectConfig =
59
+ | { mode: "redirect"; redirectUrl: string }
60
+ | { mode: "popup"; redirectUrl?: never };
61
+
62
+ export type KnownAuthProvider = "google" | "apple" | "facebook" | "auth0";
63
+
64
+ export type OauthMode = "redirect" | "popup";
65
+
29
66
  export const AlchemySignerParamsSchema = z
30
67
  .object({
31
68
  client: z
@@ -73,9 +110,59 @@ export class AlchemyWebSigner extends BaseAlchemySigner<AlchemySignerWebClient>
73
110
  } else {
74
111
  client = params_.client;
75
112
  }
76
- super({
77
- client,
78
- sessionConfig,
79
- });
113
+ const { emailBundle, oauthBundle, oauthOrgId, oauthError, idToken } =
114
+ getAndRemoveQueryParams({
115
+ emailBundle: "bundle",
116
+ // We don't need this, but we still want to remove it from the URL.
117
+ emailOrgId: "orgId",
118
+ oauthBundle: "alchemy-bundle",
119
+ oauthOrgId: "alchemy-org-id",
120
+ oauthError: "alchemy-error",
121
+ idToken: "alchemy-id-token",
122
+ });
123
+
124
+ const initialError =
125
+ oauthError != null
126
+ ? { name: "OauthError", message: oauthError }
127
+ : undefined;
128
+
129
+ super({ client, sessionConfig, initialError });
130
+
131
+ if (emailBundle) {
132
+ this.authenticate({ type: "email", bundle: emailBundle });
133
+ } else if (oauthBundle && oauthOrgId && idToken) {
134
+ this.authenticate({
135
+ type: "oauthReturn",
136
+ bundle: oauthBundle,
137
+ orgId: oauthOrgId,
138
+ idToken,
139
+ });
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Reads and removes the specified query params from the URL.
146
+ *
147
+ * @param {T} keys object whose values are the query parameter keys to read and
148
+ * remove
149
+ * @returns {{ [K in keyof T]: string | undefined }} object with the same keys
150
+ * as the input whose values are the values of the query params.
151
+ */
152
+ function getAndRemoveQueryParams<T extends Record<string, string>>(
153
+ keys: T
154
+ ): { [K in keyof T]: string | undefined } {
155
+ const url = new URL(window.location.href);
156
+ const result: Record<string, string | undefined> = {};
157
+ let foundQueryParam = false;
158
+ for (const [key, param] of Object.entries(keys)) {
159
+ const value = url.searchParams.get(param) ?? undefined;
160
+ foundQueryParam ||= value != null;
161
+ result[key] = value;
162
+ url.searchParams.delete(param);
163
+ }
164
+ if (foundQueryParam) {
165
+ window.history.replaceState(window.history.state, "", url.toString());
80
166
  }
167
+ return result as { [K in keyof T]: string | undefined };
81
168
  }
package/src/types.ts CHANGED
@@ -4,6 +4,7 @@ export type AlchemySignerEvents = {
4
4
  connected(user: User): void;
5
5
  disconnected(): void;
6
6
  statusChanged(status: AlchemySignerStatus): void;
7
+ errorChanged(error: ErrorInfo | undefined): void;
7
8
  };
8
9
 
9
10
  export type AlchemySignerEvent = keyof AlchemySignerEvents;
@@ -12,6 +13,13 @@ export enum AlchemySignerStatus {
12
13
  INITIALIZING = "INITIALIZING",
13
14
  CONNECTED = "CONNECTED",
14
15
  DISCONNECTED = "DISCONNECTED",
15
- AUTHENTICATING = "AUTHENTICATING",
16
+ AUTHENTICATING_PASSKEY = "AUTHENTICATING_PASSKEY",
17
+ AUTHENTICATING_EMAIL = "AUTHENTICATING_EMAIL",
18
+ AUTHENTICATING_OAUTH = "AUTHENTICATING_OAUTH",
16
19
  AWAITING_EMAIL_AUTH = "AWAITING_EMAIL_AUTH",
17
20
  }
21
+
22
+ export interface ErrorInfo {
23
+ name: string;
24
+ message: string;
25
+ }
@@ -0,0 +1,3 @@
1
+ export function assertNever(_: never, message: string): never {
2
+ throw new Error(message);
3
+ }
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.0.0-beta.1";
3
+ export const VERSION = "4.0.0-beta.10";