@db3.ai/app 0.1.0-beta.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (653) hide show
  1. package/README.md +75 -17
  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
@@ -0,0 +1,59 @@
1
+ import { DatabaseMigrationManager, type RollbackResult } from '../db/migrations/index.js';
2
+ import type { App } from '../server/App.js';
3
+ import type * as apps from './contracts/index.js';
4
+ /**
5
+ * Owns discovered or explicit app composition, durable installation and process-local service lifecycle.
6
+ * Installation operations run in a stopped maintenance process; boot never migrates a database.
7
+ */
8
+ export declare class Apps<TDefinitions extends apps.AppDefinitions = {}> {
9
+ #private;
10
+ /** Discovers or validates app definitions and exposes their optional services without executing app code. */
11
+ constructor(host: App, definitions?: TDefinitions);
12
+ /** Loads a discovered root App class when installation or migration tooling explicitly needs its code. */
13
+ load(id: string): Promise<void>;
14
+ /** Executes a request under the lifecycle gate so management waits for active app requests to finish. */
15
+ run<T>(operation: () => Promise<T>): Promise<T>;
16
+ /**
17
+ * Applies an explicitly authorized action in a single-process host, draining app requests and restarting resources.
18
+ * Multi-process hosts must quiesce every process and use the stopped-runtime CLI instead.
19
+ */
20
+ manage(action: apps.AppAction, id: string): Promise<apps.AppDescription[]>;
21
+ /** Returns an available app service, or undefined when absent, disabled or not booted. */
22
+ get<K extends keyof TDefinitions & string>(id: K): apps.AppServices<TDefinitions>[K];
23
+ get(id: string): unknown;
24
+ /** Returns a required ready service, rejecting use before boot or after disable/removal. */
25
+ require<K extends keyof TDefinitions & string>(id: K): NonNullable<apps.AppServices<TDefinitions>[K]>;
26
+ require(id: string): unknown;
27
+ /** Lists browser-safe definitions and retained installations for visual exploration or CLI use. */
28
+ describe(): Promise<apps.AppDescription[]>;
29
+ /**
30
+ * Collects fresh navigation from ready apps for a host-authenticated viewer, under the lifecycle gate.
31
+ * Provider failures omit only that app. Undefined uses manifest links; null intentionally hides it.
32
+ * @example await host.apps.navigation({ actor: { id: verifiedUser.id } });
33
+ */
34
+ navigation(context: apps.AppNavigationContext): Promise<apps.AppNavigationResult>;
35
+ /** Returns explicit route contributions for transport adapters, including currently disabled apps. */
36
+ routes(): {
37
+ appId: string;
38
+ route: apps.AppRoute<any>;
39
+ }[];
40
+ /** Validates the durable desired state and starts enabled apps in dependency order without schema changes. */
41
+ boot(): Promise<void>;
42
+ /** Creates or upgrades an installation using committed migrations; existing business data is preserved. */
43
+ install(id: string): Promise<apps.AppDescription>;
44
+ /** Re-enables a retained installation after validating its code, schema and required dependencies. */
45
+ enable(id: string): Promise<apps.AppDescription>;
46
+ /** Disables an app for the next boot, retaining its schema, migration ledger and business data. */
47
+ disable(id: string): Promise<apps.AppDescription>;
48
+ /** Deregisters a durable installation while retaining data and ownership history; never drops tables. */
49
+ uninstall(id: string): Promise<apps.AppDescription>;
50
+ /**
51
+ * Runs one app-owned down migration after disable, preserving ownership and migration fingerprints.
52
+ * This explicit operation may delete data. The installation requires install() before it can run again.
53
+ */
54
+ rollback(id: string): Promise<RollbackResult>;
55
+ /** Returns a separately namespaced migration manager; app schemas never enter the host snapshot. */
56
+ migrations(id: string): DatabaseMigrationManager | undefined;
57
+ /** Releases all owned resources in reverse order; attempts every cleanup even after a failure. */
58
+ close(): Promise<void>;
59
+ }
@@ -0,0 +1,566 @@
1
+ import { register } from 'tsx/esm/api';
2
+ import { createHash } from 'node:crypto';
3
+ import { readFile, readdir } from 'node:fs/promises';
4
+ import { dirname, join } from 'node:path';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
+ import { ActiveRecord } from '../db/index.js';
7
+ import { isQueueableJobClass, queueableJobName } from '../queue/index.js';
8
+ import { databaseDialectForConnection } from '../db/dialects/index.js';
9
+ import { DatabaseMigrationManager } from '../db/migrations/index.js';
10
+ import { discoverApps } from './discoverApps.js';
11
+ import { AppService } from './AppService.js';
12
+ import { AppRouteError } from './AppRouteError.js';
13
+ import { AppInstallation } from './AppInstallation.js';
14
+ import { validateAppDefinitions } from './validateAppDefinitions.js';
15
+ import { normalizeAppNavigation } from './normalizeAppNavigation.js';
16
+ /**
17
+ * Owns discovered or explicit app composition, durable installation and process-local service lifecycle.
18
+ * Installation operations run in a stopped maintenance process; boot never migrates a database.
19
+ */
20
+ export class Apps {
21
+ #host;
22
+ #definitions;
23
+ #discovered = new Map();
24
+ #loaded = new Set();
25
+ #inFlight = new Set();
26
+ #changing = false;
27
+ #order;
28
+ #reserved;
29
+ #automatic;
30
+ #services = new Map();
31
+ #schedules = new Map();
32
+ #cleanup = [];
33
+ #records = new Map();
34
+ #booted = false;
35
+ #booting;
36
+ #starting = false;
37
+ /** Discovers or validates app definitions and exposes their optional services without executing app code. */
38
+ constructor(host, definitions) {
39
+ this.#host = host;
40
+ this.#automatic = definitions === undefined;
41
+ this.#definitions = Object.assign(Object.create(null), definitions);
42
+ if (definitions === undefined) {
43
+ for (const found of discoverApps(host.directory)) {
44
+ this.#discovered.set(found.manifest.id, found);
45
+ this.#definitions[found.manifest.id] = { manifest: found.manifest, create: () => { throw new Error('Load the app before creating its service.'); } };
46
+ }
47
+ }
48
+ const reserved = [...Object.getOwnPropertyNames(Apps.prototype), 'then', 'toJSON'];
49
+ for (let prototype = host; prototype; prototype = Object.getPrototypeOf(prototype))
50
+ reserved.push(...Object.getOwnPropertyNames(prototype));
51
+ this.#reserved = reserved;
52
+ this.#order = validateAppDefinitions(this.#definitions, reserved);
53
+ for (const id of this.#order) {
54
+ Object.defineProperty(this, id, { enumerable: true, configurable: true, get: () => this.get(id) });
55
+ Object.defineProperty(host, id, { enumerable: true, configurable: true, get: () => this.get(id) });
56
+ }
57
+ }
58
+ /** Refreshes folder additions and inactive removals without executing newly discovered code. Existing code updates require restart. */
59
+ #refresh() {
60
+ if (!this.#automatic)
61
+ return;
62
+ const sources = discoverApps(this.#host.directory);
63
+ const ids = new Set(sources.map(source => source.manifest.id));
64
+ for (const id of this.#discovered.keys()) {
65
+ if (ids.has(id))
66
+ continue;
67
+ if (this.#services.has(id))
68
+ throw new Error(`Uninstall app "${id}" before removing its folder or package.`);
69
+ this.#discovered.delete(id);
70
+ this.#loaded.delete(id);
71
+ delete this.#definitions[id];
72
+ Reflect.deleteProperty(this, id);
73
+ Reflect.deleteProperty(this.#host, id);
74
+ }
75
+ for (const source of sources) {
76
+ const id = source.manifest.id;
77
+ if (this.#discovered.has(id))
78
+ continue;
79
+ const definition = { manifest: source.manifest, create: () => { throw new Error('Load the app before creating its service.'); } };
80
+ validateAppDefinitions({ ...this.#definitions, [id]: definition }, this.#reserved);
81
+ this.#definitions[id] = definition;
82
+ this.#discovered.set(id, source);
83
+ Object.defineProperty(this, id, { enumerable: true, configurable: true, get: () => this.get(id) });
84
+ Object.defineProperty(this.#host, id, { enumerable: true, configurable: true, get: () => this.get(id) });
85
+ }
86
+ this.#order.splice(0, this.#order.length, ...validateAppDefinitions(this.#definitions, this.#reserved));
87
+ }
88
+ /** Loads a discovered root App class when installation or migration tooling explicitly needs its code. */
89
+ async load(id) {
90
+ this.#refresh();
91
+ this.#definition(id);
92
+ const source = this.#discovered.get(id);
93
+ if (!source || this.#loaded.has(id))
94
+ return;
95
+ const unregister = source.entry.endsWith('.ts') ? register() : undefined;
96
+ let Service;
97
+ try {
98
+ ({ default: Service } = await import(pathToFileURL(source.entry).href));
99
+ }
100
+ finally {
101
+ await unregister?.();
102
+ }
103
+ if (typeof Service !== 'function' || !(Service.prototype instanceof AppService))
104
+ throw new Error(`App "${id}" must default-export a class extending AppService.`);
105
+ this.#definitions[id] = {
106
+ manifest: source.manifest,
107
+ create: host => new Service(host),
108
+ ...(Service.models.length ? { database: { models: Service.models, directory: pathToFileURL(join(dirname(source.entry), 'database') + '/') } } : {}),
109
+ routes: Service.routes,
110
+ jobs: Service.jobs,
111
+ ...(Service.prototype.schedule !== AppService.prototype.schedule ? { schedule: (schedule, service) => service.schedule(schedule) } : {}),
112
+ navigation: (context, service) => service.navigation(context),
113
+ start: context => context.service.start(context),
114
+ afterInstall: host => new Service(host).install(),
115
+ beforeUninstall: host => new Service(host).uninstall(),
116
+ };
117
+ validateAppDefinitions(this.#definitions, []);
118
+ this.#loaded.add(id);
119
+ }
120
+ /** Executes a request under the lifecycle gate so management waits for active app requests to finish. */
121
+ async run(operation) {
122
+ if (this.#changing)
123
+ throw new AppRouteError(503, 'Apps are being updated. Please try again shortly.');
124
+ const pending = Promise.resolve().then(operation);
125
+ this.#inFlight.add(pending);
126
+ try {
127
+ return await pending;
128
+ }
129
+ finally {
130
+ this.#inFlight.delete(pending);
131
+ }
132
+ }
133
+ /**
134
+ * Applies an explicitly authorized action in a single-process host, draining app requests and restarting resources.
135
+ * Multi-process hosts must quiesce every process and use the stopped-runtime CLI instead.
136
+ */
137
+ async manage(action, id) {
138
+ if (!['install', 'enable', 'disable', 'uninstall'].includes(action))
139
+ throw new Error('Unknown app action.');
140
+ if (this.#changing)
141
+ throw new AppRouteError(409, 'Another app operation is running.');
142
+ this.#changing = true;
143
+ try {
144
+ await Promise.allSettled([...this.#inFlight]);
145
+ await this.load(id);
146
+ await this.#assertNoPendingWork(id);
147
+ await this.close();
148
+ try {
149
+ await this[action](id);
150
+ }
151
+ finally {
152
+ await this.boot();
153
+ }
154
+ return await this.describe();
155
+ }
156
+ finally {
157
+ this.#changing = false;
158
+ }
159
+ }
160
+ get(id) {
161
+ return this.#booted || this.#starting ? this.#services.get(id) : undefined;
162
+ }
163
+ require(id) {
164
+ const service = this.get(id);
165
+ if (service === undefined)
166
+ throw new Error(`App "${id}" is not ready. Install, enable and boot it first.`);
167
+ return service;
168
+ }
169
+ /** Lists browser-safe definitions and retained installations for visual exploration or CLI use. */
170
+ async describe() {
171
+ this.#refresh();
172
+ await this.#readRecords();
173
+ const ids = new Set([...this.#order, ...this.#records.keys()]);
174
+ return [...ids].map(id => this.#description(id));
175
+ }
176
+ /**
177
+ * Collects fresh navigation from ready apps for a host-authenticated viewer, under the lifecycle gate.
178
+ * Provider failures omit only that app. Undefined uses manifest links; null intentionally hides it.
179
+ * @example await host.apps.navigation({ actor: { id: verifiedUser.id } });
180
+ */
181
+ async navigation(context) {
182
+ if (typeof context?.actor?.id !== 'string' || !context.actor.id.trim())
183
+ throw new AppRouteError(401, 'Please sign in.');
184
+ if (context.organisationId !== undefined && (typeof context.organisationId !== 'string' || !context.organisationId.trim()))
185
+ throw new AppRouteError(400, 'Invalid organisation scope.');
186
+ const viewer = Object.freeze({ actor: Object.freeze({ id: context.actor.id }), ...(context.organisationId === undefined ? {} : { organisationId: context.organisationId }) });
187
+ return this.run(async () => {
188
+ const ids = this.#booted ? this.#order.filter(id => this.#services.has(id)) : [];
189
+ const results = await ActiveRecord.withDb(this.#host.db.knex, () => Promise.allSettled(ids.map(async (appId) => {
190
+ const definition = this.#definitions[appId];
191
+ const contribution = await definition.navigation?.(viewer, this.#services.get(appId));
192
+ if (contribution === null)
193
+ return null;
194
+ const navigation = normalizeAppNavigation(contribution ?? { items: definition.manifest.navigation ?? [] });
195
+ return { ...navigation, appId, name: definition.manifest.name, ...(definition.manifest.icon === undefined ? {} : { icon: definition.manifest.icon }) };
196
+ })));
197
+ const result = { apps: [], unavailable: [] };
198
+ results.forEach((entry, index) => {
199
+ if (entry.status === 'rejected') {
200
+ result.unavailable.push(ids[index]);
201
+ this.#host.log.warn({ appId: ids[index], err: entry.reason }, 'App navigation provider failed.');
202
+ }
203
+ else if (entry.value)
204
+ result.apps.push(entry.value);
205
+ });
206
+ return result;
207
+ });
208
+ }
209
+ /** Returns explicit route contributions for transport adapters, including currently disabled apps. */
210
+ routes() {
211
+ return this.#order.flatMap(appId => (this.#definitions[appId].routes ?? []).map(route => ({ appId, route })));
212
+ }
213
+ /** Validates the durable desired state and starts enabled apps in dependency order without schema changes. */
214
+ async boot() {
215
+ if (this.#booted)
216
+ return;
217
+ if (this.#booting)
218
+ return this.#booting;
219
+ this.#booting = this.#boot();
220
+ try {
221
+ await this.#booting;
222
+ }
223
+ finally {
224
+ this.#booting = undefined;
225
+ }
226
+ }
227
+ /** Creates or upgrades an installation using committed migrations; existing business data is preserved. */
228
+ async install(id) {
229
+ return this.#maintain(async () => {
230
+ await this.load(id);
231
+ const definition = this.#definition(id);
232
+ this.#assertDependencies(id);
233
+ for (const Model of definition.database?.models ?? []) {
234
+ for (const [ownerId, installation] of this.#records) {
235
+ if (ownerId !== id && installation.description.models.some(model => model.table === Model.table))
236
+ throw new Error(`Table "${Model.table}" is retained by app "${ownerId}".`);
237
+ }
238
+ }
239
+ const existing = this.#records.get(id);
240
+ if (existing)
241
+ await this.#assertNoPendingWork(id);
242
+ if (existing && compareVersions(definition.manifest.version, existing.version) < 0)
243
+ throw new Error(`Refusing to downgrade "${id}" from ${existing.version}.`);
244
+ const hashes = await this.#migrationHashes(id);
245
+ for (const [file, hash] of Object.entries(existing?.migrationHashes ?? {})) {
246
+ if (hashes[file] !== hash)
247
+ throw new Error(`Immutable migration "${id}/${file}" was removed or changed.`);
248
+ }
249
+ const record = existing ?? AppInstallation.create({ appId: id });
250
+ record.assign({ version: definition.manifest.version, state: 'failed', description: this.#description(id), migrationHashes: hashes });
251
+ await record.save();
252
+ this.#records.set(id, record);
253
+ const manager = this.migrations(id);
254
+ if (manager) {
255
+ await manager.migrate();
256
+ if (!(await manager.check()).matches)
257
+ throw new Error(`Schema check failed for "${id}". Installation remains failed; correct the package and retry.`);
258
+ }
259
+ await definition.afterInstall?.(this.#host);
260
+ record.state = 'enabled';
261
+ await record.save();
262
+ return this.#description(id);
263
+ });
264
+ }
265
+ /** Re-enables a retained installation after validating its code, schema and required dependencies. */
266
+ async enable(id) {
267
+ return this.#maintain(async () => {
268
+ await this.load(id);
269
+ const record = this.#installed(id);
270
+ this.#assertVersion(id, record);
271
+ this.#assertDependencies(id);
272
+ const manager = this.migrations(id);
273
+ if (manager && !(await manager.check()).matches)
274
+ throw new Error(`App "${id}" requires installation or upgrade before enabling.`);
275
+ record.state = 'enabled';
276
+ await record.save();
277
+ return this.#description(id);
278
+ });
279
+ }
280
+ /** Disables an app for the next boot, retaining its schema, migration ledger and business data. */
281
+ async disable(id) {
282
+ return this.#maintain(async () => {
283
+ await this.load(id);
284
+ const record = this.#installed(id);
285
+ this.#assertNoDependants(id, true);
286
+ await this.#assertNoPendingWork(id);
287
+ record.state = 'disabled';
288
+ await record.save();
289
+ return this.#description(id);
290
+ });
291
+ }
292
+ /** Deregisters a durable installation while retaining data and ownership history; never drops tables. */
293
+ async uninstall(id) {
294
+ return this.#maintain(async () => {
295
+ await this.load(id);
296
+ const record = this.#records.get(id);
297
+ if (!record || record.state === 'uninstalled')
298
+ return this.#description(id);
299
+ this.#assertNoDependants(id, false);
300
+ await this.#assertNoPendingWork(id);
301
+ await this.#definitions[id].beforeUninstall?.(this.#host);
302
+ record.state = 'uninstalled';
303
+ await record.save();
304
+ return this.#description(id);
305
+ });
306
+ }
307
+ /**
308
+ * Runs one app-owned down migration after disable, preserving ownership and migration fingerprints.
309
+ * This explicit operation may delete data. The installation requires install() before it can run again.
310
+ */
311
+ async rollback(id) {
312
+ return this.#maintain(async () => {
313
+ await this.load(id);
314
+ const record = this.#records.get(id);
315
+ if (!record || record.state === 'enabled')
316
+ throw new Error('Disable the app before rolling back its migration.');
317
+ this.#assertNoDependants(id, false);
318
+ await this.#assertNoPendingWork(id);
319
+ const hashes = await this.#migrationHashes(id);
320
+ for (const [file, hash] of Object.entries(record.migrationHashes)) {
321
+ if (hashes[file] !== hash)
322
+ throw new Error(`Immutable migration "${id}/${file}" was removed or changed.`);
323
+ }
324
+ const manager = this.migrations(id);
325
+ if (!manager)
326
+ throw new Error(`App "${id}" has no database definition.`);
327
+ record.state = 'failed';
328
+ await record.save();
329
+ return manager.rollback();
330
+ });
331
+ }
332
+ /** Returns a separately namespaced migration manager; app schemas never enter the host snapshot. */
333
+ migrations(id) {
334
+ const database = this.#definition(id).database;
335
+ if (!database)
336
+ return undefined;
337
+ const directory = fileURLToPath(database.directory);
338
+ return new DatabaseMigrationManager({
339
+ db: this.#host.db.knex, dialect: databaseDialectForConnection(this.#host.db.knex), models: database.models,
340
+ migrationsDirectory: join(directory, 'migrations'), snapshotFile: join(directory, 'schema.snapshot.json'),
341
+ migrationTableName: `db3_app_${id}_migrations`, loadExtensions: ['.mjs'], migrationExtension: '.mjs',
342
+ });
343
+ }
344
+ /** Releases all owned resources in reverse order; attempts every cleanup even after a failure. */
345
+ async close() {
346
+ if (this.#booting)
347
+ await this.#booting.catch(() => undefined);
348
+ await this.#dispose();
349
+ }
350
+ /** Starts services only after all installed definitions, versions and schemas have passed validation. */
351
+ async #boot() {
352
+ this.#refresh();
353
+ await this.#readRecords();
354
+ for (const [id, record] of this.#records) {
355
+ if (record.state !== 'enabled')
356
+ continue;
357
+ await this.load(id);
358
+ this.#assertVersion(id, record);
359
+ this.#assertDependencies(id);
360
+ const manager = this.migrations(id);
361
+ if (manager && !(await manager.check()).matches)
362
+ throw new Error(`App "${id}" has pending or incompatible migrations; run apps:install in maintenance mode.`);
363
+ }
364
+ this.#starting = true;
365
+ try {
366
+ for (const id of this.#order) {
367
+ if (this.#records.get(id)?.state !== 'enabled')
368
+ continue;
369
+ const definition = this.#definitions[id];
370
+ const service = definition.create(this.#host);
371
+ if (service == null || typeof service?.then === 'function')
372
+ throw new Error(`App "${id}" must synchronously create a service; use start() for async work.`);
373
+ this.#services.set(id, service);
374
+ this.#registerBackgroundWork(id, definition, service);
375
+ await definition.start?.({ host: this.#host, service, defer: cleanup => { this.#cleanup.push(cleanup); } });
376
+ }
377
+ this.#booted = true;
378
+ }
379
+ catch (error) {
380
+ try {
381
+ await this.#dispose();
382
+ }
383
+ catch (cleanupError) {
384
+ throw new AggregateError([error, cleanupError], 'App startup and cleanup failed.');
385
+ }
386
+ throw error;
387
+ }
388
+ finally {
389
+ this.#starting = false;
390
+ }
391
+ }
392
+ /** Registers declared jobs and schedules together, with automatic reverse-order cleanup and lifecycle admission. */
393
+ #registerBackgroundWork(id, definition, service) {
394
+ const jobs = definition.jobs ?? [];
395
+ const names = new Set(jobs.map(queueableJobName));
396
+ if (jobs.length)
397
+ this.#cleanup.push(this.#host.queue.registerJobs(id, jobs, operation => this.run(() => ActiveRecord.withDb(this.#host.db.knex, operation))));
398
+ if (!definition.schedule)
399
+ return;
400
+ const registration = this.#host.scheduler.register(id, scope => definition.schedule({
401
+ /** Ensures declared classes and factory results can be reconstructed by independently booted workers. */
402
+ job: source => {
403
+ if (isQueueableJobClass(source)) {
404
+ if (!names.has(queueableJobName(source)))
405
+ throw new Error(`Scheduled job must be declared in app "${id}" jobs.`);
406
+ return scope.job(source);
407
+ }
408
+ return scope.job(() => {
409
+ const job = source();
410
+ if (!jobs.includes(job.constructor))
411
+ throw new Error(`Scheduled factory returned an undeclared job in "${id}".`);
412
+ return job;
413
+ });
414
+ },
415
+ call: handler => scope.call(handler),
416
+ }, service), operation => this.run(() => ActiveRecord.withDb(this.#host.db.knex, operation)));
417
+ this.#cleanup.push(registration.close);
418
+ this.#schedules.set(id, registration.definitions);
419
+ }
420
+ /** Refuses to strand active, delayed or chained jobs. All producers and workers must be quiesced for CLI maintenance. */
421
+ async #assertNoPendingWork(id) {
422
+ if (!(this.#definitions[id]?.jobs?.length || this.#records.get(id)?.description.jobs?.length))
423
+ return;
424
+ if (await this.#host.queue.hasPendingJobs(`${id}.`))
425
+ throw new AppRouteError(409, `App "${id}" has outstanding jobs. Stop scheduling and drain its queue before changing the installation.`);
426
+ }
427
+ /** Clears services even if a disposer fails; no app stays publicly available after shutdown. */
428
+ async #dispose() {
429
+ const errors = [];
430
+ for (const cleanup of this.#cleanup.splice(0).reverse()) {
431
+ try {
432
+ await cleanup();
433
+ }
434
+ catch (error) {
435
+ errors.push(error);
436
+ }
437
+ }
438
+ this.#services.clear();
439
+ this.#booted = false;
440
+ if (errors.length)
441
+ throw new AggregateError(errors, 'App cleanup failed.');
442
+ }
443
+ /** Serializes installation changes across maintenance processes using a database-specific advisory lock. */
444
+ async #maintain(operation) {
445
+ if (this.#booted || this.#booting)
446
+ throw new Error('Stop app runtimes before changing installations. Use a fresh maintenance process or explicitly authorized single-process manage().');
447
+ const db = this.#host.db.knex;
448
+ const connection = await db.client.acquireConnection();
449
+ let lock;
450
+ try {
451
+ const [rows] = await db.raw('SELECT DATABASE() AS name').connection(connection);
452
+ lock = `db3_apps_${createHash('sha256').update(String(rows[0].name)).digest('hex').slice(0, 32)}`;
453
+ const [acquired] = await db.raw('SELECT GET_LOCK(?, 10) AS acquired', [lock]).connection(connection);
454
+ if (Number(acquired[0].acquired) !== 1)
455
+ throw new Error('Another app installation operation holds the maintenance lock.');
456
+ return await ActiveRecord.withDb(db, async () => {
457
+ await this.#host.db.install(AppInstallation);
458
+ await this.#readRecords();
459
+ return operation();
460
+ });
461
+ }
462
+ finally {
463
+ try {
464
+ if (lock)
465
+ await db.raw('SELECT RELEASE_LOCK(?)', [lock]).connection(connection);
466
+ }
467
+ finally {
468
+ await db.client.releaseConnection(connection);
469
+ }
470
+ }
471
+ }
472
+ /** Reads installation metadata without creating tables or changing the database. */
473
+ async #readRecords() {
474
+ if (!(await this.#host.db.knex.schema.hasTable(AppInstallation.table))) {
475
+ this.#records.clear();
476
+ return;
477
+ }
478
+ const records = await ActiveRecord.withDb(this.#host.db.knex, () => AppInstallation.query().all());
479
+ this.#records = new Map(records.map(record => [record.appId, record]));
480
+ }
481
+ /** Resolves a registered definition with an actionable error for removed enabled packages. */
482
+ #definition(id) {
483
+ const definition = Object.hasOwn(this.#definitions, id) ? this.#definitions[id] : undefined;
484
+ if (!definition)
485
+ throw new Error(`App "${id}" is not registered. Restore its code or uninstall it before removing registration.`);
486
+ return definition;
487
+ }
488
+ /** Requires retained installed state before enable or disable operations. */
489
+ #installed(id) {
490
+ this.#definition(id);
491
+ const record = this.#records.get(id);
492
+ if (!record || record.state === 'uninstalled' || record.state === 'failed')
493
+ throw new Error(`App "${id}" must be installed first.`);
494
+ return record;
495
+ }
496
+ /** Prevents unreviewed package updates from taking effect merely because node_modules changed. */
497
+ #assertVersion(id, record) {
498
+ if (this.#definition(id).manifest.version !== record.version)
499
+ throw new Error(`App "${id}" package version changed; run apps:install before boot.`);
500
+ }
501
+ /** Checks required and present optional service contracts against enabled compatible installations. */
502
+ #assertDependencies(id) {
503
+ const manifest = this.#definition(id).manifest;
504
+ for (const [dependency, generation] of Object.entries({ ...manifest.requires, ...manifest.optional })) {
505
+ const record = this.#records.get(dependency);
506
+ if (record?.state !== 'enabled') {
507
+ if (manifest.requires?.[dependency] !== undefined)
508
+ throw new Error(`App "${id}" requires enabled app "${dependency}".`);
509
+ continue;
510
+ }
511
+ if ((this.#definition(dependency).manifest.apiVersion ?? 1) !== generation)
512
+ throw new Error(`App "${id}" requires API generation ${generation} of "${dependency}".`);
513
+ }
514
+ for (const [consumerId, record] of this.#records) {
515
+ if (record.state !== 'enabled' || consumerId === id)
516
+ continue;
517
+ const dependency = { ...record.description.manifest.requires, ...record.description.manifest.optional }[id];
518
+ if (dependency !== undefined && dependency !== (manifest.apiVersion ?? 1))
519
+ throw new Error(`App "${consumerId}" requires API generation ${dependency} of "${id}".`);
520
+ }
521
+ }
522
+ /** Prevents required dependants from being stranded by disable or uninstall. */
523
+ #assertNoDependants(id, enabledOnly) {
524
+ for (const [consumerId, record] of this.#records) {
525
+ if (record.state === 'uninstalled' || (enabledOnly && record.state !== 'enabled'))
526
+ continue;
527
+ if (record.description.manifest.requires?.[id] !== undefined)
528
+ throw new Error(`App "${consumerId}" depends on "${id}"; ${enabledOnly ? 'disable' : 'uninstall'} it first.`);
529
+ }
530
+ }
531
+ /** Retains immutable migration fingerprints independently of removable package files. */
532
+ async #migrationHashes(id) {
533
+ const database = this.#definition(id).database;
534
+ if (!database)
535
+ return {};
536
+ const directory = join(fileURLToPath(database.directory), 'migrations');
537
+ const hashes = {};
538
+ for (const file of (await readdir(directory)).filter(file => file.endsWith('.mjs')).sort()) {
539
+ hashes[file] = createHash('sha256').update(await readFile(join(directory, file))).digest('hex');
540
+ }
541
+ return hashes;
542
+ }
543
+ /** Projects source or retained metadata to a serializable description with current installation state. */
544
+ #description(id) {
545
+ const definition = this.#definitions[id];
546
+ const record = this.#records.get(id);
547
+ const source = definition ? {
548
+ manifest: definition.manifest,
549
+ models: definition.database ? definition.database.models.map(Model => ({ name: Model.name, table: Model.table })) : record?.description.models ?? [],
550
+ routes: definition.routes ? definition.routes.map(route => ({ method: route.method, path: `/api/apps/${id}${route.path === '/' ? '' : route.path}` })) : record?.description.routes ?? [],
551
+ jobs: definition.jobs ? definition.jobs.map(queueableJobName) : record?.description.jobs ?? [],
552
+ schedules: this.#schedules.get(id) ?? record?.description.schedules ?? [],
553
+ } : record.description;
554
+ return structuredClone({ ...source, jobs: source.jobs ?? [], schedules: source.schedules ?? [], registered: Boolean(definition), state: record?.state ?? 'available', ready: this.#booted && this.#services.has(id), installedVersion: record?.version ?? null });
555
+ }
556
+ }
557
+ /** Compares stable semantic release versions already validated by the definition boundary. */
558
+ function compareVersions(left, right) {
559
+ const a = left.split('.').map(Number);
560
+ const b = right.split('.').map(Number);
561
+ for (let index = 0; index < 3; index++) {
562
+ if (a[index] !== b[index])
563
+ return a[index] - b[index];
564
+ }
565
+ return 0;
566
+ }
@@ -0,0 +1,3 @@
1
+ import type { Plugin } from 'vite';
2
+ /** Supplies discovered browser entries, Tailwind sources and app service types without per-app host imports. */
3
+ export declare function appsPlugin(): Plugin;
@@ -0,0 +1,36 @@
1
+ import { discoverApps } from './discoverApps.js';
2
+ import { writeAppTypes } from './writeAppTypes.js';
3
+ /** Supplies discovered browser entries, Tailwind sources and app service types without per-app host imports. */
4
+ export function appsPlugin() {
5
+ let root;
6
+ return {
7
+ name: 'db3-apps', enforce: 'pre',
8
+ /** Generates declarations using Vite's resolved application root. */
9
+ async configResolved(config) { root = config.root; await writeAppTypes(root); },
10
+ /** Resolves the browser-only virtual registry. */
11
+ resolveId(id) { if (id === 'virtual:db3/apps')
12
+ return '\0virtual:db3/apps'; },
13
+ /** Emits lazy browser imports; server entries never enter the client graph. */
14
+ load(id) {
15
+ if (id !== '\0virtual:db3/apps')
16
+ return;
17
+ return `export default [${discoverApps(root).filter(app => app.client).map(app => `{ id: ${JSON.stringify(app.manifest.id)}, load: () => import(${JSON.stringify(app.client.replaceAll('\\', '/'))}) }`).join(',')}];`;
18
+ },
19
+ /** Includes app-owned utility classes, including those shipped inside npm packages. */
20
+ transform(code, id) {
21
+ if (!id.endsWith('.css') || !code.includes('tailwindcss'))
22
+ return;
23
+ const sources = discoverApps(root).filter(app => app.client).map(app => `@source ${JSON.stringify(app.directory.replaceAll('\\', '/'))};`);
24
+ return `${code}\n${sources.join('\n')}`;
25
+ },
26
+ /** Rebuilds the registry when folders or package installation metadata change in development. */
27
+ configureServer(server) {
28
+ server.watcher.add([`${root}/apps`, `${root}/package.json`]);
29
+ /** Restarts Vite only for discovery inputs; normal source changes retain regular HMR. */
30
+ const refresh = (path) => { if (path.endsWith('/manifest.json') || path === `${root}/package.json`)
31
+ void server.restart(); };
32
+ server.watcher.on('add', refresh).on('unlink', refresh).on('change', refresh);
33
+ server.httpServer?.once('close', () => { server.watcher.off('add', refresh).off('unlink', refresh).off('change', refresh); });
34
+ },
35
+ };
36
+ }
@@ -0,0 +1,2 @@
1
+ /** Disables an app without deleting its data. */
2
+ export declare function disableApp(id: string): Promise<import("../index.js").AppDescription>;