@kelpie/server 0.10.0 → 0.12.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 (485) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +2 -0
  3. package/dist/app.js.map +1 -1
  4. package/dist/index.d.ts +3 -3
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/actor.d.ts +3 -1
  9. package/dist/lib/actor.d.ts.map +1 -1
  10. package/dist/lib/actor.js.map +1 -1
  11. package/dist/lib/apiKeyScopes.d.ts +8 -0
  12. package/dist/lib/apiKeyScopes.d.ts.map +1 -0
  13. package/dist/lib/apiKeyScopes.js +166 -0
  14. package/dist/lib/apiKeyScopes.js.map +1 -0
  15. package/dist/lib/errors.d.ts +18 -0
  16. package/dist/lib/errors.d.ts.map +1 -1
  17. package/dist/lib/errors.js +17 -0
  18. package/dist/lib/errors.js.map +1 -1
  19. package/dist/modules/activities/repository.d.ts +2 -0
  20. package/dist/modules/activities/repository.d.ts.map +1 -1
  21. package/dist/modules/activities/repository.js +9 -0
  22. package/dist/modules/activities/repository.js.map +1 -1
  23. package/dist/modules/agent-tasks/repository.d.ts +2 -0
  24. package/dist/modules/agent-tasks/repository.d.ts.map +1 -1
  25. package/dist/modules/agent-tasks/repository.js +9 -0
  26. package/dist/modules/agent-tasks/repository.js.map +1 -1
  27. package/dist/modules/api-keys/routes.d.ts.map +1 -1
  28. package/dist/modules/api-keys/routes.js +4 -1
  29. package/dist/modules/api-keys/routes.js.map +1 -1
  30. package/dist/modules/api-keys/schema.d.ts +43 -0
  31. package/dist/modules/api-keys/schema.d.ts.map +1 -1
  32. package/dist/modules/api-keys/schema.js +2 -0
  33. package/dist/modules/api-keys/schema.js.map +1 -1
  34. package/dist/modules/api-keys/scopeMiddleware.d.ts +8 -0
  35. package/dist/modules/api-keys/scopeMiddleware.d.ts.map +1 -0
  36. package/dist/modules/api-keys/scopeMiddleware.js +21 -0
  37. package/dist/modules/api-keys/scopeMiddleware.js.map +1 -0
  38. package/dist/modules/api-keys/service.d.ts +3 -1
  39. package/dist/modules/api-keys/service.d.ts.map +1 -1
  40. package/dist/modules/api-keys/service.js +26 -1
  41. package/dist/modules/api-keys/service.js.map +1 -1
  42. package/dist/modules/auth/credentials.d.ts.map +1 -1
  43. package/dist/modules/auth/credentials.js +2 -0
  44. package/dist/modules/auth/credentials.js.map +1 -1
  45. package/dist/modules/auth/index.d.ts.map +1 -1
  46. package/dist/modules/auth/index.js +21 -4
  47. package/dist/modules/auth/index.js.map +1 -1
  48. package/dist/modules/auth/repository.d.ts +2 -1
  49. package/dist/modules/auth/repository.d.ts.map +1 -1
  50. package/dist/modules/auth/repository.js +1 -0
  51. package/dist/modules/auth/repository.js.map +1 -1
  52. package/dist/modules/auth/routes.d.ts.map +1 -1
  53. package/dist/modules/auth/routes.js +2 -6
  54. package/dist/modules/auth/routes.js.map +1 -1
  55. package/dist/modules/auth/schema.d.ts +18 -1
  56. package/dist/modules/auth/schema.d.ts.map +1 -1
  57. package/dist/modules/auth/schema.js +12 -1
  58. package/dist/modules/auth/schema.js.map +1 -1
  59. package/dist/modules/auth/service.d.ts +18 -0
  60. package/dist/modules/auth/service.d.ts.map +1 -1
  61. package/dist/modules/auth/service.js +95 -6
  62. package/dist/modules/auth/service.js.map +1 -1
  63. package/dist/modules/auth/session.d.ts +12 -0
  64. package/dist/modules/auth/session.d.ts.map +1 -1
  65. package/dist/modules/auth/session.js +12 -0
  66. package/dist/modules/auth/session.js.map +1 -1
  67. package/dist/modules/consent-purposes/index.d.ts +1 -1
  68. package/dist/modules/consent-purposes/index.js +1 -1
  69. package/dist/modules/consent-purposes/schema.d.ts +3 -3
  70. package/dist/modules/consent-purposes/schema.js +3 -3
  71. package/dist/modules/consent-purposes/service.d.ts +1 -1
  72. package/dist/modules/consent-purposes/service.d.ts.map +1 -1
  73. package/dist/modules/consent-purposes/service.js +7 -16
  74. package/dist/modules/consent-purposes/service.js.map +1 -1
  75. package/dist/modules/consent-purposes/starters.d.ts +1 -1
  76. package/dist/modules/consent-purposes/tools.js +1 -1
  77. package/dist/modules/consent-purposes/tools.js.map +1 -1
  78. package/dist/modules/conversions/clearPointers.d.ts +10 -0
  79. package/dist/modules/conversions/clearPointers.d.ts.map +1 -0
  80. package/dist/modules/conversions/clearPointers.js +40 -0
  81. package/dist/modules/conversions/clearPointers.js.map +1 -0
  82. package/dist/modules/conversions/factory.d.ts +5 -0
  83. package/dist/modules/conversions/factory.d.ts.map +1 -0
  84. package/dist/modules/conversions/factory.js +18 -0
  85. package/dist/modules/conversions/factory.js.map +1 -0
  86. package/dist/modules/conversions/fieldMap.d.ts +55 -0
  87. package/dist/modules/conversions/fieldMap.d.ts.map +1 -0
  88. package/dist/modules/conversions/fieldMap.js +398 -0
  89. package/dist/modules/conversions/fieldMap.js.map +1 -0
  90. package/dist/modules/conversions/index.d.ts +7 -0
  91. package/dist/modules/conversions/index.d.ts.map +1 -0
  92. package/dist/modules/conversions/index.js +6 -0
  93. package/dist/modules/conversions/index.js.map +1 -0
  94. package/dist/modules/conversions/mcp.d.ts +7 -0
  95. package/dist/modules/conversions/mcp.d.ts.map +1 -0
  96. package/dist/modules/conversions/mcp.js +47 -0
  97. package/dist/modules/conversions/mcp.js.map +1 -0
  98. package/dist/modules/conversions/repoint.d.ts +19 -0
  99. package/dist/modules/conversions/repoint.d.ts.map +1 -0
  100. package/dist/modules/conversions/repoint.js +51 -0
  101. package/dist/modules/conversions/repoint.js.map +1 -0
  102. package/dist/modules/conversions/routes.d.ts +26 -0
  103. package/dist/modules/conversions/routes.d.ts.map +1 -0
  104. package/dist/modules/conversions/routes.js +23 -0
  105. package/dist/modules/conversions/routes.js.map +1 -0
  106. package/dist/modules/conversions/service.d.ts +28 -0
  107. package/dist/modules/conversions/service.d.ts.map +1 -0
  108. package/dist/modules/conversions/service.js +170 -0
  109. package/dist/modules/conversions/service.js.map +1 -0
  110. package/dist/modules/conversions/wire.d.ts +4 -0
  111. package/dist/modules/conversions/wire.d.ts.map +1 -0
  112. package/dist/modules/conversions/wire.js +28 -0
  113. package/dist/modules/conversions/wire.js.map +1 -0
  114. package/dist/modules/deals/events.d.ts +9 -0
  115. package/dist/modules/deals/events.d.ts.map +1 -1
  116. package/dist/modules/deals/events.js +4 -0
  117. package/dist/modules/deals/events.js.map +1 -1
  118. package/dist/modules/deals/index.d.ts.map +1 -1
  119. package/dist/modules/deals/index.js +4 -2
  120. package/dist/modules/deals/index.js.map +1 -1
  121. package/dist/modules/deals/routes.d.ts +2 -0
  122. package/dist/modules/deals/routes.d.ts.map +1 -1
  123. package/dist/modules/deals/routes.js +8 -1
  124. package/dist/modules/deals/routes.js.map +1 -1
  125. package/dist/modules/deals/schema.d.ts +34 -0
  126. package/dist/modules/deals/schema.d.ts.map +1 -1
  127. package/dist/modules/deals/schema.js +7 -2
  128. package/dist/modules/deals/schema.js.map +1 -1
  129. package/dist/modules/deals/service.d.ts.map +1 -1
  130. package/dist/modules/deals/service.js +2 -0
  131. package/dist/modules/deals/service.js.map +1 -1
  132. package/dist/modules/deals/tools.d.ts +2 -1
  133. package/dist/modules/deals/tools.d.ts.map +1 -1
  134. package/dist/modules/deals/tools.js +3 -1
  135. package/dist/modules/deals/tools.js.map +1 -1
  136. package/dist/modules/decisions/repository.d.ts +2 -1
  137. package/dist/modules/decisions/repository.d.ts.map +1 -1
  138. package/dist/modules/decisions/repository.js +9 -1
  139. package/dist/modules/decisions/repository.js.map +1 -1
  140. package/dist/modules/enquiries/events.d.ts +6 -2
  141. package/dist/modules/enquiries/events.d.ts.map +1 -1
  142. package/dist/modules/enquiries/events.js +5 -1
  143. package/dist/modules/enquiries/events.js.map +1 -1
  144. package/dist/modules/enquiries/index.d.ts.map +1 -1
  145. package/dist/modules/enquiries/index.js +4 -2
  146. package/dist/modules/enquiries/index.js.map +1 -1
  147. package/dist/modules/enquiries/routes.d.ts +2 -0
  148. package/dist/modules/enquiries/routes.d.ts.map +1 -1
  149. package/dist/modules/enquiries/routes.js +9 -9
  150. package/dist/modules/enquiries/routes.js.map +1 -1
  151. package/dist/modules/enquiries/schema.d.ts +36 -1
  152. package/dist/modules/enquiries/schema.d.ts.map +1 -1
  153. package/dist/modules/enquiries/schema.js +9 -3
  154. package/dist/modules/enquiries/schema.js.map +1 -1
  155. package/dist/modules/enquiries/service.d.ts +0 -8
  156. package/dist/modules/enquiries/service.d.ts.map +1 -1
  157. package/dist/modules/enquiries/service.js +3 -95
  158. package/dist/modules/enquiries/service.js.map +1 -1
  159. package/dist/modules/enquiries/tools.d.ts +2 -1
  160. package/dist/modules/enquiries/tools.d.ts.map +1 -1
  161. package/dist/modules/enquiries/tools.js +4 -16
  162. package/dist/modules/enquiries/tools.js.map +1 -1
  163. package/dist/modules/forms/applyMappedFields.d.ts +20 -0
  164. package/dist/modules/forms/applyMappedFields.d.ts.map +1 -0
  165. package/dist/modules/forms/applyMappedFields.js +169 -0
  166. package/dist/modules/forms/applyMappedFields.js.map +1 -0
  167. package/dist/modules/forms/applySubmissionFields.d.ts +18 -0
  168. package/dist/modules/forms/applySubmissionFields.d.ts.map +1 -0
  169. package/dist/modules/forms/applySubmissionFields.js +230 -0
  170. package/dist/modules/forms/applySubmissionFields.js.map +1 -0
  171. package/dist/modules/forms/fields.d.ts +7 -2
  172. package/dist/modules/forms/fields.d.ts.map +1 -1
  173. package/dist/modules/forms/fields.js +17 -6
  174. package/dist/modules/forms/fields.js.map +1 -1
  175. package/dist/modules/forms/mapping.d.ts +8 -2
  176. package/dist/modules/forms/mapping.d.ts.map +1 -1
  177. package/dist/modules/forms/mapping.js +11 -0
  178. package/dist/modules/forms/mapping.js.map +1 -1
  179. package/dist/modules/forms/repository.d.ts +0 -5
  180. package/dist/modules/forms/repository.d.ts.map +1 -1
  181. package/dist/modules/forms/repository.js +0 -2
  182. package/dist/modules/forms/repository.js.map +1 -1
  183. package/dist/modules/forms/routes.d.ts +2 -30
  184. package/dist/modules/forms/routes.d.ts.map +1 -1
  185. package/dist/modules/forms/routes.js +2 -2
  186. package/dist/modules/forms/routes.js.map +1 -1
  187. package/dist/modules/forms/schema.d.ts.map +1 -1
  188. package/dist/modules/forms/schema.js +1 -2
  189. package/dist/modules/forms/schema.js.map +1 -1
  190. package/dist/modules/forms/service.d.ts.map +1 -1
  191. package/dist/modules/forms/service.js +18 -3
  192. package/dist/modules/forms/service.js.map +1 -1
  193. package/dist/modules/forms/starters.d.ts +31 -0
  194. package/dist/modules/forms/starters.d.ts.map +1 -0
  195. package/dist/modules/forms/starters.js +94 -0
  196. package/dist/modules/forms/starters.js.map +1 -0
  197. package/dist/modules/forms/submission.d.ts +1 -0
  198. package/dist/modules/forms/submission.d.ts.map +1 -1
  199. package/dist/modules/forms/submission.js +58 -37
  200. package/dist/modules/forms/submission.js.map +1 -1
  201. package/dist/modules/import-export/customFieldCsv.d.ts +9 -0
  202. package/dist/modules/import-export/customFieldCsv.d.ts.map +1 -0
  203. package/dist/modules/import-export/customFieldCsv.js +39 -0
  204. package/dist/modules/import-export/customFieldCsv.js.map +1 -0
  205. package/dist/modules/import-export/customFieldImport.d.ts +19 -0
  206. package/dist/modules/import-export/customFieldImport.d.ts.map +1 -0
  207. package/dist/modules/import-export/customFieldImport.js +76 -0
  208. package/dist/modules/import-export/customFieldImport.js.map +1 -0
  209. package/dist/modules/import-export/drafts.d.ts +57 -3
  210. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  211. package/dist/modules/import-export/drafts.js +65 -3
  212. package/dist/modules/import-export/drafts.js.map +1 -1
  213. package/dist/modules/import-export/exportRows.d.ts +15 -13
  214. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  215. package/dist/modules/import-export/exportRows.js +99 -26
  216. package/dist/modules/import-export/exportRows.js.map +1 -1
  217. package/dist/modules/import-export/plan.d.ts +42 -11
  218. package/dist/modules/import-export/plan.d.ts.map +1 -1
  219. package/dist/modules/import-export/plan.js +198 -56
  220. package/dist/modules/import-export/plan.js.map +1 -1
  221. package/dist/modules/import-export/repository.d.ts +58 -2
  222. package/dist/modules/import-export/repository.d.ts.map +1 -1
  223. package/dist/modules/import-export/repository.js +201 -12
  224. package/dist/modules/import-export/repository.js.map +1 -1
  225. package/dist/modules/import-export/routes.d.ts.map +1 -1
  226. package/dist/modules/import-export/routes.js +5 -5
  227. package/dist/modules/import-export/routes.js.map +1 -1
  228. package/dist/modules/import-export/service.d.ts +8 -3
  229. package/dist/modules/import-export/service.d.ts.map +1 -1
  230. package/dist/modules/import-export/service.js +133 -40
  231. package/dist/modules/import-export/service.js.map +1 -1
  232. package/dist/modules/import-export/streams.d.ts +2 -2
  233. package/dist/modules/import-export/streams.d.ts.map +1 -1
  234. package/dist/modules/import-export/streams.js +50 -9
  235. package/dist/modules/import-export/streams.js.map +1 -1
  236. package/dist/modules/import-export/tools.d.ts.map +1 -1
  237. package/dist/modules/import-export/tools.js +13 -7
  238. package/dist/modules/import-export/tools.js.map +1 -1
  239. package/dist/modules/import-export/validation.d.ts +5 -1
  240. package/dist/modules/import-export/validation.d.ts.map +1 -1
  241. package/dist/modules/import-export/validation.js +89 -2
  242. package/dist/modules/import-export/validation.js.map +1 -1
  243. package/dist/modules/import-export/writes.d.ts +2 -1
  244. package/dist/modules/import-export/writes.d.ts.map +1 -1
  245. package/dist/modules/import-export/writes.js +358 -25
  246. package/dist/modules/import-export/writes.js.map +1 -1
  247. package/dist/modules/lists/repository.d.ts +0 -1
  248. package/dist/modules/lists/repository.d.ts.map +1 -1
  249. package/dist/modules/lists/repository.js +0 -1
  250. package/dist/modules/lists/repository.js.map +1 -1
  251. package/dist/modules/lists/routes.d.ts +0 -2
  252. package/dist/modules/lists/routes.d.ts.map +1 -1
  253. package/dist/modules/lists/routes.js +0 -8
  254. package/dist/modules/lists/routes.js.map +1 -1
  255. package/dist/modules/lists/schema.d.ts +0 -17
  256. package/dist/modules/lists/schema.d.ts.map +1 -1
  257. package/dist/modules/lists/schema.js +0 -10
  258. package/dist/modules/lists/schema.js.map +1 -1
  259. package/dist/modules/lists/service.d.ts +2 -14
  260. package/dist/modules/lists/service.d.ts.map +1 -1
  261. package/dist/modules/lists/service.js +7 -53
  262. package/dist/modules/lists/service.js.map +1 -1
  263. package/dist/modules/lists/starters.d.ts +12 -0
  264. package/dist/modules/lists/starters.d.ts.map +1 -0
  265. package/dist/modules/lists/starters.js +4 -0
  266. package/dist/modules/lists/starters.js.map +1 -0
  267. package/dist/modules/mcp/protocol.d.ts.map +1 -1
  268. package/dist/modules/mcp/protocol.js +13 -0
  269. package/dist/modules/mcp/protocol.js.map +1 -1
  270. package/dist/modules/notes/repository.d.ts +2 -0
  271. package/dist/modules/notes/repository.d.ts.map +1 -1
  272. package/dist/modules/notes/repository.js +9 -0
  273. package/dist/modules/notes/repository.js.map +1 -1
  274. package/dist/modules/opportunities/events.d.ts +9 -0
  275. package/dist/modules/opportunities/events.d.ts.map +1 -1
  276. package/dist/modules/opportunities/events.js +4 -0
  277. package/dist/modules/opportunities/events.js.map +1 -1
  278. package/dist/modules/opportunities/index.d.ts.map +1 -1
  279. package/dist/modules/opportunities/index.js +4 -2
  280. package/dist/modules/opportunities/index.js.map +1 -1
  281. package/dist/modules/opportunities/routes.d.ts +2 -0
  282. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  283. package/dist/modules/opportunities/routes.js +8 -1
  284. package/dist/modules/opportunities/routes.js.map +1 -1
  285. package/dist/modules/opportunities/schema.d.ts +34 -0
  286. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  287. package/dist/modules/opportunities/schema.js +7 -2
  288. package/dist/modules/opportunities/schema.js.map +1 -1
  289. package/dist/modules/opportunities/service.d.ts.map +1 -1
  290. package/dist/modules/opportunities/service.js +2 -0
  291. package/dist/modules/opportunities/service.js.map +1 -1
  292. package/dist/modules/opportunities/tools.d.ts +2 -1
  293. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  294. package/dist/modules/opportunities/tools.js +3 -1
  295. package/dist/modules/opportunities/tools.js.map +1 -1
  296. package/dist/modules/partnerships/events.d.ts +9 -0
  297. package/dist/modules/partnerships/events.d.ts.map +1 -1
  298. package/dist/modules/partnerships/events.js +4 -0
  299. package/dist/modules/partnerships/events.js.map +1 -1
  300. package/dist/modules/partnerships/index.d.ts.map +1 -1
  301. package/dist/modules/partnerships/index.js +4 -2
  302. package/dist/modules/partnerships/index.js.map +1 -1
  303. package/dist/modules/partnerships/routes.d.ts +2 -0
  304. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  305. package/dist/modules/partnerships/routes.js +8 -1
  306. package/dist/modules/partnerships/routes.js.map +1 -1
  307. package/dist/modules/partnerships/schema.d.ts +34 -0
  308. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  309. package/dist/modules/partnerships/schema.js +7 -2
  310. package/dist/modules/partnerships/schema.js.map +1 -1
  311. package/dist/modules/partnerships/service.d.ts.map +1 -1
  312. package/dist/modules/partnerships/service.js +2 -0
  313. package/dist/modules/partnerships/service.js.map +1 -1
  314. package/dist/modules/partnerships/tools.d.ts +2 -1
  315. package/dist/modules/partnerships/tools.d.ts.map +1 -1
  316. package/dist/modules/partnerships/tools.js +3 -1
  317. package/dist/modules/partnerships/tools.js.map +1 -1
  318. package/dist/modules/people/personConsentWrites.d.ts +1 -1
  319. package/dist/modules/people/schema.js +1 -1
  320. package/dist/modules/people/schema.js.map +1 -1
  321. package/dist/modules/plans/repository.d.ts +2 -0
  322. package/dist/modules/plans/repository.d.ts.map +1 -1
  323. package/dist/modules/plans/repository.js +9 -0
  324. package/dist/modules/plans/repository.js.map +1 -1
  325. package/dist/modules/raises/events.d.ts +9 -0
  326. package/dist/modules/raises/events.d.ts.map +1 -1
  327. package/dist/modules/raises/events.js +4 -0
  328. package/dist/modules/raises/events.js.map +1 -1
  329. package/dist/modules/raises/index.d.ts.map +1 -1
  330. package/dist/modules/raises/index.js +4 -2
  331. package/dist/modules/raises/index.js.map +1 -1
  332. package/dist/modules/raises/routes.d.ts +2 -0
  333. package/dist/modules/raises/routes.d.ts.map +1 -1
  334. package/dist/modules/raises/routes.js +8 -1
  335. package/dist/modules/raises/routes.js.map +1 -1
  336. package/dist/modules/raises/schema.d.ts +34 -0
  337. package/dist/modules/raises/schema.d.ts.map +1 -1
  338. package/dist/modules/raises/schema.js +7 -2
  339. package/dist/modules/raises/schema.js.map +1 -1
  340. package/dist/modules/raises/service.d.ts.map +1 -1
  341. package/dist/modules/raises/service.js +2 -0
  342. package/dist/modules/raises/service.js.map +1 -1
  343. package/dist/modules/raises/tools.d.ts +2 -1
  344. package/dist/modules/raises/tools.d.ts.map +1 -1
  345. package/dist/modules/raises/tools.js +3 -1
  346. package/dist/modules/raises/tools.js.map +1 -1
  347. package/dist/modules/workspace/routes.d.ts +0 -2
  348. package/dist/modules/workspace/routes.d.ts.map +1 -1
  349. package/dist/modules/workspace/routes.js +0 -6
  350. package/dist/modules/workspace/routes.js.map +1 -1
  351. package/dist/modules/workspace/schema.d.ts +0 -34
  352. package/dist/modules/workspace/schema.d.ts.map +1 -1
  353. package/dist/modules/workspace/schema.js +0 -2
  354. package/dist/modules/workspace/schema.js.map +1 -1
  355. package/dist/modules/workspace/seedStarterForms.d.ts +17 -0
  356. package/dist/modules/workspace/seedStarterForms.d.ts.map +1 -0
  357. package/dist/modules/workspace/seedStarterForms.js +71 -0
  358. package/dist/modules/workspace/seedStarterForms.js.map +1 -0
  359. package/dist/modules/workspace/service.d.ts +0 -4
  360. package/dist/modules/workspace/service.d.ts.map +1 -1
  361. package/dist/modules/workspace/service.js +20 -10
  362. package/dist/modules/workspace/service.js.map +1 -1
  363. package/dist/modules/workspace/tools.js +1 -1
  364. package/dist/modules/workspace/tools.js.map +1 -1
  365. package/dist/runtime/module.d.ts +63 -1
  366. package/dist/runtime/module.d.ts.map +1 -1
  367. package/dist/runtime/registry.d.ts.map +1 -1
  368. package/dist/runtime/registry.js +40 -2
  369. package/dist/runtime/registry.js.map +1 -1
  370. package/dist/testing/fixtures.d.ts.map +1 -1
  371. package/dist/testing/fixtures.js +1 -0
  372. package/dist/testing/fixtures.js.map +1 -1
  373. package/migrations/0037_drop_lists_consent_purpose_id.sql +2 -0
  374. package/migrations/0038_smart_white_queen.sql +2 -0
  375. package/migrations/0039_form_map_to_open.sql +1 -0
  376. package/migrations/0040_pipeline_converted_to.sql +20 -0
  377. package/migrations/0041_api_key_scopes.sql +1 -0
  378. package/migrations/0042_drop_workspace_identity.sql +2 -0
  379. package/migrations/0043_external_sign_in.sql +2 -0
  380. package/migrations/meta/0038_snapshot.json +6554 -0
  381. package/migrations/meta/_journal.json +49 -0
  382. package/package.json +2 -2
  383. package/src/app.ts +3 -0
  384. package/src/index.ts +13 -1
  385. package/src/lib/actor.ts +3 -1
  386. package/src/lib/apiKeyScopes.ts +213 -0
  387. package/src/lib/errors.ts +30 -0
  388. package/src/modules/activities/repository.ts +24 -0
  389. package/src/modules/agent-tasks/repository.ts +24 -0
  390. package/src/modules/api-keys/routes.ts +5 -0
  391. package/src/modules/api-keys/schema.ts +2 -0
  392. package/src/modules/api-keys/scopeMiddleware.ts +30 -0
  393. package/src/modules/api-keys/service.ts +36 -2
  394. package/src/modules/auth/credentials.ts +4 -0
  395. package/src/modules/auth/index.ts +25 -4
  396. package/src/modules/auth/repository.ts +2 -1
  397. package/src/modules/auth/routes.ts +2 -8
  398. package/src/modules/auth/schema.ts +12 -1
  399. package/src/modules/auth/service.ts +143 -6
  400. package/src/modules/auth/session.ts +14 -0
  401. package/src/modules/consent-purposes/index.ts +1 -1
  402. package/src/modules/consent-purposes/schema.ts +3 -3
  403. package/src/modules/consent-purposes/service.ts +7 -16
  404. package/src/modules/consent-purposes/starters.ts +1 -1
  405. package/src/modules/consent-purposes/tools.ts +1 -1
  406. package/src/modules/conversions/clearPointers.ts +81 -0
  407. package/src/modules/conversions/factory.ts +20 -0
  408. package/src/modules/conversions/fieldMap.ts +548 -0
  409. package/src/modules/conversions/index.ts +6 -0
  410. package/src/modules/conversions/mcp.ts +71 -0
  411. package/src/modules/conversions/repoint.ts +146 -0
  412. package/src/modules/conversions/routes.ts +68 -0
  413. package/src/modules/conversions/service.ts +310 -0
  414. package/src/modules/conversions/wire.ts +42 -0
  415. package/src/modules/deals/events.ts +9 -0
  416. package/src/modules/deals/index.ts +4 -2
  417. package/src/modules/deals/routes.ts +11 -1
  418. package/src/modules/deals/schema.ts +10 -2
  419. package/src/modules/deals/service.ts +3 -0
  420. package/src/modules/deals/tools.ts +9 -1
  421. package/src/modules/decisions/repository.ts +23 -1
  422. package/src/modules/enquiries/events.ts +8 -2
  423. package/src/modules/enquiries/index.ts +4 -2
  424. package/src/modules/enquiries/routes.ts +11 -13
  425. package/src/modules/enquiries/schema.ts +12 -3
  426. package/src/modules/enquiries/service.ts +3 -150
  427. package/src/modules/enquiries/tools.ts +9 -18
  428. package/src/modules/forms/applyMappedFields.ts +248 -0
  429. package/src/modules/forms/applySubmissionFields.ts +435 -0
  430. package/src/modules/forms/fields.ts +31 -7
  431. package/src/modules/forms/mapping.ts +20 -3
  432. package/src/modules/forms/repository.ts +0 -7
  433. package/src/modules/forms/routes.ts +1 -2
  434. package/src/modules/forms/schema.ts +0 -2
  435. package/src/modules/forms/service.ts +31 -4
  436. package/src/modules/forms/starters.ts +129 -0
  437. package/src/modules/forms/submission.ts +135 -69
  438. package/src/modules/import-export/customFieldCsv.ts +55 -0
  439. package/src/modules/import-export/customFieldImport.ts +111 -0
  440. package/src/modules/import-export/drafts.ts +151 -3
  441. package/src/modules/import-export/exportRows.ts +222 -68
  442. package/src/modules/import-export/plan.ts +321 -67
  443. package/src/modules/import-export/repository.ts +356 -14
  444. package/src/modules/import-export/routes.ts +8 -8
  445. package/src/modules/import-export/service.ts +208 -45
  446. package/src/modules/import-export/streams.ts +95 -13
  447. package/src/modules/import-export/tools.ts +14 -6
  448. package/src/modules/import-export/validation.ts +128 -0
  449. package/src/modules/import-export/writes.ts +559 -27
  450. package/src/modules/lists/repository.ts +0 -2
  451. package/src/modules/lists/routes.ts +0 -8
  452. package/src/modules/lists/schema.ts +0 -10
  453. package/src/modules/lists/service.ts +9 -107
  454. package/src/modules/lists/starters.ts +16 -0
  455. package/src/modules/mcp/protocol.ts +18 -0
  456. package/src/modules/notes/repository.ts +24 -0
  457. package/src/modules/opportunities/events.ts +9 -0
  458. package/src/modules/opportunities/index.ts +4 -2
  459. package/src/modules/opportunities/routes.ts +11 -1
  460. package/src/modules/opportunities/schema.ts +10 -2
  461. package/src/modules/opportunities/service.ts +3 -0
  462. package/src/modules/opportunities/tools.ts +9 -1
  463. package/src/modules/partnerships/events.ts +9 -0
  464. package/src/modules/partnerships/index.ts +4 -2
  465. package/src/modules/partnerships/routes.ts +11 -1
  466. package/src/modules/partnerships/schema.ts +10 -2
  467. package/src/modules/partnerships/service.ts +3 -0
  468. package/src/modules/partnerships/tools.ts +9 -1
  469. package/src/modules/people/personConsentWrites.ts +1 -1
  470. package/src/modules/people/schema.ts +1 -1
  471. package/src/modules/plans/repository.ts +24 -0
  472. package/src/modules/raises/events.ts +9 -0
  473. package/src/modules/raises/index.ts +4 -2
  474. package/src/modules/raises/routes.ts +11 -1
  475. package/src/modules/raises/schema.ts +10 -2
  476. package/src/modules/raises/service.ts +3 -0
  477. package/src/modules/raises/tools.ts +9 -1
  478. package/src/modules/workspace/routes.ts +0 -6
  479. package/src/modules/workspace/schema.ts +0 -2
  480. package/src/modules/workspace/seedStarterForms.ts +98 -0
  481. package/src/modules/workspace/service.ts +23 -15
  482. package/src/modules/workspace/tools.ts +1 -1
  483. package/src/runtime/module.ts +70 -1
  484. package/src/runtime/registry.ts +54 -0
  485. package/src/testing/fixtures.ts +1 -0
@@ -0,0 +1,146 @@
1
+ import { PIPELINE_KINDS } from '@kelpie/schemas'
2
+ import type { PipelineKind } from '@kelpie/schemas'
3
+ import { and, eq } from 'drizzle-orm'
4
+
5
+ import type { Queryable } from '../../runtime/transaction.ts'
6
+ import * as activityRepository from '../activities/repository.ts'
7
+ import * as agentRunRepository from '../agent-tasks/repository.ts'
8
+ import * as decisionRepository from '../decisions/repository.ts'
9
+ import { formAttachTargets } from '../forms/schema.ts'
10
+ import * as listRepository from '../lists/repository.ts'
11
+ import * as noteRepository from '../notes/repository.ts'
12
+ import * as planRepository from '../plans/repository.ts'
13
+
14
+ /**
15
+ * The polymorphic repoint rule: mirror of `deleteRecordsAttachedTo`, used when
16
+ * a pipeline record converts to another type and its history should follow the
17
+ * new record while the source stays in place.
18
+ */
19
+
20
+ export interface PipelineTargetRef {
21
+ readonly targetType: PipelineKind
22
+ readonly targetId: string
23
+ }
24
+
25
+ /**
26
+ * @param db Must be the caller's transaction.
27
+ * @returns How many rows were repointed or removed, for the caller's activity trail.
28
+ */
29
+ export async function repointRecordsAttachedTo(
30
+ db: Queryable,
31
+ workspaceId: string,
32
+ from: PipelineTargetRef,
33
+ to: PipelineTargetRef,
34
+ ): Promise<number> {
35
+ const fromType = from.targetType
36
+ const fromId = from.targetId
37
+ const toType = to.targetType
38
+ const toId = to.targetId
39
+
40
+ const notes = await noteRepository.repointForTarget(
41
+ db,
42
+ workspaceId,
43
+ fromType,
44
+ fromId,
45
+ toType,
46
+ toId,
47
+ )
48
+ const activities = await activityRepository.repointForTarget(
49
+ db,
50
+ workspaceId,
51
+ fromType,
52
+ fromId,
53
+ toType,
54
+ toId,
55
+ )
56
+ const decisions = await decisionRepository.repointForTarget(
57
+ db,
58
+ workspaceId,
59
+ fromType,
60
+ fromId,
61
+ toType,
62
+ toId,
63
+ )
64
+ const plans = await planRepository.repointForTarget(
65
+ db,
66
+ workspaceId,
67
+ fromType,
68
+ fromId,
69
+ toType,
70
+ toId,
71
+ )
72
+ const agentRuns = await agentRunRepository.repointForTarget(
73
+ db,
74
+ workspaceId,
75
+ fromType,
76
+ fromId,
77
+ toType,
78
+ toId,
79
+ )
80
+ const attachTargets = await repointFormAttachTargets(
81
+ db,
82
+ workspaceId,
83
+ fromType,
84
+ fromId,
85
+ toType,
86
+ toId,
87
+ )
88
+ const memberships = await listRepository.deleteMembershipsForTarget(
89
+ db,
90
+ workspaceId,
91
+ fromType,
92
+ fromId,
93
+ )
94
+
95
+ return notes + activities + decisions + plans + agentRuns + attachTargets + memberships
96
+ }
97
+
98
+ async function repointFormAttachTargets(
99
+ db: Queryable,
100
+ workspaceId: string,
101
+ fromType: PipelineKind,
102
+ fromId: string,
103
+ toType: PipelineKind,
104
+ toId: string,
105
+ ): Promise<number> {
106
+ const held = await db
107
+ .select({ formId: formAttachTargets.formId })
108
+ .from(formAttachTargets)
109
+ .where(
110
+ and(
111
+ eq(formAttachTargets.workspaceId, workspaceId),
112
+ eq(formAttachTargets.targetType, fromType),
113
+ eq(formAttachTargets.targetId, fromId),
114
+ ),
115
+ )
116
+
117
+ if (held.length === 0) {
118
+ return 0
119
+ }
120
+
121
+ await db
122
+ .delete(formAttachTargets)
123
+ .where(
124
+ and(
125
+ eq(formAttachTargets.workspaceId, workspaceId),
126
+ eq(formAttachTargets.targetType, fromType),
127
+ eq(formAttachTargets.targetId, fromId),
128
+ ),
129
+ )
130
+
131
+ await db.insert(formAttachTargets).values(
132
+ held.map((row: { formId: string }) => ({
133
+ workspaceId,
134
+ formId: row.formId,
135
+ targetType: toType,
136
+ targetId: toId,
137
+ })),
138
+ )
139
+
140
+ return held.length
141
+ }
142
+
143
+ /** Whether a pipeline kind is one of the five convertible types. */
144
+ export function isPipelineKind(value: string): value is PipelineKind {
145
+ return (PIPELINE_KINDS as readonly string[]).includes(value)
146
+ }
@@ -0,0 +1,68 @@
1
+ import type { ConvertPipelineRecordInput, PipelineKind } from '@kelpie/schemas'
2
+ import type { Context, Hono } from 'hono'
3
+ import type { z } from 'zod'
4
+
5
+ import { readJsonBody } from '../../lib/http.ts'
6
+ import type { Actor } from '../auth/actor.ts'
7
+ import { resolveActorFrom } from '../auth/credentials.ts'
8
+ import type { CredentialDependencies } from '../auth/credentials.ts'
9
+ import type { ConversionsService } from './service.ts'
10
+ import { renderConvertedPipelineRecord } from './wire.ts'
11
+
12
+ export interface ConvertRouteDependencies extends CredentialDependencies {
13
+ readonly conversions: ConversionsService
14
+ readonly sourceKind: PipelineKind
15
+ readonly bodySchema: z.ZodType<{
16
+ target_type: PipelineKind
17
+ stage_id?: string | undefined
18
+ company_id?: string | undefined
19
+ kind?: string | undefined
20
+ name?: string | undefined
21
+ }>
22
+ readonly renderTarget?: (
23
+ targetKind: PipelineKind,
24
+ target: unknown,
25
+ personIds: readonly string[],
26
+ ) => Record<string, unknown>
27
+ }
28
+
29
+ export function toConvertInput(body: {
30
+ target_type: PipelineKind
31
+ stage_id?: string | undefined
32
+ company_id?: string | undefined
33
+ kind?: string | undefined
34
+ name?: string | undefined
35
+ }): ConvertPipelineRecordInput {
36
+ return {
37
+ targetType: body.target_type,
38
+ stageId: body.stage_id,
39
+ companyId: body.company_id,
40
+ kind: body.kind,
41
+ name: body.name,
42
+ }
43
+ }
44
+
45
+ export function mountPipelineConvertRoute(
46
+ router: Hono,
47
+ path: string,
48
+ dependencies: ConvertRouteDependencies,
49
+ ): void {
50
+ const requireActor = (context: Context): Promise<Actor> => resolveActorFrom(dependencies, context)
51
+
52
+ router.post(path, async (context) => {
53
+ const id = context.req.param('id')!
54
+
55
+ const body = await readJsonBody(context, dependencies.bodySchema)
56
+ const { targetKind, target, personIds } = await dependencies.conversions.convert(
57
+ await requireActor(context),
58
+ dependencies.sourceKind,
59
+ id,
60
+ toConvertInput(body),
61
+ )
62
+
63
+ const render =
64
+ dependencies.renderTarget ?? ((kind, record, ids) => renderConvertedPipelineRecord(kind, record, ids))
65
+
66
+ return context.json(render(targetKind, target, personIds), 201)
67
+ })
68
+ }
@@ -0,0 +1,310 @@
1
+ import type { ConvertPipelineRecordInput, PipelineKind } from '@kelpie/schemas'
2
+
3
+ import { toEventActor } from '../../lib/actor.ts'
4
+ import type { Actor } from '../auth/actor.ts'
5
+ import { requireWorkspaceId } from '../auth/actor.ts'
6
+ import { AppError } from '../../lib/errors.ts'
7
+ import type { Database } from '../../lib/database.ts'
8
+ import type { IdFactory } from '../../lib/ids.ts'
9
+ import type { TransactionScope } from '../../runtime/transaction.ts'
10
+ import type { EventName } from '../../runtime/events.ts'
11
+ import type { ActivityRecorder } from '../activities/recorder.ts'
12
+ import {
13
+ describeConversion,
14
+ describeCreationFrom,
15
+ describeStageChange,
16
+ } from '../activities/wording.ts'
17
+ import type { CustomFieldValuesValidator } from '../custom-fields/values.ts'
18
+ import * as personLinks from '../personLinks.ts'
19
+ import * as pipelineRepository from '../pipelines/repository.ts'
20
+ import {
21
+ assertNotAlreadyConverted,
22
+ buildTargetInsertPayload,
23
+ insertConvertedTarget,
24
+ intersectCustomFields,
25
+ loadPipelineSnapshot,
26
+ markSourceConverted,
27
+ objectLabelFor,
28
+ type ConvertedTargetRecord,
29
+ } from './fieldMap.ts'
30
+ import { repointRecordsAttachedTo } from './repoint.ts'
31
+
32
+ export interface ConversionsDependencies {
33
+ readonly db: Database
34
+ readonly transaction: TransactionScope
35
+ readonly createId: IdFactory
36
+ readonly now: () => Date
37
+ readonly recordActivity: ActivityRecorder
38
+ readonly customFields: CustomFieldValuesValidator
39
+ }
40
+
41
+ export interface ConvertPipelineRecordResult {
42
+ readonly targetKind: PipelineKind
43
+ readonly target: ConvertedTargetRecord
44
+ readonly personIds: readonly string[]
45
+ }
46
+
47
+ export interface ConversionsService {
48
+ convert(
49
+ actor: Actor,
50
+ sourceKind: PipelineKind,
51
+ sourceId: string,
52
+ body: ConvertPipelineRecordInput,
53
+ ): Promise<ConvertPipelineRecordResult>
54
+ }
55
+
56
+ function conversionEventName(sourceKind: PipelineKind): EventName {
57
+ switch (sourceKind) {
58
+ case 'enquiry':
59
+ return 'enquiries.enquiry.converted'
60
+ case 'deal':
61
+ return 'deals.deal.converted'
62
+ case 'opportunity':
63
+ return 'opportunities.opportunity.converted'
64
+ case 'raise':
65
+ return 'raises.raise.converted'
66
+ case 'partnership':
67
+ return 'partnerships.partnership.converted'
68
+ }
69
+ }
70
+
71
+ function createdEventName(targetKind: PipelineKind): EventName {
72
+ switch (targetKind) {
73
+ case 'enquiry':
74
+ return 'enquiries.enquiry.created'
75
+ case 'deal':
76
+ return 'deals.deal.created'
77
+ case 'opportunity':
78
+ return 'opportunities.opportunity.created'
79
+ case 'raise':
80
+ return 'raises.raise.created'
81
+ case 'partnership':
82
+ return 'partnerships.partnership.created'
83
+ }
84
+ }
85
+
86
+ function updatedEventName(sourceKind: PipelineKind): EventName {
87
+ switch (sourceKind) {
88
+ case 'enquiry':
89
+ return 'enquiries.enquiry.updated'
90
+ case 'deal':
91
+ return 'deals.deal.updated'
92
+ case 'opportunity':
93
+ return 'opportunities.opportunity.updated'
94
+ case 'raise':
95
+ return 'raises.raise.updated'
96
+ case 'partnership':
97
+ return 'partnerships.partnership.updated'
98
+ }
99
+ }
100
+
101
+ function stageChangedEventName(sourceKind: PipelineKind): EventName {
102
+ switch (sourceKind) {
103
+ case 'enquiry':
104
+ return 'enquiries.enquiry.stage_changed'
105
+ case 'deal':
106
+ return 'deals.deal.stage_changed'
107
+ case 'opportunity':
108
+ return 'opportunities.opportunity.stage_changed'
109
+ case 'raise':
110
+ return 'raises.raise.stage_changed'
111
+ case 'partnership':
112
+ return 'partnerships.partnership.stage_changed'
113
+ }
114
+ }
115
+
116
+ function targetEventType(kind: PipelineKind): string {
117
+ switch (kind) {
118
+ case 'enquiry':
119
+ return 'enquiry'
120
+ case 'deal':
121
+ return 'deal'
122
+ case 'opportunity':
123
+ return 'opportunity'
124
+ case 'raise':
125
+ return 'raise'
126
+ case 'partnership':
127
+ return 'partnership'
128
+ }
129
+ }
130
+
131
+ export function createConversionsService(dependencies: ConversionsDependencies): ConversionsService {
132
+ return {
133
+ async convert(actor, sourceKind, sourceId, body) {
134
+ const workspaceId = requireWorkspaceId(actor)
135
+ const targetKind = body.targetType
136
+
137
+ if (sourceKind === targetKind) {
138
+ throw AppError.validationFailed('Choose a different target type to convert into', [
139
+ { field: 'target_type', message: `Already a ${objectLabelFor(sourceKind)}` },
140
+ ])
141
+ }
142
+
143
+ const source = await loadPipelineSnapshot(dependencies.db, workspaceId, sourceKind, sourceId)
144
+
145
+ if (source === undefined) {
146
+ throw AppError.notFound(`${objectLabelFor(sourceKind)} not found`)
147
+ }
148
+
149
+ assertNotAlreadyConverted(source)
150
+
151
+ const targetStages = await pipelineRepository.listStagesOfKind(
152
+ dependencies.db,
153
+ workspaceId,
154
+ targetKind,
155
+ )
156
+ const openTargetStage = targetStages.find((row) => row.open) ?? targetStages[0]
157
+
158
+ if (openTargetStage === undefined) {
159
+ throw AppError.conflict(`This workspace has no ${objectLabelFor(targetKind).toLowerCase()} stages`)
160
+ }
161
+
162
+ if (body.stageId !== undefined) {
163
+ const chosen = targetStages.find((row) => row.id === body.stageId)
164
+
165
+ if (chosen === undefined) {
166
+ throw AppError.validationFailed('Stage not found for this target type', [
167
+ { field: 'stage_id', message: body.stageId },
168
+ ])
169
+ }
170
+ }
171
+
172
+ const sourceStages = await pipelineRepository.listStagesOfKind(
173
+ dependencies.db,
174
+ workspaceId,
175
+ sourceKind,
176
+ )
177
+ const closedSourceStage = sourceStages.find((row) => !row.open)
178
+ const currentSourceStage = sourceStages.find((row) => row.id === source.stageId)
179
+
180
+ const personIds = await personLinks.listPersonIds(dependencies.db, workspaceId, {
181
+ targetType: sourceKind,
182
+ targetId: sourceId,
183
+ })
184
+ const targetId = dependencies.createId(targetKind)
185
+ const now = dependencies.now()
186
+ const sourceLabel = objectLabelFor(sourceKind)
187
+ const targetLabel = objectLabelFor(targetKind)
188
+
189
+ return dependencies.transaction(async ({ tx, events }) => {
190
+ const payload = buildTargetInsertPayload(
191
+ source,
192
+ targetKind,
193
+ body,
194
+ openTargetStage.id,
195
+ )
196
+ const customFields = await intersectCustomFields(
197
+ tx,
198
+ workspaceId,
199
+ targetKind,
200
+ source.customFields,
201
+ dependencies.customFields,
202
+ )
203
+ const target = await insertConvertedTarget(
204
+ tx,
205
+ workspaceId,
206
+ targetKind,
207
+ targetId,
208
+ payload,
209
+ customFields,
210
+ now,
211
+ )
212
+
213
+ await personLinks.linkPeople(
214
+ tx,
215
+ dependencies.createId,
216
+ workspaceId,
217
+ { targetType: targetKind, targetId },
218
+ personIds,
219
+ )
220
+
221
+ await repointRecordsAttachedTo(
222
+ tx,
223
+ workspaceId,
224
+ { targetType: sourceKind, targetId: sourceId },
225
+ { targetType: targetKind, targetId },
226
+ )
227
+
228
+ const stageChanged =
229
+ closedSourceStage !== undefined && closedSourceStage.id !== source.stageId
230
+
231
+ await markSourceConverted(
232
+ tx,
233
+ workspaceId,
234
+ source,
235
+ targetKind,
236
+ targetId,
237
+ stageChanged ? closedSourceStage.id : undefined,
238
+ now,
239
+ )
240
+
241
+ await dependencies.recordActivity(tx, workspaceId, actor, {
242
+ targetType: targetKind,
243
+ targetId,
244
+ kind: 'created',
245
+ ...describeCreationFrom(targetLabel, sourceLabel, source.name),
246
+ })
247
+
248
+ await dependencies.recordActivity(tx, workspaceId, actor, {
249
+ targetType: sourceKind,
250
+ targetId: sourceId,
251
+ kind: 'updated',
252
+ ...describeConversion(targetLabel, payload.name),
253
+ })
254
+
255
+ if (stageChanged && currentSourceStage !== undefined) {
256
+ await dependencies.recordActivity(tx, workspaceId, actor, {
257
+ targetType: sourceKind,
258
+ targetId: sourceId,
259
+ kind: 'stage_changed',
260
+ ...describeStageChange(currentSourceStage.label, closedSourceStage.label),
261
+ })
262
+ }
263
+
264
+ events.emit(createdEventName(targetKind), { type: targetEventType(targetKind), id: targetId }, {})
265
+
266
+ const sourceChanged: string[] = stageChanged
267
+ ? ['convertedTargetType', 'convertedTargetId', 'stageId']
268
+ : ['convertedTargetType', 'convertedTargetId']
269
+
270
+ if (source.kind === 'enquiry' && targetKind === 'deal') {
271
+ sourceChanged.push('convertedDealId')
272
+ }
273
+
274
+ events.emit(
275
+ updatedEventName(sourceKind),
276
+ { type: targetEventType(sourceKind), id: sourceId },
277
+ { changed: sourceChanged },
278
+ )
279
+
280
+ if (stageChanged && currentSourceStage !== undefined) {
281
+ events.emit(
282
+ stageChangedEventName(sourceKind),
283
+ { type: targetEventType(sourceKind), id: sourceId },
284
+ { fromStageId: currentSourceStage.id, toStageId: closedSourceStage.id },
285
+ )
286
+ }
287
+
288
+ const conversionPayload =
289
+ sourceKind === 'enquiry' && targetKind === 'deal'
290
+ ? { dealId: targetId, targetType: targetKind, targetId }
291
+ : { targetType: targetKind, targetId }
292
+
293
+ events.emit(
294
+ conversionEventName(sourceKind),
295
+ { type: targetEventType(sourceKind), id: sourceId },
296
+ conversionPayload,
297
+ )
298
+
299
+ return { targetKind, target, personIds }
300
+ }, { workspaceId, actor: toEventActor(actor) })
301
+ },
302
+ }
303
+ }
304
+
305
+ /** Factory helper shared by pipeline modules. */
306
+ export function createSharedConversionsService(
307
+ dependencies: ConversionsDependencies,
308
+ ): ConversionsService {
309
+ return createConversionsService(dependencies)
310
+ }
@@ -0,0 +1,42 @@
1
+ import type { PipelineKind } from '@kelpie/schemas'
2
+
3
+ import { dealResponse } from '../deals/routes.ts'
4
+ import type { DealRecord } from '../deals/repository.ts'
5
+ import { enquiryResponse } from '../enquiries/routes.ts'
6
+ import type { EnquiryRecord } from '../enquiries/repository.ts'
7
+ import { opportunityResponse } from '../opportunities/routes.ts'
8
+ import type { OpportunityRecord } from '../opportunities/repository.ts'
9
+ import { partnershipResponse } from '../partnerships/routes.ts'
10
+ import type { PartnershipRecord } from '../partnerships/repository.ts'
11
+ import { raiseResponse } from '../raises/routes.ts'
12
+ import type { RaiseRecord } from '../raises/repository.ts'
13
+
14
+ /** Wire-shape a freshly converted pipeline record for any target type. */
15
+ export function renderConvertedPipelineRecord(
16
+ targetKind: PipelineKind,
17
+ target: unknown,
18
+ personIds: readonly string[],
19
+ ): Record<string, unknown> {
20
+ const { workspaceId: _workspaceId, ...record } = target as {
21
+ workspaceId: string
22
+ }
23
+
24
+ switch (targetKind) {
25
+ case 'enquiry':
26
+ return enquiryResponse({ ...(record as Omit<EnquiryRecord, 'workspaceId'>), personIds })
27
+ case 'deal':
28
+ return dealResponse({ ...(record as Omit<DealRecord, 'workspaceId'>), personIds })
29
+ case 'opportunity':
30
+ return opportunityResponse({
31
+ ...(record as Omit<OpportunityRecord, 'workspaceId'>),
32
+ personIds,
33
+ })
34
+ case 'raise':
35
+ return raiseResponse({ ...(record as Omit<RaiseRecord, 'workspaceId'>), personIds })
36
+ case 'partnership':
37
+ return partnershipResponse({
38
+ ...(record as Omit<PartnershipRecord, 'workspaceId'>),
39
+ personIds,
40
+ })
41
+ }
42
+ }
@@ -12,6 +12,10 @@ export const dealsEvents = {
12
12
  fromStageId: z.string().nullable(),
13
13
  toStageId: z.string(),
14
14
  }),
15
+ 'deals.deal.converted': z.object({
16
+ targetType: z.string(),
17
+ targetId: z.string(),
18
+ }),
15
19
  } satisfies ModuleEventCatalog
16
20
 
17
21
  export type DealCreatedData = Record<string, never>
@@ -23,6 +27,10 @@ export interface DealStageChangedData {
23
27
  readonly fromStageId: string | null
24
28
  readonly toStageId: string
25
29
  }
30
+ export interface DealConvertedData {
31
+ readonly targetType: string
32
+ readonly targetId: string
33
+ }
26
34
 
27
35
  declare module '../../runtime/events.ts' {
28
36
  interface KelpieEventMap {
@@ -30,5 +38,6 @@ declare module '../../runtime/events.ts' {
30
38
  'deals.deal.updated': DealUpdatedData
31
39
  'deals.deal.deleted': DealDeletedData
32
40
  'deals.deal.stage_changed': DealStageChangedData
41
+ 'deals.deal.converted': DealConvertedData
33
42
  }
34
43
  }
@@ -1,5 +1,6 @@
1
1
  import type { KelpieModule } from '../../runtime/module.ts'
2
2
  import { createActivityRecorder } from '../activities/index.ts'
3
+ import { createConversionsFromContext } from '../conversions/index.ts'
3
4
  import { createCustomFieldValues } from '../custom-fields/index.ts'
4
5
  import { dealsEvents } from './events.ts'
5
6
  import { mountDealsRoutes } from './routes.ts'
@@ -23,6 +24,7 @@ export function createDealsModule(migrationsDirectory: string): KelpieModule {
23
24
  events: dealsEvents,
24
25
 
25
26
  register(context) {
27
+ const conversions = createConversionsFromContext(context)
26
28
  const service = createDealsService({
27
29
  db: context.db,
28
30
  transaction: context.transaction,
@@ -38,10 +40,10 @@ export function createDealsModule(migrationsDirectory: string): KelpieModule {
38
40
  context.schema(schema, migrationsDirectory)
39
41
 
40
42
  context.routes((router) => {
41
- mountDealsRoutes(router, { db: context.db, now: context.now, service })
43
+ mountDealsRoutes(router, { db: context.db, now: context.now, service, conversions })
42
44
  })
43
45
 
44
- registerDealsTools(context.mcp, service)
46
+ registerDealsTools(context.mcp, service, conversions)
45
47
 
46
48
  return Promise.resolve()
47
49
  },
@@ -1,4 +1,4 @@
1
- import { customFieldsPatchShape } from '@kelpie/schemas'
1
+ import { convertPipelineRecordBody, convertedToResponse, customFieldsPatchShape } from '@kelpie/schemas'
2
2
  import type { Context, Hono } from 'hono'
3
3
  import { z } from 'zod'
4
4
 
@@ -8,6 +8,8 @@ import type { Actor } from '../auth/actor.ts'
8
8
  import { resolveActorFrom } from '../auth/credentials.ts'
9
9
  import type { CredentialDependencies } from '../auth/credentials.ts'
10
10
  import { renderCustomFieldsForWire } from '../custom-fields/wire.ts'
11
+ import { mountPipelineConvertRoute } from '../conversions/routes.ts'
12
+ import type { ConversionsService } from '../conversions/index.ts'
11
13
  import type { CreateDealInput, DealView, DealsService, UpdateDealInput } from './service.ts'
12
14
 
13
15
  /** Wire shapes for `/v1/deals`. Bodies are strict; an unknown field is a 422, per `api.md`. */
@@ -58,6 +60,7 @@ export const updateBody = z.strictObject(dealShape).partial()
58
60
 
59
61
  export interface DealsRoutesDependencies extends CredentialDependencies {
60
62
  readonly service: DealsService
63
+ readonly conversions: ConversionsService
61
64
  }
62
65
 
63
66
  export function toCreateInput(body: z.infer<typeof createBody>): CreateDealInput {
@@ -117,6 +120,7 @@ export function dealResponse(deal: DealView): Record<string, unknown> {
117
120
  summary: deal.summary,
118
121
  tags: deal.tags,
119
122
  external_id: deal.externalId,
123
+ converted_to: convertedToResponse(deal.convertedTargetType, deal.convertedTargetId),
120
124
  custom_fields: renderCustomFieldsForWire(deal.customFields),
121
125
  created_at: deal.createdAt.toISOString(),
122
126
  updated_at: deal.updatedAt.toISOString(),
@@ -170,4 +174,10 @@ export function mountDealsRoutes(router: Hono, dependencies: DealsRoutesDependen
170
174
 
171
175
  return context.body(null, 204)
172
176
  })
177
+
178
+ mountPipelineConvertRoute(router, '/deals/:id/convert', {
179
+ ...dependencies,
180
+ sourceKind: 'deal',
181
+ bodySchema: convertPipelineRecordBody,
182
+ })
173
183
  }
@@ -1,7 +1,9 @@
1
+ import { sql } from 'drizzle-orm'
2
+ import { check, bigint, date, index, jsonb, pgTable, text } from 'drizzle-orm/pg-core'
3
+ import { PIPELINE_KINDS } from '@kelpie/schemas'
1
4
  import type { CustomFieldValue } from '@kelpie/schemas'
2
- import { bigint, date, index, jsonb, pgTable, text } from 'drizzle-orm/pg-core'
3
5
 
4
- import { createdAt, primaryId, searchVector, updatedAt } from '../../lib/columns.ts'
6
+ import { createdAt, oneOf, primaryId, searchVector, updatedAt } from '../../lib/columns.ts'
5
7
  import type { SearchVectorPart } from '../../lib/columns.ts'
6
8
  import { companies } from '../companies/schema.ts'
7
9
  import { pipelineStages } from '../pipelines/schema.ts'
@@ -38,6 +40,8 @@ export const deals = pgTable(
38
40
  summary: text('summary').notNull().default(''),
39
41
  tags: text('tags').array().notNull().default([]),
40
42
  externalId: text('external_id'),
43
+ convertedTargetType: text('converted_target_type'),
44
+ convertedTargetId: text('converted_target_id'),
41
45
  // Workspace-defined fields, keyed by definition key. See people/schema.ts.
42
46
  customFields: jsonb('custom_fields')
43
47
  .$type<Readonly<Record<string, CustomFieldValue>>>()
@@ -59,6 +63,10 @@ export const deals = pgTable(
59
63
  index('deals_company_idx').on(table.companyId),
60
64
  index('deals_stage_idx').on(table.stageId),
61
65
  index('deals_search_idx').using('gin', table.searchVector),
66
+ check(
67
+ 'deals_converted_target_type_check',
68
+ sql`${table.convertedTargetType} is null or ${oneOf('deals_converted_target_type_check', table.convertedTargetType, PIPELINE_KINDS)}`,
69
+ ),
62
70
  ],
63
71
  )
64
72