@kelpie/server 0.5.1 → 0.6.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 (347) hide show
  1. package/README.md +5 -2
  2. package/dist/index.d.ts +17 -8
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +8 -4
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/actor.d.ts +9 -1
  7. package/dist/lib/actor.d.ts.map +1 -1
  8. package/dist/lib/actor.js +13 -0
  9. package/dist/lib/actor.js.map +1 -1
  10. package/dist/lib/config.d.ts +44 -6
  11. package/dist/lib/config.d.ts.map +1 -1
  12. package/dist/lib/config.js +9 -5
  13. package/dist/lib/config.js.map +1 -1
  14. package/dist/lib/email.d.ts +15 -63
  15. package/dist/lib/email.d.ts.map +1 -1
  16. package/dist/lib/email.js +13 -65
  17. package/dist/lib/email.js.map +1 -1
  18. package/dist/lib/fromEnv.d.ts +60 -0
  19. package/dist/lib/fromEnv.d.ts.map +1 -0
  20. package/dist/lib/fromEnv.js +94 -0
  21. package/dist/lib/fromEnv.js.map +1 -0
  22. package/dist/lib/ids.d.ts +6 -0
  23. package/dist/lib/ids.d.ts.map +1 -1
  24. package/dist/lib/ids.js +6 -0
  25. package/dist/lib/ids.js.map +1 -1
  26. package/dist/lib/kelpieConfigFile.d.ts +123 -0
  27. package/dist/lib/kelpieConfigFile.d.ts.map +1 -0
  28. package/dist/lib/kelpieConfigFile.js +111 -0
  29. package/dist/lib/kelpieConfigFile.js.map +1 -0
  30. package/dist/lib/logger.d.ts +38 -7
  31. package/dist/lib/logger.d.ts.map +1 -1
  32. package/dist/lib/logger.js +58 -20
  33. package/dist/lib/logger.js.map +1 -1
  34. package/dist/modules/agent-tasks/index.d.ts.map +1 -1
  35. package/dist/modules/agent-tasks/index.js +4 -1
  36. package/dist/modules/agent-tasks/index.js.map +1 -1
  37. package/dist/modules/agent-tasks/prompt.d.ts +36 -6
  38. package/dist/modules/agent-tasks/prompt.d.ts.map +1 -1
  39. package/dist/modules/agent-tasks/prompt.js +33 -4
  40. package/dist/modules/agent-tasks/prompt.js.map +1 -1
  41. package/dist/modules/agent-tasks/service.d.ts.map +1 -1
  42. package/dist/modules/agent-tasks/service.js +3 -2
  43. package/dist/modules/agent-tasks/service.js.map +1 -1
  44. package/dist/modules/agent-tasks/wire.d.ts +11 -0
  45. package/dist/modules/agent-tasks/wire.d.ts.map +1 -1
  46. package/dist/modules/agent-tasks/wire.js +1 -0
  47. package/dist/modules/agent-tasks/wire.js.map +1 -1
  48. package/dist/modules/auth/index.d.ts.map +1 -1
  49. package/dist/modules/auth/index.js +8 -7
  50. package/dist/modules/auth/index.js.map +1 -1
  51. package/dist/modules/companies/events.d.ts +22 -0
  52. package/dist/modules/companies/events.d.ts.map +1 -0
  53. package/dist/modules/companies/events.js +8 -0
  54. package/dist/modules/companies/events.js.map +1 -0
  55. package/dist/modules/companies/index.d.ts.map +1 -1
  56. package/dist/modules/companies/index.js +2 -0
  57. package/dist/modules/companies/index.js.map +1 -1
  58. package/dist/modules/companies/service.d.ts +1 -0
  59. package/dist/modules/companies/service.d.ts.map +1 -1
  60. package/dist/modules/companies/service.js +8 -11
  61. package/dist/modules/companies/service.js.map +1 -1
  62. package/dist/modules/core.d.ts.map +1 -1
  63. package/dist/modules/core.js +4 -0
  64. package/dist/modules/core.js.map +1 -1
  65. package/dist/modules/deals/events.d.ts +31 -0
  66. package/dist/modules/deals/events.d.ts.map +1 -0
  67. package/dist/modules/deals/events.js +12 -0
  68. package/dist/modules/deals/events.js.map +1 -0
  69. package/dist/modules/deals/index.d.ts.map +1 -1
  70. package/dist/modules/deals/index.js +2 -0
  71. package/dist/modules/deals/index.js.map +1 -1
  72. package/dist/modules/deals/service.d.ts +1 -0
  73. package/dist/modules/deals/service.d.ts.map +1 -1
  74. package/dist/modules/deals/service.js +9 -18
  75. package/dist/modules/deals/service.js.map +1 -1
  76. package/dist/modules/decisions/events.d.ts +21 -0
  77. package/dist/modules/decisions/events.d.ts.map +1 -0
  78. package/dist/modules/decisions/events.js +11 -0
  79. package/dist/modules/decisions/events.js.map +1 -0
  80. package/dist/modules/decisions/index.d.ts.map +1 -1
  81. package/dist/modules/decisions/index.js +2 -0
  82. package/dist/modules/decisions/index.js.map +1 -1
  83. package/dist/modules/decisions/service.d.ts +1 -0
  84. package/dist/modules/decisions/service.d.ts.map +1 -1
  85. package/dist/modules/decisions/service.js +4 -7
  86. package/dist/modules/decisions/service.js.map +1 -1
  87. package/dist/modules/forms/events.d.ts +37 -0
  88. package/dist/modules/forms/events.d.ts.map +1 -0
  89. package/dist/modules/forms/events.js +15 -0
  90. package/dist/modules/forms/events.js.map +1 -0
  91. package/dist/modules/forms/index.d.ts.map +1 -1
  92. package/dist/modules/forms/index.js +2 -0
  93. package/dist/modules/forms/index.js.map +1 -1
  94. package/dist/modules/forms/service.d.ts +1 -0
  95. package/dist/modules/forms/service.d.ts.map +1 -1
  96. package/dist/modules/forms/service.js +8 -11
  97. package/dist/modules/forms/service.js.map +1 -1
  98. package/dist/modules/forms/submission.d.ts +5 -0
  99. package/dist/modules/forms/submission.d.ts.map +1 -1
  100. package/dist/modules/forms/submission.js +54 -28
  101. package/dist/modules/forms/submission.js.map +1 -1
  102. package/dist/modules/handbook/events.d.ts +28 -0
  103. package/dist/modules/handbook/events.d.ts.map +1 -0
  104. package/dist/modules/handbook/events.js +14 -0
  105. package/dist/modules/handbook/events.js.map +1 -0
  106. package/dist/modules/handbook/index.d.ts.map +1 -1
  107. package/dist/modules/handbook/index.js +2 -0
  108. package/dist/modules/handbook/index.js.map +1 -1
  109. package/dist/modules/handbook/service.d.ts +1 -0
  110. package/dist/modules/handbook/service.d.ts.map +1 -1
  111. package/dist/modules/handbook/service.js +8 -15
  112. package/dist/modules/handbook/service.js.map +1 -1
  113. package/dist/modules/hiring/candidates.d.ts +1 -0
  114. package/dist/modules/hiring/candidates.d.ts.map +1 -1
  115. package/dist/modules/hiring/candidates.js +8 -11
  116. package/dist/modules/hiring/candidates.js.map +1 -1
  117. package/dist/modules/hiring/events.d.ts +35 -0
  118. package/dist/modules/hiring/events.d.ts.map +1 -0
  119. package/dist/modules/hiring/events.js +11 -0
  120. package/dist/modules/hiring/events.js.map +1 -0
  121. package/dist/modules/hiring/index.d.ts.map +1 -1
  122. package/dist/modules/hiring/index.js +2 -0
  123. package/dist/modules/hiring/index.js.map +1 -1
  124. package/dist/modules/hiring/roles.d.ts +1 -0
  125. package/dist/modules/hiring/roles.d.ts.map +1 -1
  126. package/dist/modules/hiring/roles.js +8 -11
  127. package/dist/modules/hiring/roles.js.map +1 -1
  128. package/dist/modules/import-export/events.d.ts +22 -0
  129. package/dist/modules/import-export/events.d.ts.map +1 -0
  130. package/dist/modules/import-export/events.js +12 -0
  131. package/dist/modules/import-export/events.js.map +1 -0
  132. package/dist/modules/import-export/index.d.ts.map +1 -1
  133. package/dist/modules/import-export/index.js +2 -0
  134. package/dist/modules/import-export/index.js.map +1 -1
  135. package/dist/modules/import-export/service.d.ts +5 -0
  136. package/dist/modules/import-export/service.d.ts.map +1 -1
  137. package/dist/modules/import-export/service.js +53 -14
  138. package/dist/modules/import-export/service.js.map +1 -1
  139. package/dist/modules/notes/events.d.ts +22 -0
  140. package/dist/modules/notes/events.d.ts.map +1 -0
  141. package/dist/modules/notes/events.js +12 -0
  142. package/dist/modules/notes/events.js.map +1 -0
  143. package/dist/modules/notes/index.d.ts.map +1 -1
  144. package/dist/modules/notes/index.js +2 -0
  145. package/dist/modules/notes/index.js.map +1 -1
  146. package/dist/modules/notes/service.d.ts +1 -0
  147. package/dist/modules/notes/service.d.ts.map +1 -1
  148. package/dist/modules/notes/service.js +4 -7
  149. package/dist/modules/notes/service.js.map +1 -1
  150. package/dist/modules/opportunities/events.d.ts +31 -0
  151. package/dist/modules/opportunities/events.d.ts.map +1 -0
  152. package/dist/modules/opportunities/events.js +12 -0
  153. package/dist/modules/opportunities/events.js.map +1 -0
  154. package/dist/modules/opportunities/index.d.ts.map +1 -1
  155. package/dist/modules/opportunities/index.js +2 -0
  156. package/dist/modules/opportunities/index.js.map +1 -1
  157. package/dist/modules/opportunities/service.d.ts +1 -0
  158. package/dist/modules/opportunities/service.d.ts.map +1 -1
  159. package/dist/modules/opportunities/service.js +9 -18
  160. package/dist/modules/opportunities/service.js.map +1 -1
  161. package/dist/modules/partnerships/events.d.ts +31 -0
  162. package/dist/modules/partnerships/events.d.ts.map +1 -0
  163. package/dist/modules/partnerships/events.js +12 -0
  164. package/dist/modules/partnerships/events.js.map +1 -0
  165. package/dist/modules/partnerships/index.d.ts.map +1 -1
  166. package/dist/modules/partnerships/index.js +2 -0
  167. package/dist/modules/partnerships/index.js.map +1 -1
  168. package/dist/modules/partnerships/service.d.ts +1 -0
  169. package/dist/modules/partnerships/service.d.ts.map +1 -1
  170. package/dist/modules/partnerships/service.js +9 -18
  171. package/dist/modules/partnerships/service.js.map +1 -1
  172. package/dist/modules/people/events.d.ts +28 -0
  173. package/dist/modules/people/events.d.ts.map +1 -0
  174. package/dist/modules/people/events.js +18 -0
  175. package/dist/modules/people/events.js.map +1 -0
  176. package/dist/modules/people/index.d.ts.map +1 -1
  177. package/dist/modules/people/index.js +2 -0
  178. package/dist/modules/people/index.js.map +1 -1
  179. package/dist/modules/people/service.d.ts +1 -0
  180. package/dist/modules/people/service.d.ts.map +1 -1
  181. package/dist/modules/people/service.js +8 -11
  182. package/dist/modules/people/service.js.map +1 -1
  183. package/dist/modules/pipelines/service.d.ts +4 -0
  184. package/dist/modules/pipelines/service.d.ts.map +1 -1
  185. package/dist/modules/pipelines/service.js +31 -8
  186. package/dist/modules/pipelines/service.js.map +1 -1
  187. package/dist/modules/plans/events.d.ts +21 -0
  188. package/dist/modules/plans/events.d.ts.map +1 -0
  189. package/dist/modules/plans/events.js +11 -0
  190. package/dist/modules/plans/events.js.map +1 -0
  191. package/dist/modules/plans/index.d.ts.map +1 -1
  192. package/dist/modules/plans/index.js +2 -0
  193. package/dist/modules/plans/index.js.map +1 -1
  194. package/dist/modules/plans/service.d.ts +1 -0
  195. package/dist/modules/plans/service.d.ts.map +1 -1
  196. package/dist/modules/plans/service.js +6 -14
  197. package/dist/modules/plans/service.js.map +1 -1
  198. package/dist/modules/positions/events.d.ts +22 -0
  199. package/dist/modules/positions/events.d.ts.map +1 -0
  200. package/dist/modules/positions/events.js +8 -0
  201. package/dist/modules/positions/events.js.map +1 -0
  202. package/dist/modules/positions/index.d.ts.map +1 -1
  203. package/dist/modules/positions/index.js +2 -0
  204. package/dist/modules/positions/index.js.map +1 -1
  205. package/dist/modules/positions/service.d.ts +1 -0
  206. package/dist/modules/positions/service.d.ts.map +1 -1
  207. package/dist/modules/positions/service.js +8 -11
  208. package/dist/modules/positions/service.js.map +1 -1
  209. package/dist/modules/raises/events.d.ts +31 -0
  210. package/dist/modules/raises/events.d.ts.map +1 -0
  211. package/dist/modules/raises/events.js +12 -0
  212. package/dist/modules/raises/events.js.map +1 -0
  213. package/dist/modules/raises/index.d.ts.map +1 -1
  214. package/dist/modules/raises/index.js +2 -0
  215. package/dist/modules/raises/index.js.map +1 -1
  216. package/dist/modules/raises/service.d.ts +1 -0
  217. package/dist/modules/raises/service.d.ts.map +1 -1
  218. package/dist/modules/raises/service.js +9 -18
  219. package/dist/modules/raises/service.js.map +1 -1
  220. package/dist/modules/reseal.d.ts +55 -0
  221. package/dist/modules/reseal.d.ts.map +1 -1
  222. package/dist/modules/reseal.js +90 -1
  223. package/dist/modules/reseal.js.map +1 -1
  224. package/dist/modules/smtp-email/index.d.ts +69 -0
  225. package/dist/modules/smtp-email/index.d.ts.map +1 -0
  226. package/dist/modules/smtp-email/index.js +82 -0
  227. package/dist/modules/smtp-email/index.js.map +1 -0
  228. package/dist/modules/webhooks/index.d.ts.map +1 -1
  229. package/dist/modules/webhooks/index.js +5 -1
  230. package/dist/modules/webhooks/index.js.map +1 -1
  231. package/dist/modules/webhooks/payloads.d.ts +22 -7
  232. package/dist/modules/webhooks/payloads.d.ts.map +1 -1
  233. package/dist/modules/webhooks/payloads.js +63 -44
  234. package/dist/modules/webhooks/payloads.js.map +1 -1
  235. package/dist/modules/workspace/events.d.ts +52 -0
  236. package/dist/modules/workspace/events.d.ts.map +1 -0
  237. package/dist/modules/workspace/events.js +16 -0
  238. package/dist/modules/workspace/events.js.map +1 -0
  239. package/dist/modules/workspace/index.d.ts.map +1 -1
  240. package/dist/modules/workspace/index.js +6 -2
  241. package/dist/modules/workspace/index.js.map +1 -1
  242. package/dist/modules/workspace/service.d.ts +1 -0
  243. package/dist/modules/workspace/service.d.ts.map +1 -1
  244. package/dist/modules/workspace/service.js +13 -15
  245. package/dist/modules/workspace/service.js.map +1 -1
  246. package/dist/modules/workspace/workspaceAccessMiddleware.d.ts.map +1 -1
  247. package/dist/modules/workspace/workspaceAccessMiddleware.js +11 -3
  248. package/dist/modules/workspace/workspaceAccessMiddleware.js.map +1 -1
  249. package/dist/runtime/events.d.ts +86 -108
  250. package/dist/runtime/events.d.ts.map +1 -1
  251. package/dist/runtime/events.js +123 -52
  252. package/dist/runtime/events.js.map +1 -1
  253. package/dist/runtime/module.d.ts +54 -2
  254. package/dist/runtime/module.d.ts.map +1 -1
  255. package/dist/runtime/registry.d.ts +23 -0
  256. package/dist/runtime/registry.d.ts.map +1 -1
  257. package/dist/runtime/registry.js +102 -2
  258. package/dist/runtime/registry.js.map +1 -1
  259. package/dist/runtime/transaction.d.ts +29 -4
  260. package/dist/runtime/transaction.d.ts.map +1 -1
  261. package/dist/runtime/transaction.js +48 -7
  262. package/dist/runtime/transaction.js.map +1 -1
  263. package/dist/testing/app.d.ts.map +1 -1
  264. package/dist/testing/app.js +11 -3
  265. package/dist/testing/app.js.map +1 -1
  266. package/dist/testing/database.d.ts.map +1 -1
  267. package/dist/testing/database.js +6 -3
  268. package/dist/testing/database.js.map +1 -1
  269. package/dist/testing/services.d.ts +21 -1
  270. package/dist/testing/services.d.ts.map +1 -1
  271. package/dist/testing/services.js +20 -5
  272. package/dist/testing/services.js.map +1 -1
  273. package/package.json +5 -2
  274. package/src/index.ts +44 -9
  275. package/src/lib/actor.ts +15 -1
  276. package/src/lib/config.ts +56 -7
  277. package/src/lib/email.ts +22 -92
  278. package/src/lib/fromEnv.ts +143 -0
  279. package/src/lib/ids.ts +6 -0
  280. package/src/lib/kelpieConfigFile.ts +283 -0
  281. package/src/lib/logger.ts +92 -34
  282. package/src/modules/agent-tasks/index.ts +4 -1
  283. package/src/modules/agent-tasks/prompt.ts +57 -9
  284. package/src/modules/agent-tasks/service.ts +3 -2
  285. package/src/modules/agent-tasks/wire.ts +12 -0
  286. package/src/modules/auth/index.ts +11 -9
  287. package/src/modules/companies/events.ts +25 -0
  288. package/src/modules/companies/index.ts +2 -0
  289. package/src/modules/companies/service.ts +8 -11
  290. package/src/modules/core.ts +4 -0
  291. package/src/modules/deals/events.ts +34 -0
  292. package/src/modules/deals/index.ts +2 -0
  293. package/src/modules/deals/service.ts +17 -18
  294. package/src/modules/decisions/events.ts +24 -0
  295. package/src/modules/decisions/index.ts +2 -0
  296. package/src/modules/decisions/service.ts +8 -7
  297. package/src/modules/forms/events.ts +37 -0
  298. package/src/modules/forms/index.ts +2 -0
  299. package/src/modules/forms/service.ts +12 -11
  300. package/src/modules/forms/submission.ts +80 -29
  301. package/src/modules/handbook/events.ts +31 -0
  302. package/src/modules/handbook/index.ts +2 -0
  303. package/src/modules/handbook/service.ts +8 -15
  304. package/src/modules/hiring/candidates.ts +8 -11
  305. package/src/modules/hiring/events.ts +36 -0
  306. package/src/modules/hiring/index.ts +2 -0
  307. package/src/modules/hiring/roles.ts +8 -11
  308. package/src/modules/import-export/events.ts +25 -0
  309. package/src/modules/import-export/index.ts +2 -0
  310. package/src/modules/import-export/service.ts +83 -15
  311. package/src/modules/notes/events.ts +25 -0
  312. package/src/modules/notes/index.ts +2 -0
  313. package/src/modules/notes/service.ts +8 -7
  314. package/src/modules/opportunities/events.ts +34 -0
  315. package/src/modules/opportunities/index.ts +2 -0
  316. package/src/modules/opportunities/service.ts +17 -18
  317. package/src/modules/partnerships/events.ts +34 -0
  318. package/src/modules/partnerships/index.ts +2 -0
  319. package/src/modules/partnerships/service.ts +17 -18
  320. package/src/modules/people/events.ts +36 -0
  321. package/src/modules/people/index.ts +2 -0
  322. package/src/modules/people/service.ts +97 -87
  323. package/src/modules/pipelines/service.ts +47 -8
  324. package/src/modules/plans/events.ts +24 -0
  325. package/src/modules/plans/index.ts +2 -0
  326. package/src/modules/plans/service.ts +14 -14
  327. package/src/modules/positions/events.ts +25 -0
  328. package/src/modules/positions/index.ts +2 -0
  329. package/src/modules/positions/service.ts +8 -11
  330. package/src/modules/raises/events.ts +34 -0
  331. package/src/modules/raises/index.ts +2 -0
  332. package/src/modules/raises/service.ts +17 -18
  333. package/src/modules/reseal.ts +144 -1
  334. package/src/modules/smtp-email/index.ts +119 -0
  335. package/src/modules/webhooks/index.ts +5 -1
  336. package/src/modules/webhooks/payloads.ts +94 -48
  337. package/src/modules/workspace/events.ts +46 -0
  338. package/src/modules/workspace/index.ts +6 -2
  339. package/src/modules/workspace/service.ts +37 -15
  340. package/src/modules/workspace/workspaceAccessMiddleware.ts +12 -3
  341. package/src/runtime/events.ts +268 -107
  342. package/src/runtime/module.ts +55 -2
  343. package/src/runtime/registry.ts +169 -1
  344. package/src/runtime/transaction.ts +94 -17
  345. package/src/testing/app.ts +11 -3
  346. package/src/testing/database.ts +6 -3
  347. package/src/testing/services.ts +34 -5
@@ -1,5 +1,6 @@
1
1
  import { Hono } from 'hono';
2
2
  import { requireWorkspaceId } from '../lib/actor.js';
3
+ import { createLogEmailSender } from '../lib/email.js';
3
4
  import { AppError, describeThrown, describeValidationIssue, toErrorDetails } from '../lib/errors.js';
4
5
  import { createEntitlementRegistry, requireCapability } from './entitlements.js';
5
6
  import { createEventBus } from './events.js';
@@ -24,9 +25,47 @@ function assertMountablePath(moduleId, kind, path) {
24
25
  }
25
26
  }
26
27
  }
27
- function createModuleContext(module, accumulator, options, events, entitlements, moduleCatalog) {
28
+ /**
29
+ * The email sender every module writes through. `target` is set once, after
30
+ * all modules have registered, from the provider `email.provider` picked. Until
31
+ * then a `.send()` throws: consumer modules capture the proxy at register time
32
+ * but only reach it at request time, so this is unreachable in normal flow.
33
+ */
34
+ class EmailSenderProxy {
35
+ target = undefined;
36
+ setTarget(sender) {
37
+ this.target = sender;
38
+ }
39
+ send(message) {
40
+ if (this.target === undefined) {
41
+ return Promise.reject(new Error('email sender used before boot resolved a provider. Set email.provider in kelpie.config.ts.'));
42
+ }
43
+ return this.target.send(message);
44
+ }
45
+ }
46
+ /**
47
+ * The name the runtime uses for its built-in log sender. Reserved: a module
48
+ * that tries to register under this name fails boot.
49
+ */
50
+ const LOG_PROVIDER_NAME = 'log';
51
+ function createModuleContext(module, accumulator, options, events, entitlements, moduleCatalog, emailProxy, providers) {
28
52
  return {
29
53
  ...options.services,
54
+ email: emailProxy,
55
+ provideEmailSender(name, build) {
56
+ if (name === LOG_PROVIDER_NAME) {
57
+ throw new ModuleBootError([
58
+ `module "${module.id}" registers email provider "${name}", which is reserved by the runtime`,
59
+ ]);
60
+ }
61
+ const existing = providers.get(name);
62
+ if (existing !== undefined) {
63
+ throw new ModuleBootError([
64
+ `module "${module.id}" registers email provider "${name}", but module "${existing.registeredBy}" already did`,
65
+ ]);
66
+ }
67
+ providers.set(name, { build, registeredBy: module.id });
68
+ },
30
69
  routes(mount) {
31
70
  const router = new Hono();
32
71
  // Gate first, so it runs before anything `mount` adds: Hono composes a
@@ -119,6 +158,28 @@ export async function registerModules(options) {
119
158
  }
120
159
  const events = options.events ?? createEventBus(options.logger);
121
160
  const entitlements = options.entitlements ?? createEntitlementRegistry();
161
+ const emailProxy = new EmailSenderProxy();
162
+ const emailProviders = new Map();
163
+ // The built-in log provider is always available, no module required. Named
164
+ // 'log' in kelpie.config.ts's email.provider picks this one. Built eagerly
165
+ // because it has no env to parse and never fails.
166
+ const logSender = createLogEmailSender(options.logger, options.email.from);
167
+ emailProviders.set(LOG_PROVIDER_NAME, {
168
+ build: () => logSender,
169
+ registeredBy: '<runtime>',
170
+ });
171
+ // Seed test-supplied providers before any module registers, so a module
172
+ // collision with one of them fails boot the same way two modules would.
173
+ if (options.additionalEmailProviders !== undefined) {
174
+ for (const [name, sender] of options.additionalEmailProviders) {
175
+ if (emailProviders.has(name)) {
176
+ throw new ModuleBootError([
177
+ `additionalEmailProviders names "${name}", which is already registered by the runtime`,
178
+ ]);
179
+ }
180
+ emailProviders.set(name, { build: () => sender, registeredBy: '<additionalEmailProviders>' });
181
+ }
182
+ }
122
183
  const accumulator = {
123
184
  routers: [],
124
185
  publicRouters: [],
@@ -149,8 +210,21 @@ export async function registerModules(options) {
149
210
  if (options.moduleConfig !== undefined) {
150
211
  entitlements.provide(createModuleConfigProvider(options.moduleConfig));
151
212
  }
213
+ // Register every module's event catalog before any `register` runs, so a
214
+ // module that subscribes to another module's event during its own registration
215
+ // finds a validated name.
216
+ for (const module of ordered) {
217
+ if (module.events !== undefined) {
218
+ try {
219
+ events.registerCatalog({ moduleId: module.id, events: module.events });
220
+ }
221
+ catch (error) {
222
+ throw new ModuleBootError([describeThrown(error)], { cause: error });
223
+ }
224
+ }
225
+ }
152
226
  for (const module of ordered) {
153
- const context = createModuleContext(module, accumulator, options, events, entitlements, moduleCatalog);
227
+ const context = createModuleContext(module, accumulator, options, events, entitlements, moduleCatalog, emailProxy, emailProviders);
154
228
  try {
155
229
  await module.register(context);
156
230
  }
@@ -164,9 +238,35 @@ export async function registerModules(options) {
164
238
  }
165
239
  context.log.debug('module registered');
166
240
  }
241
+ // Resolve the configured provider. The lookup happens after every module has
242
+ // registered, so a module registering a provider late in the list still wins
243
+ // if the config names it. An unknown name is a boot error whose message lists
244
+ // every registered name, so a self-hoster sees what they had to pick from.
245
+ const chosen = emailProviders.get(options.email.provider);
246
+ if (chosen === undefined) {
247
+ const available = [...emailProviders.keys()].sort();
248
+ throw new ModuleBootError([
249
+ `email.provider is "${options.email.provider}", which no module registered. Available: ${available.join(', ')}`,
250
+ ]);
251
+ }
252
+ // Only the chosen provider is built. A registered-but-unused provider never
253
+ // runs its factory, so a self-hoster who leaves a module in `modules:` but
254
+ // picks a different provider is not asked for the unused module's env.
255
+ let chosenSender;
256
+ try {
257
+ chosenSender = chosen.build();
258
+ }
259
+ catch (error) {
260
+ if (error instanceof ModuleBootError) {
261
+ throw error;
262
+ }
263
+ throw new ModuleBootError([`email provider "${options.email.provider}" (${chosen.registeredBy}) failed to build: ${describeThrown(error)}`], { cause: error });
264
+ }
265
+ emailProxy.setTarget(chosenSender);
167
266
  options.logger.info('modules registered', {
168
267
  count: ordered.length,
169
268
  ids: ordered.map((module) => module.id),
269
+ emailProvider: options.email.provider,
170
270
  });
171
271
  return {
172
272
  routers: accumulator.routers,
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/runtime/registry.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
+ import type { EventActor, EventTarget } from '@kelpie/schemas';
1
2
  import type { Database } from '../lib/database.ts';
3
+ import type { IdFactory } from '../lib/ids.ts';
2
4
  import type { Logger } from '../lib/logger.ts';
3
- import type { DomainEventName, DomainEvents, EventBus } from './events.ts';
5
+ import type { EventBus, EventName, KelpieEventMap } from './events.ts';
4
6
  /**
5
7
  * One service call, one transaction, per `architecture.md`.
6
8
  *
@@ -15,20 +17,43 @@ export type Transaction = Parameters<Parameters<Database['transaction']>[0]>[0];
15
17
  * transaction when a service is composing several writes.
16
18
  */
17
19
  export type Queryable = Database | Transaction;
18
- /** Collects events during the transaction. Nothing leaves until commit. */
20
+ type EventMapFor<Name extends EventName> = keyof KelpieEventMap extends never ? unknown : Name extends keyof KelpieEventMap ? KelpieEventMap[Name] : unknown;
21
+ /**
22
+ * Collects events during the transaction. Nothing leaves until commit.
23
+ *
24
+ * `emit` stamps the envelope (id, workspaceId, actor, occurredAt, causedBy) so
25
+ * services pass only what they know: the name, the target the event refers to,
26
+ * and the module-defined payload.
27
+ */
19
28
  export interface BufferedEvents {
20
- emit<Name extends DomainEventName>(name: Name, payload: DomainEvents[Name]): void;
29
+ emit<Name extends EventName>(name: Name, target: EventTarget, data: EventMapFor<Name>): void;
21
30
  }
22
31
  export interface TransactionContext {
23
32
  readonly tx: Transaction;
24
33
  readonly events: BufferedEvents;
25
34
  }
35
+ export interface TransactionOptions {
36
+ /**
37
+ * The tenant this work belongs to. Every event emitted from the scope stamps
38
+ * it into the envelope. Required when any event is emitted; a scope that
39
+ * emits nothing may omit it.
40
+ */
41
+ readonly workspaceId?: string;
42
+ /** Who caused this work. Defaults to `system`. */
43
+ readonly actor?: EventActor;
44
+ }
26
45
  /** Runs `work` in one transaction and publishes its events after commit. */
27
- export type TransactionScope = <Result>(work: (context: TransactionContext) => Promise<Result>) => Promise<Result>;
46
+ export type TransactionScope = <Result>(work: (context: TransactionContext) => Promise<Result>, options?: TransactionOptions) => Promise<Result>;
28
47
  export interface TransactionScopeDependencies {
29
48
  readonly db: Database;
30
49
  readonly bus: EventBus;
31
50
  readonly logger: Logger;
51
+ readonly createId: IdFactory;
52
+ /** Injected so a test can pin timestamps. Defaults to `Date.now`. */
53
+ readonly now?: () => Date;
54
+ /** Chain-depth cap. Reads `KELPIE_EVENT_MAX_DEPTH`; otherwise 8. */
55
+ readonly maxDepth?: number;
32
56
  }
33
57
  export declare function createTransactionScope(dependencies: TransactionScopeDependencies): TransactionScope;
58
+ export {};
34
59
  //# sourceMappingURL=transaction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/runtime/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAE1E;;;;;;GAMG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAE/E;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAA;AAE9C,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,IAAI,SAAS,eAAe,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAClF;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC;AAED,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EACpC,IAAI,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,CAAC,KACnD,OAAO,CAAC,MAAM,CAAC,CAAA;AAYpB,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,4BAA4B,GAAG,gBAAgB,CA2BnG"}
1
+ {"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../src/runtime/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAe,MAAM,iBAAiB,CAAA;AAE3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEtE;;;;;;GAMG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;AAE/E;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAA;AAE9C,KAAK,WAAW,CAAC,IAAI,SAAS,SAAS,IAAI,MAAM,cAAc,SAAS,KAAK,GACzE,OAAO,GACP,IAAI,SAAS,MAAM,cAAc,GAC/B,cAAc,CAAC,IAAI,CAAC,GACpB,OAAO,CAAA;AAEb;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,IAAI,SAAS,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC7F;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,kDAAkD;IAClD,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAC5B;AAED,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EACpC,IAAI,EAAE,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,CAAC,EACtD,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAA;AASpB,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,sBAAsB,CAAC,YAAY,EAAE,4BAA4B,GAAG,gBAAgB,CAiEnG"}
@@ -1,24 +1,65 @@
1
+ import { checkEventCycle, currentEventChain } from './events.js';
2
+ const SYSTEM_ACTOR = { kind: 'system' };
1
3
  export function createTransactionScope(dependencies) {
2
- return async function runInTransaction(work) {
4
+ const now = dependencies.now ?? (() => new Date());
5
+ const maxDepth = dependencies.maxDepth ?? readMaxDepthFromEnv() ?? 8;
6
+ return async function runInTransaction(work, options) {
7
+ const actor = options?.actor ?? SYSTEM_ACTOR;
8
+ const workspaceId = options?.workspaceId;
3
9
  const buffered = [];
4
10
  const result = await dependencies.db.transaction((tx) => work({
5
11
  tx,
6
12
  events: {
7
- emit(name, payload) {
8
- buffered.push({ name, publish: () => dependencies.bus.publish(name, payload) });
13
+ emit(name, target, data) {
14
+ if (workspaceId === undefined || workspaceId.length === 0) {
15
+ throw new Error(`event "${name}" was emitted without a workspaceId: pass it via TransactionOptions`);
16
+ }
17
+ const chain = currentEventChain();
18
+ const outcome = checkEventCycle(chain, name, target, maxDepth);
19
+ if (outcome.kind !== 'ok') {
20
+ dependencies.logger.error('event cycle guard dropped emit', {
21
+ event: name,
22
+ target,
23
+ reason: outcome.kind,
24
+ chain: chain.map((entry) => ({
25
+ id: entry.id,
26
+ name: entry.name,
27
+ target: { type: entry.targetType, id: entry.targetId },
28
+ })),
29
+ });
30
+ return;
31
+ }
32
+ const envelope = {
33
+ id: dependencies.createId('event'),
34
+ name,
35
+ workspaceId,
36
+ actor,
37
+ occurredAt: now().toISOString(),
38
+ target,
39
+ ...(chain.length > 0 ? { causedBy: chain[chain.length - 1].id } : {}),
40
+ data: data,
41
+ };
42
+ buffered.push({ name, envelope });
9
43
  },
10
44
  },
11
45
  }));
12
46
  // Past this line the transaction has committed. Publishing is deliberately
13
- // not awaited: the webhooks engine is a consumer, and an outbound HTTP
14
- // delivery must not sit inside the request that triggered it. Tests and
15
- // graceful shutdown wait via `bus.drain()`.
47
+ // not awaited: an outbound HTTP delivery must not sit inside the request
48
+ // that triggered it. Tests and graceful shutdown wait via `bus.drain()`.
16
49
  for (const event of buffered) {
17
- void event.publish().catch((error) => {
50
+ void dependencies.bus.publish(event.envelope).catch((error) => {
18
51
  dependencies.logger.error('event publication failed', { event: event.name, error });
19
52
  });
20
53
  }
21
54
  return result;
22
55
  };
23
56
  }
57
+ function readMaxDepthFromEnv() {
58
+ const raw = process.env.KELPIE_EVENT_MAX_DEPTH;
59
+ if (raw === undefined || raw === '') {
60
+ return undefined;
61
+ }
62
+ const parsed = Number.parseInt(raw, 10);
63
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
64
+ }
24
65
  //# sourceMappingURL=transaction.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/runtime/transaction.ts"],"names":[],"mappings":"AAoDA,MAAM,UAAU,sBAAsB,CAAC,YAA0C;IAC/E,OAAO,KAAK,UAAU,gBAAgB,CAAC,IAAI;QACzC,MAAM,QAAQ,GAAoB,EAAE,CAAA;QAEpC,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CACtD,IAAI,CAAC;YACH,EAAE;YACF,MAAM,EAAE;gBACN,IAAI,CAAC,IAAI,EAAE,OAAO;oBAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAA;gBACjF,CAAC;aACF;SACF,CAAC,CACH,CAAA;QAED,2EAA2E;QAC3E,uEAAuE;QACvE,wEAAwE;QACxE,4CAA4C;QAC5C,KAAK,MAAM,KAAK,IAAI,QAAQ,EAAE,CAAC;YAC7B,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;gBAC5C,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;YACrF,CAAC,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../src/runtime/transaction.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/testing/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAGzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAIrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAejD;;;;GAIG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC1C,wFAAwF;IACxF,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAA;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAA;IAC3C,sFAAsF;IACtF,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACzD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,CAAA;IAC5D,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;IACpC,sFAAsF;IACtF,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;CACxD;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAA;IAC3C,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAID,wBAAsB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CA4BlF"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/testing/app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAGzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AACjE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AAIrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAejD;;;;GAIG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAC1C,wFAAwF;IACxF,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAA;IAClC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC,aAAa,CAAC,CAAA;IACrD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,MAAM,CAAA;IACzC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;IAChC,6EAA6E;IAC7E,QAAQ,CAAC,YAAY,CAAC,EAAE,mBAAmB,CAAA;IAC3C,sFAAsF;IACtF,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACzD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,CAAC,CAAA;IAC5D,kFAAkF;IAClF,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAA;IACpC,sFAAsF;IACtF,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;CACxD;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC,CAAA;IAC/B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAA;IAC3C,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACrC;AAID,wBAAsB,aAAa,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,CAoClF"}
@@ -1,9 +1,9 @@
1
1
  import { createApp } from '../app.js';
2
- import { createLogger } from '../lib/logger.js';
2
+ import { createCaptureTransport, createLogger } from '../lib/logger.js';
3
3
  import { rateLimitConfigFrom, rateLimitConfigSchema } from '../lib/rateLimit.js';
4
4
  import { registerModules } from '../runtime/registry.js';
5
5
  import { TEST_ENVIRONMENT } from './environment.js';
6
- import { createTestServices } from './services.js';
6
+ import { TEST_EMAIL_FROM, TEST_EMAIL_PROVIDER, createTestServices } from './services.js';
7
7
  /** The same defaults `loadConfig` produces from an empty environment: one source of numbers for both. */
8
8
  const DEFAULT_TEST_RATE_LIMIT = rateLimitConfigFrom(rateLimitConfigSchema.parse({}));
9
9
  /**
@@ -18,13 +18,21 @@ function testClientIp(context) {
18
18
  const reachableDatabase = () => Promise.resolve({ reachable: true });
19
19
  export async function createTestApp(options = {}) {
20
20
  const logLines = [];
21
- const logger = createLogger('debug', (line) => logLines.push(line));
21
+ const logger = createLogger({
22
+ level: 'debug',
23
+ transports: [createCaptureTransport((line) => logLines.push(line))],
24
+ });
22
25
  const services = options.services ?? createTestServices();
26
+ // Seed the test collecting sender under a stable name and point the email
27
+ // config at it. A test that wants a real provider module in the mix registers
28
+ // it as usual; picking that name in `email.provider` overrides this default.
23
29
  const contributions = await registerModules({
24
30
  modules: options.modules ?? [],
25
31
  environment: options.environment ?? TEST_ENVIRONMENT,
26
32
  logger,
27
33
  events: services.events,
34
+ email: { provider: TEST_EMAIL_PROVIDER, from: TEST_EMAIL_FROM },
35
+ additionalEmailProviders: new Map([[TEST_EMAIL_PROVIDER, services.emailSender]]),
28
36
  ...(options.entitlements === undefined ? {} : { entitlements: options.entitlements }),
29
37
  ...(options.moduleConfig === undefined ? {} : { moduleConfig: options.moduleConfig }),
30
38
  ...(options.resolveActor === undefined ? {} : { resolveActor: options.resolveActor }),
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/testing/app.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAKrC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAKhF,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAGlD,yGAAyG;AACzG,MAAM,uBAAuB,GAAoB,mBAAmB,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAA;AAErG;;;;;GAKG;AACH,SAAS,YAAY,CAAC,OAAgB;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,aAAa,CAAA;AAC/D,CAAC;AAwCD,MAAM,iBAAiB,GAAG,GAA2B,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;AAE5F,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAO,GAAmB,EAAE;IAC9D,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IAEnE,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,kBAAkB,EAAE,CAAA;IACzD,MAAM,aAAa,GAAG,MAAM,eAAe,CAAC;QAC1C,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QAC9B,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,gBAAgB;QACpD,MAAM;QACN,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;QACrF,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;QACrF,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC;QACrF,QAAQ;KACT,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,SAAS,CAAC;QACpB,MAAM;QACN,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,iBAAiB;QACzD,aAAa;QACb,WAAW,EAAE,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,GAAG,EAAE;QACnD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC;QAClE,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,uBAAuB;QACvD,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,YAAY;KACzD,CAAC,CAAA;IAEF,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAA;AACnD,CAAC"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/testing/app.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAmB5D,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAE5E;AA+BD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmCzF"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAmB5D,MAAM,WAAW,YAAa,SAAQ,kBAAkB;IACtD,6EAA6E;IAC7E,QAAQ,CAAC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1C;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAE5E;AA+BD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAsCzF"}
@@ -6,7 +6,7 @@ import { coreModules } from '../modules/core.js';
6
6
  import { runMigrations } from '../runtime/migrate.js';
7
7
  import { registerModules } from '../runtime/registry.js';
8
8
  import { TEST_ENVIRONMENT } from './environment.js';
9
- import { createTestServices } from './services.js';
9
+ import { TEST_EMAIL_FROM, TEST_EMAIL_PROVIDER, createTestServices } from './services.js';
10
10
  /**
11
11
  * A migrated database for integration tests.
12
12
  *
@@ -15,7 +15,7 @@ import { createTestServices } from './services.js';
15
15
  * `truncateAll` empties the tables rather than re-migrating, which is an order of
16
16
  * magnitude faster and just as isolated.
17
17
  */
18
- const silentLogger = createLogger('error', () => undefined);
18
+ const silentLogger = createLogger({ level: 'error', transports: [] });
19
19
  /**
20
20
  * Reads the test database location. Integration tests are skipped rather than
21
21
  * failed when it is absent, so `npm test` still works without Postgres running.
@@ -55,12 +55,15 @@ async function ensureDatabaseExists(connectionString) {
55
55
  export async function connectTestDatabase(connectionString) {
56
56
  await ensureDatabaseExists(connectionString);
57
57
  const connection = connectDatabase(connectionString, silentLogger);
58
+ const services = createTestServices({ db: connection.db });
58
59
  const contributions = await registerModules({
59
60
  modules: coreModules,
60
61
  // Enough for core modules to configure themselves; no test reads it further.
61
62
  environment: TEST_ENVIRONMENT,
62
63
  logger: silentLogger,
63
- services: createTestServices({ db: connection.db }),
64
+ services,
65
+ email: { provider: TEST_EMAIL_PROVIDER, from: TEST_EMAIL_FROM },
66
+ additionalEmailProviders: new Map([[TEST_EMAIL_PROVIDER, services.emailSender]]),
64
67
  });
65
68
  await runMigrations(connection.db, contributions.schemas, silentLogger);
66
69
  async function truncateAll() {
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/testing/database.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,35 @@
1
1
  import type { Database } from '../lib/database.ts';
2
- import type { EmailMessage } from '../lib/email.ts';
2
+ import type { EmailMessage, EmailSender } from '../lib/email.ts';
3
3
  import type { IdFactory } from '../lib/ids.ts';
4
+ import type { SecretEncryptionConfig } from '../lib/secrets.ts';
4
5
  import type { EventBus } from '../runtime/events.ts';
5
6
  import type { ModuleServices } from '../runtime/module.ts';
7
+ /**
8
+ * The provider name `createTestApp` seeds and points `email.provider` at.
9
+ * Exported so a test spawning `registerModules` directly can pass the same
10
+ * name and reach the same collecting sender.
11
+ */
12
+ export declare const TEST_EMAIL_PROVIDER = "test";
13
+ /** The from address the test email config uses. Arbitrary but real. */
14
+ export declare const TEST_EMAIL_FROM = "kelpie-test@example.com";
6
15
  export interface TestServicesOptions {
7
16
  readonly db?: Database;
8
17
  readonly now?: () => Date;
9
18
  readonly createId?: IdFactory;
10
19
  readonly events?: EventBus;
20
+ /** Threaded through to `ModuleServices.appBaseUrl`, so a test exercises the preferred path. */
21
+ readonly appBaseUrl?: string;
22
+ /** Threaded through to `ModuleServices.secretEncryption`, so a test exercises the preferred path. */
23
+ readonly secretEncryption?: SecretEncryptionConfig;
11
24
  }
12
25
  export interface TestServices extends ModuleServices {
26
+ /**
27
+ * The collecting sender `createTestApp` seeds under `TEST_EMAIL_PROVIDER`.
28
+ * `services.emailSender` (this field) is what actually receives calls; a
29
+ * consumer module reaches it through `context.email`, which the runtime's
30
+ * proxy points at whichever provider `email.provider` picked.
31
+ */
32
+ readonly emailSender: EmailSender;
13
33
  /** Everything the email port was asked to send, in order. */
14
34
  readonly sentEmails: readonly EmailMessage[];
15
35
  readonly events: EventBus;
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/testing/services.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,iBAAiB,CAAA;AAEhE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAG9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAc1D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAA;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAA;CAC3B;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAA;IAC5C,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAC1B;AAkBD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAelF"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/testing/services.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAEhE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAE9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAA;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAc1D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,SAAS,CAAA;AAEzC,uEAAuE;AACvE,eAAO,MAAM,eAAe,4BAA4B,CAAA;AAExD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAA;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAA;IAC1B,+FAA+F;IAC/F,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,qGAAqG;IACrG,QAAQ,CAAC,gBAAgB,CAAC,EAAE,sBAAsB,CAAA;CACnD;AAED,MAAM,WAAW,YAAa,SAAQ,cAAc;IAClD;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAA;IACjC,6DAA6D;IAC7D,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAA;IAC5C,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;CAC1B;AAkBD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAsBlF"}
@@ -12,6 +12,14 @@ import { createTransactionScope } from '../runtime/transaction.js';
12
12
  */
13
13
  /** Never queried. A unit test that reaches the database fails here, loudly. */
14
14
  const UNUSED_DATABASE_URL = 'postgres://unused:unused@127.0.0.1:1/unused';
15
+ /**
16
+ * The provider name `createTestApp` seeds and points `email.provider` at.
17
+ * Exported so a test spawning `registerModules` directly can pass the same
18
+ * name and reach the same collecting sender.
19
+ */
20
+ export const TEST_EMAIL_PROVIDER = 'test';
21
+ /** The from address the test email config uses. Arbitrary but real. */
22
+ export const TEST_EMAIL_FROM = 'kelpie-test@example.com';
15
23
  /** Collects messages instead of sending them, so a test can read the reset link. */
16
24
  function createCollectingEmailSender() {
17
25
  const sent = [];
@@ -26,18 +34,25 @@ function createCollectingEmailSender() {
26
34
  };
27
35
  }
28
36
  export function createTestServices(options = {}) {
29
- const logger = createLogger('error', () => undefined);
37
+ const logger = createLogger({ level: 'error', transports: [] });
30
38
  const db = options.db ?? connectDatabase(UNUSED_DATABASE_URL, logger).db;
31
39
  const events = options.events ?? createEventBus(logger);
40
+ const createId = options.createId ?? createIdFactory();
41
+ const now = options.now ?? (() => new Date());
32
42
  const { sender, sent } = createCollectingEmailSender();
33
43
  return {
34
44
  db,
35
- transaction: createTransactionScope({ db, bus: events, logger }),
36
- email: sender,
37
- createId: options.createId ?? createIdFactory(),
38
- now: options.now ?? (() => new Date()),
45
+ transaction: createTransactionScope({ db, bus: events, logger, createId, now }),
46
+ createId,
47
+ now,
48
+ emailSender: sender,
39
49
  sentEmails: sent,
40
50
  events,
51
+ // Spread conditionally so the field is absent (not `undefined`) when the
52
+ // caller does not opt in, keeping the fallback path (context.config) live
53
+ // for the many suites that never touch these fields.
54
+ ...(options.appBaseUrl === undefined ? {} : { appBaseUrl: options.appBaseUrl }),
55
+ ...(options.secretEncryption === undefined ? {} : { secretEncryption: options.secretEncryption }),
41
56
  };
42
57
  }
43
58
  //# sourceMappingURL=services.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/testing/services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAGpD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAElE;;;;;;GAMG;AAEH,+EAA+E;AAC/E,MAAM,mBAAmB,GAAG,6CAA6C,CAAA;AAezE,oFAAoF;AACpF,SAAS,2BAA2B;IAClC,MAAM,IAAI,GAAmB,EAAE,CAAA;IAE/B,OAAO;QACL,IAAI;QACJ,MAAM,EAAE;YACN,IAAI,CAAC,OAAO;gBACV,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBAElB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;YAC1B,CAAC;SACF;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAO,GAAwB,EAAE;IAClE,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,CAAA;IACrD,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,eAAe,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;IACxE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,CAAC,CAAA;IACvD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,2BAA2B,EAAE,CAAA;IAEtD,OAAO;QACL,EAAE;QACF,WAAW,EAAE,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QAChE,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,eAAe,EAAE;QAC/C,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,GAAS,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5C,UAAU,EAAE,IAAI;QAChB,MAAM;KACP,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"services.js","sourceRoot":"","sources":["../../src/testing/services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AAGpD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAGrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAElE;;;;;;GAMG;AAEH,+EAA+E;AAC/E,MAAM,mBAAmB,GAAG,6CAA6C,CAAA;AAEzE;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAA;AAEzC,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG,yBAAyB,CAAA;AA0BxD,oFAAoF;AACpF,SAAS,2BAA2B;IAClC,MAAM,IAAI,GAAmB,EAAE,CAAA;IAE/B,OAAO;QACL,IAAI;QACJ,MAAM,EAAE;YACN,IAAI,CAAC,OAAO;gBACV,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBAElB,OAAO,OAAO,CAAC,OAAO,EAAE,CAAA;YAC1B,CAAC;SACF;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAO,GAAwB,EAAE;IAClE,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAA;IAC/D,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,eAAe,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,EAAE,CAAA;IACxE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,CAAC,CAAA;IACvD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,EAAE,CAAA;IACtD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAS,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,CAAA;IACnD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,2BAA2B,EAAE,CAAA;IAEtD,OAAO;QACL,EAAE;QACF,WAAW,EAAE,sBAAsB,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;QAC/E,QAAQ;QACR,GAAG;QACH,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,IAAI;QAChB,MAAM;QACN,yEAAyE;QACzE,0EAA0E;QAC1E,qDAAqD;QACrD,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC;QAC/E,GAAG,CAAC,OAAO,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC;KAClG,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kelpie/server",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "description": "The Kelpie service as a library: module runtime, core CRM modules, REST API, MCP surface, and the shared migration pipeline.",
5
5
  "keywords": [
6
6
  "kelpie",
@@ -52,13 +52,16 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@hono/node-server": "^2.0.12",
55
- "@kelpie/schemas": "^0.5.1",
55
+ "@kelpie/schemas": "^0.6.0",
56
56
  "@node-rs/argon2": "^2.0.2",
57
57
  "drizzle-orm": "^0.45.2",
58
+ "emittery": "^2.0.0",
58
59
  "hono": "^4.12.32",
59
60
  "nodemailer": "^9.0.5",
60
61
  "postgres": "^3.4.9",
61
62
  "ulid": "^3.0.2",
63
+ "winston": "^3.19.0",
64
+ "winston-transport": "^4.9.0",
62
65
  "zod": "^4.4.3"
63
66
  },
64
67
  "devDependencies": {