@protobase/client 0.33.4 → 0.34.1
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/account-security.d.ts +17 -0
- package/dist/account-security.js +14 -0
- package/dist/auth-types.d.ts +4 -2
- package/dist/auth.d.ts +14 -2
- package/dist/auth.js +4 -1
- package/dist/connect.d.ts +27 -0
- package/dist/connect.js +43 -0
- package/dist/index.d.ts +3 -2
- package/dist/static-session.js +8 -1
- package/package.json +5 -5
|
@@ -25,6 +25,19 @@ export type Passkey = {
|
|
|
25
25
|
createdAt?: string;
|
|
26
26
|
backedUp: boolean;
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* An app the person allowed to act as them, such as an MCP client: its client id, the name it gave itself, when they
|
|
30
|
+
* last allowed it, and as what: each role (its label) and organization (its name) they allowed it with.
|
|
31
|
+
*/
|
|
32
|
+
export type ConnectedApp = {
|
|
33
|
+
clientId: string;
|
|
34
|
+
name?: string;
|
|
35
|
+
allowedAt: string;
|
|
36
|
+
access: {
|
|
37
|
+
role: string;
|
|
38
|
+
organization?: string;
|
|
39
|
+
}[];
|
|
40
|
+
};
|
|
28
41
|
/** A new authenticator app: the `otpauth://` URI it scans, and the backup codes that work once each instead of a code. */
|
|
29
42
|
export type AuthenticatorSetup = {
|
|
30
43
|
totpURI: string;
|
|
@@ -55,6 +68,10 @@ export declare const accountSecurity: (client: BetterAuthClient) => {
|
|
|
55
68
|
* `?error=<code>` when the link did not go through, for example `account_already_linked_to_different_user`.
|
|
56
69
|
*/
|
|
57
70
|
linkProvider: (provider: string, callbackURL: string) => Promise<string>;
|
|
71
|
+
/** The apps the person allowed to act as them, newest first; on an app with MCP on. */
|
|
72
|
+
connectedApps: () => Promise<ConnectedApp[]>;
|
|
73
|
+
/** Disconnects an app: it is forgotten, and its access ends within 15 minutes; it has to ask again to come back. */
|
|
74
|
+
disconnectApp: (clientId: string) => Promise<void>;
|
|
58
75
|
/** New backup codes for the authenticator app; the old ones stop working. */
|
|
59
76
|
newBackupCodes: (password?: string) => Promise<string[]>;
|
|
60
77
|
};
|
package/dist/account-security.js
CHANGED
|
@@ -85,6 +85,20 @@ const accountSecurity = (client) => ({
|
|
|
85
85
|
if (error || !data?.url) throw authError(error, "Could not start linking the account");
|
|
86
86
|
return data.url;
|
|
87
87
|
},
|
|
88
|
+
/** The apps the person allowed to act as them, newest first; on an app with MCP on. */
|
|
89
|
+
connectedApps: async () => {
|
|
90
|
+
const { data, error } = await client.$fetch("/account/connected-apps");
|
|
91
|
+
if (error || !data) throw authError(error, "Could not read your connected apps");
|
|
92
|
+
return data.apps;
|
|
93
|
+
},
|
|
94
|
+
/** Disconnects an app: it is forgotten, and its access ends within 15 minutes; it has to ask again to come back. */
|
|
95
|
+
disconnectApp: async (clientId) => {
|
|
96
|
+
const { error } = await client.$fetch("/account/connected-apps/disconnect", {
|
|
97
|
+
method: "POST",
|
|
98
|
+
body: { clientId }
|
|
99
|
+
});
|
|
100
|
+
if (error) throw authError(error, "Could not disconnect the app");
|
|
101
|
+
},
|
|
88
102
|
/** New backup codes for the authenticator app; the old ones stop working. */
|
|
89
103
|
newBackupCodes: async (password) => {
|
|
90
104
|
const { data, error } = await client.twoFactor.generateBackupCodes(password ? { password } : {});
|
package/dist/auth-types.d.ts
CHANGED
|
@@ -35,8 +35,9 @@ export type SamlSignIn = {
|
|
|
35
35
|
* `sendSignUpCode`); `socialProviders` the ids of the sign-in providers, for example
|
|
36
36
|
* `github`; `platformSignIn` the one of them the platform adds; `samlProviders` the app's SAML identity providers; `staffSignIn` the operator provider's name when its staff
|
|
37
37
|
* can sign in as people; `organizations` when the app has them; `anonymous` when visitors may browse what the project's
|
|
38
|
-
* anonymous role reads without signing in; `
|
|
39
|
-
* the app sets for everyone, which the screens before
|
|
38
|
+
* anonymous role reads without signing in; `mcp` when MCP clients can connect, so the account page lists them; `plugins`
|
|
39
|
+
* those the app loads before anyone signs in; `locale` the language the app sets for everyone, which the screens before
|
|
40
|
+
* `/meta` are in.
|
|
40
41
|
*/
|
|
41
42
|
export type SetupStatus = {
|
|
42
43
|
needsAdmin: boolean;
|
|
@@ -58,6 +59,7 @@ export type SetupStatus = {
|
|
|
58
59
|
roles: RoleLabel[];
|
|
59
60
|
};
|
|
60
61
|
anonymous?: boolean;
|
|
62
|
+
mcp?: boolean;
|
|
61
63
|
plugins?: PluginRef[];
|
|
62
64
|
locale?: Locale;
|
|
63
65
|
};
|
package/dist/auth.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SignInPolicy, SignInPolicyState } from "./sign-in-policy.js";
|
|
2
|
-
import { AccountSignIn, AuthenticatorSetup, Passkey } from "./account-security.js";
|
|
2
|
+
import { AccountSignIn, AuthenticatorSetup, ConnectedApp, Passkey } from "./account-security.js";
|
|
3
|
+
import { ConnectingClient } from "./connect.js";
|
|
3
4
|
import { CurrentOrganization, InvitationPreview, InvitationSent, Organization, OrganizationInvitation, OrganizationMember, OrganizationRole, OrganizationsFound } from "./organizations.js";
|
|
4
5
|
import { ActiveRole } from "./roles.js";
|
|
5
6
|
import { AuthUser, RoleLabel, SetupStatus, SignInResult, TwoFactorMethod } from "./auth-types.js";
|
|
@@ -24,7 +25,7 @@ export declare const tokenExpiry: (token: string) => number;
|
|
|
24
25
|
* The browser side of Better Auth: sign in with a password, an emailed code or a passkey (with a second step for an
|
|
25
26
|
* account with two-factor authentication), the account's passkeys and two-factor authentication (`account`), the
|
|
26
27
|
* sign-in policy for admins (`signInPolicy`), the people who can sign in for admins (`users`), staff of the operator
|
|
27
|
-
* signing in as people (`staff`), organizations (`organizations`), the role the session acts with (`roles`), and a short-lived
|
|
28
|
+
* signing in as people (`staff`), organizations (`organizations`), the role the session acts with (`roles`), allowing an outside app such as an MCP client (`connect`), and a short-lived
|
|
28
29
|
* JWT held in memory only (never in storage), fetched with the session cookie and refreshed before it expires.
|
|
29
30
|
*/
|
|
30
31
|
export declare const createAuthSession: (options?: AuthSessionOptions) => {
|
|
@@ -60,8 +61,19 @@ export declare const createAuthSession: (options?: AuthSessionOptions) => {
|
|
|
60
61
|
turnOffTwoFactor: (password?: string) => Promise<void>;
|
|
61
62
|
linkedProviders: () => Promise<string[]>;
|
|
62
63
|
linkProvider: (provider: string, callbackURL: string) => Promise<string>;
|
|
64
|
+
connectedApps: () => Promise<ConnectedApp[]>;
|
|
65
|
+
disconnectApp: (clientId: string) => Promise<void>;
|
|
63
66
|
newBackupCodes: (password?: string) => Promise<string[]>;
|
|
64
67
|
};
|
|
68
|
+
connect: {
|
|
69
|
+
client: (clientId: string) => Promise<ConnectingClient>;
|
|
70
|
+
resume: (oauthQuery: string) => Promise<{
|
|
71
|
+
url: string;
|
|
72
|
+
}>;
|
|
73
|
+
answer: (accept: boolean, oauthQuery: string) => Promise<{
|
|
74
|
+
url: string;
|
|
75
|
+
}>;
|
|
76
|
+
};
|
|
65
77
|
organizations: {
|
|
66
78
|
list: () => Promise<Organization[]>;
|
|
67
79
|
current: () => Promise<CurrentOrganization>;
|
package/dist/auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AuthError, authError } from "./auth-error.js";
|
|
2
2
|
import { accountSecurity } from "./account-security.js";
|
|
3
|
+
import { connectClient } from "./connect.js";
|
|
3
4
|
import { betterAuthClient } from "./better-auth-client.js";
|
|
4
5
|
import { organizationsClient } from "./organizations.js";
|
|
5
6
|
import { rolesClient } from "./roles.js";
|
|
@@ -21,7 +22,7 @@ const tokenExpiry = (token) => {
|
|
|
21
22
|
* The browser side of Better Auth: sign in with a password, an emailed code or a passkey (with a second step for an
|
|
22
23
|
* account with two-factor authentication), the account's passkeys and two-factor authentication (`account`), the
|
|
23
24
|
* sign-in policy for admins (`signInPolicy`), the people who can sign in for admins (`users`), staff of the operator
|
|
24
|
-
* signing in as people (`staff`), organizations (`organizations`), the role the session acts with (`roles`), and a short-lived
|
|
25
|
+
* signing in as people (`staff`), organizations (`organizations`), the role the session acts with (`roles`), allowing an outside app such as an MCP client (`connect`), and a short-lived
|
|
25
26
|
* JWT held in memory only (never in storage), fetched with the session cookie and refreshed before it expires.
|
|
26
27
|
*/
|
|
27
28
|
const createAuthSession = (options = {}) => {
|
|
@@ -83,6 +84,7 @@ const createAuthSession = (options = {}) => {
|
|
|
83
84
|
...body.passkeyDomains && { passkeyDomains: body.passkeyDomains },
|
|
84
85
|
...body.organizations && { organizations: body.organizations },
|
|
85
86
|
...body.anonymous && { anonymous: true },
|
|
87
|
+
...body.mcp && { mcp: true },
|
|
86
88
|
...body.plugins && body.plugins.length > 0 && { plugins: body.plugins },
|
|
87
89
|
...isLocale(body.locale) && { locale: body.locale }
|
|
88
90
|
};
|
|
@@ -149,6 +151,7 @@ const createAuthSession = (options = {}) => {
|
|
|
149
151
|
if (error) throw authError(error, "Could not set the password");
|
|
150
152
|
},
|
|
151
153
|
account: accountSecurity(client),
|
|
154
|
+
connect: connectClient(client),
|
|
152
155
|
organizations: organizationsClient(client, () => token({ refresh: true })),
|
|
153
156
|
roles: rolesClient(client, () => token({ refresh: true })),
|
|
154
157
|
signInPolicy: signInPolicyClient(client),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BetterAuthClient } from "./better-auth-client.js";
|
|
2
|
+
//#region src/connect.d.ts
|
|
3
|
+
/** What a client says about itself, as the server hands it to anyone: its id and the name it gave itself. */
|
|
4
|
+
export type ConnectingClient = {
|
|
5
|
+
client_id: string;
|
|
6
|
+
client_name?: string;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* The calls of the connect page, where someone allows an outside app, such as an MCP client, to act as them. Each
|
|
10
|
+
* takes the signed request the server sent the page (`oauthQuery`, its query) and resolves with where to go next, or
|
|
11
|
+
* rejects with `AuthError` carrying the code: `invalid_signature` for an expired request, `STAFF_CANNOT_CONNECT`,
|
|
12
|
+
* `SIGN_IN_SETUP_REQUIRED` or `ADDRESS_NOT_VERIFIED`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const connectClient: (client: BetterAuthClient) => {
|
|
15
|
+
/** The client asking, by its id. */
|
|
16
|
+
client: (clientId: string) => Promise<ConnectingClient>;
|
|
17
|
+
/** Picks the request up for the signed-in person: the connect page again to ask them, or the client when they allowed it before. */
|
|
18
|
+
resume: (oauthQuery: string) => Promise<{
|
|
19
|
+
url: string;
|
|
20
|
+
}>;
|
|
21
|
+
/** Allows the client (`accept`) or not: where to send the browser, the client with a code or with `access_denied`. */
|
|
22
|
+
answer: (accept: boolean, oauthQuery: string) => Promise<{
|
|
23
|
+
url: string;
|
|
24
|
+
}>;
|
|
25
|
+
};
|
|
26
|
+
export type ConnectClient = ReturnType<typeof connectClient>;
|
|
27
|
+
//#endregion
|
package/dist/connect.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { AuthError } from "./auth-error.js";
|
|
2
|
+
//#region src/connect.ts
|
|
3
|
+
const connectError = (error, fallback) => new AuthError(error?.message || error?.error_description || fallback, error?.status ?? 500, error?.code ?? error?.error);
|
|
4
|
+
/**
|
|
5
|
+
* The calls of the connect page, where someone allows an outside app, such as an MCP client, to act as them. Each
|
|
6
|
+
* takes the signed request the server sent the page (`oauthQuery`, its query) and resolves with where to go next, or
|
|
7
|
+
* rejects with `AuthError` carrying the code: `invalid_signature` for an expired request, `STAFF_CANNOT_CONNECT`,
|
|
8
|
+
* `SIGN_IN_SETUP_REQUIRED` or `ADDRESS_NOT_VERIFIED`.
|
|
9
|
+
*/
|
|
10
|
+
const connectClient = (client) => ({
|
|
11
|
+
/** The client asking, by its id. */
|
|
12
|
+
client: async (clientId) => {
|
|
13
|
+
const { data, error } = await client.$fetch("/oauth2/public-client", { query: { client_id: clientId } });
|
|
14
|
+
if (error || !data) throw connectError(error, "Could not read the app asking");
|
|
15
|
+
return data;
|
|
16
|
+
},
|
|
17
|
+
/** Picks the request up for the signed-in person: the connect page again to ask them, or the client when they allowed it before. */
|
|
18
|
+
resume: async (oauthQuery) => {
|
|
19
|
+
const { data, error } = await client.$fetch("/oauth2/continue", {
|
|
20
|
+
method: "POST",
|
|
21
|
+
body: {
|
|
22
|
+
postLogin: true,
|
|
23
|
+
oauth_query: oauthQuery
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
if (error || !data?.url) throw connectError(error, "Could not go on with the request");
|
|
27
|
+
return { url: data.url };
|
|
28
|
+
},
|
|
29
|
+
/** Allows the client (`accept`) or not: where to send the browser, the client with a code or with `access_denied`. */
|
|
30
|
+
answer: async (accept, oauthQuery) => {
|
|
31
|
+
const { data, error } = await client.$fetch("/oauth2/consent", {
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: {
|
|
34
|
+
accept,
|
|
35
|
+
oauth_query: oauthQuery
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
if (error || !data?.url) throw connectError(error, "Could not answer the request");
|
|
39
|
+
return { url: data.url };
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
//#endregion
|
|
43
|
+
export { connectClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,7 +9,8 @@ import { fileUrl } from "./file-urls.js";
|
|
|
9
9
|
import { routedClient } from "./routed-client.js";
|
|
10
10
|
import { SourceMeta, sourceMeta } from "./source-meta.js";
|
|
11
11
|
import { SignInPolicy, SignInPolicyClient, SignInPolicyState, SignInRule, StaffAccessRule } from "./sign-in-policy.js";
|
|
12
|
-
import { AccountSecurity, AccountSignIn, AuthenticatorSetup, Passkey, RequiredSetup } from "./account-security.js";
|
|
12
|
+
import { AccountSecurity, AccountSignIn, AuthenticatorSetup, ConnectedApp, Passkey, RequiredSetup } from "./account-security.js";
|
|
13
|
+
import { ConnectClient, ConnectingClient } from "./connect.js";
|
|
13
14
|
import { CurrentOrganization, InvitationPreview, InvitationSent, Organization, OrganizationInvitation, OrganizationMember, OrganizationRole, OrganizationsClient, OrganizationsFound } from "./organizations.js";
|
|
14
15
|
import { ActiveRole, RoleOption, RolesClient } from "./roles.js";
|
|
15
16
|
import { AuthUser, PlatformSignIn, RoleLabel, SamlSignIn, SetupStatus, SignInMethod, SignInResult, TwoFactorMethod } from "./auth-types.js";
|
|
@@ -20,4 +21,4 @@ import { AuthSession, AuthSessionOptions, createAuthSession, tokenExpiry } from
|
|
|
20
21
|
import { createStaticSession } from "./static-session.js";
|
|
21
22
|
import { AssistantClient, AssistantClientOptions, AssistantConnection, createAssistantClient } from "./assistant.js";
|
|
22
23
|
import { RuntimeClient, RuntimeClientOptions, RuntimeLastUpdate, RuntimePolicy, RuntimeStatus, RuntimeUpdateStage, createRuntimeClient } from "./runtime.js";
|
|
23
|
-
export { type AccountSecurity, type AccountSignIn, type ActiveRole, type Aggregate, type AggregateGroup, type AggregateParams, type AggregateSplitTotal, ApiError, type AppUser, type AssistantClient, type AssistantClientOptions, type AssistantConnection, AuthError, type AuthSession, type AuthSessionOptions, type AuthUser, type AuthenticatorSetup, type BatchOp, type BatchRef, type BatchResult, type Client, type ClientOptions, type CommentPage, type CommentPerson, type CurrentOrganization, type Facet, type FilterInput, type FormChallenge, type FormProof, type Histogram, type HistogramBucket, type HistoryChange, type HistoryPage, type InvitationPreview, type InvitationSent, type InvokeOptions, type ListPage, type ListParams, type LiveChange, type LiveHandlers, type MapBounds, type MapBucket, type MapLayerModel, type MapParams, type MapResult, type MentionableUser, type Meta, type MetaResult, type Organization, type OrganizationInvitation, type OrganizationMember, type OrganizationRole, type OrganizationsClient, type OrganizationsFound, type Passkey, type PlatformSignIn, type PluginRef, PreconditionFailedError, type ProblemDetails, type ProblemError, type PublicForm, type RecordComment, type RecordOf, type RecordPermissions, type RecordPhotos, type RelatedLabels, type RequiredSetup, type ResourcePermissions, type ResourceRef, type RoleLabel, type RoleOption, type RolesClient, type RuntimeClient, type RuntimeClientOptions, type RuntimeLastUpdate, type RuntimePolicy, type RuntimeStatus, type RuntimeUpdateStage, type SamlSignIn, type Series, type SeriesParams, type SeriesPoint, type SetupStatus, type SignInMethod, type SignInPolicy, type SignInPolicyClient, type SignInPolicyState, type SignInResult, type SignInRule, type SourceMeta, type SourceRef, type StaffAccessRule, type StaffSignIn, type StaffSignInClient, type Stored, type StoredFile, type StoredFileVariant, type TwoFactorMethod, type UploadOptions, type UploadProgress, type UploadResult, type UserInvitation, type UserInvitationSent, type UsersClient, type UsersFound, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, fileUrl, filterText, isApiError, listWire, routedClient, sourceMeta, tokenExpiry };
|
|
24
|
+
export { type AccountSecurity, type AccountSignIn, type ActiveRole, type Aggregate, type AggregateGroup, type AggregateParams, type AggregateSplitTotal, ApiError, type AppUser, type AssistantClient, type AssistantClientOptions, type AssistantConnection, AuthError, type AuthSession, type AuthSessionOptions, type AuthUser, type AuthenticatorSetup, type BatchOp, type BatchRef, type BatchResult, type Client, type ClientOptions, type CommentPage, type CommentPerson, type ConnectClient, type ConnectedApp, type ConnectingClient, type CurrentOrganization, type Facet, type FilterInput, type FormChallenge, type FormProof, type Histogram, type HistogramBucket, type HistoryChange, type HistoryPage, type InvitationPreview, type InvitationSent, type InvokeOptions, type ListPage, type ListParams, type LiveChange, type LiveHandlers, type MapBounds, type MapBucket, type MapLayerModel, type MapParams, type MapResult, type MentionableUser, type Meta, type MetaResult, type Organization, type OrganizationInvitation, type OrganizationMember, type OrganizationRole, type OrganizationsClient, type OrganizationsFound, type Passkey, type PlatformSignIn, type PluginRef, PreconditionFailedError, type ProblemDetails, type ProblemError, type PublicForm, type RecordComment, type RecordOf, type RecordPermissions, type RecordPhotos, type RelatedLabels, type RequiredSetup, type ResourcePermissions, type ResourceRef, type RoleLabel, type RoleOption, type RolesClient, type RuntimeClient, type RuntimeClientOptions, type RuntimeLastUpdate, type RuntimePolicy, type RuntimeStatus, type RuntimeUpdateStage, type SamlSignIn, type Series, type SeriesParams, type SeriesPoint, type SetupStatus, type SignInMethod, type SignInPolicy, type SignInPolicyClient, type SignInPolicyState, type SignInResult, type SignInRule, type SourceMeta, type SourceRef, type StaffAccessRule, type StaffSignIn, type StaffSignInClient, type Stored, type StoredFile, type StoredFileVariant, type TwoFactorMethod, type UploadOptions, type UploadProgress, type UploadResult, type UserInvitation, type UserInvitationSent, type UsersClient, type UsersFound, createAssistantClient, createAuthSession, createClient, createRuntimeClient, createStaticSession, fileUrl, filterText, isApiError, listWire, routedClient, sourceMeta, tokenExpiry };
|
package/dist/static-session.js
CHANGED
|
@@ -72,7 +72,14 @@ const createStaticSession = (token, user = {
|
|
|
72
72
|
turnOffTwoFactor: unsupported("turn off two-factor authentication"),
|
|
73
73
|
newBackupCodes: unsupported("make backup codes"),
|
|
74
74
|
linkedProviders: async () => [],
|
|
75
|
-
linkProvider: unsupported("link a sign-in provider")
|
|
75
|
+
linkProvider: unsupported("link a sign-in provider"),
|
|
76
|
+
connectedApps: async () => [],
|
|
77
|
+
disconnectApp: unsupported("disconnect an app")
|
|
78
|
+
},
|
|
79
|
+
connect: {
|
|
80
|
+
client: unsupported("allow an app"),
|
|
81
|
+
resume: unsupported("allow an app"),
|
|
82
|
+
answer: unsupported("allow an app")
|
|
76
83
|
},
|
|
77
84
|
signInPolicy: {
|
|
78
85
|
read: unsupported("read the sign-in policy"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "Typed fetch client for the Protobase REST API.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@better-auth/passkey": "^1.7.
|
|
33
|
-
"@protobase/layout": "0.
|
|
34
|
-
"@protobase/schema": "0.
|
|
32
|
+
"@better-auth/passkey": "^1.7.12",
|
|
33
|
+
"@protobase/layout": "0.34.1",
|
|
34
|
+
"@protobase/schema": "0.34.1",
|
|
35
35
|
"@simplewebauthn/browser": "^13.3.0",
|
|
36
|
-
"better-auth": "^1.7.
|
|
36
|
+
"better-auth": "^1.7.12"
|
|
37
37
|
}
|
|
38
38
|
}
|