@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
package/src/index.ts CHANGED
@@ -7,6 +7,21 @@ export type { WebBundleOptions } from './webBundle.ts'
7
7
  export { ConfigurationError, loadConfig } from './lib/config.ts'
8
8
  export type { Environment, KelpieConfig, LogLevel, RuntimeMode } from './lib/config.ts'
9
9
 
10
+ export { fromEnv, isFromEnvMarker, resolveMarker, resolveMarkers } from './lib/fromEnv.ts'
11
+ export type { ConfigValue, FromEnvMarker, FromEnvProblem, ResolveResult } from './lib/fromEnv.ts'
12
+
13
+ export { defineKelpieConfig, resolveKelpieConfig } from './lib/kelpieConfigFile.ts'
14
+ export type {
15
+ EmailInput,
16
+ KelpieConfigInput,
17
+ RateLimitBudgetInput,
18
+ RateLimitInput,
19
+ SecretEncryptionInput,
20
+ } from './lib/kelpieConfigFile.ts'
21
+
22
+ export { appUrlConfigSchema } from './lib/appUrl.ts'
23
+ export type { AppUrlConfig } from './lib/appUrl.ts'
24
+
10
25
  export { resolveClientIpFrom } from './lib/clientIp.ts'
11
26
 
12
27
  export { ModuleConfigFileError, readModuleConfigFile } from './lib/moduleConfig.ts'
@@ -23,9 +38,12 @@ export type { Database, DatabaseConnection, DatabaseProbe } from './lib/database
23
38
 
24
39
  export * as schema from './schema/index.ts'
25
40
 
26
- export { createEmailSender, createLogEmailSender, emailConfigSchema } from './lib/email.ts'
41
+ export { createLogEmailSender, emailConfigSchema } from './lib/email.ts'
27
42
  export type { EmailConfig, EmailMessage, EmailSender } from './lib/email.ts'
28
43
 
44
+ export { SMTP_EMAIL_PROVIDER, createSmtpEmailModule, createSmtpEmailSender } from './modules/smtp-email/index.ts'
45
+ export type { SmtpEmailConfig, SmtpEmailModuleOptions, SmtpTransport } from './modules/smtp-email/index.ts'
46
+
29
47
  export { MINIMUM_PASSWORD_LENGTH, hashPassword, isPasswordStrongEnough, verifyPassword } from './lib/passwords.ts'
30
48
  export { generateToken, hashToken, tokenHashesMatch } from './lib/tokens.ts'
31
49
 
@@ -49,8 +67,13 @@ export type { ErrorBody, ErrorCode, ErrorDetail, ErrorStatus, ValidationIssue }
49
67
  export { createIdFactory, idPrefixes } from './lib/ids.ts'
50
68
  export type { IdFactory, ObjectKind } from './lib/ids.ts'
51
69
 
52
- export { createLogger } from './lib/logger.ts'
53
- export type { LogFields, Logger, LogSink } from './lib/logger.ts'
70
+ export {
71
+ createCaptureTransport,
72
+ createLogger,
73
+ createStdoutTransport,
74
+ createTransportForDestination,
75
+ } from './lib/logger.ts'
76
+ export type { CreateLoggerOptions, LogFields, Logger, LoggingDestination } from './lib/logger.ts'
54
77
 
55
78
  export type {
56
79
  KelpieModule,
@@ -76,21 +99,33 @@ export type {
76
99
 
77
100
  export { SEATS_LIMIT } from './modules/workspace/capabilities.ts'
78
101
 
79
- export { DOMAIN_EVENT_NAMES, RECORD_OBJECT_TYPES, createEventBus } from './runtime/events.ts'
102
+ export {
103
+ RECORD_OBJECT_TYPES,
104
+ checkEventCycle,
105
+ createEventBus,
106
+ currentEventChain,
107
+ } from './runtime/events.ts'
80
108
  export type {
81
- DomainEventName,
82
- DomainEvents,
109
+ AnyEventHandler,
110
+ CycleGuardOutcome,
83
111
  EventBus,
112
+ EventBusOptions,
113
+ EventCatalog,
114
+ EventChainEntry,
84
115
  EventHandler,
116
+ EventName,
117
+ KelpieEventMap,
85
118
  RecordObjectType,
86
- StagedObjectType,
119
+ SubscribeOptions,
87
120
  } from './runtime/events.ts'
121
+ export type { ModuleEventCatalog } from './runtime/module.ts'
88
122
 
89
123
  export { createTransactionScope } from './runtime/transaction.ts'
90
124
  export type {
91
125
  BufferedEvents,
92
126
  Transaction,
93
127
  TransactionContext,
128
+ TransactionOptions,
94
129
  TransactionScope,
95
130
  TransactionScopeDependencies,
96
131
  } from './runtime/transaction.ts'
@@ -100,8 +135,8 @@ export type { MigrationPlanStep } from './runtime/migrate.ts'
100
135
 
101
136
  export { coreMigrationsDirectory, coreModules } from './modules/core.ts'
102
137
 
103
- export { resealStoredSecrets } from './modules/reseal.ts'
104
- export type { ResealColumnOutcome, ResealOutcome } from './modules/reseal.ts'
138
+ export { resealStoredSecrets, runReseal } from './modules/reseal.ts'
139
+ export type { ResealColumnOutcome, ResealOutcome, ResealPass, RunResealOptions } from './modules/reseal.ts'
105
140
 
106
141
  export { KEY_KINDS, kindOfSecret, mintKey, parseKeyKind, readBearerToken } from './modules/api-keys/keys.ts'
107
142
  export type { KeyKind, MintedKey } from './modules/api-keys/keys.ts'
package/src/lib/actor.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MemberRole } from '@kelpie/schemas'
1
+ import type { EventActor, MemberRole } from '@kelpie/schemas'
2
2
 
3
3
  import { AppError } from './errors.ts'
4
4
 
@@ -97,3 +97,17 @@ export function actorUserId(actor: Actor): string | null {
97
97
  export function actorMemberId(actor: Actor): string | null {
98
98
  return actor.memberId
99
99
  }
100
+
101
+ /**
102
+ * Maps the request actor to the actor stamped on domain events.
103
+ *
104
+ * A signed-in user becomes `user`. A workspace key (no user behind it) becomes
105
+ * `system`, because the event was caused by the workspace itself rather than
106
+ * any one person.
107
+ */
108
+ export function toEventActor(actor: Actor): EventActor {
109
+ if (actor.userId !== null) {
110
+ return { kind: 'user', id: actor.userId }
111
+ }
112
+ return { kind: 'system' }
113
+ }
package/src/lib/config.ts CHANGED
@@ -3,8 +3,14 @@ import { z } from 'zod'
3
3
  import { emailConfigSchema } from './email.ts'
4
4
  import type { EmailConfig } from './email.ts'
5
5
  import { describeValidationIssue } from './errors.ts'
6
+ // `EmailConfig` is `{ EMAIL_PROVIDER, EMAIL_FROM }`. `EMAIL_PROVIDER` names one
7
+ // of the registered senders; `'log'` is always available, other names come
8
+ // from provider modules. Provider-specific config (SMTP settings, an API key)
9
+ // belongs to the module that reads it through `context.config(...)`.
10
+ import type { LoggingDestination } from './logger.ts'
6
11
  import { rateLimitConfigFrom, rateLimitConfigSchema } from './rateLimit.ts'
7
12
  import type { RateLimitConfig } from './rateLimit.ts'
13
+ import type { SecretEncryptionConfig } from './secrets.ts'
8
14
 
9
15
  /**
10
16
  * The single place the service reads environment variables. Every other module
@@ -18,12 +24,29 @@ export type RuntimeMode = 'development' | 'test' | 'production'
18
24
 
19
25
  export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
20
26
 
27
+ /**
28
+ * Everything the logger needs to boot: the minimum severity to emit, and the
29
+ * ordered list of destinations each line is written to. Stdout is one such
30
+ * destination; adding a file or a hosted collector means adding an entry to
31
+ * `destinations` and extending `LoggingDestination` in `lib/logger.ts`.
32
+ */
33
+ export interface LoggingConfig {
34
+ readonly level: LogLevel
35
+ readonly destinations: readonly LoggingDestination[]
36
+ }
37
+
21
38
  export interface KelpieConfig {
22
39
  readonly runtimeMode: RuntimeMode
23
40
  readonly port: number
24
41
  readonly databaseUrl: string
25
- readonly logLevel: LogLevel
26
- /** Transactional mail only. Roadmap decision 4: configured, never hardcoded. */
42
+ readonly logging: LoggingConfig
43
+ /**
44
+ * The provider name the module runtime looks up in its registry, and the
45
+ * from address every outgoing message uses. See `lib/email.ts` for the
46
+ * shape and rules; `'log'` is always available, `'smtp'` is registered by
47
+ * the built-in `smtp-email` core module, and other names come from
48
+ * third-party provider modules.
49
+ */
27
50
  readonly email: EmailConfig
28
51
  /**
29
52
  * Path to the deploy-time module override file (`lib/moduleConfig.ts`).
@@ -44,6 +67,28 @@ export interface KelpieConfig {
44
67
  * client IP is read from `X-Forwarded-For` (`lib/clientIp.ts`).
45
68
  */
46
69
  readonly trustedProxyHopCount: number
70
+ /**
71
+ * What modules see through `context.config(schema)`. `resolveKelpieConfig`
72
+ * produces this by merging any `env` section in `kelpie.config.ts` over
73
+ * `process.env`, so a key in the config file wins for that key and unset
74
+ * keys pass through. `loadConfig` sets it to the environment it was given,
75
+ * so an old caller keeps the same behaviour.
76
+ */
77
+ readonly env: Environment
78
+ /**
79
+ * The deployment's base URL, source of every emailed link. Optional so an
80
+ * older assembly that omits it from `kelpie.config.ts` still boots: modules
81
+ * that need it fall back to `context.config(appUrlConfigSchema)` when unset.
82
+ * A new assembly declares it as a first-class field.
83
+ */
84
+ readonly appBaseUrl: string | undefined
85
+ /**
86
+ * The key(s) that seal stored secrets. Optional for the same reason
87
+ * `appBaseUrl` is: modules that need it fall back to
88
+ * `context.config(secretEncryptionConfigSchema)`. The base assembly declares
89
+ * it, so both webhooks and agent-tasks receive it through `services`.
90
+ */
91
+ readonly secretEncryption: SecretEncryptionConfig | undefined
47
92
  }
48
93
 
49
94
  /** Thrown at boot when the environment cannot produce a valid configuration. */
@@ -82,10 +127,8 @@ const environmentSchema = z.object({
82
127
  /**
83
128
  * Parses an environment into a validated config.
84
129
  *
85
- * `emailConfigSchema` is a discriminated union, so it is parsed separately
86
- * from the rest: a union has no flat `.shape` to spread into `environmentSchema`,
87
- * only its own `EMAIL_PROVIDER`-keyed branches. Problems from both parses are
88
- * combined into one error, preserving the "every missing variable at once" rule.
130
+ * The email variables are parsed separately so a caller sees every missing
131
+ * variable at once, rather than one at a time.
89
132
  *
90
133
  * @param environment Raw variables, normally `process.env`.
91
134
  * @throws ConfigurationError listing every invalid or missing variable.
@@ -107,11 +150,17 @@ export function loadConfig(environment: Environment): KelpieConfig {
107
150
  runtimeMode: environmentResult.data.NODE_ENV,
108
151
  port: environmentResult.data.PORT,
109
152
  databaseUrl: environmentResult.data.DATABASE_URL,
110
- logLevel: environmentResult.data.LOG_LEVEL,
153
+ logging: {
154
+ level: environmentResult.data.LOG_LEVEL,
155
+ destinations: [{ kind: 'stdout' }],
156
+ },
111
157
  email: emailResult.data,
112
158
  moduleConfigPath: environmentResult.data.KELPIE_MODULE_CONFIG_PATH,
113
159
  webBundleDirectory: environmentResult.data.WEB_BUNDLE_DIR,
114
160
  rateLimit: rateLimitConfigFrom(environmentResult.data),
115
161
  trustedProxyHopCount: environmentResult.data.TRUSTED_PROXY_HOP_COUNT,
162
+ env: environment,
163
+ appBaseUrl: undefined,
164
+ secretEncryption: undefined,
116
165
  }
117
166
  }
package/src/lib/email.ts CHANGED
@@ -1,7 +1,5 @@
1
- import nodemailer from 'nodemailer'
2
1
  import { z } from 'zod'
3
2
 
4
- import { describeThrown } from './errors.ts'
5
3
  import type { Logger } from './logger.ts'
6
4
 
7
5
  /**
@@ -9,15 +7,15 @@ import type { Logger } from './logger.ts'
9
7
  * and account-change notifications, nothing else. Kelpie never sends outreach
10
8
  * email.
11
9
  *
12
- * Roadmap decision 4: the provider is configured, never hardcoded. Core ships
13
- * the port and two providers, `log` and `smtp`. Both need no vendor account a
14
- * deployment doesn't already have, which is what keeps them in core rather than
15
- * a module, per `modules.md`'s split test. A provider that does need one
16
- * (Resend, Postmark, Mailtrap, SendGrid) is a commercial integration under that
17
- * same test and belongs in a module: it supplies its own `EmailSender` from its
18
- * own config, and an assembly's entry point wires it into `services.email` in
19
- * place of `createEmailSender`, the same way `kelpie-cloud/src/server.ts` wires
20
- * this one today.
10
+ * The assembly names one named provider in `kelpie.config.ts`'s
11
+ * `email.provider`. The module runtime resolves the name against a registry
12
+ * every module can contribute to via `context.provideEmailSender(name, sender)`.
13
+ * `'log'` is a built-in name the runtime always registers, so a bare install
14
+ * has something to point at. `'smtp'` is registered by the built-in
15
+ * `smtp-email` core module. Other names come from third-party provider modules
16
+ * (Resend, Postmark, SES) that follow the same registry pattern. Transport is
17
+ * arbitrary: the module builds one behind the `EmailSender` interface and
18
+ * hands it to core, which knows only how to `send`.
21
19
  */
22
20
 
23
21
  export interface EmailMessage {
@@ -30,40 +28,29 @@ export interface EmailSender {
30
28
  send(message: EmailMessage): Promise<void>
31
29
  }
32
30
 
33
- const logEmailConfigSchema = z.object({
34
- EMAIL_PROVIDER: z.literal('log'),
31
+ export const emailConfigSchema = z.object({
32
+ /**
33
+ * The named provider `registerModules` resolves against its registry. `'log'`
34
+ * is a built-in, always present. Any other name needs a module that
35
+ * registered it via `context.provideEmailSender(name, sender)`. Free-string
36
+ * so a self-hoster can add a module core has never heard of.
37
+ */
38
+ EMAIL_PROVIDER: z.string().min(1),
35
39
  EMAIL_FROM: z.string().min(1),
36
40
  })
37
41
 
38
- const smtpEmailConfigSchema = z.object({
39
- EMAIL_PROVIDER: z.literal('smtp'),
40
- EMAIL_FROM: z.string().min(1),
41
- SMTP_HOST: z.string().min(1),
42
- SMTP_PORT: z.coerce.number().int().positive().max(65535),
43
- SMTP_SECURE: z.enum(['true', 'false']).transform((value) => value === 'true'),
44
- SMTP_USER: z.string().min(1),
45
- SMTP_PASSWORD: z.string().min(1),
46
- })
47
-
48
- export const emailConfigSchema = z.discriminatedUnion('EMAIL_PROVIDER', [
49
- logEmailConfigSchema,
50
- smtpEmailConfigSchema,
51
- ])
52
-
53
42
  export type EmailConfig = z.infer<typeof emailConfigSchema>
54
- export type SmtpEmailConfig = z.infer<typeof smtpEmailConfigSchema>
55
43
 
56
44
  /**
57
- * Writes the message to the log instead of sending it. For self-hosted
58
- * development, where the reset link in the log is exactly what you want.
59
- *
60
- * This is a deliberate choice, not a fallback: `EMAIL_PROVIDER` has no default,
61
- * so nobody reaches this provider without naming it.
45
+ * Writes the message to the log instead of sending it. The registry default,
46
+ * swapped out for a real sender by picking a different provider name in
47
+ * `email.provider` (`'smtp'` for the built-in SMTP module, or any name a
48
+ * third-party provider module registers).
62
49
  */
63
50
  export function createLogEmailSender(logger: Logger, from: string): EmailSender {
64
51
  return {
65
52
  send(message) {
66
- logger.info('email not sent: provider is "log"', {
53
+ logger.info('email not sent: no provider module registered', {
67
54
  from,
68
55
  to: message.to,
69
56
  subject: message.subject,
@@ -74,60 +61,3 @@ export function createLogEmailSender(logger: Logger, from: string): EmailSender
74
61
  },
75
62
  }
76
63
  }
77
-
78
- /**
79
- * What `createSmtpEmailSender` sends a message through. A real deployment gets
80
- * one backed by `nodemailer`; a test injects one that records calls, so the
81
- * sender is verifiable without a container running a real SMTP conversation.
82
- */
83
- export interface SmtpTransport {
84
- sendMail(message: { from: string; to: string; subject: string; text: string }): Promise<unknown>
85
- }
86
-
87
- function createNodemailerTransport(config: SmtpEmailConfig): SmtpTransport {
88
- return nodemailer.createTransport({
89
- host: config.SMTP_HOST,
90
- port: config.SMTP_PORT,
91
- secure: config.SMTP_SECURE,
92
- auth: { user: config.SMTP_USER, pass: config.SMTP_PASSWORD },
93
- })
94
- }
95
-
96
- /** Sends over SMTP. `transport` defaults to a real connection built from `config`. */
97
- export function createSmtpEmailSender(
98
- config: SmtpEmailConfig,
99
- logger: Logger,
100
- transport: SmtpTransport = createNodemailerTransport(config),
101
- ): EmailSender {
102
- return {
103
- async send(message) {
104
- try {
105
- await transport.sendMail({
106
- from: config.EMAIL_FROM,
107
- to: message.to,
108
- subject: message.subject,
109
- text: message.body,
110
- })
111
- } catch (cause) {
112
- const reason = describeThrown(cause)
113
- logger.error('smtp send failed', { to: message.to, reason })
114
- throw new Error(`Failed to send email to ${message.to} over SMTP: ${reason}`, { cause })
115
- }
116
- },
117
- }
118
- }
119
-
120
- /**
121
- * Builds the configured sender.
122
- *
123
- * @throws Never. An unknown provider cannot reach here: the config schema is a
124
- * discriminated union, so boot rejects it first.
125
- */
126
- export function createEmailSender(config: EmailConfig, logger: Logger): EmailSender {
127
- switch (config.EMAIL_PROVIDER) {
128
- case 'log':
129
- return createLogEmailSender(logger, config.EMAIL_FROM)
130
- case 'smtp':
131
- return createSmtpEmailSender(config, logger)
132
- }
133
- }
@@ -0,0 +1,143 @@
1
+ import type { ZodType } from 'zod'
2
+
3
+ import type { Environment } from './config.ts'
4
+
5
+ /**
6
+ * A marker a `kelpie.config.ts` file uses to say "read this leaf from the
7
+ * environment." The assembly's config file is the shape and the defaults;
8
+ * `fromEnv` marks the leaves a deployment may override without a code change.
9
+ *
10
+ * Every marker names an env var, the Zod schema that parses it, and optionally
11
+ * a default. Without a default the marker is required: the env var must be set,
12
+ * or boot fails with the other configuration problems.
13
+ *
14
+ * The resolver walks the config object, replaces each marker with the parsed
15
+ * value, and returns the fully-resolved object. Nothing in the app reads
16
+ * `process.env` for these fields after boot.
17
+ */
18
+
19
+ const FROM_ENV_MARKER = Symbol.for('kelpie.fromEnv')
20
+
21
+ export interface FromEnvMarker<T> {
22
+ readonly [FROM_ENV_MARKER]: true
23
+ readonly envKey: string
24
+ readonly schema: ZodType<T>
25
+ readonly defaultValue: T | undefined
26
+ readonly hasDefault: boolean
27
+ }
28
+
29
+ /** A leaf in the config file: either a literal already-typed value, or a marker. */
30
+ export type ConfigValue<T> = T | FromEnvMarker<T>
31
+
32
+ export function fromEnv<T>(envKey: string, schema: ZodType<T>): FromEnvMarker<T>
33
+ export function fromEnv<T>(envKey: string, schema: ZodType<T>, defaultValue: T): FromEnvMarker<T>
34
+ export function fromEnv<T>(envKey: string, schema: ZodType<T>, defaultValue?: T): FromEnvMarker<T> {
35
+ const hasDefault = arguments.length >= 3
36
+
37
+ return {
38
+ [FROM_ENV_MARKER]: true,
39
+ envKey,
40
+ schema,
41
+ defaultValue: hasDefault ? (defaultValue as T) : undefined,
42
+ hasDefault,
43
+ }
44
+ }
45
+
46
+ export function isFromEnvMarker(value: unknown): value is FromEnvMarker<unknown> {
47
+ return typeof value === 'object' && value !== null && (value as Record<PropertyKey, unknown>)[FROM_ENV_MARKER] === true
48
+ }
49
+
50
+ /** One problem discovered while resolving markers. Path is the dotted field. */
51
+ export interface FromEnvProblem {
52
+ readonly path: string
53
+ readonly message: string
54
+ }
55
+
56
+ export interface ResolveResult<T> {
57
+ readonly value: T | undefined
58
+ readonly problems: readonly FromEnvProblem[]
59
+ }
60
+
61
+ /**
62
+ * Resolves one marker against an environment.
63
+ *
64
+ * Missing and no default: one required problem.
65
+ * Missing with default: the default, unvalidated. A hardcoded default is
66
+ * trusted because the developer wrote it in the assembly file.
67
+ * Present: parsed through the marker's schema. Parse failures become problems.
68
+ */
69
+ export function resolveMarker<T>(marker: FromEnvMarker<T>, environment: Environment, path: string): ResolveResult<T> {
70
+ const raw = environment[marker.envKey]
71
+
72
+ if (raw === undefined) {
73
+ if (marker.hasDefault) {
74
+ return { value: marker.defaultValue, problems: [] }
75
+ }
76
+
77
+ return {
78
+ value: undefined,
79
+ problems: [{ path, message: `${marker.envKey} is required` }],
80
+ }
81
+ }
82
+
83
+ const result = marker.schema.safeParse(raw)
84
+
85
+ if (!result.success) {
86
+ return {
87
+ value: undefined,
88
+ problems: result.error.issues.map((issue) => ({
89
+ path,
90
+ message: `${marker.envKey}: ${issue.message}`,
91
+ })),
92
+ }
93
+ }
94
+
95
+ return { value: result.data, problems: [] }
96
+ }
97
+
98
+ /**
99
+ * Walks any value, replacing every `FromEnvMarker` with its resolved value.
100
+ * Objects and arrays are walked recursively; other values pass through.
101
+ *
102
+ * Collects problems from every marker rather than throwing at the first one,
103
+ * so a self-hoster fixes their environment once rather than a variable at a
104
+ * time.
105
+ */
106
+ export function resolveMarkers(
107
+ input: unknown,
108
+ environment: Environment,
109
+ path = '',
110
+ ): { readonly value: unknown; readonly problems: readonly FromEnvProblem[] } {
111
+ if (isFromEnvMarker(input)) {
112
+ return resolveMarker(input, environment, path)
113
+ }
114
+
115
+ if (Array.isArray(input)) {
116
+ const problems: FromEnvProblem[] = []
117
+ const value = input.map((item, index) => {
118
+ const childPath = `${path}[${String(index)}]`
119
+ const result = resolveMarkers(item, environment, childPath)
120
+ problems.push(...result.problems)
121
+
122
+ return result.value
123
+ })
124
+
125
+ return { value, problems }
126
+ }
127
+
128
+ if (typeof input === 'object' && input !== null) {
129
+ const problems: FromEnvProblem[] = []
130
+ const value: Record<string, unknown> = {}
131
+
132
+ for (const [key, child] of Object.entries(input)) {
133
+ const childPath = path.length > 0 ? `${path}.${key}` : key
134
+ const result = resolveMarkers(child, environment, childPath)
135
+ problems.push(...result.problems)
136
+ value[key] = result.value
137
+ }
138
+
139
+ return { value, problems }
140
+ }
141
+
142
+ return { value: input, problems: [] }
143
+ }
package/src/lib/ids.ts CHANGED
@@ -52,6 +52,12 @@ export const idPrefixes = {
52
52
  * a bucket is bookkeeping the rate limiter owns, not a resource with routes.
53
53
  */
54
54
  rateLimitBucket: 'rl',
55
+ /**
56
+ * One published domain event. Stamped on the envelope so downstream consumers
57
+ * (webhooks, MCP subscribers, an eventual outbox) have a stable idempotency
58
+ * key. Not persisted by core.
59
+ */
60
+ event: 'ev',
55
61
  } as const
56
62
 
57
63
  export type ObjectKind = keyof typeof idPrefixes