@protobase/server 0.5.0 → 0.7.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.
@@ -9,7 +9,7 @@ import { deleteSessionCookie } from "better-auth/cookies";
9
9
  * Staff of the operator sign in as a person of this app, for support (see `staffSignInEndpoints`). A staff session
10
10
  * shows who started it and why, can be stopped, and cannot change the person's sign-in or the sign-in policy. Every
11
11
  * staff sign-in is logged for the app's admins. The plugin is there without an operator provider too, so its table
12
- * exists from the first `auth:migrate`.
12
+ * exists from the first auth migration.
13
13
  */
14
14
  const staffSignInPlugin = ({ operator, mailer }) => ({
15
15
  id: "protobase-staff-sign-in",
@@ -7,24 +7,30 @@ import { Hono } from "hono";
7
7
  * `GET {authBase}/status`: `needsAdmin` while the admin store has no user, so a login page can say how to create one;
8
8
  * `signInMethods`, the ways to sign in the sign-in policy leaves on (`password`, `emailCode`, `passkey`), so it offers
9
9
  * only those; `passwordReset` when reset mail can be sent and passwords are on, so it offers "Forgot password?" only
10
- * then; the ids of the configured `socialProviders`, so it offers "Continue with GitHub" when `github` is one; and
11
- * `staffSignIn`, the operator provider's name, when staff can sign in as people.
10
+ * then; the ids of the `socialProviders` people can sign in with, so it offers "Continue with GitHub" when `github` is
11
+ * one; `platformSignIn`, the id and name of the platform's provider when it is one of them; and `staffSignIn`, the
12
+ * operator provider's name, when staff can sign in as people.
12
13
  */
13
14
  const statusRoute = (auth) => {
14
15
  const app = new Hono();
15
16
  app.get("/status", async (c) => {
16
- const policy = effectiveSignInPolicy((await readSignInPolicy((await auth.$context).adapter)).policy, { mail: auth.mail });
17
+ const context = await auth.$context;
18
+ const policy = effectiveSignInPolicy((await readSignInPolicy(context.adapter)).policy, { mail: auth.mail });
17
19
  const signInMethods = [
18
20
  ...policy.password === "allowed" ? ["password"] : [],
19
21
  ...policy.emailCode === "allowed" ? ["emailCode"] : [],
20
22
  ...policy.passkey !== "forbidden" ? ["passkey"] : []
21
23
  ];
22
24
  const staffSignIn = auth.operator && policy.staffAccess !== "forbidden" ? auth.operator : void 0;
25
+ const platform = auth.platformSignIn;
26
+ const platformSignIn = platform && policy.platformSignIn === "allowed" && context.socialProviders.some((provider) => provider.id === platform.provider) ? platform : void 0;
27
+ const socialProviders = [...auth.socialProviders, ...platformSignIn ? [platformSignIn.provider] : []];
23
28
  return c.json({
24
29
  needsAdmin: !await hasUsers(auth),
25
30
  signInMethods,
26
31
  passwordReset: auth.passwordReset && policy.password === "allowed",
27
- socialProviders: auth.socialProviders,
32
+ socialProviders,
33
+ ...platformSignIn && { platformSignIn },
28
34
  ...staffSignIn && { staffSignIn }
29
35
  });
30
36
  });
@@ -3,11 +3,17 @@ import { parseRoles } from "./parse-roles.js";
3
3
  //#region src/better-auth/users.d.ts
4
4
  /** The roles this auth instance allows, `admin` first. */
5
5
  export declare const roleChoices: (auth: AdminAuth) => string[];
6
+ /** An account at a sign-in provider, as Better Auth keys it: `{ providerId: 'github', accountId: '<GitHub user id>' }`. */
7
+ export type LinkedAccount = {
8
+ providerId: string;
9
+ accountId: string;
10
+ };
6
11
  export type NewUser = {
7
12
  email: string;
8
13
  password: string;
9
14
  name?: string;
10
15
  role?: string;
16
+ accounts?: LinkedAccount[];
11
17
  };
12
18
  export type StoredUser = {
13
19
  id: string;
@@ -21,7 +27,8 @@ export declare const hasUsers: (auth: AdminAuth) => Promise<boolean>;
21
27
  /**
22
28
  * Creates a user directly in the admin store. Host side only (no HTTP route creates accounts while the store is empty):
23
29
  * the first user is always an `admin`, later ones get `role` (default `user`). The address counts as verified, so the
24
- * user can also sign in with an emailed code.
30
+ * user can also sign in with an emailed code. `accounts` link the user to sign-in providers up front, so a provider
31
+ * signs them in by its own id whatever address it reports; one that signs in another user already is refused.
25
32
  */
26
33
  export declare const createUser: (auth: AdminAuth, input: NewUser) => Promise<{
27
34
  id: string;
@@ -10,22 +10,37 @@ const checkRoles = (auth, role) => {
10
10
  };
11
11
  /** Whether the admin store has any user yet. */
12
12
  const hasUsers = async (auth) => (await auth.$context).adapter.count({ model: "user" }).then((count) => count > 0);
13
+ const checkAccounts = async (auth, accounts) => {
14
+ const { internalAdapter } = await auth.$context;
15
+ for (const account of accounts) {
16
+ if (!account.providerId || !account.accountId || account.providerId === "credential") throw new Error(`Cannot link an account "${account.providerId}:${account.accountId}"`);
17
+ if (await internalAdapter.findAccountByKey(account)) throw new Error(`The ${account.providerId} account ${account.accountId} signs in another user already`);
18
+ }
19
+ };
13
20
  /**
14
21
  * Creates a user directly in the admin store. Host side only (no HTTP route creates accounts while the store is empty):
15
22
  * the first user is always an `admin`, later ones get `role` (default `user`). The address counts as verified, so the
16
- * user can also sign in with an emailed code.
23
+ * user can also sign in with an emailed code. `accounts` link the user to sign-in providers up front, so a provider
24
+ * signs them in by its own id whatever address it reports; one that signs in another user already is refused.
17
25
  */
18
26
  const createUser = async (auth, input) => {
19
27
  const first = !await hasUsers(auth);
20
28
  const requested = input.role ?? auth.defaultRole;
21
29
  if (!first && requested === void 0) throw new Error(`A role is required: choose one of ${auth.roles.join(", ")}`);
22
30
  const role = first ? "admin" : checkRoles(auth, requested).join(",");
31
+ const accounts = input.accounts ?? [];
32
+ await checkAccounts(auth, accounts);
23
33
  const { user } = await auth.api.createUser({ body: {
24
34
  email: input.email,
25
35
  password: input.password,
26
36
  name: input.name ?? input.email.split("@")[0],
27
37
  role
28
38
  } });
39
+ const { internalAdapter } = await auth.$context;
40
+ for (const account of accounts) await internalAdapter.linkAccount({
41
+ userId: user.id,
42
+ ...account
43
+ });
29
44
  return {
30
45
  id: user.id,
31
46
  email: user.email,
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { SignInPolicy, SignInRule, StaffAccessRule, defaultSignInPolicy, signInPolicyMethods } from "./better-auth/sign-in-policy.js";
2
2
  import { StaffSignIn } from "./better-auth/staff-log.js";
3
3
  import { OperatorProvider, readOperatorSettings } from "./better-auth/operator-provider.js";
4
+ import { PlatformSignIn, readPlatformSignIn } from "./better-auth/platform-sign-in.js";
4
5
  import { AdminAuth, CreateAuthOptions, UserCreatedHook, createAuth, normalizeRoles } from "./better-auth/create-auth.js";
5
6
  import { ResourceSource, configExports } from "./resource-source.js";
6
7
  import { ChatMessage, ChatTextPart, Completion, CompletionOptions, ModelError, ModelSettings, ReasoningDetail, ReasoningEffort, ToolCall, ToolSpec, streamChatCompletion } from "./assistant/chat-completions.js";
@@ -20,8 +21,9 @@ import { JwtOptions, jwtAuthenticator } from "./auth/jwt.js";
20
21
  import { HttpProblem, badRequest, forbidden, notFound, unauthorized } from "./problem.js";
21
22
  import { BetterAuthAuthenticatorOptions, betterAuthAuthenticator } from "./better-auth/authenticator.js";
22
23
  import { parseRoles } from "./better-auth/parse-roles.js";
23
- import { NewUser, StoredUser, createUser, deleteUser, hasUsers, listUsers, roleChoices, setUserBanned, setUserRole } from "./better-auth/users.js";
24
+ import { LinkedAccount, NewUser, StoredUser, createUser, deleteUser, hasUsers, listUsers, roleChoices, setUserBanned, setUserRole } from "./better-auth/users.js";
24
25
  import { IssueTokenOptions, issueToken, maxTokenTtlSeconds } from "./better-auth/tokens.js";
26
+ import { authSchemaMigration, checkAuthSchema } from "./better-auth/auth-schema.js";
25
27
  import { AssistantBackend, assistantProtocolRoutes } from "./assistant/protocol-routes.js";
26
28
  import { fileConversationStore } from "./assistant/file-conversation-store.js";
27
29
  import { withCacheBreakpoints } from "./assistant/cache-breakpoints.js";
@@ -29,4 +31,4 @@ import { TurnOptions, runTurn } from "./assistant/turn.js";
29
31
  import { WidgetOptions, maxWidgetPropsBytes, widget } from "./assistant/widget.js";
30
32
  import { QueryOptions, QueryResult, runReadOnlyQuery, runReadWriteQuery } from "./assistant/run-query.js";
31
33
  import { readOnlyQueryTool, readWriteQueryTool } from "./assistant/query-tools.js";
32
- export { type Admin, type AdminAuth, type AdminOptions, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticatorOptions, type ChatMessage, type ChatTextPart, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CreateAdminInput, type CreateAuthOptions, HttpProblem, type IssueTokenOptions, type JwtOptions, ModelError, type ModelSettings, type NewUser, type OperatorProvider, type PipelineHook, type ProjectConfig, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RecordKeyInput, type ResourceSource, type RuntimeOptions, type ScanGuardMode, type Session, type SignInPolicy, type SignInRule, type StaffAccessRule, type StaffSignIn, type StoredUser, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TurnOptions, type User, type UserCreatedHook, type ViewSource, type WidgetOptions, type WriteEvent, type WriteOperation, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, badRequest, betterAuthAuthenticator, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createUser, defaultSignInPolicy, defineConfig, defineTool, deleteUser, fileConversationStore, forbidden, hasUsers, issueToken, jwtAuthenticator, listUsers, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, normalizeRoles, notFound, parseRoles, readOnlyQueryTool, readOperatorSettings, readWriteQueryTool, requestApproval, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setUserBanned, setUserRole, signInPolicyMethods, streamChatCompletion, unauthorized, widget, withCacheBreakpoints };
34
+ export { type Admin, type AdminAuth, type AdminOptions, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticatorOptions, type ChatMessage, type ChatTextPart, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CreateAdminInput, type CreateAuthOptions, HttpProblem, type IssueTokenOptions, type JwtOptions, type LinkedAccount, ModelError, type ModelSettings, type NewUser, type OperatorProvider, type PipelineHook, type PlatformSignIn, type ProjectConfig, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RecordKeyInput, type ResourceSource, type RuntimeOptions, type ScanGuardMode, type Session, type SignInPolicy, type SignInRule, type StaffAccessRule, type StaffSignIn, type StoredUser, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TurnOptions, type User, type UserCreatedHook, type ViewSource, type WidgetOptions, type WriteEvent, type WriteOperation, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, checkAuthSchema, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createUser, defaultSignInPolicy, defineConfig, defineTool, deleteUser, fileConversationStore, forbidden, hasUsers, issueToken, jwtAuthenticator, listUsers, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, normalizeRoles, notFound, parseRoles, readOnlyQueryTool, readOperatorSettings, readPlatformSignIn, readWriteQueryTool, requestApproval, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setUserBanned, setUserRole, signInPolicyMethods, streamChatCompletion, unauthorized, widget, withCacheBreakpoints };
package/dist/index.js CHANGED
@@ -12,6 +12,7 @@ import { ModelError, streamChatCompletion } from "./assistant/chat-completions.j
12
12
  import { runTurn } from "./assistant/turn.js";
13
13
  import { consoleAuditQueue } from "./audit/console-queue.js";
14
14
  import { readOperatorSettings } from "./better-auth/operator-provider.js";
15
+ import { readPlatformSignIn } from "./better-auth/platform-sign-in.js";
15
16
  import { defaultSignInPolicy, signInPolicyMethods } from "./better-auth/sign-in-policy.js";
16
17
  import { parseRoles } from "./better-auth/parse-roles.js";
17
18
  import { createAuth, normalizeRoles } from "./better-auth/create-auth.js";
@@ -23,5 +24,6 @@ import { defineConfig, mergeConfig } from "./project-config.js";
23
24
  import { jwtAuthenticator } from "./auth/jwt.js";
24
25
  import { betterAuthAuthenticator } from "./better-auth/authenticator.js";
25
26
  import { issueToken, maxTokenTtlSeconds } from "./better-auth/tokens.js";
27
+ import { authSchemaMigration, checkAuthSchema } from "./better-auth/auth-schema.js";
26
28
  import { maxWidgetPropsBytes, widget } from "./assistant/widget.js";
27
- export { HttpProblem, ModelError, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, badRequest, betterAuthAuthenticator, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createUser, defaultSignInPolicy, defineConfig, defineTool, deleteUser, fileConversationStore, forbidden, hasUsers, issueToken, jwtAuthenticator, listUsers, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, normalizeRoles, notFound, parseRoles, readOnlyQueryTool, readOperatorSettings, readWriteQueryTool, requestApproval, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setUserBanned, setUserRole, signInPolicyMethods, streamChatCompletion, unauthorized, widget, withCacheBreakpoints };
29
+ export { HttpProblem, ModelError, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, checkAuthSchema, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createUser, defaultSignInPolicy, defineConfig, defineTool, deleteUser, fileConversationStore, forbidden, hasUsers, issueToken, jwtAuthenticator, listUsers, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, normalizeRoles, notFound, parseRoles, readOnlyQueryTool, readOperatorSettings, readPlatformSignIn, readWriteQueryTool, requestApproval, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setUserBanned, setUserRole, signInPolicyMethods, streamChatCompletion, unauthorized, widget, withCacheBreakpoints };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.5.0",
3
+ "version": "0.7.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": {
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@better-auth/passkey": "^1.7.7",
33
- "@protobase/layout": "0.5.0",
34
- "@protobase/query": "0.5.0",
35
- "@protobase/schema": "0.5.0",
33
+ "@protobase/layout": "0.7.0",
34
+ "@protobase/query": "0.7.0",
35
+ "@protobase/schema": "0.7.0",
36
36
  "@scalar/hono-api-reference": "^0.12.10",
37
37
  "@simplewebauthn/server": "^13.3.1",
38
38
  "better-auth": "^1.7.7",