@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.
Files changed (653) hide show
  1. package/README.md +68 -9
  2. package/agent-instructions.md +76 -0
  3. package/dist/ai/AIErrors.d.ts +7 -1
  4. package/dist/ai/AIErrors.js +8 -1
  5. package/dist/ai/AIFailover.d.ts +10 -0
  6. package/dist/ai/AIFailover.js +3 -2
  7. package/dist/ai/AIProviderAdmission.d.ts +101 -0
  8. package/dist/ai/AIProviderAdmission.js +336 -0
  9. package/dist/ai/AIRateLimiter.d.ts +11 -2
  10. package/dist/ai/AIRateLimiter.js +125 -10
  11. package/dist/ai/AIRequestTrackingError.d.ts +22 -0
  12. package/dist/ai/AIRequestTrackingError.js +33 -0
  13. package/dist/ai/Agent.d.ts +7 -7
  14. package/dist/ai/Agent.js +84 -56
  15. package/dist/ai/Ai.d.ts +11 -3
  16. package/dist/ai/Ai.js +94 -44
  17. package/dist/ai/OpenAIProviderError.js +1 -1
  18. package/dist/ai/ProviderSseObserver.d.ts +19 -0
  19. package/dist/ai/ProviderSseObserver.js +98 -0
  20. package/dist/ai/aiServiceTier.d.ts +5 -0
  21. package/dist/ai/aiServiceTier.js +14 -0
  22. package/dist/ai/chunkEmbeddingText.d.ts +14 -0
  23. package/dist/ai/chunkEmbeddingText.js +147 -0
  24. package/dist/ai/contracts/AI.d.ts +16 -0
  25. package/dist/ai/contracts/AIRequestErrorDiagnostics.d.ts +12 -0
  26. package/dist/ai/contracts/AIRequestErrorDiagnostics.js +1 -0
  27. package/dist/ai/contracts/AIServiceTier.d.ts +2 -0
  28. package/dist/ai/contracts/AIServiceTier.js +1 -0
  29. package/dist/ai/contracts/Agent.d.ts +3 -0
  30. package/dist/ai/contracts/EmbeddingTextChunk.d.ts +25 -0
  31. package/dist/ai/contracts/EmbeddingTextChunk.js +1 -0
  32. package/dist/ai/contracts/Pricing.d.ts +7 -1
  33. package/dist/ai/contracts/Providers.d.ts +2 -0
  34. package/dist/ai/contracts/index.d.ts +2 -0
  35. package/dist/ai/contracts/index.js +1 -0
  36. package/dist/ai/index.d.ts +8 -2
  37. package/dist/ai/index.js +5 -2
  38. package/dist/ai/{Models.d.ts → modelPricing.d.ts} +2 -2
  39. package/dist/ai/{Models.js → modelPricing.js} +38 -4
  40. package/dist/apps/AppInstallation.d.ts +21 -0
  41. package/dist/apps/AppInstallation.js +16 -0
  42. package/dist/apps/AppRouteError.d.ts +6 -0
  43. package/dist/apps/AppRouteError.js +10 -0
  44. package/dist/apps/AppService.d.ts +24 -0
  45. package/dist/apps/AppService.js +21 -0
  46. package/dist/apps/Apps.d.ts +59 -0
  47. package/dist/apps/Apps.js +566 -0
  48. package/dist/apps/appsPlugin.d.ts +3 -0
  49. package/dist/apps/appsPlugin.js +36 -0
  50. package/dist/apps/commands/disableApp.d.ts +2 -0
  51. package/dist/apps/commands/disableApp.js +5 -0
  52. package/dist/apps/commands/enableApp.d.ts +2 -0
  53. package/dist/apps/commands/enableApp.js +5 -0
  54. package/dist/apps/commands/index.d.ts +10 -0
  55. package/dist/apps/commands/index.js +27 -0
  56. package/dist/apps/commands/installApp.d.ts +2 -0
  57. package/dist/apps/commands/installApp.js +5 -0
  58. package/dist/apps/commands/listApps.d.ts +2 -0
  59. package/dist/apps/commands/listApps.js +5 -0
  60. package/dist/apps/commands/makeAppMigration.d.ts +2 -0
  61. package/dist/apps/commands/makeAppMigration.js +9 -0
  62. package/dist/apps/commands/rollbackApp.d.ts +2 -0
  63. package/dist/apps/commands/rollbackApp.js +5 -0
  64. package/dist/apps/commands/uninstallApp.d.ts +2 -0
  65. package/dist/apps/commands/uninstallApp.js +5 -0
  66. package/dist/apps/contracts/AppAction.d.ts +2 -0
  67. package/dist/apps/contracts/AppAction.js +1 -0
  68. package/dist/apps/contracts/AppDefinition.d.ts +45 -0
  69. package/dist/apps/contracts/AppDefinition.js +1 -0
  70. package/dist/apps/contracts/AppDescription.d.ts +32 -0
  71. package/dist/apps/contracts/AppDescription.js +1 -0
  72. package/dist/apps/contracts/AppManifest.d.ts +30 -0
  73. package/dist/apps/contracts/AppManifest.js +1 -0
  74. package/dist/apps/contracts/AppNavigation.d.ts +9 -0
  75. package/dist/apps/contracts/AppNavigation.js +1 -0
  76. package/dist/apps/contracts/AppNavigationBadge.d.ts +6 -0
  77. package/dist/apps/contracts/AppNavigationBadge.js +1 -0
  78. package/dist/apps/contracts/AppNavigationContext.d.ts +8 -0
  79. package/dist/apps/contracts/AppNavigationContext.js +1 -0
  80. package/dist/apps/contracts/AppNavigationResult.d.ts +12 -0
  81. package/dist/apps/contracts/AppNavigationResult.js +1 -0
  82. package/dist/apps/contracts/AppRoute.d.ts +19 -0
  83. package/dist/apps/contracts/AppRoute.js +1 -0
  84. package/dist/apps/contracts/DiscoveredApp.d.ts +10 -0
  85. package/dist/apps/contracts/DiscoveredApp.js +1 -0
  86. package/dist/apps/contracts/InstalledApps.d.ts +3 -0
  87. package/dist/apps/contracts/InstalledApps.js +1 -0
  88. package/dist/apps/contracts/index.d.ts +11 -0
  89. package/dist/apps/contracts/index.js +1 -0
  90. package/dist/apps/defineApp.d.ts +7 -0
  91. package/dist/apps/defineApp.js +8 -0
  92. package/dist/apps/discoverApps.d.ts +3 -0
  93. package/dist/apps/discoverApps.js +62 -0
  94. package/dist/apps/fastify.d.ts +1 -0
  95. package/dist/apps/fastify.js +1 -0
  96. package/dist/apps/index.d.ts +7 -0
  97. package/dist/apps/index.js +7 -0
  98. package/dist/apps/normalizeAppNavigation.d.ts +3 -0
  99. package/dist/apps/normalizeAppNavigation.js +30 -0
  100. package/dist/apps/registerAppRoutes.d.ts +6 -0
  101. package/dist/apps/registerAppRoutes.js +52 -0
  102. package/dist/apps/validateAppDefinitions.d.ts +3 -0
  103. package/dist/apps/validateAppDefinitions.js +65 -0
  104. package/dist/apps/vite.d.ts +1 -0
  105. package/dist/apps/vite.js +1 -0
  106. package/dist/apps/writeAppTypes.d.ts +2 -0
  107. package/dist/apps/writeAppTypes.js +13 -0
  108. package/dist/auth/Auth.d.ts +18 -0
  109. package/dist/auth/Auth.js +89 -13
  110. package/dist/auth/PasswordLoginAttempt.d.ts +50 -0
  111. package/dist/auth/PasswordLoginAttempt.js +60 -0
  112. package/dist/auth/PasswordSuspendedError.d.ts +10 -0
  113. package/dist/auth/PasswordSuspendedError.js +13 -0
  114. package/dist/auth/contracts/PasswordAuthProviderOptions.d.ts +26 -0
  115. package/dist/auth/contracts/PasswordAuthProviderOptions.js +1 -0
  116. package/dist/auth/contracts/PasswordSuspension.d.ts +7 -0
  117. package/dist/auth/contracts/PasswordSuspension.js +1 -0
  118. package/dist/auth/contracts/PasswordSuspensionOptions.d.ts +10 -0
  119. package/dist/auth/contracts/PasswordSuspensionOptions.js +1 -0
  120. package/dist/auth/contracts/index.d.ts +3 -0
  121. package/dist/auth/contracts/index.js +3 -0
  122. package/dist/auth/index.d.ts +2 -0
  123. package/dist/auth/index.js +2 -0
  124. package/dist/auth/providers/PasswordAuthProvider.d.ts +19 -23
  125. package/dist/auth/providers/PasswordAuthProvider.js +96 -8
  126. package/dist/auth/providers/resolveAuthProviders.js +1 -0
  127. package/dist/cli/Cli.d.ts +2 -0
  128. package/dist/cli/Cli.js +8 -0
  129. package/dist/cli/commands/repl.js +2 -1
  130. package/dist/cli/contracts/CliCommand.d.ts +2 -0
  131. package/dist/cli/contracts/CliCommandInfo.d.ts +12 -0
  132. package/dist/cli/contracts/CliCommandInfo.js +1 -0
  133. package/dist/cli/contracts/index.d.ts +1 -0
  134. package/dist/cli/index.d.ts +1 -0
  135. package/dist/cli/index.js +1 -0
  136. package/dist/cli/listDb3Commands.d.ts +8 -0
  137. package/dist/cli/listDb3Commands.js +10 -0
  138. package/dist/cli/runDb3.d.ts +3 -6
  139. package/dist/cli/runDb3.js +5 -59
  140. package/dist/cli/withDb3Cli.d.ts +4 -0
  141. package/dist/cli/withDb3Cli.js +60 -0
  142. package/dist/db/ActiveQueryBuilder.d.ts +8 -0
  143. package/dist/db/ActiveQueryBuilder.js +11 -0
  144. package/dist/db/ActiveRecord.d.ts +6 -0
  145. package/dist/db/ActiveRecord.js +8 -0
  146. package/dist/db/connection.js +14 -2
  147. package/dist/db/fields/TimestampField.d.ts +1 -1
  148. package/dist/db/fields/TimestampField.js +7 -12
  149. package/dist/db/migrations/DatabaseMigrationManager.d.ts +3 -1
  150. package/dist/db/migrations/DatabaseMigrationManager.js +9 -3
  151. package/dist/db/migrations/contracts/DatabaseMigration.d.ts +7 -0
  152. package/dist/db/migrations/index.d.ts +1 -1
  153. package/dist/db/migrations/index.js +1 -1
  154. package/dist/db/migrations/{KnexMigrationRenderer.d.ts → renderKnexMigration.d.ts} +4 -3
  155. package/dist/db/migrations/{KnexMigrationRenderer.js → renderKnexMigration.js} +7 -6
  156. package/dist/flows/FlowCompiler.js +1 -1
  157. package/dist/flows/Flows.js +1 -1
  158. package/dist/flows/index.d.ts +1 -1
  159. package/dist/flows/index.js +1 -1
  160. package/dist/health/Health.d.ts +41 -0
  161. package/dist/health/Health.js +153 -0
  162. package/dist/health/contracts/Health.d.ts +36 -0
  163. package/dist/health/contracts/Health.js +1 -0
  164. package/dist/health/contracts/HealthHttp.d.ts +15 -0
  165. package/dist/health/contracts/HealthHttp.js +1 -0
  166. package/dist/health/contracts/index.d.ts +2 -0
  167. package/dist/health/contracts/index.js +1 -0
  168. package/dist/health/databaseHealthCheck.d.ts +15 -0
  169. package/dist/health/databaseHealthCheck.js +18 -0
  170. package/dist/health/fastify.d.ts +13 -0
  171. package/dist/health/fastify.js +44 -0
  172. package/dist/health/index.d.ts +3 -0
  173. package/dist/health/index.js +2 -0
  174. package/dist/in-app/InApp.d.ts +33 -0
  175. package/dist/in-app/InApp.js +191 -0
  176. package/dist/in-app/InAppError.d.ts +6 -0
  177. package/dist/in-app/InAppError.js +10 -0
  178. package/dist/in-app/InAppRecord.d.ts +36 -0
  179. package/dist/in-app/InAppRecord.js +24 -0
  180. package/dist/in-app/contracts/InAppInbox.d.ts +45 -0
  181. package/dist/in-app/contracts/InAppInbox.js +1 -0
  182. package/dist/in-app/contracts/InAppMessage.d.ts +22 -0
  183. package/dist/in-app/contracts/InAppMessage.js +1 -0
  184. package/dist/in-app/contracts/InAppScope.d.ts +17 -0
  185. package/dist/in-app/contracts/InAppScope.js +1 -0
  186. package/dist/in-app/contracts/index.d.ts +3 -0
  187. package/dist/in-app/contracts/index.js +3 -0
  188. package/dist/in-app/index.d.ts +4 -0
  189. package/dist/in-app/index.js +4 -0
  190. package/dist/in-app/validation.d.ts +21 -0
  191. package/dist/in-app/validation.js +50 -0
  192. package/dist/index.d.ts +2 -14
  193. package/dist/index.js +2 -5
  194. package/dist/logging/DevelopmentConsole.d.ts +42 -0
  195. package/dist/logging/DevelopmentConsole.js +162 -0
  196. package/dist/logging/Log.d.ts +3 -1
  197. package/dist/logging/Log.js +5 -2
  198. package/dist/logging/PrettyLogFormatter.d.ts +16 -0
  199. package/dist/logging/PrettyLogFormatter.js +151 -0
  200. package/dist/logging/acquireDevelopmentConsole.d.ts +6 -0
  201. package/dist/logging/acquireDevelopmentConsole.js +21 -0
  202. package/dist/logging/contracts/DevelopmentConsoleOptions.d.ts +16 -0
  203. package/dist/logging/contracts/DevelopmentConsoleOptions.js +1 -0
  204. package/dist/logging/contracts/EmailLogOptions.d.ts +8 -0
  205. package/dist/logging/contracts/EmailLogOptions.js +1 -0
  206. package/dist/logging/contracts/HttpExchangeMonitorOptions.d.ts +12 -0
  207. package/dist/logging/contracts/HttpExchangeMonitorOptions.js +1 -0
  208. package/dist/logging/contracts/LogTransportOptions.d.ts +19 -0
  209. package/dist/logging/contracts/LogTransportOptions.js +1 -0
  210. package/dist/logging/contracts/LoggingOptions.d.ts +12 -1
  211. package/dist/logging/contracts/index.d.ts +4 -0
  212. package/dist/logging/contracts/index.js +4 -0
  213. package/dist/logging/drivers/PinoLoggerDriver.d.ts +3 -1
  214. package/dist/logging/drivers/PinoLoggerDriver.js +75 -16
  215. package/dist/logging/formatLogEmail.d.ts +4 -0
  216. package/dist/logging/formatLogEmail.js +21 -0
  217. package/dist/logging/highlightQueueMessage.d.ts +11 -0
  218. package/dist/logging/highlightQueueMessage.js +36 -0
  219. package/dist/logging/httpBodyCapture.d.ts +24 -0
  220. package/dist/logging/httpBodyCapture.js +321 -0
  221. package/dist/logging/index.d.ts +2 -0
  222. package/dist/logging/index.js +2 -0
  223. package/dist/logging/redactLogEmail.d.ts +2 -0
  224. package/dist/logging/redactLogEmail.js +12 -0
  225. package/dist/logging/registerHttpExchangeMonitor.d.ts +10 -0
  226. package/dist/logging/registerHttpExchangeMonitor.js +43 -0
  227. package/dist/logging/transports/EmailLogTransport.d.ts +18 -0
  228. package/dist/logging/transports/EmailLogTransport.js +47 -0
  229. package/dist/mail/Mail.d.ts +2 -0
  230. package/dist/mail/Mail.js +3 -0
  231. package/dist/mail/MailDeliveryError.d.ts +9 -0
  232. package/dist/mail/MailDeliveryError.js +16 -0
  233. package/dist/mail/index.d.ts +1 -0
  234. package/dist/mail/index.js +1 -0
  235. package/dist/mail/transports/MailgunTransport.js +2 -0
  236. package/dist/mail/transports/ResendTransport.d.ts +3 -2
  237. package/dist/mail/transports/ResendTransport.js +22 -14
  238. package/dist/media/MediaManager.d.ts +4 -2
  239. package/dist/media/MediaManager.js +40 -8
  240. package/dist/network/BlockedUrlError.d.ts +16 -0
  241. package/dist/network/BlockedUrlError.js +19 -0
  242. package/dist/network/assertPublicUrl.d.ts +22 -0
  243. package/dist/network/assertPublicUrl.js +67 -0
  244. package/dist/network/contracts/GuardedFetch.d.ts +35 -0
  245. package/dist/network/contracts/GuardedFetch.js +1 -0
  246. package/dist/network/contracts/PublicUrlOptions.d.ts +17 -0
  247. package/dist/network/contracts/PublicUrlOptions.js +1 -0
  248. package/dist/network/contracts/index.d.ts +2 -0
  249. package/dist/network/contracts/index.js +2 -0
  250. package/dist/network/guardedFetch.d.ts +29 -0
  251. package/dist/network/guardedFetch.js +133 -0
  252. package/dist/network/index.d.ts +6 -0
  253. package/dist/network/index.js +6 -0
  254. package/dist/network/playwright/GuardedBrowserProxy.d.ts +32 -0
  255. package/dist/network/playwright/GuardedBrowserProxy.js +172 -0
  256. package/dist/network/playwright/contracts/GuardedBrowserContextOptions.d.ts +37 -0
  257. package/dist/network/playwright/contracts/GuardedBrowserContextOptions.js +1 -0
  258. package/dist/network/playwright/contracts/index.d.ts +1 -0
  259. package/dist/network/playwright/contracts/index.js +1 -0
  260. package/dist/network/playwright/index.d.ts +2 -0
  261. package/dist/network/playwright/index.js +2 -0
  262. package/dist/network/playwright/newGuardedBrowserContext.d.ts +21 -0
  263. package/dist/network/playwright/newGuardedBrowserContext.js +86 -0
  264. package/dist/network/privateNetworkAddresses.d.ts +44 -0
  265. package/dist/network/privateNetworkAddresses.js +157 -0
  266. package/dist/network/publicAddressLookup.d.ts +26 -0
  267. package/dist/network/publicAddressLookup.js +42 -0
  268. package/dist/notifications/Notifications.d.ts +27 -0
  269. package/dist/notifications/Notifications.js +99 -0
  270. package/dist/notifications/contracts/Notification.d.ts +56 -0
  271. package/dist/notifications/contracts/Notification.js +1 -0
  272. package/dist/notifications/contracts/NotificationDelivery.d.ts +11 -0
  273. package/dist/notifications/contracts/NotificationDelivery.js +1 -0
  274. package/dist/notifications/contracts/index.d.ts +2 -0
  275. package/dist/notifications/contracts/index.js +2 -0
  276. package/dist/notifications/index.d.ts +2 -0
  277. package/dist/notifications/index.js +2 -0
  278. package/dist/queue/JobRunAttempt.d.ts +16 -0
  279. package/dist/queue/JobRunAttempt.js +17 -0
  280. package/dist/queue/JobRunEvent.d.ts +15 -0
  281. package/dist/queue/JobRunEvent.js +16 -0
  282. package/dist/queue/JobRunStoppedError.d.ts +6 -0
  283. package/dist/queue/JobRunStoppedError.js +10 -0
  284. package/dist/queue/Queue.d.ts +19 -4
  285. package/dist/queue/Queue.js +122 -9
  286. package/dist/queue/QueueTerminalError.d.ts +9 -0
  287. package/dist/queue/QueueTerminalError.js +12 -0
  288. package/dist/queue/QueueWorker.d.ts +12 -5
  289. package/dist/queue/QueueWorker.js +94 -9
  290. package/dist/queue/QueueWorkerReporter.d.ts +17 -0
  291. package/dist/queue/QueueWorkerReporter.js +71 -0
  292. package/dist/queue/QueueableJob.d.ts +2 -2
  293. package/dist/queue/RunnableJob.d.ts +78 -0
  294. package/dist/queue/RunnableJob.js +284 -0
  295. package/dist/queue/console.d.ts +8 -0
  296. package/dist/queue/console.js +53 -19
  297. package/dist/queue/contracts/QueueDriver.d.ts +8 -0
  298. package/dist/queue/contracts/QueueJobRunner.d.ts +4 -0
  299. package/dist/queue/contracts/QueueJobRunner.js +1 -0
  300. package/dist/queue/contracts/QueuePayload.d.ts +1 -1
  301. package/dist/queue/contracts/QueueSelection.d.ts +11 -0
  302. package/dist/queue/contracts/QueueSelection.js +1 -0
  303. package/dist/queue/contracts/QueueService.d.ts +18 -4
  304. package/dist/queue/contracts/QueueWorkerLifecycle.d.ts +2 -2
  305. package/dist/queue/contracts/QueueWorkerSnapshot.d.ts +14 -0
  306. package/dist/queue/contracts/QueueWorkerSnapshot.js +1 -0
  307. package/dist/queue/contracts/QueueableJob.d.ts +7 -3
  308. package/dist/queue/contracts/QueueableJobContract.d.ts +12 -0
  309. package/dist/queue/contracts/QueueableJobContract.js +1 -0
  310. package/dist/queue/contracts/index.d.ts +4 -0
  311. package/dist/queue/contracts/index.js +2 -0
  312. package/dist/queue/drivers/DatabaseQueueDriver.d.ts +4 -0
  313. package/dist/queue/drivers/DatabaseQueueDriver.js +27 -3
  314. package/dist/queue/drivers/RedisQueueDriver.d.ts +7 -0
  315. package/dist/queue/drivers/RedisQueueDriver.js +37 -0
  316. package/dist/queue/index.d.ts +5 -0
  317. package/dist/queue/index.js +5 -0
  318. package/dist/queue/jobEnvelopeHasPrefix.d.ts +3 -0
  319. package/dist/queue/jobEnvelopeHasPrefix.js +4 -0
  320. package/dist/scheduler/ScheduledEvent.d.ts +8 -4
  321. package/dist/scheduler/ScheduledEvent.js +17 -3
  322. package/dist/scheduler/ScheduledJob.d.ts +1 -1
  323. package/dist/scheduler/Scheduler.d.ts +5 -0
  324. package/dist/scheduler/Scheduler.js +92 -28
  325. package/dist/scheduler/SchedulerCheckpointRecord.d.ts +16 -0
  326. package/dist/scheduler/SchedulerCheckpointRecord.js +53 -0
  327. package/dist/scheduler/SchedulerWorker.d.ts +3 -5
  328. package/dist/scheduler/SchedulerWorker.js +58 -14
  329. package/dist/scheduler/console.js +3 -1
  330. package/dist/scheduler/contracts/Schedule.d.ts +19 -0
  331. package/dist/scheduler/contracts/Schedule.js +1 -0
  332. package/dist/scheduler/contracts/Scheduler.d.ts +18 -6
  333. package/dist/scheduler/contracts/SchedulerCheckpoint.d.ts +23 -0
  334. package/dist/scheduler/contracts/SchedulerCheckpoint.js +1 -0
  335. package/dist/scheduler/contracts/SchedulerConsole.d.ts +5 -0
  336. package/dist/scheduler/contracts/SchedulerWorker.d.ts +6 -1
  337. package/dist/scheduler/contracts/index.d.ts +2 -0
  338. package/dist/scheduler/contracts/index.js +2 -0
  339. package/dist/scheduler/index.d.ts +1 -0
  340. package/dist/scheduler/index.js +1 -0
  341. package/dist/server/App.d.ts +36 -4
  342. package/dist/server/App.js +57 -7
  343. package/dist/server/contracts/HttpErrorHandlerOptions.d.ts +29 -0
  344. package/dist/server/contracts/HttpErrorHandlerOptions.js +1 -0
  345. package/dist/server/contracts/index.d.ts +1 -0
  346. package/dist/server/contracts/index.js +1 -0
  347. package/dist/server/index.d.ts +4 -0
  348. package/dist/server/index.js +4 -0
  349. package/dist/server/publicServerErrorMessage.d.ts +11 -0
  350. package/dist/server/publicServerErrorMessage.js +16 -0
  351. package/dist/server/registerBrowserJsonFormatting.d.ts +16 -0
  352. package/dist/server/registerBrowserJsonFormatting.js +100 -0
  353. package/dist/server/registerHttpErrorHandler.d.ts +20 -0
  354. package/dist/server/registerHttpErrorHandler.js +93 -0
  355. package/dist/ssr/vite/contracts/ViteSsrOptions.d.ts +2 -0
  356. package/dist/ssr/vite/fastifyViteSsr.js +4 -3
  357. package/dist/storage/drivers/FlystorageDisk.js +2 -2
  358. package/dist/storage/index.d.ts +2 -2
  359. package/dist/storage/index.js +2 -2
  360. package/dist/websocket/WebSocketChannels.d.ts +18 -0
  361. package/dist/websocket/WebSocketChannels.js +129 -0
  362. package/dist/websocket/WebSocketConnection.d.ts +25 -0
  363. package/dist/websocket/WebSocketConnection.js +244 -0
  364. package/dist/websocket/WebSockets.d.ts +41 -0
  365. package/dist/websocket/WebSockets.js +194 -0
  366. package/dist/websocket/client/WebSocketClient.d.ts +21 -0
  367. package/dist/websocket/client/WebSocketClient.js +230 -0
  368. package/dist/websocket/client/index.d.ts +3 -0
  369. package/dist/websocket/client/index.js +1 -0
  370. package/dist/websocket/contracts/WebSocketChannel.d.ts +20 -0
  371. package/dist/websocket/contracts/WebSocketChannel.js +1 -0
  372. package/dist/websocket/contracts/WebSocketClient.d.ts +45 -0
  373. package/dist/websocket/contracts/WebSocketClient.js +1 -0
  374. package/dist/websocket/contracts/WebSocketEndpoint.d.ts +43 -0
  375. package/dist/websocket/contracts/WebSocketEndpoint.js +1 -0
  376. package/dist/websocket/contracts/WebSocketOptions.d.ts +48 -0
  377. package/dist/websocket/contracts/WebSocketOptions.js +1 -0
  378. package/dist/websocket/contracts/WebSocketPresence.d.ts +6 -0
  379. package/dist/websocket/contracts/WebSocketPresence.js +1 -0
  380. package/dist/websocket/contracts/WebSocketServiceOptions.d.ts +12 -0
  381. package/dist/websocket/contracts/WebSocketServiceOptions.js +1 -0
  382. package/dist/websocket/contracts/index.d.ts +6 -0
  383. package/dist/websocket/contracts/index.js +1 -0
  384. package/dist/websocket/defineChannel.d.ts +8 -0
  385. package/dist/websocket/defineChannel.js +13 -0
  386. package/dist/websocket/defineWebSocket.d.ts +14 -0
  387. package/dist/websocket/defineWebSocket.js +4 -0
  388. package/dist/websocket/fastify.d.ts +11 -0
  389. package/dist/websocket/fastify.js +38 -0
  390. package/dist/websocket/index.d.ts +5 -0
  391. package/dist/websocket/index.js +4 -0
  392. package/package.json +108 -7
  393. package/src/ai/AIErrors.ts +10 -0
  394. package/src/ai/AIFailover.ts +3 -2
  395. package/src/ai/AIProviderAdmission.ts +329 -0
  396. package/src/ai/AIRateLimiter.ts +134 -10
  397. package/src/ai/AIRequestTrackingError.ts +37 -0
  398. package/src/ai/Agent.ts +85 -71
  399. package/src/ai/Ai.ts +104 -48
  400. package/src/ai/OpenAIProviderError.ts +1 -1
  401. package/src/ai/ProviderSseObserver.ts +89 -0
  402. package/src/ai/README.md +216 -11
  403. package/src/ai/aiServiceTier.ts +14 -0
  404. package/src/ai/chunkEmbeddingText.ts +137 -0
  405. package/src/ai/contracts/AI.ts +17 -0
  406. package/src/ai/contracts/AIRequestErrorDiagnostics.ts +12 -0
  407. package/src/ai/contracts/AIServiceTier.ts +2 -0
  408. package/src/ai/contracts/Agent.ts +3 -0
  409. package/src/ai/contracts/EmbeddingTextChunk.ts +26 -0
  410. package/src/ai/contracts/Pricing.ts +7 -1
  411. package/src/ai/contracts/Providers.ts +2 -0
  412. package/src/ai/contracts/index.ts +2 -0
  413. package/src/ai/examples/prepareDocumentEmbeddings.ts +20 -0
  414. package/src/ai/index.ts +9 -2
  415. package/src/ai/{Models.ts → modelPricing.ts} +37 -4
  416. package/src/apps/AppInstallation.ts +25 -0
  417. package/src/apps/AppRouteError.ts +8 -0
  418. package/src/apps/AppService.ts +30 -0
  419. package/src/apps/Apps.ts +508 -0
  420. package/src/apps/README.md +354 -0
  421. package/src/apps/appsPlugin.ts +34 -0
  422. package/src/apps/commands/disableApp.ts +6 -0
  423. package/src/apps/commands/enableApp.ts +6 -0
  424. package/src/apps/commands/index.ts +29 -0
  425. package/src/apps/commands/installApp.ts +6 -0
  426. package/src/apps/commands/listApps.ts +6 -0
  427. package/src/apps/commands/makeAppMigration.ts +9 -0
  428. package/src/apps/commands/rollbackApp.ts +6 -0
  429. package/src/apps/commands/uninstallApp.ts +6 -0
  430. package/src/apps/contracts/AppAction.ts +2 -0
  431. package/src/apps/contracts/AppDefinition.ts +49 -0
  432. package/src/apps/contracts/AppDescription.ts +27 -0
  433. package/src/apps/contracts/AppManifest.ts +32 -0
  434. package/src/apps/contracts/AppNavigation.ts +10 -0
  435. package/src/apps/contracts/AppNavigationBadge.ts +6 -0
  436. package/src/apps/contracts/AppNavigationContext.ts +6 -0
  437. package/src/apps/contracts/AppNavigationResult.ts +9 -0
  438. package/src/apps/contracts/AppRoute.ts +18 -0
  439. package/src/apps/contracts/DiscoveredApp.ts +11 -0
  440. package/src/apps/contracts/InstalledApps.ts +2 -0
  441. package/src/apps/contracts/index.ts +11 -0
  442. package/src/apps/defineApp.ts +10 -0
  443. package/src/apps/discoverApps.ts +56 -0
  444. package/src/apps/fastify.ts +1 -0
  445. package/src/apps/index.ts +7 -0
  446. package/src/apps/normalizeAppNavigation.ts +29 -0
  447. package/src/apps/registerAppRoutes.ts +48 -0
  448. package/src/apps/validateAppDefinitions.ts +52 -0
  449. package/src/apps/vite.ts +1 -0
  450. package/src/apps/writeAppTypes.ts +14 -0
  451. package/src/auth/Auth.ts +89 -23
  452. package/src/auth/PasswordLoginAttempt.ts +72 -0
  453. package/src/auth/PasswordSuspendedError.ts +13 -0
  454. package/src/auth/README.md +94 -4
  455. package/src/auth/contracts/PasswordAuthProviderOptions.ts +30 -0
  456. package/src/auth/contracts/PasswordSuspension.ts +7 -0
  457. package/src/auth/contracts/PasswordSuspensionOptions.ts +10 -0
  458. package/src/auth/contracts/index.ts +3 -0
  459. package/src/auth/examples/runPasswordAuth.ts +6 -6
  460. package/src/auth/index.ts +2 -0
  461. package/src/auth/providers/PasswordAuthProvider.ts +96 -30
  462. package/src/auth/providers/resolveAuthProviders.ts +1 -0
  463. package/src/cli/Cli.ts +9 -0
  464. package/src/cli/README.md +19 -0
  465. package/src/cli/commands/repl.ts +2 -1
  466. package/src/cli/contracts/CliCommand.ts +2 -0
  467. package/src/cli/contracts/CliCommandInfo.ts +13 -0
  468. package/src/cli/contracts/index.ts +1 -0
  469. package/src/cli/index.ts +1 -0
  470. package/src/cli/listDb3Commands.ts +12 -0
  471. package/src/cli/runDb3.ts +5 -51
  472. package/src/cli/withDb3Cli.ts +55 -0
  473. package/src/db/ActiveQueryBuilder.ts +12 -0
  474. package/src/db/ActiveRecord.ts +9 -0
  475. package/src/db/README.md +45 -1
  476. package/src/db/connection.ts +12 -1
  477. package/src/db/examples/FieldNote.ts +7 -13
  478. package/src/db/examples/KnowledgeNote.ts +7 -13
  479. package/src/db/examples/runNoteMigrations.ts +11 -11
  480. package/src/db/fields/TimestampField.ts +8 -17
  481. package/src/db/migrations/DatabaseMigrationManager.ts +12 -4
  482. package/src/db/migrations/contracts/DatabaseMigration.ts +9 -0
  483. package/src/db/migrations/index.ts +1 -1
  484. package/src/db/migrations/{KnexMigrationRenderer.ts → renderKnexMigration.ts} +8 -14
  485. package/src/flows/FlowCompiler.ts +1 -1
  486. package/src/flows/Flows.ts +1 -1
  487. package/src/flows/index.ts +1 -1
  488. package/src/health/Health.ts +163 -0
  489. package/src/health/README.md +46 -0
  490. package/src/health/contracts/Health.ts +47 -0
  491. package/src/health/contracts/HealthHttp.ts +19 -0
  492. package/src/health/contracts/index.ts +2 -0
  493. package/src/health/databaseHealthCheck.ts +21 -0
  494. package/src/health/fastify.ts +49 -0
  495. package/src/health/index.ts +3 -0
  496. package/src/in-app/InApp.ts +173 -0
  497. package/src/in-app/InAppError.ts +8 -0
  498. package/src/in-app/InAppRecord.ts +41 -0
  499. package/src/in-app/README.md +193 -0
  500. package/src/in-app/contracts/InAppInbox.ts +51 -0
  501. package/src/in-app/contracts/InAppMessage.ts +19 -0
  502. package/src/in-app/contracts/InAppScope.ts +12 -0
  503. package/src/in-app/contracts/index.ts +3 -0
  504. package/src/in-app/examples/sendReportReady.ts +14 -0
  505. package/src/in-app/index.ts +4 -0
  506. package/src/in-app/validation.ts +49 -0
  507. package/src/index.ts +2 -22
  508. package/src/logging/DevelopmentConsole.ts +154 -0
  509. package/src/logging/Log.ts +5 -2
  510. package/src/logging/PrettyLogFormatter.ts +165 -0
  511. package/src/logging/README.md +52 -109
  512. package/src/logging/acquireDevelopmentConsole.ts +19 -0
  513. package/src/logging/contracts/DevelopmentConsoleOptions.ts +13 -0
  514. package/src/logging/contracts/EmailLogOptions.ts +9 -0
  515. package/src/logging/contracts/HttpExchangeMonitorOptions.ts +13 -0
  516. package/src/logging/contracts/LogTransportOptions.ts +10 -0
  517. package/src/logging/contracts/LoggingOptions.ts +12 -1
  518. package/src/logging/contracts/index.ts +4 -0
  519. package/src/logging/development/README.md +88 -0
  520. package/src/logging/drivers/PinoLoggerDriver.ts +72 -20
  521. package/src/logging/examples/runDevelopmentLogs.ts +36 -0
  522. package/src/logging/formatLogEmail.ts +24 -0
  523. package/src/logging/highlightQueueMessage.ts +38 -0
  524. package/src/logging/httpBodyCapture.ts +393 -0
  525. package/src/logging/index.ts +2 -0
  526. package/src/logging/redactLogEmail.ts +12 -0
  527. package/src/logging/registerHttpExchangeMonitor.ts +45 -0
  528. package/src/logging/transports/EmailLogTransport.ts +46 -0
  529. package/src/mail/Mail.ts +5 -0
  530. package/src/mail/MailDeliveryError.ts +8 -0
  531. package/src/mail/README.md +11 -1
  532. package/src/mail/index.ts +1 -0
  533. package/src/mail/transports/MailgunTransport.ts +2 -0
  534. package/src/mail/transports/ResendTransport.ts +24 -22
  535. package/src/media/MediaManager.ts +31 -10
  536. package/src/media/README.md +4 -0
  537. package/src/media/examples/runPrivateFiles.ts +2 -2
  538. package/src/network/BlockedUrlError.ts +19 -0
  539. package/src/network/README.md +133 -0
  540. package/src/network/assertPublicUrl.ts +77 -0
  541. package/src/network/contracts/GuardedFetch.ts +40 -0
  542. package/src/network/contracts/PublicUrlOptions.ts +17 -0
  543. package/src/network/contracts/index.ts +2 -0
  544. package/src/network/examples/runGuardedFetch.ts +35 -0
  545. package/src/network/guardedFetch.ts +150 -0
  546. package/src/network/index.ts +6 -0
  547. package/src/network/playwright/GuardedBrowserProxy.ts +172 -0
  548. package/src/network/playwright/contracts/GuardedBrowserContextOptions.ts +43 -0
  549. package/src/network/playwright/contracts/index.ts +1 -0
  550. package/src/network/playwright/index.ts +2 -0
  551. package/src/network/playwright/newGuardedBrowserContext.ts +74 -0
  552. package/src/network/privateNetworkAddresses.ts +166 -0
  553. package/src/network/publicAddressLookup.ts +49 -0
  554. package/src/notifications/Notifications.ts +105 -0
  555. package/src/notifications/README.md +59 -0
  556. package/src/notifications/contracts/Notification.ts +65 -0
  557. package/src/notifications/contracts/NotificationDelivery.ts +11 -0
  558. package/src/notifications/contracts/index.ts +2 -0
  559. package/src/notifications/examples/ReportReadyNotification.ts +31 -0
  560. package/src/notifications/index.ts +2 -0
  561. package/src/queue/JobRunAttempt.ts +17 -0
  562. package/src/queue/JobRunEvent.ts +16 -0
  563. package/src/queue/JobRunStoppedError.ts +8 -0
  564. package/src/queue/Queue.ts +112 -11
  565. package/src/queue/QueueTerminalError.ts +12 -0
  566. package/src/queue/QueueWorker.ts +86 -7
  567. package/src/queue/QueueWorkerReporter.ts +59 -0
  568. package/src/queue/QueueableJob.ts +2 -2
  569. package/src/queue/README.md +142 -1
  570. package/src/queue/RunnableJob.ts +272 -0
  571. package/src/queue/console.ts +54 -21
  572. package/src/queue/contracts/QueueDriver.ts +9 -0
  573. package/src/queue/contracts/QueueJobRunner.ts +4 -0
  574. package/src/queue/contracts/QueuePayload.ts +1 -1
  575. package/src/queue/contracts/QueueSelection.ts +11 -0
  576. package/src/queue/contracts/QueueService.ts +19 -4
  577. package/src/queue/contracts/QueueWorkerLifecycle.ts +2 -2
  578. package/src/queue/contracts/QueueWorkerSnapshot.ts +15 -0
  579. package/src/queue/contracts/QueueableJob.ts +7 -3
  580. package/src/queue/contracts/QueueableJobContract.ts +13 -0
  581. package/src/queue/contracts/index.ts +6 -0
  582. package/src/queue/drivers/DatabaseQueueDriver.ts +25 -3
  583. package/src/queue/drivers/RedisQueueDriver.ts +36 -0
  584. package/src/queue/examples/runQueueSelection.ts +34 -0
  585. package/src/queue/index.ts +7 -0
  586. package/src/queue/jobEnvelopeHasPrefix.ts +6 -0
  587. package/src/scheduler/README.md +50 -9
  588. package/src/scheduler/ScheduledEvent.ts +20 -5
  589. package/src/scheduler/ScheduledJob.ts +1 -1
  590. package/src/scheduler/Scheduler.ts +73 -27
  591. package/src/scheduler/SchedulerCheckpointRecord.ts +51 -0
  592. package/src/scheduler/SchedulerWorker.ts +54 -19
  593. package/src/scheduler/console.ts +3 -1
  594. package/src/scheduler/contracts/Schedule.ts +22 -0
  595. package/src/scheduler/contracts/Scheduler.ts +21 -6
  596. package/src/scheduler/contracts/SchedulerCheckpoint.ts +23 -0
  597. package/src/scheduler/contracts/SchedulerConsole.ts +5 -0
  598. package/src/scheduler/contracts/SchedulerWorker.ts +6 -1
  599. package/src/scheduler/contracts/index.ts +2 -0
  600. package/src/scheduler/examples/runSchedulerWindow.ts +54 -0
  601. package/src/scheduler/index.ts +1 -0
  602. package/src/server/App.ts +73 -10
  603. package/src/server/README.md +95 -2
  604. package/src/server/contracts/HttpErrorHandlerOptions.ts +29 -0
  605. package/src/server/contracts/index.ts +1 -0
  606. package/src/server/examples/createFirstServer.ts +5 -3
  607. package/src/server/index.ts +4 -0
  608. package/src/server/publicServerErrorMessage.ts +17 -0
  609. package/src/server/registerBrowserJsonFormatting.ts +94 -0
  610. package/src/server/registerHttpErrorHandler.ts +96 -0
  611. package/src/ssr/README.md +6 -0
  612. package/src/ssr/vite/contracts/ViteSsrOptions.ts +2 -0
  613. package/src/ssr/vite/fastifyViteSsr.ts +4 -3
  614. package/src/storage/drivers/FlystorageDisk.ts +2 -2
  615. package/src/storage/index.ts +2 -2
  616. package/src/websocket/README.md +458 -0
  617. package/src/websocket/WebSocketChannels.ts +99 -0
  618. package/src/websocket/WebSocketConnection.ts +162 -0
  619. package/src/websocket/WebSockets.ts +157 -0
  620. package/src/websocket/client/WebSocketClient.ts +188 -0
  621. package/src/websocket/client/index.ts +3 -0
  622. package/src/websocket/contracts/WebSocketChannel.ts +23 -0
  623. package/src/websocket/contracts/WebSocketClient.ts +48 -0
  624. package/src/websocket/contracts/WebSocketEndpoint.ts +46 -0
  625. package/src/websocket/contracts/WebSocketOptions.ts +50 -0
  626. package/src/websocket/contracts/WebSocketPresence.ts +6 -0
  627. package/src/websocket/contracts/WebSocketServiceOptions.ts +12 -0
  628. package/src/websocket/contracts/index.ts +6 -0
  629. package/src/websocket/defineChannel.ts +14 -0
  630. package/src/websocket/defineWebSocket.ts +15 -0
  631. package/src/websocket/examples/board/LiveBoard.ts +97 -0
  632. package/src/websocket/examples/board/SummarizeBoardJob.ts +52 -0
  633. package/src/websocket/examples/board/boardSnapshot.ts +16 -0
  634. package/src/websocket/examples/board/createBoardClient.ts +43 -0
  635. package/src/websocket/examples/board/createBoardStore.ts +58 -0
  636. package/src/websocket/examples/board/registerBoardRoutes.ts +31 -0
  637. package/src/websocket/examples/createChannelSync.ts +66 -0
  638. package/src/websocket/examples/deploymentEndpoint.ts +13 -0
  639. package/src/websocket/examples/deploymentSnapshot.ts +36 -0
  640. package/src/websocket/examples/resourceChannels.ts +18 -0
  641. package/src/websocket/examples/userEndpoint.ts +27 -0
  642. package/src/websocket/fastify.ts +39 -0
  643. package/src/websocket/index.ts +5 -0
  644. package/templates/AGENTS.md +33 -2
  645. /package/dist/flows/{FlowValueValidator.d.ts → flowValueValidator.d.ts} +0 -0
  646. /package/dist/flows/{FlowValueValidator.js → flowValueValidator.js} +0 -0
  647. /package/dist/storage/{mime.d.ts → mimeTypeFromPath.d.ts} +0 -0
  648. /package/dist/storage/{mime.js → mimeTypeFromPath.js} +0 -0
  649. /package/dist/storage/{contents.d.ts → storageContentsToBuffer.d.ts} +0 -0
  650. /package/dist/storage/{contents.js → storageContentsToBuffer.js} +0 -0
  651. /package/src/flows/{FlowValueValidator.ts → flowValueValidator.ts} +0 -0
  652. /package/src/storage/{mime.ts → mimeTypeFromPath.ts} +0 -0
  653. /package/src/storage/{contents.ts → storageContentsToBuffer.ts} +0 -0
@@ -3,6 +3,8 @@ import { fileURLToPath } from 'node:url';
3
3
  import { hostname } from 'node:os';
4
4
  import pino from 'pino';
5
5
  import { isInteractiveDevelopmentEnvironment } from '../../devtools/index.js';
6
+ import { EmailLogTransport } from '../transports/EmailLogTransport.js';
7
+ import { acquireDevelopmentConsole } from '../acquireDevelopmentConsole.js';
6
8
  const defaultRedactions = [
7
9
  'password',
8
10
  '*.password',
@@ -24,6 +26,8 @@ const defaultRedactions = [
24
26
  export class PinoLoggerDriver {
25
27
  logger;
26
28
  #transport;
29
+ #emails = [];
30
+ #console;
27
31
  #closed = false;
28
32
  #closing = false;
29
33
  #closePromise = null;
@@ -32,10 +36,24 @@ export class PinoLoggerDriver {
32
36
  *
33
37
  * @param options - Framework logging configuration.
34
38
  * @param destination - Optional direct destination used by focused tests.
39
+ * @param mail - Application-owned mail service used by the email destination.
35
40
  */
36
- constructor(options = {}, destination) {
41
+ constructor(options = {}, destination, mail) {
37
42
  const environment = options.environment ?? process.env.NODE_ENV ?? 'development';
38
43
  const level = resolveLogLevel(options, process.env);
44
+ if ((options.transports?.filter(transport => transport.type === 'console').length ?? 0) > 1)
45
+ throw new Error('Configure at most one console log transport.');
46
+ for (const transport of options.transports ?? []) {
47
+ if (!['console', 'file', 'email', 'devtools'].includes(transport.type))
48
+ throw new Error('Unknown logging transport type.');
49
+ if (transport.level !== undefined && !isLogLevel(transport.level))
50
+ throw new Error('Invalid logging transport level.');
51
+ if (transport.type === 'email' && transport.level !== 'silent') {
52
+ if (!mail)
53
+ throw new Error('Email logging requires an application Mail resolver.');
54
+ this.#emails.push({ level: transport.level ?? 'error', stream: new EmailLogTransport(transport, mail) });
55
+ }
56
+ }
39
57
  const source = options.source
40
58
  ?? process.env.PLATFORM_LOG_SOURCE
41
59
  ?? process.env.npm_package_name
@@ -58,28 +76,51 @@ export class PinoLoggerDriver {
58
76
  };
59
77
  if (destination) {
60
78
  this.#transport = null;
61
- this.logger = pino(pinoOptions, destination);
79
+ this.logger = pino(pinoOptions, this.#destinations(destination));
80
+ return;
81
+ }
82
+ const format = options.consoleFormat ?? process.env.PLATFORM_LOG_FORMAT ?? 'auto';
83
+ if (!['auto', 'pretty', 'json'].includes(format))
84
+ throw new Error(`Invalid PLATFORM_LOG_FORMAT value "${format}". Use auto, pretty, or json.`);
85
+ const consoleTransport = options.transports?.find(transport => transport.type === 'console');
86
+ const consoleEnabled = options.transports ? Boolean(consoleTransport) : options.console !== false;
87
+ const pretty = consoleEnabled && consoleTransport?.level !== 'silent' && level !== 'silent' && (format === 'pretty' || (format === 'auto' && isInteractiveDevelopmentEnvironment(environment) && Boolean(process.stdout.isTTY)));
88
+ const targets = transportTargets(pretty ? { ...options, console: false, transports: options.transports?.filter(transport => transport.type !== 'console') } : options, level, environment, process.env);
89
+ if (pretty) {
90
+ this.#transport = targets.length ? pino.transport({ targets }) : null;
91
+ this.#transport?.on('error', reportTransportError);
92
+ this.#console = acquireDevelopmentConsole();
93
+ const streams = [{ level: (consoleTransport?.level === 'silent' ? 'trace' : consoleTransport?.level) ?? level, stream: this.#console.console }];
94
+ if (this.#transport)
95
+ streams.push({ level: 'trace', stream: this.#transport });
96
+ this.logger = pino(pinoOptions, this.#destinations(pino.multistream(streams)));
62
97
  return;
63
98
  }
64
- const targets = transportTargets(options, level, environment, process.env);
65
99
  if (targets.length === 0) {
66
100
  this.#transport = null;
67
101
  this.logger = pino({
68
102
  ...pinoOptions,
69
- level: 'silent',
70
- });
103
+ level: this.#emails.length ? level : 'silent',
104
+ }, this.#emails.length ? this.#destinations({ /** Discards the disabled console destination. */ write() { } }) : undefined);
71
105
  return;
72
106
  }
73
- if (targets.length === 1 && targets[0]?.target === 'pino/file') {
107
+ if (targets.length === 1 && targets[0]?.target === 'pino/file' && targets[0]?.options?.destination === 1 && targets[0]?.level === level) {
74
108
  this.#transport = null;
75
- this.logger = pino(pinoOptions);
109
+ this.logger = pino(pinoOptions, this.#destinations(process.stdout));
76
110
  return;
77
111
  }
78
112
  this.#transport = pino.transport({
79
113
  targets,
80
114
  });
81
115
  this.#transport.on('error', reportTransportError);
82
- this.logger = pino(pinoOptions, this.#transport);
116
+ this.logger = pino(pinoOptions, this.#destinations(this.#transport));
117
+ }
118
+ /** Fans already serialized and redacted records out to ordinary destinations and operator email. */
119
+ #destinations(destination) {
120
+ return this.#emails.length ? pino.multistream([
121
+ { level: 'trace', stream: destination },
122
+ ...this.#emails,
123
+ ]) : destination;
83
124
  }
84
125
  /**
85
126
  * Waits until Pino has handed accepted records to its destination.
@@ -94,7 +135,8 @@ export class PinoLoggerDriver {
94
135
  this.#transport.ref();
95
136
  }
96
137
  await new Promise((resolve, reject) => {
97
- this.logger.flush((error) => {
138
+ const destination = this.#transport ?? this.logger;
139
+ destination.flush((error) => {
98
140
  if (error) {
99
141
  reject(error);
100
142
  return;
@@ -102,6 +144,8 @@ export class PinoLoggerDriver {
102
144
  resolve();
103
145
  });
104
146
  });
147
+ await this.#console?.console.flush();
148
+ await Promise.all(this.#emails.map(email => email.stream.flush()));
105
149
  }
106
150
  finally {
107
151
  if (!this.#closing) {
@@ -123,6 +167,7 @@ export class PinoLoggerDriver {
123
167
  if (this.#closed)
124
168
  return;
125
169
  this.#closing = true;
170
+ this.#console?.release();
126
171
  await this.flush();
127
172
  this.#closed = true;
128
173
  if (!this.#transport)
@@ -162,15 +207,29 @@ function transportTargets(options, level, environment, env) {
162
207
  if (level === 'silent')
163
208
  return [];
164
209
  const targets = [];
210
+ if (options.transports) {
211
+ for (const transport of options.transports) {
212
+ const minimum = transport.level ?? level;
213
+ if (minimum === 'silent')
214
+ continue;
215
+ if (transport.type === 'console')
216
+ targets.push({ target: 'pino/file', level: minimum, options: { destination: 1 } });
217
+ if (transport.type === 'file') {
218
+ if (!transport.destination)
219
+ throw new Error('File logging requires a destination.');
220
+ targets.push({ target: 'pino/file', level: minimum, options: { destination: transport.destination, mkdir: true } });
221
+ }
222
+ if (transport.type === 'devtools')
223
+ targets.push({ target: devtoolsTransportTarget(), level: minimum, options: transport.options ?? {} });
224
+ }
225
+ return targets;
226
+ }
165
227
  if (options.console !== false) {
166
- targets.push({
167
- target: 'pino/file',
168
- level,
169
- options: {
170
- destination: 1,
171
- },
172
- });
228
+ targets.push({ target: 'pino/file', level, options: { destination: 1 } });
173
229
  }
230
+ const file = options.file ?? env.PLATFORM_LOG_FILE;
231
+ if (file)
232
+ targets.push({ target: 'pino/file', level, options: { destination: file, mkdir: true } });
174
233
  if (devtoolsEnabled(options.devtools, environment, env)) {
175
234
  targets.push({
176
235
  target: devtoolsTransportTarget(),
@@ -0,0 +1,4 @@
1
+ import type { MailMessage } from '../mail/index.js';
2
+ import type { EmailLogOptions } from './contracts/index.js';
3
+ /** Formats a redacted log record without copying arbitrary nested payloads or exception properties into email. */
4
+ export declare function formatLogEmail(record: Record<string, unknown>, options: EmailLogOptions): MailMessage;
@@ -0,0 +1,21 @@
1
+ import { redactLogEmail } from './redactLogEmail.js';
2
+ /** Formats a redacted log record without copying arbitrary nested payloads or exception properties into email. */
3
+ export function formatLogEmail(record, options) {
4
+ const context = Object.fromEntries(Object.entries(record).filter(([key, value]) => key !== 'err' && (value === null || ['string', 'number', 'boolean'].includes(typeof value))));
5
+ const sections = [`Log context (JSON):\n${JSON.stringify(context, null, 2)}`];
6
+ let error = record.err;
7
+ if (typeof error === 'string')
8
+ sections.push(`Exception: ${error}`);
9
+ for (let depth = 0; error && typeof error === 'object' && depth < 4; depth++) {
10
+ const value = error;
11
+ sections.push(`${depth ? 'Caused by' : 'Exception'}: ${String(value.type ?? value.name ?? 'Error')}\nMessage: ${String(value.message ?? 'Unavailable')}\nStack trace:\n${String(value.stack ?? 'Unavailable')}`);
12
+ error = value.cause;
13
+ }
14
+ const text = redactLogEmail(sections.join('\n\n'));
15
+ const subject = redactLogEmail(`${options.subjectPrefix ?? 'Application error'}: ${String(record.msg ?? 'Exception logged')}`).replace(/[\r\n]/g, ' ').slice(0, 200);
16
+ return { to: options.to, subject, text, html: `<pre style="white-space:pre-wrap">${escapeHtml(text)}</pre>` };
17
+ }
18
+ /** Escapes log text as inert HTML content in the email's preformatted body. */
19
+ function escapeHtml(text) {
20
+ return text.replace(/[&<>"']/g, character => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[character]);
21
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Colours the parts of a queue log message that are scanned most: the state
3
+ * verb after `[queue] ` (blue in progress, green done, yellow retrying, red
4
+ * failed) and job labels (bold magenta). Other messages are returned unchanged
5
+ * apart from job labels.
6
+ *
7
+ * @param message - Plain log message.
8
+ * @param paint - Wraps text in an SGR code, such as `'32'` or `'1;35'`.
9
+ * @returns The message with colour codes.
10
+ */
11
+ export declare function highlightQueueMessage(message: string, paint: (text: string, code: string) => string): string;
@@ -0,0 +1,36 @@
1
+ /** Terminal colour for each queue state verb at the start of a `[queue]` message. */
2
+ const STATES = [
3
+ [/^(Claimed|Running|Dispatched)\b/, '34'],
4
+ [/^(Processed|Retried)\b/, '32'],
5
+ [/^(Released|Deferred)\b/, '33'],
6
+ [/^(Failed|Lost lease|Stopped fenced)\b/, '31'],
7
+ ];
8
+ /** A job label such as `CollectKeywordRanksJob#5249`. */
9
+ const JOB_LABEL = /\b[A-Z][A-Za-z0-9_]*#\d+\b/g;
10
+ /**
11
+ * Colours the parts of a queue log message that are scanned most: the state
12
+ * verb after `[queue] ` (blue in progress, green done, yellow retrying, red
13
+ * failed) and job labels (bold magenta). Other messages are returned unchanged
14
+ * apart from job labels.
15
+ *
16
+ * @param message - Plain log message.
17
+ * @param paint - Wraps text in an SGR code, such as `'32'` or `'1;35'`.
18
+ * @returns The message with colour codes.
19
+ */
20
+ export function highlightQueueMessage(message, paint) {
21
+ let prefix = '';
22
+ let rest = message;
23
+ if (rest.startsWith('[queue] ')) {
24
+ prefix = '[queue] ';
25
+ rest = rest.slice(prefix.length);
26
+ for (const [pattern, code] of STATES) {
27
+ const match = pattern.exec(rest);
28
+ if (match) {
29
+ prefix += paint(match[0], code);
30
+ rest = rest.slice(match[0].length);
31
+ break;
32
+ }
33
+ }
34
+ }
35
+ return prefix + rest.replace(JOB_LABEL, label => paint(label, '1;35'));
36
+ }
@@ -0,0 +1,24 @@
1
+ import type { HttpBodyLog } from './contracts/index.js';
2
+ /**
3
+ * Captures one request or response body without retaining unbounded payloads.
4
+ *
5
+ * @param payload - Parsed request body or outgoing Fastify payload.
6
+ * @param contentType - Media type reported by the HTTP message.
7
+ * @param maxBodyBytes - Maximum UTF-8 bytes retained in the log record.
8
+ * @returns Bounded body metadata and an inspectable value when safe.
9
+ */
10
+ export declare function captureBody(payload: unknown, contentType: string | undefined, maxBodyBytes: number): HttpBodyLog;
11
+ /**
12
+ * Redacts credential-bearing headers before a record reaches Pino.
13
+ *
14
+ * @param headers - Fastify request or response header collection.
15
+ * @returns Header object safe for local request inspection.
16
+ */
17
+ export declare function redactHeaders(headers: Readonly<Record<string, unknown>>): Record<string, unknown>;
18
+ /**
19
+ * Converts a Fastify header into one displayable content-type string.
20
+ *
21
+ * @param value - Request or response content-type header.
22
+ * @returns First string value when present.
23
+ */
24
+ export declare function headerValue(value: unknown): string | undefined;
@@ -0,0 +1,321 @@
1
+ const maximumCapturedProperties = 2_000;
2
+ const maximumCaptureDepth = 12;
3
+ const maximumHeaderValueLength = 4_096;
4
+ const redactedValue = '[Redacted]';
5
+ /**
6
+ * Captures one request or response body without retaining unbounded payloads.
7
+ *
8
+ * @param payload - Parsed request body or outgoing Fastify payload.
9
+ * @param contentType - Media type reported by the HTTP message.
10
+ * @param maxBodyBytes - Maximum UTF-8 bytes retained in the log record.
11
+ * @returns Bounded body metadata and an inspectable value when safe.
12
+ */
13
+ export function captureBody(payload, contentType, maxBodyBytes) {
14
+ if (payload === undefined || payload === null || payload === '') {
15
+ return {
16
+ kind: 'empty',
17
+ contentType,
18
+ };
19
+ }
20
+ if (isStreamLike(payload)) {
21
+ return {
22
+ kind: 'stream',
23
+ contentType,
24
+ note: 'Streaming response body omitted.',
25
+ };
26
+ }
27
+ if (Buffer.isBuffer(payload) || payload instanceof Uint8Array) {
28
+ const buffer = Buffer.from(payload);
29
+ if (!isTextContentType(contentType)) {
30
+ return {
31
+ kind: 'binary',
32
+ contentType,
33
+ sizeBytes: buffer.byteLength,
34
+ note: 'Binary body omitted.',
35
+ };
36
+ }
37
+ return captureText(buffer.toString('utf8'), contentType, maxBodyBytes);
38
+ }
39
+ if (typeof payload === 'string') {
40
+ return captureText(payload, contentType, maxBodyBytes);
41
+ }
42
+ return captureJson(payload, contentType, maxBodyBytes);
43
+ }
44
+ /**
45
+ * Captures textual content, parsing JSON so nested secrets can be redacted.
46
+ *
47
+ * @param value - Original textual payload.
48
+ * @param contentType - Media type reported by the HTTP message.
49
+ * @param maxBodyBytes - Maximum UTF-8 bytes retained in the log record.
50
+ * @returns Text or JSON body capture.
51
+ */
52
+ function captureText(value, contentType, maxBodyBytes) {
53
+ if (isFormContentType(contentType)) {
54
+ return captureJson(formBodyFromText(value), contentType, maxBodyBytes);
55
+ }
56
+ if (isJsonContentType(contentType) || looksLikeJson(value)) {
57
+ try {
58
+ return captureJson(JSON.parse(value), contentType, maxBodyBytes);
59
+ }
60
+ catch {
61
+ // Malformed JSON remains useful as bounded response text.
62
+ }
63
+ }
64
+ const sizeBytes = Buffer.byteLength(value);
65
+ return {
66
+ kind: 'text',
67
+ contentType,
68
+ sizeBytes,
69
+ truncated: sizeBytes > maxBodyBytes,
70
+ value: truncateUtf8(value, maxBodyBytes),
71
+ };
72
+ }
73
+ /**
74
+ * Converts URL-encoded form text into a shape that supports field redaction.
75
+ *
76
+ * Repeated form keys remain arrays so the inspector does not silently discard
77
+ * submitted values.
78
+ *
79
+ * @param value - URL-encoded request body.
80
+ * @returns Parsed form object suitable for normal JSON sanitization.
81
+ */
82
+ function formBodyFromText(value) {
83
+ const captured = {};
84
+ for (const [key, item] of new URLSearchParams(value)) {
85
+ const existing = captured[key];
86
+ if (existing === undefined) {
87
+ captured[key] = item;
88
+ continue;
89
+ }
90
+ captured[key] = Array.isArray(existing)
91
+ ? [...existing, item]
92
+ : [existing, item];
93
+ }
94
+ return captured;
95
+ }
96
+ /**
97
+ * Produces a JSON-safe, recursively redacted representation of a payload.
98
+ *
99
+ * @param value - Parsed body value.
100
+ * @param contentType - Media type reported by the HTTP message.
101
+ * @param maxBodyBytes - Maximum UTF-8 bytes retained in the log record.
102
+ * @returns JSON body capture.
103
+ */
104
+ function captureJson(value, contentType, maxBodyBytes) {
105
+ const sanitized = sanitizeBodyValue(value, '', {
106
+ seen: new WeakSet(),
107
+ remainingProperties: maximumCapturedProperties,
108
+ });
109
+ const serialized = JSON.stringify(sanitized);
110
+ if (serialized === undefined) {
111
+ return captureText(String(value), contentType, maxBodyBytes);
112
+ }
113
+ const sizeBytes = Buffer.byteLength(serialized);
114
+ return {
115
+ kind: 'json',
116
+ contentType,
117
+ sizeBytes,
118
+ truncated: sizeBytes > maxBodyBytes,
119
+ value: sizeBytes > maxBodyBytes
120
+ ? truncateUtf8(serialized, maxBodyBytes)
121
+ : sanitized,
122
+ };
123
+ }
124
+ /**
125
+ * Recursively removes sensitive fields and bounds complex object traversal.
126
+ *
127
+ * @param value - Current body value.
128
+ * @param key - Owning object key used for sensitive-name detection.
129
+ * @param state - Shared circular-reference and property-count state.
130
+ * @param depth - Current traversal depth.
131
+ * @returns JSON-safe value suitable for structured logging.
132
+ */
133
+ function sanitizeBodyValue(value, key, state, depth = 0) {
134
+ if (isSensitiveName(key))
135
+ return redactedValue;
136
+ if (value === null || value === undefined)
137
+ return value;
138
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
139
+ return value;
140
+ }
141
+ if (typeof value === 'bigint')
142
+ return value.toString();
143
+ if (typeof value !== 'object')
144
+ return String(value);
145
+ if (state.seen.has(value))
146
+ return '[Circular]';
147
+ if (depth >= maximumCaptureDepth)
148
+ return '[Maximum depth reached]';
149
+ state.seen.add(value);
150
+ if (value instanceof Date)
151
+ return value.toISOString();
152
+ if (value instanceof Error) {
153
+ return {
154
+ name: value.name,
155
+ message: value.message,
156
+ stack: value.stack,
157
+ };
158
+ }
159
+ if (Buffer.isBuffer(value) || value instanceof Uint8Array) {
160
+ return `[Binary ${value.byteLength} bytes]`;
161
+ }
162
+ if (Array.isArray(value)) {
163
+ const captured = [];
164
+ for (const item of value) {
165
+ if (state.remainingProperties <= 0) {
166
+ captured.push('[Capture limit reached]');
167
+ break;
168
+ }
169
+ state.remainingProperties -= 1;
170
+ captured.push(sanitizeBodyValue(item, '', state, depth + 1));
171
+ }
172
+ return captured;
173
+ }
174
+ const captured = {};
175
+ for (const [childKey, childValue] of Object.entries(value)) {
176
+ if (state.remainingProperties <= 0) {
177
+ captured['[capture]'] = 'Property limit reached';
178
+ break;
179
+ }
180
+ state.remainingProperties -= 1;
181
+ captured[childKey] = sanitizeBodyValue(childValue, childKey, state, depth + 1);
182
+ }
183
+ return captured;
184
+ }
185
+ /**
186
+ * Redacts credential-bearing headers before a record reaches Pino.
187
+ *
188
+ * @param headers - Fastify request or response header collection.
189
+ * @returns Header object safe for local request inspection.
190
+ */
191
+ export function redactHeaders(headers) {
192
+ const captured = {};
193
+ for (const [name, value] of Object.entries(headers)) {
194
+ captured[name] = isSensitiveName(name)
195
+ ? redactedValue
196
+ : boundedHeaderValue(value);
197
+ }
198
+ return captured;
199
+ }
200
+ /**
201
+ * Bounds one response or request header value.
202
+ *
203
+ * @param value - Original Fastify header value.
204
+ * @returns Original scalar shape with long strings shortened.
205
+ */
206
+ function boundedHeaderValue(value) {
207
+ if (typeof value === 'string') {
208
+ return value.length > maximumHeaderValueLength
209
+ ? `${value.slice(0, maximumHeaderValueLength)}…`
210
+ : value;
211
+ }
212
+ if (Array.isArray(value)) {
213
+ return value.map(item => boundedHeaderValue(item));
214
+ }
215
+ return value;
216
+ }
217
+ /**
218
+ * Detects common credential and session field names.
219
+ *
220
+ * @param name - Header or JSON property name.
221
+ * @returns True when the value must be removed from the capture.
222
+ */
223
+ function isSensitiveName(name) {
224
+ const normalized = name.toLowerCase().replace(/[-_]/g, '');
225
+ return normalized === 'authorization'
226
+ || normalized === 'proxyauthorization'
227
+ || normalized === 'cookie'
228
+ || normalized === 'setcookie'
229
+ || normalized === 'password'
230
+ || normalized === 'passphrase'
231
+ || normalized === 'secret'
232
+ || normalized === 'token'
233
+ || normalized === 'accesstoken'
234
+ || normalized === 'refreshtoken'
235
+ || normalized === 'apikey'
236
+ || normalized === 'xapikey';
237
+ }
238
+ /**
239
+ * Converts a Fastify header into one displayable content-type string.
240
+ *
241
+ * @param value - Request or response content-type header.
242
+ * @returns First string value when present.
243
+ */
244
+ export function headerValue(value) {
245
+ if (typeof value === 'string')
246
+ return value;
247
+ if (Array.isArray(value) && typeof value[0] === 'string')
248
+ return value[0];
249
+ return undefined;
250
+ }
251
+ /**
252
+ * Identifies payloads that Fastify will stream instead of serialize.
253
+ *
254
+ * @param value - Candidate outgoing response payload.
255
+ * @returns True when the value exposes the Node stream pipe contract.
256
+ */
257
+ function isStreamLike(value) {
258
+ return typeof value === 'object'
259
+ && value !== null
260
+ && 'pipe' in value
261
+ && typeof value.pipe === 'function';
262
+ }
263
+ /**
264
+ * Identifies media types that are safe to decode as UTF-8 text.
265
+ *
266
+ * @param contentType - HTTP content type.
267
+ * @returns True for JSON and common textual media types.
268
+ */
269
+ function isTextContentType(contentType) {
270
+ const normalized = (contentType || '').toLowerCase();
271
+ return normalized.startsWith('text/')
272
+ || normalized.includes('json')
273
+ || normalized.includes('xml')
274
+ || normalized.includes('javascript')
275
+ || normalized.includes('x-www-form-urlencoded')
276
+ || normalized.includes('svg');
277
+ }
278
+ /**
279
+ * Identifies JSON media types.
280
+ *
281
+ * @param contentType - HTTP content type.
282
+ * @returns True when the media type uses JSON.
283
+ */
284
+ function isJsonContentType(contentType) {
285
+ return (contentType || '').toLowerCase().includes('json');
286
+ }
287
+ /**
288
+ * Identifies URL-encoded form media types requiring field-level redaction.
289
+ *
290
+ * @param contentType - HTTP content type.
291
+ * @returns True when the body uses URL-encoded form syntax.
292
+ */
293
+ function isFormContentType(contentType) {
294
+ return (contentType || '').toLowerCase().includes('x-www-form-urlencoded');
295
+ }
296
+ /**
297
+ * Detects likely JSON text when a content type was omitted or incorrect.
298
+ *
299
+ * @param value - Textual payload.
300
+ * @returns True when the trimmed body begins with a JSON container.
301
+ */
302
+ function looksLikeJson(value) {
303
+ const trimmed = value.trim();
304
+ return (trimmed.startsWith('{') && trimmed.endsWith('}'))
305
+ || (trimmed.startsWith('[') && trimmed.endsWith(']'));
306
+ }
307
+ /**
308
+ * Truncates text by UTF-8 byte length rather than JavaScript character count.
309
+ *
310
+ * @param value - Original text.
311
+ * @param maxBytes - Maximum bytes to retain.
312
+ * @returns Original or shortened UTF-8 text.
313
+ */
314
+ function truncateUtf8(value, maxBytes) {
315
+ const buffer = Buffer.from(value);
316
+ if (buffer.byteLength <= maxBytes)
317
+ return value;
318
+ const marker = '…';
319
+ const contentBytes = Math.max(0, maxBytes - Buffer.byteLength(marker));
320
+ return `${buffer.subarray(0, contentBytes).toString('utf8')}…`;
321
+ }
@@ -1,3 +1,5 @@
1
1
  export * from './contracts/index.js';
2
2
  export * from './drivers/index.js';
3
3
  export * from './Log.js';
4
+ export * from './DevelopmentConsole.js';
5
+ export * from './registerHttpExchangeMonitor.js';
@@ -1,3 +1,5 @@
1
1
  export * from './contracts/index.js';
2
2
  export * from './drivers/index.js';
3
3
  export * from './Log.js';
4
+ export * from './DevelopmentConsole.js';
5
+ export * from './registerHttpExchangeMonitor.js';
@@ -0,0 +1,2 @@
1
+ /** Redacts common credential forms while preserving exception wording and stack locations. */
2
+ export declare function redactLogEmail(text: string): string;
@@ -0,0 +1,12 @@
1
+ /** Redacts common credential forms while preserving exception wording and stack locations. */
2
+ export function redactLogEmail(text) {
3
+ return text
4
+ .replace(/\b(?:Bearer|Basic)\s+[^\s"',;]+/gi, '[REDACTED authorization]')
5
+ .replace(/\b(?:sk-|sk_|rk_|ghp_|github_pat_)[A-Za-z0-9_-]+/g, '[REDACTED key]')
6
+ .replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[REDACTED token]')
7
+ .replace(/(["']?(?:password|passwd|api[_-]?key|access[_-]?token|refresh[_-]?token|client[_-]?secret|authorization|token|secret)["']?\s*[:=]\s*)(?:"[^"\n]*"|'[^'\n]*'|[^\s,;]+)/gi, '$1[REDACTED]')
8
+ .replace(/((?:set-cookie|cookie)\s*:\s*)[^\r\n]+/gi, '$1[REDACTED]')
9
+ .replace(/\b[a-z][a-z0-9+.-]*:\/\/[^\s<>"']+/gi, url => url
10
+ .replace(/(\/\/)[^/@\s]+@/, '$1[REDACTED]@')
11
+ .replace(/[?#].*$/, '?[REDACTED parameters]'));
12
+ }
@@ -0,0 +1,10 @@
1
+ import type { FastifyInstance } from 'fastify';
2
+ import type * as logging from './contracts/index.js';
3
+ /**
4
+ * Captures bounded, redacted payloads for grouped console logs and devtools.
5
+ * Register before routes on a Fastify host using app.log.logger. Fastify's own
6
+ * arrival/completion records provide lifecycle timing; streams are never consumed.
7
+ * @param server - Caller-owned HTTP server.
8
+ * @param options - Development capture and private-route exclusion policy.
9
+ */
10
+ export declare function registerHttpExchangeMonitor(server: FastifyInstance, options?: logging.HttpExchangeMonitorOptions): void;
@@ -0,0 +1,43 @@
1
+ import { isInteractiveDevelopmentEnvironment } from '../devtools/index.js';
2
+ import { captureBody, headerValue, redactHeaders } from './httpBodyCapture.js';
3
+ /**
4
+ * Captures bounded, redacted payloads for grouped console logs and devtools.
5
+ * Register before routes on a Fastify host using app.log.logger. Fastify's own
6
+ * arrival/completion records provide lifecycle timing; streams are never consumed.
7
+ * @param server - Caller-owned HTTP server.
8
+ * @param options - Development capture and private-route exclusion policy.
9
+ */
10
+ export function registerHttpExchangeMonitor(server, options = {}) {
11
+ if (options.enabled === false || !isInteractiveDevelopmentEnvironment(options.environment ?? process.env.NODE_ENV))
12
+ return;
13
+ const configured = options.maxBodyBytes;
14
+ const maxBodyBytes = configured && Number.isFinite(configured) && configured > 0 ? Math.min(65536, Math.floor(configured)) : 16384;
15
+ const ended = new WeakSet();
16
+ /** Reports one terminal interruption even if timeout and socket close both fire. */
17
+ function interrupted(request, message) {
18
+ if (ended.has(request))
19
+ return;
20
+ ended.add(request);
21
+ request.log.warn(message);
22
+ }
23
+ server.addHook('onRequest', (request, reply, done) => {
24
+ reply.raw.once('close', () => {
25
+ if (!reply.raw.writableFinished)
26
+ interrupted(request, 'request aborted');
27
+ });
28
+ done();
29
+ });
30
+ server.addHook('onTimeout', (request, _reply, done) => { interrupted(request, 'request timed out'); done(); });
31
+ server.addHook('onRequestAbort', (request, done) => { interrupted(request, 'request aborted'); done(); });
32
+ server.addHook('onResponse', (request, _reply, done) => { ended.add(request); done(); });
33
+ server.addHook('onSend', (request, reply, payload, done) => {
34
+ if (!options.exclude?.(request)) {
35
+ const httpExchange = {
36
+ request: { method: request.method, url: request.url, headers: redactHeaders(request.headers), body: captureBody(request.body, headerValue(request.headers['content-type']), maxBodyBytes) },
37
+ response: { statusCode: reply.statusCode, headers: redactHeaders(reply.getHeaders()), body: captureBody(payload, headerValue(reply.getHeader('content-type')), maxBodyBytes) },
38
+ };
39
+ request.log.info({ httpExchange }, 'request exchange');
40
+ }
41
+ done(null, payload);
42
+ });
43
+ }