@protobase/server 0.47.1 → 0.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin-options.d.ts +2 -2
- package/dist/app-identity.d.ts +2 -2
- package/dist/app-name.d.ts +2 -0
- package/dist/auth-store.d.ts +3 -0
- package/dist/auth-store.js +3 -0
- package/dist/better-auth/auth-schema.d.ts +7 -8
- package/dist/better-auth/auth-schema.js +40 -42
- package/dist/better-auth/auth-settings.d.ts +8754 -0
- package/dist/better-auth/auth-settings.js +43 -0
- package/dist/better-auth/auth-tables.d.ts +1 -1
- package/dist/better-auth/auth-tables.js +11 -9
- package/dist/better-auth/authenticate-settings.d.ts +15 -0
- package/dist/better-auth/authenticate-settings.js +12 -0
- package/dist/better-auth/authenticator.d.ts +1 -1
- package/dist/better-auth/create-auth.d.ts +34 -14
- package/dist/better-auth/create-auth.js +27 -10
- package/dist/better-auth/mcp/mcp-auth-plugins.d.ts +2719 -0
- package/dist/better-auth/mcp/mcp-auth-plugins.js +68 -0
- package/dist/better-auth/mcp/mcp-plugins.d.ts +7 -2
- package/dist/better-auth/mcp/mcp-plugins.js +3 -68
- package/dist/better-auth/mcp/mcp-token-claims.js +1 -1
- package/dist/better-auth/organizations/store.d.ts +1 -0
- package/dist/better-auth/saml-plugin.d.ts +993 -0
- package/dist/better-auth/saml-plugin.js +36 -0
- package/dist/better-auth/saml-sign-in.d.ts +27 -1
- package/dist/better-auth/saml-sign-in.js +1 -33
- package/dist/better-auth/store/adoption.js +87 -0
- package/dist/better-auth/store/ddl.js +18 -0
- package/dist/better-auth/store/drift.d.ts +9 -0
- package/dist/better-auth/store/drift.js +18 -0
- package/dist/better-auth/store/migration-sql.js +15 -0
- package/dist/better-auth/store/migrations/001-core.js +80 -0
- package/dist/better-auth/store/migrations/002-two-factor.js +25 -0
- package/dist/better-auth/store/migrations/003-passkeys.js +29 -0
- package/dist/better-auth/store/migrations/004-sign-in-policy.js +22 -0
- package/dist/better-auth/store/migrations/005-staff-sign-in.js +25 -0
- package/dist/better-auth/store/migrations/006-organizations.js +50 -0
- package/dist/better-auth/store/migrations/007-mcp.js +150 -0
- package/dist/better-auth/store/migrations/index.js +22 -0
- package/dist/better-auth/store/migrations/migration.d.ts +3 -0
- package/dist/better-auth/store/migrations/migration.js +14 -0
- package/dist/better-auth/store/migrations-table.d.ts +7 -0
- package/dist/better-auth/store/migrations-table.js +23 -0
- package/dist/better-auth/store/resources-outside.d.ts +7 -0
- package/dist/better-auth/store/resources-outside.js +20 -0
- package/dist/better-auth/store/store-db.js +13 -0
- package/dist/better-auth/store/store-names.d.ts +2 -0
- package/dist/better-auth/store/store-names.js +14 -0
- package/dist/better-auth/store/table-names.d.ts +7 -0
- package/dist/better-auth/store/table-names.js +10 -0
- package/dist/better-auth/user-table.js +1 -1
- package/dist/better-auth/users.d.ts +2 -2
- package/dist/comments/comment-users.d.ts +1 -1
- package/dist/config-exports.d.ts +2 -0
- package/dist/config-exports.js +2 -0
- package/dist/create-admin.d.ts +6 -4
- package/dist/create-admin.js +3 -1
- package/dist/encryption/keyring.js +1 -1
- package/dist/files/options.d.ts +5 -8
- package/dist/files/provider-settings.d.ts +16 -0
- package/dist/files/provider-settings.js +17 -0
- package/dist/files/runtime.js +4 -4
- package/dist/forms/runtime.js +3 -3
- package/dist/index.d.ts +22 -19
- package/dist/index.js +11 -11
- package/dist/internal.d.ts +13 -0
- package/dist/internal.js +13 -0
- package/dist/jobs/declared-job.d.ts +24 -0
- package/dist/jobs/declared-job.js +26 -0
- package/dist/jobs/job-types.d.ts +2 -2
- package/dist/mcp/mcp-authenticator.js +3 -3
- package/dist/notifications/device-store-of.d.ts +2 -2
- package/dist/notifications/device-store-of.js +1 -1
- package/dist/notifications/device-store.d.ts +1 -1
- package/dist/notifications/device-store.js +1 -1
- package/dist/notifications/history-store-of.d.ts +2 -2
- package/dist/notifications/history-store-of.js +1 -1
- package/dist/notifications/history-store.d.ts +1 -1
- package/dist/notifications/history-store.js +1 -1
- package/dist/notifications/options.d.ts +3 -1
- package/dist/notifications/options.js +1 -1
- package/dist/notifications/schema.d.ts +3 -3
- package/dist/notifications/schema.js +8 -8
- package/dist/notifications/send-notification.js +1 -1
- package/dist/notifications/sender.d.ts +1 -1
- package/dist/notifications/sender.js +2 -2
- package/dist/notifications/senders-of.d.ts +1 -1
- package/dist/notifications/senders-of.js +1 -1
- package/dist/package.js +1 -1
- package/dist/webhooks/subscription.d.ts +1 -0
- package/dist/webhooks/table/options.d.ts +1 -1
- package/dist/webhooks/table/schema.d.ts +2 -2
- package/dist/webhooks/table/schema.js +2 -2
- package/dist/webhooks/table/webhook-table.js +2 -2
- package/dist/webhooks/table/webhooks-module.d.ts +108 -0
- package/dist/webhooks/table/webhooks-module.js +11 -0
- package/package.json +8 -5
- package/dist/better-auth/mcp/mcp-tables.js +0 -32
- package/dist/better-auth/snake-case-migration.js +0 -122
- package/dist/notifications/plugin.d.ts +0 -13
- package/dist/notifications/plugin.js +0 -16
- package/dist/project-config.d.ts +0 -54
- package/dist/project-config.js +0 -182
- package/dist/webhooks/table/plugin.d.ts +0 -10
- 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 {
|
|
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
|
|
79
|
-
import { s3FileStore
|
|
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,20 +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 {
|
|
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 {
|
|
96
|
+
import { betterAuthTokens } from "./better-auth/authenticator.js";
|
|
98
97
|
import { issueToken, maxTokenTtlSeconds } from "./better-auth/tokens.js";
|
|
99
|
-
import { authStoreTables } from "./better-auth/auth-tables.js";
|
|
100
98
|
import { authSchemaMigration, checkAuthSchema } from "./better-auth/auth-schema.js";
|
|
99
|
+
import { authSchemaDrift } from "./better-auth/store/drift.js";
|
|
100
|
+
import { authStoreTables } from "./better-auth/auth-tables.js";
|
|
101
|
+
import { checkResourcesOutsideAuthStore } from "./better-auth/store/resources-outside.js";
|
|
101
102
|
import { checkComputed, computedMigration } from "./computed/computed-schema.js";
|
|
102
|
-
import { webhooks } from "./webhooks/table/plugin.js";
|
|
103
103
|
import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.js";
|
|
104
104
|
import { checkAi } from "./ai/check-ai.js";
|
|
105
|
-
import { notifications } from "./notifications/plugin.js";
|
|
106
105
|
import { checkNotificationsSchema, notificationsMigration } from "./notifications/schema.js";
|
|
107
106
|
import { sendNotification } from "./notifications/send-notification.js";
|
|
108
107
|
import { maxWidgetPropsBytes, widget } from "./assistant/widget.js";
|
|
@@ -117,10 +116,11 @@ import { storeFile } from "./files/store-file.js";
|
|
|
117
116
|
import { createFileCleanup } from "./files/file-cleanup.js";
|
|
118
117
|
import { createEncryptionTools } from "./encryption/tools.js";
|
|
119
118
|
import { aspectRatio, fileSize, fileType, imageSize, processor } from "./files/processors.js";
|
|
119
|
+
import { enqueueJob } from "./jobs/declared-job.js";
|
|
120
120
|
import { defineEmail } from "./mail/define-email.js";
|
|
121
121
|
import { startJobs } from "./jobs/runtime.js";
|
|
122
122
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
123
123
|
import { composeRelease, releaseManifest } from "./mobile-release/release.js";
|
|
124
124
|
import { mobileReleaseApp } from "./mobile-release/release-app.js";
|
|
125
125
|
import { mobileSigningKeyVariable, readSigningKey } from "./mobile-release/signing-key.js";
|
|
126
|
-
export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables,
|
|
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 };
|
package/dist/internal.js
ADDED
|
@@ -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 };
|
package/dist/jobs/job-types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Mailer } from "../mail/smtp-mailer.js";
|
|
2
1
|
import { StandardSchema } from "../functions/read-json.js";
|
|
2
|
+
import { Mailer } from "../mail/smtp-mailer.js";
|
|
3
3
|
import { SendNotification } from "../notifications/send-input.js";
|
|
4
4
|
import { Db } from "@protobase/query";
|
|
5
5
|
//#region src/jobs/job-types.d.ts
|
|
@@ -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 (`
|
|
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("
|
|
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
|
|
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
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AdminAuth } from "../better-auth/create-auth.js";
|
|
2
1
|
import { DeviceStore } from "./device-store.js";
|
|
3
2
|
import { NotificationsOptions } from "./options.js";
|
|
3
|
+
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
|
|
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
|
|
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
|
|
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
|
|
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". */
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AdminAuth } from "../better-auth/create-auth.js";
|
|
2
1
|
import { HistoryStore } from "./history-store.js";
|
|
3
2
|
import { NotificationsOptions } from "./options.js";
|
|
3
|
+
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
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
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
|
|
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);
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { AdminAuth } from "../better-auth/create-auth.js";
|
|
2
1
|
import { NotificationsOptions } from "./options.js";
|
|
2
|
+
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
|
|
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
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { migrationCommand } from "../changes/capture-schema.js";
|
|
2
2
|
import { historyNames, notificationsNames } from "./options.js";
|
|
3
|
-
import { storeSchema } from "../better-auth/
|
|
3
|
+
import { storeSchema } from "../better-auth/store/store-names.js";
|
|
4
4
|
import { deviceSessionColumnSql, devicesTableSql, qualified } from "./schema-sql.js";
|
|
5
5
|
import { historyTableSql } from "./history-sql.js";
|
|
6
6
|
import { sql } from "kysely";
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
@@ -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 (`
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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),
|