@protobase/server 0.48.0 → 0.49.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.
Files changed (74) hide show
  1. package/dist/admin-options.d.ts +2 -2
  2. package/dist/app-identity.d.ts +2 -2
  3. package/dist/app-name.d.ts +2 -0
  4. package/dist/better-auth/auth-settings.d.ts +8773 -0
  5. package/dist/better-auth/auth-settings.js +43 -0
  6. package/dist/better-auth/authenticate-settings.d.ts +15 -0
  7. package/dist/better-auth/authenticate-settings.js +12 -0
  8. package/dist/better-auth/create-auth.d.ts +51 -11
  9. package/dist/better-auth/create-auth.js +33 -11
  10. package/dist/better-auth/mcp/mcp-auth-plugins.d.ts +2719 -0
  11. package/dist/better-auth/mcp/mcp-auth-plugins.js +68 -0
  12. package/dist/better-auth/mcp/mcp-plugins.d.ts +7 -2
  13. package/dist/better-auth/mcp/mcp-plugins.js +3 -68
  14. package/dist/better-auth/mcp/mcp-token-claims.js +1 -1
  15. package/dist/better-auth/organizations/store.d.ts +1 -0
  16. package/dist/better-auth/saml-plugin.d.ts +993 -0
  17. package/dist/better-auth/saml-plugin.js +36 -0
  18. package/dist/better-auth/saml-sign-in.d.ts +27 -1
  19. package/dist/better-auth/saml-sign-in.js +1 -33
  20. package/dist/better-auth/secret-versions.d.ts +7 -0
  21. package/dist/better-auth/secret-versions.js +21 -0
  22. package/dist/better-auth/signing-keys.js +86 -0
  23. package/dist/better-auth/tokens.js +1 -0
  24. package/dist/better-auth/user-table.js +1 -1
  25. package/dist/better-auth/users.d.ts +1 -1
  26. package/dist/create-admin.d.ts +5 -3
  27. package/dist/create-admin.js +3 -1
  28. package/dist/encryption/keyring.js +1 -1
  29. package/dist/files/options.d.ts +5 -8
  30. package/dist/files/provider-settings.d.ts +16 -0
  31. package/dist/files/provider-settings.js +17 -0
  32. package/dist/files/runtime.js +4 -4
  33. package/dist/forms/runtime.js +3 -3
  34. package/dist/gotrue/sessions-plugin.js +3 -9
  35. package/dist/index.d.ts +16 -15
  36. package/dist/index.js +8 -10
  37. package/dist/internal.d.ts +13 -0
  38. package/dist/internal.js +13 -0
  39. package/dist/jobs/declared-job.d.ts +24 -0
  40. package/dist/jobs/declared-job.js +26 -0
  41. package/dist/jobs/job-types.d.ts +1 -1
  42. package/dist/mcp/mcp-authenticator.js +3 -3
  43. package/dist/notifications/device-store-of.d.ts +1 -1
  44. package/dist/notifications/device-store-of.js +1 -1
  45. package/dist/notifications/device-store.d.ts +1 -1
  46. package/dist/notifications/device-store.js +1 -1
  47. package/dist/notifications/history-store-of.d.ts +1 -1
  48. package/dist/notifications/history-store-of.js +1 -1
  49. package/dist/notifications/history-store.d.ts +1 -1
  50. package/dist/notifications/history-store.js +1 -1
  51. package/dist/notifications/options.d.ts +3 -1
  52. package/dist/notifications/options.js +1 -1
  53. package/dist/notifications/schema.d.ts +2 -2
  54. package/dist/notifications/schema.js +7 -7
  55. package/dist/notifications/send-notification.js +1 -1
  56. package/dist/notifications/sender.d.ts +1 -1
  57. package/dist/notifications/sender.js +2 -2
  58. package/dist/notifications/senders-of.d.ts +1 -1
  59. package/dist/notifications/senders-of.js +1 -1
  60. package/dist/package.js +1 -1
  61. package/dist/webhooks/subscription.d.ts +1 -0
  62. package/dist/webhooks/table/options.d.ts +1 -1
  63. package/dist/webhooks/table/schema.d.ts +2 -2
  64. package/dist/webhooks/table/schema.js +2 -2
  65. package/dist/webhooks/table/webhook-table.js +2 -2
  66. package/dist/webhooks/table/webhooks-module.d.ts +108 -0
  67. package/dist/webhooks/table/webhooks-module.js +11 -0
  68. package/package.json +6 -5
  69. package/dist/notifications/plugin.d.ts +0 -13
  70. package/dist/notifications/plugin.js +0 -16
  71. package/dist/project-config.d.ts +0 -54
  72. package/dist/project-config.js +0 -182
  73. package/dist/webhooks/table/plugin.d.ts +0 -10
  74. package/dist/webhooks/table/plugin.js +0 -18
package/dist/index.js CHANGED
@@ -26,7 +26,7 @@ import { apiKeyCaller } from "./api-keys/resolve-caller.js";
26
26
  import { jwtAuthenticator, jwtVerifier } from "./auth/jwt.js";
27
27
  import { realtimeLimits } from "./realtime/realtime-limits.js";
28
28
  import { objectKey } from "./storage/object-key.js";
29
- import { defaultAppName, shownAppName } from "./app-name.js";
29
+ import { appNameOver, defaultAppName, shownAppName } from "./app-name.js";
30
30
  import { supabasePath } from "./supabase-paths.js";
31
31
  import { goTruePath } from "./gotrue/keys.js";
32
32
  import { defaultSignInPolicy, signInPolicyMethods } from "./better-auth/sign-in-policy.js";
@@ -34,7 +34,7 @@ import { parseRoles } from "./better-auth/parse-roles.js";
34
34
  import { passwordLength } from "./better-auth/new-account-password.js";
35
35
  import { readOperatorSettings } from "./better-auth/operator-provider.js";
36
36
  import { readPlatformSignIn } from "./better-auth/platform-sign-in.js";
37
- import { createAuth, normalizeRoles } from "./better-auth/create-auth.js";
37
+ import { normalizeRoles } from "./better-auth/create-auth.js";
38
38
  import { mcpApprovals } from "./mcp/mcp-approval-store.js";
39
39
  import { mcpToolContext } from "./mcp/mcp-context.js";
40
40
  import { mcpGate, sessionOf } from "./mcp/mcp-gate.js";
@@ -75,8 +75,8 @@ import { NotificationSendError, maxMessageBytes, maxRecipients } from "./notific
75
75
  import { errorReportingSettings, errorReportingVariable } from "./error-reporting/error-reporting-settings.js";
76
76
  import { storageCleanupSchedule } from "./files/cleanup-schedule.js";
77
77
  import { limitedFileStore, storeUsage } from "./files/limits.js";
78
- import { localFileStore, localFiles } from "./files/local-files.js";
79
- import { s3FileStore, s3Files } from "./files/s3-files.js";
78
+ import { localFileStore } from "./files/local-files.js";
79
+ import { s3FileStore } from "./files/s3-files.js";
80
80
  import { storageProvider } from "./files/storage-provider.js";
81
81
  import { isBackgroundWork, runInBackground, wantsLongQueries } from "./background-work.js";
82
82
  import { capSocketMessages, honorSocketMessageCaps, socketMessageCapOf } from "./functions/socket-message-cap.js";
@@ -89,22 +89,19 @@ import { pngIcons } from "./web-app/app-icons.js";
89
89
  import { webManifestPath } from "./web-app/web-manifest-route.js";
90
90
  import { createAdmin } from "./create-admin.js";
91
91
  import { handleDroppedConnections } from "./dropped-connections.js";
92
- import { appPool, longQueryPool, poolWaitMs, readDbConnections } from "./app-pool.js";
92
+ import { poolWaitMs, readDbConnections } from "./app-pool.js";
93
93
  import { configExports } from "./resource-source.js";
94
94
  import { checkViewQueries } from "./check-view-queries.js";
95
- import { defineConfig, mergeConfig } from "./project-config.js";
96
95
  import { withTrustedApps } from "./better-auth/app-tokens.js";
97
- import { betterAuthAuthenticator, betterAuthTokens } from "./better-auth/authenticator.js";
96
+ import { betterAuthTokens } from "./better-auth/authenticator.js";
98
97
  import { issueToken, maxTokenTtlSeconds } from "./better-auth/tokens.js";
99
98
  import { authSchemaMigration, checkAuthSchema } from "./better-auth/auth-schema.js";
100
99
  import { authSchemaDrift } from "./better-auth/store/drift.js";
101
100
  import { authStoreTables } from "./better-auth/auth-tables.js";
102
101
  import { checkResourcesOutsideAuthStore } from "./better-auth/store/resources-outside.js";
103
102
  import { checkComputed, computedMigration } from "./computed/computed-schema.js";
104
- import { webhooks } from "./webhooks/table/plugin.js";
105
103
  import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.js";
106
104
  import { checkAi } from "./ai/check-ai.js";
107
- import { notifications } from "./notifications/plugin.js";
108
105
  import { checkNotificationsSchema, notificationsMigration } from "./notifications/schema.js";
109
106
  import { sendNotification } from "./notifications/send-notification.js";
110
107
  import { maxWidgetPropsBytes, widget } from "./assistant/widget.js";
@@ -119,10 +116,11 @@ import { storeFile } from "./files/store-file.js";
119
116
  import { createFileCleanup } from "./files/file-cleanup.js";
120
117
  import { createEncryptionTools } from "./encryption/tools.js";
121
118
  import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/processors.js";
119
+ import { enqueueJob } from "./jobs/declared-job.js";
122
120
  import { defineEmail } from "./mail/define-email.js";
123
121
  import { startJobs } from "./jobs/runtime.js";
124
122
  import { jobsDrainApp } from "./jobs/drain-route.js";
125
123
  import { composeRelease, releaseManifest } from "./mobile-release/release.js";
126
124
  import { mobileReleaseApp } from "./mobile-release/release-app.js";
127
125
  import { mobileSigningKeyVariable, readSigningKey } from "./mobile-release/signing-key.js";
128
- export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appPool, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthAuthenticator, betterAuthTokens, capSocketMessages, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, composeRelease, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createAuth, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineConfig, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, deviceIdParam, deviceStore, devicesPath, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, localFiles, longQueryPool, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpRoutes, mcpServer, mcpToolContext, mcpTools, mergeConfig, migrationCommand, mobileReleaseApp, mobileSigningKeyVariable, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notifications, notificationsMigration, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readSigningKey, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, recordOf, releaseManifest, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, s3Files, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooks, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
126
+ export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, capSocketMessages, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentsMigration, composeRelease, computedMigration, configExports, consoleAuditQueue, conversationKey, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, defineTool, deleteRecordTool, deleteUser, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, mobileReleaseApp, mobileSigningKeyVariable, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readSigningKey, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, recordOf, releaseManifest, removeDevicesWithUsers, removeHistoryWithUsers, removeMember, renderVariant, requestApproval, requireEnv, resourceChange, roleChoices, runInBackground, runReadOnlyQuery, runReadWriteQuery, runTurn, runtimeUrl, runtimeVariable, s3FileStore, seesAssistant, seesRuntime, sendNotification, sessionOf, setMemberRoles, setUserBanned, setUserRole, shownAppName, signInPolicyMethods, socketMessageCapOf, sourceOptions, sourcesFor, sourcesVariable, startErrorReporting, startJobs, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, writeRecordTools };
@@ -0,0 +1,13 @@
1
+ import { checkNotificationsOptions } from "./notifications/options.js";
2
+ import { isSubscription } from "./webhooks/subscription.js";
3
+ import { appPool, longQueryPool } from "./app-pool.js";
4
+ import { AppAuthInput, appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
5
+ import { betterAuthAuthenticator } from "./better-auth/authenticator.js";
6
+ import { buildAuthenticator } from "./better-auth/authenticate-settings.js";
7
+ import { localFiles } from "./files/local-files.js";
8
+ import { s3Files } from "./files/s3-files.js";
9
+ import { fileProviderOf } from "./files/provider-settings.js";
10
+ import { declaredJob } from "./jobs/declared-job.js";
11
+ import { AuthPlugins, buildAuth, createAuth, loadAuthPlugins } from "./better-auth/create-auth.js";
12
+ import { webhooksModule } from "./webhooks/table/webhooks-module.js";
13
+ export { type AppAuthInput, type AuthPlugins, appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
@@ -0,0 +1,13 @@
1
+ import { buildAuth, createAuth, loadAuthPlugins } from "./better-auth/create-auth.js";
2
+ import { isSubscription } from "./webhooks/subscription.js";
3
+ import { checkNotificationsOptions } from "./notifications/options.js";
4
+ import { localFiles } from "./files/local-files.js";
5
+ import { s3Files } from "./files/s3-files.js";
6
+ import { appPool, longQueryPool } from "./app-pool.js";
7
+ import { betterAuthAuthenticator } from "./better-auth/authenticator.js";
8
+ import { declaredJob } from "./jobs/declared-job.js";
9
+ import { appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
10
+ import { buildAuthenticator } from "./better-auth/authenticate-settings.js";
11
+ import { fileProviderOf } from "./files/provider-settings.js";
12
+ import { webhooksModule } from "./webhooks/table/webhooks-module.js";
13
+ export { appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
@@ -0,0 +1,24 @@
1
+ import { EnqueueOptions, JobContext, JobDefinition, JobOptions } from "./job-types.js";
2
+ import { ArgumentsSpec } from "@protobase/schema";
3
+ import { Db } from "@protobase/query";
4
+ //#region src/jobs/declared-job.d.ts
5
+ /**
6
+ * A job as `protobase.config.ts` declares it, by its name: what it does, its arguments and when it runs. Its run is the
7
+ * default export of `jobs/<name>.ts`, loaded the first time the job runs.
8
+ */
9
+ export type JobDeclaration = Omit<JobOptions<unknown>, 'name' | 'payload' | 'run'> & {
10
+ /** What the job does, for the people who read the config and the failed jobs page. */
11
+ description?: string;
12
+ /** Its arguments by name, each a field type or a type with options (see `ArgumentSpec`), such as `{ invoiceId: 'bigint' }`. */
13
+ arguments?: ArgumentsSpec;
14
+ };
15
+ /** The default export of `jobs/<name>.ts`: what the job does with its arguments. */
16
+ export type JobRun<Payload = Record<string, unknown>> = (payload: Payload, context: JobContext) => Promise<void> | void;
17
+ /** The job a config declares, whose run `load` gives on its first run. */
18
+ export declare const declaredJob: (name: string, { description: _, arguments: args, ...options }: JobDeclaration, load: () => Promise<JobRun>) => JobDefinition;
19
+ /**
20
+ * Enqueues the job named `name`, which the config declares, in `db`'s own transaction when it is one, and returns its
21
+ * id: what a write hook calls, so the job commits with the write or not at all.
22
+ */
23
+ export declare const enqueueJob: (db: Db, name: string, payload?: Record<string, unknown>, options?: EnqueueOptions) => Promise<string>;
24
+ //#endregion
@@ -0,0 +1,26 @@
1
+ import { currentJobs } from "./current.js";
2
+ import { defineJob } from "./define-job.js";
3
+ import { argumentsSchema } from "@protobase/schema";
4
+ //#region src/jobs/declared-job.ts
5
+ /** The job a config declares, whose run `load` gives on its first run. */
6
+ const declaredJob = (name, { description: _, arguments: args, ...options }, load) => {
7
+ let run;
8
+ return defineJob({
9
+ ...options,
10
+ name,
11
+ ...args && { payload: argumentsSchema(name, args) },
12
+ run: async (payload, context) => (await (run ??= load()))(payload ?? {}, context)
13
+ });
14
+ };
15
+ /**
16
+ * Enqueues the job named `name`, which the config declares, in `db`'s own transaction when it is one, and returns its
17
+ * id: what a write hook calls, so the job commits with the write or not at all.
18
+ */
19
+ const enqueueJob = (db, name, payload, options) => {
20
+ const runtime = currentJobs();
21
+ const definition = runtime.definition(name);
22
+ if (!definition) throw new Error(`There is no job "${name}": declare it in protobase.config.ts's jobs`);
23
+ return runtime.enqueue(definition, db, payload, options);
24
+ };
25
+ //#endregion
26
+ export { declaredJob, enqueueJob };
@@ -19,7 +19,7 @@ export type JobContext = {
19
19
  signal: AbortSignal;
20
20
  /** Sends mail through the app's SMTP server (`PROTOBASE_SMTP_URL`, `PROTOBASE_MAIL_FROM`); `undefined` when the app has no mail. */
21
21
  mail?: Mailer;
22
- /** Sends a notification as `sendNotification` does; `undefined` when the app has no `notifications()`. */
22
+ /** Sends a notification as `sendNotification` does; `undefined` when the app has no `notifications`. */
23
23
  sendNotification?: SendNotification;
24
24
  };
25
25
  export type JobOptions<Payload> = {
@@ -3,7 +3,7 @@ import { isMcpWrites } from "./mcp-writes.js";
3
3
  const hasAudiences = (authenticate) => typeof authenticate.forAudience === "function";
4
4
  const isMcpOptions = (options) => options === void 0 || options === false || typeof options === "object" && options !== null && !Array.isArray(options) && Object.entries(options).every(([name, value]) => value === void 0 || name === "sql" && typeof value === "boolean" || name === "writes" && isMcpWrites(value));
5
5
  /**
6
- * The authenticator of the MCP endpoint's tokens, when MCP is on (`createAuth({ mcp })`); none when the host serves its
6
+ * The authenticator of the MCP endpoint's tokens, when MCP is on (`auth.mcp`); none when the host serves its
7
7
  * own (`options.mcp: false`). Stops the server at startup when `options.mcp` is neither `false` nor
8
8
  * `{ sql?: boolean; writes?: boolean | { resources?: string[]; rolesWithoutApproval?: string[] } }`, when it is set without MCP, or when `authenticate` cannot verify tokens for
9
9
  * another audience.
@@ -11,9 +11,9 @@ const isMcpOptions = (options) => options === void 0 || options === false || typ
11
11
  const mcpAuthenticator = (authenticate, mcp, options) => {
12
12
  if (!isMcpOptions(options)) throw new Error("options.mcp takes false or { sql?: boolean, writes?: boolean | { resources?: [<resource>, ...], rolesWithoutApproval?: [<role>, ...] } }");
13
13
  if (options === false) return void 0;
14
- if (options && !mcp) throw new Error("options.mcp needs createAuth({ mcp }) passed as auth");
14
+ if (options && !mcp) throw new Error("mcpEndpoint needs auth.mcp in protobase.config.ts");
15
15
  if (!mcp) return void 0;
16
- if (!hasAudiences(authenticate)) throw new Error("MCP needs authenticate from betterAuthAuthenticator, whose forAudience verifies the MCP tokens");
16
+ if (!hasAudiences(authenticate)) throw new Error("MCP needs the app's own authenticator, whose forAudience verifies the MCP tokens: leave `authenticate` a module of your own out of protobase.config.ts");
17
17
  return authenticate.forAudience(mcp.resource);
18
18
  };
19
19
  //#endregion
@@ -4,7 +4,7 @@ import { AdminAuth } from "../better-auth/create-auth.js";
4
4
  import { Db } from "@protobase/query";
5
5
  //#region src/notifications/device-store-of.d.ts
6
6
  /**
7
- * The devices' store `notifications()` configures: the app's own `store`, or the devices table in `db`. An app that
7
+ * The devices' store `notifications` configures: the app's own `store`, or the devices table in `db`. An app that
8
8
  * deletes users without Protobase's auth calls its `removeAllForUser` as it deletes one.
9
9
  */
10
10
  export declare const deviceStore: (db: Db, options?: NotificationsOptions) => DeviceStore;
@@ -1,7 +1,7 @@
1
1
  import { postgresDeviceStore } from "./postgres-store.js";
2
2
  //#region src/notifications/device-store-of.ts
3
3
  /**
4
- * The devices' store `notifications()` configures: the app's own `store`, or the devices table in `db`. An app that
4
+ * The devices' store `notifications` configures: the app's own `store`, or the devices table in `db`. An app that
5
5
  * deletes users without Protobase's auth calls its `removeAllForUser` as it deletes one.
6
6
  */
7
7
  const deviceStore = (db, options = {}) => options.store ?? postgresDeviceStore(db, options);
@@ -2,7 +2,7 @@ import { Device, NewDevice } from "./device.js";
2
2
  //#region src/notifications/device-store.d.ts
3
3
  /**
4
4
  * Where each user's devices are kept: the Postgres default (`postgresDeviceStore`), or a store of the app's own passed
5
- * as `notifications({ store })`. Plain data in and out, so any store can implement it. Every method throws on an empty
5
+ * as `notifications.store`. Plain data in and out, so any store can implement it. Every method throws on an empty
6
6
  * user id, id or token, and none touches every device.
7
7
  */
8
8
  export type DeviceStore = {
@@ -10,7 +10,7 @@ const methods = [
10
10
  /** The store, checked to have every method; a missing one is an error naming it. */
11
11
  const checkDeviceStore = (store) => {
12
12
  const missing = methods.find((method) => typeof store[method] !== "function");
13
- if (missing !== void 0) throw new Error(`notifications({ store }): the device store has no ${missing} method`);
13
+ if (missing !== void 0) throw new Error(`notifications.store: the device store has no ${missing} method`);
14
14
  return store;
15
15
  };
16
16
  /** The value, refused when empty: no store call may be read as "every device". */
@@ -4,7 +4,7 @@ import { AdminAuth } from "../better-auth/create-auth.js";
4
4
  import { Db } from "@protobase/query";
5
5
  //#region src/notifications/history-store-of.d.ts
6
6
  /**
7
- * The history's store `notifications()` configures: the app's own `historyStore`, or the history table in `db`. An app
7
+ * The history's store `notifications` configures: the app's own `historyStore`, or the history table in `db`. An app
8
8
  * that deletes users without Protobase's auth calls its `removeAllForUser` as it deletes one.
9
9
  */
10
10
  export declare const historyStore: (db: Db, options?: NotificationsOptions) => HistoryStore;
@@ -1,7 +1,7 @@
1
1
  import { postgresHistoryStore } from "./postgres-history-store.js";
2
2
  //#region src/notifications/history-store-of.ts
3
3
  /**
4
- * The history's store `notifications()` configures: the app's own `historyStore`, or the history table in `db`. An app
4
+ * The history's store `notifications` configures: the app's own `historyStore`, or the history table in `db`. An app
5
5
  * that deletes users without Protobase's auth calls its `removeAllForUser` as it deletes one.
6
6
  */
7
7
  const historyStore = (db, options = {}) => options.historyStore ?? postgresHistoryStore(db, options);
@@ -4,7 +4,7 @@ import { HistoryPosition, NewNotification, StoredNotification } from "./history.
4
4
  export declare const maxUnreadCount = 100;
5
5
  /**
6
6
  * Where each user's inbox notifications are kept: the Postgres default (`postgresHistoryStore`), or a store of the
7
- * app's own passed as `notifications({ historyStore })`. Plain data in and out, so any store can implement it. Every
7
+ * app's own passed as `notifications.historyStore`. Plain data in and out, so any store can implement it. Every
8
8
  * method takes the user and touches that user's entries alone; each throws on an empty user id or id.
9
9
  */
10
10
  export type HistoryStore = {
@@ -12,7 +12,7 @@ const methods = [
12
12
  /** The store, checked to have every method; a missing one is an error naming it. */
13
13
  const checkHistoryStore = (store) => {
14
14
  const missing = methods.find((method) => typeof store[method] !== "function");
15
- if (missing !== void 0) throw new Error(`notifications({ historyStore }): the history store has no ${missing} method`);
15
+ if (missing !== void 0) throw new Error(`notifications.historyStore: the history store has no ${missing} method`);
16
16
  return store;
17
17
  };
18
18
  /** The most entries `list` gives at once. */
@@ -8,7 +8,7 @@ export type DeviceColumn = (typeof deviceColumns)[number];
8
8
  /** The columns of the history table, by the name Protobase gives them. */
9
9
  export declare const historyColumns: readonly ["id", "user_id", "title", "body", "url", "data", "created_at", "read_at"];
10
10
  export type HistoryColumn = (typeof historyColumns)[number];
11
- /** Notifications, turned on with `extends: [notifications()]`. */
11
+ /** Notifications, turned on with `notifications: {}` in `protobase.config.ts`. */
12
12
  export type NotificationsOptions = {
13
13
  /** The bell in the top bar; default true. `false` keeps only the backend. */
14
14
  ui?: boolean;
@@ -34,4 +34,6 @@ export type NotificationsOptions = {
34
34
  */
35
35
  senders?: PushSender[];
36
36
  };
37
+ /** The options, checked as `notifications` takes them: the names, given stores' methods and the senders given. */
38
+ export declare const checkNotificationsOptions: (options: NotificationsOptions) => NotificationsOptions;
37
39
  //#endregion
@@ -51,7 +51,7 @@ const historyNames = (options = {}) => ({
51
51
  table: checkedName("history.table", options.history?.table ?? "history"),
52
52
  columns: columnNames("history", historyColumns, options.history?.columns)
53
53
  });
54
- /** The options, checked as `notifications()` takes them: the names, given stores' methods and the senders given. */
54
+ /** The options, checked as `notifications` takes them: the names, given stores' methods and the senders given. */
55
55
  const checkNotificationsOptions = (options) => {
56
56
  if (options.ui !== void 0 && typeof options.ui !== "boolean") throw new Error("notifications ui is true or false");
57
57
  notificationsNames(options);
@@ -3,12 +3,12 @@ import { AdminAuth } from "../better-auth/create-auth.js";
3
3
  import { Db } from "@protobase/query";
4
4
  //#region src/notifications/schema.d.ts
5
5
  /**
6
- * The SQL that adds the tables `notifications()` keeps devices and each user's history in, under the names its options
6
+ * The SQL that adds the tables `notifications` keeps devices and each user's history in, under the names its options
7
7
  * give; with `auth`, their user columns point at auth's users table. Each table is left out when it exists or a store
8
8
  * of the app's own replaces it, and an existing devices table without its session column gets that column;
9
9
  * `undefined` when nothing is left.
10
10
  */
11
11
  export declare const notificationsMigration: (db: Db, options?: NotificationsOptions, auth?: AdminAuth) => Promise<string | undefined>;
12
- /** Refuses to start while the devices or the history table lacks what `notifications()` needs, naming it. */
12
+ /** Refuses to start while the devices or the history table lacks what `notifications` needs, naming it. */
13
13
  export declare const checkNotificationsSchema: (db: Db, options?: NotificationsOptions, auth?: AdminAuth) => Promise<void>;
14
14
  //#endregion
@@ -13,7 +13,7 @@ const authUsersTable = (auth) => ({
13
13
  const regclass = async (db, name) => (await sql`select to_regclass(${name})::oid as oid`.execute(db)).rows[0].oid;
14
14
  const userIdType = async (db, users) => {
15
15
  const oid = await regclass(db, qualified(users));
16
- if (oid === null) throw new Error(`notifications(): auth's users table ${qualified(users)} is not in the app's database, so devices cannot point at it`);
16
+ if (oid === null) throw new Error(`notifications: auth's users table ${qualified(users)} is not in the app's database, so devices cannot point at it`);
17
17
  const { rows } = await sql`select format_type(atttypid, atttypmod) as type from pg_attribute where attrelid = ${oid} and attname = 'id'`.execute(db);
18
18
  return rows[0].type;
19
19
  };
@@ -26,7 +26,7 @@ const lacksSessionColumn = async (db, names) => {
26
26
  return oid !== null && !(await columnsOf(db, oid)).some((row) => row.name === names.columns.session_id);
27
27
  };
28
28
  /**
29
- * The SQL that adds the tables `notifications()` keeps devices and each user's history in, under the names its options
29
+ * The SQL that adds the tables `notifications` keeps devices and each user's history in, under the names its options
30
30
  * give; with `auth`, their user columns point at auth's users table. Each table is left out when it exists or a store
31
31
  * of the app's own replaces it, and an existing devices table without its session column gets that column;
32
32
  * `undefined` when nothing is left.
@@ -50,9 +50,9 @@ const notificationsMigration = async (db, options = {}, auth) => {
50
50
  ];
51
51
  return `${[...new Set(statements)].join(";\n\n")};`;
52
52
  };
53
- const missingTable = (what, table) => /* @__PURE__ */ new Error(`The ${what} table ${table} of notifications() is missing. Write it as a migration with \`${migrationCommand}\`, apply it with the project's migrations, then start again.`);
53
+ const missingTable = (what, table) => /* @__PURE__ */ new Error(`The ${what} table ${table} of notifications is missing. Write it as a migration with \`${migrationCommand}\`, apply it with the project's migrations, then start again.`);
54
54
  /**
55
- * Refuses to start while the devices table lacks what `notifications()` needs, naming it: the table, each column under
55
+ * Refuses to start while the devices table lacks what `notifications` needs, naming it: the table, each column under
56
56
  * its configured name, a unique index on the token alone, which moving a device relies on, and with `auth` a foreign key
57
57
  * from the user column that deletes a user's devices with the user. Nothing to check with a store of the app's own.
58
58
  */
@@ -65,7 +65,7 @@ const checkDevicesTable = async (db, options, users) => {
65
65
  const found = await columnsOf(db, oid);
66
66
  const numOf = (column) => found.find((row) => row.name === names.columns[column])?.num;
67
67
  const missing = Object.keys(names.columns).find((column) => numOf(column) === void 0);
68
- if (missing !== void 0) throw new Error(`The devices table ${devices} has no column "${names.columns[missing]}": add it, or name the table's own with notifications({ devices: { columns: { ${missing}: ... } } })`);
68
+ if (missing !== void 0) throw new Error(`The devices table ${devices} has no column "${names.columns[missing]}": add it, or name the table's own with notifications: { devices: { columns: { ${missing}: ... } } } in protobase.config.ts`);
69
69
  if (!await uniqueOn(db, oid, numOf("token"))) throw new Error(`The devices table ${devices} needs a unique index on its token column "${names.columns.token}" alone, which moving a device to the user who registers it relies on`);
70
70
  if (users && !await cascadesFrom(db, oid, numOf("user_id"), users)) throw new Error(`The devices table ${devices} needs a foreign key from "${names.columns.user_id}" to ${qualified(users)} with on delete cascade, so a deleted user's devices go with them`);
71
71
  };
@@ -79,10 +79,10 @@ const checkHistoryTable = async (db, options, users) => {
79
79
  const found = await columnsOf(db, oid);
80
80
  const numOf = (column) => found.find((row) => row.name === names.columns[column])?.num;
81
81
  const missing = Object.keys(names.columns).find((column) => numOf(column) === void 0);
82
- if (missing !== void 0) throw new Error(`The history table ${history} has no column "${names.columns[missing]}": add it, or name the table's own with notifications({ history: { columns: { ${missing}: ... } } })`);
82
+ if (missing !== void 0) throw new Error(`The history table ${history} has no column "${names.columns[missing]}": add it, or name the table's own with notifications: { history: { columns: { ${missing}: ... } } } in protobase.config.ts`);
83
83
  if (users && !await cascadesFrom(db, oid, numOf("user_id"), users)) throw new Error(`The history table ${history} needs a foreign key from "${names.columns.user_id}" to ${qualified(users)} with on delete cascade, so a deleted user's history goes with them`);
84
84
  };
85
- /** Refuses to start while the devices or the history table lacks what `notifications()` needs, naming it. */
85
+ /** Refuses to start while the devices or the history table lacks what `notifications` needs, naming it. */
86
86
  const checkNotificationsSchema = async (db, options = {}, auth) => {
87
87
  const users = auth && authUsersTable(auth);
88
88
  await checkDevicesTable(db, options, users);
@@ -12,7 +12,7 @@ import { pushJobName } from "./push-job-name.js";
12
12
  const sendNotification = async (db, to, message) => {
13
13
  const send = checkedSend(to, message);
14
14
  const job = currentJobs().definition(pushJobName);
15
- if (!job) throw new Error("Notifications are off: add extends: [notifications()] to protobase.config.ts to send them");
15
+ if (!job) throw new Error("Notifications are off: add notifications: {} to protobase.config.ts to send them");
16
16
  await job.enqueue(db, send);
17
17
  };
18
18
  //#endregion
@@ -14,7 +14,7 @@ export type PushAnswer = {
14
14
  };
15
15
  /**
16
16
  * Delivers notifications to the devices of its `kinds`, through their push service: the built-in Web Push sender, or
17
- * one of the app's own passed as `notifications({ senders })`, typically from a package. `send` takes a message and a
17
+ * one of the app's own passed as `notifications.senders`, typically from a package. `send` takes a message and a
18
18
  * batch of devices of those kinds only, and answers each device by its id. A sender for `web` devices names the VAPID
19
19
  * `publicKey` browsers subscribe with, which every client may read.
20
20
  */
@@ -2,7 +2,7 @@ import { deviceKinds } from "./device.js";
2
2
  import { isPublicKey } from "./web-push/keys.js";
3
3
  //#region src/notifications/sender.ts
4
4
  const checkSender = (sender, index, claimed) => {
5
- const name = `notifications({ senders }): sender ${index}`;
5
+ const name = `notifications.senders: sender ${index}`;
6
6
  if (typeof sender !== "object" || sender === null || typeof sender.send !== "function") throw new Error(`${name} has no send method`);
7
7
  if (!Array.isArray(sender.kinds) || sender.kinds.length === 0) throw new Error(`${name} names no kinds: ${deviceKinds.join(", ")}`);
8
8
  for (const kind of sender.kinds) {
@@ -14,7 +14,7 @@ const checkSender = (sender, index, claimed) => {
14
14
  };
15
15
  /** The senders, checked: each with a send method and kinds, no kind delivered by two, and a public key when one is named. */
16
16
  const checkSenders = (senders) => {
17
- if (!Array.isArray(senders)) throw new Error("notifications({ senders }) is a list of senders");
17
+ if (!Array.isArray(senders)) throw new Error("notifications.senders is a list of senders");
18
18
  const claimed = /* @__PURE__ */ new Set();
19
19
  senders.forEach((sender, index) => checkSender(sender, index, claimed));
20
20
  return senders;
@@ -2,7 +2,7 @@ import { PushSender } from "./sender.js";
2
2
  import { NotificationsOptions } from "./options.js";
3
3
  //#region src/notifications/senders-of.d.ts
4
4
  /**
5
- * The senders `notifications()` delivers with: the app's own `senders`, which replace the built-in ones, or the
5
+ * The senders `notifications` delivers with: the app's own `senders`, which replace the built-in ones, or the
6
6
  * built-in ones whose environment is set. Each comes guarded (see `guardedSender`): the code that sends calls them only
7
7
  * through what this returns. A VAPID variable that is wrong stops startup.
8
8
  */
@@ -8,7 +8,7 @@ const builtInSenders = (env) => {
8
8
  return vapid ? [webPushSender(vapid)] : [];
9
9
  };
10
10
  /**
11
- * The senders `notifications()` delivers with: the app's own `senders`, which replace the built-in ones, or the
11
+ * The senders `notifications` delivers with: the app's own `senders`, which replace the built-in ones, or the
12
12
  * built-in ones whose environment is set. Each comes guarded (see `guardedSender`): the code that sends calls them only
13
13
  * through what this returns. A VAPID variable that is wrong stops startup.
14
14
  */
package/dist/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.48.0";
2
+ var version = "0.49.1";
3
3
  //#endregion
4
4
  export { version };
@@ -89,4 +89,5 @@ export type SubscriptionDefinition = {
89
89
  * empty.
90
90
  */
91
91
  export declare const subscription: (name: string, options: SubscriptionOptions) => SubscriptionDefinition;
92
+ export declare const isSubscription: (value: unknown) => value is SubscriptionDefinition;
92
93
  //#endregion
@@ -1,6 +1,6 @@
1
1
  import { TenantValue } from "../../types.js";
2
2
  //#region src/webhooks/table/options.d.ts
3
- /** Webhook subscriptions made in the admin app (`extends: [webhooks()]`), kept in a table of the app's database. */
3
+ /** Webhook subscriptions made in the admin app (`webhooks: {}`), kept in a table of the app's database. */
4
4
  export type WebhooksOptions = {
5
5
  /** The schema of the subscriptions table and the deliveries view; default `webhooks`. */
6
6
  schema?: string;
@@ -3,11 +3,11 @@ import { WebhooksOptions } from "./options.js";
3
3
  import { Db } from "@protobase/query";
4
4
  //#region src/webhooks/table/schema.d.ts
5
5
  /**
6
- * The SQL that brings the `webhooks` schema to what `webhooks()` needs: the subscriptions table, its commands, the
6
+ * The SQL that brings the `webhooks` schema to what `webhooks` needs: the subscriptions table, its commands, the
7
7
  * deliveries view and, with `deliveryLog`, the log table. `undefined` when current. Needs the jobs schema, which the
8
8
  * deliveries view reads. Tables are never dropped.
9
9
  */
10
10
  export declare const webhooksMigration: (db: Db, options?: WebhooksOptions, events?: EventsOptions) => Promise<string | undefined>;
11
- /** Refuses to go on while the `webhooks` schema lacks what `webhooks()` needs; the project's migrations add it. */
11
+ /** Refuses to go on while the `webhooks` schema lacks what `webhooks` needs; the project's migrations add it. */
12
12
  export declare const checkWebhooksSchema: (db: Db, options?: WebhooksOptions) => Promise<void>;
13
13
  //#endregion
@@ -17,7 +17,7 @@ const readWebhooksSchema = async (db, schema) => {
17
17
  };
18
18
  };
19
19
  /**
20
- * The SQL that brings the `webhooks` schema to what `webhooks()` needs: the subscriptions table, its commands, the
20
+ * The SQL that brings the `webhooks` schema to what `webhooks` needs: the subscriptions table, its commands, the
21
21
  * deliveries view and, with `deliveryLog`, the log table. `undefined` when current. Needs the jobs schema, which the
22
22
  * deliveries view reads. Tables are never dropped.
23
23
  */
@@ -33,7 +33,7 @@ const webhooksMigration = async (db, options = {}, events) => {
33
33
  ...needsLog ? [deliveryLogSql(schema)] : []
34
34
  ].join(";\n\n")};`;
35
35
  };
36
- /** Refuses to go on while the `webhooks` schema lacks what `webhooks()` needs; the project's migrations add it. */
36
+ /** Refuses to go on while the `webhooks` schema lacks what `webhooks` needs; the project's migrations add it. */
37
37
  const checkWebhooksSchema = async (db, options = {}) => {
38
38
  const schema = webhooksSchema(options);
39
39
  const found = await readWebhooksSchema(db, schema);
@@ -4,12 +4,12 @@ import { checkWebhookUrl } from "./address-check.js";
4
4
  import { tableSubscriptions } from "./table-subscriptions.js";
5
5
  //#region src/webhooks/table/webhook-table.ts
6
6
  /**
7
- * What `createAdmin` needs for the subscriptions of `webhooks()`: the table, the owners' current roles (from Better Auth
7
+ * What `createAdmin` needs for the subscriptions of `webhooks`: the table, the owners' current roles (from Better Auth
8
8
  * unless the options say otherwise) and, unless allowed, the check that keeps URLs off private addresses.
9
9
  */
10
10
  const webhookTable = (options, auth) => {
11
11
  const ownerRoles = options.ownerRoles ?? (auth && betterAuthOwnerRoles(auth));
12
- if (!ownerRoles) throw new Error("webhooks() delivers as each subscription's owner, with their current roles: pass `auth` (Better Auth) or `ownerRoles` to webhooks()");
12
+ if (!ownerRoles) throw new Error("webhooks deliver as each subscription's owner, with their current roles: give the config `auth` (Better Auth), or `webhooks.ownerRoles`");
13
13
  return {
14
14
  subscriptions: tableSubscriptions({
15
15
  schema: webhooksSchema(options),