@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
package/src/ai/Ai.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
/// <reference path="./sdkNodeCompatibility.d.ts" preserve="true" />
|
|
2
|
+
import type { GenerateEmbeddingOptions } from './contracts/AI';
|
|
3
|
+
import { AIProviderAdmission, AIProviderDeferredError, AIProviderStoppedError } from './AIProviderAdmission';
|
|
4
|
+
import { isQueueRetryLaterError } from '@db3.ai/app/queue';
|
|
2
5
|
import OpenAI from 'openai';
|
|
3
6
|
import { OpenAIProvider, type ModelProvider } from '@openai/agents';
|
|
4
7
|
import { aiExecutionContext, scopedAiOptions } from './AiExecutionContext';
|
|
@@ -10,15 +13,18 @@ import { AiMessage, AI_MESSAGE_ROLE, type AiMessageRole } from './AiMessage';
|
|
|
10
13
|
import { AiRequest, AI_REQUEST_STATUS } from './AiRequest';
|
|
11
14
|
const defaultAIConfig = { model: 'gpt-4.1-mini' };
|
|
12
15
|
import { estimateTokensFromText } from './Estimates.js';
|
|
13
|
-
import { calculateAIImageRequestCostUSD, calculateAIRequestCostUSD } from './
|
|
16
|
+
import { calculateAIImageRequestCostUSD, calculateAIRequestCostUSD } from './modelPricing.js';
|
|
14
17
|
import { AI_PROVIDER } from './contracts/AI.js';
|
|
15
18
|
import { AIAllowanceExceededError, AIConfigurationError, AIRequestError } from './AIErrors.js';
|
|
19
|
+
import { AIRequestTrackingError } from './AIRequestTrackingError.js';
|
|
16
20
|
import { isFailoverableFailure, isFailoverableResponse } from './AIFailover.js';
|
|
17
21
|
import { providerChainFromEnvironment, resolveProviderChain, simulatedProviderOutage, type AIProviderAttempt, type AIProviderAttemptFailure } from './AIProviders.js';
|
|
18
22
|
import { AIRateLimitDeferredError, AIRateLimiter, embeddingsRateLimitEndpoint, imagesRateLimitEndpoint, providerResponseMetadata, responsesRateLimitEndpoint, type AIProviderResponseMetadata, type AIRateLimitLease } from './AIRateLimiter.js';
|
|
19
23
|
import { isOpenAIQuotaError, openAIProviderError } from './OpenAIProviderError.js';
|
|
20
24
|
import { providerReportedCostUSD } from './ProviderCosts.js';
|
|
21
25
|
import { sendResponsesRequest } from './ResponsesProviderCall.js';
|
|
26
|
+
import type { AIServiceTier } from './contracts/AIServiceTier';
|
|
27
|
+
import { assertAIServiceTier, effectiveAIServiceTier } from './aiServiceTier';
|
|
22
28
|
import type { AIAllowanceCheckInput, AIRecordIdentity, AIModels, AIConfig, AIOptions, AIProvider, AIProviderSelection, AIResponseLogOptions, EmbeddingResponsePayloadWithUsage, GenerateEmbeddingResult, GenerateImageInput, GenerateImageOptions, GenerateImageResult, GenerateStructuredInput, GenerateTextInput, GenerateTextResult, ImageResponsePayloadWithUsage, RequestLogOptions, TextResponsePayloadWithUsage, TokenUsage, TrackedEmbeddingRequest, TrackedImageRequest, TrackedRequest } from './contracts/AI.js';
|
|
23
29
|
|
|
24
30
|
/**
|
|
@@ -94,6 +100,7 @@ export class Ai {
|
|
|
94
100
|
/** Logical ownership field used by this application. */
|
|
95
101
|
readonly scopeField: string;
|
|
96
102
|
private readonly rateLimiter: AIRateLimiter | null;
|
|
103
|
+
readonly providerAdmission: AIProviderAdmission;
|
|
97
104
|
|
|
98
105
|
/**
|
|
99
106
|
* Create an AI service instance.
|
|
@@ -106,6 +113,8 @@ export class Ai {
|
|
|
106
113
|
private readonly modelConfig: AIConfig = defaultAIConfig,
|
|
107
114
|
) {
|
|
108
115
|
if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0)) throw new AIConfigurationError('timeoutMs must be positive.');
|
|
116
|
+
this.providerAdmission = new AIProviderAdmission({ recoveryLeaseSeconds: (options.timeoutMs ?? 60_000) / 1000 + 30, ...options.providerAdmission });
|
|
117
|
+
if ((options.providerAdmission?.recoveryLeaseSeconds ?? Infinity) * 1000 <= (options.timeoutMs ?? 60_000)) throw new AIConfigurationError('Recovery lease must exceed provider timeout.');
|
|
109
118
|
this.models = { conversation: AiConversation, request: AiRequest, message: AiMessage, ...options.models };
|
|
110
119
|
this.scopeField = options.scopeField ?? 'scope';
|
|
111
120
|
this.rateLimiter = options.rateLimiter === false
|
|
@@ -247,6 +256,8 @@ export class Ai {
|
|
|
247
256
|
const result = await this.generateTextResult({
|
|
248
257
|
model: input.model,
|
|
249
258
|
provider: input.provider,
|
|
259
|
+
transientFailureScope: input.transientFailureScope,
|
|
260
|
+
serviceTier: input.serviceTier,
|
|
250
261
|
instructions: input.instructions,
|
|
251
262
|
input: input.input,
|
|
252
263
|
maxOutputTokens: input.maxOutputTokens,
|
|
@@ -303,6 +314,9 @@ export class Ai {
|
|
|
303
314
|
const operation = options.operation ?? 'responses.create';
|
|
304
315
|
const attempts = this.resolveProviders(input.provider ?? null, input.model ?? null)
|
|
305
316
|
.filter(attempt => attempt.supportsResponsesApi);
|
|
317
|
+
const serviceTier = input.serviceTier ?? 'default';
|
|
318
|
+
for (const attempt of attempts) assertAIServiceTier(attempt.provider, serviceTier);
|
|
319
|
+
const timeoutMs = this.requestTimeoutMs(serviceTier);
|
|
306
320
|
const attemptFailures: AIProviderAttemptFailure[] = [];
|
|
307
321
|
let tracked: TrackedRequest | null = null;
|
|
308
322
|
let trackedSettled = false;
|
|
@@ -312,7 +326,7 @@ export class Ai {
|
|
|
312
326
|
}
|
|
313
327
|
|
|
314
328
|
for (let index = 0; index < attempts.length; index++) {
|
|
315
|
-
const attempt = attempts[index]
|
|
329
|
+
const attempt = { ...attempts[index]!, transientFailureScope: input.transientFailureScope };
|
|
316
330
|
const hasFallback = index < attempts.length - 1;
|
|
317
331
|
const attemptStartMs = Date.now();
|
|
318
332
|
const request = {
|
|
@@ -320,7 +334,7 @@ export class Ai {
|
|
|
320
334
|
instructions: input.instructions,
|
|
321
335
|
input: input.input,
|
|
322
336
|
store: false,
|
|
323
|
-
...(attempt.provider === AI_PROVIDER.openai ? { service_tier:
|
|
337
|
+
...(attempt.provider === AI_PROVIDER.openai ? { service_tier: serviceTier } : {}),
|
|
324
338
|
...maxOutputTokensPayload(input.maxOutputTokens),
|
|
325
339
|
...extraRequest,
|
|
326
340
|
};
|
|
@@ -371,14 +385,15 @@ export class Ai {
|
|
|
371
385
|
baseUrl: attempt.baseUrl,
|
|
372
386
|
apiKey: attempt.apiKey,
|
|
373
387
|
request,
|
|
374
|
-
fetcher: this.fetcher(),
|
|
388
|
+
fetcher: this.providerAdmission.transport(attempt, this.fetcher(timeoutMs), timeoutMs),
|
|
375
389
|
});
|
|
376
390
|
const { payload, metadata } = result;
|
|
391
|
+
const admissionFailure = this.providerAdmission.requestFailure(attempt, null);
|
|
377
392
|
|
|
378
|
-
if (!result.ok) {
|
|
393
|
+
if (!result.ok || admissionFailure) {
|
|
379
394
|
const message = responseErrorMessage(payload) || `AI provider ${attempt.provider} request failed with HTTP ${result.status}.`;
|
|
380
395
|
|
|
381
|
-
if (hasFallback && isFailoverableResponse(result.status, payload)) {
|
|
396
|
+
if (hasFallback && (isFailoverableFailure(admissionFailure) || isFailoverableResponse(result.status, payload))) {
|
|
382
397
|
const failure = providerAttemptFailure(attempt, attemptStartMs, message, result.status, responseErrorCode(payload));
|
|
383
398
|
|
|
384
399
|
attemptFailures.push(failure);
|
|
@@ -401,9 +416,9 @@ export class Ai {
|
|
|
401
416
|
continue;
|
|
402
417
|
}
|
|
403
418
|
|
|
404
|
-
const deferred = isRateLimitFailure(result.status, payload)
|
|
419
|
+
const deferred = admissionFailure ?? (isRateLimitFailure(result.status, payload)
|
|
405
420
|
? rateLimitDeferredError(lease, metadata, message)
|
|
406
|
-
: null;
|
|
421
|
+
: null);
|
|
407
422
|
|
|
408
423
|
if (tracked) {
|
|
409
424
|
attachProviderAttempts(tracked.aiRequest, attemptFailures);
|
|
@@ -416,7 +431,7 @@ export class Ai {
|
|
|
416
431
|
|
|
417
432
|
if (deferred) throw deferred;
|
|
418
433
|
|
|
419
|
-
throw new AIRequestError(message, responseErrorCode(payload));
|
|
434
|
+
throw new AIRequestError(message, responseErrorCode(payload), { status: result.status, requestId: metadata.providerRequestId });
|
|
420
435
|
}
|
|
421
436
|
|
|
422
437
|
const text = payload?.status !== undefined && payload.status !== 'completed' ? null : responseOutputText(payload);
|
|
@@ -497,15 +512,15 @@ export class Ai {
|
|
|
497
512
|
continue;
|
|
498
513
|
}
|
|
499
514
|
|
|
500
|
-
if (tracked && !trackedSettled && !(error instanceof AIRequestError) && !(error instanceof AIRateLimitDeferredError)) {
|
|
515
|
+
if (tracked && !trackedSettled && (!(error instanceof AIRequestError) || error instanceof AIProviderStoppedError) && !(error instanceof AIRateLimitDeferredError)) {
|
|
501
516
|
attachProviderAttempts(tracked.aiRequest, attemptFailures);
|
|
502
517
|
await this.failTrackedRequest(
|
|
503
518
|
tracked,
|
|
504
|
-
|
|
519
|
+
providerAdmissionResponse(error),
|
|
505
520
|
errorMessage(error),
|
|
506
|
-
|
|
521
|
+
providerAdmissionMetadata(error),
|
|
507
522
|
failedLease,
|
|
508
|
-
providerStarted,
|
|
523
|
+
providerAdmissionStarted(error, providerStarted),
|
|
509
524
|
);
|
|
510
525
|
}
|
|
511
526
|
|
|
@@ -558,7 +573,7 @@ export class Ai {
|
|
|
558
573
|
input: TrackedProviderAttemptFailure,
|
|
559
574
|
): Promise<void> {
|
|
560
575
|
const usage = tokenUsage(input.response);
|
|
561
|
-
const modelCostUSD = textRequestCostUSD(input.attempt.provider, input.attempt.model, usage, input.response);
|
|
576
|
+
const modelCostUSD = textRequestCostUSD(input.attempt.provider, input.attempt.model, usage, input.response, input.request.service_tier);
|
|
562
577
|
|
|
563
578
|
const aiRequest = new this.models.request({
|
|
564
579
|
conversation: tracked.conversation,
|
|
@@ -693,7 +708,7 @@ export class Ai {
|
|
|
693
708
|
lease: AIRateLimitLease | null = null,
|
|
694
709
|
): Promise<void> {
|
|
695
710
|
const usage = tokenUsage(response);
|
|
696
|
-
const costUSD = textRequestCostUSD(tracked.provider, tracked.model, usage, response);
|
|
711
|
+
const costUSD = textRequestCostUSD(tracked.provider, tracked.model, usage, response, asRecord(tracked.aiRequest.request)?.service_tier);
|
|
697
712
|
|
|
698
713
|
tracked.aiRequest.assign({
|
|
699
714
|
response,
|
|
@@ -738,7 +753,7 @@ export class Ai {
|
|
|
738
753
|
const usage = tokenUsage(response);
|
|
739
754
|
const costUSD = !providerStarted
|
|
740
755
|
? 0
|
|
741
|
-
: textRequestCostUSD(tracked.provider, tracked.model, usage, response);
|
|
756
|
+
: textRequestCostUSD(tracked.provider, tracked.model, usage, response, asRecord(tracked.aiRequest.request)?.service_tier);
|
|
742
757
|
|
|
743
758
|
tracked.aiRequest.assign({
|
|
744
759
|
response,
|
|
@@ -890,7 +905,12 @@ export class Ai {
|
|
|
890
905
|
request,
|
|
891
906
|
metadata: options.metadata ?? null,
|
|
892
907
|
startedAt: new Date(),
|
|
893
|
-
})
|
|
908
|
+
});
|
|
909
|
+
try {
|
|
910
|
+
await aiRequest.save();
|
|
911
|
+
} catch (error) {
|
|
912
|
+
throw new AIRequestTrackingError(error);
|
|
913
|
+
}
|
|
894
914
|
|
|
895
915
|
return {
|
|
896
916
|
aiRequest,
|
|
@@ -907,12 +927,13 @@ export class Ai {
|
|
|
907
927
|
response: EmbeddingResponsePayloadWithUsage | null,
|
|
908
928
|
metadata: AIProviderResponseMetadata = emptyProviderResponseMetadata(),
|
|
909
929
|
lease: AIRateLimitLease | null = null,
|
|
930
|
+
retainResult = false,
|
|
910
931
|
): Promise<void> {
|
|
911
932
|
const usage = embeddingTokenUsage(response);
|
|
912
933
|
const costUSD = calculateAIRequestCostUSD(tracked.model, usage);
|
|
913
934
|
|
|
914
935
|
tracked.aiRequest.assign({
|
|
915
|
-
response: compactEmbeddingResponse(response),
|
|
936
|
+
response: retainResult ? response : compactEmbeddingResponse(response),
|
|
916
937
|
providerRequestId: metadata.providerRequestId,
|
|
917
938
|
providerProcessingMs: metadata.providerProcessingMs,
|
|
918
939
|
rateLimitBucket: lease?.bucket ?? null,
|
|
@@ -1153,9 +1174,11 @@ export class Ai {
|
|
|
1153
1174
|
* @param initialLease - Optional preflight reservation consumed by the first request.
|
|
1154
1175
|
* @returns SDK provider using the service's transport and rate-limit lifecycle.
|
|
1155
1176
|
*/
|
|
1156
|
-
createAgentProvider(attempt: AIProviderAttempt, initialLease: AIRateLimitLease | null = null): ModelProvider {
|
|
1177
|
+
createAgentProvider(attempt: AIProviderAttempt, initialLease: AIRateLimitLease | null = null, serviceTier: AIServiceTier = 'default'): ModelProvider {
|
|
1178
|
+
assertAIServiceTier(attempt.provider, serviceTier);
|
|
1179
|
+
const timeoutMs = this.requestTimeoutMs(serviceTier);
|
|
1157
1180
|
return new OpenAIProvider({
|
|
1158
|
-
openAIClient: new OpenAI({ apiKey: attempt.apiKey, baseURL: attempt.baseUrl, fetch: this.agentFetcher(attempt, initialLease), timeout:
|
|
1181
|
+
openAIClient: new OpenAI({ apiKey: attempt.apiKey, baseURL: attempt.baseUrl, fetch: this.agentFetcher(attempt, initialLease, timeoutMs), timeout: timeoutMs, maxRetries: 0 }),
|
|
1159
1182
|
useResponses: attempt.supportsResponsesApi,
|
|
1160
1183
|
});
|
|
1161
1184
|
}
|
|
@@ -1172,9 +1195,9 @@ export class Ai {
|
|
|
1172
1195
|
* @param initialLease - First-request reservation, if acquired by the agent.
|
|
1173
1196
|
* @returns Transport that maintains provider capacity and request diagnostics.
|
|
1174
1197
|
*/
|
|
1175
|
-
private agentFetcher(attempt: AIProviderAttempt, initialLease: AIRateLimitLease | null): typeof fetch {
|
|
1198
|
+
private agentFetcher(attempt: AIProviderAttempt, initialLease: AIRateLimitLease | null, timeoutMs: number): typeof fetch {
|
|
1176
1199
|
let pendingLease = initialLease;
|
|
1177
|
-
const transport = this.fetcher();
|
|
1200
|
+
const transport = this.providerAdmission.transport(attempt, this.fetcher(timeoutMs), timeoutMs);
|
|
1178
1201
|
return async (url, init) => {
|
|
1179
1202
|
const aiRequest = aiExecutionContext.getStore()?.aiRequest ?? null;
|
|
1180
1203
|
const lease = pendingLease ?? await this.acquireRateLimit({
|
|
@@ -1213,12 +1236,22 @@ export class Ai {
|
|
|
1213
1236
|
};
|
|
1214
1237
|
}
|
|
1215
1238
|
|
|
1239
|
+
/** Resolves the account connection for OpenAI-only images and embeddings. */
|
|
1240
|
+
private openAIAdmissionAttempt(model: string): AIProviderAttempt {
|
|
1241
|
+
return { provider: AI_PROVIDER.openai, model, apiKey: this.requireApiKey(), baseUrl: this.baseUrl(), supportsResponsesApi: true };
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
/** Resolves a tier-aware request timeout while respecting an explicit service override. */
|
|
1245
|
+
private requestTimeoutMs(serviceTier: AIServiceTier): number {
|
|
1246
|
+
return this.options.timeoutMs ?? (serviceTier === 'flex' ? 900_000 : 60_000);
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1216
1249
|
/**
|
|
1217
1250
|
* Fetch implementation used by provider calls.
|
|
1218
1251
|
*/
|
|
1219
|
-
private fetcher(): typeof fetch {
|
|
1252
|
+
private fetcher(timeoutMs = this.options.timeoutMs ?? 60_000): typeof fetch {
|
|
1220
1253
|
const transport = this.options.fetch || fetch;
|
|
1221
|
-
return (url, init) => transport(url, { ...init, signal: init?.signal ?? AbortSignal.timeout(
|
|
1254
|
+
return (url, init) => transport(url, { ...init, signal: init?.signal ?? AbortSignal.timeout(timeoutMs) });
|
|
1222
1255
|
}
|
|
1223
1256
|
|
|
1224
1257
|
/**
|
|
@@ -1325,6 +1358,7 @@ export class Ai {
|
|
|
1325
1358
|
const model = input.model || this.config('ImageGeneration', 'gpt-image-2');
|
|
1326
1359
|
const prompt = input.prompt.replace(/\s+/g, ' ').trim();
|
|
1327
1360
|
const outputFormat = input.outputFormat ?? 'png';
|
|
1361
|
+
const admissionAttempt = this.openAIAdmissionAttempt(model);
|
|
1328
1362
|
const operation = options.operation ?? 'images.generate';
|
|
1329
1363
|
const request = {
|
|
1330
1364
|
model,
|
|
@@ -1378,7 +1412,7 @@ export class Ai {
|
|
|
1378
1412
|
await this.attachRateLimitRequest(lease, tracked?.aiRequest ?? null);
|
|
1379
1413
|
|
|
1380
1414
|
providerStarted = true;
|
|
1381
|
-
const response = await this.fetcher()(this.imagesUrl(), {
|
|
1415
|
+
const response = await this.providerAdmission.transport(admissionAttempt, this.fetcher())(this.imagesUrl(), {
|
|
1382
1416
|
method: 'POST',
|
|
1383
1417
|
headers: {
|
|
1384
1418
|
authorization: `Bearer ${apiKey}`,
|
|
@@ -1389,11 +1423,12 @@ export class Ai {
|
|
|
1389
1423
|
const metadata = providerResponseMetadata(response.headers);
|
|
1390
1424
|
const payload = await response.json().catch(() => null) as ImageResponsePayloadWithUsage | null;
|
|
1391
1425
|
|
|
1392
|
-
|
|
1426
|
+
const admissionFailure = this.providerAdmission.requestFailure(admissionAttempt, null);
|
|
1427
|
+
if (!response.ok || admissionFailure) {
|
|
1393
1428
|
const message = responseErrorMessage(payload as TextResponsePayloadWithUsage | null) || `OpenAI image request failed with HTTP ${response.status}.`;
|
|
1394
|
-
const deferred = isRateLimitFailure(response.status, payload)
|
|
1429
|
+
const deferred = admissionFailure ?? (isRateLimitFailure(response.status, payload)
|
|
1395
1430
|
? rateLimitDeferredError(lease, metadata, message)
|
|
1396
|
-
: null;
|
|
1431
|
+
: null);
|
|
1397
1432
|
|
|
1398
1433
|
if (tracked) {
|
|
1399
1434
|
await this.failTrackedImageRequest(tracked, payload, message, metadata, lease);
|
|
@@ -1405,7 +1440,7 @@ export class Ai {
|
|
|
1405
1440
|
|
|
1406
1441
|
if (deferred) throw deferred;
|
|
1407
1442
|
|
|
1408
|
-
throw new AIRequestError(message, responseErrorCode(payload));
|
|
1443
|
+
throw new AIRequestError(message, responseErrorCode(payload), { status: response.status, requestId: metadata.providerRequestId });
|
|
1409
1444
|
}
|
|
1410
1445
|
|
|
1411
1446
|
const b64Json = imageBase64(payload);
|
|
@@ -1477,18 +1512,18 @@ export class Ai {
|
|
|
1477
1512
|
|
|
1478
1513
|
await this.releaseRateLimit(lease);
|
|
1479
1514
|
|
|
1480
|
-
if (tracked && !trackedSettled
|
|
1515
|
+
if (tracked && !trackedSettled) {
|
|
1481
1516
|
await this.failTrackedImageRequest(
|
|
1482
1517
|
tracked,
|
|
1483
|
-
|
|
1518
|
+
providerAdmissionResponse(error),
|
|
1484
1519
|
errorMessage(error),
|
|
1485
|
-
|
|
1520
|
+
providerAdmissionMetadata(error),
|
|
1486
1521
|
lease,
|
|
1487
|
-
providerStarted,
|
|
1522
|
+
providerAdmissionStarted(error, providerStarted),
|
|
1488
1523
|
);
|
|
1489
1524
|
}
|
|
1490
1525
|
|
|
1491
|
-
if (error instanceof
|
|
1526
|
+
if (isQueueRetryLaterError(error) || error instanceof AIProviderStoppedError) throw error;
|
|
1492
1527
|
if (error instanceof AIAllowanceExceededError) throw error;
|
|
1493
1528
|
if (error instanceof AIRequestError) throw error;
|
|
1494
1529
|
|
|
@@ -1507,7 +1542,7 @@ export class Ai {
|
|
|
1507
1542
|
async generateEmbedding(
|
|
1508
1543
|
input: string,
|
|
1509
1544
|
model: string = 'text-embedding-3-small',
|
|
1510
|
-
options:
|
|
1545
|
+
options: GenerateEmbeddingOptions = {},
|
|
1511
1546
|
): Promise<GenerateEmbeddingResult> {
|
|
1512
1547
|
options = scopedAiOptions(options, this.scopeField);
|
|
1513
1548
|
assertIndependentUsage(options);
|
|
@@ -1515,6 +1550,7 @@ export class Ai {
|
|
|
1515
1550
|
if (!input) throw new Error('Input is required for embedding generation.');
|
|
1516
1551
|
|
|
1517
1552
|
const apiKey = this.requireApiKey();
|
|
1553
|
+
const admissionAttempt = this.openAIAdmissionAttempt(model);
|
|
1518
1554
|
const operation = options.operation ?? 'embeddings.create';
|
|
1519
1555
|
const request = {
|
|
1520
1556
|
model,
|
|
@@ -1556,7 +1592,7 @@ export class Ai {
|
|
|
1556
1592
|
|
|
1557
1593
|
await this.attachRateLimitRequest(lease, tracked?.aiRequest ?? null);
|
|
1558
1594
|
providerStarted = true;
|
|
1559
|
-
const response = await this.fetcher()(this.embeddingsUrl(), {
|
|
1595
|
+
const response = await this.providerAdmission.transport(admissionAttempt, this.fetcher())(this.embeddingsUrl(), {
|
|
1560
1596
|
method: 'POST',
|
|
1561
1597
|
headers: {
|
|
1562
1598
|
authorization: `Bearer ${apiKey}`,
|
|
@@ -1567,11 +1603,12 @@ export class Ai {
|
|
|
1567
1603
|
const metadata = providerResponseMetadata(response.headers);
|
|
1568
1604
|
const payload = await response.json().catch(() => null) as EmbeddingResponsePayloadWithUsage | null;
|
|
1569
1605
|
|
|
1570
|
-
|
|
1606
|
+
const admissionFailure = this.providerAdmission.requestFailure(admissionAttempt, null);
|
|
1607
|
+
if (!response.ok || admissionFailure) {
|
|
1571
1608
|
const message = responseErrorMessage(payload as TextResponsePayloadWithUsage | null) || `OpenAI embedding request failed with HTTP ${response.status}.`;
|
|
1572
|
-
const deferred = isRateLimitFailure(response.status, payload)
|
|
1609
|
+
const deferred = admissionFailure ?? (isRateLimitFailure(response.status, payload)
|
|
1573
1610
|
? rateLimitDeferredError(lease, metadata, message)
|
|
1574
|
-
: null;
|
|
1611
|
+
: null);
|
|
1575
1612
|
|
|
1576
1613
|
if (tracked) {
|
|
1577
1614
|
await this.failTrackedEmbeddingRequest(tracked, payload, message, metadata, lease);
|
|
@@ -1583,7 +1620,7 @@ export class Ai {
|
|
|
1583
1620
|
|
|
1584
1621
|
if (deferred) throw deferred;
|
|
1585
1622
|
|
|
1586
|
-
throw new AIRequestError(message, responseErrorCode(payload));
|
|
1623
|
+
throw new AIRequestError(message, responseErrorCode(payload), { status: response.status, requestId: metadata.providerRequestId });
|
|
1587
1624
|
}
|
|
1588
1625
|
|
|
1589
1626
|
const vector = payload?.data?.[0]?.embedding;
|
|
@@ -1602,7 +1639,7 @@ export class Ai {
|
|
|
1602
1639
|
}
|
|
1603
1640
|
|
|
1604
1641
|
if (tracked) {
|
|
1605
|
-
await this.completeTrackedEmbeddingRequest(tracked, payload, metadata, lease);
|
|
1642
|
+
await this.completeTrackedEmbeddingRequest(tracked, payload, metadata, lease, options.retainResult === true);
|
|
1606
1643
|
trackedSettled = true;
|
|
1607
1644
|
}
|
|
1608
1645
|
|
|
@@ -1625,18 +1662,19 @@ export class Ai {
|
|
|
1625
1662
|
|
|
1626
1663
|
await this.releaseRateLimit(lease);
|
|
1627
1664
|
|
|
1628
|
-
if (tracked && !trackedSettled && !(error instanceof AIRequestError) && !(error instanceof AIRateLimitDeferredError)) {
|
|
1665
|
+
if (tracked && !trackedSettled && (!(error instanceof AIRequestError) || error instanceof AIProviderStoppedError) && !(error instanceof AIRateLimitDeferredError)) {
|
|
1629
1666
|
await this.failTrackedEmbeddingRequest(
|
|
1630
1667
|
tracked,
|
|
1631
|
-
|
|
1668
|
+
providerAdmissionResponse(error),
|
|
1632
1669
|
errorMessage(error),
|
|
1633
|
-
|
|
1670
|
+
providerAdmissionMetadata(error),
|
|
1634
1671
|
lease,
|
|
1635
|
-
providerStarted,
|
|
1672
|
+
providerAdmissionStarted(error, providerStarted),
|
|
1636
1673
|
);
|
|
1637
1674
|
}
|
|
1638
1675
|
|
|
1639
|
-
if (error instanceof
|
|
1676
|
+
if (isQueueRetryLaterError(error) || error instanceof AIProviderStoppedError) throw error;
|
|
1677
|
+
if (error instanceof AIRequestTrackingError) throw error;
|
|
1640
1678
|
if (error instanceof AIRequestError) throw error;
|
|
1641
1679
|
|
|
1642
1680
|
throw new AIRequestError(errorMessage(error));
|
|
@@ -1839,7 +1877,9 @@ function attachProviderAttempts(aiRequest: AiRequest, failures: AIProviderAttemp
|
|
|
1839
1877
|
* @returns True when the provider indicates a rate-limit failure.
|
|
1840
1878
|
*/
|
|
1841
1879
|
function isRateLimitFailure(status: number, payload: unknown): boolean {
|
|
1842
|
-
|
|
1880
|
+
// Some credit-exhaustion responses omit a stable code. Do not turn their
|
|
1881
|
+
// explicit billing failure into an unlimited queue capacity deferral.
|
|
1882
|
+
if (isOpenAIQuotaError(payload) || /\b(?:you have )?no credits remaining\b/i.test(openAIProviderError(payload).message)) return false;
|
|
1843
1883
|
|
|
1844
1884
|
const code = responseErrorCode(payload);
|
|
1845
1885
|
|
|
@@ -1930,9 +1970,10 @@ function textRequestCostUSD(
|
|
|
1930
1970
|
model: string,
|
|
1931
1971
|
usage: TokenUsage,
|
|
1932
1972
|
payload: TextResponsePayloadWithUsage | null,
|
|
1973
|
+
requestedTier?: unknown,
|
|
1933
1974
|
): number | null {
|
|
1934
1975
|
if (provider === AI_PROVIDER.openai) {
|
|
1935
|
-
return calculateAIRequestCostUSD(model, usage);
|
|
1976
|
+
return calculateAIRequestCostUSD(typeof payload?.model === 'string' ? payload.model : model, { ...usage, serviceTier: effectiveAIServiceTier(payload?.service_tier, requestedTier) });
|
|
1936
1977
|
}
|
|
1937
1978
|
|
|
1938
1979
|
return providerReportedCostUSD(provider, payload);
|
|
@@ -2174,3 +2215,18 @@ function scopeRecordId(scope: AIRecordIdentity | string | null): string | null {
|
|
|
2174
2215
|
|
|
2175
2216
|
return id === null || id === undefined ? null : String(id);
|
|
2176
2217
|
}
|
|
2218
|
+
|
|
2219
|
+
/** Retains safe provider diagnostics for admission failures in the existing audit trail. */
|
|
2220
|
+
function providerAdmissionResponse(error: unknown): null | { error: { code: string | null; message: string } } {
|
|
2221
|
+
return error instanceof AIProviderStoppedError ? { error: { code: error.providerCode ?? error.code, message: error.message } } : null;
|
|
2222
|
+
}
|
|
2223
|
+
|
|
2224
|
+
/** Distinguishes actual provider rejection from blocked-before-provider work. */
|
|
2225
|
+
function providerAdmissionStarted(error: unknown, fallback: boolean): boolean {
|
|
2226
|
+
return error instanceof AIProviderStoppedError || error instanceof AIProviderDeferredError ? error.providerStarted : fallback;
|
|
2227
|
+
}
|
|
2228
|
+
|
|
2229
|
+
/** Keeps provider support identifiers without duplicating response bodies. */
|
|
2230
|
+
function providerAdmissionMetadata(error: unknown): AIProviderResponseMetadata {
|
|
2231
|
+
return { ...emptyProviderResponseMetadata(), providerRequestId: error instanceof AIProviderStoppedError ? error.requestId : null };
|
|
2232
|
+
}
|
|
@@ -58,7 +58,7 @@ export function openAIProviderError(value: unknown): OpenAIProviderErrorDetails
|
|
|
58
58
|
export function isOpenAIQuotaError(value: unknown): boolean {
|
|
59
59
|
const code = openAIProviderError(value).code;
|
|
60
60
|
|
|
61
|
-
return code !== null && OPENAI_QUOTA_ERROR_CODES.has(code);
|
|
61
|
+
return (code !== null && OPENAI_QUOTA_ERROR_CODES.has(code)) || /\b(?:you have )?no credits remaining\b/i.test(openAIProviderError(value).message);
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Maximum retained decoded characters for one SSE line or joined data event. */
|
|
2
|
+
const MAX_EVENT_CHARACTERS = 1_048_576;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Observes SSE framing without rewriting transport bytes or dispatching SDK events.
|
|
6
|
+
* CR, LF and CRLF terminate lines; blank lines dispatch joined data fields. An
|
|
7
|
+
* oversized event is discarded until its blank boundary, allowing later errors
|
|
8
|
+
* to remain observable. Malformed or unfinished input permanently disqualifies
|
|
9
|
+
* this observer from asserting recovery, even if a later event completes.
|
|
10
|
+
*/
|
|
11
|
+
export class ProviderSseObserver {
|
|
12
|
+
#line = '';
|
|
13
|
+
#lineNonempty = false;
|
|
14
|
+
#skipLf = false;
|
|
15
|
+
#data: string[] = [];
|
|
16
|
+
#dataLength = 0;
|
|
17
|
+
#eventOpen = false;
|
|
18
|
+
#discardEvent = false;
|
|
19
|
+
#valid = true;
|
|
20
|
+
|
|
21
|
+
/** Receives complete joined data fields; the caller owns provider semantics. */
|
|
22
|
+
constructor(readonly onData: (data: string) => Promise<void>) {}
|
|
23
|
+
|
|
24
|
+
/** Records malformed JSON/encoding while continuing to observe later events. */
|
|
25
|
+
invalidate(): void { this.#valid = false; }
|
|
26
|
+
|
|
27
|
+
/** True only when every observed event is valid and ends at a blank boundary. */
|
|
28
|
+
get complete(): boolean { return this.#valid && !this.#lineNonempty && !this.#eventOpen && !this.#discardEvent; }
|
|
29
|
+
|
|
30
|
+
/** Consumes one decoded fragment; CRLF may be split between calls. */
|
|
31
|
+
async push(text: string): Promise<void> {
|
|
32
|
+
let start = 0;
|
|
33
|
+
for (let index = 0; index < text.length; index++) {
|
|
34
|
+
const character = text[index];
|
|
35
|
+
if (this.#skipLf) {
|
|
36
|
+
this.#skipLf = false;
|
|
37
|
+
if (character === '\n') { start = index + 1; continue; }
|
|
38
|
+
}
|
|
39
|
+
if (character !== '\r' && character !== '\n') continue;
|
|
40
|
+
this.#append(text.slice(start, index));
|
|
41
|
+
await this.#finishLine();
|
|
42
|
+
this.#skipLf = character === '\r';
|
|
43
|
+
start = index + 1;
|
|
44
|
+
}
|
|
45
|
+
this.#append(text.slice(start));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Bounds retained line and event storage before adding another fragment. */
|
|
49
|
+
#append(fragment: string): void {
|
|
50
|
+
if (!fragment.length) return;
|
|
51
|
+
this.#lineNonempty = true;
|
|
52
|
+
if (this.#discardEvent) return;
|
|
53
|
+
if (this.#line.length + this.#dataLength + fragment.length > MAX_EVENT_CHARACTERS) {
|
|
54
|
+
this.invalidate();
|
|
55
|
+
this.#discardEvent = true;
|
|
56
|
+
this.#line = '';
|
|
57
|
+
this.#data = [];
|
|
58
|
+
this.#dataLength = 0;
|
|
59
|
+
} else this.#line += fragment;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Dispatches only complete events, retaining SSE's joined-data semantics. */
|
|
63
|
+
async #finishLine(): Promise<void> {
|
|
64
|
+
const line = this.#line;
|
|
65
|
+
const nonempty = this.#lineNonempty;
|
|
66
|
+
this.#line = '';
|
|
67
|
+
this.#lineNonempty = false;
|
|
68
|
+
if (!nonempty) {
|
|
69
|
+
const data = this.#discardEvent || !this.#data.length ? null : this.#data.join('\n');
|
|
70
|
+
this.#data = [];
|
|
71
|
+
this.#dataLength = 0;
|
|
72
|
+
this.#eventOpen = false;
|
|
73
|
+
this.#discardEvent = false;
|
|
74
|
+
if (data !== null) await this.onData(data);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (this.#discardEvent || line.startsWith(':')) return;
|
|
78
|
+
this.#eventOpen = true;
|
|
79
|
+
if (line !== 'data' && !line.startsWith('data:')) return;
|
|
80
|
+
const data = line === 'data' ? '' : line.slice(line[5] === ' ' ? 6 : 5);
|
|
81
|
+
this.#dataLength += data.length + 1;
|
|
82
|
+
if (this.#dataLength > MAX_EVENT_CHARACTERS) {
|
|
83
|
+
this.invalidate();
|
|
84
|
+
this.#discardEvent = true;
|
|
85
|
+
this.#data = [];
|
|
86
|
+
this.#dataLength = 0;
|
|
87
|
+
} else this.#data.push(data);
|
|
88
|
+
}
|
|
89
|
+
}
|