@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
@@ -1,5 +1,11 @@
1
+ import { randomBytes, randomUUID } from 'node:crypto';
1
2
  import { AuthProvider, PASSWORD_AUTH_PROVIDER } from '../AuthProvider.js';
2
3
  import { defaultPasswordHash } from '../passwordHash.js';
4
+ import { PasswordSuspendedError } from '../PasswordSuspendedError.js';
5
+ import { PasswordLoginAttempt } from '../PasswordLoginAttempt.js';
6
+ const DEFAULT_MAX_FAILED_ATTEMPTS = 20;
7
+ /** Valid default-cost scrypt value used only for unknown-identity timing parity. */
8
+ const DUMMY_PASSWORD_HASH = 'scrypt$1$16384$8$1$64$0123456789abcdef0123456789abcdef$' + '00'.repeat(64);
3
9
  /**
4
10
  * Provider driver for first-party email and password authentication.
5
11
  *
@@ -12,6 +18,8 @@ export class PasswordAuthProvider {
12
18
  IdentityModel;
13
19
  ProviderModel;
14
20
  passwordHash;
21
+ #suspension;
22
+ #dummyHash;
15
23
  /**
16
24
  * Creates a password auth provider.
17
25
  *
@@ -21,25 +29,91 @@ export class PasswordAuthProvider {
21
29
  this.IdentityModel = options.identityModel;
22
30
  this.ProviderModel = options.providerModel ?? AuthProvider;
23
31
  this.passwordHash = options.passwordHash ?? defaultPasswordHash;
32
+ this.#suspension = resolveSuspension(options.suspension);
24
33
  }
25
34
  /**
26
- * Verifies submitted password credentials against the stored provider row.
35
+ * Verifies credentials under the identity's durable attempt lock.
27
36
  *
28
- * @param input - Submitted password credential payload.
29
- * @returns Normalized password provider profile, or null when verification fails.
37
+ * Unknown identities receive the same failed-attempt accounting and password
38
+ * hashing work as existing accounts. Suspension persists until verified
39
+ * password recovery; a correct password cannot clear a suspended identity.
40
+ *
41
+ * @param input - Submitted password credentials.
42
+ * @returns Verified provider profile, or null for an invalid password.
43
+ * @throws {PasswordSuspendedError} When this identity needs password recovery.
30
44
  */
31
45
  async verify(input) {
32
46
  if (!isPasswordCredentials(input))
33
47
  return null;
34
48
  const identity = normalizeIdentity(input[this.IdentityModel.identityField]);
35
- if (!identity)
49
+ if (!identity || identity.length > 255)
36
50
  return null;
51
+ if (!this.#suspension)
52
+ return this.#verifyPassword(identity, input.password);
53
+ // Return the refusal from the transaction so the threshold update commits
54
+ // before the public error is thrown.
55
+ const result = await PasswordLoginAttempt.withIdentityLock(identity, async (attempt) => {
56
+ if (attempt.suspendedAt)
57
+ return new PasswordSuspendedError();
58
+ const profile = await this.#verifyPassword(identity, input.password);
59
+ if (profile) {
60
+ attempt.failedAttempts = 0;
61
+ }
62
+ else {
63
+ attempt.failedAttempts += 1;
64
+ if (attempt.failedAttempts >= this.#suspension.maxFailedAttempts) {
65
+ attempt.suspendedAt = new Date();
66
+ attempt.suspensionId = randomUUID();
67
+ }
68
+ }
69
+ await attempt.save();
70
+ return attempt.suspendedAt ? new PasswordSuspendedError({ attemptId: String(attempt.id), suspensionId: attempt.suspensionId }) : profile;
71
+ });
72
+ if (result instanceof PasswordSuspendedError)
73
+ throw result;
74
+ return result;
75
+ }
76
+ /**
77
+ * Performs equivalent hashing work for known and unknown identities.
78
+ * @param identity - Normalized submitted identity.
79
+ * @param password - Submitted plaintext password, never persisted.
80
+ * @returns Profile only when an existing password credential matches.
81
+ */
82
+ async #verifyPassword(identity, password) {
37
83
  const provider = await this.findProvider(identity);
38
- if (!provider)
39
- return null;
40
- if (!await provider.verifyPassword(input.password, this.passwordHash))
84
+ // SQL collations may match distinct identities (for example accented text).
85
+ // Only our exact normalized key may reach the credential verification path.
86
+ if (!provider || normalizeIdentity(provider.providerUserId) !== identity) {
87
+ const dummy = this.passwordHash === defaultPasswordHash
88
+ ? DUMMY_PASSWORD_HASH
89
+ : await (this.#dummyHash ??= this.passwordHash.hash(randomBytes(32).toString('hex')).catch(error => {
90
+ this.#dummyHash = undefined;
91
+ throw error;
92
+ }));
93
+ await this.passwordHash.verify(password, dummy);
41
94
  return null;
42
- return profileFromProvider(provider);
95
+ }
96
+ return await provider.verifyPassword(password, this.passwordHash) ? profileFromProvider(provider) : null;
97
+ }
98
+ /**
99
+ * Replaces a verified owner's password and clears suspension atomically.
100
+ * Called by Auth only after a usable, identity-matched recovery token is locked.
101
+ * @param user - Account whose email recovery proof was verified.
102
+ * @param password - Replacement plaintext password.
103
+ * @returns Saved password provider.
104
+ */
105
+ async recoverPassword(user, password) {
106
+ const identity = this.userIdentityValue(user);
107
+ if (!identity)
108
+ throw new Error('Cannot recover a password without an identity.');
109
+ return PasswordLoginAttempt.withIdentityLock(identity, async (attempt) => {
110
+ const provider = await this.setPassword(user, password);
111
+ attempt.failedAttempts = 0;
112
+ attempt.suspendedAt = null;
113
+ attempt.suspensionId = null;
114
+ await attempt.save();
115
+ return provider;
116
+ });
43
117
  }
44
118
  /**
45
119
  * Creates or replaces the password provider for a user.
@@ -193,3 +267,17 @@ function profileFromProvider(provider) {
193
267
  profile: provider.profile,
194
268
  };
195
269
  }
270
+ /**
271
+ * Resolves the failed-attempt threshold and rejects invalid startup config.
272
+ * @param options - Identity suspension policy, or false to disable accounting.
273
+ * @returns Validated threshold, or null when disabled.
274
+ */
275
+ function resolveSuspension(options) {
276
+ if (options === false)
277
+ return null;
278
+ const maxFailedAttempts = options?.maxFailedAttempts ?? DEFAULT_MAX_FAILED_ATTEMPTS;
279
+ if (!Number.isSafeInteger(maxFailedAttempts) || maxFailedAttempts < 1 || maxFailedAttempts > 1_000_000) {
280
+ throw new Error('Password suspension maxFailedAttempts must be an integer between 1 and 1000000.');
281
+ }
282
+ return { maxFailedAttempts };
283
+ }
@@ -45,6 +45,7 @@ function resolveAuthProvider(provider, config, factoryOptions) {
45
45
  identityModel: factoryOptions.identityModel,
46
46
  providerModel: factoryOptions.providerModel,
47
47
  passwordHash: factoryOptions.passwordHash,
48
+ suspension: options.suspension,
48
49
  });
49
50
  case GOOGLE_AUTH_PROVIDER:
50
51
  return new GoogleAuthProvider(googleOptionsFromConfig(options));
package/dist/cli/Cli.d.ts CHANGED
@@ -8,6 +8,8 @@ export declare class Cli {
8
8
  * @param options - Root directory and output adapters.
9
9
  */
10
10
  constructor(config: cli.CliConfig, options?: cli.CliOptions);
11
+ /** Returns detached metadata without booting the app or exposing executable handlers. */
12
+ commands(): cli.CliCommandInfo[];
11
13
  /**
12
14
  * Runs one invocation, printing help without app startup and closing a created app on failure too.
13
15
  * @param argv - Arguments after the executable name.
package/dist/cli/Cli.js CHANGED
@@ -35,6 +35,14 @@ export class Cli {
35
35
  this.#commands.set(command.name, command);
36
36
  }
37
37
  }
38
+ /** Returns detached metadata without booting the app or exposing executable handlers. */
39
+ commands() {
40
+ return [...this.#commands.values()].map(command => ({
41
+ name: command.name, description: command.description,
42
+ arguments: (command.arguments ?? []).map(argument => ({ ...argument })),
43
+ interactive: command.interactive ?? false,
44
+ }));
45
+ }
38
46
  /**
39
47
  * Runs one invocation, printing help without app startup and closing a created app on failure too.
40
48
  * @param argv - Arguments after the executable name.
@@ -8,7 +8,8 @@ import { runRepl } from '../runRepl.js';
8
8
  */
9
9
  export function createReplCommand(loadModels, options) {
10
10
  return {
11
- name: 'repl', description: 'Explore the application and its models in an interactive terminal.',
11
+ name: 'repl',
12
+ interactive: true, description: 'Explore the application and its models in an interactive terminal.',
12
13
  /** Boots the app without an HTTP listener and keeps it alive until REPL exit. */
13
14
  async run(context) {
14
15
  const application = await context.app();
@@ -25,6 +25,8 @@ export interface CliCommand {
25
25
  description: string;
26
26
  /** Positional argument declarations used for validation and help. */
27
27
  arguments?: readonly CliArgument[];
28
+ /** Requires an interactive terminal session; visual one-shot runners must exclude it. */
29
+ interactive?: boolean;
28
30
  /** Executes the operation; return a nonzero status for a reported failure. */
29
31
  run(context: CliCommandContext): number | void | Promise<number | void>;
30
32
  }
@@ -0,0 +1,12 @@
1
+ import type { CliArgument } from './CliCommand.js';
2
+ /** Serializable command metadata for explorers; never includes executable handlers or configuration. */
3
+ export interface CliCommandInfo {
4
+ /** Unique registered command name. */
5
+ name: string;
6
+ /** Human-readable purpose shown in help and visual explorers. */
7
+ description: string;
8
+ /** Ordered positional inputs accepted by the CLI. */
9
+ arguments: readonly CliArgument[];
10
+ /** Interactive commands require a terminal session instead of a one-shot form. */
11
+ interactive: boolean;
12
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -3,3 +3,4 @@ export type * from './CliConfig.js';
3
3
  export type * from './CliOptions.js';
4
4
  export type * from './CommandDefinition.js';
5
5
  export type * from './ReplOptions.js';
6
+ export type * from './CliCommandInfo.js';
@@ -3,3 +3,4 @@ export * from './Cli.js';
3
3
  export * from './runDb3.js';
4
4
  export * from './defineCommand.js';
5
5
  export * from './runRepl.js';
6
+ export * from './listDb3Commands.js';
package/dist/cli/index.js CHANGED
@@ -3,3 +3,4 @@ export * from './Cli.js';
3
3
  export * from './runDb3.js';
4
4
  export * from './defineCommand.js';
5
5
  export * from './runRepl.js';
6
+ export * from './listDb3Commands.js';
@@ -0,0 +1,8 @@
1
+ import type * as cli from './contracts/index.js';
2
+ /**
3
+ * Discovers registered and built-in commands without creating the application.
4
+ * Configuration imports must remain free of startup side effects, as for CLI help.
5
+ * @param options - App root containing server/cli.config.ts, .mjs or .js.
6
+ * @returns Serializable command descriptions, including terminal-only capabilities.
7
+ */
8
+ export declare function listDb3Commands(options?: Pick<cli.CliOptions, 'directory'>): Promise<cli.CliCommandInfo[]>;
@@ -0,0 +1,10 @@
1
+ import { withDb3Cli } from './withDb3Cli.js';
2
+ /**
3
+ * Discovers registered and built-in commands without creating the application.
4
+ * Configuration imports must remain free of startup side effects, as for CLI help.
5
+ * @param options - App root containing server/cli.config.ts, .mjs or .js.
6
+ * @returns Serializable command descriptions, including terminal-only capabilities.
7
+ */
8
+ export async function listDb3Commands(options = {}) {
9
+ return withDb3Cli(options, async (runner) => runner.commands());
10
+ }
@@ -1,11 +1,8 @@
1
1
  import type * as cli from './contracts/index.js';
2
2
  /**
3
- * Loads app registration and runs the framework CLI from source or an installed package.
4
- *
5
- * TypeScript config loading supports the same extensionless imports as the starter.
6
- * No HTTP listener is started. Help and queue:make-job do not create the app.
3
+ * Runs registered framework commands with app-owned startup and cleanup.
7
4
  * @param argv - Arguments after db3.
8
- * @param options - Application root and optional output adapters.
9
- * @returns Exit status to assign to process.exitCode.
5
+ * @param options - Application root and terminal adapters.
6
+ * @returns Process-compatible exit status without exiting the process.
10
7
  */
11
8
  export declare function runDb3(argv: readonly string[], options?: cli.CliOptions): Promise<number>;
@@ -1,70 +1,16 @@
1
- import { access } from 'node:fs/promises';
2
- import { randomUUID } from 'node:crypto';
3
- import { resolve } from 'node:path';
4
- import { pathToFileURL } from 'node:url';
5
- import { register } from 'tsx/esm/api';
6
- import { Cli } from './Cli.js';
7
- import { createReplCommand } from './commands/repl.js';
1
+ import { withDb3Cli } from './withDb3Cli.js';
8
2
  /**
9
- * Loads app registration and runs the framework CLI from source or an installed package.
10
- *
11
- * TypeScript config loading supports the same extensionless imports as the starter.
12
- * No HTTP listener is started. Help and queue:make-job do not create the app.
3
+ * Runs registered framework commands with app-owned startup and cleanup.
13
4
  * @param argv - Arguments after db3.
14
- * @param options - Application root and optional output adapters.
15
- * @returns Exit status to assign to process.exitCode.
5
+ * @param options - Application root and terminal adapters.
6
+ * @returns Process-compatible exit status without exiting the process.
16
7
  */
17
8
  export async function runDb3(argv, options = {}) {
18
- const loader = register({ namespace: `db3-cli-${randomUUID()}` });
19
9
  try {
20
- const { queueCommands } = await import('../queue/commands/index.js');
21
- const directory = resolve(options.directory ?? process.cwd());
22
- const configModule = await loadAppModule(directory, 'server/cli.config', loader.import);
23
- const config = configModule ? configModule.default : { commands: [] };
24
- // Validate app config before combining it with commands that need no app bootstrap.
25
- if (!config || !Array.isArray(config.commands))
26
- throw new Error('CLI configuration must export a commands array.');
27
- const repl = createReplCommand(async () => loadReplModels(directory, loader.import), options);
28
- return await new Cli({ ...config, commands: [repl, ...queueCommands, ...config.commands] }, { ...options, directory }).run(argv);
10
+ return await withDb3Cli(options, runner => runner.run(argv));
29
11
  }
30
12
  catch (error) {
31
13
  (options.writeError ?? console.error)(error instanceof Error ? error.message : 'Unable to load CLI configuration.');
32
14
  return 1;
33
15
  }
34
- finally {
35
- await loader.unregister();
36
- }
37
- }
38
- /** Loads an optional conventional app module without hiding errors from its imports. */
39
- async function loadAppModule(directory, path, importModule) {
40
- for (const extension of ['ts', 'mjs', 'js']) {
41
- const file = resolve(directory, `${path}.${extension}`);
42
- try {
43
- await access(file);
44
- }
45
- catch (error) {
46
- if (error.code === 'ENOENT')
47
- continue;
48
- throw error;
49
- }
50
- return importModule(pathToFileURL(file).href, import.meta.url);
51
- }
52
- return undefined;
53
- }
54
- /** Exposes named model constructors from the same registry used by app migrations. */
55
- async function loadReplModels(directory, importModule) {
56
- const module = await loadAppModule(directory, 'server/database/models', importModule);
57
- if (!module)
58
- return {};
59
- if (!Array.isArray(module.models))
60
- throw new Error('server/database/models must export a models array for the REPL.');
61
- const models = Object.create(null);
62
- for (const model of module.models) {
63
- if (typeof model !== 'function' || !/^[A-Za-z_$][\w$]*$/.test(model.name))
64
- throw new Error('REPL models must be named constructors.');
65
- if (['app', 'models', '__proto__', 'constructor', 'prototype'].includes(model.name) || Object.hasOwn(models, model.name))
66
- throw new Error(`Duplicate or reserved REPL model name: ${model.name}`);
67
- models[model.name] = model;
68
- }
69
- return models;
70
16
  }
@@ -0,0 +1,4 @@
1
+ import { Cli } from './Cli.js';
2
+ import type * as cli from './contracts/index.js';
3
+ /** Loads one app's command registry and releases its TypeScript loader after use. */
4
+ export declare function withDb3Cli<T>(options: cli.CliOptions, use: (runner: Cli) => Promise<T>): Promise<T>;
@@ -0,0 +1,60 @@
1
+ import { access } from 'node:fs/promises';
2
+ import { randomUUID } from 'node:crypto';
3
+ import { resolve } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { register } from 'tsx/esm/api';
6
+ import { Cli } from './Cli.js';
7
+ import { createReplCommand } from './commands/repl.js';
8
+ // Cache the import before scoped loaders alter hooks; avoid the CLI/Queue barrel cycle.
9
+ let queueModule;
10
+ /** Loads one app's command registry and releases its TypeScript loader after use. */
11
+ export async function withDb3Cli(options, use) {
12
+ const { queueCommands } = await (queueModule ??= import('../queue/commands/index.js'));
13
+ const loader = register({ namespace: `db3-cli-${randomUUID()}` });
14
+ try {
15
+ const directory = resolve(options.directory ?? process.cwd());
16
+ const configModule = await loadAppModule(directory, 'server/cli.config', loader.import);
17
+ const config = configModule ? configModule.default : { commands: [] };
18
+ // Validate app config before combining it with commands that need no app bootstrap.
19
+ if (!config || !Array.isArray(config.commands))
20
+ throw new Error('CLI configuration must export a commands array.');
21
+ const repl = createReplCommand(async () => loadReplModels(directory, loader.import), options);
22
+ return await use(new Cli({ ...config, commands: [repl, ...queueCommands, ...config.commands] }, { ...options, directory }));
23
+ }
24
+ finally {
25
+ await loader.unregister();
26
+ }
27
+ }
28
+ /** Loads an optional conventional app module without hiding errors from its imports. */
29
+ async function loadAppModule(directory, path, importModule) {
30
+ for (const extension of ['ts', 'mjs', 'js']) {
31
+ const file = resolve(directory, `${path}.${extension}`);
32
+ try {
33
+ await access(file);
34
+ }
35
+ catch (error) {
36
+ if (error.code === 'ENOENT')
37
+ continue;
38
+ throw error;
39
+ }
40
+ return importModule(pathToFileURL(file).href, import.meta.url);
41
+ }
42
+ return undefined;
43
+ }
44
+ /** Exposes named model constructors from the same registry used by app migrations. */
45
+ async function loadReplModels(directory, importModule) {
46
+ const module = await loadAppModule(directory, 'server/database/models', importModule);
47
+ if (!module)
48
+ return {};
49
+ if (!Array.isArray(module.models))
50
+ throw new Error('server/database/models must export a models array for the REPL.');
51
+ const models = Object.create(null);
52
+ for (const model of module.models) {
53
+ if (typeof model !== 'function' || !/^[A-Za-z_$][\w$]*$/.test(model.name))
54
+ throw new Error('REPL models must be named constructors.');
55
+ if (['app', 'models', '__proto__', 'constructor', 'prototype'].includes(model.name) || Object.hasOwn(models, model.name))
56
+ throw new Error(`Duplicate or reserved REPL model name: ${model.name}`);
57
+ models[model.name] = model;
58
+ }
59
+ return models;
60
+ }
@@ -132,6 +132,14 @@ export declare class ActiveQueryBuilder<TRecord extends ActiveRecord> {
132
132
  * Adds field-aware ordering.
133
133
  */
134
134
  orderBy(fieldName: string, direction?: 'asc' | 'desc'): this;
135
+ /**
136
+ * Adds SELECT ... FOR UPDATE while retaining typed ActiveRecord results.
137
+ * Execute inside a transaction; locks are released on commit or rollback.
138
+ * This delegates to Knex and does not start or finish a transaction.
139
+ * @returns This query for further filtering or execution.
140
+ * @example await app().db.transaction(async () => { const user = await User.where('id', id).forUpdate().first(); });
141
+ */
142
+ forUpdate(): this;
135
143
  /**
136
144
  * Limits the number of returned records.
137
145
  */
@@ -208,6 +208,17 @@ export class ActiveQueryBuilder {
208
208
  this.qb.orderBy(this.qualifiedColumn(field), direction);
209
209
  return this;
210
210
  }
211
+ /**
212
+ * Adds SELECT ... FOR UPDATE while retaining typed ActiveRecord results.
213
+ * Execute inside a transaction; locks are released on commit or rollback.
214
+ * This delegates to Knex and does not start or finish a transaction.
215
+ * @returns This query for further filtering or execution.
216
+ * @example await app().db.transaction(async () => { const user = await User.where('id', id).forUpdate().first(); });
217
+ */
218
+ forUpdate() {
219
+ this.qb.forUpdate();
220
+ return this;
221
+ }
211
222
  /**
212
223
  * Limits the number of returned records.
213
224
  */
@@ -204,6 +204,12 @@ export declare abstract class ActiveRecord {
204
204
  * Returns the database connection for the current ActiveRecord operation.
205
205
  */
206
206
  static getDb(): Knex;
207
+ /**
208
+ * Returns the explicit transaction/database scope, without resolving model or app defaults.
209
+ * Infrastructure adapters use this to participate in an application's atomic outbox writes.
210
+ * @returns Current scoped connection, or undefined outside withDb().
211
+ */
212
+ static getScopedDb(): Knex | undefined;
207
213
  /**
208
214
  * Runs work with a temporary database connection for all ActiveRecord statics.
209
215
  */
@@ -132,6 +132,14 @@ export class ActiveRecord {
132
132
  ?? activeAppDatabase()
133
133
  ?? defaultDb();
134
134
  }
135
+ /**
136
+ * Returns the explicit transaction/database scope, without resolving model or app defaults.
137
+ * Infrastructure adapters use this to participate in an application's atomic outbox writes.
138
+ * @returns Current scoped connection, or undefined outside withDb().
139
+ */
140
+ static getScopedDb() {
141
+ return scopedDb.getStore();
142
+ }
135
143
  /**
136
144
  * Runs work with a temporary database connection for all ActiveRecord statics.
137
145
  */
@@ -1,5 +1,6 @@
1
1
  import 'dotenv/config';
2
2
  import knex from 'knex';
3
+ import { utcDate } from '@db3.ai/pure/dates';
3
4
  import { rememberDatabaseDialect, resolveDatabaseDialect, } from './dialects/index.js';
4
5
  let database = null;
5
6
  /**
@@ -16,9 +17,14 @@ function requiredEnv(name) {
16
17
  * Builds a Knex connection value from the current process environment.
17
18
  */
18
19
  function databaseConnection(dialect) {
19
- if (process.env.DATABASE_URL)
20
- return process.env.DATABASE_URL;
20
+ if (process.env.DATABASE_URL) {
21
+ const url = new URL(process.env.DATABASE_URL);
22
+ if (dialect.name !== 'postgres')
23
+ url.searchParams.set('timezone', 'Z');
24
+ return url.toString();
25
+ }
21
26
  return {
27
+ ...(dialect.name !== 'postgres' ? { timezone: 'Z' } : {}),
22
28
  host: process.env.DB_HOST || '127.0.0.1',
23
29
  port: Number(process.env.DB_PORT || dialect.defaultPort),
24
30
  user: process.env.DB_USER || 'root',
@@ -36,6 +42,12 @@ export function db() {
36
42
  client: dialect.knexClient,
37
43
  connection: databaseConnection(dialect),
38
44
  pool: {
45
+ /** Initializes SQL functions and TIMESTAMP conversion in UTC on every pooled connection. */
46
+ afterCreate(connection, done) {
47
+ if (dialect.name === 'postgres')
48
+ connection.setTypeParser?.(1114, utcDate);
49
+ connection.query(dialect.name === 'postgres' ? "SET TIME ZONE 'UTC'" : "SET time_zone = '+00:00'", error => done(error, connection));
50
+ },
39
51
  min: Number(process.env.DB_POOL_MIN || 0),
40
52
  max: Number(process.env.DB_POOL_MAX || 10),
41
53
  },
@@ -28,7 +28,7 @@ export declare class TimestampField extends FieldType<Date | null, Date | string
28
28
  /**
29
29
  * Converts app-memory Date to database value.
30
30
  */
31
- protected toDbValue(input: Date | null): Date | null;
31
+ protected toDbValue(input: Date | null): Date | string | null;
32
32
  protected defaultFormComponent(): string;
33
33
  protected defaultSearchFilterComponent(): string | null;
34
34
  /**
@@ -1,3 +1,4 @@
1
+ import { utcDate } from '@db3.ai/pure/dates';
1
2
  import { FieldType, fieldSchemaIndexes, } from '../FieldType.js';
2
3
  /**
3
4
  * Timestamp field using `Date | null` in app memory.
@@ -16,17 +17,7 @@ export class TimestampField extends FieldType {
16
17
  * Parses app input into a Date object.
17
18
  */
18
19
  parse(input) {
19
- if (input === null || input === undefined || input === '') {
20
- return null;
21
- }
22
- if (input instanceof Date) {
23
- return input;
24
- }
25
- const date = new Date(String(input));
26
- if (Number.isNaN(date.getTime())) {
27
- return null;
28
- }
29
- return date;
20
+ return input instanceof Date || typeof input === 'string' ? utcDate(input) : null;
30
21
  }
31
22
  /**
32
23
  * Converts database value into app-memory Date.
@@ -41,7 +32,11 @@ export class TimestampField extends FieldType {
41
32
  if (input === null || input === undefined) {
42
33
  return null;
43
34
  }
44
- return input;
35
+ // PostgreSQL timestamp-without-timezone ignores offsets on Date parameters.
36
+ // Send UTC calendar components explicitly rather than the driver's local rendering.
37
+ return this.schemaDialect().name === 'postgres'
38
+ ? input.toISOString().replace('T', ' ').replace('Z', '')
39
+ : input;
45
40
  }
46
41
  defaultFormComponent() {
47
42
  return 'DomDatePicker';
@@ -1,4 +1,4 @@
1
- import type { DatabaseCheckResult, DatabaseMigrationManagerOptions, DatabaseMigrationStatus, DatabaseSyncResult, MakeMigrationOptions, MakeMigrationResult, MigrateOptions, MigrateResult } from './contracts/index.js';
1
+ import type { DatabaseCheckResult, DatabaseMigrationManagerOptions, DatabaseMigrationStatus, DatabaseSyncResult, MakeMigrationOptions, MakeMigrationResult, MigrateOptions, MigrateResult, RollbackResult } from './contracts/index.js';
2
2
  /**
3
3
  * Reusable application-configured model migration service.
4
4
  *
@@ -44,6 +44,8 @@ export declare class DatabaseMigrationManager {
44
44
  * @returns Applied migration names, batch, and optional baselined filenames.
45
45
  */
46
46
  migrate(options?: MigrateOptions): Promise<MigrateResult>;
47
+ /** Runs the latest committed migration's own down function. The caller must quiesce consumers first. */
48
+ rollback(): Promise<RollbackResult>;
47
49
  /**
48
50
  * Runs the development convenience flow under one generation lock.
49
51
  *
@@ -2,7 +2,7 @@ import { access, mkdir, open, readdir, readFile, rename, unlink, writeFile, } fr
2
2
  import { basename, dirname, extname, isAbsolute, join, } from 'node:path';
3
3
  import { inspectDatabaseSchema } from './DatabaseSchemaInspector.js';
4
4
  import { DatabaseMigrationBaselineError, DatabaseMigrationLockError, DatabaseMigrationSourceGenerationError, } from './errors.js';
5
- import { renderKnexMigration } from './KnexMigrationRenderer.js';
5
+ import { renderKnexMigration } from './renderKnexMigration.js';
6
6
  import { collectModelSchema } from './ModelSchemaCollector.js';
7
7
  import { diffSchemaSnapshots } from './SchemaDiffer.js';
8
8
  import { promoteDestructiveSchemaChanges } from './promoteDestructiveSchemaChanges.js';
@@ -35,6 +35,7 @@ export class DatabaseMigrationManager {
35
35
  ...options,
36
36
  models: [...options.models],
37
37
  migrationTableName: options.migrationTableName ?? DEFAULT_MIGRATION_TABLE,
38
+ migrationExtension: options.migrationExtension ?? '.ts',
38
39
  loadExtensions: options.loadExtensions ?? DEFAULT_LOAD_EXTENSIONS,
39
40
  environment: options.environment ?? process.env.NODE_ENV ?? 'development',
40
41
  generationLockFile,
@@ -128,6 +129,11 @@ export class DatabaseMigrationManager {
128
129
  baselined,
129
130
  };
130
131
  }
132
+ /** Runs the latest committed migration's own down function. The caller must quiesce consumers first. */
133
+ async rollback() {
134
+ const [batch, names] = await this.#options.db.migrate.down(this.#knexConfig());
135
+ return { reverted: names.map(String), batch: typeof batch === 'number' ? batch : null };
136
+ }
131
137
  /**
132
138
  * Runs the development convenience flow under one generation lock.
133
139
  *
@@ -187,8 +193,8 @@ export class DatabaseMigrationManager {
187
193
  };
188
194
  }
189
195
  const name = migrationName(options.name, plan);
190
- const file = join(this.#options.migrationsDirectory, `${formatMigrationTimestamp(this.#options.now())}_${name}.ts`);
191
- const source = renderKnexMigration(plan);
196
+ const file = join(this.#options.migrationsDirectory, `${formatMigrationTimestamp(this.#options.now())}_${name}${this.#options.migrationExtension}`);
197
+ const source = renderKnexMigration(plan, this.#options.migrationExtension === '.mjs' ? 'javascript' : 'typescript');
192
198
  await writeMigrationAndSnapshotAtomically(file, source, this.#options.snapshotFile, desired);
193
199
  return {
194
200
  generated: true,
@@ -22,6 +22,8 @@ export interface DatabaseMigrationManagerOptions {
22
22
  migrationSchemaName?: string;
23
23
  /** Migration file extensions Knex may load. */
24
24
  loadExtensions?: readonly string[];
25
+ /** Generated migration format. Use .mjs for assets shared unchanged with npm packages. */
26
+ migrationExtension?: '.ts' | '.mjs';
25
27
  /** Current application environment. Source generation is refused in production. */
26
28
  environment?: string;
27
29
  /** Absolute cross-process lock path used while generating source files. */
@@ -116,3 +118,8 @@ export interface DatabaseSyncResult {
116
118
  migrate: MigrateResult | null;
117
119
  check: DatabaseCheckResult | null;
118
120
  }
121
+ /** Result of executing the latest migration's app-authored down function. */
122
+ export interface RollbackResult {
123
+ reverted: string[];
124
+ batch: number | null;
125
+ }
@@ -2,7 +2,7 @@ export * from './contracts/index.js';
2
2
  export * from './DatabaseMigrationManager.js';
3
3
  export * from './DatabaseSchemaInspector.js';
4
4
  export * from './errors.js';
5
- export * from './KnexMigrationRenderer.js';
5
+ export * from './renderKnexMigration.js';
6
6
  export * from './ModelSchemaCollector.js';
7
7
  export * from './promoteDestructiveSchemaChanges.js';
8
8
  export * from './SchemaDiffer.js';