@protobase/server 0.68.5 → 0.69.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/better-auth/auth-settings.d.ts +155 -28
- package/dist/better-auth/auth-settings.js +3 -2
- package/dist/better-auth/connections/connection-account-hooks.js +62 -0
- package/dist/better-auth/connections/connection-events.d.ts +11 -0
- package/dist/better-auth/connections/connection-events.js +16 -0
- package/dist/better-auth/connections/connection-oauth-provider.js +129 -0
- package/dist/better-auth/connections/connections-plugin.js +98 -0
- package/dist/better-auth/connections/declared-connections.d.ts +21 -0
- package/dist/better-auth/connections/declared-connections.js +54 -0
- package/dist/better-auth/connections/revoke-token.js +34 -0
- package/dist/better-auth/create-auth.d.ts +162 -17
- package/dist/better-auth/create-auth.js +59 -5
- package/dist/better-auth/refresh-refusals.js +43 -0
- package/dist/better-auth/staff-checks.js +1 -0
- package/dist/create-admin.js +11 -1
- package/dist/forms/rate-limit.js +33 -11
- package/dist/forms/routes.js +1 -1
- package/dist/functions/verify-signature.js +4 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3 -2
- package/dist/locale/en.js +3 -0
- package/dist/locale/nl.js +3 -0
- package/dist/mcp/mcp-tools.d.ts +2 -1
- package/dist/mcp/mcp-tools.js +4 -2
- package/dist/notifications/history-routes.js +1 -1
- package/dist/package.js +1 -1
- package/dist/personal-mail/linked-accounts.js +17 -13
- package/dist/types.d.ts +2 -0
- package/dist/webhooks/attempt.js +2 -2
- package/dist/webhooks/table/webhook-table.js +1 -1
- package/dist/workflows/connections/connection-accounts.js +18 -0
- package/dist/workflows/connections/connection-consent.js +49 -0
- package/dist/workflows/connections/connection-provider.js +10 -0
- package/dist/workflows/connections/connection-tokens.js +54 -0
- package/dist/workflows/connections/connection-triggers.js +37 -0
- package/dist/workflows/connections/connection-wiring.js +73 -0
- package/dist/workflows/connections/enabler-authority.js +35 -0
- package/dist/workflows/connections/enabler-mailbox.js +15 -0
- package/dist/workflows/connections/single-flight.js +17 -0
- package/dist/workflows/hooks/hook-auth.js +40 -0
- package/dist/workflows/hooks/hook-event.js +51 -0
- package/dist/workflows/hooks/hook-paths.d.ts +16 -0
- package/dist/workflows/hooks/hook-paths.js +32 -0
- package/dist/workflows/hooks/hook-route.js +99 -0
- package/dist/workflows/hooks/hook-runs.js +32 -0
- package/dist/workflows/hooks/hook-secrets.js +42 -0
- package/dist/workflows/hooks/hook-store.js +35 -0
- package/dist/workflows/hooks/hooks-sql.js +20 -0
- package/dist/workflows/hooks/issue-body.js +21 -0
- package/dist/workflows/hooks/issue-route.js +23 -0
- package/dist/workflows/hooks/issue-webhook.js +46 -0
- package/dist/workflows/hooks/read-body.js +32 -0
- package/dist/workflows/may-update-workflow.js +26 -0
- package/dist/workflows/mcp/webhook-tools.d.ts +9 -0
- package/dist/workflows/mcp/webhook-tools.js +103 -0
- package/dist/workflows/mcp/workflow-instructions.js +1 -1
- package/dist/workflows/mcp/workflow-read-tools.d.ts +3 -0
- package/dist/workflows/plugin-records.js +1 -1
- package/dist/workflows/plugin-services.js +1 -1
- package/dist/workflows/ready/ready-start.js +1 -1
- package/dist/workflows/run-files.js +7 -1
- package/dist/workflows/save-hook.js +7 -2
- package/dist/workflows/schema-sql.js +17 -3
- package/dist/workflows/schema.js +3 -1
- package/dist/workflows/start-workflow.d.ts +3 -1
- package/dist/workflows/start-workflow.js +10 -4
- package/dist/workflows/triggers/delete-hook.js +15 -0
- package/dist/workflows/triggers/plugin-call.js +45 -0
- package/dist/workflows/triggers/poll-job.js +120 -0
- package/dist/workflows/triggers/poll-result.js +32 -0
- package/dist/workflows/triggers/poll-schedule.js +32 -0
- package/dist/workflows/triggers/trigger-claim.js +81 -0
- package/dist/workflows/triggers/trigger-jobs.js +53 -7
- package/dist/workflows/triggers/trigger-start.js +112 -0
- package/dist/workflows/triggers/trigger-sync.js +15 -10
- package/dist/workflows/workflow-engine.js +57 -9
- package/dist/workflows/workflow-types.d.ts +11 -4
- package/dist/workflows/workflow-types.js +21 -15
- package/dist/write-shared.js +1 -0
- package/package.json +6 -6
- package/dist/better-auth/end-replaced-session.d.ts +0 -17
package/dist/index.d.ts
CHANGED
|
@@ -104,6 +104,7 @@ import { newWebhookSecret } from "./webhooks/standard-webhooks.js";
|
|
|
104
104
|
import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.js";
|
|
105
105
|
import { checkWorkflowsSchema, workflowsMigration } from "./workflows/schema.js";
|
|
106
106
|
import { StartWorkflowOptions, startWorkflow } from "./workflows/start-workflow.js";
|
|
107
|
+
import { hookPath, redactHookKeys, webhookIssuePath, webhookParams } from "./workflows/hooks/hook-paths.js";
|
|
107
108
|
import { checkUserTablesSchema, userTablesMigration } from "./user-tables/schema.js";
|
|
108
109
|
import { ownedDefinitionsMigration } from "./user-tables/owned-definitions.js";
|
|
109
110
|
import { UserTables, userTableResources } from "./user-tables/user-table-resources.js";
|
|
@@ -196,4 +197,4 @@ import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/ru
|
|
|
196
197
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
197
198
|
import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
|
|
198
199
|
import { AdminAuth, CreateAuthOptions, UserCreatedHook, normalizeRoles } from "./better-auth/create-auth.js";
|
|
199
|
-
export { type Admin, type AdminAuth, type AdminOptions, type AggregateParams, type ApiFunction, type ApiKeys, type ApiKeysOptions, type ApnsEnvironment, type AppIcons, type AppIdentity, type AppPoolConfig, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type ArgumentsPayload, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type AuthHooks, type AuthSettings, type AuthenticateSettings, type Authenticator, type BaseToolContext, type BatchOperation, type BatchResult, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type CallBackend, type CallMember, type Caller, type CallerOptions, type CallsAccess, type CallsOptions, type CapturedRow, type CascadingKey, type ChannelBroadcast, type ChannelSender, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentToolsInput, type CommentUsers, type Completion, type CompletionOptions, ConnectionsBusy, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DecryptField, type Device, type DeviceColumn, type DeviceKind, type DeviceStore, DeviceStoreError, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueJob, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldDecrypter, type FieldReader, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileProviderSettings, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryColumn, type HistoryOptions, type HistoryPosition, type HistoryStore, HistoryStoreError, type HookContext, HttpProblem, type IssueTokenOptions, type JobContext, type JobDeclaration, type JobDefinition, type JobName, type JobOptions, type JobPayload, type JobRun, type JobsRuntime, type JsonObject, type JsonValue, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LiveKitBackend, type LocalFilesOptions, type MailAttachment, type MailMessage, MailServerTimeoutError, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpApprovals, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type McpWrites, type MemberInput, type Membership, MissingCredentials, type MobileConfig, ModelError, type ModelSettings, type NewDevice, type NewNotification, type NewOrganization, type NewUser, type NotificationRecipients, NotificationSendError, type NotificationsOptions, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PdfComponent, type PdfOptions, type PdfTemplate, PersonalMailError, type PersonalMailErrorCode, type PersonalMailProviderId, type PgModule, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type PushAnswer, type PushMessage, PushMessageError, type PushSender, type QueryOptions, type QueryResult, type ReadableResources, type RealtimeOptions, type RealtimePrune, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordGroups, type RecordKey, 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 SendNotification, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StartWorkflowOptions, type StatusOptions, type StoreFileInput, type StoredMember, type StoredNotification, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolComment, type ToolCommentPage, type ToolComments, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type Urgency, type User, type UserCreatedHook, type UserTables, type VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, type WorkflowCatalog, type WorkflowTypes, type WorkflowsOptions, type WriteEvent, type WriteOperation, type WriteRecordToolsInput, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, callsMigration, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkCalls, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkUserTablesSchema, checkViewQueries, checkWebhooksSchema, checkWorkflowsSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, definePdf, defineTool, deleteRecordTool, deleteUser, describeResourceTool, 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, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, onDoNotDisturb, ownedDefinitionsMigration, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readDefinitionsVersion, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, reloadingAdmin, 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, sqlSends, startErrorReporting, startJobs, startWorkflow, statusMigration, statusNames, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, userTableResources, userTablesMigration, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, workflowInstructions, workflowReadTools, workflowTypes, workflowWriteTools, workflowsMigration, writeRecordTools };
|
|
200
|
+
export { type Admin, type AdminAuth, type AdminOptions, type AggregateParams, type ApiFunction, type ApiKeys, type ApiKeysOptions, type ApnsEnvironment, type AppIcons, type AppIdentity, type AppPoolConfig, type ApplyOptions, type ApplyResult, type ApprovalAnswer, type ApprovalRequest, type ArgumentsPayload, type AssistantBackend, type AssistantOptions, type AssistantSettings, type AssistantTool, type AuditEvent, type AuditQueue, type AuthHooks, type AuthSettings, type AuthenticateSettings, type Authenticator, type BaseToolContext, type BatchOperation, type BatchResult, type BetterAuthAuthenticator, type BetterAuthAuthenticatorOptions, type CallBackend, type CallMember, type Caller, type CallerOptions, type CallsAccess, type CallsOptions, type CapturedRow, type CascadingKey, type ChannelBroadcast, type ChannelSender, type ChatMessage, type ChatTextPart, type CheckAiInput, type CleanupEntry, type CleanupReport, type CleanupSchedule, type CoalescedChange, type CommentItem, type CommentToolsInput, type CommentUsers, type Completion, type CompletionOptions, ConnectionsBusy, type Conversation, type ConversationRecord, type ConversationStore, type ConversationsOptions, type CorsOptions, type CorsOrigins, type CreateAdminInput, type CreateAuthOptions, type DecryptField, type Device, type DeviceColumn, type DeviceKind, type DeviceStore, DeviceStoreError, type DrainResult, type EmailComponent, type EmailOptions, type EmailTemplate, type EncryptionStatus, type EncryptionTools, type EncryptionToolsInput, type EnqueueJob, type EnqueueOptions, type ErrorReporter, type ErrorReportingOptions, type ErrorReportingSettings, type EventData, type EventsOptions, FatalJobError, type FieldApplied, type FieldDecrypter, type FieldReader, type FieldStatus, type FileCleanupInput, type FileLimits, type FileObject, type FileProvider, type FileProviderSettings, type FileRef, type FileStore, type FileVariantObject, type FilesOptions, type FunctionApp, type FunctionCaller, type FunctionContext, type FunctionEnv, type FunctionHandler, type FunctionOptions, type FunctionRecords, type FunctionSocket, type FunctionSource, type HistoryColumn, type HistoryOptions, type HistoryPosition, type HistoryStore, HistoryStoreError, type HookContext, HttpProblem, type IssueTokenOptions, type JobContext, type JobDeclaration, type JobDefinition, type JobName, type JobOptions, type JobPayload, type JobRun, type JobsRuntime, type JsonObject, type JsonValue, type JwtOptions, type JwtVerifyOptions, type KeyFunctionContext, type LinkedAccount, type ListParams, type LiveKitBackend, type LocalFilesOptions, type MailAttachment, type MailMessage, MailServerTimeoutError, type Mailer, type MapLayer, type MapOptions, type MapSettings, type McpApprovals, type McpGateInput, type McpHandlerInput, type McpRoutesInput, type McpServerInput, type McpToolsInput, type McpWrites, type MemberInput, type Membership, MissingCredentials, type MobileConfig, ModelError, type ModelSettings, type NewDevice, type NewNotification, type NewOrganization, type NewUser, type NotificationRecipients, NotificationSendError, type NotificationsOptions, type OperatorProvider, type OrganizationRole, type OrganizationsOptions, type PdfComponent, type PdfOptions, type PdfTemplate, PersonalMailError, type PersonalMailErrorCode, type PersonalMailProviderId, type PgModule, type PipelineHook, type PlatformSignIn, type PluginOption, type PluginRef, type PngIcon, type ProtectedFunctionOptions, type PublicFunctionContext, type PublicFunctionEnv, type PublicFunctionHandler, type PublicFunctionOptions, type PushAnswer, type PushMessage, PushMessageError, type PushSender, type QueryOptions, type QueryResult, type ReadableResources, type RealtimeOptions, type RealtimePrune, type ReasoningDetail, type ReasoningEffort, type RebindOption, type RecordGroups, type RecordKey, 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 SendNotification, type Session, type SessionOrganization, type Sharp, type SignInPolicy, type SignInRule, type SignatureOptions, type SocketEvents, type SourceOption, type SourceRef, type StaffAccessRule, type StaffSignIn, type StandardSchema, type StandardWebhookOptions, type StartJobsOptions, type StartWorkflowOptions, type StatusOptions, type StoreFileInput, type StoredMember, type StoredNotification, type StoredObject, type StoredOrganization, type StoredUser, type StrayValues, type SubscriptionDefinition, type SubscriptionEvent, type SubscriptionOptions, type TenantValue, type ToolAnnotations, type ToolCall, type ToolComment, type ToolCommentPage, type ToolComments, type ToolContext, type ToolRecord, type ToolRecords, type ToolSpec, type TrustedApp, type TurnOptions, type UnreadableEntry, type Urgency, type User, type UserCreatedHook, type UserTables, type VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, type WorkflowCatalog, type WorkflowTypes, type WorkflowsOptions, type WriteEvent, type WriteOperation, type WriteRecordToolsInput, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, callsMigration, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkCalls, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkUserTablesSchema, checkViewQueries, checkWebhooksSchema, checkWorkflowsSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, definePdf, defineTool, deleteRecordTool, deleteUser, describeResourceTool, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, hookPath, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, onDoNotDisturb, ownedDefinitionsMigration, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readDefinitionsVersion, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, redactHookKeys, refusalOf, refused, relayed, reloadingAdmin, 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, sqlSends, startErrorReporting, startJobs, startWorkflow, statusMigration, statusNames, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, userTableResources, userTablesMigration, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhookIssuePath, webhookParams, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, workflowInstructions, workflowReadTools, workflowTypes, workflowWriteTools, workflowsMigration, writeRecordTools };
|
package/dist/index.js
CHANGED
|
@@ -68,6 +68,8 @@ import { recordOf, resourceChange } from "./changes/resource-change.js";
|
|
|
68
68
|
import { defineFunction } from "./functions/define-function.js";
|
|
69
69
|
import { newWebhookSecret } from "./webhooks/standard-webhooks.js";
|
|
70
70
|
import { subscription } from "./webhooks/subscription.js";
|
|
71
|
+
import { verifySignature, verifyStandardWebhook } from "./functions/verify-signature.js";
|
|
72
|
+
import { hookPath, redactHookKeys, webhookIssuePath, webhookParams } from "./workflows/hooks/hook-paths.js";
|
|
71
73
|
import { startWorkflow } from "./workflows/start-workflow.js";
|
|
72
74
|
import { workflowTypes } from "./workflows/workflow-types.js";
|
|
73
75
|
import { historyIdPattern, historyLimits } from "./notifications/history.js";
|
|
@@ -135,7 +137,6 @@ import { checkQueryRunner, queryRunnerMigration } from "./assistant/query-runner
|
|
|
135
137
|
import { startErrorReporting } from "./error-reporting/error-reporter.js";
|
|
136
138
|
import { functionApp } from "./functions/function-app.js";
|
|
137
139
|
import { readJson } from "./functions/read-json.js";
|
|
138
|
-
import { verifySignature, verifyStandardWebhook } from "./functions/verify-signature.js";
|
|
139
140
|
import { requireEnv } from "./functions/require-env.js";
|
|
140
141
|
import { storeFile } from "./files/store-file.js";
|
|
141
142
|
import { createFileCleanup } from "./files/file-cleanup.js";
|
|
@@ -146,4 +147,4 @@ import { defineEmail } from "./mail/define-email.js";
|
|
|
146
147
|
import { definePdf } from "./pdf/define-pdf.js";
|
|
147
148
|
import { startJobs } from "./jobs/runtime.js";
|
|
148
149
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
149
|
-
export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MailServerTimeoutError, MissingCredentials, ModelError, NotificationSendError, PersonalMailError, PushMessageError, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, callsMigration, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkCalls, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkUserTablesSchema, checkViewQueries, checkWebhooksSchema, checkWorkflowsSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, definePdf, defineTool, deleteRecordTool, deleteUser, describeResourceTool, 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, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, onDoNotDisturb, ownedDefinitionsMigration, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readDefinitionsVersion, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, reloadingAdmin, 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, sqlSends, startErrorReporting, startJobs, startWorkflow, statusMigration, statusNames, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, userTableResources, userTablesMigration, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, workflowInstructions, workflowReadTools, workflowTypes, workflowWriteTools, workflowsMigration, writeRecordTools };
|
|
150
|
+
export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MailServerTimeoutError, MissingCredentials, ModelError, NotificationSendError, PersonalMailError, PushMessageError, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, callsMigration, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkCalls, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkUserTablesSchema, checkViewQueries, checkWebhooksSchema, checkWorkflowsSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, definePdf, defineTool, deleteRecordTool, deleteUser, describeResourceTool, deviceIdParam, deviceStore, devicesPath, enqueueJob, errorReportingSettings, errorReportingVariable, eventMatcher, fileConversationStore, fileSize, fileType, forbidden, formatUri, functionApp, generateVapidKeys, getRecordTool, goTruePath, handleDroppedConnections, hasUsers, historyIdParam, historyIdPattern, historyLimits, historyPath, historyStore, honorSocketMessageCaps, hookPath, imageSize, isBackgroundWork, isCaptured, isJobDefinition, isOAuthWellKnownPath, isSchedule, issueToken, jobDefinitions, jobsDrainApp, jobsSchema, jobsSchemaMigration, jwtAuthenticator, jwtVerifier, limitedFileStore, listCommentsTool, listOrganizations, listRecordsTool, listResourcesTool, listUsers, localFileStore, longQueryTimeoutMs, mapSettings, mapStyleUrl, mapStyleVariable, maxDevicesPerUser, maxHistoryPage, maxMessageBytes, maxRecipients, maxTokenTtlSeconds, maxTtlSeconds, maxUnreadCount, maxWidgetPropsBytes, mcpApprovals, mcpGate, mcpHandler, mcpIcons, mcpInstructions, mcpRoutes, mcpServer, mcpToolContext, mcpTools, migrationCommand, newWebhookSecret, normalizeRoles, notFound, notificationSenders, notificationsMigration, oauthWellKnownPaths, objectKey, onDoNotDisturb, ownedDefinitionsMigration, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readDefinitionsVersion, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, redactHookKeys, refusalOf, refused, relayed, reloadingAdmin, 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, sqlSends, startErrorReporting, startJobs, startWorkflow, statusMigration, statusNames, storageCleanupSchedule, storageProvider, storeFile, storeUsage, streamChatCompletion, subscription, supabasePath, thumbHash, unauthorized, updateRecordTool, urgencies, userTableResources, userTablesMigration, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable, variantPath, verifySignature, verifyStandardWebhook, waitUntil, wantsLongQueries, webManifestPath, webPushSender, webauthnPath, webhookIssuePath, webhookParams, webhooksMigration, widget, withCacheBreakpoints, withTrustedApps, workflowInstructions, workflowReadTools, workflowTypes, workflowWriteTools, workflowsMigration, writeRecordTools };
|
package/dist/locale/en.js
CHANGED
|
@@ -26,6 +26,9 @@ var en_default = {
|
|
|
26
26
|
"hidden": "hidden",
|
|
27
27
|
"yes": "Yes",
|
|
28
28
|
"no": "No",
|
|
29
|
+
"webhookTitle": "Issue a new webhook URL for {record}?",
|
|
30
|
+
"webhookBody": "Its old URL stops at once, and the new URL and secret are shown to this client once.",
|
|
31
|
+
"issue": "Issue",
|
|
29
32
|
"createNamedAction": "Create {resource} \"{title}\""
|
|
30
33
|
},
|
|
31
34
|
"mcp/approval": {
|
package/dist/locale/nl.js
CHANGED
|
@@ -26,6 +26,9 @@ var nl_default = {
|
|
|
26
26
|
"hidden": "verborgen",
|
|
27
27
|
"yes": "Ja",
|
|
28
28
|
"no": "Nee",
|
|
29
|
+
"webhookTitle": "Een nieuwe webhook-URL uitgeven voor {record}?",
|
|
30
|
+
"webhookBody": "De oude URL werkt meteen niet meer, en de nieuwe URL en het geheim worden eenmalig aan deze client getoond.",
|
|
31
|
+
"issue": "Uitgeven",
|
|
29
32
|
"createNamedAction": "{resource} \"{title}\" aanmaken"
|
|
30
33
|
},
|
|
31
34
|
"mcp/approval": {
|
package/dist/mcp/mcp-tools.d.ts
CHANGED
|
@@ -21,7 +21,8 @@ export type McpToolsInput = {
|
|
|
21
21
|
commented?: string[];
|
|
22
22
|
/**
|
|
23
23
|
* Offers the workflow tools, for an app with `workflows`: reading workflows, their types and runs, and checking
|
|
24
|
-
* definitions against the app's types; with writes on, `create_workflow`, `update_workflow
|
|
24
|
+
* definitions against the app's types; with writes on, `create_workflow`, `update_workflow`, `run_workflow`,
|
|
25
|
+
* `enable_workflow` and `new_webhook_url` too.
|
|
25
26
|
* Off by default.
|
|
26
27
|
*/
|
|
27
28
|
workflows?: WorkflowCatalog;
|
package/dist/mcp/mcp-tools.js
CHANGED
|
@@ -7,6 +7,7 @@ import { batchWriteTool } from "../assistant/batch-write-tool.js";
|
|
|
7
7
|
import { commentTools } from "../assistant/comment-tools.js";
|
|
8
8
|
import { workflowReadTools } from "../workflows/mcp/workflow-read-tools.js";
|
|
9
9
|
import { workflowWriteTools } from "../workflows/mcp/workflow-write-tools.js";
|
|
10
|
+
import { webhookTools } from "../workflows/mcp/webhook-tools.js";
|
|
10
11
|
//#region src/mcp/mcp-tools.ts
|
|
11
12
|
const writeTools = (input) => [...writeRecordTools(input), batchWriteTool(input)];
|
|
12
13
|
const builtInNames = (db) => new Set([
|
|
@@ -21,7 +22,8 @@ const builtInNames = (db) => new Set([
|
|
|
21
22
|
triggers: {}
|
|
22
23
|
})
|
|
23
24
|
}),
|
|
24
|
-
...workflowWriteTools()
|
|
25
|
+
...workflowWriteTools(),
|
|
26
|
+
...webhookTools({}, () => Promise.reject(/* @__PURE__ */ new Error("Not called")))
|
|
25
27
|
].map((tool) => tool.name));
|
|
26
28
|
/** The app's own tools; one whose name is taken twice, or by a built-in tool, stops the server at startup. */
|
|
27
29
|
const checkedOwnTools = (db, own) => {
|
|
@@ -43,7 +45,7 @@ const mcpTools = ({ db, sql, writes, commented = [], workflows, own = [] }) => {
|
|
|
43
45
|
const limits = writes === false ? false : writes === true || !writes.resources ? {} : { resources: writes.resources };
|
|
44
46
|
const write = limits === false ? [] : writeTools(limits);
|
|
45
47
|
const comments = commentTools({ commented }, limits);
|
|
46
|
-
const flows = workflows ? [...workflowReadTools(workflows), ...limits === false ? [] : workflowWriteTools(limits)] : [];
|
|
48
|
+
const flows = workflows ? [...workflowReadTools(workflows), ...limits === false ? [] : [...workflowWriteTools(limits), ...webhookTools(limits, workflows.issueWebhook)]] : [];
|
|
47
49
|
const query = sql ? [readOnlyQueryTool(db)] : [];
|
|
48
50
|
return (session) => [
|
|
49
51
|
...read,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { badRequest } from "../problem.js";
|
|
2
|
+
import { ownSignInUser } from "./caller.js";
|
|
2
3
|
import { historyIdPattern } from "./history.js";
|
|
3
4
|
import "./history-store.js";
|
|
4
|
-
import { ownSignInUser } from "./caller.js";
|
|
5
5
|
import { historyCursor, historyPosition } from "./history-cursor.js";
|
|
6
6
|
import { jsonBody, jsonOnly, limitedBody, queryOf } from "./history-request.js";
|
|
7
7
|
import { historyUrl } from "./history-url.js";
|
package/dist/package.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { watchRefusals } from "../better-auth/refresh-refusals.js";
|
|
1
2
|
import { PersonalMailError } from "./personal-mail-error.js";
|
|
2
3
|
import { APIError } from "better-auth/api";
|
|
3
4
|
//#region src/personal-mail/linked-accounts.ts
|
|
@@ -5,7 +6,7 @@ const storedScopes = (scope) => (scope ?? "").split(/[\s,]+/).filter(Boolean);
|
|
|
5
6
|
/**
|
|
6
7
|
* The accounts Better Auth keeps, with the tokens it stores, decrypted when `encryptOAuthTokens` is on. Its
|
|
7
8
|
* `getAccessToken` refreshes a token within five seconds of expiry with the provider's refresh token and stores the new
|
|
8
|
-
* one; when the provider refuses the refresh, as for a revoked grant, that is `link_expired`.
|
|
9
|
+
* one; when the provider refuses the refresh token, as for a revoked grant, that is `link_expired`.
|
|
9
10
|
*/
|
|
10
11
|
const betterAuthLinkedAccounts = (auth) => ({
|
|
11
12
|
accounts: async (userId) => {
|
|
@@ -17,21 +18,24 @@ const betterAuthLinkedAccounts = (auth) => ({
|
|
|
17
18
|
}));
|
|
18
19
|
},
|
|
19
20
|
accessToken: async (userId, account, provider) => {
|
|
20
|
-
const accessToken = await
|
|
21
|
+
const accessToken = await accountAccessToken(auth, userId, account.id);
|
|
21
22
|
if (!accessToken) throw new PersonalMailError("link_expired", provider);
|
|
22
23
|
return accessToken;
|
|
23
24
|
}
|
|
24
25
|
});
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
26
|
+
/**
|
|
27
|
+
* A valid access token of the account, refreshed first when it expired; undefined when the provider refused the refresh
|
|
28
|
+
* token (`invalid_grant`) or the account holds none. A refresh that failed otherwise, as when the provider was down,
|
|
29
|
+
* throws, so the caller tries again later rather than asking the person to connect the account again.
|
|
30
|
+
*/
|
|
31
|
+
const accountAccessToken = async (auth, userId, accountId) => {
|
|
32
|
+
const answer = await watchRefusals(() => auth.api.getAccessToken({ body: {
|
|
33
|
+
accountId,
|
|
34
|
+
userId
|
|
35
|
+
} }));
|
|
36
|
+
if ("value" in answer) return answer.value.accessToken || void 0;
|
|
37
|
+
if (answer.refused && answer.error instanceof APIError && answer.error.body?.code === "FAILED_TO_GET_ACCESS_TOKEN") return;
|
|
38
|
+
throw answer.error;
|
|
35
39
|
};
|
|
36
40
|
//#endregion
|
|
37
|
-
export { betterAuthLinkedAccounts, storedScopes };
|
|
41
|
+
export { accountAccessToken, betterAuthLinkedAccounts, storedScopes };
|
package/dist/types.d.ts
CHANGED
|
@@ -76,6 +76,8 @@ export type WriteEvent = {
|
|
|
76
76
|
tenant?: TenantValue;
|
|
77
77
|
/** The writer is a visitor without a token, through a public form. */
|
|
78
78
|
anonymous?: true;
|
|
79
|
+
/** The writer's session as the API resolved it, for a hook that allows a write only for someone signed in as themselves (`ownSignInUser`). */
|
|
80
|
+
session: Session;
|
|
79
81
|
before?: Row;
|
|
80
82
|
after?: Row;
|
|
81
83
|
};
|
package/dist/webhooks/attempt.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { AddressRefusedError, pinnedRequest } from "./table/pinned-request.js";
|
|
2
|
+
import { readLimited } from "./table/read-limited.js";
|
|
1
3
|
import { invokeFunction } from "../functions/define-function.js";
|
|
2
4
|
import { retryAfterMs } from "./retry-schedule.js";
|
|
3
5
|
import { standardWebhookHeaders } from "./standard-webhooks.js";
|
|
4
6
|
import { subscriberSession } from "./subscriber-view.js";
|
|
5
|
-
import { AddressRefusedError, pinnedRequest } from "./table/pinned-request.js";
|
|
6
|
-
import { readLimited } from "./table/read-limited.js";
|
|
7
7
|
//#region src/webhooks/attempt.ts
|
|
8
8
|
/** How long a receiver has to answer. */
|
|
9
9
|
const attemptTimeoutMs = 15e3;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { betterAuthOwnerRoles } from "./owner-roles.js";
|
|
2
1
|
import { checkWebhookUrl } from "./address-check.js";
|
|
2
|
+
import { betterAuthOwnerRoles } from "./owner-roles.js";
|
|
3
3
|
import { webhooksSchema } from "./options.js";
|
|
4
4
|
import { tableSubscriptions } from "./table-subscriptions.js";
|
|
5
5
|
//#region src/webhooks/table/webhook-table.ts
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { accountAccessToken, storedScopes } from "../../personal-mail/linked-accounts.js";
|
|
2
|
+
//#region src/workflows/connections/connection-accounts.ts
|
|
3
|
+
/** The accounts Better Auth keeps, read through its internal adapter, with its refreshing `getAccessToken`. */
|
|
4
|
+
const betterAuthConnectionAccounts = (auth) => ({
|
|
5
|
+
find: async (userId, accountId) => {
|
|
6
|
+
const account = (await (await auth.$context).internalAdapter.findAccounts(userId)).find((candidate) => candidate.id === accountId);
|
|
7
|
+
if (!account) return;
|
|
8
|
+
return {
|
|
9
|
+
id: account.id,
|
|
10
|
+
providerId: account.providerId,
|
|
11
|
+
scopes: storedScopes(account.scope),
|
|
12
|
+
refreshToken: account.refreshToken ?? null
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
accessToken: (userId, accountId) => accountAccessToken(auth, userId, accountId)
|
|
16
|
+
});
|
|
17
|
+
//#endregion
|
|
18
|
+
export { betterAuthConnectionAccounts };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { badRequest, forbidden } from "../../problem.js";
|
|
2
|
+
import { connectionProviderId, holdsScopes } from "./connection-provider.js";
|
|
3
|
+
import { ownSignInUser } from "../../notifications/caller.js";
|
|
4
|
+
import { sql } from "kysely";
|
|
5
|
+
import { usedConnections } from "@protobase/workflows";
|
|
6
|
+
//#region src/workflows/connections/connection-consent.ts
|
|
7
|
+
/** The refusal of every account the caller may not turn on, the same whether it exists or not. */
|
|
8
|
+
const notOwnConnection = () => forbidden("own-sign-in-only", "Only the owner of each connection this workflow uses, signed in as themselves, can turn it on: turn it off to save it, and its owner turns it on again in the admin app");
|
|
9
|
+
/**
|
|
10
|
+
* Turning a version on is the consent that lets its runs sign in through the accounts it binds: it is refused unless
|
|
11
|
+
* the caller is signed in as themselves (not staff signed in as them, nor an outside app acting for them) and owns
|
|
12
|
+
* every bound account, of its connection's provider and holding its scopes. Returns who consented, which the version
|
|
13
|
+
* keeps as `enabled_by`: the caller when they are signed in as themselves, else nobody, as for a version that binds
|
|
14
|
+
* no account turned on by an outside app.
|
|
15
|
+
*/
|
|
16
|
+
const connectionConsent = ({ accounts, declarationOf, connectionOf }) => async (session, definition) => {
|
|
17
|
+
const keys = [...usedConnections(definition, connectionOf)];
|
|
18
|
+
if (keys.length === 0) {
|
|
19
|
+
if (session.anonymous || session.client || session.signIn?.staff !== false) return null;
|
|
20
|
+
return String(session.user.id);
|
|
21
|
+
}
|
|
22
|
+
const unbound = keys.filter((key) => !definition.connections?.[key]);
|
|
23
|
+
if (unbound.length > 0) throw badRequest("invalid-workflow", `Connect an account for ${unbound.join(", ")} in the workflow's connections before turning it on`);
|
|
24
|
+
const userId = ownSignInUser(session, "turn on a workflow that signs in through their connection");
|
|
25
|
+
for (const key of keys) {
|
|
26
|
+
const declaration = declarationOf(key);
|
|
27
|
+
const [plugin, name] = key.split(":");
|
|
28
|
+
const account = await accounts.find(userId, definition.connections[key]);
|
|
29
|
+
if (!account || account.providerId !== connectionProviderId(plugin, name, declaration) || !holdsScopes(account.scopes, declaration)) throw notOwnConnection();
|
|
30
|
+
}
|
|
31
|
+
return userId;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Keeps who turned a version on, as its runs' steps read it, and withdraws the consent when the workflow is turned
|
|
35
|
+
* off: every version's runs then sign in through no account until it is turned on again. Someone else turning a
|
|
36
|
+
* version on withdraws the earlier person's consent on every other version, so a waiting run of one of them signs in
|
|
37
|
+
* through no account of theirs; the earlier versions the same person turned on keep it.
|
|
38
|
+
*/
|
|
39
|
+
const saveConsent = async (trx, schema, workflowId, enabled, enabledBy) => {
|
|
40
|
+
const versions = sql.id(schema, "versions");
|
|
41
|
+
if (enabled === null) {
|
|
42
|
+
await sql`update ${versions} set enabled_by = null where workflow_id = ${workflowId} and enabled_by is not null`.execute(trx);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
await sql`update ${versions} set enabled_by = null where workflow_id = ${workflowId} and version <> ${enabled} and enabled_by is distinct from ${enabledBy}`.execute(trx);
|
|
46
|
+
await sql`update ${versions} set enabled_by = ${enabledBy} where workflow_id = ${workflowId} and version = ${enabled}`.execute(trx);
|
|
47
|
+
};
|
|
48
|
+
//#endregion
|
|
49
|
+
export { connectionConsent, notOwnConnection, saveConsent };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/workflows/connections/connection-provider.ts
|
|
2
|
+
/**
|
|
3
|
+
* The Better Auth provider id a connection's accounts are kept under: the app's sign-in provider it names, or one of
|
|
4
|
+
* its own, `workflow-<plugin>-<connection>`, for an `oauth` connection; plugin and connection names hold no `-`.
|
|
5
|
+
*/
|
|
6
|
+
const connectionProviderId = (plugin, name, declaration) => "signIn" in declaration ? declaration.signIn : `workflow-${plugin}-${name}`;
|
|
7
|
+
/** Whether an account's stored scopes hold every scope the connection asks for. */
|
|
8
|
+
const holdsScopes = (stored, declaration) => (declaration.scopes ?? []).every((scope) => stored.includes(scope));
|
|
9
|
+
//#endregion
|
|
10
|
+
export { connectionProviderId, holdsScopes };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { connectionProviderId, holdsScopes } from "./connection-provider.js";
|
|
2
|
+
import { enablerMayUpdate } from "./enabler-authority.js";
|
|
3
|
+
import { singleFlight } from "./single-flight.js";
|
|
4
|
+
import { sql } from "kysely";
|
|
5
|
+
import { ConnectionError } from "@protobase/workflows/plugin";
|
|
6
|
+
//#region src/workflows/connections/connection-tokens.ts
|
|
7
|
+
/**
|
|
8
|
+
* An account's valid access token, refreshed when it expired, with overlapping refreshes of one account joined into
|
|
9
|
+
* one. Another worker may rotate the refresh token between this one's read (`before`, the stored refresh token) and its
|
|
10
|
+
* refresh, which the provider then refuses: reading the account once more tells that apart, and the stored token is
|
|
11
|
+
* then the fresh one. Undefined when the provider refused it.
|
|
12
|
+
*/
|
|
13
|
+
const sharedRefresh = (accounts) => {
|
|
14
|
+
const refresh = singleFlight();
|
|
15
|
+
return async (userId, accountId, before) => {
|
|
16
|
+
const token = await refresh(accountId, () => accounts.accessToken(userId, accountId));
|
|
17
|
+
if (token) return token;
|
|
18
|
+
const after = await accounts.find(userId, accountId);
|
|
19
|
+
if (!after || after.refreshToken === before) return;
|
|
20
|
+
return refresh(accountId, () => accounts.accessToken(userId, accountId));
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The connection a step or trigger declared, bound by its workflow. Each `accessToken()` checks afresh, caching nothing:
|
|
25
|
+
* the version it runs binds an account to the connection, the person who turned that version on owns that account of
|
|
26
|
+
* the connection's provider with its scopes, and may still update the workflow in its tenant. Anything else is
|
|
27
|
+
* `not_connected`, with one message that tells nothing of whether the account exists; a refresh the provider refuses
|
|
28
|
+
* is `link_expired`. The token is blanked out of all the step records (`secret`).
|
|
29
|
+
*/
|
|
30
|
+
const connectionTokens = ({ deps, schema, roles, accounts }) => {
|
|
31
|
+
const tokenOf = sharedRefresh(accounts);
|
|
32
|
+
return (use) => {
|
|
33
|
+
const key = `${use.plugin}:${use.name}`;
|
|
34
|
+
const notConnected = () => new ConnectionError("not_connected", `This workflow has no connection it may use for ${key}: its owner connects an account and turns the workflow on`);
|
|
35
|
+
return { accessToken: async () => {
|
|
36
|
+
const ref = await use.version();
|
|
37
|
+
if (!ref) throw notConnected();
|
|
38
|
+
const db = deps().db;
|
|
39
|
+
const { rows } = await sql`select v.definition -> 'connections' ->> ${key} as account, v.enabled_by, v.tenant_id
|
|
40
|
+
from ${sql.id(schema, "versions")} v where v.workflow_id = ${ref.workflowId} and v.version = ${ref.version}`.execute(db);
|
|
41
|
+
const consent = rows[0];
|
|
42
|
+
if (!consent?.account || !consent.enabled_by) throw notConnected();
|
|
43
|
+
if (!await enablerMayUpdate(db, deps(), roles, consent.enabled_by, consent.tenant_id ?? void 0, ref.workflowId)) throw notConnected();
|
|
44
|
+
const account = await accounts.find(consent.enabled_by, consent.account);
|
|
45
|
+
if (!account || account.providerId !== connectionProviderId(use.plugin, use.name, use.declaration) || !holdsScopes(account.scopes, use.declaration)) throw notConnected();
|
|
46
|
+
const token = await tokenOf(consent.enabled_by, account.id, account.refreshToken);
|
|
47
|
+
if (!token) throw new ConnectionError("link_expired", `The account connected for ${key} no longer signs in: its owner connects it again`);
|
|
48
|
+
use.secret(token);
|
|
49
|
+
return token;
|
|
50
|
+
} };
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { connectionTokens, sharedRefresh };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { sql } from "kysely";
|
|
2
|
+
//#region src/workflows/connections/connection-triggers.ts
|
|
3
|
+
/**
|
|
4
|
+
* The triggers of connected accounts, as sign-in tells of them: a link resumes the triggers waiting on that account's
|
|
5
|
+
* sign-in, which poll again from the cursor they kept or renew the subscription they kept; a disconnect makes the
|
|
6
|
+
* running ones wait for a new sign-in.
|
|
7
|
+
*/
|
|
8
|
+
const connectionTriggers = (db, schema, jobs) => {
|
|
9
|
+
const triggers = sql.id(schema, "triggers");
|
|
10
|
+
return {
|
|
11
|
+
linked: async (accountId) => {
|
|
12
|
+
await db().transaction().execute(async (trx) => {
|
|
13
|
+
const { rows } = await sql`update ${triggers} set status = 'active', consecutive_failures = 0, last_error = null, updated_at = now()
|
|
14
|
+
where connection_id = ${accountId} and status = 'needs_sign_in' returning id, generation`.execute(trx);
|
|
15
|
+
for (const row of rows) await jobs.start.enqueue(trx, {
|
|
16
|
+
trigger: row.id,
|
|
17
|
+
generation: row.generation
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
disconnected: async (accountId) => {
|
|
22
|
+
const error = JSON.stringify({
|
|
23
|
+
code: "link_expired",
|
|
24
|
+
message: "The connected account was disconnected: its owner connects it again",
|
|
25
|
+
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
26
|
+
});
|
|
27
|
+
await sql`update ${triggers} set status = 'needs_sign_in', last_error = ${error}::jsonb, poll_job_id = null, poll_attempt = null, next_poll_at = null, updated_at = now()
|
|
28
|
+
where connection_id = ${accountId} and status in ('active', 'failing')`.execute(db());
|
|
29
|
+
},
|
|
30
|
+
needsSignIn: async (accountIds) => {
|
|
31
|
+
const { rows } = await sql`select distinct connection_id from ${triggers} where status = 'needs_sign_in' and connection_id in (${sql.join(accountIds)})`.execute(db());
|
|
32
|
+
return rows.map((row) => row.connection_id);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
//#endregion
|
|
37
|
+
export { connectionTriggers };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { connectionConsent } from "./connection-consent.js";
|
|
2
|
+
import { enablerMayUpdate } from "./enabler-authority.js";
|
|
3
|
+
import { enablerMailbox } from "./enabler-mailbox.js";
|
|
4
|
+
import { connectionTokens } from "./connection-tokens.js";
|
|
5
|
+
import { sql } from "kysely";
|
|
6
|
+
import { ConnectionError } from "@protobase/workflows/plugin";
|
|
7
|
+
//#region src/workflows/connections/connection-wiring.ts
|
|
8
|
+
const noAccounts = {
|
|
9
|
+
find: async () => void 0,
|
|
10
|
+
accessToken: async () => void 0
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* The connections of an app's workflows: the consent a save checks as a version is turned on, and the connection each
|
|
14
|
+
* step and trigger that declares one gets, bound by the version its run or trigger runs.
|
|
15
|
+
*/
|
|
16
|
+
const connectionWiring = ({ deps, schema, roles, accounts = noAccounts, plugins, connectionOf, personalMailer }) => {
|
|
17
|
+
const declarationOf = (key) => {
|
|
18
|
+
const [plugin, name] = key.split(":");
|
|
19
|
+
return plugins.find((candidate) => candidate.name === plugin)?.connections?.[name];
|
|
20
|
+
};
|
|
21
|
+
const consent = connectionConsent({
|
|
22
|
+
accounts,
|
|
23
|
+
declarationOf,
|
|
24
|
+
connectionOf
|
|
25
|
+
});
|
|
26
|
+
const tokens = connectionTokens({
|
|
27
|
+
deps,
|
|
28
|
+
schema,
|
|
29
|
+
roles,
|
|
30
|
+
accounts
|
|
31
|
+
});
|
|
32
|
+
const use = (type, version, secret) => {
|
|
33
|
+
const key = connectionOf[type];
|
|
34
|
+
const declaration = key === void 0 ? void 0 : declarationOf(key);
|
|
35
|
+
if (!key || !declaration) return;
|
|
36
|
+
const [plugin, name] = key.split(":");
|
|
37
|
+
return tokens({
|
|
38
|
+
plugin,
|
|
39
|
+
name,
|
|
40
|
+
declaration,
|
|
41
|
+
version,
|
|
42
|
+
secret
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const runVersion = async (runId) => {
|
|
46
|
+
const { rows } = await sql`select workflow_id, version from ${sql.id(schema, "runs")} where id = ${runId}`.execute(deps().db);
|
|
47
|
+
const run = rows[0];
|
|
48
|
+
return run?.version == null ? void 0 : {
|
|
49
|
+
workflowId: run.workflow_id,
|
|
50
|
+
version: run.version
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
const step = (stepId, name, task) => use(stepId, () => runVersion(task.runId), task.secret) ?? { accessToken: () => Promise.reject(new ConnectionError("not_connected", `${stepId} signs in through "${name}", which this app does not declare`)) };
|
|
54
|
+
const trigger = (row, secret) => use(row.type, async () => row.workflow_id === null ? void 0 : {
|
|
55
|
+
workflowId: row.workflow_id,
|
|
56
|
+
version: row.version
|
|
57
|
+
}, secret);
|
|
58
|
+
const runEnabler = async (runId) => {
|
|
59
|
+
const { rows } = await sql`select r.workflow_id, v.enabled_by, v.tenant_id from ${sql.id(schema, "runs")} r
|
|
60
|
+
join ${sql.id(schema, "versions")} v on v.workflow_id = r.workflow_id and v.version = r.version where r.id = ${runId}`.execute(deps().db);
|
|
61
|
+
const row = rows[0];
|
|
62
|
+
if (!row?.enabled_by) return null;
|
|
63
|
+
return await enablerMayUpdate(deps().db, deps(), roles, row.enabled_by, row.tenant_id ?? void 0, row.workflow_id) ? row.enabled_by : null;
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
consent,
|
|
67
|
+
step,
|
|
68
|
+
trigger,
|
|
69
|
+
mailbox: personalMailer && ((task) => enablerMailbox(() => runEnabler(task.runId), personalMailer))
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
//#endregion
|
|
73
|
+
export { connectionWiring };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { requestAccess } from "../../request-access.js";
|
|
2
|
+
import { deletedRows } from "../../params.js";
|
|
3
|
+
import { fetchReadable } from "../../fetch-readable.js";
|
|
4
|
+
import { mayUpdateWorkflow } from "../may-update-workflow.js";
|
|
5
|
+
//#region src/workflows/connections/enabler-authority.ts
|
|
6
|
+
/**
|
|
7
|
+
* Whether the person who turned a workflow on may still do so: with the roles they hold now in its tenant, they may
|
|
8
|
+
* read this one and update it, as its update row filter and record-level rule decide. Losing either, as when they were
|
|
9
|
+
* demoted or left the organization, withdraws the connection their consent gave its runs.
|
|
10
|
+
*/
|
|
11
|
+
const enablerMayUpdate = async (db, deps, roles, enabledBy, tenant, workflowId) => {
|
|
12
|
+
const held = await roles({
|
|
13
|
+
id: enabledBy,
|
|
14
|
+
...tenant !== void 0 && { tenant }
|
|
15
|
+
});
|
|
16
|
+
if (held.length === 0) return false;
|
|
17
|
+
const entry = deps.registry.find("workflows");
|
|
18
|
+
const session = {
|
|
19
|
+
user: {
|
|
20
|
+
id: enabledBy,
|
|
21
|
+
roles: held
|
|
22
|
+
},
|
|
23
|
+
...tenant !== void 0 && {
|
|
24
|
+
tenant,
|
|
25
|
+
organization: { id: tenant }
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const access = await requestAccess(deps, entry, session);
|
|
29
|
+
if (!access.resolved.operations.update) return false;
|
|
30
|
+
const found = await fetchReadable(db, access, [workflowId], deletedRows(access.full, false), {});
|
|
31
|
+
if (!found) return false;
|
|
32
|
+
return mayUpdateWorkflow(db, access, workflowId, found.record);
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { enablerMayUpdate };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { PersonalMailError } from "../../personal-mail/personal-mail-error.js";
|
|
2
|
+
//#region src/workflows/connections/enabler-mailbox.ts
|
|
3
|
+
/**
|
|
4
|
+
* The step context's `mailbox`: each message goes out from the own mailbox of the person who turned the run's version
|
|
5
|
+
* on, signed in as themselves, as `enablerOf` reads them afresh; nobody (a version an outside app turned on, a workflow
|
|
6
|
+
* turned off, or someone who may no longer change it) sends nothing and fails `not_linked`. A job's own code gets no
|
|
7
|
+
* such mailer: only this consent lets mail leave someone's mailbox without their own request.
|
|
8
|
+
*/
|
|
9
|
+
const enablerMailbox = (enablerOf, personalMailer) => ({ send: async (message) => {
|
|
10
|
+
const enabledBy = await enablerOf();
|
|
11
|
+
if (!enabledBy) throw new PersonalMailError("not_linked");
|
|
12
|
+
await personalMailer(enabledBy).send(message);
|
|
13
|
+
} });
|
|
14
|
+
//#endregion
|
|
15
|
+
export { enablerMailbox };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/workflows/connections/single-flight.ts
|
|
2
|
+
/**
|
|
3
|
+
* Joins calls of one key that overlap: the second waits for the first's result instead of starting its own, such as a
|
|
4
|
+
* second refresh of one account's token. An entry lives only while its call runs, so the map holds the calls in flight.
|
|
5
|
+
*/
|
|
6
|
+
const singleFlight = () => {
|
|
7
|
+
const running = /* @__PURE__ */ new Map();
|
|
8
|
+
return (key, call) => {
|
|
9
|
+
const joined = running.get(key);
|
|
10
|
+
if (joined) return joined;
|
|
11
|
+
const started = call().finally(() => running.delete(key));
|
|
12
|
+
running.set(key, started);
|
|
13
|
+
return started;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { singleFlight };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { HttpProblem } from "../../problem.js";
|
|
2
|
+
import { verifySignature, verifyStandardWebhook } from "../../functions/verify-signature.js";
|
|
3
|
+
import { bearerMatches, usableSecret } from "./hook-secrets.js";
|
|
4
|
+
//#region src/workflows/hooks/hook-auth.ts
|
|
5
|
+
/** The hmac options of a trigger's `auth`, and the header its signature comes in, which the run never sees. */
|
|
6
|
+
const hmacOptions = (input) => input.auth ?? {};
|
|
7
|
+
const verified = (check) => check.then(() => true, (error) => {
|
|
8
|
+
if (error instanceof HttpProblem && error.status === 401) return false;
|
|
9
|
+
throw error;
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* Whether the call proves it comes from the sender, by the trigger's mode: a Standard Webhooks signature within five
|
|
13
|
+
* minutes, an HMAC of the body in the configured header, or the bearer secret. A secret the mode cannot check with, as
|
|
14
|
+
* after the mode changed since the URL was issued, proves nothing. `signed` holds the bytes already read.
|
|
15
|
+
*/
|
|
16
|
+
const authenticated = async (signed, mode, hook) => {
|
|
17
|
+
if (mode === "bearer") {
|
|
18
|
+
const token = /^Bearer (.+)$/.exec(signed.headers.get("authorization") ?? "")?.[1];
|
|
19
|
+
return token !== void 0 && bearerMatches(token, hook.secret_hash);
|
|
20
|
+
}
|
|
21
|
+
if (!usableSecret(mode, hook.secret)) return false;
|
|
22
|
+
if (mode === "standard_webhooks") return verified(verifyStandardWebhook(signed, { secret: hook.secret }));
|
|
23
|
+
const { header, prefix, encoding, hash } = hmacOptions(hook.input);
|
|
24
|
+
if (!header) return false;
|
|
25
|
+
return verified(verifySignature(signed, {
|
|
26
|
+
secret: hook.secret,
|
|
27
|
+
header,
|
|
28
|
+
...prefix !== void 0 && { prefix },
|
|
29
|
+
...encoding && { encoding },
|
|
30
|
+
...hash && { hash }
|
|
31
|
+
}));
|
|
32
|
+
};
|
|
33
|
+
/** The key a call starts its run once under: the signed `webhook-id`, or the configured idempotency header's value. */
|
|
34
|
+
const idempotencyKey = (request, mode, input) => {
|
|
35
|
+
if (mode === "standard_webhooks") return request.headers.get("webhook-id") ?? void 0;
|
|
36
|
+
const header = input.idempotency_header;
|
|
37
|
+
return typeof header === "string" ? request.headers.get(header) ?? void 0 : void 0;
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { authenticated, hmacOptions, idempotencyKey };
|