@db3.ai/app 0.1.0-beta.1 → 0.1.0-beta.4
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 +68 -9
- 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,133 @@
|
|
|
1
|
+
import { Agent } from 'undici';
|
|
2
|
+
import { BlockedUrlError } from './BlockedUrlError.js';
|
|
3
|
+
import { assertPublicUrl } from './assertPublicUrl.js';
|
|
4
|
+
import { publicAddressLookup } from './publicAddressLookup.js';
|
|
5
|
+
const DEFAULT_MAX_REDIRECTS = 4;
|
|
6
|
+
const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
|
|
7
|
+
const CROSS_ORIGIN_SENSITIVE_HEADERS = ['authorization', 'cookie', 'proxy-authorization'];
|
|
8
|
+
let publicDispatcher;
|
|
9
|
+
let privateDispatcher;
|
|
10
|
+
/**
|
|
11
|
+
* Fetches a user-supplied URL without allowing it to reach private networks.
|
|
12
|
+
*
|
|
13
|
+
* Each hop is validated before it is requested, and the connection itself uses
|
|
14
|
+
* {@link publicAddressLookup}, so the address DNS returns at connect time is
|
|
15
|
+
* the address that was checked. Redirects are followed manually: every target
|
|
16
|
+
* is validated, `303` (and `301`/`302` after `POST`) switch to `GET` without a
|
|
17
|
+
* body as `fetch` does, and credentials (`Authorization`, `Cookie`) are removed
|
|
18
|
+
* when a redirect leaves the original origin.
|
|
19
|
+
*
|
|
20
|
+
* `allowPrivate` permits private destinations without weakening TLS certificate
|
|
21
|
+
* verification. Local HTTPS receivers must present a certificate trusted by Node.
|
|
22
|
+
*
|
|
23
|
+
* The request is sent with the runtime's global `fetch`, so test doubles that
|
|
24
|
+
* replace `globalThis.fetch` continue to work.
|
|
25
|
+
*
|
|
26
|
+
* @param rawUrl - Absolute HTTP(S) URL to request.
|
|
27
|
+
* @param options - Fetch init, redirect handling and destination policy.
|
|
28
|
+
* @returns Final response and the URL that produced it.
|
|
29
|
+
* @throws {BlockedUrlError} When any hop targets a refused destination or the
|
|
30
|
+
* redirect limit is exceeded.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* const { response, finalUrl } = await guardedFetch('https://example.com/', {
|
|
34
|
+
* init: { headers: { accept: 'text/html' }, signal: AbortSignal.timeout(10_000) },
|
|
35
|
+
* });
|
|
36
|
+
*/
|
|
37
|
+
export async function guardedFetch(rawUrl, options = {}) {
|
|
38
|
+
const maxRedirects = options.maxRedirects ?? DEFAULT_MAX_REDIRECTS;
|
|
39
|
+
let current = rawUrl;
|
|
40
|
+
let init = { ...options.init };
|
|
41
|
+
for (let hop = 0;; hop++) {
|
|
42
|
+
await assertPublicUrl(current, options);
|
|
43
|
+
const response = await fetchHop(current, init, options.allowPrivate === true);
|
|
44
|
+
const location = response.headers.get('location');
|
|
45
|
+
if (!REDIRECT_STATUSES.has(response.status) || !location || options.redirect === 'manual') {
|
|
46
|
+
return { response, finalUrl: current };
|
|
47
|
+
}
|
|
48
|
+
await response.body?.cancel();
|
|
49
|
+
if (hop >= maxRedirects)
|
|
50
|
+
throw new BlockedUrlError('Too many redirects.');
|
|
51
|
+
const next = new URL(location, current).toString();
|
|
52
|
+
init = redirectInit(init, response.status, new URL(current).origin !== new URL(next).origin);
|
|
53
|
+
current = next;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Sends one request hop through the dispatcher matching the destination policy.
|
|
58
|
+
*
|
|
59
|
+
* @param url - Already validated hop URL.
|
|
60
|
+
* @param init - Fetch options for this hop.
|
|
61
|
+
* @param allowPrivate - Whether private destinations are allowed.
|
|
62
|
+
* @returns Unfollowed hop response.
|
|
63
|
+
* @throws {BlockedUrlError} When the connect-time lookup refuses the address.
|
|
64
|
+
*/
|
|
65
|
+
async function fetchHop(url, init, allowPrivate) {
|
|
66
|
+
try {
|
|
67
|
+
// The caller checks each URL/redirect; this dispatcher validates the actual
|
|
68
|
+
// socket address, including DNS changes between validation and connection.
|
|
69
|
+
return await fetch(url, {
|
|
70
|
+
...init,
|
|
71
|
+
redirect: 'manual',
|
|
72
|
+
dispatcher: hopDispatcher(allowPrivate),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw blockedCause(error) ?? error;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Chooses the connection dispatcher for one hop.
|
|
81
|
+
*
|
|
82
|
+
* @param allowPrivate - Whether private destinations are allowed.
|
|
83
|
+
* @returns Shared dispatcher for the hop's policy.
|
|
84
|
+
*/
|
|
85
|
+
function hopDispatcher(allowPrivate) {
|
|
86
|
+
if (!allowPrivate) {
|
|
87
|
+
return publicDispatcher ??= new Agent({ connect: { lookup: publicAddressLookup, rejectUnauthorized: true } });
|
|
88
|
+
}
|
|
89
|
+
return privateDispatcher ??= new Agent({ connect: { rejectUnauthorized: true } });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Builds the fetch options for the next redirect hop.
|
|
93
|
+
*
|
|
94
|
+
* @param init - Options used for the previous hop.
|
|
95
|
+
* @param status - Redirect status code.
|
|
96
|
+
* @param crossOrigin - Whether the redirect leaves the previous origin.
|
|
97
|
+
* @returns Options for the next hop.
|
|
98
|
+
*/
|
|
99
|
+
function redirectInit(init, status, crossOrigin) {
|
|
100
|
+
const method = (init.method ?? 'GET').toUpperCase();
|
|
101
|
+
const switchesToGet = status === 303
|
|
102
|
+
? method !== 'GET' && method !== 'HEAD'
|
|
103
|
+
: (status === 301 || status === 302) && method === 'POST';
|
|
104
|
+
const headers = new Headers(init.headers);
|
|
105
|
+
if (switchesToGet) {
|
|
106
|
+
headers.delete('content-type');
|
|
107
|
+
headers.delete('content-length');
|
|
108
|
+
}
|
|
109
|
+
if (crossOrigin) {
|
|
110
|
+
for (const name of CROSS_ORIGIN_SENSITIVE_HEADERS)
|
|
111
|
+
headers.delete(name);
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
...init,
|
|
115
|
+
headers,
|
|
116
|
+
...(switchesToGet ? { method: 'GET', body: undefined } : {}),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Finds a guard rejection wrapped inside a fetch network error.
|
|
121
|
+
*
|
|
122
|
+
* @param error - Error thrown by `fetch`.
|
|
123
|
+
* @returns The wrapped `BlockedUrlError`, or null.
|
|
124
|
+
*/
|
|
125
|
+
function blockedCause(error) {
|
|
126
|
+
let current = error;
|
|
127
|
+
for (let depth = 0; depth < 5 && current; depth++) {
|
|
128
|
+
if (current instanceof BlockedUrlError)
|
|
129
|
+
return current;
|
|
130
|
+
current = current.cause;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BlockedUrlError } from '../BlockedUrlError.js';
|
|
2
|
+
/** Internal connection policy; the browser adapter owns request attribution. */
|
|
3
|
+
interface ProxyOptions {
|
|
4
|
+
allowPrivate?: boolean;
|
|
5
|
+
requestTimeoutMs?: number;
|
|
6
|
+
onBlocked: (url: string, error: BlockedUrlError) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Context-owned loopback proxy enforcing the destination of every browser socket.
|
|
10
|
+
*
|
|
11
|
+
* HTTP bodies stream without buffering. HTTPS remains end-to-end TLS through a
|
|
12
|
+
* validated CONNECT tunnel, preserving browser certificates, cookies and origins.
|
|
13
|
+
* Redirects create normal browser requests and cannot escape the proxy's policy.
|
|
14
|
+
*/
|
|
15
|
+
export declare class GuardedBrowserProxy {
|
|
16
|
+
#private;
|
|
17
|
+
/** Creates an unstarted, isolated browser proxy. */
|
|
18
|
+
constructor(options: ProxyOptions);
|
|
19
|
+
/**
|
|
20
|
+
* Starts the proxy on an ephemeral loopback port.
|
|
21
|
+
* @returns Chromium proxy options; the bypass rule includes loopback traffic.
|
|
22
|
+
*/
|
|
23
|
+
start(): Promise<{
|
|
24
|
+
server: string;
|
|
25
|
+
bypass: string;
|
|
26
|
+
username: string;
|
|
27
|
+
password: string;
|
|
28
|
+
}>;
|
|
29
|
+
/** Stops accepting requests and synchronously tears down every owned socket. */
|
|
30
|
+
close(): void;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { randomBytes } from 'node:crypto';
|
|
2
|
+
import { createServer, request as httpRequest } from 'node:http';
|
|
3
|
+
import { connect } from 'node:net';
|
|
4
|
+
import { assertPublicUrl } from '../assertPublicUrl.js';
|
|
5
|
+
import { BlockedUrlError } from '../BlockedUrlError.js';
|
|
6
|
+
import { normalizedUrlHostname } from '../privateNetworkAddresses.js';
|
|
7
|
+
import { publicAddressLookup } from '../publicAddressLookup.js';
|
|
8
|
+
/**
|
|
9
|
+
* Context-owned loopback proxy enforcing the destination of every browser socket.
|
|
10
|
+
*
|
|
11
|
+
* HTTP bodies stream without buffering. HTTPS remains end-to-end TLS through a
|
|
12
|
+
* validated CONNECT tunnel, preserving browser certificates, cookies and origins.
|
|
13
|
+
* Redirects create normal browser requests and cannot escape the proxy's policy.
|
|
14
|
+
*/
|
|
15
|
+
export class GuardedBrowserProxy {
|
|
16
|
+
#options;
|
|
17
|
+
#sockets = new Set();
|
|
18
|
+
#server = createServer();
|
|
19
|
+
#username = 'db3-browser';
|
|
20
|
+
#password = randomBytes(32).toString('hex');
|
|
21
|
+
#closed = false;
|
|
22
|
+
/** Creates an unstarted, isolated browser proxy. */
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.#options = options;
|
|
25
|
+
this.#server.on('connection', socket => this.#track(socket));
|
|
26
|
+
this.#server.on('request', (request, response) => { void this.#forward(request, response); });
|
|
27
|
+
this.#server.on('connect', (request, socket, head) => { void this.#tunnel(request, socket, head); });
|
|
28
|
+
this.#server.on('clientError', (_error, socket) => socket.destroy());
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Starts the proxy on an ephemeral loopback port.
|
|
32
|
+
* @returns Chromium proxy options; the bypass rule includes loopback traffic.
|
|
33
|
+
*/
|
|
34
|
+
async start() {
|
|
35
|
+
await new Promise((resolve, reject) => {
|
|
36
|
+
this.#server.once('error', reject);
|
|
37
|
+
this.#server.listen(0, '127.0.0.1', () => {
|
|
38
|
+
this.#server.off('error', reject);
|
|
39
|
+
resolve();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
const address = this.#server.address();
|
|
43
|
+
if (!address || typeof address === 'string')
|
|
44
|
+
throw new Error('Browser proxy did not open a TCP port.');
|
|
45
|
+
return { server: `http://127.0.0.1:${address.port}`, bypass: '<-loopback>', username: this.#username, password: this.#password };
|
|
46
|
+
}
|
|
47
|
+
/** Stops accepting requests and synchronously tears down every owned socket. */
|
|
48
|
+
close() {
|
|
49
|
+
if (this.#closed)
|
|
50
|
+
return;
|
|
51
|
+
this.#closed = true;
|
|
52
|
+
for (const socket of this.#sockets)
|
|
53
|
+
socket.destroy();
|
|
54
|
+
this.#server.close();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Registers socket cleanup and an inactivity timeout without buffering data.
|
|
58
|
+
* @param socket - Accepted browser socket or outgoing destination connection.
|
|
59
|
+
*/
|
|
60
|
+
#track(socket) {
|
|
61
|
+
if (this.#closed) {
|
|
62
|
+
socket.destroy();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
this.#sockets.add(socket);
|
|
66
|
+
socket.once('close', () => this.#sockets.delete(socket));
|
|
67
|
+
socket.on('error', () => socket.destroy());
|
|
68
|
+
if ('setTimeout' in socket)
|
|
69
|
+
socket.setTimeout(this.#options.requestTimeoutMs ?? 30_000, () => socket.destroy());
|
|
70
|
+
}
|
|
71
|
+
/** Checks the per-context proxy credential supplied by Chromium. */
|
|
72
|
+
#authorized(request) {
|
|
73
|
+
return request.headers['proxy-authorization'] === `Basic ${Buffer.from(`${this.#username}:${this.#password}`).toString('base64')}`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Streams a normal HTTP proxy request through a validated connection.
|
|
77
|
+
* @param request - Browser's absolute-form request.
|
|
78
|
+
* @param response - Response streamed back to the browser.
|
|
79
|
+
*/
|
|
80
|
+
async #forward(request, response) {
|
|
81
|
+
if (!this.#authorized(request)) {
|
|
82
|
+
response.writeHead(407, { 'proxy-authenticate': 'Basic realm="db3-browser"' }).end();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const url = request.url ?? '';
|
|
86
|
+
try {
|
|
87
|
+
await assertPublicUrl(url, this.#options);
|
|
88
|
+
const destination = new URL(url);
|
|
89
|
+
if (destination.protocol !== 'http:')
|
|
90
|
+
throw new BlockedUrlError('HTTPS browser requests must use a CONNECT tunnel.');
|
|
91
|
+
if (this.#closed || response.destroyed)
|
|
92
|
+
return;
|
|
93
|
+
const headers = { ...request.headers, host: destination.host };
|
|
94
|
+
delete headers['proxy-authorization'];
|
|
95
|
+
delete headers['proxy-connection'];
|
|
96
|
+
const outgoing = httpRequest(destination, {
|
|
97
|
+
method: request.method,
|
|
98
|
+
headers,
|
|
99
|
+
agent: false,
|
|
100
|
+
lookup: this.#options.allowPrivate ? undefined : publicAddressLookup,
|
|
101
|
+
}, upstream => {
|
|
102
|
+
response.writeHead(upstream.statusCode ?? 502, upstream.headers);
|
|
103
|
+
upstream.on('error', () => response.destroy());
|
|
104
|
+
upstream.pipe(response);
|
|
105
|
+
});
|
|
106
|
+
outgoing.on('socket', socket => this.#track(socket));
|
|
107
|
+
outgoing.on('error', error => {
|
|
108
|
+
this.#reportBlocked(url, error);
|
|
109
|
+
response.destroy();
|
|
110
|
+
});
|
|
111
|
+
request.on('aborted', () => outgoing.destroy());
|
|
112
|
+
request.on('error', () => outgoing.destroy());
|
|
113
|
+
response.on('close', () => outgoing.destroy());
|
|
114
|
+
request.pipe(outgoing);
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
this.#reportBlocked(url, error);
|
|
118
|
+
response.destroy();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Opens a TLS tunnel only after validating its actual destination connection.
|
|
123
|
+
* @param request - Chromium CONNECT authority.
|
|
124
|
+
* @param browser - Browser side of the opaque tunnel.
|
|
125
|
+
* @param head - Bytes received with the CONNECT request.
|
|
126
|
+
*/
|
|
127
|
+
async #tunnel(request, browser, head) {
|
|
128
|
+
if (!this.#authorized(request)) {
|
|
129
|
+
browser.end('HTTP/1.1 407 Proxy Authentication Required\r\nProxy-Authenticate: Basic realm="db3-browser"\r\nContent-Length: 0\r\n\r\n');
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
const url = `https://${request.url ?? ''}/`;
|
|
133
|
+
try {
|
|
134
|
+
await assertPublicUrl(url, this.#options);
|
|
135
|
+
if (this.#closed || browser.destroyed)
|
|
136
|
+
return;
|
|
137
|
+
const destination = new URL(url);
|
|
138
|
+
const upstream = connect({
|
|
139
|
+
host: normalizedUrlHostname(destination.hostname),
|
|
140
|
+
port: Number(destination.port || 443),
|
|
141
|
+
lookup: this.#options.allowPrivate ? undefined : publicAddressLookup,
|
|
142
|
+
});
|
|
143
|
+
this.#track(upstream);
|
|
144
|
+
browser.once('close', () => upstream.destroy());
|
|
145
|
+
upstream.once('close', () => browser.destroy());
|
|
146
|
+
upstream.on('error', error => {
|
|
147
|
+
this.#reportBlocked(url, error);
|
|
148
|
+
browser.destroy();
|
|
149
|
+
});
|
|
150
|
+
upstream.once('connect', () => {
|
|
151
|
+
browser.write('HTTP/1.1 200 Connection Established\r\n\r\n');
|
|
152
|
+
if (head.length)
|
|
153
|
+
upstream.write(head);
|
|
154
|
+
upstream.pipe(browser);
|
|
155
|
+
browser.pipe(upstream);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
this.#reportBlocked(url, error);
|
|
160
|
+
browser.destroy();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/** Records policy refusals without allowing observer failures to escape I/O. */
|
|
164
|
+
#reportBlocked(url, error) {
|
|
165
|
+
if (!(error instanceof BlockedUrlError))
|
|
166
|
+
return;
|
|
167
|
+
try {
|
|
168
|
+
this.#options.onBlocked(url, error);
|
|
169
|
+
}
|
|
170
|
+
catch { /* Observers cannot change network enforcement. */ }
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Request } from 'playwright';
|
|
2
|
+
import type { BlockedUrlError } from '../../BlockedUrlError.js';
|
|
3
|
+
import type { PublicUrlOptions } from '../../contracts/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Details passed to the observer when the guard refuses a browser request.
|
|
6
|
+
*/
|
|
7
|
+
export interface BlockedBrowserRequest {
|
|
8
|
+
/** URL the page tried to load. */
|
|
9
|
+
url: string;
|
|
10
|
+
/** Guard rejection with a caller-safe message. */
|
|
11
|
+
error: BlockedUrlError;
|
|
12
|
+
/**
|
|
13
|
+
* Playwright request that was aborted.
|
|
14
|
+
*
|
|
15
|
+
* Use `request.isNavigationRequest()` and `request.frame()` to tell whether
|
|
16
|
+
* the page's own navigation was refused rather than an embedded resource.
|
|
17
|
+
*/
|
|
18
|
+
request: Request;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Network policy for a browser context whose traffic is routed through the guard.
|
|
22
|
+
*/
|
|
23
|
+
export interface GuardedBrowserContextOptions extends PublicUrlOptions {
|
|
24
|
+
/**
|
|
25
|
+
* Playwright resource types aborted without a network request, for example
|
|
26
|
+
* `['image', 'font', 'media']` when only the rendered DOM is needed.
|
|
27
|
+
*/
|
|
28
|
+
blockedResourceTypes?: readonly string[];
|
|
29
|
+
/** Socket inactivity timeout in milliseconds. Defaults to 30 seconds. */
|
|
30
|
+
requestTimeoutMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Observer called for each request refused by the destination policy.
|
|
33
|
+
*
|
|
34
|
+
* The request is aborted whether or not an observer is supplied.
|
|
35
|
+
*/
|
|
36
|
+
onBlocked?: (blocked: BlockedBrowserRequest) => void;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './GuardedBrowserContextOptions.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './GuardedBrowserContextOptions.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Browser, BrowserContext, BrowserContextOptions } from 'playwright';
|
|
2
|
+
import type * as playwrightNetwork from './contracts/index.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a Chromium context with connection-level private-network protection.
|
|
5
|
+
*
|
|
6
|
+
* All HTTP requests and HTTPS tunnels use a context-owned authenticated proxy.
|
|
7
|
+
* Its socket lookup validates DNS at connect time, including redirect hops that
|
|
8
|
+
* Playwright does not route again. Chromium retains native redirects, cookies,
|
|
9
|
+
* response streaming and TLS verification. Closing the context closes its proxy.
|
|
10
|
+
* Service workers and WebSockets are disabled; callers must also disable WebRTC
|
|
11
|
+
* non-proxied UDP when launching Chromium for untrusted pages.
|
|
12
|
+
*
|
|
13
|
+
* @param browser - Launched Chromium browser.
|
|
14
|
+
* @param contextOptions - Browser settings; upstream proxy overrides are refused.
|
|
15
|
+
* @param options - Destination policy, resource filters and refusal observer.
|
|
16
|
+
* @returns Isolated browser context, owned and closed by the caller.
|
|
17
|
+
* @example
|
|
18
|
+
* const context = await newGuardedBrowserContext(browser);
|
|
19
|
+
* try { await (await context.newPage()).goto(url); } finally { await context.close(); }
|
|
20
|
+
*/
|
|
21
|
+
export declare function newGuardedBrowserContext(browser: Browser, contextOptions?: BrowserContextOptions, options?: playwrightNetwork.GuardedBrowserContextOptions): Promise<BrowserContext>;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { BlockedUrlError } from '../BlockedUrlError.js';
|
|
2
|
+
import { assertPublicUrl } from '../assertPublicUrl.js';
|
|
3
|
+
import { GuardedBrowserProxy } from './GuardedBrowserProxy.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates a Chromium context with connection-level private-network protection.
|
|
6
|
+
*
|
|
7
|
+
* All HTTP requests and HTTPS tunnels use a context-owned authenticated proxy.
|
|
8
|
+
* Its socket lookup validates DNS at connect time, including redirect hops that
|
|
9
|
+
* Playwright does not route again. Chromium retains native redirects, cookies,
|
|
10
|
+
* response streaming and TLS verification. Closing the context closes its proxy.
|
|
11
|
+
* Service workers and WebSockets are disabled; callers must also disable WebRTC
|
|
12
|
+
* non-proxied UDP when launching Chromium for untrusted pages.
|
|
13
|
+
*
|
|
14
|
+
* @param browser - Launched Chromium browser.
|
|
15
|
+
* @param contextOptions - Browser settings; upstream proxy overrides are refused.
|
|
16
|
+
* @param options - Destination policy, resource filters and refusal observer.
|
|
17
|
+
* @returns Isolated browser context, owned and closed by the caller.
|
|
18
|
+
* @example
|
|
19
|
+
* const context = await newGuardedBrowserContext(browser);
|
|
20
|
+
* try { await (await context.newPage()).goto(url); } finally { await context.close(); }
|
|
21
|
+
*/
|
|
22
|
+
export async function newGuardedBrowserContext(browser, contextOptions = {}, options = {}) {
|
|
23
|
+
if (browser.browserType().name() !== 'chromium')
|
|
24
|
+
throw new Error('Guarded browser contexts require Chromium.');
|
|
25
|
+
if (contextOptions.proxy)
|
|
26
|
+
throw new Error('Guarded browser contexts own their proxy configuration.');
|
|
27
|
+
const requests = new Set();
|
|
28
|
+
const reported = new WeakSet();
|
|
29
|
+
const blockedOrigins = new Map();
|
|
30
|
+
const blockedTypes = new Set(options.blockedResourceTypes ?? []);
|
|
31
|
+
/** Attributes a connection rejection without exposing observer errors to I/O. */
|
|
32
|
+
function report(request, error) {
|
|
33
|
+
if (reported.has(request))
|
|
34
|
+
return;
|
|
35
|
+
reported.add(request);
|
|
36
|
+
try {
|
|
37
|
+
options.onBlocked?.({ url: request.url(), request, error });
|
|
38
|
+
}
|
|
39
|
+
catch { /* Observers cannot change network enforcement. */ }
|
|
40
|
+
}
|
|
41
|
+
const proxy = new GuardedBrowserProxy({
|
|
42
|
+
...options,
|
|
43
|
+
onBlocked: (url, error) => {
|
|
44
|
+
const origin = new URL(url).origin;
|
|
45
|
+
blockedOrigins.set(origin, error);
|
|
46
|
+
for (const request of requests)
|
|
47
|
+
if (new URL(request.url()).origin === origin)
|
|
48
|
+
report(request, error);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
let context;
|
|
52
|
+
try {
|
|
53
|
+
context = await browser.newContext({ ...contextOptions, proxy: await proxy.start(), serviceWorkers: 'block' });
|
|
54
|
+
context.once('close', () => { proxy.close(); requests.clear(); blockedOrigins.clear(); });
|
|
55
|
+
context.on('request', request => {
|
|
56
|
+
requests.add(request);
|
|
57
|
+
const error = blockedOrigins.get(new URL(request.url()).origin);
|
|
58
|
+
if (error)
|
|
59
|
+
report(request, error);
|
|
60
|
+
});
|
|
61
|
+
context.on('requestfinished', request => requests.delete(request));
|
|
62
|
+
context.on('requestfailed', request => requests.delete(request));
|
|
63
|
+
await context.route('**/*', async (route) => {
|
|
64
|
+
try {
|
|
65
|
+
if (blockedTypes.has(route.request().resourceType())) {
|
|
66
|
+
await route.abort('blockedbyclient');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await assertPublicUrl(route.request().url(), options);
|
|
70
|
+
await route.continue();
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (error instanceof BlockedUrlError)
|
|
74
|
+
report(route.request(), error);
|
|
75
|
+
await route.abort(error instanceof BlockedUrlError ? 'blockedbyclient' : 'failed').catch(() => undefined);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
await context.routeWebSocket('**/*', socket => socket.close());
|
|
79
|
+
return context;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
proxy.close();
|
|
83
|
+
await context?.close();
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes a URL hostname for address classification.
|
|
3
|
+
*
|
|
4
|
+
* WHATWG URL parsing already canonicalizes numeric IPv4 forms such as
|
|
5
|
+
* `2130706433` and `0x7f.1`. This helper additionally lowercases the value,
|
|
6
|
+
* removes IPv6 brackets and drops one trailing root-label dot so `localhost.`
|
|
7
|
+
* and `localhost` are treated the same.
|
|
8
|
+
*
|
|
9
|
+
* @param hostname - `URL.hostname` value to normalize.
|
|
10
|
+
* @returns Lowercase hostname or IP literal without brackets or a trailing dot.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* normalizedUrlHostname(new URL('http://[::1]/').hostname); // '::1'
|
|
14
|
+
*/
|
|
15
|
+
export declare function normalizedUrlHostname(hostname: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Checks whether a hostname is reserved for the local machine.
|
|
18
|
+
*
|
|
19
|
+
* DNS names are otherwise judged by the addresses they resolve to, so this
|
|
20
|
+
* only covers names that never need a DNS query to reach loopback.
|
|
21
|
+
*
|
|
22
|
+
* @param hostname - Hostname normalized with {@link normalizedUrlHostname}.
|
|
23
|
+
* @returns True for `localhost` and any `*.localhost` name.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isPrivateHostname(hostname: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Checks whether an IP address must not be reached by server-side requests.
|
|
28
|
+
*
|
|
29
|
+
* The policy blocks loopback, private, link-local (including cloud metadata),
|
|
30
|
+
* carrier-grade NAT, benchmarking, documentation, multicast and reserved
|
|
31
|
+
* ranges. IPv6 forms that embed an IPv4 address (mapped, NAT64 and 6to4) are
|
|
32
|
+
* judged by the embedded address, and tunnelling or deprecated forms that can
|
|
33
|
+
* reach IPv4 hosts indirectly are blocked outright. Values that are not valid
|
|
34
|
+
* IP literals return false so callers can resolve them as hostnames instead.
|
|
35
|
+
*
|
|
36
|
+
* @param address - IPv4 or IPv6 literal, with or without IPv6 brackets.
|
|
37
|
+
* @returns True when the address is private, local or reserved.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* isPrivateIpAddress('169.254.169.254'); // true
|
|
41
|
+
* isPrivateIpAddress('::ffff:7f00:1'); // true (IPv4-mapped 127.0.0.1)
|
|
42
|
+
* isPrivateIpAddress('93.184.216.34'); // false
|
|
43
|
+
*/
|
|
44
|
+
export declare function isPrivateIpAddress(address: string): boolean;
|