@db3.ai/app 0.1.0-beta.1 → 0.1.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/README.md +75 -17
- package/agent-instructions.md +76 -0
- package/dist/ai/AIErrors.d.ts +7 -1
- package/dist/ai/AIErrors.js +8 -1
- package/dist/ai/AIFailover.d.ts +10 -0
- package/dist/ai/AIFailover.js +3 -2
- package/dist/ai/AIProviderAdmission.d.ts +101 -0
- package/dist/ai/AIProviderAdmission.js +336 -0
- package/dist/ai/AIRateLimiter.d.ts +11 -2
- package/dist/ai/AIRateLimiter.js +125 -10
- package/dist/ai/AIRequestTrackingError.d.ts +22 -0
- package/dist/ai/AIRequestTrackingError.js +33 -0
- package/dist/ai/Agent.d.ts +7 -7
- package/dist/ai/Agent.js +84 -56
- package/dist/ai/Ai.d.ts +11 -3
- package/dist/ai/Ai.js +94 -44
- package/dist/ai/OpenAIProviderError.js +1 -1
- package/dist/ai/ProviderSseObserver.d.ts +19 -0
- package/dist/ai/ProviderSseObserver.js +98 -0
- package/dist/ai/aiServiceTier.d.ts +5 -0
- package/dist/ai/aiServiceTier.js +14 -0
- package/dist/ai/chunkEmbeddingText.d.ts +14 -0
- package/dist/ai/chunkEmbeddingText.js +147 -0
- package/dist/ai/contracts/AI.d.ts +16 -0
- package/dist/ai/contracts/AIRequestErrorDiagnostics.d.ts +12 -0
- package/dist/ai/contracts/AIRequestErrorDiagnostics.js +1 -0
- package/dist/ai/contracts/AIServiceTier.d.ts +2 -0
- package/dist/ai/contracts/AIServiceTier.js +1 -0
- package/dist/ai/contracts/Agent.d.ts +3 -0
- package/dist/ai/contracts/EmbeddingTextChunk.d.ts +25 -0
- package/dist/ai/contracts/EmbeddingTextChunk.js +1 -0
- package/dist/ai/contracts/Pricing.d.ts +7 -1
- package/dist/ai/contracts/Providers.d.ts +2 -0
- package/dist/ai/contracts/index.d.ts +2 -0
- package/dist/ai/contracts/index.js +1 -0
- package/dist/ai/index.d.ts +8 -2
- package/dist/ai/index.js +5 -2
- package/dist/ai/{Models.d.ts → modelPricing.d.ts} +2 -2
- package/dist/ai/{Models.js → modelPricing.js} +38 -4
- package/dist/apps/AppInstallation.d.ts +21 -0
- package/dist/apps/AppInstallation.js +16 -0
- package/dist/apps/AppRouteError.d.ts +6 -0
- package/dist/apps/AppRouteError.js +10 -0
- package/dist/apps/AppService.d.ts +24 -0
- package/dist/apps/AppService.js +21 -0
- package/dist/apps/Apps.d.ts +59 -0
- package/dist/apps/Apps.js +566 -0
- package/dist/apps/appsPlugin.d.ts +3 -0
- package/dist/apps/appsPlugin.js +36 -0
- package/dist/apps/commands/disableApp.d.ts +2 -0
- package/dist/apps/commands/disableApp.js +5 -0
- package/dist/apps/commands/enableApp.d.ts +2 -0
- package/dist/apps/commands/enableApp.js +5 -0
- package/dist/apps/commands/index.d.ts +10 -0
- package/dist/apps/commands/index.js +27 -0
- package/dist/apps/commands/installApp.d.ts +2 -0
- package/dist/apps/commands/installApp.js +5 -0
- package/dist/apps/commands/listApps.d.ts +2 -0
- package/dist/apps/commands/listApps.js +5 -0
- package/dist/apps/commands/makeAppMigration.d.ts +2 -0
- package/dist/apps/commands/makeAppMigration.js +9 -0
- package/dist/apps/commands/rollbackApp.d.ts +2 -0
- package/dist/apps/commands/rollbackApp.js +5 -0
- package/dist/apps/commands/uninstallApp.d.ts +2 -0
- package/dist/apps/commands/uninstallApp.js +5 -0
- package/dist/apps/contracts/AppAction.d.ts +2 -0
- package/dist/apps/contracts/AppAction.js +1 -0
- package/dist/apps/contracts/AppDefinition.d.ts +45 -0
- package/dist/apps/contracts/AppDefinition.js +1 -0
- package/dist/apps/contracts/AppDescription.d.ts +32 -0
- package/dist/apps/contracts/AppDescription.js +1 -0
- package/dist/apps/contracts/AppManifest.d.ts +30 -0
- package/dist/apps/contracts/AppManifest.js +1 -0
- package/dist/apps/contracts/AppNavigation.d.ts +9 -0
- package/dist/apps/contracts/AppNavigation.js +1 -0
- package/dist/apps/contracts/AppNavigationBadge.d.ts +6 -0
- package/dist/apps/contracts/AppNavigationBadge.js +1 -0
- package/dist/apps/contracts/AppNavigationContext.d.ts +8 -0
- package/dist/apps/contracts/AppNavigationContext.js +1 -0
- package/dist/apps/contracts/AppNavigationResult.d.ts +12 -0
- package/dist/apps/contracts/AppNavigationResult.js +1 -0
- package/dist/apps/contracts/AppRoute.d.ts +19 -0
- package/dist/apps/contracts/AppRoute.js +1 -0
- package/dist/apps/contracts/DiscoveredApp.d.ts +10 -0
- package/dist/apps/contracts/DiscoveredApp.js +1 -0
- package/dist/apps/contracts/InstalledApps.d.ts +3 -0
- package/dist/apps/contracts/InstalledApps.js +1 -0
- package/dist/apps/contracts/index.d.ts +11 -0
- package/dist/apps/contracts/index.js +1 -0
- package/dist/apps/defineApp.d.ts +7 -0
- package/dist/apps/defineApp.js +8 -0
- package/dist/apps/discoverApps.d.ts +3 -0
- package/dist/apps/discoverApps.js +62 -0
- package/dist/apps/fastify.d.ts +1 -0
- package/dist/apps/fastify.js +1 -0
- package/dist/apps/index.d.ts +7 -0
- package/dist/apps/index.js +7 -0
- package/dist/apps/normalizeAppNavigation.d.ts +3 -0
- package/dist/apps/normalizeAppNavigation.js +30 -0
- package/dist/apps/registerAppRoutes.d.ts +6 -0
- package/dist/apps/registerAppRoutes.js +52 -0
- package/dist/apps/validateAppDefinitions.d.ts +3 -0
- package/dist/apps/validateAppDefinitions.js +65 -0
- package/dist/apps/vite.d.ts +1 -0
- package/dist/apps/vite.js +1 -0
- package/dist/apps/writeAppTypes.d.ts +2 -0
- package/dist/apps/writeAppTypes.js +13 -0
- package/dist/auth/Auth.d.ts +18 -0
- package/dist/auth/Auth.js +89 -13
- package/dist/auth/PasswordLoginAttempt.d.ts +50 -0
- package/dist/auth/PasswordLoginAttempt.js +60 -0
- package/dist/auth/PasswordSuspendedError.d.ts +10 -0
- package/dist/auth/PasswordSuspendedError.js +13 -0
- package/dist/auth/contracts/PasswordAuthProviderOptions.d.ts +26 -0
- package/dist/auth/contracts/PasswordAuthProviderOptions.js +1 -0
- package/dist/auth/contracts/PasswordSuspension.d.ts +7 -0
- package/dist/auth/contracts/PasswordSuspension.js +1 -0
- package/dist/auth/contracts/PasswordSuspensionOptions.d.ts +10 -0
- package/dist/auth/contracts/PasswordSuspensionOptions.js +1 -0
- package/dist/auth/contracts/index.d.ts +3 -0
- package/dist/auth/contracts/index.js +3 -0
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/providers/PasswordAuthProvider.d.ts +19 -23
- package/dist/auth/providers/PasswordAuthProvider.js +96 -8
- package/dist/auth/providers/resolveAuthProviders.js +1 -0
- package/dist/cli/Cli.d.ts +2 -0
- package/dist/cli/Cli.js +8 -0
- package/dist/cli/commands/repl.js +2 -1
- package/dist/cli/contracts/CliCommand.d.ts +2 -0
- package/dist/cli/contracts/CliCommandInfo.d.ts +12 -0
- package/dist/cli/contracts/CliCommandInfo.js +1 -0
- package/dist/cli/contracts/index.d.ts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +1 -0
- package/dist/cli/listDb3Commands.d.ts +8 -0
- package/dist/cli/listDb3Commands.js +10 -0
- package/dist/cli/runDb3.d.ts +3 -6
- package/dist/cli/runDb3.js +5 -59
- package/dist/cli/withDb3Cli.d.ts +4 -0
- package/dist/cli/withDb3Cli.js +60 -0
- package/dist/db/ActiveQueryBuilder.d.ts +8 -0
- package/dist/db/ActiveQueryBuilder.js +11 -0
- package/dist/db/ActiveRecord.d.ts +6 -0
- package/dist/db/ActiveRecord.js +8 -0
- package/dist/db/connection.js +14 -2
- package/dist/db/fields/TimestampField.d.ts +1 -1
- package/dist/db/fields/TimestampField.js +7 -12
- package/dist/db/migrations/DatabaseMigrationManager.d.ts +3 -1
- package/dist/db/migrations/DatabaseMigrationManager.js +9 -3
- package/dist/db/migrations/contracts/DatabaseMigration.d.ts +7 -0
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +1 -1
- package/dist/db/migrations/{KnexMigrationRenderer.d.ts → renderKnexMigration.d.ts} +4 -3
- package/dist/db/migrations/{KnexMigrationRenderer.js → renderKnexMigration.js} +7 -6
- package/dist/flows/FlowCompiler.js +1 -1
- package/dist/flows/Flows.js +1 -1
- package/dist/flows/index.d.ts +1 -1
- package/dist/flows/index.js +1 -1
- package/dist/health/Health.d.ts +41 -0
- package/dist/health/Health.js +153 -0
- package/dist/health/contracts/Health.d.ts +36 -0
- package/dist/health/contracts/Health.js +1 -0
- package/dist/health/contracts/HealthHttp.d.ts +15 -0
- package/dist/health/contracts/HealthHttp.js +1 -0
- package/dist/health/contracts/index.d.ts +2 -0
- package/dist/health/contracts/index.js +1 -0
- package/dist/health/databaseHealthCheck.d.ts +15 -0
- package/dist/health/databaseHealthCheck.js +18 -0
- package/dist/health/fastify.d.ts +13 -0
- package/dist/health/fastify.js +44 -0
- package/dist/health/index.d.ts +3 -0
- package/dist/health/index.js +2 -0
- package/dist/in-app/InApp.d.ts +33 -0
- package/dist/in-app/InApp.js +191 -0
- package/dist/in-app/InAppError.d.ts +6 -0
- package/dist/in-app/InAppError.js +10 -0
- package/dist/in-app/InAppRecord.d.ts +36 -0
- package/dist/in-app/InAppRecord.js +24 -0
- package/dist/in-app/contracts/InAppInbox.d.ts +45 -0
- package/dist/in-app/contracts/InAppInbox.js +1 -0
- package/dist/in-app/contracts/InAppMessage.d.ts +22 -0
- package/dist/in-app/contracts/InAppMessage.js +1 -0
- package/dist/in-app/contracts/InAppScope.d.ts +17 -0
- package/dist/in-app/contracts/InAppScope.js +1 -0
- package/dist/in-app/contracts/index.d.ts +3 -0
- package/dist/in-app/contracts/index.js +3 -0
- package/dist/in-app/index.d.ts +4 -0
- package/dist/in-app/index.js +4 -0
- package/dist/in-app/validation.d.ts +21 -0
- package/dist/in-app/validation.js +50 -0
- package/dist/index.d.ts +2 -14
- package/dist/index.js +2 -5
- package/dist/logging/DevelopmentConsole.d.ts +42 -0
- package/dist/logging/DevelopmentConsole.js +162 -0
- package/dist/logging/Log.d.ts +3 -1
- package/dist/logging/Log.js +5 -2
- package/dist/logging/PrettyLogFormatter.d.ts +16 -0
- package/dist/logging/PrettyLogFormatter.js +151 -0
- package/dist/logging/acquireDevelopmentConsole.d.ts +6 -0
- package/dist/logging/acquireDevelopmentConsole.js +21 -0
- package/dist/logging/contracts/DevelopmentConsoleOptions.d.ts +16 -0
- package/dist/logging/contracts/DevelopmentConsoleOptions.js +1 -0
- package/dist/logging/contracts/EmailLogOptions.d.ts +8 -0
- package/dist/logging/contracts/EmailLogOptions.js +1 -0
- package/dist/logging/contracts/HttpExchangeMonitorOptions.d.ts +12 -0
- package/dist/logging/contracts/HttpExchangeMonitorOptions.js +1 -0
- package/dist/logging/contracts/LogTransportOptions.d.ts +19 -0
- package/dist/logging/contracts/LogTransportOptions.js +1 -0
- package/dist/logging/contracts/LoggingOptions.d.ts +12 -1
- package/dist/logging/contracts/index.d.ts +4 -0
- package/dist/logging/contracts/index.js +4 -0
- package/dist/logging/drivers/PinoLoggerDriver.d.ts +3 -1
- package/dist/logging/drivers/PinoLoggerDriver.js +75 -16
- package/dist/logging/formatLogEmail.d.ts +4 -0
- package/dist/logging/formatLogEmail.js +21 -0
- package/dist/logging/highlightQueueMessage.d.ts +11 -0
- package/dist/logging/highlightQueueMessage.js +36 -0
- package/dist/logging/httpBodyCapture.d.ts +24 -0
- package/dist/logging/httpBodyCapture.js +321 -0
- package/dist/logging/index.d.ts +2 -0
- package/dist/logging/index.js +2 -0
- package/dist/logging/redactLogEmail.d.ts +2 -0
- package/dist/logging/redactLogEmail.js +12 -0
- package/dist/logging/registerHttpExchangeMonitor.d.ts +10 -0
- package/dist/logging/registerHttpExchangeMonitor.js +43 -0
- package/dist/logging/transports/EmailLogTransport.d.ts +18 -0
- package/dist/logging/transports/EmailLogTransport.js +47 -0
- package/dist/mail/Mail.d.ts +2 -0
- package/dist/mail/Mail.js +3 -0
- package/dist/mail/MailDeliveryError.d.ts +9 -0
- package/dist/mail/MailDeliveryError.js +16 -0
- package/dist/mail/index.d.ts +1 -0
- package/dist/mail/index.js +1 -0
- package/dist/mail/transports/MailgunTransport.js +2 -0
- package/dist/mail/transports/ResendTransport.d.ts +3 -2
- package/dist/mail/transports/ResendTransport.js +22 -14
- package/dist/media/MediaManager.d.ts +4 -2
- package/dist/media/MediaManager.js +40 -8
- package/dist/network/BlockedUrlError.d.ts +16 -0
- package/dist/network/BlockedUrlError.js +19 -0
- package/dist/network/assertPublicUrl.d.ts +22 -0
- package/dist/network/assertPublicUrl.js +67 -0
- package/dist/network/contracts/GuardedFetch.d.ts +35 -0
- package/dist/network/contracts/GuardedFetch.js +1 -0
- package/dist/network/contracts/PublicUrlOptions.d.ts +17 -0
- package/dist/network/contracts/PublicUrlOptions.js +1 -0
- package/dist/network/contracts/index.d.ts +2 -0
- package/dist/network/contracts/index.js +2 -0
- package/dist/network/guardedFetch.d.ts +29 -0
- package/dist/network/guardedFetch.js +133 -0
- package/dist/network/index.d.ts +6 -0
- package/dist/network/index.js +6 -0
- package/dist/network/playwright/GuardedBrowserProxy.d.ts +32 -0
- package/dist/network/playwright/GuardedBrowserProxy.js +172 -0
- package/dist/network/playwright/contracts/GuardedBrowserContextOptions.d.ts +37 -0
- package/dist/network/playwright/contracts/GuardedBrowserContextOptions.js +1 -0
- package/dist/network/playwright/contracts/index.d.ts +1 -0
- package/dist/network/playwright/contracts/index.js +1 -0
- package/dist/network/playwright/index.d.ts +2 -0
- package/dist/network/playwright/index.js +2 -0
- package/dist/network/playwright/newGuardedBrowserContext.d.ts +21 -0
- package/dist/network/playwright/newGuardedBrowserContext.js +86 -0
- package/dist/network/privateNetworkAddresses.d.ts +44 -0
- package/dist/network/privateNetworkAddresses.js +157 -0
- package/dist/network/publicAddressLookup.d.ts +26 -0
- package/dist/network/publicAddressLookup.js +42 -0
- package/dist/notifications/Notifications.d.ts +27 -0
- package/dist/notifications/Notifications.js +99 -0
- package/dist/notifications/contracts/Notification.d.ts +56 -0
- package/dist/notifications/contracts/Notification.js +1 -0
- package/dist/notifications/contracts/NotificationDelivery.d.ts +11 -0
- package/dist/notifications/contracts/NotificationDelivery.js +1 -0
- package/dist/notifications/contracts/index.d.ts +2 -0
- package/dist/notifications/contracts/index.js +2 -0
- package/dist/notifications/index.d.ts +2 -0
- package/dist/notifications/index.js +2 -0
- package/dist/queue/JobRunAttempt.d.ts +16 -0
- package/dist/queue/JobRunAttempt.js +17 -0
- package/dist/queue/JobRunEvent.d.ts +15 -0
- package/dist/queue/JobRunEvent.js +16 -0
- package/dist/queue/JobRunStoppedError.d.ts +6 -0
- package/dist/queue/JobRunStoppedError.js +10 -0
- package/dist/queue/Queue.d.ts +19 -4
- package/dist/queue/Queue.js +122 -9
- package/dist/queue/QueueTerminalError.d.ts +9 -0
- package/dist/queue/QueueTerminalError.js +12 -0
- package/dist/queue/QueueWorker.d.ts +12 -5
- package/dist/queue/QueueWorker.js +94 -9
- package/dist/queue/QueueWorkerReporter.d.ts +17 -0
- package/dist/queue/QueueWorkerReporter.js +71 -0
- package/dist/queue/QueueableJob.d.ts +2 -2
- package/dist/queue/RunnableJob.d.ts +78 -0
- package/dist/queue/RunnableJob.js +284 -0
- package/dist/queue/console.d.ts +8 -0
- package/dist/queue/console.js +53 -19
- package/dist/queue/contracts/QueueDriver.d.ts +8 -0
- package/dist/queue/contracts/QueueJobRunner.d.ts +4 -0
- package/dist/queue/contracts/QueueJobRunner.js +1 -0
- package/dist/queue/contracts/QueuePayload.d.ts +1 -1
- package/dist/queue/contracts/QueueSelection.d.ts +11 -0
- package/dist/queue/contracts/QueueSelection.js +1 -0
- package/dist/queue/contracts/QueueService.d.ts +18 -4
- package/dist/queue/contracts/QueueWorkerLifecycle.d.ts +2 -2
- package/dist/queue/contracts/QueueWorkerSnapshot.d.ts +14 -0
- package/dist/queue/contracts/QueueWorkerSnapshot.js +1 -0
- package/dist/queue/contracts/QueueableJob.d.ts +7 -3
- package/dist/queue/contracts/QueueableJobContract.d.ts +12 -0
- package/dist/queue/contracts/QueueableJobContract.js +1 -0
- package/dist/queue/contracts/index.d.ts +4 -0
- package/dist/queue/contracts/index.js +2 -0
- package/dist/queue/drivers/DatabaseQueueDriver.d.ts +4 -0
- package/dist/queue/drivers/DatabaseQueueDriver.js +27 -3
- package/dist/queue/drivers/RedisQueueDriver.d.ts +7 -0
- package/dist/queue/drivers/RedisQueueDriver.js +37 -0
- package/dist/queue/index.d.ts +5 -0
- package/dist/queue/index.js +5 -0
- package/dist/queue/jobEnvelopeHasPrefix.d.ts +3 -0
- package/dist/queue/jobEnvelopeHasPrefix.js +4 -0
- package/dist/scheduler/ScheduledEvent.d.ts +8 -4
- package/dist/scheduler/ScheduledEvent.js +17 -3
- package/dist/scheduler/ScheduledJob.d.ts +1 -1
- package/dist/scheduler/Scheduler.d.ts +5 -0
- package/dist/scheduler/Scheduler.js +92 -28
- package/dist/scheduler/SchedulerCheckpointRecord.d.ts +16 -0
- package/dist/scheduler/SchedulerCheckpointRecord.js +53 -0
- package/dist/scheduler/SchedulerWorker.d.ts +3 -5
- package/dist/scheduler/SchedulerWorker.js +58 -14
- package/dist/scheduler/console.js +3 -1
- package/dist/scheduler/contracts/Schedule.d.ts +19 -0
- package/dist/scheduler/contracts/Schedule.js +1 -0
- package/dist/scheduler/contracts/Scheduler.d.ts +18 -6
- package/dist/scheduler/contracts/SchedulerCheckpoint.d.ts +23 -0
- package/dist/scheduler/contracts/SchedulerCheckpoint.js +1 -0
- package/dist/scheduler/contracts/SchedulerConsole.d.ts +5 -0
- package/dist/scheduler/contracts/SchedulerWorker.d.ts +6 -1
- package/dist/scheduler/contracts/index.d.ts +2 -0
- package/dist/scheduler/contracts/index.js +2 -0
- package/dist/scheduler/index.d.ts +1 -0
- package/dist/scheduler/index.js +1 -0
- package/dist/server/App.d.ts +36 -4
- package/dist/server/App.js +57 -7
- package/dist/server/contracts/HttpErrorHandlerOptions.d.ts +29 -0
- package/dist/server/contracts/HttpErrorHandlerOptions.js +1 -0
- package/dist/server/contracts/index.d.ts +1 -0
- package/dist/server/contracts/index.js +1 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +4 -0
- package/dist/server/publicServerErrorMessage.d.ts +11 -0
- package/dist/server/publicServerErrorMessage.js +16 -0
- package/dist/server/registerBrowserJsonFormatting.d.ts +16 -0
- package/dist/server/registerBrowserJsonFormatting.js +100 -0
- package/dist/server/registerHttpErrorHandler.d.ts +20 -0
- package/dist/server/registerHttpErrorHandler.js +93 -0
- package/dist/ssr/vite/contracts/ViteSsrOptions.d.ts +2 -0
- package/dist/ssr/vite/fastifyViteSsr.js +4 -3
- package/dist/storage/drivers/FlystorageDisk.js +2 -2
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/index.js +2 -2
- package/dist/websocket/WebSocketChannels.d.ts +18 -0
- package/dist/websocket/WebSocketChannels.js +129 -0
- package/dist/websocket/WebSocketConnection.d.ts +25 -0
- package/dist/websocket/WebSocketConnection.js +244 -0
- package/dist/websocket/WebSockets.d.ts +41 -0
- package/dist/websocket/WebSockets.js +194 -0
- package/dist/websocket/client/WebSocketClient.d.ts +21 -0
- package/dist/websocket/client/WebSocketClient.js +230 -0
- package/dist/websocket/client/index.d.ts +3 -0
- package/dist/websocket/client/index.js +1 -0
- package/dist/websocket/contracts/WebSocketChannel.d.ts +20 -0
- package/dist/websocket/contracts/WebSocketChannel.js +1 -0
- package/dist/websocket/contracts/WebSocketClient.d.ts +45 -0
- package/dist/websocket/contracts/WebSocketClient.js +1 -0
- package/dist/websocket/contracts/WebSocketEndpoint.d.ts +43 -0
- package/dist/websocket/contracts/WebSocketEndpoint.js +1 -0
- package/dist/websocket/contracts/WebSocketOptions.d.ts +48 -0
- package/dist/websocket/contracts/WebSocketOptions.js +1 -0
- package/dist/websocket/contracts/WebSocketPresence.d.ts +6 -0
- package/dist/websocket/contracts/WebSocketPresence.js +1 -0
- package/dist/websocket/contracts/WebSocketServiceOptions.d.ts +12 -0
- package/dist/websocket/contracts/WebSocketServiceOptions.js +1 -0
- package/dist/websocket/contracts/index.d.ts +6 -0
- package/dist/websocket/contracts/index.js +1 -0
- package/dist/websocket/defineChannel.d.ts +8 -0
- package/dist/websocket/defineChannel.js +13 -0
- package/dist/websocket/defineWebSocket.d.ts +14 -0
- package/dist/websocket/defineWebSocket.js +4 -0
- package/dist/websocket/fastify.d.ts +11 -0
- package/dist/websocket/fastify.js +38 -0
- package/dist/websocket/index.d.ts +5 -0
- package/dist/websocket/index.js +4 -0
- package/package.json +108 -7
- package/src/ai/AIErrors.ts +10 -0
- package/src/ai/AIFailover.ts +3 -2
- package/src/ai/AIProviderAdmission.ts +329 -0
- package/src/ai/AIRateLimiter.ts +134 -10
- package/src/ai/AIRequestTrackingError.ts +37 -0
- package/src/ai/Agent.ts +85 -71
- package/src/ai/Ai.ts +104 -48
- package/src/ai/OpenAIProviderError.ts +1 -1
- package/src/ai/ProviderSseObserver.ts +89 -0
- package/src/ai/README.md +216 -11
- package/src/ai/aiServiceTier.ts +14 -0
- package/src/ai/chunkEmbeddingText.ts +137 -0
- package/src/ai/contracts/AI.ts +17 -0
- package/src/ai/contracts/AIRequestErrorDiagnostics.ts +12 -0
- package/src/ai/contracts/AIServiceTier.ts +2 -0
- package/src/ai/contracts/Agent.ts +3 -0
- package/src/ai/contracts/EmbeddingTextChunk.ts +26 -0
- package/src/ai/contracts/Pricing.ts +7 -1
- package/src/ai/contracts/Providers.ts +2 -0
- package/src/ai/contracts/index.ts +2 -0
- package/src/ai/examples/prepareDocumentEmbeddings.ts +20 -0
- package/src/ai/index.ts +9 -2
- package/src/ai/{Models.ts → modelPricing.ts} +37 -4
- package/src/apps/AppInstallation.ts +25 -0
- package/src/apps/AppRouteError.ts +8 -0
- package/src/apps/AppService.ts +30 -0
- package/src/apps/Apps.ts +508 -0
- package/src/apps/README.md +354 -0
- package/src/apps/appsPlugin.ts +34 -0
- package/src/apps/commands/disableApp.ts +6 -0
- package/src/apps/commands/enableApp.ts +6 -0
- package/src/apps/commands/index.ts +29 -0
- package/src/apps/commands/installApp.ts +6 -0
- package/src/apps/commands/listApps.ts +6 -0
- package/src/apps/commands/makeAppMigration.ts +9 -0
- package/src/apps/commands/rollbackApp.ts +6 -0
- package/src/apps/commands/uninstallApp.ts +6 -0
- package/src/apps/contracts/AppAction.ts +2 -0
- package/src/apps/contracts/AppDefinition.ts +49 -0
- package/src/apps/contracts/AppDescription.ts +27 -0
- package/src/apps/contracts/AppManifest.ts +32 -0
- package/src/apps/contracts/AppNavigation.ts +10 -0
- package/src/apps/contracts/AppNavigationBadge.ts +6 -0
- package/src/apps/contracts/AppNavigationContext.ts +6 -0
- package/src/apps/contracts/AppNavigationResult.ts +9 -0
- package/src/apps/contracts/AppRoute.ts +18 -0
- package/src/apps/contracts/DiscoveredApp.ts +11 -0
- package/src/apps/contracts/InstalledApps.ts +2 -0
- package/src/apps/contracts/index.ts +11 -0
- package/src/apps/defineApp.ts +10 -0
- package/src/apps/discoverApps.ts +56 -0
- package/src/apps/fastify.ts +1 -0
- package/src/apps/index.ts +7 -0
- package/src/apps/normalizeAppNavigation.ts +29 -0
- package/src/apps/registerAppRoutes.ts +48 -0
- package/src/apps/validateAppDefinitions.ts +52 -0
- package/src/apps/vite.ts +1 -0
- package/src/apps/writeAppTypes.ts +14 -0
- package/src/auth/Auth.ts +89 -23
- package/src/auth/PasswordLoginAttempt.ts +72 -0
- package/src/auth/PasswordSuspendedError.ts +13 -0
- package/src/auth/README.md +94 -4
- package/src/auth/contracts/PasswordAuthProviderOptions.ts +30 -0
- package/src/auth/contracts/PasswordSuspension.ts +7 -0
- package/src/auth/contracts/PasswordSuspensionOptions.ts +10 -0
- package/src/auth/contracts/index.ts +3 -0
- package/src/auth/examples/runPasswordAuth.ts +6 -6
- package/src/auth/index.ts +2 -0
- package/src/auth/providers/PasswordAuthProvider.ts +96 -30
- package/src/auth/providers/resolveAuthProviders.ts +1 -0
- package/src/cli/Cli.ts +9 -0
- package/src/cli/README.md +19 -0
- package/src/cli/commands/repl.ts +2 -1
- package/src/cli/contracts/CliCommand.ts +2 -0
- package/src/cli/contracts/CliCommandInfo.ts +13 -0
- package/src/cli/contracts/index.ts +1 -0
- package/src/cli/index.ts +1 -0
- package/src/cli/listDb3Commands.ts +12 -0
- package/src/cli/runDb3.ts +5 -51
- package/src/cli/withDb3Cli.ts +55 -0
- package/src/db/ActiveQueryBuilder.ts +12 -0
- package/src/db/ActiveRecord.ts +9 -0
- package/src/db/README.md +45 -1
- package/src/db/connection.ts +12 -1
- package/src/db/examples/FieldNote.ts +7 -13
- package/src/db/examples/KnowledgeNote.ts +7 -13
- package/src/db/examples/runNoteMigrations.ts +11 -11
- package/src/db/fields/TimestampField.ts +8 -17
- package/src/db/migrations/DatabaseMigrationManager.ts +12 -4
- package/src/db/migrations/contracts/DatabaseMigration.ts +9 -0
- package/src/db/migrations/index.ts +1 -1
- package/src/db/migrations/{KnexMigrationRenderer.ts → renderKnexMigration.ts} +8 -14
- package/src/flows/FlowCompiler.ts +1 -1
- package/src/flows/Flows.ts +1 -1
- package/src/flows/index.ts +1 -1
- package/src/health/Health.ts +163 -0
- package/src/health/README.md +46 -0
- package/src/health/contracts/Health.ts +47 -0
- package/src/health/contracts/HealthHttp.ts +19 -0
- package/src/health/contracts/index.ts +2 -0
- package/src/health/databaseHealthCheck.ts +21 -0
- package/src/health/fastify.ts +49 -0
- package/src/health/index.ts +3 -0
- package/src/in-app/InApp.ts +173 -0
- package/src/in-app/InAppError.ts +8 -0
- package/src/in-app/InAppRecord.ts +41 -0
- package/src/in-app/README.md +193 -0
- package/src/in-app/contracts/InAppInbox.ts +51 -0
- package/src/in-app/contracts/InAppMessage.ts +19 -0
- package/src/in-app/contracts/InAppScope.ts +12 -0
- package/src/in-app/contracts/index.ts +3 -0
- package/src/in-app/examples/sendReportReady.ts +14 -0
- package/src/in-app/index.ts +4 -0
- package/src/in-app/validation.ts +49 -0
- package/src/index.ts +2 -22
- package/src/logging/DevelopmentConsole.ts +154 -0
- package/src/logging/Log.ts +5 -2
- package/src/logging/PrettyLogFormatter.ts +165 -0
- package/src/logging/README.md +52 -109
- package/src/logging/acquireDevelopmentConsole.ts +19 -0
- package/src/logging/contracts/DevelopmentConsoleOptions.ts +13 -0
- package/src/logging/contracts/EmailLogOptions.ts +9 -0
- package/src/logging/contracts/HttpExchangeMonitorOptions.ts +13 -0
- package/src/logging/contracts/LogTransportOptions.ts +10 -0
- package/src/logging/contracts/LoggingOptions.ts +12 -1
- package/src/logging/contracts/index.ts +4 -0
- package/src/logging/development/README.md +88 -0
- package/src/logging/drivers/PinoLoggerDriver.ts +72 -20
- package/src/logging/examples/runDevelopmentLogs.ts +36 -0
- package/src/logging/formatLogEmail.ts +24 -0
- package/src/logging/highlightQueueMessage.ts +38 -0
- package/src/logging/httpBodyCapture.ts +393 -0
- package/src/logging/index.ts +2 -0
- package/src/logging/redactLogEmail.ts +12 -0
- package/src/logging/registerHttpExchangeMonitor.ts +45 -0
- package/src/logging/transports/EmailLogTransport.ts +46 -0
- package/src/mail/Mail.ts +5 -0
- package/src/mail/MailDeliveryError.ts +8 -0
- package/src/mail/README.md +11 -1
- package/src/mail/index.ts +1 -0
- package/src/mail/transports/MailgunTransport.ts +2 -0
- package/src/mail/transports/ResendTransport.ts +24 -22
- package/src/media/MediaManager.ts +31 -10
- package/src/media/README.md +4 -0
- package/src/media/examples/runPrivateFiles.ts +2 -2
- package/src/network/BlockedUrlError.ts +19 -0
- package/src/network/README.md +133 -0
- package/src/network/assertPublicUrl.ts +77 -0
- package/src/network/contracts/GuardedFetch.ts +40 -0
- package/src/network/contracts/PublicUrlOptions.ts +17 -0
- package/src/network/contracts/index.ts +2 -0
- package/src/network/examples/runGuardedFetch.ts +35 -0
- package/src/network/guardedFetch.ts +150 -0
- package/src/network/index.ts +6 -0
- package/src/network/playwright/GuardedBrowserProxy.ts +172 -0
- package/src/network/playwright/contracts/GuardedBrowserContextOptions.ts +43 -0
- package/src/network/playwright/contracts/index.ts +1 -0
- package/src/network/playwright/index.ts +2 -0
- package/src/network/playwright/newGuardedBrowserContext.ts +74 -0
- package/src/network/privateNetworkAddresses.ts +166 -0
- package/src/network/publicAddressLookup.ts +49 -0
- package/src/notifications/Notifications.ts +105 -0
- package/src/notifications/README.md +59 -0
- package/src/notifications/contracts/Notification.ts +65 -0
- package/src/notifications/contracts/NotificationDelivery.ts +11 -0
- package/src/notifications/contracts/index.ts +2 -0
- package/src/notifications/examples/ReportReadyNotification.ts +31 -0
- package/src/notifications/index.ts +2 -0
- package/src/queue/JobRunAttempt.ts +17 -0
- package/src/queue/JobRunEvent.ts +16 -0
- package/src/queue/JobRunStoppedError.ts +8 -0
- package/src/queue/Queue.ts +112 -11
- package/src/queue/QueueTerminalError.ts +12 -0
- package/src/queue/QueueWorker.ts +86 -7
- package/src/queue/QueueWorkerReporter.ts +59 -0
- package/src/queue/QueueableJob.ts +2 -2
- package/src/queue/README.md +142 -1
- package/src/queue/RunnableJob.ts +272 -0
- package/src/queue/console.ts +54 -21
- package/src/queue/contracts/QueueDriver.ts +9 -0
- package/src/queue/contracts/QueueJobRunner.ts +4 -0
- package/src/queue/contracts/QueuePayload.ts +1 -1
- package/src/queue/contracts/QueueSelection.ts +11 -0
- package/src/queue/contracts/QueueService.ts +19 -4
- package/src/queue/contracts/QueueWorkerLifecycle.ts +2 -2
- package/src/queue/contracts/QueueWorkerSnapshot.ts +15 -0
- package/src/queue/contracts/QueueableJob.ts +7 -3
- package/src/queue/contracts/QueueableJobContract.ts +13 -0
- package/src/queue/contracts/index.ts +6 -0
- package/src/queue/drivers/DatabaseQueueDriver.ts +25 -3
- package/src/queue/drivers/RedisQueueDriver.ts +36 -0
- package/src/queue/examples/runQueueSelection.ts +34 -0
- package/src/queue/index.ts +7 -0
- package/src/queue/jobEnvelopeHasPrefix.ts +6 -0
- package/src/scheduler/README.md +50 -9
- package/src/scheduler/ScheduledEvent.ts +20 -5
- package/src/scheduler/ScheduledJob.ts +1 -1
- package/src/scheduler/Scheduler.ts +73 -27
- package/src/scheduler/SchedulerCheckpointRecord.ts +51 -0
- package/src/scheduler/SchedulerWorker.ts +54 -19
- package/src/scheduler/console.ts +3 -1
- package/src/scheduler/contracts/Schedule.ts +22 -0
- package/src/scheduler/contracts/Scheduler.ts +21 -6
- package/src/scheduler/contracts/SchedulerCheckpoint.ts +23 -0
- package/src/scheduler/contracts/SchedulerConsole.ts +5 -0
- package/src/scheduler/contracts/SchedulerWorker.ts +6 -1
- package/src/scheduler/contracts/index.ts +2 -0
- package/src/scheduler/examples/runSchedulerWindow.ts +54 -0
- package/src/scheduler/index.ts +1 -0
- package/src/server/App.ts +73 -10
- package/src/server/README.md +95 -2
- package/src/server/contracts/HttpErrorHandlerOptions.ts +29 -0
- package/src/server/contracts/index.ts +1 -0
- package/src/server/examples/createFirstServer.ts +5 -3
- package/src/server/index.ts +4 -0
- package/src/server/publicServerErrorMessage.ts +17 -0
- package/src/server/registerBrowserJsonFormatting.ts +94 -0
- package/src/server/registerHttpErrorHandler.ts +96 -0
- package/src/ssr/README.md +6 -0
- package/src/ssr/vite/contracts/ViteSsrOptions.ts +2 -0
- package/src/ssr/vite/fastifyViteSsr.ts +4 -3
- package/src/storage/drivers/FlystorageDisk.ts +2 -2
- package/src/storage/index.ts +2 -2
- package/src/websocket/README.md +458 -0
- package/src/websocket/WebSocketChannels.ts +99 -0
- package/src/websocket/WebSocketConnection.ts +162 -0
- package/src/websocket/WebSockets.ts +157 -0
- package/src/websocket/client/WebSocketClient.ts +188 -0
- package/src/websocket/client/index.ts +3 -0
- package/src/websocket/contracts/WebSocketChannel.ts +23 -0
- package/src/websocket/contracts/WebSocketClient.ts +48 -0
- package/src/websocket/contracts/WebSocketEndpoint.ts +46 -0
- package/src/websocket/contracts/WebSocketOptions.ts +50 -0
- package/src/websocket/contracts/WebSocketPresence.ts +6 -0
- package/src/websocket/contracts/WebSocketServiceOptions.ts +12 -0
- package/src/websocket/contracts/index.ts +6 -0
- package/src/websocket/defineChannel.ts +14 -0
- package/src/websocket/defineWebSocket.ts +15 -0
- package/src/websocket/examples/board/LiveBoard.ts +97 -0
- package/src/websocket/examples/board/SummarizeBoardJob.ts +52 -0
- package/src/websocket/examples/board/boardSnapshot.ts +16 -0
- package/src/websocket/examples/board/createBoardClient.ts +43 -0
- package/src/websocket/examples/board/createBoardStore.ts +58 -0
- package/src/websocket/examples/board/registerBoardRoutes.ts +31 -0
- package/src/websocket/examples/createChannelSync.ts +66 -0
- package/src/websocket/examples/deploymentEndpoint.ts +13 -0
- package/src/websocket/examples/deploymentSnapshot.ts +36 -0
- package/src/websocket/examples/resourceChannels.ts +18 -0
- package/src/websocket/examples/userEndpoint.ts +27 -0
- package/src/websocket/fastify.ts +39 -0
- package/src/websocket/index.ts +5 -0
- package/templates/AGENTS.md +33 -2
- /package/dist/flows/{FlowValueValidator.d.ts → flowValueValidator.d.ts} +0 -0
- /package/dist/flows/{FlowValueValidator.js → flowValueValidator.js} +0 -0
- /package/dist/storage/{mime.d.ts → mimeTypeFromPath.d.ts} +0 -0
- /package/dist/storage/{mime.js → mimeTypeFromPath.js} +0 -0
- /package/dist/storage/{contents.d.ts → storageContentsToBuffer.d.ts} +0 -0
- /package/dist/storage/{contents.js → storageContentsToBuffer.js} +0 -0
- /package/src/flows/{FlowValueValidator.ts → flowValueValidator.ts} +0 -0
- /package/src/storage/{mime.ts → mimeTypeFromPath.ts} +0 -0
- /package/src/storage/{contents.ts → storageContentsToBuffer.ts} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ActiveRecord } from '../db';
|
|
2
|
+
import type { SchedulerCheckpoint } from './contracts';
|
|
3
|
+
|
|
4
|
+
/** Durable scheduler restart progress; register this model in the application's migration registry. */
|
|
5
|
+
export class SchedulerCheckpointRecord extends ActiveRecord.define({
|
|
6
|
+
table: 'scheduler_checkpoints',
|
|
7
|
+
fields: field => ({
|
|
8
|
+
id: field.ulid(),
|
|
9
|
+
name: field.string({ required: true, length: 120, unique: true }),
|
|
10
|
+
value: field.json<{ evaluatedFor: string }>({ required: true }),
|
|
11
|
+
updatedAt: field.timestamp({ column: 'updated_at', auto: 'update' }),
|
|
12
|
+
}),
|
|
13
|
+
}) {
|
|
14
|
+
/** Returns restart persistence for one stable scheduler name; concurrent saves never regress progress. */
|
|
15
|
+
static checkpoint(name = 'default'): SchedulerCheckpoint {
|
|
16
|
+
return {
|
|
17
|
+
/** Establishes coverage before the first dispatch without resetting an existing scheduler. */
|
|
18
|
+
async load(firstMinute: Date): Promise<Date> {
|
|
19
|
+
let record = await SchedulerCheckpointRecord.where('name', name).first();
|
|
20
|
+
if (!record) {
|
|
21
|
+
try {
|
|
22
|
+
record = await SchedulerCheckpointRecord.create({ name, value: { evaluatedFor: new Date(firstMinute.getTime() - 60_000).toISOString() } }).save();
|
|
23
|
+
} catch (error) {
|
|
24
|
+
record = await SchedulerCheckpointRecord.where('name', name).first();
|
|
25
|
+
if (!record) throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return checkpointMinute(record.value!.evaluatedFor);
|
|
29
|
+
},
|
|
30
|
+
/** Advances only a valid, initialized UTC-minute cursor under a database row lock. */
|
|
31
|
+
async save(evaluatedFor: Date): Promise<void> {
|
|
32
|
+
const minute = checkpointMinute(evaluatedFor.toISOString());
|
|
33
|
+
await SchedulerCheckpointRecord.getDb().transaction(transaction => ActiveRecord.withDb(transaction, async () => {
|
|
34
|
+
const row = await SchedulerCheckpointRecord.where('name', name).toKnex().forUpdate().first();
|
|
35
|
+
if (!row) throw new Error('Scheduler checkpoint must be initialized before advancing it.');
|
|
36
|
+
const record = SchedulerCheckpointRecord.fromDb(row);
|
|
37
|
+
if (checkpointMinute(record.value!.evaluatedFor).getTime() >= minute.getTime()) return;
|
|
38
|
+
record.value = { evaluatedFor: minute.toISOString() };
|
|
39
|
+
await record.save();
|
|
40
|
+
}));
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Rejects corrupt progress rather than silently skipping an unknown scheduling window. */
|
|
47
|
+
function checkpointMinute(value: unknown): Date {
|
|
48
|
+
const minute = new Date(typeof value === 'string' ? value : NaN);
|
|
49
|
+
if (!Number.isFinite(minute.getTime()) || minute.getTime() % 60_000 !== 0) throw new Error('Scheduler checkpoint requires a valid UTC minute.');
|
|
50
|
+
return minute;
|
|
51
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type * as scheduler from './contracts';
|
|
2
2
|
import { Scheduler } from './Scheduler';
|
|
3
|
+
import { utcMinute } from './scheduleTime';
|
|
3
4
|
|
|
4
5
|
const DEFAULT_SLOW_TICK_WARNING_MS = 50_000;
|
|
6
|
+
const MINUTE_MS = 60_000;
|
|
7
|
+
const MAX_MINUTES_PER_BATCH = 60;
|
|
8
|
+
const FAILED_TICK_RETRY_MS = 1_000;
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* Long-running minute-aligned process adapter around Scheduler.runDue().
|
|
@@ -10,6 +14,9 @@ export class SchedulerWorker {
|
|
|
10
14
|
#running = false;
|
|
11
15
|
#abortController: AbortController | null = null;
|
|
12
16
|
readonly #now: () => Date;
|
|
17
|
+
#nextMinute: number | null = null;
|
|
18
|
+
readonly #onTick?: scheduler.SchedulerWorkerOptions['onTick'];
|
|
19
|
+
readonly #checkpoint?: scheduler.SchedulerCheckpoint;
|
|
13
20
|
readonly #sleep: scheduler.SchedulerSleep;
|
|
14
21
|
readonly #logger: scheduler.SchedulerLogger;
|
|
15
22
|
readonly #slowTickWarningMs: number;
|
|
@@ -24,6 +31,8 @@ export class SchedulerWorker {
|
|
|
24
31
|
private readonly schedulerService: Scheduler,
|
|
25
32
|
options: scheduler.SchedulerWorkerOptions = {},
|
|
26
33
|
) {
|
|
34
|
+
this.#onTick = options.onTick;
|
|
35
|
+
this.#checkpoint = options.checkpoint;
|
|
27
36
|
this.#now = options.now ?? (() => new Date());
|
|
28
37
|
this.#sleep = options.sleep ?? schedulerSleep;
|
|
29
38
|
this.#logger = options.logger ?? consoleSchedulerLogger();
|
|
@@ -32,7 +41,9 @@ export class SchedulerWorker {
|
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
/**
|
|
35
|
-
*
|
|
44
|
+
* Evaluates every uncovered minute in order, including time spent dispatching
|
|
45
|
+
* earlier batches. Catch-up yields after sixty minutes without discarding work.
|
|
46
|
+
* A durable checkpoint resumes coverage across replacement processes.
|
|
36
47
|
*
|
|
37
48
|
* @throws Error when the same worker instance is started twice.
|
|
38
49
|
*/
|
|
@@ -45,15 +56,28 @@ export class SchedulerWorker {
|
|
|
45
56
|
this.#abortController = new AbortController();
|
|
46
57
|
|
|
47
58
|
try {
|
|
59
|
+
if (this.#nextMinute === null) {
|
|
60
|
+
const firstMinute = utcMinute(this.#now());
|
|
61
|
+
const previous = await this.#checkpoint?.load(firstMinute);
|
|
62
|
+
this.#nextMinute = previous ? utcMinute(previous).getTime() + MINUTE_MS : firstMinute.getTime();
|
|
63
|
+
}
|
|
64
|
+
let batchSize = 0;
|
|
48
65
|
while (this.#running) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
const now = this.#now();
|
|
67
|
+
const currentMinute = utcMinute(now).getTime();
|
|
68
|
+
if (this.#nextMinute <= currentMinute) {
|
|
69
|
+
const completed = await this.#runTick(new Date(this.#nextMinute));
|
|
70
|
+
if (completed) this.#nextMinute += MINUTE_MS;
|
|
71
|
+
if (!this.#running) break;
|
|
72
|
+
if (!completed || ++batchSize >= MAX_MINUTES_PER_BATCH) {
|
|
73
|
+
await this.#sleep(completed ? 1 : FAILED_TICK_RETRY_MS, this.#abortController.signal);
|
|
74
|
+
batchSize = 0;
|
|
75
|
+
}
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
batchSize = 0;
|
|
79
|
+
// An early timer or backward clock step must not skip or repeat a minute.
|
|
80
|
+
await this.#sleep(Math.min(MINUTE_MS, Math.max(1, this.#nextMinute - now.getTime())), this.#abortController.signal);
|
|
57
81
|
}
|
|
58
82
|
} finally {
|
|
59
83
|
this.#running = false;
|
|
@@ -70,13 +94,22 @@ export class SchedulerWorker {
|
|
|
70
94
|
}
|
|
71
95
|
|
|
72
96
|
/**
|
|
73
|
-
* Evaluates one
|
|
97
|
+
* Evaluates one fixed minute, preserving progress only after the whole batch.
|
|
98
|
+
* Recorded event failures remain visible and do not prevent later minutes;
|
|
99
|
+
* incomplete evaluations and checkpoint failures retry this same minute.
|
|
100
|
+
*
|
|
101
|
+
* @param evaluatedFor - Original scheduled minute, independent of dispatch duration.
|
|
102
|
+
* @returns Whether the complete minute was evaluated and its checkpoint saved.
|
|
74
103
|
*/
|
|
75
|
-
|
|
104
|
+
async #runTick(evaluatedFor: Date): Promise<boolean> {
|
|
76
105
|
const startedAt = performance.now();
|
|
106
|
+
let completed = false;
|
|
77
107
|
|
|
78
108
|
try {
|
|
79
|
-
const result = await this.schedulerService.runDue(
|
|
109
|
+
const result = await this.schedulerService.runDue(evaluatedFor);
|
|
110
|
+
if (result.failures.length === 0) await this.#onTick?.(result);
|
|
111
|
+
await this.#checkpoint?.save(evaluatedFor);
|
|
112
|
+
completed = true;
|
|
80
113
|
|
|
81
114
|
if (result.due > 0 || result.failures.length > 0) {
|
|
82
115
|
this.#logger.info(
|
|
@@ -90,7 +123,7 @@ export class SchedulerWorker {
|
|
|
90
123
|
);
|
|
91
124
|
}
|
|
92
125
|
} catch (error) {
|
|
93
|
-
this.#logger.error(
|
|
126
|
+
this.#logger.error(`[scheduler] Evaluation for ${evaluatedFor.toISOString()} did not finish; retrying the same minute.`, error);
|
|
94
127
|
}
|
|
95
128
|
|
|
96
129
|
const durationMs = performance.now() - startedAt;
|
|
@@ -100,6 +133,7 @@ export class SchedulerWorker {
|
|
|
100
133
|
`[scheduler] Tick took ${Math.round(durationMs)}ms; inline calls should remain short.`,
|
|
101
134
|
);
|
|
102
135
|
}
|
|
136
|
+
return completed;
|
|
103
137
|
}
|
|
104
138
|
}
|
|
105
139
|
|
|
@@ -126,14 +160,15 @@ async function schedulerSleep(
|
|
|
126
160
|
signal: AbortSignal,
|
|
127
161
|
): Promise<void> {
|
|
128
162
|
await new Promise<void>(resolve => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
signal.addEventListener('abort', () => {
|
|
163
|
+
/** Clears the timer and its abort subscription on either completion path. */
|
|
164
|
+
const finish = (): void => {
|
|
132
165
|
clearTimeout(timeout);
|
|
166
|
+
signal.removeEventListener('abort', finish);
|
|
133
167
|
resolve();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
});
|
|
168
|
+
};
|
|
169
|
+
const timeout = setTimeout(finish, delayMs);
|
|
170
|
+
signal.addEventListener('abort', finish, { once: true });
|
|
171
|
+
if (signal.aborted) finish();
|
|
137
172
|
});
|
|
138
173
|
}
|
|
139
174
|
|
package/src/scheduler/console.ts
CHANGED
|
@@ -43,7 +43,7 @@ export async function runSchedulerConsole(
|
|
|
43
43
|
await runWithApp(options, app => {
|
|
44
44
|
for (const definition of app.scheduler.definitions()) {
|
|
45
45
|
console.log(
|
|
46
|
-
`${definition.name}\t${definition.kind}\
|
|
46
|
+
`${definition.name}\t${definition.kind}\t${definition.frequency.type === 'minute' ? 'every minute' : definition.frequency.type === 'hourly' ? 'hourly (UTC)' : `daily at ${definition.frequency.time}`}\t${definition.timezone}${definition.jobName ? `\t${definition.jobName}` : ''}`,
|
|
47
47
|
);
|
|
48
48
|
}
|
|
49
49
|
});
|
|
@@ -153,6 +153,8 @@ async function workScheduler(
|
|
|
153
153
|
app.scheduler.definitions();
|
|
154
154
|
|
|
155
155
|
const worker = new SchedulerWorker(app.scheduler, {
|
|
156
|
+
onTick: options.onTick,
|
|
157
|
+
checkpoint: options.checkpoint,
|
|
156
158
|
logger: app.log ? schedulerLogger(app.log) : undefined,
|
|
157
159
|
});
|
|
158
160
|
let shuttingDown = false;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ScheduledJob } from '../ScheduledJob';
|
|
2
|
+
import type { ScheduledCall } from '../ScheduledCall';
|
|
3
|
+
import type { ScheduledJobSource, ScheduledCallHandler, ScheduledTaskDefinition } from './Scheduler';
|
|
4
|
+
|
|
5
|
+
/** Fluent declaration surface shared by the host scheduler and app-owned schedule.ts files. */
|
|
6
|
+
export interface Schedule {
|
|
7
|
+
/** Declares queued work; workers execute the expensive operation. */
|
|
8
|
+
job(source: ScheduledJobSource): ScheduledJob;
|
|
9
|
+
/** Declares a short inline operation executed by the scheduler. */
|
|
10
|
+
call(handler: ScheduledCallHandler): ScheduledCall;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Ownership handle for one group's registrations. Closing removes only that group. */
|
|
14
|
+
export interface ScheduleRegistration {
|
|
15
|
+
/** Browser-safe definitions, including the owning app identifier. */
|
|
16
|
+
definitions: ScheduledTaskDefinition[];
|
|
17
|
+
/** Idempotently removes the group's runtime definitions. Durable history remains. */
|
|
18
|
+
close(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Wraps one complete occurrence, including claiming and dispatch, in the owner's lifecycle gate. */
|
|
22
|
+
export type ScheduleRunner = (operation: () => Promise<void>) => Promise<void>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { QueueableJob } from '../../queue';
|
|
1
|
+
import type { QueueableJobContract as QueueableJob } from '../../queue';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Supported scheduled task kinds.
|
|
@@ -18,25 +18,40 @@ export type ScheduledOccurrenceStatus =
|
|
|
18
18
|
| 'failed';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* Daily frequency
|
|
21
|
+
* Daily frequency interpreted in the configured timezone.
|
|
22
22
|
*/
|
|
23
23
|
export interface DailyScheduleFrequency {
|
|
24
|
-
/** Frequency discriminator
|
|
24
|
+
/** Frequency discriminator. */
|
|
25
25
|
type: 'daily';
|
|
26
26
|
/** Local wall-clock time in 24-hour HH:mm format. */
|
|
27
27
|
time: string;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/** Runs once for each evaluated UTC minute, including catch-up after downtime. */
|
|
31
|
+
export interface MinuteScheduleFrequency {
|
|
32
|
+
type: 'minute';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Supported calendar frequencies; durable claims remain scoped to UTC minutes. */
|
|
36
|
+
export type ScheduleFrequency = DailyScheduleFrequency | MinuteScheduleFrequency | HourlyScheduleFrequency;
|
|
37
|
+
|
|
38
|
+
/** Runs at minute zero of each UTC hour, including catch-up; independent of local daylight-saving changes. */
|
|
39
|
+
export interface HourlyScheduleFrequency {
|
|
40
|
+
type: 'hourly';
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
/**
|
|
31
44
|
* Normalized public description of one registered schedule.
|
|
32
45
|
*/
|
|
33
46
|
export interface ScheduledTaskDefinition {
|
|
47
|
+
/** App or other runtime group that owns this registration; absent for host declarations. */
|
|
48
|
+
owner?: string;
|
|
34
49
|
/** Stable task name used for deduplication and history. */
|
|
35
50
|
name: string;
|
|
36
51
|
/** Whether the task dispatches a job or executes an inline callback. */
|
|
37
52
|
kind: ScheduledTaskKind;
|
|
38
|
-
/**
|
|
39
|
-
frequency:
|
|
53
|
+
/** Minute/hour cadence or daily local wall-clock time. */
|
|
54
|
+
frequency: ScheduleFrequency;
|
|
40
55
|
/** IANA timezone used to interpret the frequency. */
|
|
41
56
|
timezone: string;
|
|
42
57
|
/** Durable queue job name when known without invoking a factory. */
|
|
@@ -61,7 +76,7 @@ export interface ScheduledJobClass {
|
|
|
61
76
|
* @param data - JSON-safe queue payload.
|
|
62
77
|
* @returns Rehydrated job instance.
|
|
63
78
|
*/
|
|
64
|
-
fromJSON(data: Record<string, unknown>): QueueableJob
|
|
79
|
+
fromJSON(data: Record<string, unknown>): QueueableJob | Promise<QueueableJob>;
|
|
65
80
|
}
|
|
66
81
|
|
|
67
82
|
/**
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Application-owned durable progress for one registered scheduler.
|
|
3
|
+
* Share this checkpoint between replacement processes using the same definitions.
|
|
4
|
+
*/
|
|
5
|
+
export interface SchedulerCheckpoint {
|
|
6
|
+
/**
|
|
7
|
+
* Loads the last fully evaluated UTC minute. On first use, atomically persist
|
|
8
|
+
* and return the minute immediately before firstMinute, establishing the start
|
|
9
|
+
* of coverage before any scheduled work is attempted.
|
|
10
|
+
*
|
|
11
|
+
* @param firstMinute - Current UTC minute at the worker's first startup.
|
|
12
|
+
* @returns Last evaluated minute, or the newly established starting boundary.
|
|
13
|
+
*/
|
|
14
|
+
load(firstMinute: Date): Promise<Date>;
|
|
15
|
+
/**
|
|
16
|
+
* Advances progress after all events in a minute have been considered.
|
|
17
|
+
* Concurrent saves must never move the stored minute backwards. A rejected
|
|
18
|
+
* save causes the worker to reconsider that minute using occurrence deduplication.
|
|
19
|
+
*
|
|
20
|
+
* @param evaluatedFor - UTC minute whose complete evaluation was recorded.
|
|
21
|
+
*/
|
|
22
|
+
save(evaluatedFor: Date): Promise<void>;
|
|
23
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Scheduler } from '../Scheduler';
|
|
2
2
|
import type { Logger } from '../../logging';
|
|
3
|
+
import type { SchedulerWorkerOptions } from './SchedulerWorker';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Parsed scheduler command name, positional arguments, and long options.
|
|
@@ -29,6 +30,10 @@ export interface SchedulerConsoleApp {
|
|
|
29
30
|
* Application hooks and help customisation for scheduler console commands.
|
|
30
31
|
*/
|
|
31
32
|
export interface SchedulerConsoleOptions {
|
|
33
|
+
/** Called after a successful scheduler worker tick for application-owned health reporting. */
|
|
34
|
+
onTick?: SchedulerWorkerOptions['onTick'];
|
|
35
|
+
/** Durable worker progress, initialized only by scheduler:work. One-off commands leave it alone. */
|
|
36
|
+
checkpoint?: SchedulerWorkerOptions['checkpoint'];
|
|
32
37
|
/** Resolves the active application instance after bootstrap. */
|
|
33
38
|
app: () => SchedulerConsoleApp;
|
|
34
39
|
/** Prepares schema, queue jobs, and schedule definitions. */
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { SchedulerLogger } from './Scheduler';
|
|
1
|
+
import type { SchedulerLogger, SchedulerRunResult } from './Scheduler';
|
|
2
|
+
import type { SchedulerCheckpoint } from './SchedulerCheckpoint';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Abort-aware sleep function used by the long-running scheduler worker.
|
|
@@ -12,6 +13,10 @@ export type SchedulerSleep = (
|
|
|
12
13
|
* Runtime dependencies and logging overrides for SchedulerWorker.
|
|
13
14
|
*/
|
|
14
15
|
export interface SchedulerWorkerOptions {
|
|
16
|
+
/** Durable coverage across process restarts; without it, coverage starts in the current process. */
|
|
17
|
+
checkpoint?: SchedulerCheckpoint;
|
|
18
|
+
/** Records a successful evaluation and its actual minute; hook failures retry that minute. */
|
|
19
|
+
onTick?: (result: SchedulerRunResult) => Promise<void>;
|
|
15
20
|
/** Clock used to align and evaluate scheduler ticks. */
|
|
16
21
|
now?: () => Date;
|
|
17
22
|
/** Abort-aware sleeper used between minute boundaries. */
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { createGeneratedTestDatabase } from '@db3.ai/app/db/test/db';
|
|
6
|
+
import { FailedJob, QueuedJob } from '@db3.ai/app/queue';
|
|
7
|
+
import { ScheduledOccurrence, SchedulerWorker } from '@db3.ai/app/scheduler';
|
|
8
|
+
import { App } from '@db3.ai/app/server';
|
|
9
|
+
import { WriteDailySummaryJob } from './WriteDailySummaryJob';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Demonstrates elapsed-minute scheduling with a real SQL queue and a controlled clock.
|
|
13
|
+
* Crossing the first boundary during a heartbeat, then spending seventy seconds
|
|
14
|
+
* dispatching two jobs, must also cover the following minute. This isolated lab
|
|
15
|
+
* removes its test database and files and makes no external provider calls.
|
|
16
|
+
*
|
|
17
|
+
* @returns Original due minutes and final outcomes after queue processing.
|
|
18
|
+
*/
|
|
19
|
+
export async function runSchedulerWindow() {
|
|
20
|
+
const root = await mkdtemp(join(tmpdir(), 'db3-scheduler-window-'));
|
|
21
|
+
try {
|
|
22
|
+
const database = await createGeneratedTestDatabase('scheduler_window_guide');
|
|
23
|
+
const application = new App({ db: database.db, storage: { disks: { local: { driver: 'local', root } } } });
|
|
24
|
+
try {
|
|
25
|
+
await application.db.install(QueuedJob, FailedJob, ScheduledOccurrence);
|
|
26
|
+
application.scheduler.job(WriteDailySummaryJob).name('first-summary').dailyAt('09:00');
|
|
27
|
+
application.scheduler.job(WriteDailySummaryJob).name('second-summary').dailyAt('09:00');
|
|
28
|
+
application.scheduler.job(WriteDailySummaryJob).name('next-summary').dailyAt('09:01');
|
|
29
|
+
let clock = Date.parse('2026-01-01T08:59:59.999Z');
|
|
30
|
+
const unsubscribe = application.queue.events.subscribe(async event => {
|
|
31
|
+
if (event.action === 'dispatched') clock += 35_000;
|
|
32
|
+
});
|
|
33
|
+
const worker = new SchedulerWorker(application.scheduler, {
|
|
34
|
+
now: () => new Date(clock),
|
|
35
|
+
onTick: async result => {
|
|
36
|
+
clock += 3;
|
|
37
|
+
if (result.evaluatedFor.getTime() === Date.parse('2026-01-01T09:01:00Z')) worker.stop();
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
try { await worker.start(); } finally { worker.stop(); unsubscribe(); }
|
|
41
|
+
while (await application.queue.workNextJob()) { /* Drain this lab's three jobs. */ }
|
|
42
|
+
const occurrences = await ScheduledOccurrence.query().orderBy('scheduledFor').orderBy('name').all();
|
|
43
|
+
return occurrences.map(occurrence => ({ name: occurrence.name, scheduledFor: occurrence.scheduledFor?.toISOString() ?? null, status: occurrence.status }));
|
|
44
|
+
} finally {
|
|
45
|
+
try { await application.close(); } finally { await database.destroy(); }
|
|
46
|
+
}
|
|
47
|
+
} finally {
|
|
48
|
+
await rm(root, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
53
|
+
console.log(JSON.stringify(await runSchedulerWindow(), null, 2));
|
|
54
|
+
}
|
package/src/scheduler/index.ts
CHANGED
package/src/server/App.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import type { WebSocketServiceOptions } from '../websocket';
|
|
1
2
|
import type { Knex } from 'knex';
|
|
2
3
|
import { resolve } from 'node:path';
|
|
3
4
|
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import { Ai, type AIOptions } from '../ai';
|
|
6
|
+
import { Apps, type AppDefinitions, type AppServices, type InstalledApps } from '../apps';
|
|
5
7
|
|
|
6
8
|
import {
|
|
7
9
|
Auth,
|
|
@@ -23,6 +25,12 @@ import {
|
|
|
23
25
|
Database,
|
|
24
26
|
type DatabaseOptions,
|
|
25
27
|
} from '../db';
|
|
28
|
+
import { InApp, type InAppOptions } from '../in-app';
|
|
29
|
+
import { Health, type HealthOptions } from '../health';
|
|
30
|
+
import { Mail, type MailOptions } from '../mail';
|
|
31
|
+
import { Notifications } from '../notifications';
|
|
32
|
+
import { WebSockets } from '../websocket';
|
|
33
|
+
import { UserIdentity } from '../auth';
|
|
26
34
|
import { Events } from '../events';
|
|
27
35
|
import { UrlGenerator, type UrlGeneratorOptions } from '../url';
|
|
28
36
|
import {
|
|
@@ -48,7 +56,9 @@ import {
|
|
|
48
56
|
} from './appContext';
|
|
49
57
|
|
|
50
58
|
/** Application root, service configuration and optional dependencies supplied at bootstrap. */
|
|
51
|
-
export interface AppOptions {
|
|
59
|
+
export interface AppOptions<TApps extends AppDefinitions = {}> {
|
|
60
|
+
/** Optional explicit composition. Omit to discover local apps and marked npm dependencies. */
|
|
61
|
+
apps?: TApps;
|
|
52
62
|
/** App root as a path or file URL; defaults to the working directory at construction. */
|
|
53
63
|
directory?: string | URL;
|
|
54
64
|
/** Provider adapters and extensible ActiveRecord models for app().ai. */
|
|
@@ -62,6 +72,14 @@ export interface AppOptions {
|
|
|
62
72
|
/** Canonical application URL configuration used across all runtimes. */
|
|
63
73
|
url?: UrlGeneratorOptions;
|
|
64
74
|
queue?: QueueOptions;
|
|
75
|
+
/** Authorization policy for application-scoped in-app inboxes. */
|
|
76
|
+
inApp?: InAppOptions;
|
|
77
|
+
/** Optional shared transport for channel events from API and worker processes. */
|
|
78
|
+
webSockets?: WebSocketServiceOptions;
|
|
79
|
+
/** Application health identity and initial component checks. */
|
|
80
|
+
health?: HealthOptions;
|
|
81
|
+
/** Provider-neutral mail delivery used directly and by app().notifications. */
|
|
82
|
+
mail?: MailOptions;
|
|
65
83
|
/** Serializable classes and ActiveRecord models registered with app().serializer. */
|
|
66
84
|
serializer?: SerializerOptions;
|
|
67
85
|
storage?: StorageOptions;
|
|
@@ -73,7 +91,7 @@ export interface AppOptions {
|
|
|
73
91
|
* Keep this as the place where top-level framework capabilities are discovered
|
|
74
92
|
* and wired, not where domain logic itself accumulates.
|
|
75
93
|
*/
|
|
76
|
-
export class App {
|
|
94
|
+
export class App<TApps extends AppDefinitions = {}> {
|
|
77
95
|
private readonly services = new Map<string, unknown>();
|
|
78
96
|
/** Absolute app root used for conventional server paths, independent of later working-directory changes. */
|
|
79
97
|
readonly directory: string;
|
|
@@ -83,13 +101,19 @@ export class App {
|
|
|
83
101
|
*
|
|
84
102
|
* @param options - Framework services and application configuration.
|
|
85
103
|
*/
|
|
86
|
-
constructor(protected readonly options: AppOptions = {}) {
|
|
104
|
+
constructor(protected readonly options: AppOptions<TApps> = {}) {
|
|
87
105
|
this.directory = resolve(options.directory instanceof URL ? fileURLToPath(options.directory) : options.directory ?? process.cwd());
|
|
106
|
+
if (options.apps) void this.apps;
|
|
88
107
|
setActiveApp(this);
|
|
89
108
|
|
|
90
109
|
if (this.config.has('security')) void this.security;
|
|
91
110
|
}
|
|
92
111
|
|
|
112
|
+
/** Returns the app composition registry with optional, inferred public service accessors. */
|
|
113
|
+
get apps(): Apps<TApps> & AppServices<TApps> {
|
|
114
|
+
return this.service('apps', () => new Apps(this, this.options.apps)) as Apps<TApps> & AppServices<TApps>;
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
/** Returns the lazy database service with this app's connection, model registry and root directory. */
|
|
94
118
|
get db(): Database {
|
|
95
119
|
return this.service('db', () => {
|
|
@@ -101,6 +125,31 @@ export class App {
|
|
|
101
125
|
});
|
|
102
126
|
}
|
|
103
127
|
|
|
128
|
+
/** Returns the durable inbox service using the configured Auth identity model. */
|
|
129
|
+
get inApp(): InApp {
|
|
130
|
+
return this.service('inApp', () => new InApp(this.options.inApp, this.options.auth?.identityModel ?? UserIdentity));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Returns the extensible application health registry. */
|
|
134
|
+
get health(): Health {
|
|
135
|
+
return this.service('health', () => new Health(this.options.health));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Returns the provider-neutral mail service configured for this application. */
|
|
139
|
+
get mail(): Mail {
|
|
140
|
+
return this.service('mail', () => new Mail(this.options.mail));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Returns the notification coordinator for application-owned channel renderers. */
|
|
144
|
+
get notifications(): Notifications<any> {
|
|
145
|
+
return this.service('notifications', () => new Notifications(this.inApp, this.mail, this.options.auth?.identityModel ?? UserIdentity));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Returns authenticated WebSocket endpoints owned by this application's lifecycle. */
|
|
149
|
+
get webSockets(): WebSockets {
|
|
150
|
+
return this.service('webSockets', () => new WebSockets(this, this.options.webSockets));
|
|
151
|
+
}
|
|
152
|
+
|
|
104
153
|
get auth(): Auth<any> {
|
|
105
154
|
return this.service('auth', () => new Auth<any>({
|
|
106
155
|
...this.options.auth,
|
|
@@ -148,7 +197,7 @@ export class App {
|
|
|
148
197
|
* @returns Pino-backed logging service with app lifecycle ownership.
|
|
149
198
|
*/
|
|
150
199
|
get log(): Log {
|
|
151
|
-
return this.service('log', () => new Log(this.options.log));
|
|
200
|
+
return this.service('log', () => new Log(this.options.log, () => this.mail));
|
|
152
201
|
}
|
|
153
202
|
|
|
154
203
|
/**
|
|
@@ -179,7 +228,10 @@ export class App {
|
|
|
179
228
|
get queue(): Queue {
|
|
180
229
|
return this.service('queue', () => new Queue(
|
|
181
230
|
this.db,
|
|
182
|
-
|
|
231
|
+
{
|
|
232
|
+
onLifecycleError: failure => this.log.error({ err: failure.error, component: 'queue', source: failure.source, hook: failure.hook, jobId: failure.event.jobId, jobName: failure.event.jobName, action: failure.event.action }, 'Queue lifecycle handler failed'),
|
|
233
|
+
...this.options.queue,
|
|
234
|
+
},
|
|
183
235
|
));
|
|
184
236
|
}
|
|
185
237
|
|
|
@@ -268,18 +320,26 @@ export class App {
|
|
|
268
320
|
* Closes shared resources owned by the default app.
|
|
269
321
|
*/
|
|
270
322
|
async close(): Promise<void> {
|
|
323
|
+
const errors: unknown[] = [];
|
|
324
|
+
/** Continues releasing host resources when an app or transport disposer fails. */
|
|
325
|
+
const release = async (cleanup: () => void | Promise<void>): Promise<void> => {
|
|
326
|
+
try { await cleanup(); } catch (error) { errors.push(error); }
|
|
327
|
+
};
|
|
328
|
+
await release(() => (this.services.get('apps') as Apps | undefined)?.close());
|
|
329
|
+
await release(() => (this.services.get('webSockets') as WebSockets | undefined)?.close());
|
|
271
330
|
clearActiveApp(this);
|
|
272
331
|
|
|
273
|
-
(this.services.get('scheduler') as Scheduler | undefined)?.close();
|
|
274
|
-
(this.services.get('events') as Events | undefined)?.clear();
|
|
275
|
-
await (this.services.get('cache') as Cache | undefined)?.close();
|
|
276
|
-
await (this.services.get('log') as Log | undefined)?.close();
|
|
332
|
+
await release(() => (this.services.get('scheduler') as Scheduler | undefined)?.close());
|
|
333
|
+
await release(() => (this.services.get('events') as Events | undefined)?.clear());
|
|
334
|
+
await release(() => (this.services.get('cache') as Cache | undefined)?.close());
|
|
335
|
+
await release(() => (this.services.get('log') as Log | undefined)?.close());
|
|
277
336
|
|
|
278
337
|
if (!this.options.db) {
|
|
279
|
-
await destroyDatabase();
|
|
338
|
+
await release(() => destroyDatabase());
|
|
280
339
|
}
|
|
281
340
|
|
|
282
341
|
this.services.clear();
|
|
342
|
+
if (errors.length) throw new AggregateError(errors, 'Application shutdown failed.');
|
|
283
343
|
}
|
|
284
344
|
|
|
285
345
|
private resolveDbConnection(): Knex {
|
|
@@ -324,3 +384,6 @@ function parseOptionalBoolean(input: string | undefined): boolean | undefined {
|
|
|
324
384
|
);
|
|
325
385
|
}
|
|
326
386
|
}
|
|
387
|
+
|
|
388
|
+
/** Optional discovered app services, generated from root App.ts classes by DB3 tooling. */
|
|
389
|
+
export interface App<TApps extends AppDefinitions = {}> extends InstalledApps {}
|