@protobase/server 0.59.1 → 0.59.3
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/store/migrations-table.js +1 -1
- package/dist/channels/binary-frame.js +44 -0
- package/dist/channels/channel-protocol.js +16 -3
- package/dist/channels/channel-refusals.js +1 -1
- package/dist/channels/channel-routes.js +22 -9
- package/dist/channels/channel-sender.d.ts +1 -1
- package/dist/channels/channel-sender.js +24 -12
- package/dist/channels/channel-socket.js +12 -7
- package/dist/channels/database-sends.js +57 -0
- package/dist/channels/sends-prune.js +15 -0
- package/dist/channels/sends-schema-sql.js +30 -0
- package/dist/channels/sends-schema.d.ts +7 -0
- package/dist/channels/sends-schema.js +18 -0
- package/dist/channels/sent.js +17 -1
- package/dist/create-admin.d.ts +5 -2
- package/dist/create-admin.js +33 -4
- package/dist/deps.d.ts +2 -0
- package/dist/index.d.ts +6 -2
- package/dist/index.js +6 -2
- package/dist/internal.d.ts +2 -1
- package/dist/internal.js +2 -1
- package/dist/meta.d.ts +2 -0
- package/dist/meta.js +1 -0
- package/dist/notifications/caller.js +2 -2
- package/dist/notifications/deliver.js +14 -2
- package/dist/notifications/push-job.js +5 -3
- package/dist/notifications/schema.js +7 -4
- package/dist/package.js +1 -1
- package/dist/realtime/database-broadcasts.js +2 -25
- package/dist/realtime/followed-poll.js +34 -0
- package/dist/realtime/realtime-prune.d.ts +5 -3
- package/dist/realtime/realtime-prune.js +8 -3
- package/dist/realtime/relay/realtime-options.d.ts +7 -0
- package/dist/realtime/relay/realtime-options.js +7 -1
- package/dist/status/do-not-disturb.d.ts +9 -0
- package/dist/status/do-not-disturb.js +15 -0
- package/dist/status/options.d.ts +15 -0
- package/dist/status/options.js +25 -0
- package/dist/status/routes.js +38 -0
- package/dist/status/schema-sql.js +19 -0
- package/dist/status/schema.d.ts +12 -0
- package/dist/status/schema.js +33 -0
- package/dist/status/status-input.js +33 -0
- package/dist/status/status-store.js +39 -0
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MobileConfig } from "./mobile-config.js";
|
|
2
2
|
import { AppIdentity } from "./app-identity.js";
|
|
3
3
|
import { AppIcons, PngIcon, pngIcons } from "./web-app/app-icons.js";
|
|
4
|
-
import { RealtimeOptions, relayed } from "./realtime/relay/realtime-options.js";
|
|
4
|
+
import { RealtimeOptions, relayed, sqlSends } from "./realtime/relay/realtime-options.js";
|
|
5
5
|
import { EventsOptions } from "./changes/events-options.js";
|
|
6
6
|
import { DecryptField, FieldDecrypter, FieldReader, RecordKey } from "./encryption/decrypt-field-types.js";
|
|
7
7
|
import { StandardSchema, readJson } from "./functions/read-json.js";
|
|
@@ -22,6 +22,7 @@ import { HistoryStore, maxHistoryPage, maxUnreadCount } from "./notifications/hi
|
|
|
22
22
|
import { PushAnswer, PushSender } from "./notifications/sender.js";
|
|
23
23
|
import { DeviceColumn, HistoryColumn, NotificationsOptions } from "./notifications/options.js";
|
|
24
24
|
import { CallBackend, CallsOptions, LiveKitBackend } from "./calls/calls-options.js";
|
|
25
|
+
import { StatusOptions, statusNames } from "./status/options.js";
|
|
25
26
|
import { EventData, RunContext, SubscriptionDefinition, SubscriptionEvent, SubscriptionOptions, subscription } from "./webhooks/subscription.js";
|
|
26
27
|
import { Sharp, renderVariant, thumbHash } from "./files/images.js";
|
|
27
28
|
import { FileProvider, FileStore, StoredObject } from "./files/store.js";
|
|
@@ -101,6 +102,7 @@ import { parseColumns, readOutbox } from "./changes/outbox.js";
|
|
|
101
102
|
import { newWebhookSecret } from "./webhooks/standard-webhooks.js";
|
|
102
103
|
import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.js";
|
|
103
104
|
import { checkRealtimeRelay, realtimeRelayMigration } from "./realtime/relay/relay-schema.js";
|
|
105
|
+
import { channelSendsMigration, checkChannelSends } from "./channels/sends-schema.js";
|
|
104
106
|
import { checkComments, commentsMigration } from "./comments/comments-sql.js";
|
|
105
107
|
import { CheckAiInput, checkAi } from "./ai/check-ai.js";
|
|
106
108
|
import { CommentItem } from "./comments/comment-item.js";
|
|
@@ -117,6 +119,8 @@ import { sendNotification } from "./notifications/send-notification.js";
|
|
|
117
119
|
import { VapidSettings, readVapidSettings, vapidPrivateKeyVariable, vapidPublicKeyVariable, vapidSubjectVariable } from "./notifications/web-push/vapid-settings.js";
|
|
118
120
|
import { WebPushOptions, webPushSender } from "./notifications/web-push/web-push-sender.js";
|
|
119
121
|
import { generateVapidKeys } from "./notifications/web-push/keys.js";
|
|
122
|
+
import { checkStatusSchema, statusMigration } from "./status/schema.js";
|
|
123
|
+
import { onDoNotDisturb } from "./status/do-not-disturb.js";
|
|
120
124
|
import { MemberInput, NewOrganization, addAppRoleToOwners, addMember, createOrganization, listOrganizations, removeMember, setMemberRoles } from "./better-auth/organizations/host.js";
|
|
121
125
|
import { AssistantBackend, assistantProtocolRoutes } from "./assistant/protocol-routes.js";
|
|
122
126
|
import { fileConversationStore } from "./assistant/file-conversation-store.js";
|
|
@@ -175,4 +179,4 @@ import { DrainResult, JobsRuntime, StartJobsOptions, startJobs } from "./jobs/ru
|
|
|
175
179
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
176
180
|
import { checkJobsSchema, jobsSchema, jobsSchemaMigration } from "./jobs/schema.js";
|
|
177
181
|
import { AdminAuth, CreateAuthOptions, UserCreatedHook, normalizeRoles } from "./better-auth/create-auth.js";
|
|
178
|
-
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 MailMessage, 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 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 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 VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, 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, capSocketMessages, changesMigration, checkAi, checkAuthSchema, checkChanges, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, 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, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, 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 };
|
|
182
|
+
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 MailMessage, 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 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 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 VapidSettings, type ViewSource, type WebPushFields, type WebPushOptions, type WebhooksOptions, type WidgetOptions, 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, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, 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, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, 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, statusMigration, statusNames, 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 };
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import { apiKeySettings, apiKeyVariables } from "./api-keys/api-key-settings.js"
|
|
|
25
25
|
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
|
-
import { relayed } from "./realtime/relay/realtime-options.js";
|
|
28
|
+
import { relayed, sqlSends } from "./realtime/relay/realtime-options.js";
|
|
29
29
|
import { backgroundSettled, waitUntil } from "./functions/wait-until.js";
|
|
30
30
|
import { objectKey } from "./storage/object-key.js";
|
|
31
31
|
import { appNameOver, defaultAppName, shownAppName } from "./app-name.js";
|
|
@@ -78,6 +78,8 @@ import { readVapidSettings, vapidPrivateKeyVariable, vapidPublicKeyVariable, vap
|
|
|
78
78
|
import { webPushSender } from "./notifications/web-push/web-push-sender.js";
|
|
79
79
|
import { notificationSenders } from "./notifications/senders-of.js";
|
|
80
80
|
import { NotificationSendError, maxMessageBytes, maxRecipients } from "./notifications/send-input.js";
|
|
81
|
+
import { onDoNotDisturb } from "./status/do-not-disturb.js";
|
|
82
|
+
import { statusNames } from "./status/options.js";
|
|
81
83
|
import { errorReportingSettings, errorReportingVariable } from "./error-reporting/error-reporting-settings.js";
|
|
82
84
|
import { storageCleanupSchedule } from "./files/cleanup-schedule.js";
|
|
83
85
|
import { limitedFileStore, storeUsage } from "./files/limits.js";
|
|
@@ -109,9 +111,11 @@ import { checkResourcesOutsideAuthStore } from "./better-auth/store/resources-ou
|
|
|
109
111
|
import { checkComputed, computedMigration } from "./computed/computed-schema.js";
|
|
110
112
|
import { checkWebhooksSchema, webhooksMigration } from "./webhooks/table/schema.js";
|
|
111
113
|
import { checkRealtimeRelay, realtimeRelayMigration } from "./realtime/relay/relay-schema.js";
|
|
114
|
+
import { channelSendsMigration, checkChannelSends } from "./channels/sends-schema.js";
|
|
112
115
|
import { checkAi } from "./ai/check-ai.js";
|
|
113
116
|
import { checkNotificationsSchema, notificationsMigration } from "./notifications/schema.js";
|
|
114
117
|
import { sendNotification } from "./notifications/send-notification.js";
|
|
118
|
+
import { checkStatusSchema, statusMigration } from "./status/schema.js";
|
|
115
119
|
import { maxWidgetPropsBytes, widget } from "./assistant/widget.js";
|
|
116
120
|
import { checkQueryRunner, queryRunnerMigration } from "./assistant/query-runner/query-runner.js";
|
|
117
121
|
import { startErrorReporting } from "./error-reporting/error-reporter.js";
|
|
@@ -127,4 +131,4 @@ import { enqueueJob } from "./jobs/declared-job.js";
|
|
|
127
131
|
import { defineEmail } from "./mail/define-email.js";
|
|
128
132
|
import { startJobs } from "./jobs/runtime.js";
|
|
129
133
|
import { jobsDrainApp } from "./jobs/drain-route.js";
|
|
130
|
-
export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addCommentTool, 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, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, 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, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, 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 };
|
|
134
|
+
export { ConnectionsBusy, DeviceStoreError, FatalJobError, HistoryStoreError, HttpProblem, MissingCredentials, ModelError, NotificationSendError, PushMessageError, addAppRoleToOwners, addCommentTool, addMember, apiKeyCaller, apiKeySettings, apiKeyVariables, appNameOver, aspectRatio, assistantProtocolRoutes, assistantRoles, assistantSettings, assistantVariables, authSchemaDrift, authSchemaMigration, authStoreTables, backgroundSettled, badRequest, batchWriteTool, beforeSignInPluginsVariable, betterAuthTokens, capSocketMessages, changesMigration, channelSendsMigration, checkAi, checkAuthSchema, checkChanges, checkChannelSends, checkComments, checkComputed, checkJobsSchema, checkNotificationsSchema, checkQueryRunner, checkRealtimeRelay, checkResourcesOutsideAuthStore, checkSourceNames, checkStatusSchema, checkViewQueries, checkWebhooksSchema, coalesce, commentTools, commentsMigration, computedMigration, configExports, consoleAuditQueue, conversationKey, countRecordsTool, createAdmin, createConversations, createEncryptionTools, createFileCleanup, createOrganization, createRecordTool, createUser, defaultAppName, defaultHistoryPage, defaultSignInPolicy, defineEmail, defineFunction, defineJob, 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, parseColumns, parseRoles, passwordLength, pluginOptions, pluginsBeforeSignIn, pluginsFor, pluginsVariable, pngIcons, poolWaitMs, postgresDeviceStore, postgresHistoryStore, processor, pushMessage, queryRunnerMigration, readDbConnections, readJson, readOnlyQueryTool, readOperatorSettings, readOutbox, readPlatformSignIn, readRecordTools, readVapidSettings, readWriteQueryTool, readableResources, realtimeLimits, realtimeRelayMigration, recordOf, refusalOf, refused, relayed, 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, statusMigration, statusNames, 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 };
|
package/dist/internal.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { checkNotificationsOptions } from "./notifications/options.js";
|
|
2
2
|
import { checkCallsOptions } from "./calls/calls-options.js";
|
|
3
|
+
import { checkStatusOptions } from "./status/options.js";
|
|
3
4
|
import { isSubscription } from "./webhooks/subscription.js";
|
|
4
5
|
import { appPool, longQueryPool } from "./app-pool.js";
|
|
5
6
|
import { AppAuthInput, appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
|
|
@@ -11,4 +12,4 @@ import { fileProviderOf } from "./files/provider-settings.js";
|
|
|
11
12
|
import { declaredJob } from "./jobs/declared-job.js";
|
|
12
13
|
import { AuthPlugins, buildAuth, createAuth, loadAuthPlugins } from "./better-auth/create-auth.js";
|
|
13
14
|
import { webhooksModule } from "./webhooks/table/webhooks-module.js";
|
|
14
|
-
export { type AppAuthInput, type AuthPlugins, appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
|
|
15
|
+
export { type AppAuthInput, type AuthPlugins, appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, checkStatusOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
|
package/dist/internal.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildAuth, createAuth, loadAuthPlugins } from "./better-auth/create-auth.js";
|
|
2
2
|
import { isSubscription } from "./webhooks/subscription.js";
|
|
3
3
|
import { checkNotificationsOptions } from "./notifications/options.js";
|
|
4
|
+
import { checkStatusOptions } from "./status/options.js";
|
|
4
5
|
import { localFiles } from "./files/local-files.js";
|
|
5
6
|
import { s3Files } from "./files/s3-files.js";
|
|
6
7
|
import { appPool, longQueryPool } from "./app-pool.js";
|
|
@@ -11,4 +12,4 @@ import { appAuthOptions, buildAppAuth } from "./better-auth/auth-settings.js";
|
|
|
11
12
|
import { buildAuthenticator } from "./better-auth/authenticate-settings.js";
|
|
12
13
|
import { webhooksModule } from "./webhooks/table/webhooks-module.js";
|
|
13
14
|
import { checkCallsOptions } from "./calls/calls-options.js";
|
|
14
|
-
export { appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
|
|
15
|
+
export { appAuthOptions, appPool, betterAuthAuthenticator, buildAppAuth, buildAuth, buildAuthenticator, checkCallsOptions, checkNotificationsOptions, checkStatusOptions, createAuth, declaredJob, fileProviderOf, isSubscription, loadAuthPlugins, localFiles, longQueryPool, s3Files, webhooksModule };
|
package/dist/meta.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ export type CallerMeta = {
|
|
|
59
59
|
bell?: true;
|
|
60
60
|
webPushKey?: string;
|
|
61
61
|
};
|
|
62
|
+
/** With `status: {}`: people set their own status, and see the statuses of those they share an organization with. */
|
|
63
|
+
status?: true;
|
|
62
64
|
/** The language the admin app's screens are in, when the app sets one for everyone. */
|
|
63
65
|
locale?: Locale;
|
|
64
66
|
/** The hosts besides the app's own whose images the admin app draws with the page's referrer, when there are any. */
|
package/dist/meta.js
CHANGED
|
@@ -97,6 +97,7 @@ const createMeta = (deps, appName, appIcon) => {
|
|
|
97
97
|
...deps.bell && { bell: true },
|
|
98
98
|
...deps.webPushKey && { webPushKey: deps.webPushKey }
|
|
99
99
|
} },
|
|
100
|
+
...deps.status && { status: true },
|
|
100
101
|
...deps.locale && { locale: deps.locale },
|
|
101
102
|
...deps.files && deps.files.trustedHosts.length > 0 && { files: { trustedHosts: deps.files.trustedHosts } },
|
|
102
103
|
...plugins.length > 0 && { plugins },
|
|
@@ -5,8 +5,8 @@ import { forbidden } from "../problem.js";
|
|
|
5
5
|
* Refused: visitors, outside apps acting for the user (an MCP client), and every session whose authenticator does not
|
|
6
6
|
* mark it as the user's own sign-in (`Session.signIn`), staff signed in as the user included.
|
|
7
7
|
*/
|
|
8
|
-
const ownSignInUser = (session) => {
|
|
9
|
-
const refuse = () => forbidden("own-sign-in-only",
|
|
8
|
+
const ownSignInUser = (session, what = "reach their devices and notifications") => {
|
|
9
|
+
const refuse = () => forbidden("own-sign-in-only", `Only someone signed in as themselves can ${what}`);
|
|
10
10
|
if (session.anonymous || session.client || session.signIn?.staff !== false) throw refuse();
|
|
11
11
|
const userId = String(session.user.id);
|
|
12
12
|
if (userId === "" || session.user.id === void 0 || session.user.id === null) throw refuse();
|
|
@@ -16,7 +16,8 @@ const listed = (counts) => [...counts].map(([method, count]) => `${count} in ${m
|
|
|
16
16
|
* One try of a send, resuming from `given`: for a user send, each user's history entry when the send is for the inbox
|
|
17
17
|
* (once, as `record` marks it), then the user's devices as the store lists them now; for a device send, the devices
|
|
18
18
|
* with those ids now. A device the store gives that is not the user's, or not one asked for, gets nothing. With
|
|
19
|
-
* `liveSessions`, a device whose session no longer stands is removed instead of pushed to
|
|
19
|
+
* `liveSessions`, a device whose session no longer stands is removed instead of pushed to; with `quiet`, a device of a
|
|
20
|
+
* user on do not disturb gets nothing, now or on a later try, though the history keeps the entry. Each kind's
|
|
20
21
|
* devices go to its sender in one batch; a kind without a sender is skipped. An answer of `gone` removes the device,
|
|
21
22
|
* `retry` leaves it to the next try once and gives up on it the second time, and any other is done. A sender that
|
|
22
23
|
* throws leaves its batch to the next try. The try then throws, counting what is left, so the job retries it, or
|
|
@@ -70,8 +71,19 @@ const deliver = async ({ to, message }, given, steps) => {
|
|
|
70
71
|
}
|
|
71
72
|
return pending.filter(stands);
|
|
72
73
|
};
|
|
74
|
+
const undisturbed = async (devices) => {
|
|
75
|
+
const { quiet } = steps;
|
|
76
|
+
const pending = devices.filter((device) => !done.has(device.id));
|
|
77
|
+
if (!quiet || pending.length === 0) return pending;
|
|
78
|
+
const held = await quiet([...new Set(pending.map((device) => device.userId))]);
|
|
79
|
+
const kept = pending.filter((device) => !held.has(device.userId));
|
|
80
|
+
if (kept.length === pending.length) return kept;
|
|
81
|
+
for (const device of pending.filter((device) => held.has(device.userId))) markDone(device.id);
|
|
82
|
+
await steps.save(progress);
|
|
83
|
+
return kept;
|
|
84
|
+
};
|
|
73
85
|
const push = async (given) => {
|
|
74
|
-
const devices = await standing(given);
|
|
86
|
+
const devices = await undisturbed(await standing(given));
|
|
75
87
|
for (const device of devices) if (!steps.senders.some((sender) => sender.kinds.includes(device.kind))) markDone(device.id);
|
|
76
88
|
for (const sender of steps.senders) {
|
|
77
89
|
const batch = devices.filter((device) => sender.kinds.includes(device.kind) && !done.has(device.id));
|
|
@@ -26,11 +26,12 @@ const recordOnce = (db, options, job) => async (userId, entry, progress) => {
|
|
|
26
26
|
};
|
|
27
27
|
/**
|
|
28
28
|
* The job that delivers what `sendNotification` sends, through `senders` (guarded, see `notificationSenders`) and the
|
|
29
|
-
* stores `options` configure; with `liveSessions`, as with Protobase's auth, only to devices whose session stands
|
|
29
|
+
* stores `options` configure; with `liveSessions`, as with Protobase's auth, only to devices whose session stands, and
|
|
30
|
+
* with `quiet`, as with `status`, to no device of a user on do not disturb. A
|
|
30
31
|
* try resumes where the last one stopped (see `deliver`); once delivered, the job keeps no message. A few tries only: a
|
|
31
32
|
* device that keeps asking for a retry is given up on the second time.
|
|
32
33
|
*/
|
|
33
|
-
const pushJob = (options, senders, liveSessions) => defineJob({
|
|
34
|
+
const pushJob = (options, senders, liveSessions, quiet) => defineJob({
|
|
34
35
|
name: pushJobName,
|
|
35
36
|
payload: pushPayload,
|
|
36
37
|
maxAttempts: 5,
|
|
@@ -44,7 +45,8 @@ const pushJob = (options, senders, liveSessions) => defineJob({
|
|
|
44
45
|
save: (progress) => saveJobProgress(db, job, progress),
|
|
45
46
|
hold: () => holdJob(db, job),
|
|
46
47
|
complete: () => replaceJobData(db, job, { complete: true }),
|
|
47
|
-
...liveSessions && { liveSessions }
|
|
48
|
+
...liveSessions && { liveSessions },
|
|
49
|
+
...quiet && { quiet: (userIds) => quiet(db, userIds) }
|
|
48
50
|
});
|
|
49
51
|
}
|
|
50
52
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { migrationCommand } from "../changes/capture-schema.js";
|
|
2
2
|
import { historyNames, notificationsNames } from "./options.js";
|
|
3
|
-
import { storeSchema } from "../better-auth/store/store-names.js";
|
|
4
3
|
import { deviceSessionColumnSql, devicesTableSql, qualified } from "./schema-sql.js";
|
|
4
|
+
import { storeSchema } from "../better-auth/store/store-names.js";
|
|
5
5
|
import { historyTableSql } from "./history-sql.js";
|
|
6
6
|
import { sql } from "kysely";
|
|
7
7
|
//#region src/notifications/schema.ts
|
|
@@ -11,9 +11,12 @@ const authUsersTable = (auth) => ({
|
|
|
11
11
|
table: auth.options.user?.modelName ?? "user"
|
|
12
12
|
});
|
|
13
13
|
const regclass = async (db, name) => (await sql`select to_regclass(${name})::oid as oid`.execute(db)).rows[0].oid;
|
|
14
|
-
const userIdType = async (db, users
|
|
14
|
+
const userIdType = async (db, users, of = {
|
|
15
|
+
feature: "notifications",
|
|
16
|
+
rows: "devices"
|
|
17
|
+
}) => {
|
|
15
18
|
const oid = await regclass(db, qualified(users));
|
|
16
|
-
if (oid === null) throw new Error(
|
|
19
|
+
if (oid === null) throw new Error(`${of.feature}: auth's users table ${qualified(users)} is not in the app's database, so ${of.rows} cannot point at it`);
|
|
17
20
|
const { rows } = await sql`select format_type(atttypid, atttypmod) as type from pg_attribute where attrelid = ${oid} and attname = 'id'`.execute(db);
|
|
18
21
|
return rows[0].type;
|
|
19
22
|
};
|
|
@@ -89,4 +92,4 @@ const checkNotificationsSchema = async (db, options = {}, auth) => {
|
|
|
89
92
|
await checkHistoryTable(db, options, users);
|
|
90
93
|
};
|
|
91
94
|
//#endregion
|
|
92
|
-
export { authUsersTable, checkNotificationsSchema, notificationsMigration };
|
|
95
|
+
export { authUsersTable, checkNotificationsSchema, notificationsMigration, regclass, userIdType };
|
package/dist/package.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { writeTransaction } from "../transactions.js";
|
|
2
2
|
import { fitsFrame } from "./broadcast-frame.js";
|
|
3
|
+
import { followedPoll } from "./followed-poll.js";
|
|
3
4
|
import { realtimeLimits } from "./realtime-limits.js";
|
|
4
5
|
import { sql } from "kysely";
|
|
5
6
|
import { Buffer } from "node:buffer";
|
|
@@ -43,8 +44,6 @@ const messagesTableExists = async (db) => (await sql`select to_regclass('realtim
|
|
|
43
44
|
* `realtime.messages` sends nothing, and is checked again at each read.
|
|
44
45
|
*/
|
|
45
46
|
const databaseBroadcasts = ({ db, statementTimeoutMs, broadcasts, intervalMs = 1e3, report }) => {
|
|
46
|
-
let followers = 0;
|
|
47
|
-
let running = false;
|
|
48
47
|
const read = async () => {
|
|
49
48
|
if (!await messagesTableExists(db)) return;
|
|
50
49
|
for (;;) {
|
|
@@ -56,29 +55,7 @@ const databaseBroadcasts = ({ db, statementTimeoutMs, broadcasts, intervalMs = 1
|
|
|
56
55
|
if (rows.length < batchSize) return;
|
|
57
56
|
}
|
|
58
57
|
};
|
|
59
|
-
|
|
60
|
-
if (followers === 0) {
|
|
61
|
-
running = false;
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
await read().catch(report);
|
|
65
|
-
setTimeout(() => void tick(), intervalMs);
|
|
66
|
-
};
|
|
67
|
-
return {
|
|
68
|
-
/** Reads the table from now on, until the returned function is called; once for each call, however often. */
|
|
69
|
-
follow: () => {
|
|
70
|
-
followers += 1;
|
|
71
|
-
if (!running) {
|
|
72
|
-
running = true;
|
|
73
|
-
tick();
|
|
74
|
-
}
|
|
75
|
-
let followed = true;
|
|
76
|
-
return () => {
|
|
77
|
-
if (!followed) return;
|
|
78
|
-
followed = false;
|
|
79
|
-
followers -= 1;
|
|
80
|
-
};
|
|
81
|
-
} };
|
|
58
|
+
return followedPoll(read, intervalMs, report);
|
|
82
59
|
};
|
|
83
60
|
//#endregion
|
|
84
61
|
export { databaseBroadcasts, messagesTableExists, publicationOfRow };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/realtime/followed-poll.ts
|
|
2
|
+
/**
|
|
3
|
+
* Runs `read` every `intervalMs` while anyone follows, starting at once with the first follower; a failed read goes to
|
|
4
|
+
* `report`, and the next one tries again.
|
|
5
|
+
*/
|
|
6
|
+
const followedPoll = (read, intervalMs, report) => {
|
|
7
|
+
let followers = 0;
|
|
8
|
+
let running = false;
|
|
9
|
+
const tick = async () => {
|
|
10
|
+
if (followers === 0) {
|
|
11
|
+
running = false;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
await read().catch(report);
|
|
15
|
+
setTimeout(() => void tick(), intervalMs);
|
|
16
|
+
};
|
|
17
|
+
return {
|
|
18
|
+
/** Reads from now on, until the returned function is called; once for each call, however often. */
|
|
19
|
+
follow: () => {
|
|
20
|
+
followers += 1;
|
|
21
|
+
if (!running) {
|
|
22
|
+
running = true;
|
|
23
|
+
tick();
|
|
24
|
+
}
|
|
25
|
+
let followed = true;
|
|
26
|
+
return () => {
|
|
27
|
+
if (!followed) return;
|
|
28
|
+
followed = false;
|
|
29
|
+
followers -= 1;
|
|
30
|
+
};
|
|
31
|
+
} };
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { followedPoll };
|
|
@@ -5,15 +5,17 @@ export type RealtimePruneOptions = {
|
|
|
5
5
|
statementTimeoutMs: number;
|
|
6
6
|
/** Whether the app's processes relay through `realtime_relay`, whose frames and counts are pruned too. */
|
|
7
7
|
relayed: boolean;
|
|
8
|
+
/** Whether SQL sends to the record channels through `channels.sends`, whose old rows are pruned too. */
|
|
9
|
+
sqlSends: boolean;
|
|
8
10
|
/** Where a failed prune goes; the next one tries again. */
|
|
9
11
|
report: (error: unknown) => void;
|
|
10
12
|
};
|
|
11
13
|
/**
|
|
12
14
|
* Prunes what the realtime tables keep whether or not a socket is open, as on an app that never opens one: the old
|
|
13
|
-
* broadcast rows of `realtime.messages
|
|
14
|
-
* only while the process does, so it never wakes a sleeping app.
|
|
15
|
+
* broadcast rows of `realtime.messages`, relayed, the relay's old frames and counts and, with `sqlSends`, the old
|
|
16
|
+
* rows of `channels.sends`, on `pruneSchedule`. It runs only while the process does, so it never wakes a sleeping app.
|
|
15
17
|
*/
|
|
16
|
-
export declare const startRealtimePrune: ({ db, statementTimeoutMs, relayed, report }: RealtimePruneOptions) => {
|
|
18
|
+
export declare const startRealtimePrune: ({ db, statementTimeoutMs, relayed, sqlSends, report }: RealtimePruneOptions) => {
|
|
17
19
|
stop: () => Promise<void>;
|
|
18
20
|
};
|
|
19
21
|
export type RealtimePrune = ReturnType<typeof startRealtimePrune>;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { pruneFrames } from "./relay/relay-frame-sql.js";
|
|
2
2
|
import { pruneBroadcasts } from "./broadcast-prune.js";
|
|
3
|
+
import { pruneSends } from "../channels/sends-prune.js";
|
|
3
4
|
import { pruneSchedule } from "./prune-schedule.js";
|
|
4
5
|
//#region src/realtime/realtime-prune.ts
|
|
5
6
|
/**
|
|
6
7
|
* Prunes what the realtime tables keep whether or not a socket is open, as on an app that never opens one: the old
|
|
7
|
-
* broadcast rows of `realtime.messages
|
|
8
|
-
* only while the process does, so it never wakes a sleeping app.
|
|
8
|
+
* broadcast rows of `realtime.messages`, relayed, the relay's old frames and counts and, with `sqlSends`, the old
|
|
9
|
+
* rows of `channels.sends`, on `pruneSchedule`. It runs only while the process does, so it never wakes a sleeping app.
|
|
9
10
|
*/
|
|
10
|
-
const startRealtimePrune = ({ db, statementTimeoutMs, relayed, report }) => pruneSchedule([
|
|
11
|
+
const startRealtimePrune = ({ db, statementTimeoutMs, relayed, sqlSends, report }) => pruneSchedule([
|
|
12
|
+
() => pruneBroadcasts(db, statementTimeoutMs),
|
|
13
|
+
...relayed ? [() => pruneFrames(db)] : [],
|
|
14
|
+
...sqlSends ? [() => pruneSends(db, statementTimeoutMs)] : []
|
|
15
|
+
], report);
|
|
11
16
|
//#endregion
|
|
12
17
|
export { startRealtimePrune };
|
|
@@ -7,7 +7,14 @@ export type RealtimeOptions = {
|
|
|
7
7
|
* `realtime_relay` schema of the app's database, which `protobase migration` writes.
|
|
8
8
|
*/
|
|
9
9
|
processes?: 'one' | 'many';
|
|
10
|
+
/**
|
|
11
|
+
* `true` lets SQL in the app's database broadcast to the record channels with `channels.send()`, from the `channels`
|
|
12
|
+
* schema `protobase migration` writes.
|
|
13
|
+
*/
|
|
14
|
+
sqlSends?: boolean;
|
|
10
15
|
};
|
|
11
16
|
/** Whether the options share broadcasts and presence between processes. */
|
|
12
17
|
export declare const relayed: (options?: RealtimeOptions) => boolean;
|
|
18
|
+
/** Whether the options let SQL broadcast to the record channels. */
|
|
19
|
+
export declare const sqlSends: (options?: RealtimeOptions) => boolean;
|
|
13
20
|
//#endregion
|
|
@@ -5,5 +5,11 @@ const relayed = (options = {}) => {
|
|
|
5
5
|
if (options.processes === "many") return true;
|
|
6
6
|
throw new Error(`Invalid realtime.processes "${String(options.processes)}": use "one" or "many"`);
|
|
7
7
|
};
|
|
8
|
+
/** Whether the options let SQL broadcast to the record channels. */
|
|
9
|
+
const sqlSends = (options = {}) => {
|
|
10
|
+
if (options.sqlSends === void 0) return false;
|
|
11
|
+
if (typeof options.sqlSends === "boolean") return options.sqlSends;
|
|
12
|
+
throw new Error(`Invalid realtime.sqlSends "${String(options.sqlSends)}": use true or false`);
|
|
13
|
+
};
|
|
8
14
|
//#endregion
|
|
9
|
-
export { relayed };
|
|
15
|
+
export { relayed, sqlSends };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { StatusNames } from "./options.js";
|
|
2
|
+
import { Db } from "@protobase/query";
|
|
3
|
+
//#region src/status/do-not-disturb.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Which of these people are on do not disturb now: their status says so and its clear time, if any, is still to come.
|
|
6
|
+
* The one check of everything that would alert someone, such as a push, so each holds it alike.
|
|
7
|
+
*/
|
|
8
|
+
export declare const onDoNotDisturb: (db: Db, names: StatusNames, userIds: readonly string[]) => Promise<Set<string>>;
|
|
9
|
+
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { qualified } from "../notifications/schema-sql.js";
|
|
2
|
+
import { sql } from "kysely";
|
|
3
|
+
//#region src/status/do-not-disturb.ts
|
|
4
|
+
/**
|
|
5
|
+
* Which of these people are on do not disturb now: their status says so and its clear time, if any, is still to come.
|
|
6
|
+
* The one check of everything that would alert someone, such as a push, so each holds it alike.
|
|
7
|
+
*/
|
|
8
|
+
const onDoNotDisturb = async (db, names, userIds) => {
|
|
9
|
+
if (userIds.length === 0) return /* @__PURE__ */ new Set();
|
|
10
|
+
const { rows } = await sql`select user_id from ${sql.raw(qualified(names))}
|
|
11
|
+
where user_id in (${sql.join([...new Set(userIds)])}) and availability = 'do_not_disturb' and (clears_at is null or clears_at > now())`.execute(db);
|
|
12
|
+
return new Set(rows.map((row) => String(row.user_id)));
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { onDoNotDisturb };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/status/options.d.ts
|
|
2
|
+
/** People's own status, turned on with `status: {}` in `protobase.config.ts`; it needs auth with organizations. */
|
|
3
|
+
export type StatusOptions = {
|
|
4
|
+
/** The schema of the statuses table; default `status`. */
|
|
5
|
+
schema?: string;
|
|
6
|
+
};
|
|
7
|
+
/** The statuses table's names, checked: a bad schema name is an error naming the option. */
|
|
8
|
+
export declare const statusNames: (options?: StatusOptions) => {
|
|
9
|
+
schema: string;
|
|
10
|
+
table: string;
|
|
11
|
+
};
|
|
12
|
+
export type StatusNames = ReturnType<typeof statusNames>;
|
|
13
|
+
/** The options, checked as `status` takes them. */
|
|
14
|
+
export declare const checkStatusOptions: (options: StatusOptions) => StatusOptions;
|
|
15
|
+
//#endregion
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//#region src/status/options.ts
|
|
2
|
+
const namePattern = /^[a-z_][a-z0-9_]*$/;
|
|
3
|
+
const maxNameBytes = 63;
|
|
4
|
+
/** The statuses table's names, checked: a bad schema name is an error naming the option. */
|
|
5
|
+
const statusNames = (options = {}) => {
|
|
6
|
+
const schema = options.schema ?? "status";
|
|
7
|
+
if (typeof schema !== "string" || !namePattern.test(schema) || Buffer.byteLength(schema) > maxNameBytes) throw new Error(`status schema is not a valid name: use lowercase letters, digits and "_", at most ${maxNameBytes} characters`);
|
|
8
|
+
return {
|
|
9
|
+
schema,
|
|
10
|
+
table: "statuses"
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
/** The options, checked as `status` takes them. */
|
|
14
|
+
const checkStatusOptions = (options) => {
|
|
15
|
+
const unknown = Object.keys(options).find((key) => key !== "schema");
|
|
16
|
+
if (unknown !== void 0) throw new Error(`status takes no option "${unknown}": only schema`);
|
|
17
|
+
statusNames(options);
|
|
18
|
+
return options;
|
|
19
|
+
};
|
|
20
|
+
/** Status shows people to the members of their organizations, so an app without organizations cannot turn it on. */
|
|
21
|
+
const checkStatusAuth = (auth) => {
|
|
22
|
+
if (!auth?.organizations) throw new Error("status: {} shows people to the members of their organizations: turn organizations on in the auth config, or remove status");
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { checkStatusAuth, checkStatusOptions, statusNames };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ownSignInUser } from "../notifications/caller.js";
|
|
2
|
+
import { jsonBody, jsonOnly, limitedBody } from "../notifications/history-request.js";
|
|
3
|
+
import { statusInput } from "./status-input.js";
|
|
4
|
+
import { clearStatus, ownStatus, setStatus, visibleStatuses } from "./status-store.js";
|
|
5
|
+
import { Hono } from "hono";
|
|
6
|
+
//#region src/status/routes.ts
|
|
7
|
+
const noStore = { "Cache-Control": "no-store" };
|
|
8
|
+
const viewerOf = (session) => session.anonymous || session.client ? void 0 : String(session.user.id);
|
|
9
|
+
/**
|
|
10
|
+
* The status endpoints, mounted at `statusPath` behind the API's authenticator: `GET /` the caller's own status,
|
|
11
|
+
* `PUT /` sets it, `DELETE /` clears it, and `GET /people` the statuses of everyone who shares an organization with
|
|
12
|
+
* the caller. No request names whose status it sets: the person comes from the session alone, and only someone
|
|
13
|
+
* signed in as themselves sets theirs, never staff signed in as them (see `ownSignInUser`).
|
|
14
|
+
*/
|
|
15
|
+
const statusRoutes = (db, tables) => {
|
|
16
|
+
const app = new Hono();
|
|
17
|
+
app.get("/", async (c) => {
|
|
18
|
+
const viewer = viewerOf(c.get("session"));
|
|
19
|
+
const status = viewer === void 0 ? void 0 : await ownStatus(db, tables, viewer);
|
|
20
|
+
return c.json({ status: status ?? null }, 200, noStore);
|
|
21
|
+
});
|
|
22
|
+
app.put("/", jsonOnly, limitedBody, async (c) => {
|
|
23
|
+
const userId = ownSignInUser(c.get("session"), "set their status");
|
|
24
|
+
await setStatus(db, tables, userId, statusInput(await jsonBody(c)));
|
|
25
|
+
return c.json({ status: await ownStatus(db, tables, userId) ?? null }, 200, noStore);
|
|
26
|
+
});
|
|
27
|
+
app.delete("/", async (c) => {
|
|
28
|
+
await clearStatus(db, tables, ownSignInUser(c.get("session"), "set their status"));
|
|
29
|
+
return c.body(null, 204);
|
|
30
|
+
});
|
|
31
|
+
app.get("/people", async (c) => {
|
|
32
|
+
const viewer = viewerOf(c.get("session"));
|
|
33
|
+
return c.json({ statuses: viewer === void 0 ? [] : await visibleStatuses(db, tables, viewer) }, 200, noStore);
|
|
34
|
+
});
|
|
35
|
+
return app;
|
|
36
|
+
};
|
|
37
|
+
//#endregion
|
|
38
|
+
export { statusRoutes };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { quoteIdent } from "../changes/capture-sql.js";
|
|
2
|
+
import { qualified } from "../notifications/schema-sql.js";
|
|
3
|
+
//#region src/status/schema-sql.ts
|
|
4
|
+
/**
|
|
5
|
+
* The statuses table: one row per person who set a status, which goes with the user. A custom text or a clear time
|
|
6
|
+
* not set is NULL, and nothing has a default. Clearing a status deletes its row.
|
|
7
|
+
*/
|
|
8
|
+
const statusesTableSql = ({ schema, table }, user) => [`create schema if not exists ${quoteIdent(schema)}`, `create table ${qualified({
|
|
9
|
+
schema,
|
|
10
|
+
table
|
|
11
|
+
})} (
|
|
12
|
+
user_id ${user.type} primary key references ${user.references} on delete cascade,
|
|
13
|
+
availability text not null check (availability in ('automatic', 'busy', 'do_not_disturb')),
|
|
14
|
+
text text check (char_length(text) between 1 and 100),
|
|
15
|
+
clears_at timestamptz,
|
|
16
|
+
updated_at timestamptz not null
|
|
17
|
+
)`];
|
|
18
|
+
//#endregion
|
|
19
|
+
export { statusesTableSql };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StatusOptions } from "./options.js";
|
|
2
|
+
import { AdminAuth } from "../better-auth/create-auth.js";
|
|
3
|
+
import { Db } from "@protobase/query";
|
|
4
|
+
//#region src/status/schema.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* The SQL that adds the statuses table `status` keeps people's statuses in, its user column pointing at auth's users
|
|
7
|
+
* table; `undefined` when it exists. An app without organizations is refused (see `checkStatusAuth`).
|
|
8
|
+
*/
|
|
9
|
+
export declare const statusMigration: (db: Db, options: StatusOptions, auth: AdminAuth | undefined) => Promise<string | undefined>;
|
|
10
|
+
/** Refuses to start while the statuses table is missing, or the app has no organizations. */
|
|
11
|
+
export declare const checkStatusSchema: (db: Db, options: StatusOptions, auth: AdminAuth | undefined) => Promise<void>;
|
|
12
|
+
//#endregion
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { migrationCommand } from "../changes/capture-schema.js";
|
|
2
|
+
import { qualified } from "../notifications/schema-sql.js";
|
|
3
|
+
import { checkStatusAuth, statusNames } from "./options.js";
|
|
4
|
+
import { authUsersTable, regclass, userIdType } from "../notifications/schema.js";
|
|
5
|
+
import { statusesTableSql } from "./schema-sql.js";
|
|
6
|
+
//#region src/status/schema.ts
|
|
7
|
+
/**
|
|
8
|
+
* The SQL that adds the statuses table `status` keeps people's statuses in, its user column pointing at auth's users
|
|
9
|
+
* table; `undefined` when it exists. An app without organizations is refused (see `checkStatusAuth`).
|
|
10
|
+
*/
|
|
11
|
+
const statusMigration = async (db, options, auth) => {
|
|
12
|
+
checkStatusAuth(auth);
|
|
13
|
+
const names = statusNames(options);
|
|
14
|
+
if (await regclass(db, qualified(names)) !== null) return;
|
|
15
|
+
const users = authUsersTable(auth);
|
|
16
|
+
const type = await userIdType(db, users, {
|
|
17
|
+
feature: "status",
|
|
18
|
+
rows: "statuses"
|
|
19
|
+
});
|
|
20
|
+
return `${statusesTableSql(names, {
|
|
21
|
+
type,
|
|
22
|
+
references: `${qualified(users)} (id)`
|
|
23
|
+
}).join(";\n\n")};`;
|
|
24
|
+
};
|
|
25
|
+
/** Refuses to start while the statuses table is missing, or the app has no organizations. */
|
|
26
|
+
const checkStatusSchema = async (db, options, auth) => {
|
|
27
|
+
checkStatusAuth(auth);
|
|
28
|
+
const table = qualified(statusNames(options));
|
|
29
|
+
if (await regclass(db, table) !== null) return;
|
|
30
|
+
throw new Error(`The statuses table ${table} of status is missing. Write it as a migration with \`${migrationCommand}\`, apply it with the project's migrations, then start again.`);
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { checkStatusSchema, statusMigration };
|