@protobase/server 0.53.7 → 0.54.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/better-auth/auth-settings.d.ts +33 -2
- package/dist/better-auth/create-auth.d.ts +44 -8
- package/dist/better-auth/create-auth.js +18 -5
- package/dist/better-auth/last-admin-guard.js +9 -5
- package/dist/better-auth/locked-accounts.js +6 -5
- package/dist/better-auth/self-deletion.js +40 -0
- package/dist/better-auth/status-route.js +2 -1
- package/dist/better-auth/user-deletion.js +4 -3
- package/dist/check-views.js +1 -1
- package/dist/package.js +1 -1
- package/package.json +4 -4
|
@@ -74,6 +74,35 @@ export declare const appAuthOptions: (settings: AuthSettings, { pool, db, hooks,
|
|
|
74
74
|
/** The app's Better Auth from its `auth` settings, built at serve time with only the plugins they turn on. */
|
|
75
75
|
export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput) => Promise<import("better-auth").Auth<{
|
|
76
76
|
user: {
|
|
77
|
+
deleteUser: {
|
|
78
|
+
enabled: boolean;
|
|
79
|
+
beforeDelete: (user: {
|
|
80
|
+
id: string;
|
|
81
|
+
email: string;
|
|
82
|
+
}) => Promise<void>;
|
|
83
|
+
afterDelete: (user: {
|
|
84
|
+
id: string;
|
|
85
|
+
}) => Promise<void>;
|
|
86
|
+
};
|
|
87
|
+
additionalFields?: {
|
|
88
|
+
metadata?: {
|
|
89
|
+
readonly type: "json";
|
|
90
|
+
readonly required: false;
|
|
91
|
+
readonly fieldName: string;
|
|
92
|
+
} | undefined;
|
|
93
|
+
lastOrganizationId?: {
|
|
94
|
+
readonly type: "string";
|
|
95
|
+
readonly required: false;
|
|
96
|
+
readonly input: false;
|
|
97
|
+
readonly fieldName: "last_organization_id";
|
|
98
|
+
} | undefined;
|
|
99
|
+
emailConfirmedAt: {
|
|
100
|
+
readonly type: "date";
|
|
101
|
+
readonly required: false;
|
|
102
|
+
readonly input: false;
|
|
103
|
+
readonly fieldName: "email_confirmed_at";
|
|
104
|
+
};
|
|
105
|
+
} | undefined;
|
|
77
106
|
modelName: string;
|
|
78
107
|
fields: {
|
|
79
108
|
name: string;
|
|
@@ -84,7 +113,8 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
|
|
|
84
113
|
updatedAt: string;
|
|
85
114
|
};
|
|
86
115
|
} | {
|
|
87
|
-
|
|
116
|
+
deleteUser?: undefined;
|
|
117
|
+
additionalFields?: {
|
|
88
118
|
metadata?: {
|
|
89
119
|
readonly type: "json";
|
|
90
120
|
readonly required: false;
|
|
@@ -102,7 +132,7 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
|
|
|
102
132
|
readonly input: false;
|
|
103
133
|
readonly fieldName: "email_confirmed_at";
|
|
104
134
|
};
|
|
105
|
-
};
|
|
135
|
+
} | undefined;
|
|
106
136
|
modelName: string;
|
|
107
137
|
fields: {
|
|
108
138
|
name: string;
|
|
@@ -8751,6 +8781,7 @@ export declare const buildAppAuth: (settings: AuthSettings, input: AppAuthInput)
|
|
|
8751
8781
|
signInFirst: "password" | "emailCode";
|
|
8752
8782
|
passwordReset: boolean;
|
|
8753
8783
|
leakedPasswords: boolean;
|
|
8784
|
+
accountDeletion: boolean;
|
|
8754
8785
|
signUp: boolean;
|
|
8755
8786
|
signUpRole: string | undefined;
|
|
8756
8787
|
userMetadata: boolean;
|
|
@@ -135,6 +135,12 @@ export type CreateAuthOptions = {
|
|
|
135
135
|
* the password's SHA-1 hash leave the server. While the list cannot be reached, setting a password fails. Default off.
|
|
136
136
|
*/
|
|
137
137
|
leakedPasswords?: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Lets the signed-in person delete their own account from the account page, with their password or from a session
|
|
140
|
+
* that signed in within the last day; `false` turns it off, for apps whose accounts are managed by an organization's
|
|
141
|
+
* admins. Default on, as app stores require an app that makes accounts to delete them too.
|
|
142
|
+
*/
|
|
143
|
+
accountDeletion?: boolean;
|
|
138
144
|
/**
|
|
139
145
|
* The identity provider the operator's staff sign in with to sign in as people of this app, for support. Defaults
|
|
140
146
|
* to the one the platform passes in `PROTOBASE_OPERATOR_ISSUER`, `PROTOBASE_OPERATOR_CLIENT_ID` and
|
|
@@ -193,6 +199,35 @@ export type AuthPlugins = {
|
|
|
193
199
|
export declare const loadAuthPlugins: (options: Pick<CreateAuthOptions, "sso" | "mcp">) => Promise<AuthPlugins>;
|
|
194
200
|
export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlugins) => import("better-auth").Auth<{
|
|
195
201
|
user: {
|
|
202
|
+
deleteUser: {
|
|
203
|
+
enabled: boolean;
|
|
204
|
+
beforeDelete: (user: {
|
|
205
|
+
id: string;
|
|
206
|
+
email: string;
|
|
207
|
+
}) => Promise<void>;
|
|
208
|
+
afterDelete: (user: {
|
|
209
|
+
id: string;
|
|
210
|
+
}) => Promise<void>;
|
|
211
|
+
};
|
|
212
|
+
additionalFields?: {
|
|
213
|
+
metadata?: {
|
|
214
|
+
readonly type: "json";
|
|
215
|
+
readonly required: false;
|
|
216
|
+
readonly fieldName: string;
|
|
217
|
+
} | undefined;
|
|
218
|
+
lastOrganizationId?: {
|
|
219
|
+
readonly type: "string";
|
|
220
|
+
readonly required: false;
|
|
221
|
+
readonly input: false;
|
|
222
|
+
readonly fieldName: "last_organization_id";
|
|
223
|
+
} | undefined;
|
|
224
|
+
emailConfirmedAt: {
|
|
225
|
+
readonly type: "date";
|
|
226
|
+
readonly required: false;
|
|
227
|
+
readonly input: false;
|
|
228
|
+
readonly fieldName: "email_confirmed_at";
|
|
229
|
+
};
|
|
230
|
+
} | undefined;
|
|
196
231
|
modelName: string;
|
|
197
232
|
fields: {
|
|
198
233
|
name: string;
|
|
@@ -203,7 +238,8 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
203
238
|
updatedAt: string;
|
|
204
239
|
};
|
|
205
240
|
} | {
|
|
206
|
-
|
|
241
|
+
deleteUser?: undefined;
|
|
242
|
+
additionalFields?: {
|
|
207
243
|
metadata?: {
|
|
208
244
|
readonly type: "json";
|
|
209
245
|
readonly required: false;
|
|
@@ -221,7 +257,7 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
221
257
|
readonly input: false;
|
|
222
258
|
readonly fieldName: "email_confirmed_at";
|
|
223
259
|
};
|
|
224
|
-
};
|
|
260
|
+
} | undefined;
|
|
225
261
|
modelName: string;
|
|
226
262
|
fields: {
|
|
227
263
|
name: string;
|
|
@@ -1364,7 +1400,7 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
1364
1400
|
expiresAt: Date;
|
|
1365
1401
|
token: string;
|
|
1366
1402
|
ipAddress?: string | null | undefined;
|
|
1367
|
-
userAgent
|
|
1403
|
+
userAgent?: string | null | undefined;
|
|
1368
1404
|
};
|
|
1369
1405
|
user: Record<string, any> & {
|
|
1370
1406
|
id: string;
|
|
@@ -1757,7 +1793,7 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
1757
1793
|
email: string;
|
|
1758
1794
|
emailVerified: boolean;
|
|
1759
1795
|
name: string;
|
|
1760
|
-
image
|
|
1796
|
+
image? /** Runs after a user is created, by any route: `createUser`, an admin, or a social sign-up. Default none. */ : string | null | undefined;
|
|
1761
1797
|
}) | import("better-auth/plugins").UserWithTwoFactor;
|
|
1762
1798
|
}>;
|
|
1763
1799
|
generateBackupCodes: import("better-call").StrictEndpoint<"/two-factor/generate-backup-codes", {
|
|
@@ -1952,9 +1988,7 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
1952
1988
|
email: string;
|
|
1953
1989
|
emailVerified: boolean;
|
|
1954
1990
|
name: string;
|
|
1955
|
-
image
|
|
1956
|
-
/** The app's name, from `PROTOBASE_APP_NAME` or `appName`; default `Protobase`. */
|
|
1957
|
-
/** The app's name, from `PROTOBASE_APP_NAME` or `appName`; default `Protobase`. */ : string | null | undefined;
|
|
1991
|
+
image?: string | null | undefined;
|
|
1958
1992
|
};
|
|
1959
1993
|
}>;
|
|
1960
1994
|
generateTOTP: import("better-call").StrictEndpoint<string, {
|
|
@@ -5023,7 +5057,7 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
5023
5057
|
organization: {
|
|
5024
5058
|
name?: string;
|
|
5025
5059
|
slug?: string;
|
|
5026
|
-
logo
|
|
5060
|
+
logo?: string | null;
|
|
5027
5061
|
metadata?: Record<string, any>;
|
|
5028
5062
|
[key: string]: any;
|
|
5029
5063
|
};
|
|
@@ -8881,6 +8915,8 @@ export declare const createAuth: (options: CreateAuthOptions, plugins?: AuthPlug
|
|
|
8881
8915
|
passwordReset: boolean;
|
|
8882
8916
|
/** New passwords are checked against Have I Been Pwned's list of leaked ones (`leakedPasswords`). */
|
|
8883
8917
|
leakedPasswords: boolean;
|
|
8918
|
+
/** The signed-in person can delete their own account (`accountDeletion`). */
|
|
8919
|
+
accountDeletion: boolean;
|
|
8884
8920
|
/** Open sign-up is on and offered: the app asks for it, and can mail the codes. */
|
|
8885
8921
|
signUp: boolean;
|
|
8886
8922
|
/** The role of accounts made by open sign-up, while it is offered. */
|
|
@@ -19,8 +19,9 @@ import { setPasswordPath, setPasswordPlugin } from "./set-password.js";
|
|
|
19
19
|
import { signUpPaths, signUpPlugin } from "./sign-up/sign-up-plugin.js";
|
|
20
20
|
import { leakedPasswordsPlugin } from "./leaked-passwords.js";
|
|
21
21
|
import { lockedAccountsPlugin, readLockedAccounts } from "./locked-accounts.js";
|
|
22
|
-
import { userDeletion } from "./user-deletion.js";
|
|
23
22
|
import { revokeMcpGrants } from "./mcp/revoke-grants.js";
|
|
23
|
+
import { selfDeletionCallbackPath, selfDeletionOptions, selfDeletionPath } from "./self-deletion.js";
|
|
24
|
+
import { userDeletion } from "./user-deletion.js";
|
|
24
25
|
import { mcpUnusedPaths, resolveMcp } from "./mcp/mcp-plugins.js";
|
|
25
26
|
import { lastOrganizationField, sessionOrganizationHooks } from "./organizations/session-organization.js";
|
|
26
27
|
import { organizationPlugin } from "./organizations/organization-plugin.js";
|
|
@@ -149,6 +150,13 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
149
150
|
...organizations && userFieldsNamed(lastOrganizationField, users),
|
|
150
151
|
...metadataField(users)
|
|
151
152
|
};
|
|
153
|
+
const accountDeletion = options.accountDeletion !== false;
|
|
154
|
+
const deleteUser = accountDeletion ? { deleteUser: selfDeletionOptions({
|
|
155
|
+
lockedAccounts,
|
|
156
|
+
mcp: Boolean(mcp),
|
|
157
|
+
adapter: async () => (await context()).adapter,
|
|
158
|
+
...deletion && { deletion }
|
|
159
|
+
}) } : {};
|
|
152
160
|
return {
|
|
153
161
|
appName,
|
|
154
162
|
database: options.database,
|
|
@@ -167,10 +175,11 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
167
175
|
...mail && passwordResetOptions(mail, mcp ? { onPasswordReset: async ({ user }) => revokeMcpGrants((await context()).adapter, user.id) } : {})
|
|
168
176
|
},
|
|
169
177
|
...options.socialProviders && { socialProviders: options.socialProviders },
|
|
170
|
-
user:
|
|
178
|
+
user: {
|
|
171
179
|
...userModel(users),
|
|
172
|
-
additionalFields: userFields
|
|
173
|
-
|
|
180
|
+
...Object.keys(userFields).length > 0 && { additionalFields: userFields },
|
|
181
|
+
...deleteUser
|
|
182
|
+
},
|
|
174
183
|
session: coreNames.session,
|
|
175
184
|
verification: coreNames.verification,
|
|
176
185
|
account: {
|
|
@@ -252,6 +261,8 @@ const betterAuthOptions = (options, { origins = [], passkeyDomain, roles, defini
|
|
|
252
261
|
}) : []
|
|
253
262
|
].map((plugin) => withUserColumns(plugin, users)),
|
|
254
263
|
disabledPaths: [
|
|
264
|
+
selfDeletionCallbackPath,
|
|
265
|
+
...accountDeletion ? [] : [selfDeletionPath],
|
|
255
266
|
...unusedEmailCodePaths,
|
|
256
267
|
...adminImpersonationPaths,
|
|
257
268
|
...organizations ? organizationPaths : [],
|
|
@@ -385,7 +396,7 @@ const createAuth = (options, plugins = {}) => {
|
|
|
385
396
|
signInPolicy,
|
|
386
397
|
...organizations && { organizations },
|
|
387
398
|
...mcp && { mcp },
|
|
388
|
-
|
|
399
|
+
context
|
|
389
400
|
});
|
|
390
401
|
assertNoEndpointKeyClashes(authOptions.plugins);
|
|
391
402
|
const auth = betterAuth(authOptions);
|
|
@@ -424,6 +435,8 @@ const createAuth = (options, plugins = {}) => {
|
|
|
424
435
|
passwordReset: Boolean(mailer),
|
|
425
436
|
/** New passwords are checked against Have I Been Pwned's list of leaked ones (`leakedPasswords`). */
|
|
426
437
|
leakedPasswords: Boolean(options.leakedPasswords),
|
|
438
|
+
/** The signed-in person can delete their own account (`accountDeletion`). */
|
|
439
|
+
accountDeletion: options.accountDeletion !== false,
|
|
427
440
|
/** Open sign-up is on and offered: the app asks for it, and can mail the codes. */
|
|
428
441
|
signUp: Boolean(signUpRole && mailer),
|
|
429
442
|
/** The role of accounts made by open sign-up, while it is offered. */
|
|
@@ -29,6 +29,13 @@ const adminChange = (path, body) => {
|
|
|
29
29
|
...banned !== void 0 && { banned }
|
|
30
30
|
};
|
|
31
31
|
};
|
|
32
|
+
/** Refuses, with `400 LAST_ADMIN`, a change that would leave no active admin. */
|
|
33
|
+
const refuseLastAdmin = () => {
|
|
34
|
+
throw new APIError("BAD_REQUEST", {
|
|
35
|
+
code: "LAST_ADMIN",
|
|
36
|
+
message: "This is the last admin: make someone else an admin first."
|
|
37
|
+
});
|
|
38
|
+
};
|
|
32
39
|
const guardedPaths = [
|
|
33
40
|
"/admin/set-role",
|
|
34
41
|
"/admin/ban-user",
|
|
@@ -51,12 +58,9 @@ const lastAdminGuardPlugin = () => ({
|
|
|
51
58
|
"banned"
|
|
52
59
|
]
|
|
53
60
|
});
|
|
54
|
-
if (wouldLeaveNoAdmin(users, change))
|
|
55
|
-
code: "LAST_ADMIN",
|
|
56
|
-
message: "This is the last admin: make someone else an admin first."
|
|
57
|
-
});
|
|
61
|
+
if (wouldLeaveNoAdmin(users, change)) refuseLastAdmin();
|
|
58
62
|
})
|
|
59
63
|
}] }
|
|
60
64
|
});
|
|
61
65
|
//#endregion
|
|
62
|
-
export { adminChange, lastAdminGuardPlugin };
|
|
66
|
+
export { adminChange, lastAdminGuardPlugin, refuseLastAdmin };
|
|
@@ -22,7 +22,8 @@ const lockedFields = {
|
|
|
22
22
|
"updatedAt"
|
|
23
23
|
].includes(field)
|
|
24
24
|
};
|
|
25
|
-
|
|
25
|
+
/** Refuses, with `403 ACCOUNT_LOCKED`, a change to or the deletion of a locked account. */
|
|
26
|
+
const refuseLockedAccount = () => {
|
|
26
27
|
throw new APIError("FORBIDDEN", {
|
|
27
28
|
code: "ACCOUNT_LOCKED",
|
|
28
29
|
message: "This account is locked: its address, password, passkeys, two-factor authentication and linked accounts stay as they are, and it cannot be deleted."
|
|
@@ -55,10 +56,10 @@ const lockAccounts = (adapter, emails) => {
|
|
|
55
56
|
};
|
|
56
57
|
const checkUpdate = async (model, where, fields) => {
|
|
57
58
|
const locked = lockedFields[model];
|
|
58
|
-
if (locked && fields.some(locked) && await matchesLocked(model, where))
|
|
59
|
+
if (locked && fields.some(locked) && await matchesLocked(model, where)) refuseLockedAccount();
|
|
59
60
|
};
|
|
60
61
|
const checkDelete = async (model, where) => {
|
|
61
|
-
if (lockedFields[model] && await matchesLocked(model, where))
|
|
62
|
+
if (lockedFields[model] && await matchesLocked(model, where)) refuseLockedAccount();
|
|
62
63
|
};
|
|
63
64
|
const checkCreate = async (model, data) => {
|
|
64
65
|
if (model === "user" || !lockedFields[model]) return;
|
|
@@ -70,7 +71,7 @@ const lockAccounts = (adapter, emails) => {
|
|
|
70
71
|
value: data.userId
|
|
71
72
|
}]
|
|
72
73
|
}) === 0) return;
|
|
73
|
-
|
|
74
|
+
refuseLockedAccount();
|
|
74
75
|
};
|
|
75
76
|
return {
|
|
76
77
|
...adapter,
|
|
@@ -120,4 +121,4 @@ const lockedAccountsPlugin = (emails) => ({
|
|
|
120
121
|
}
|
|
121
122
|
});
|
|
122
123
|
//#endregion
|
|
123
|
-
export { lockAccounts, lockedAccountsPlugin, lockedAccountsVariable, readLockedAccounts };
|
|
124
|
+
export { lockAccounts, lockedAccountsPlugin, lockedAccountsVariable, readLockedAccounts, refuseLockedAccount };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { wouldLeaveNoAdmin } from "./last-admin.js";
|
|
2
|
+
import { refuseLastAdmin } from "./last-admin-guard.js";
|
|
3
|
+
import { refuseLockedAccount } from "./locked-accounts.js";
|
|
4
|
+
import { revokeMcpGrants } from "./mcp/revoke-grants.js";
|
|
5
|
+
//#region src/better-auth/self-deletion.ts
|
|
6
|
+
/** The paths of Better Auth's own deletion of the signed-in person's account, and of its emailed confirmation, which Protobase does not send. */
|
|
7
|
+
const selfDeletionPath = "/delete-user";
|
|
8
|
+
const selfDeletionCallbackPath = "/delete-user/callback";
|
|
9
|
+
/**
|
|
10
|
+
* Better Auth's `user.deleteUser`: the signed-in person deletes their own account, with their password or from a
|
|
11
|
+
* session that signed in within the last day. Once Better Auth has checked that, a locked account and the last active
|
|
12
|
+
* admin are refused, the `userDeletion` listeners and the MCP grants go, and Better Auth deletes the user with their
|
|
13
|
+
* sessions and accounts; the listeners run once more after.
|
|
14
|
+
*/
|
|
15
|
+
const selfDeletionOptions = ({ lockedAccounts, deletion, mcp, adapter }) => ({
|
|
16
|
+
enabled: true,
|
|
17
|
+
beforeDelete: async (user) => {
|
|
18
|
+
if (lockedAccounts.includes(user.email.toLowerCase())) refuseLockedAccount();
|
|
19
|
+
const store = await adapter();
|
|
20
|
+
const users = await store.findMany({
|
|
21
|
+
model: "user",
|
|
22
|
+
select: [
|
|
23
|
+
"id",
|
|
24
|
+
"role",
|
|
25
|
+
"banned"
|
|
26
|
+
]
|
|
27
|
+
});
|
|
28
|
+
if (wouldLeaveNoAdmin(users, {
|
|
29
|
+
userId: user.id,
|
|
30
|
+
removed: true
|
|
31
|
+
})) refuseLastAdmin();
|
|
32
|
+
await deletion?.run(user.id);
|
|
33
|
+
if (mcp) await revokeMcpGrants(store, user.id);
|
|
34
|
+
},
|
|
35
|
+
afterDelete: async (user) => {
|
|
36
|
+
await deletion?.run(user.id);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
//#endregion
|
|
40
|
+
export { selfDeletionCallbackPath, selfDeletionOptions, selfDeletionPath };
|
|
@@ -9,7 +9,7 @@ import { Hono } from "hono";
|
|
|
9
9
|
* `GET {authBase}/status`: `needsAdmin` while the admin store has no user, so a login page can say how to create one;
|
|
10
10
|
* `signInMethods`, the ways to sign in the sign-in policy leaves on (`password`, `emailCode`, `passkey`), so it offers
|
|
11
11
|
* only those; `passwordReset` when reset mail can be sent and passwords are on, so it offers "Forgot password?" only
|
|
12
|
-
* then; `signInFirst: 'emailCode'` when the app has the sign-in page lead with an emailed code and the policy leaves both it and passwords on; `changeEmail` when mail can be sent, so the account page offers to change the address with an emailed code; `signUp` when the app has open sign-up, so it offers "Create an account"; the ids of the `socialProviders` people can sign in with, so it offers "Continue with GitHub" when `github` is
|
|
12
|
+
* then; `signInFirst: 'emailCode'` when the app has the sign-in page lead with an emailed code and the policy leaves both it and passwords on; `changeEmail` when mail can be sent, so the account page offers to change the address with an emailed code; `accountDeletion` when people may delete their own account, so the account page offers it; `signUp` when the app has open sign-up, so it offers "Create an account"; the ids of the `socialProviders` people can sign in with, so it offers "Continue with GitHub" when `github` is
|
|
13
13
|
* one; `platformSignIn`, the id and name of the platform's provider when it is one of them; `samlProviders`, the id and name of each SAML provider, when the app has any; `staffSignIn`, the
|
|
14
14
|
* operator provider's name, when staff can sign in as people; `passkeyDomains`, when people have passkeys for more than
|
|
15
15
|
* one of the app's hosts, the RP IDs a passkey sign-in can ask for, the passkey domain first; with organizations, who may create them and the roles
|
|
@@ -39,6 +39,7 @@ const statusRoute = (auth, { anonymous = false, plugins = [], locale } = {}) =>
|
|
|
39
39
|
passwordReset: auth.passwordReset && policy.password === "allowed",
|
|
40
40
|
...auth.signInFirst === "emailCode" && signInMethods.includes("emailCode") && signInMethods.includes("password") && { signInFirst: "emailCode" },
|
|
41
41
|
...auth.mail && { changeEmail: true },
|
|
42
|
+
...auth.accountDeletion && { accountDeletion: true },
|
|
42
43
|
...auth.signUp && { signUp: true },
|
|
43
44
|
socialProviders,
|
|
44
45
|
...platformSignIn && { platformSignIn },
|
|
@@ -4,9 +4,10 @@ import { createAuthMiddleware, getSessionFromCtx, isAPIError } from "better-auth
|
|
|
4
4
|
//#region src/better-auth/user-deletion.ts
|
|
5
5
|
const removePath = "/admin/remove-user";
|
|
6
6
|
/**
|
|
7
|
-
* What runs when a user is deleted, by an admin (`/admin/remove-user`)
|
|
8
|
-
* before anything is deleted, so one that throws stops the
|
|
9
|
-
* place, and once more after the user is gone, for what was
|
|
7
|
+
* What runs when a user is deleted, by an admin (`/admin/remove-user`), by `deleteUser` (the CLI) or by themselves
|
|
8
|
+
* (`/delete-user`, see `selfDeletionOptions`): each listener before anything is deleted, so one that throws stops the
|
|
9
|
+
* deletion with the user, their sessions and accounts in place, and once more after the user is gone, for what was
|
|
10
|
+
* added in between.
|
|
10
11
|
*/
|
|
11
12
|
const userDeletion = () => {
|
|
12
13
|
const listeners = /* @__PURE__ */ new Map();
|
package/dist/check-views.js
CHANGED
|
@@ -34,7 +34,7 @@ const sensitiveErrors = (view, model) => {
|
|
|
34
34
|
["the sidebar", layoutItems(view.layout).flatMap((item) => item.kind === "sidebar" ? item.fields : [])],
|
|
35
35
|
["a map", layoutItems(view.layout).flatMap((item) => item.kind === "map" ? [item.latitude, item.longitude] : [])],
|
|
36
36
|
["a gallery", layoutItems(view.layout).flatMap((item) => item.kind === "gallery" && item.image !== void 0 ? [item.image] : [])],
|
|
37
|
-
["the recent records", view.nav?.recent ? [view.nav.recent.status]
|
|
37
|
+
["the recent records", view.nav?.recent?.status === void 0 ? [] : [view.nav.recent.status]],
|
|
38
38
|
["an action", view.actions.flatMap((action) => [...actionFields(action.run), ...actionWhenFields(action.when)])]
|
|
39
39
|
].flatMap(([place, names]) => [...new Set(names.filter(sensitive))].map((name) => `sensitive field "${name}" cannot be in ${place}`));
|
|
40
40
|
};
|
package/dist/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"description": "The Protobase REST API as a Hono app, with Better Auth sign-in.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"@better-auth/passkey": "^1.7.12",
|
|
41
41
|
"@better-auth/sso": "^1.7.12",
|
|
42
42
|
"@modelcontextprotocol/server": "^2.3.1",
|
|
43
|
-
"@protobase/layout": "0.
|
|
44
|
-
"@protobase/query": "0.
|
|
45
|
-
"@protobase/schema": "0.
|
|
43
|
+
"@protobase/layout": "0.54.0",
|
|
44
|
+
"@protobase/query": "0.54.0",
|
|
45
|
+
"@protobase/schema": "0.54.0",
|
|
46
46
|
"@react-email/render": "^2.1.0",
|
|
47
47
|
"@scalar/hono-api-reference": "^0.12.10",
|
|
48
48
|
"@sentry/core": "^11.7.0",
|