@protobase/server 0.12.9 → 0.12.11

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.
@@ -2192,7 +2192,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
2192
2192
  userId: string;
2193
2193
  expiresAt: Date;
2194
2194
  token: string;
2195
- ipAddress?: string | null | undefined;
2195
+ ipAddress? /** The RP ID of new passkeys. */ : string | null | undefined;
2196
2196
  userAgent?: string | null | undefined;
2197
2197
  };
2198
2198
  user: Record<string, any> & {
@@ -1,6 +1,5 @@
1
1
  import { multiHostBaseURL, readOrigins, resolveOrigins } from "./origins.js";
2
- import { readMailSettings } from "../mail/mail-settings.js";
3
- import { smtpMailer } from "../mail/smtp-mailer.js";
2
+ import { platformMailer } from "../mail/platform-mailer.js";
4
3
  import { readOperatorSettings, resolveOperator } from "./operator-provider.js";
5
4
  import { roleDefinitions } from "./organizations/role-definitions.js";
6
5
  import { lastOrganizationField, organizationClaims, sessionOrganizationHooks } from "./organizations/session-organization.js";
@@ -27,10 +26,6 @@ const platformOperator = () => readOperatorSettings(globalThis.process?.env ?? {
27
26
  const platformSignInSettings = () => readPlatformSignIn(globalThis.process?.env ?? {});
28
27
  const platformOrigins = () => readOrigins(globalThis.process?.env ?? {});
29
28
  const platformPasskeyDomain = () => readPasskeyDomain(globalThis.process?.env ?? {});
30
- const platformMailer = () => {
31
- const settings = readMailSettings(globalThis.process?.env ?? {});
32
- return settings && smtpMailer(settings);
33
- };
34
29
  const tokenLifetime = "15m";
35
30
  const authBasePath = "/api/auth";
36
31
  /**
@@ -12,10 +12,11 @@ import { Hono } from "hono";
12
12
  * then; 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; `staffSignIn`, the
14
14
  * operator provider's name, when staff can sign in as people; `passkeyDomains`, when people have passkeys for more than
15
- * one of the app's hosts, the RP IDs a passkey sign-in can ask for, the passkey domain first; and with organizations, who may create them and the roles
16
- * with their labels, `membership` for those a member can hold, and the roles each one's holders may also give.
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
16
+ * with their labels, `membership` for those a member can hold, and the roles each one's holders may also give; and
17
+ * `anonymous` when the project has an anonymous role, so the admin app opens for visitors before anyone signs in.
17
18
  */
18
- const statusRoute = (auth) => {
19
+ const statusRoute = (auth, { anonymous = false } = {}) => {
19
20
  const app = new Hono();
20
21
  app.get("/status", async (c) => {
21
22
  const context = await auth.$context;
@@ -38,6 +39,7 @@ const statusRoute = (auth) => {
38
39
  ...platformSignIn && { platformSignIn },
39
40
  ...staffSignIn && { staffSignIn },
40
41
  ...passkeyDomains.length > 1 && { passkeyDomains },
42
+ ...anonymous && { anonymous },
41
43
  ...auth.organizations && { organizations: {
42
44
  create: auth.organizations.create,
43
45
  roles: auth.roleDefinitions.names.map((name) => ({
@@ -26,6 +26,12 @@ const valueLabelErrors = (view, model) => Object.entries(view.fields).flatMap(([
26
26
  if (field?.type !== "enum") return [`value labels of "${name}" need an enum field`];
27
27
  return Object.keys(hints.valueLabels).filter((value) => !field.enumValues?.includes(value)).map((value) => `value label "${value}" is not a value of "${name}"`);
28
28
  });
29
+ const valueColorErrors = (view, model) => Object.entries(view.fields).flatMap(([name, hints]) => {
30
+ if (!hints.valueColors) return [];
31
+ const field = model.fields[name];
32
+ if (field?.type !== "enum") return [`value colours of "${name}" need an enum field`];
33
+ return Object.keys(hints.valueColors).filter((value) => !field.enumValues?.includes(value)).map((value) => `value colour "${value}" is not a value of "${name}"`);
34
+ });
29
35
  const linkErrors = (view, model, models, pages) => view.actions.flatMap(({ name, run }) => {
30
36
  if (run?.kind !== "link") return [];
31
37
  if ("href" in run) {
@@ -50,7 +56,7 @@ const widgetErrors = (view, model, fieldTypes) => Object.entries(view.fields).fl
50
56
  });
51
57
  /**
52
58
  * Fails at startup when a view uses a sensitive field where it would show empty, a display or custom section names a
53
- * field the resource does not have, labels values its enum does not have, shows a field with a field type of
59
+ * field the resource does not have, labels or colours values its enum does not have, shows a field with a field type of
54
60
  * `fieldTypes` (each with the storage types it shows) that does not show it,
55
61
  * has a related section that does not fit the resources, or a link to an address the app does not have.
56
62
  */
@@ -65,6 +71,7 @@ const checkViews = (registry, views, pages = [], fieldTypes = {}) => {
65
71
  ...sensitiveErrors(view, model),
66
72
  ...unknownFieldErrors(view, model),
67
73
  ...valueLabelErrors(view, model),
74
+ ...valueColorErrors(view, model),
68
75
  ...widgetErrors(view, model, fieldTypes),
69
76
  ...related,
70
77
  ...linkErrors(view, model, models, pageNames)
@@ -36,6 +36,7 @@ import { createScanGuard } from "./scan-guard.js";
36
36
  import { failedJobs, failedJobsView } from "./jobs/failed-jobs.js";
37
37
  import { Hono } from "hono";
38
38
  import { checkPages } from "@protobase/layout";
39
+ import { anonymousRole } from "@protobase/schema";
39
40
  //#region src/create-admin.ts
40
41
  const declaredRoles = (auth, roles) => {
41
42
  const names = [...auth?.roles ?? [], ...Object.keys(roles?.definitions ?? {})];
@@ -126,8 +127,10 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
126
127
  }, withAnonymous(authenticate, options.roles));
127
128
  const system = guarded((app) => {
128
129
  app.route("/", docsRoutes(deps));
129
- app.route("/", metaRoutes(meta));
130
130
  });
131
+ const metaApp = guarded((app) => {
132
+ app.route("/", metaRoutes(meta));
133
+ }, withAnonymous(authenticate, options.roles));
131
134
  const app = new Hono();
132
135
  app.onError(onError);
133
136
  const corsOrigins = options.cors ?? readCorsOrigins(globalThis.process?.env ?? {});
@@ -142,7 +145,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
142
145
  }));
143
146
  }
144
147
  if (auth) {
145
- app.route(authBasePath, statusRoute(auth));
148
+ app.route(authBasePath, statusRoute(auth, { anonymous: Object.hasOwn(options.roles?.definitions ?? {}, anonymousRole) }));
146
149
  if (auth.organizations) app.route(authBasePath, organizationRoutes({
147
150
  auth,
148
151
  audit: deps.audit,
@@ -177,6 +180,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
177
180
  app.route("/", batchRoute(deps, authenticate, meta));
178
181
  app.route("/", fileRoutes(deps, authenticate));
179
182
  app.route(basePath, api);
183
+ app.route(`${deps.systemPath}/meta`, metaApp);
180
184
  app.route(deps.systemPath || "/", system);
181
185
  const webhooks = createWebhooks({
182
186
  deps,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
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
+ import { MailMessage, Mailer } from "./mail/smtp-mailer.js";
3
4
  import { OperatorProvider, readOperatorSettings } from "./better-auth/operator-provider.js";
4
5
  import { RoleDefinition, RolesInput } from "./better-auth/organizations/role-definitions.js";
5
6
  import { OrganizationRole, StoredMember, StoredOrganization } from "./better-auth/organizations/store.js";
@@ -74,4 +75,4 @@ import { FatalJobError } from "./jobs/run-job.js";
74
75
  import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/runtime.js";
75
76
  import { jobsDrainApp } from "./jobs/drain-route.js";
76
77
  import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
77
- export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticatorOptions, type CapturedRow, type ChatMessage, type ChatTextPart, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DrainResult, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FileCleanupInput, type FileObject, type FileProvider, type FileStore, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSource, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type LinkedAccount, type ListParams, type LocalFilesOptions, type MemberInput, MissingCredentials, ModelError, type ModelSettings, type NewOrganization, type NewUser, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type ProjectConfig, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RecordKeyInput, type RecordPage, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type SignInPolicy, type SignInRule, type SignatureOptions, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoredMember, type StoredObject, type StoredOrganization, type StoredUser, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type User, type UserCreatedHook, type ViewSource, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkSourceNames, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, functionApp, hasUsers, imageSize, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, listOrganizations, listUsers, localFileStore, localFiles, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, streamChatCompletion, subscription, unauthorized, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
78
+ export { type Admin, type AdminAuth, type AdminOptions, type ApiFunction, type ApprovalAnswer, type ApprovalRequest, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type Authenticator, type BetterAuthAuthenticatorOptions, type CapturedRow, type ChatMessage, type ChatTextPart, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type Completion, type CompletionOptions, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DrainResult, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FileCleanupInput, type FileObject, type FileProvider, type FileStore, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSource, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MemberInput, MissingCredentials, ModelError, type ModelSettings, type NewOrganization, type NewUser, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type ProjectConfig, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type QueryOptions, type QueryResult, type ReasoningDetail, type ReasoningEffort, type RecordKeyInput, type RecordPage, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type SignInPolicy, type SignInRule, type SignatureOptions, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoredMember, type StoredObject, type StoredOrganization, type StoredUser, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolCall, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type User, type UserCreatedHook, type ViewSource, type WebhooksOptions, type WidgetOptions, type WriteEvent, type WriteOperation, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkSourceNames, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, functionApp, hasUsers, imageSize, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, listOrganizations, listUsers, localFileStore, localFiles, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, streamChatCompletion, subscription, unauthorized, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
@@ -1,3 +1,4 @@
1
+ import { Mailer } from "../mail/smtp-mailer.js";
1
2
  import { StandardSchema } from "../functions/read-json.js";
2
3
  import { Db } from "@protobase/query";
3
4
  //#region src/jobs/job-types.d.ts
@@ -13,6 +14,8 @@ export type JobContext = {
13
14
  };
14
15
  /** Aborted when the job's timeout passes, or when the worker shuts down and its grace period ends. */
15
16
  signal: AbortSignal;
17
+ /** Sends plain-text mail through the app's SMTP server (`PROTOBASE_SMTP_URL`, `PROTOBASE_MAIL_FROM`); `undefined` when the app has no mail. */
18
+ mail?: Mailer;
16
19
  };
17
20
  export type JobOptions<Payload> = {
18
21
  /** Letters, digits, `_`, `-`, `.` and `/`; the job's queue in the `jobs` schema. */
@@ -48,7 +48,7 @@ const errorOutput = (error) => error instanceof Error ? {
48
48
  * One try of one job: completed when `run` returns, failed (to be retried while attempts are left) when it throws, and
49
49
  * failed for good on a `FatalJobError` or an invalid payload.
50
50
  */
51
- const runJob = async (definition, job, db) => {
51
+ const runJob = async (definition, job, db, mail) => {
52
52
  try {
53
53
  const payload = await checkPayload(definition, job.data ?? void 0);
54
54
  const context = {
@@ -59,7 +59,8 @@ const runJob = async (definition, job, db) => {
59
59
  attempt: job.retryCount + 1,
60
60
  maxAttempts: job.retryLimit + 1
61
61
  },
62
- signal: job.signal
62
+ signal: job.signal,
63
+ ...mail && { mail }
63
64
  };
64
65
  await throughWriteFreeze(() => definition.options.run(payload, context), job.signal);
65
66
  return {
@@ -1,3 +1,4 @@
1
+ import { Mailer } from "../mail/smtp-mailer.js";
1
2
  import { JobDefinition } from "./job-types.js";
2
3
  import { JobsEnqueuer } from "./current.js";
3
4
  import { Db } from "@protobase/query";
@@ -15,6 +16,11 @@ export type StartJobsOptions = {
15
16
  onError: (error: unknown) => void;
16
17
  /** The time recurring jobs are scheduled from; tests pass their own. */
17
18
  now?: () => Date;
19
+ /**
20
+ * What jobs send mail with (`context.mail`): by default the platform's SMTP server from `PROTOBASE_SMTP_URL` and
21
+ * `PROTOBASE_MAIL_FROM`, when set; `false` turns mail off whatever the environment says.
22
+ */
23
+ mailer?: Mailer | false;
18
24
  };
19
25
  /** What a drain left: whether no job is due or running any more, how many are, and when the next one is due. */
20
26
  export type DrainResult = {
@@ -42,5 +48,5 @@ export type JobsRuntime = JobsEnqueuer & {
42
48
  * that retries jobs whose worker died. It reads the jobs schema, never changes it: check it first with
43
49
  * `checkJobsSchema`. Enqueueing through `defineJob(...).enqueue` reaches the runtime started here.
44
50
  */
45
- export declare const startJobs: ({ db, jobs, work, pollSeconds, shutdownSeconds, onError, now }: StartJobsOptions) => Promise<JobsRuntime>;
51
+ export declare const startJobs: ({ db, jobs, work, pollSeconds, shutdownSeconds, onError, now, mailer }: StartJobsOptions) => Promise<JobsRuntime>;
46
52
  //#endregion
@@ -1,5 +1,6 @@
1
1
  import { clearCurrentJobs, setCurrentJobs } from "./current.js";
2
2
  import { jobsSchema } from "./schema.js";
3
+ import { platformMailer } from "../mail/platform-mailer.js";
3
4
  import "./schedule.js";
4
5
  import { runJob, validatePayload } from "./run-job.js";
5
6
  import { jobsDatabase } from "./database.js";
@@ -25,7 +26,8 @@ const createBoss = (db, work) => new PgBoss({
25
26
  * that retries jobs whose worker died. It reads the jobs schema, never changes it: check it first with
26
27
  * `checkJobsSchema`. Enqueueing through `defineJob(...).enqueue` reaches the runtime started here.
27
28
  */
28
- const startJobs = async ({ db, jobs, work = true, pollSeconds = 2, shutdownSeconds = 30, onError, now = () => /* @__PURE__ */ new Date() }) => {
29
+ const startJobs = async ({ db, jobs, work = true, pollSeconds = 2, shutdownSeconds = 30, onError, now = () => /* @__PURE__ */ new Date(), mailer }) => {
30
+ const mail = mailer === void 0 ? platformMailer() : mailer || void 0;
29
31
  const boss = createBoss(db, work);
30
32
  boss.on("error", onError);
31
33
  await boss.start();
@@ -56,7 +58,7 @@ const startJobs = async ({ db, jobs, work = true, pollSeconds = 2, shutdownSecon
56
58
  }, async ([job]) => {
57
59
  const current = definitions.get(definition.name) ?? definition;
58
60
  if (current.options.schedule !== void 0 && job.singletonKey === "protobase.schedule") await schedules.following(current, job.startAfter);
59
- return [await runJob(current, job, db)];
61
+ return [await runJob(current, job, db, mail)];
60
62
  });
61
63
  workers.set(definition.name, {
62
64
  id,
@@ -0,0 +1,10 @@
1
+ import { readMailSettings } from "./mail-settings.js";
2
+ import { smtpMailer } from "./smtp-mailer.js";
3
+ //#region src/mail/platform-mailer.ts
4
+ /** The platform's SMTP server and sender from `PROTOBASE_SMTP_URL` and `PROTOBASE_MAIL_FROM`; `undefined` when mail is off. */
5
+ const platformMailer = (env = globalThis.process?.env ?? {}) => {
6
+ const settings = readMailSettings(env);
7
+ return settings && smtpMailer(settings);
8
+ };
9
+ //#endregion
10
+ export { platformMailer };
@@ -3,7 +3,7 @@ import { Hono } from "hono";
3
3
  //#region src/routes/meta.ts
4
4
  const metaRoutes = (meta) => {
5
5
  const app = new Hono();
6
- app.get("/meta", async (c) => {
6
+ app.get("/", async (c) => {
7
7
  const { body, etag } = await meta.forCaller(c.get("session"));
8
8
  const headers = {
9
9
  ETag: etag,
@@ -30,10 +30,12 @@ const listShape = shapes.object({
30
30
  name: shapes.data,
31
31
  label: shapes.data,
32
32
  icon: shapes.data,
33
+ image: shapes.field,
33
34
  title: shapes.field,
34
35
  subtitle: shapes.field,
35
36
  badge: shapes.field,
36
37
  meta: shapes.list(shapes.field),
38
+ flags: shapes.list(shapes.field),
37
39
  card: shapes.data
38
40
  }),
39
41
  custom: shapes.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.12.9",
3
+ "version": "0.12.11",
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.12.9",
34
- "@protobase/query": "0.12.9",
35
- "@protobase/schema": "0.12.9",
33
+ "@protobase/layout": "0.12.11",
34
+ "@protobase/query": "0.12.11",
35
+ "@protobase/schema": "0.12.11",
36
36
  "@scalar/hono-api-reference": "^0.12.10",
37
37
  "@sentry/core": "^11.7.0",
38
38
  "@simplewebauthn/server": "^13.3.1",