@protobase/server 0.21.3 → 0.21.5

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/app-name.js CHANGED
@@ -1,9 +1,11 @@
1
1
  //#region src/app-name.ts
2
2
  const appNameVariable = "PROTOBASE_APP_NAME";
3
+ /** The app's name when neither the app nor the platform names it. */
4
+ const defaultAppName = "Protobase";
3
5
  /**
4
6
  * The app's name the platform passes in `PROTOBASE_APP_NAME`, such as `Property Finder`; `undefined` when it is not
5
7
  * set. Protobase names the app with it in sign-in prompts and in the mail it sends, unless the app names itself.
6
8
  */
7
9
  const readAppName = (env) => env["PROTOBASE_APP_NAME"]?.trim() || void 0;
8
10
  //#endregion
9
- export { appNameVariable, readAppName };
11
+ export { appNameVariable, defaultAppName, readAppName };
@@ -800,7 +800,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
800
800
  expiresAt: Date;
801
801
  token: string;
802
802
  ipAddress?: string | null | undefined;
803
- userAgent?: string | null | undefined;
803
+ userAgent? /** Open sign-up is on and offered: the app asks for it, and can mail the codes. */ : string | null | undefined;
804
804
  };
805
805
  };
806
806
  }>>[];
@@ -3749,15 +3749,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
3749
3749
  name?: string;
3750
3750
  slug?: string;
3751
3751
  logo?: string | null;
3752
- metadata?
3753
- /**
3754
- * The options `createAuth` gives Better Auth, with the roles, default role, mailer, operator provider and platform
3755
- * sign-in provider already resolved.
3756
- */
3757
- /**
3758
- * The options `createAuth` gives Better Auth, with the roles, default role, mailer, operator provider and platform
3759
- * sign-in provider already resolved.
3760
- */ : Record<string, any>;
3752
+ metadata?: Record<string, any>;
3761
3753
  [key: string]: any;
3762
3754
  };
3763
3755
  }>;
@@ -4240,7 +4232,7 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
4240
4232
  hooks: {
4241
4233
  after: {
4242
4234
  matcher: (context: {
4243
- path?: string;
4235
+ path? /** Sign-in attempts allowed per minute and client, default 5; also the sign-up requests allowed. */ : string;
4244
4236
  }) => boolean;
4245
4237
  handler: import("better-auth").Middleware<import("better-auth").MiddlewareOptions, (inputContext: import("better-auth").MiddlewareInputContext<import("better-auth").MiddlewareOptions>) => Promise<void>>;
4246
4238
  }[];
@@ -4374,6 +4366,8 @@ export declare const createAuth: (options: CreateAuthOptions) => import("better-
4374
4366
  /** Open sign-up is on and offered: the app asks for it, and can mail the codes. */
4375
4367
  signUp: boolean;
4376
4368
  socialProviders: string[];
4369
+ /** The app's name it signs in and mails as: `appName`, else `PROTOBASE_APP_NAME`, else `Protobase`. */
4370
+ appName: string;
4377
4371
  operator: string | undefined;
4378
4372
  platformSignIn: {
4379
4373
  provider: string;
@@ -1,5 +1,5 @@
1
1
  import { multiHostBaseURL, readOrigins, resolveOrigins } from "./origins.js";
2
- import { readAppName } from "../app-name.js";
2
+ import { defaultAppName, readAppName } from "../app-name.js";
3
3
  import { platformMailer } from "../mail/platform-mailer.js";
4
4
  import { readOperatorSettings, resolveOperator } from "./operator-provider.js";
5
5
  import { roleDefinitions } from "./organizations/role-definitions.js";
@@ -29,7 +29,6 @@ const platformSignInSettings = () => readPlatformSignIn(globalThis.process?.env
29
29
  const platformOrigins = () => readOrigins(globalThis.process?.env ?? {});
30
30
  const platformPasskeyDomain = () => readPasskeyDomain(globalThis.process?.env ?? {});
31
31
  const platformAppName = () => readAppName(globalThis.process?.env ?? {});
32
- const defaultAppName = "Protobase";
33
32
  const tokenLifetime = "15m";
34
33
  const authBasePath = "/api/auth";
35
34
  /**
@@ -277,6 +276,8 @@ const createAuth = (options) => {
277
276
  /** Open sign-up is on and offered: the app asks for it, and can mail the codes. */
278
277
  signUp: Boolean(signUpRole && mailer),
279
278
  socialProviders,
279
+ /** The app's name it signs in and mails as: `appName`, else `PROTOBASE_APP_NAME`, else `Protobase`. */
280
+ appName: appName ?? "Protobase",
280
281
  operator: operator?.name,
281
282
  platformSignIn: platformSignIn && {
282
283
  provider: platformSignIn.provider,
@@ -0,0 +1,38 @@
1
+ import { HttpProblem } from "./problem.js";
2
+ import { requestAccess } from "./request-access.js";
3
+ //#region src/blocked-delete.ts
4
+ /**
5
+ * The resource whose rows kept `deleted`'s record from being deleted, from the table a foreign key violation names, and
6
+ * its relation field pointing at `deleted` when there is exactly one, on a single column, so its list can be filtered by
7
+ * it. `undefined` when no resource or several read that table, or none of its fields points at `deleted`, as when a
8
+ * cascade was blocked further down.
9
+ */
10
+ const blockingRelation = (error, deleted, entries) => {
11
+ const tables = entries.filter(({ model }) => model.table.name === error.table && (model.table.schema === void 0 || model.table.schema === error.schema));
12
+ if (tables.length !== 1) return void 0;
13
+ const entry = tables[0];
14
+ const pointing = Object.entries(entry.model.fields).filter(([, field]) => field.type === "relation" && field.relation?.resource === deleted.name);
15
+ if (pointing.length === 0) return void 0;
16
+ const only = pointing.length === 1 ? pointing[0] : void 0;
17
+ return only && only[1].relation.columns.length === 1 ? {
18
+ entry,
19
+ field: only[0]
20
+ } : { entry };
21
+ };
22
+ /**
23
+ * The 409 for a delete other records still point at. It names their resource (`blockedBy`) only to a caller who may
24
+ * list it, and the field pointing at the record only when they may filter by it, as with any field they cannot see.
25
+ */
26
+ const blockedDelete = async (deps, access, error) => {
27
+ const match = blockingRelation(error, access.entry, deps.registry.entries);
28
+ const blocking = match && await requestAccess(deps, match.entry, access.session);
29
+ const listed = blocking && blocking.resolved.operations.list;
30
+ const field = listed && match.field && blocking.model.fields[match.field]?.filterable ? match.field : void 0;
31
+ const blockedBy = listed ? {
32
+ resource: match.entry.name,
33
+ ...field && { field }
34
+ } : void 0;
35
+ return new HttpProblem(409, "conflict", "Conflict", "Other records still point at this record", blockedBy && { blockedBy });
36
+ };
37
+ //#endregion
38
+ export { blockedDelete, blockingRelation };
@@ -6,6 +6,7 @@ import { builtInAssistant } from "./assistant/built-in-assistant.js";
6
6
  import { consoleAuditQueue } from "./audit/console-queue.js";
7
7
  import { webauthnPath } from "./better-auth/origins.js";
8
8
  import { apiCors, readCorsOrigins } from "./api-cors.js";
9
+ import { readAppName } from "./app-name.js";
9
10
  import { authBasePath } from "./better-auth/create-auth.js";
10
11
  import { organizationRoutes } from "./better-auth/organizations/admin-routes.js";
11
12
  import { statusRoute } from "./better-auth/status-route.js";
@@ -131,7 +132,7 @@ const createAdmin = ({ resources: appResources, views: appViews = [], pages = []
131
132
  ...auth && { actorNames: betterAuthActorNames(auth) }
132
133
  } }
133
134
  };
134
- const meta = createMeta(deps);
135
+ const meta = createMeta(deps, auth?.appName ?? readAppName(globalThis.process?.env ?? {}) ?? "Protobase");
135
136
  const onError = createErrorHandler(options.onUnhandledError);
136
137
  const guarded = (routes, caller = authenticate) => {
137
138
  const app = new Hono();
@@ -0,0 +1,9 @@
1
+ //#region src/dropped-connections.d.ts
2
+ type ErrorEmitter = {
3
+ on(event: 'error', listener: (error: Error) => void): unknown;
4
+ };
5
+ type Pool = ErrorEmitter & {
6
+ on(event: 'connect', listener: (client: ErrorEmitter) => void): unknown;
7
+ };
8
+ export declare const handleDroppedConnections: <P extends Pool>(pool: P) => P;
9
+ //#endregion
@@ -0,0 +1,8 @@
1
+ //#region src/dropped-connections.ts
2
+ const handleDroppedConnections = (pool) => {
3
+ pool.on("connect", (client) => client.on("error", (error) => console.error(`Lost a database connection: ${error.message}`)));
4
+ pool.on("error", () => {});
5
+ return pool;
6
+ };
7
+ //#endregion
8
+ export { handleDroppedConnections };
@@ -41,4 +41,4 @@ const createErrorHandler = (onUnhandledError) => (error, c) => {
41
41
  return problemResponse(new HttpProblem(500, "internal-error", titles[500], "The server failed to handle the request"), c.req.path);
42
42
  };
43
43
  //#endregion
44
- export { createErrorHandler, problemOf };
44
+ export { createErrorHandler, isDatabaseError, problemOf };
package/dist/index.d.ts CHANGED
@@ -39,6 +39,7 @@ import { AssistantOptions, AssistantSettings, assistantRoles, assistantSettings,
39
39
  import { RuntimeOptions, runtimeUrl, runtimeVariable, seesRuntime } from "./runtime/runtime-settings.js";
40
40
  import { AdminOptions } from "./admin-options.js";
41
41
  import { CreateAdminInput, createAdmin } from "./create-admin.js";
42
+ import { handleDroppedConnections } from "./dropped-connections.js";
42
43
  import { checkViewQueries } from "./check-view-queries.js";
43
44
  import { ProjectConfig, defineConfig, mergeConfig } from "./project-config.js";
44
45
  import { consoleAuditQueue } from "./audit/console-queue.js";
@@ -86,4 +87,4 @@ import { FatalJobError } from "./jobs/run-job.js";
86
87
  import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/runtime.js";
87
88
  import { jobsDrainApp } from "./jobs/drain-route.js";
88
89
  import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
89
- 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 EmailComponent, type EmailOptions, type EmailTemplate, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSource, type HistoryOptions, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, 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 RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, 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, beforeSignInPluginsVariable, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, hasUsers, imageSize, isCaptured, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, limitedFileStore, listOrganizations, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storeFile, streamChatCompletion, subscription, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
90
+ 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 EmailComponent, type EmailOptions, type EmailTemplate, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSource, type HistoryOptions, HttpProblem, type IssueTokenOptions, type JobContext, type JobDefinition, type JobOptions, type JobsRuntime, type JwtOptions, type LinkedAccount, type ListParams, type LocalFilesOptions, type MailMessage, type Mailer, type MapLayer, type MapOptions, type MapSettings, 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 RenderedEmail, type ResourceChange, type ResourceSource, type RoleDefinition, type RolesInput, type RunContext, type RuntimeOptions, type S3Bucket, type S3FilesOptions, type S3ListPage, type S3Object, type ScanGuardMode, type ScheduledDelete, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StoreFileInput, 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, beforeSignInPluginsVariable, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, handleDroppedConnections, hasUsers, imageSize, isCaptured, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, limitedFileStore, listOrganizations, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storeFile, streamChatCompletion, subscription, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ import { runtimeUrl, runtimeVariable, seesRuntime } from "./runtime/runtime-sett
42
42
  import { checkSourceNames, sourceOptions, sourcesFor, sourcesVariable } from "./sources/source-settings.js";
43
43
  import { renderVariant, thumbHash } from "./files/images.js";
44
44
  import { createAdmin } from "./create-admin.js";
45
+ import { handleDroppedConnections } from "./dropped-connections.js";
45
46
  import { configExports } from "./resource-source.js";
46
47
  import { checkViewQueries } from "./check-view-queries.js";
47
48
  import { defineConfig, mergeConfig } from "./project-config.js";
@@ -65,4 +66,4 @@ import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/p
65
66
  import { defineEmail } from "./mail/define-email.js";
66
67
  import { startJobs } from "./jobs/runtime.js";
67
68
  import { jobsDrainApp } from "./jobs/drain-route.js";
68
- export { FatalJobError, HttpProblem, MissingCredentials, ModelError, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, beforeSignInPluginsVariable, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, hasUsers, imageSize, isCaptured, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, limitedFileStore, listOrganizations, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storeFile, streamChatCompletion, subscription, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
69
+ export { FatalJobError, HttpProblem, MissingCredentials, ModelError, addAppRoleToOwners, addMember, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaMigration, badRequest, beforeSignInPluginsVariable, betterAuthAuthenticator, changesMigration, checkAuthSchema, checkChanges, checkJobsSchema, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createFileCleanup, createOrganization, createUser, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteUser, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, handleDroppedConnections, hasUsers, imageSize, isCaptured, isJobDefinition, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, limitedFileStore, listOrganizations, listUsers, localFileStore, localFiles, mapSettings, mapStyleUrl, mapStyleVariable, maxTokenTtlSeconds, maxWidgetPropsBytes, mergeConfig, migrationCommand, newWebhookSecret, normalizeRoles, notFound, parseColumns, parseRoles, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, processor, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readWriteQueryTool, recordOf, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, setMemberRoles, setUserBanned, setUserRole, signInPolicyMethods, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storeFile, streamChatCompletion, subscription, thumbHash, unauthorized, variantPath, verifySignature, verifyStandardWebhook, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps };
package/dist/meta.js CHANGED
@@ -28,7 +28,7 @@ const modelsHash = (deps) => sha256Hex(stableJson(deps.registry.entries.map((ent
28
28
  * they could use once signed in, which keep their place in the bottom bar and the user menu.
29
29
  * The ETag hashes all of it, so it differs per user and per roles.
30
30
  */
31
- const createMeta = (deps) => {
31
+ const createMeta = (deps, appName) => {
32
32
  const base = modelsHash(deps);
33
33
  const forCaller = async (session) => {
34
34
  const accesses = await Promise.all(deps.registry.entries.map((entry) => requestAccess(deps, entry, session)));
@@ -55,6 +55,7 @@ const createMeta = (deps) => {
55
55
  const plugins = pluginsFor(deps.plugins, session.user.roles);
56
56
  const sources = sourcesFor(deps.sources, session.user.roles);
57
57
  const body = {
58
+ appName,
58
59
  resources: visible.map((access) => access.readable),
59
60
  views,
60
61
  pages,
@@ -1,8 +1,10 @@
1
1
  import { HttpProblem, badRequest } from "./problem.js";
2
+ import { isDatabaseError } from "./error-handler.js";
2
3
  import { deleteRecord, fetchRecord, insertRecord, restoreRecord } from "./records.js";
3
4
  import { tenantScope } from "./tenant.js";
4
5
  import { requestAccess, requireOperation, targetFilter, writableFields } from "./request-access.js";
5
6
  import { writeTransaction } from "./transactions.js";
7
+ import { blockedDelete } from "./blocked-delete.js";
6
8
  import { attachFiles } from "./files/attach.js";
7
9
  import { actorSettings, wakeDispatch } from "./changes/actor.js";
8
10
  import { validateBody } from "./validate-body.js";
@@ -71,7 +73,10 @@ const removeOrRestore = async (trx, deps, access, request) => {
71
73
  await notify(trx, "undelete", current.record, restored.record);
72
74
  return shown(access, restored);
73
75
  }
74
- const removed = await deleteRecord(trx, entry, request.key, scope?.tenantValue, shape);
76
+ const removed = await deleteRecord(trx, entry, request.key, scope?.tenantValue, shape).catch(async (error) => {
77
+ if (isDatabaseError(error) && error.code === "23503") throw await blockedDelete(deps, access, error);
78
+ throw error;
79
+ });
75
80
  await notify(trx, "delete", current.record, void 0);
76
81
  return shown(access, removed);
77
82
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/server",
3
- "version": "0.21.3",
3
+ "version": "0.21.5",
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.21.3",
34
- "@protobase/query": "0.21.3",
35
- "@protobase/schema": "0.21.3",
33
+ "@protobase/layout": "0.21.5",
34
+ "@protobase/query": "0.21.5",
35
+ "@protobase/schema": "0.21.5",
36
36
  "@react-email/render": "^2.1.0",
37
37
  "@scalar/hono-api-reference": "^0.12.10",
38
38
  "@sentry/core": "^11.7.0",