@softr/sdk 0.0.24 → 0.0.25

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.
@@ -1,10 +1,9 @@
1
- import { panic, todo } from "../../assertions.js";
1
+ import { assert, panic } from "../../assertions.js";
2
2
  import { writeCookies } from "../../cookies.js";
3
3
  import { sessionConfig } from "../config.js";
4
4
  import { makePlatform } from "../platform.js";
5
- import { makeSessionDataCookie, makeSessionTokenCookie } from "../session.js";
5
+ import { clearPendingAuth, makePendingAuthCookie, makeSessionDataCookie, makeSessionTokenCookie } from "../session.js";
6
6
  import { authError } from "./utils.js";
7
- import { signIn } from "./password.js";
8
7
 
9
8
  //#region src/auth/methods/signup.ts
10
9
  /**
@@ -13,11 +12,13 @@ import { signIn } from "./password.js";
13
12
  * User only exists once `confirmSignUp` returns the code.
14
13
  */
15
14
  async function signUp(details) {
16
- const result = await makePlatform(sessionConfig().applicationId).signUp(signUpBody(details));
15
+ const result = await makePlatform(sessionConfig().applicationId).sendSignUpCode(details);
17
16
  if (!result.ok) {
18
- if (result.status >= 500) panic(result.message);
19
17
  if (result.status === 409) return authError("emailTaken", result.message);
20
- return authError("invalidDetails", result.message);
18
+ if (result.status === 429) return authError("tooManyAttempts", result.message);
19
+ if (result.status === 400) return authError("invalidDetails", result.message);
20
+ if (result.status >= 500) panic(`Expected the sign-up code to be emailed, but got ${result.status}: ` + result.message);
21
+ throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app allows sign-up.`);
21
22
  }
22
23
  return {
23
24
  success: true,
@@ -25,63 +26,56 @@ async function signUp(details) {
25
26
  };
26
27
  }
27
28
  /**
28
- * Finishes sign-up flow with the emailed code and signs the visitor in.
29
+ * Finishes a sign-up with the emailed code, creating the account and signing
30
+ * the visitor in.
29
31
  *
30
- * The platform splits on how the app is configured: a code-only app creates the
31
- * user on the second `sign-up` request and answers with a token, while a
32
- * password app answers it with an empty 200 and expects the password on
33
- * `users/new`.
32
+ * `password` is what the account is created with. Leave it out only for an app
33
+ * that signs people in with an emailed code. An app expecting a password
34
+ * rejects a sign-up without one, and the other way round.
35
+ *
36
+ * A `signedIn` result means the visitor is signed in. An app that also asks for
37
+ * an authenticator app answers `authenticatorRequired` instead, naming the step
38
+ * to send them to next.
34
39
  */
35
40
  async function confirmSignUp(details) {
36
41
  const platform = makePlatform(sessionConfig().applicationId);
37
- const verified = await platform.signUp({
38
- ...signUpBody(details),
39
- token: details.code
42
+ const { password,...rest } = details;
43
+ const result = password === void 0 ? await platform.signUpWithCode(rest) : await platform.signUpWithPassword({
44
+ ...rest,
45
+ password
40
46
  });
41
- if (!verified.ok) {
42
- if (verified.status >= 500) panic(verified.message);
43
- if (verified.status === 409) return authError("emailTaken", verified.message);
44
- return authError("invalidCode", verified.message);
47
+ if (!result.ok) {
48
+ if (result.status === 409) return authError("emailTaken", result.message);
49
+ if (result.status === 429) return authError("tooManyAttempts", result.message);
50
+ if (result.status === 400 || result.status === 401) return authError("invalidCode", result.message);
51
+ if (result.status >= 500) panic(`Expected sign-up to succeed, but got ${result.status}: ` + result.message);
52
+ throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app allows sign-up.`);
45
53
  }
46
- let token = verified.data?.jwt;
47
- if (!token) {
48
- const created = await platform.new({
49
- ...signUpBody(details),
50
- password: details.password,
51
- token: details.code
52
- });
53
- if (created.ok) token = created.data?.jwt;
54
- else {
55
- if (created.status >= 500) panic(created.message);
56
- if (created.status === 409) return authError("emailTaken", created.message);
57
- const signedIn = await signIn({
58
- email: details.email,
59
- password: details.password
60
- });
61
- if (!signedIn.success) return authError("invalidCode", created.message);
62
- return signedIn;
63
- }
54
+ if (result.data.status === "MFA_REQUIRED") {
55
+ const { mfa } = result.data;
56
+ assert(mfa, "Expected a challenge from sign-up, but got none");
57
+ writeCookies([makePendingAuthCookie(mfa.challengeToken)]);
58
+ return {
59
+ success: true,
60
+ data: {
61
+ status: "authenticatorRequired",
62
+ step: mfa.action === "VERIFICATION_REQUIRED" ? "verify" : mfa.action === "SETUP_REQUIRED" ? "setup" : "setupOptional"
63
+ }
64
+ };
64
65
  }
65
- if (!token) todo("The sign-up returned no session token. This app is configured for a sign-up flow the SDK cannot finish yet.");
66
- const result = await platform.session(token);
67
- if (!result.ok) panic(result.message);
68
- const session = result.data;
69
- if (session.user === null) panic("Session token issued, but no user could be resolved for it.");
70
- writeCookies([makeSessionTokenCookie(token), makeSessionDataCookie(session, token)]);
66
+ const { session } = result.data;
67
+ assert(session, "Expected a session from sign-up, but got none");
68
+ writeCookies([makeSessionTokenCookie(session.jwt), makeSessionDataCookie({
69
+ user: session.user,
70
+ permissions: session.permissions
71
+ }, session.jwt)]);
72
+ clearPendingAuth();
71
73
  return {
72
74
  success: true,
73
- data: session.user
74
- };
75
- }
76
- /**
77
- * `name` is dropped when absent rather than sent as `undefined`: the platform's
78
- * validator runs on whatever key is present, and an explicit null is not the
79
- * same request as no name at all.
80
- */
81
- function signUpBody(details) {
82
- return details.name === void 0 ? { email: details.email } : {
83
- email: details.email,
84
- name: details.name
75
+ data: {
76
+ status: "signedIn",
77
+ user: session.user
78
+ }
85
79
  };
86
80
  }
87
81
 
@@ -0,0 +1,35 @@
1
+ import { User } from "../user.js";
2
+ import { AuthError, Result } from "./utils.js";
3
+
4
+ //#region src/auth/methods/social.d.ts
5
+
6
+ /**
7
+ * Signs a visitor in with a Google token the browser obtained, creating their
8
+ * account the first time.
9
+ *
10
+ * Pass the id token Google Identity Services handed the page. An access token
11
+ * is rejected, and so is a token minted for another app. `fullName` names a
12
+ * first-time visitor and does nothing for one who already has an account.
13
+ *
14
+ * A `signedIn` result means the visitor is signed in. An app that also asks for
15
+ * an authenticator app answers `authenticatorRequired` instead, naming the step
16
+ * to send them to next.
17
+ */
18
+ declare function signInWithGoogle(credentials: {
19
+ email: string;
20
+ token: string;
21
+ fullName?: string;
22
+ }): Promise<Result<{
23
+ status: "signedIn";
24
+ user: User;
25
+ } | {
26
+ status: "authenticatorRequired";
27
+ /**
28
+ * `verify`: they have an authenticator app and owe a code.
29
+ * `setup`: the app requires one and they have none yet.
30
+ * `setupOptional`: same, except they may skip it instead.
31
+ */
32
+ step: "verify" | "setup" | "setupOptional";
33
+ }, AuthError>>;
34
+ //#endregion
35
+ export { signInWithGoogle };
@@ -0,0 +1,58 @@
1
+ import { assert, panic } from "../../assertions.js";
2
+ import { writeCookies } from "../../cookies.js";
3
+ import { sessionConfig } from "../config.js";
4
+ import { makePlatform } from "../platform.js";
5
+ import { clearPendingAuth, makePendingAuthCookie, makeSessionDataCookie, makeSessionTokenCookie } from "../session.js";
6
+ import { authError } from "./utils.js";
7
+
8
+ //#region src/auth/methods/social.ts
9
+ /**
10
+ * Signs a visitor in with a Google token the browser obtained, creating their
11
+ * account the first time.
12
+ *
13
+ * Pass the id token Google Identity Services handed the page. An access token
14
+ * is rejected, and so is a token minted for another app. `fullName` names a
15
+ * first-time visitor and does nothing for one who already has an account.
16
+ *
17
+ * A `signedIn` result means the visitor is signed in. An app that also asks for
18
+ * an authenticator app answers `authenticatorRequired` instead, naming the step
19
+ * to send them to next.
20
+ */
21
+ async function signInWithGoogle(credentials) {
22
+ const result = await makePlatform(sessionConfig().applicationId).signInWithGoogle(credentials);
23
+ if (!result.ok) {
24
+ if (result.status === 429) return authError("tooManyAttempts", result.message);
25
+ if (result.status === 400 || result.status === 401) return authError("invalidCredentials", result.message);
26
+ if (result.status >= 500) panic(`Expected Google sign-in to succeed, but got ${result.status}: ` + result.message);
27
+ throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app allows Google sign-in.`);
28
+ }
29
+ if (result.data.status === "MFA_REQUIRED") {
30
+ const { mfa } = result.data;
31
+ assert(mfa, "Expected a challenge from Google sign-in, but got none");
32
+ writeCookies([makePendingAuthCookie(mfa.challengeToken)]);
33
+ return {
34
+ success: true,
35
+ data: {
36
+ status: "authenticatorRequired",
37
+ step: mfa.action === "VERIFICATION_REQUIRED" ? "verify" : mfa.action === "SETUP_REQUIRED" ? "setup" : "setupOptional"
38
+ }
39
+ };
40
+ }
41
+ const { session } = result.data;
42
+ assert(session, "Expected a session from Google sign-in, but got none");
43
+ writeCookies([makeSessionTokenCookie(session.jwt), makeSessionDataCookie({
44
+ user: session.user,
45
+ permissions: session.permissions
46
+ }, session.jwt)]);
47
+ clearPendingAuth();
48
+ return {
49
+ success: true,
50
+ data: {
51
+ status: "signedIn",
52
+ user: session.user
53
+ }
54
+ };
55
+ }
56
+
57
+ //#endregion
58
+ export { signInWithGoogle };
@@ -10,6 +10,6 @@ type AuthError = {
10
10
  code: AuthErrorCode;
11
11
  message: string;
12
12
  };
13
- type AuthErrorCode = "invalidCredentials" | "tooManyAttempts" | "emailTaken" | "invalidDetails" | "invalidCode";
13
+ type AuthErrorCode = "invalidCredentials" | "tooManyAttempts" | "emailTaken" | "invalidDetails" | "invalidCode" | "notAuthenticated";
14
14
  //#endregion
15
15
  export { AuthError, Result };
@@ -22,18 +22,196 @@ function makePlatform(applicationId) {
22
22
  method: "POST",
23
23
  json: credentials
24
24
  }, z.object({
25
- jwt: z.string(),
26
- user: userSchema,
27
- permissions: permissionsSchema
25
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
26
+ session: z.object({
27
+ jwt: z.string(),
28
+ user: userSchema,
29
+ permissions: permissionsSchema
30
+ }).nullish(),
31
+ mfa: z.object({
32
+ action: z.enum([
33
+ "VERIFICATION_REQUIRED",
34
+ "SETUP_REQUIRED",
35
+ "SETUP_OPTIONAL"
36
+ ]),
37
+ challengeToken: z.string()
38
+ }).nullish()
39
+ })),
40
+ sendSignInCode: (email) => request(`/v1/vibe/applications/${applicationId}/users/tokens/send-code`, {
41
+ method: "POST",
42
+ json: { email }
43
+ }, z.null()),
44
+ signInWithCode: (credentials) => request(`/v1/vibe/applications/${applicationId}/users/tokens/with-code`, {
45
+ method: "POST",
46
+ json: credentials
47
+ }, z.object({
48
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
49
+ session: z.object({
50
+ jwt: z.string(),
51
+ user: userSchema,
52
+ permissions: permissionsSchema
53
+ }).nullish(),
54
+ mfa: z.object({
55
+ action: z.enum([
56
+ "VERIFICATION_REQUIRED",
57
+ "SETUP_REQUIRED",
58
+ "SETUP_OPTIONAL"
59
+ ]),
60
+ challengeToken: z.string()
61
+ }).nullish()
62
+ })),
63
+ signInWithGoogle: (body) => request(`/v1/vibe/applications/${applicationId}/users/tokens/with-google`, {
64
+ method: "POST",
65
+ json: body
66
+ }, z.object({
67
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
68
+ session: z.object({
69
+ jwt: z.string(),
70
+ user: userSchema,
71
+ permissions: permissionsSchema
72
+ }).nullish(),
73
+ mfa: z.object({
74
+ action: z.enum([
75
+ "VERIFICATION_REQUIRED",
76
+ "SETUP_REQUIRED",
77
+ "SETUP_OPTIONAL"
78
+ ]),
79
+ challengeToken: z.string()
80
+ }).nullish()
28
81
  })),
29
- signUp: (body) => request(`/v1/applications/${applicationId}/users/sign-up`, {
82
+ signInWithMagicLink: (body) => request(`/v1/vibe/applications/${applicationId}/users/tokens/with-magic-link`, {
30
83
  method: "POST",
31
84
  json: body
32
- }, z.object({ jwt: z.string().nullish() }).nullable()),
33
- new: (body) => request(`/v1/applications/${applicationId}/users/new`, {
85
+ }, z.object({
86
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
87
+ session: z.object({
88
+ jwt: z.string(),
89
+ user: userSchema,
90
+ permissions: permissionsSchema
91
+ }).nullish(),
92
+ mfa: z.object({
93
+ action: z.enum([
94
+ "VERIFICATION_REQUIRED",
95
+ "SETUP_REQUIRED",
96
+ "SETUP_OPTIONAL"
97
+ ]),
98
+ challengeToken: z.string()
99
+ }).nullish()
100
+ })),
101
+ sendSignUpCode: (body) => request(`/v1/vibe/applications/${applicationId}/users/sign-up/send-code`, {
102
+ method: "POST",
103
+ json: body
104
+ }, z.null()),
105
+ signUpWithCode: (body) => request(`/v1/vibe/applications/${applicationId}/users/sign-up/with-code`, {
106
+ method: "POST",
107
+ json: body
108
+ }, z.object({
109
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
110
+ session: z.object({
111
+ jwt: z.string(),
112
+ user: userSchema,
113
+ permissions: permissionsSchema
114
+ }).nullish(),
115
+ mfa: z.object({
116
+ action: z.enum([
117
+ "VERIFICATION_REQUIRED",
118
+ "SETUP_REQUIRED",
119
+ "SETUP_OPTIONAL"
120
+ ]),
121
+ challengeToken: z.string()
122
+ }).nullish()
123
+ })),
124
+ signUpWithPassword: (body) => request(`/v1/vibe/applications/${applicationId}/users/sign-up/with-password`, {
34
125
  method: "POST",
35
126
  json: body
36
- }, z.object({ jwt: z.string().nullish() }).nullable()),
127
+ }, z.object({
128
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
129
+ session: z.object({
130
+ jwt: z.string(),
131
+ user: userSchema,
132
+ permissions: permissionsSchema
133
+ }).nullish(),
134
+ mfa: z.object({
135
+ action: z.enum([
136
+ "VERIFICATION_REQUIRED",
137
+ "SETUP_REQUIRED",
138
+ "SETUP_OPTIONAL"
139
+ ]),
140
+ challengeToken: z.string()
141
+ }).nullish()
142
+ })),
143
+ authenticatorSetupInit: (token) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/setup/init`, {
144
+ method: "POST",
145
+ token
146
+ }, z.object({
147
+ otpauthUri: z.string(),
148
+ qrPngBase64: z.string()
149
+ })),
150
+ authenticatorSetupComplete: (token, code) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/setup/complete`, {
151
+ method: "POST",
152
+ token,
153
+ json: { code }
154
+ }, z.object({
155
+ session: z.object({
156
+ jwt: z.string(),
157
+ user: userSchema,
158
+ permissions: permissionsSchema
159
+ }),
160
+ backupCodes: z.array(z.string())
161
+ })),
162
+ authenticatorSetupDismiss: (token) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/setup/dismiss`, {
163
+ method: "POST",
164
+ token
165
+ }, z.object({
166
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
167
+ session: z.object({
168
+ jwt: z.string(),
169
+ user: userSchema,
170
+ permissions: permissionsSchema
171
+ }).nullish(),
172
+ mfa: z.object({
173
+ action: z.enum([
174
+ "VERIFICATION_REQUIRED",
175
+ "SETUP_REQUIRED",
176
+ "SETUP_OPTIONAL"
177
+ ]),
178
+ challengeToken: z.string()
179
+ }).nullish()
180
+ })),
181
+ authenticatorVerify: (token, body) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/totp/verify`, {
182
+ method: "POST",
183
+ token,
184
+ json: body
185
+ }, z.object({
186
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
187
+ session: z.object({
188
+ jwt: z.string(),
189
+ user: userSchema,
190
+ permissions: permissionsSchema
191
+ }).nullish(),
192
+ mfa: z.object({
193
+ action: z.enum([
194
+ "VERIFICATION_REQUIRED",
195
+ "SETUP_REQUIRED",
196
+ "SETUP_OPTIONAL"
197
+ ]),
198
+ challengeToken: z.string()
199
+ }).nullish()
200
+ })),
201
+ authenticatorSendResetCode: (token) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/reset/send-code`, {
202
+ method: "POST",
203
+ token
204
+ }, z.null()),
205
+ authenticatorReset: (token, code) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/reset`, {
206
+ method: "POST",
207
+ token,
208
+ json: { code }
209
+ }, z.null()),
210
+ authenticatorRemove: (token, code) => request(`/v1/vibe/applications/${applicationId}/users/authenticator/remove`, {
211
+ method: "POST",
212
+ token,
213
+ json: { code }
214
+ }, z.null()),
37
215
  signOut: (token) => request(`/v1/applications/${applicationId}/users/sign-out`, {
38
216
  method: "POST",
39
217
  token
@@ -1,5 +1,9 @@
1
+ import { confirmAuthenticatorSetup, removeAuthenticator, resetAuthenticator, sendAuthenticatorResetCode, skipAuthenticatorSetup, startAuthenticatorSetup, verifyAuthenticator } from "./methods/authenticator.js";
2
+ import { sendSignInCode, signInWithCode } from "./methods/code.js";
3
+ import { signInWithMagicLink } from "./methods/magicLink.js";
1
4
  import { signIn, signOut } from "./methods/password.js";
2
5
  import { confirmSignUp, signUp } from "./methods/signup.js";
6
+ import { signInWithGoogle } from "./methods/social.js";
3
7
  import "@tanstack/react-start/server-only";
4
8
 
5
9
  //#region src/auth/server.d.ts
@@ -12,6 +16,17 @@ declare const auth: {
12
16
  signOut: typeof signOut;
13
17
  signUp: typeof signUp;
14
18
  confirmSignUp: typeof confirmSignUp;
19
+ sendSignInCode: typeof sendSignInCode;
20
+ signInWithCode: typeof signInWithCode;
21
+ signInWithGoogle: typeof signInWithGoogle;
22
+ signInWithMagicLink: typeof signInWithMagicLink;
23
+ startAuthenticatorSetup: typeof startAuthenticatorSetup;
24
+ confirmAuthenticatorSetup: typeof confirmAuthenticatorSetup;
25
+ skipAuthenticatorSetup: typeof skipAuthenticatorSetup;
26
+ verifyAuthenticator: typeof verifyAuthenticator;
27
+ sendAuthenticatorResetCode: typeof sendAuthenticatorResetCode;
28
+ resetAuthenticator: typeof resetAuthenticator;
29
+ removeAuthenticator: typeof removeAuthenticator;
15
30
  };
16
31
  //#endregion
17
32
  export { auth };
@@ -1,5 +1,9 @@
1
+ import { confirmAuthenticatorSetup, removeAuthenticator, resetAuthenticator, sendAuthenticatorResetCode, skipAuthenticatorSetup, startAuthenticatorSetup, verifyAuthenticator } from "./methods/authenticator.js";
2
+ import { sendSignInCode, signInWithCode } from "./methods/code.js";
3
+ import { signInWithMagicLink } from "./methods/magicLink.js";
1
4
  import { signIn, signOut } from "./methods/password.js";
2
5
  import { confirmSignUp, signUp } from "./methods/signup.js";
6
+ import { signInWithGoogle } from "./methods/social.js";
3
7
  import "@tanstack/react-start/server-only";
4
8
 
5
9
  //#region src/auth/server.ts
@@ -10,7 +14,18 @@ const auth = {
10
14
  signIn,
11
15
  signOut,
12
16
  signUp,
13
- confirmSignUp
17
+ confirmSignUp,
18
+ sendSignInCode,
19
+ signInWithCode,
20
+ signInWithGoogle,
21
+ signInWithMagicLink,
22
+ startAuthenticatorSetup,
23
+ confirmAuthenticatorSetup,
24
+ skipAuthenticatorSetup,
25
+ verifyAuthenticator,
26
+ sendAuthenticatorResetCode,
27
+ resetAuthenticator,
28
+ removeAuthenticator
14
29
  };
15
30
 
16
31
  //#endregion
@@ -9,8 +9,14 @@ import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:
9
9
  //#region src/auth/session.ts
10
10
  const SESSION_TOKEN = "session_token";
11
11
  const SESSION_DATA = "session_data";
12
+ const PENDING_AUTH = "pending_auth";
12
13
  const SESSION_DATA_TTL_SECONDS = 300;
13
14
  /**
15
+ * How long a visitor has to answer a second factor. The platform expires the
16
+ * challenge token itself. This only decides how long the browser carries it.
17
+ */
18
+ const PENDING_AUTH_TTL_SECONDS = 600;
19
+ /**
14
20
  * A browser refuses a `__Host-` cookie unless it is `Secure`, `Path=/` and free
15
21
  * of `Domain` — that last clause is the one worth having, since it stops a
16
22
  * sibling host planting a cookie of this name for us to honour.
@@ -67,10 +73,37 @@ function makeSessionDataCookie(session, sessionToken) {
67
73
  });
68
74
  }
69
75
  /**
76
+ * The challenge token from a sign-in that stopped at a second factor, or
77
+ * `null`.
78
+ *
79
+ * It is a bearer credential scoped to the authenticator endpoints, so it stays
80
+ * sealed in the jar the way a session token does, instead of passing through
81
+ * the app.
82
+ */
83
+ function readPendingAuthToken() {
84
+ const { name } = sessionCookie(PENDING_AUTH);
85
+ return openEnvelope(readRequestCookies()[name], PENDING_AUTH);
86
+ }
87
+ function makePendingAuthCookie(token) {
88
+ const { name, secure } = sessionCookie(PENDING_AUTH);
89
+ return serializeCookie(name, sealEnvelope(token, PENDING_AUTH), {
90
+ maxAge: PENDING_AUTH_TTL_SECONDS,
91
+ secure
92
+ });
93
+ }
94
+ /** Drops an outstanding challenge without touching the session. */
95
+ function clearPendingAuth() {
96
+ clearCookies([PENDING_AUTH]);
97
+ }
98
+ /**
70
99
  * Writes rather than returns: a forgotten list would leave the session live.
71
100
  */
72
101
  function clearSession() {
73
- clearCookies([SESSION_TOKEN, SESSION_DATA]);
102
+ clearCookies([
103
+ SESSION_TOKEN,
104
+ SESSION_DATA,
105
+ PENDING_AUTH
106
+ ]);
74
107
  }
75
108
  const sessionDataSchema = z.object({
76
109
  user: userSchema.nullable(),
@@ -163,4 +196,4 @@ function openEnvelope(raw, purpose) {
163
196
  }
164
197
 
165
198
  //#endregion
166
- export { clearSession, makeSessionDataCookie, makeSessionTokenCookie, readSessionData, readSessionToken };
199
+ export { clearPendingAuth, clearSession, makePendingAuthCookie, makeSessionDataCookie, makeSessionTokenCookie, readPendingAuthToken, readSessionData, readSessionToken };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@softr/sdk",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
@@ -11,7 +11,7 @@ description: >-
11
11
  metadata:
12
12
  type: core
13
13
  library: softr-sdk
14
- library_version: 0.0.24
14
+ library_version: 0.0.25
15
15
  ---
16
16
 
17
17
  # Softr SDK core
@@ -124,4 +124,4 @@ type User = {
124
124
 
125
125
  ## Version
126
126
 
127
- Targets `@softr/sdk` v0.0.24.
127
+ Targets `@softr/sdk` v0.0.25.