@kelpie/server 0.10.0 → 0.11.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 (439) 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/lib/actor.d.ts +3 -1
  5. package/dist/lib/actor.d.ts.map +1 -1
  6. package/dist/lib/actor.js.map +1 -1
  7. package/dist/lib/apiKeyScopes.d.ts +8 -0
  8. package/dist/lib/apiKeyScopes.d.ts.map +1 -0
  9. package/dist/lib/apiKeyScopes.js +166 -0
  10. package/dist/lib/apiKeyScopes.js.map +1 -0
  11. package/dist/modules/activities/repository.d.ts +2 -0
  12. package/dist/modules/activities/repository.d.ts.map +1 -1
  13. package/dist/modules/activities/repository.js +9 -0
  14. package/dist/modules/activities/repository.js.map +1 -1
  15. package/dist/modules/agent-tasks/repository.d.ts +2 -0
  16. package/dist/modules/agent-tasks/repository.d.ts.map +1 -1
  17. package/dist/modules/agent-tasks/repository.js +9 -0
  18. package/dist/modules/agent-tasks/repository.js.map +1 -1
  19. package/dist/modules/api-keys/routes.d.ts.map +1 -1
  20. package/dist/modules/api-keys/routes.js +4 -1
  21. package/dist/modules/api-keys/routes.js.map +1 -1
  22. package/dist/modules/api-keys/schema.d.ts +43 -0
  23. package/dist/modules/api-keys/schema.d.ts.map +1 -1
  24. package/dist/modules/api-keys/schema.js +2 -0
  25. package/dist/modules/api-keys/schema.js.map +1 -1
  26. package/dist/modules/api-keys/scopeMiddleware.d.ts +8 -0
  27. package/dist/modules/api-keys/scopeMiddleware.d.ts.map +1 -0
  28. package/dist/modules/api-keys/scopeMiddleware.js +21 -0
  29. package/dist/modules/api-keys/scopeMiddleware.js.map +1 -0
  30. package/dist/modules/api-keys/service.d.ts +3 -1
  31. package/dist/modules/api-keys/service.d.ts.map +1 -1
  32. package/dist/modules/api-keys/service.js +26 -1
  33. package/dist/modules/api-keys/service.js.map +1 -1
  34. package/dist/modules/auth/credentials.d.ts.map +1 -1
  35. package/dist/modules/auth/credentials.js +2 -0
  36. package/dist/modules/auth/credentials.js.map +1 -1
  37. package/dist/modules/consent-purposes/index.d.ts +1 -1
  38. package/dist/modules/consent-purposes/index.js +1 -1
  39. package/dist/modules/consent-purposes/schema.d.ts +3 -3
  40. package/dist/modules/consent-purposes/schema.js +3 -3
  41. package/dist/modules/consent-purposes/service.d.ts +1 -1
  42. package/dist/modules/consent-purposes/service.d.ts.map +1 -1
  43. package/dist/modules/consent-purposes/service.js +7 -16
  44. package/dist/modules/consent-purposes/service.js.map +1 -1
  45. package/dist/modules/consent-purposes/starters.d.ts +1 -1
  46. package/dist/modules/consent-purposes/tools.js +1 -1
  47. package/dist/modules/consent-purposes/tools.js.map +1 -1
  48. package/dist/modules/conversions/clearPointers.d.ts +10 -0
  49. package/dist/modules/conversions/clearPointers.d.ts.map +1 -0
  50. package/dist/modules/conversions/clearPointers.js +40 -0
  51. package/dist/modules/conversions/clearPointers.js.map +1 -0
  52. package/dist/modules/conversions/factory.d.ts +5 -0
  53. package/dist/modules/conversions/factory.d.ts.map +1 -0
  54. package/dist/modules/conversions/factory.js +18 -0
  55. package/dist/modules/conversions/factory.js.map +1 -0
  56. package/dist/modules/conversions/fieldMap.d.ts +55 -0
  57. package/dist/modules/conversions/fieldMap.d.ts.map +1 -0
  58. package/dist/modules/conversions/fieldMap.js +398 -0
  59. package/dist/modules/conversions/fieldMap.js.map +1 -0
  60. package/dist/modules/conversions/index.d.ts +7 -0
  61. package/dist/modules/conversions/index.d.ts.map +1 -0
  62. package/dist/modules/conversions/index.js +6 -0
  63. package/dist/modules/conversions/index.js.map +1 -0
  64. package/dist/modules/conversions/mcp.d.ts +7 -0
  65. package/dist/modules/conversions/mcp.d.ts.map +1 -0
  66. package/dist/modules/conversions/mcp.js +47 -0
  67. package/dist/modules/conversions/mcp.js.map +1 -0
  68. package/dist/modules/conversions/repoint.d.ts +19 -0
  69. package/dist/modules/conversions/repoint.d.ts.map +1 -0
  70. package/dist/modules/conversions/repoint.js +51 -0
  71. package/dist/modules/conversions/repoint.js.map +1 -0
  72. package/dist/modules/conversions/routes.d.ts +26 -0
  73. package/dist/modules/conversions/routes.d.ts.map +1 -0
  74. package/dist/modules/conversions/routes.js +23 -0
  75. package/dist/modules/conversions/routes.js.map +1 -0
  76. package/dist/modules/conversions/service.d.ts +28 -0
  77. package/dist/modules/conversions/service.d.ts.map +1 -0
  78. package/dist/modules/conversions/service.js +170 -0
  79. package/dist/modules/conversions/service.js.map +1 -0
  80. package/dist/modules/conversions/wire.d.ts +4 -0
  81. package/dist/modules/conversions/wire.d.ts.map +1 -0
  82. package/dist/modules/conversions/wire.js +28 -0
  83. package/dist/modules/conversions/wire.js.map +1 -0
  84. package/dist/modules/deals/events.d.ts +9 -0
  85. package/dist/modules/deals/events.d.ts.map +1 -1
  86. package/dist/modules/deals/events.js +4 -0
  87. package/dist/modules/deals/events.js.map +1 -1
  88. package/dist/modules/deals/index.d.ts.map +1 -1
  89. package/dist/modules/deals/index.js +4 -2
  90. package/dist/modules/deals/index.js.map +1 -1
  91. package/dist/modules/deals/routes.d.ts +2 -0
  92. package/dist/modules/deals/routes.d.ts.map +1 -1
  93. package/dist/modules/deals/routes.js +8 -1
  94. package/dist/modules/deals/routes.js.map +1 -1
  95. package/dist/modules/deals/schema.d.ts +34 -0
  96. package/dist/modules/deals/schema.d.ts.map +1 -1
  97. package/dist/modules/deals/schema.js +7 -2
  98. package/dist/modules/deals/schema.js.map +1 -1
  99. package/dist/modules/deals/service.d.ts.map +1 -1
  100. package/dist/modules/deals/service.js +2 -0
  101. package/dist/modules/deals/service.js.map +1 -1
  102. package/dist/modules/deals/tools.d.ts +2 -1
  103. package/dist/modules/deals/tools.d.ts.map +1 -1
  104. package/dist/modules/deals/tools.js +3 -1
  105. package/dist/modules/deals/tools.js.map +1 -1
  106. package/dist/modules/decisions/repository.d.ts +2 -1
  107. package/dist/modules/decisions/repository.d.ts.map +1 -1
  108. package/dist/modules/decisions/repository.js +9 -1
  109. package/dist/modules/decisions/repository.js.map +1 -1
  110. package/dist/modules/enquiries/events.d.ts +6 -2
  111. package/dist/modules/enquiries/events.d.ts.map +1 -1
  112. package/dist/modules/enquiries/events.js +5 -1
  113. package/dist/modules/enquiries/events.js.map +1 -1
  114. package/dist/modules/enquiries/index.d.ts.map +1 -1
  115. package/dist/modules/enquiries/index.js +4 -2
  116. package/dist/modules/enquiries/index.js.map +1 -1
  117. package/dist/modules/enquiries/routes.d.ts +2 -0
  118. package/dist/modules/enquiries/routes.d.ts.map +1 -1
  119. package/dist/modules/enquiries/routes.js +9 -9
  120. package/dist/modules/enquiries/routes.js.map +1 -1
  121. package/dist/modules/enquiries/schema.d.ts +36 -1
  122. package/dist/modules/enquiries/schema.d.ts.map +1 -1
  123. package/dist/modules/enquiries/schema.js +9 -3
  124. package/dist/modules/enquiries/schema.js.map +1 -1
  125. package/dist/modules/enquiries/service.d.ts +0 -8
  126. package/dist/modules/enquiries/service.d.ts.map +1 -1
  127. package/dist/modules/enquiries/service.js +3 -95
  128. package/dist/modules/enquiries/service.js.map +1 -1
  129. package/dist/modules/enquiries/tools.d.ts +2 -1
  130. package/dist/modules/enquiries/tools.d.ts.map +1 -1
  131. package/dist/modules/enquiries/tools.js +4 -16
  132. package/dist/modules/enquiries/tools.js.map +1 -1
  133. package/dist/modules/forms/applyMappedFields.d.ts +20 -0
  134. package/dist/modules/forms/applyMappedFields.d.ts.map +1 -0
  135. package/dist/modules/forms/applyMappedFields.js +169 -0
  136. package/dist/modules/forms/applyMappedFields.js.map +1 -0
  137. package/dist/modules/forms/applySubmissionFields.d.ts +18 -0
  138. package/dist/modules/forms/applySubmissionFields.d.ts.map +1 -0
  139. package/dist/modules/forms/applySubmissionFields.js +230 -0
  140. package/dist/modules/forms/applySubmissionFields.js.map +1 -0
  141. package/dist/modules/forms/fields.d.ts +7 -2
  142. package/dist/modules/forms/fields.d.ts.map +1 -1
  143. package/dist/modules/forms/fields.js +17 -6
  144. package/dist/modules/forms/fields.js.map +1 -1
  145. package/dist/modules/forms/mapping.d.ts +8 -2
  146. package/dist/modules/forms/mapping.d.ts.map +1 -1
  147. package/dist/modules/forms/mapping.js +11 -0
  148. package/dist/modules/forms/mapping.js.map +1 -1
  149. package/dist/modules/forms/repository.d.ts +0 -5
  150. package/dist/modules/forms/repository.d.ts.map +1 -1
  151. package/dist/modules/forms/repository.js +0 -2
  152. package/dist/modules/forms/repository.js.map +1 -1
  153. package/dist/modules/forms/routes.d.ts +2 -30
  154. package/dist/modules/forms/routes.d.ts.map +1 -1
  155. package/dist/modules/forms/routes.js +2 -2
  156. package/dist/modules/forms/routes.js.map +1 -1
  157. package/dist/modules/forms/schema.d.ts.map +1 -1
  158. package/dist/modules/forms/schema.js +1 -2
  159. package/dist/modules/forms/schema.js.map +1 -1
  160. package/dist/modules/forms/service.d.ts.map +1 -1
  161. package/dist/modules/forms/service.js +18 -3
  162. package/dist/modules/forms/service.js.map +1 -1
  163. package/dist/modules/forms/starters.d.ts +31 -0
  164. package/dist/modules/forms/starters.d.ts.map +1 -0
  165. package/dist/modules/forms/starters.js +94 -0
  166. package/dist/modules/forms/starters.js.map +1 -0
  167. package/dist/modules/forms/submission.d.ts +1 -0
  168. package/dist/modules/forms/submission.d.ts.map +1 -1
  169. package/dist/modules/forms/submission.js +58 -37
  170. package/dist/modules/forms/submission.js.map +1 -1
  171. package/dist/modules/import-export/customFieldCsv.d.ts +9 -0
  172. package/dist/modules/import-export/customFieldCsv.d.ts.map +1 -0
  173. package/dist/modules/import-export/customFieldCsv.js +39 -0
  174. package/dist/modules/import-export/customFieldCsv.js.map +1 -0
  175. package/dist/modules/import-export/customFieldImport.d.ts +19 -0
  176. package/dist/modules/import-export/customFieldImport.d.ts.map +1 -0
  177. package/dist/modules/import-export/customFieldImport.js +76 -0
  178. package/dist/modules/import-export/customFieldImport.js.map +1 -0
  179. package/dist/modules/import-export/drafts.d.ts +57 -3
  180. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  181. package/dist/modules/import-export/drafts.js +65 -3
  182. package/dist/modules/import-export/drafts.js.map +1 -1
  183. package/dist/modules/import-export/exportRows.d.ts +15 -13
  184. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  185. package/dist/modules/import-export/exportRows.js +99 -26
  186. package/dist/modules/import-export/exportRows.js.map +1 -1
  187. package/dist/modules/import-export/plan.d.ts +42 -11
  188. package/dist/modules/import-export/plan.d.ts.map +1 -1
  189. package/dist/modules/import-export/plan.js +198 -56
  190. package/dist/modules/import-export/plan.js.map +1 -1
  191. package/dist/modules/import-export/repository.d.ts +58 -2
  192. package/dist/modules/import-export/repository.d.ts.map +1 -1
  193. package/dist/modules/import-export/repository.js +201 -12
  194. package/dist/modules/import-export/repository.js.map +1 -1
  195. package/dist/modules/import-export/routes.d.ts.map +1 -1
  196. package/dist/modules/import-export/routes.js +5 -5
  197. package/dist/modules/import-export/routes.js.map +1 -1
  198. package/dist/modules/import-export/service.d.ts +8 -3
  199. package/dist/modules/import-export/service.d.ts.map +1 -1
  200. package/dist/modules/import-export/service.js +133 -40
  201. package/dist/modules/import-export/service.js.map +1 -1
  202. package/dist/modules/import-export/streams.d.ts +2 -2
  203. package/dist/modules/import-export/streams.d.ts.map +1 -1
  204. package/dist/modules/import-export/streams.js +50 -9
  205. package/dist/modules/import-export/streams.js.map +1 -1
  206. package/dist/modules/import-export/tools.d.ts.map +1 -1
  207. package/dist/modules/import-export/tools.js +13 -7
  208. package/dist/modules/import-export/tools.js.map +1 -1
  209. package/dist/modules/import-export/validation.d.ts +5 -1
  210. package/dist/modules/import-export/validation.d.ts.map +1 -1
  211. package/dist/modules/import-export/validation.js +89 -2
  212. package/dist/modules/import-export/validation.js.map +1 -1
  213. package/dist/modules/import-export/writes.d.ts +2 -1
  214. package/dist/modules/import-export/writes.d.ts.map +1 -1
  215. package/dist/modules/import-export/writes.js +358 -25
  216. package/dist/modules/import-export/writes.js.map +1 -1
  217. package/dist/modules/lists/repository.d.ts +0 -1
  218. package/dist/modules/lists/repository.d.ts.map +1 -1
  219. package/dist/modules/lists/repository.js +0 -1
  220. package/dist/modules/lists/repository.js.map +1 -1
  221. package/dist/modules/lists/routes.d.ts +0 -2
  222. package/dist/modules/lists/routes.d.ts.map +1 -1
  223. package/dist/modules/lists/routes.js +0 -8
  224. package/dist/modules/lists/routes.js.map +1 -1
  225. package/dist/modules/lists/schema.d.ts +0 -17
  226. package/dist/modules/lists/schema.d.ts.map +1 -1
  227. package/dist/modules/lists/schema.js +0 -10
  228. package/dist/modules/lists/schema.js.map +1 -1
  229. package/dist/modules/lists/service.d.ts +2 -14
  230. package/dist/modules/lists/service.d.ts.map +1 -1
  231. package/dist/modules/lists/service.js +7 -53
  232. package/dist/modules/lists/service.js.map +1 -1
  233. package/dist/modules/lists/starters.d.ts +12 -0
  234. package/dist/modules/lists/starters.d.ts.map +1 -0
  235. package/dist/modules/lists/starters.js +4 -0
  236. package/dist/modules/lists/starters.js.map +1 -0
  237. package/dist/modules/mcp/protocol.d.ts.map +1 -1
  238. package/dist/modules/mcp/protocol.js +13 -0
  239. package/dist/modules/mcp/protocol.js.map +1 -1
  240. package/dist/modules/notes/repository.d.ts +2 -0
  241. package/dist/modules/notes/repository.d.ts.map +1 -1
  242. package/dist/modules/notes/repository.js +9 -0
  243. package/dist/modules/notes/repository.js.map +1 -1
  244. package/dist/modules/opportunities/events.d.ts +9 -0
  245. package/dist/modules/opportunities/events.d.ts.map +1 -1
  246. package/dist/modules/opportunities/events.js +4 -0
  247. package/dist/modules/opportunities/events.js.map +1 -1
  248. package/dist/modules/opportunities/index.d.ts.map +1 -1
  249. package/dist/modules/opportunities/index.js +4 -2
  250. package/dist/modules/opportunities/index.js.map +1 -1
  251. package/dist/modules/opportunities/routes.d.ts +2 -0
  252. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  253. package/dist/modules/opportunities/routes.js +8 -1
  254. package/dist/modules/opportunities/routes.js.map +1 -1
  255. package/dist/modules/opportunities/schema.d.ts +34 -0
  256. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  257. package/dist/modules/opportunities/schema.js +7 -2
  258. package/dist/modules/opportunities/schema.js.map +1 -1
  259. package/dist/modules/opportunities/service.d.ts.map +1 -1
  260. package/dist/modules/opportunities/service.js +2 -0
  261. package/dist/modules/opportunities/service.js.map +1 -1
  262. package/dist/modules/opportunities/tools.d.ts +2 -1
  263. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  264. package/dist/modules/opportunities/tools.js +3 -1
  265. package/dist/modules/opportunities/tools.js.map +1 -1
  266. package/dist/modules/partnerships/events.d.ts +9 -0
  267. package/dist/modules/partnerships/events.d.ts.map +1 -1
  268. package/dist/modules/partnerships/events.js +4 -0
  269. package/dist/modules/partnerships/events.js.map +1 -1
  270. package/dist/modules/partnerships/index.d.ts.map +1 -1
  271. package/dist/modules/partnerships/index.js +4 -2
  272. package/dist/modules/partnerships/index.js.map +1 -1
  273. package/dist/modules/partnerships/routes.d.ts +2 -0
  274. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  275. package/dist/modules/partnerships/routes.js +8 -1
  276. package/dist/modules/partnerships/routes.js.map +1 -1
  277. package/dist/modules/partnerships/schema.d.ts +34 -0
  278. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  279. package/dist/modules/partnerships/schema.js +7 -2
  280. package/dist/modules/partnerships/schema.js.map +1 -1
  281. package/dist/modules/partnerships/service.d.ts.map +1 -1
  282. package/dist/modules/partnerships/service.js +2 -0
  283. package/dist/modules/partnerships/service.js.map +1 -1
  284. package/dist/modules/partnerships/tools.d.ts +2 -1
  285. package/dist/modules/partnerships/tools.d.ts.map +1 -1
  286. package/dist/modules/partnerships/tools.js +3 -1
  287. package/dist/modules/partnerships/tools.js.map +1 -1
  288. package/dist/modules/people/personConsentWrites.d.ts +1 -1
  289. package/dist/modules/people/schema.js +1 -1
  290. package/dist/modules/people/schema.js.map +1 -1
  291. package/dist/modules/plans/repository.d.ts +2 -0
  292. package/dist/modules/plans/repository.d.ts.map +1 -1
  293. package/dist/modules/plans/repository.js +9 -0
  294. package/dist/modules/plans/repository.js.map +1 -1
  295. package/dist/modules/raises/events.d.ts +9 -0
  296. package/dist/modules/raises/events.d.ts.map +1 -1
  297. package/dist/modules/raises/events.js +4 -0
  298. package/dist/modules/raises/events.js.map +1 -1
  299. package/dist/modules/raises/index.d.ts.map +1 -1
  300. package/dist/modules/raises/index.js +4 -2
  301. package/dist/modules/raises/index.js.map +1 -1
  302. package/dist/modules/raises/routes.d.ts +2 -0
  303. package/dist/modules/raises/routes.d.ts.map +1 -1
  304. package/dist/modules/raises/routes.js +8 -1
  305. package/dist/modules/raises/routes.js.map +1 -1
  306. package/dist/modules/raises/schema.d.ts +34 -0
  307. package/dist/modules/raises/schema.d.ts.map +1 -1
  308. package/dist/modules/raises/schema.js +7 -2
  309. package/dist/modules/raises/schema.js.map +1 -1
  310. package/dist/modules/raises/service.d.ts.map +1 -1
  311. package/dist/modules/raises/service.js +2 -0
  312. package/dist/modules/raises/service.js.map +1 -1
  313. package/dist/modules/raises/tools.d.ts +2 -1
  314. package/dist/modules/raises/tools.d.ts.map +1 -1
  315. package/dist/modules/raises/tools.js +3 -1
  316. package/dist/modules/raises/tools.js.map +1 -1
  317. package/dist/modules/workspace/routes.d.ts +0 -2
  318. package/dist/modules/workspace/routes.d.ts.map +1 -1
  319. package/dist/modules/workspace/routes.js +0 -6
  320. package/dist/modules/workspace/routes.js.map +1 -1
  321. package/dist/modules/workspace/schema.d.ts +0 -34
  322. package/dist/modules/workspace/schema.d.ts.map +1 -1
  323. package/dist/modules/workspace/schema.js +0 -2
  324. package/dist/modules/workspace/schema.js.map +1 -1
  325. package/dist/modules/workspace/seedStarterForms.d.ts +17 -0
  326. package/dist/modules/workspace/seedStarterForms.d.ts.map +1 -0
  327. package/dist/modules/workspace/seedStarterForms.js +71 -0
  328. package/dist/modules/workspace/seedStarterForms.js.map +1 -0
  329. package/dist/modules/workspace/service.d.ts +0 -4
  330. package/dist/modules/workspace/service.d.ts.map +1 -1
  331. package/dist/modules/workspace/service.js +20 -10
  332. package/dist/modules/workspace/service.js.map +1 -1
  333. package/dist/modules/workspace/tools.js +1 -1
  334. package/dist/modules/workspace/tools.js.map +1 -1
  335. package/dist/testing/fixtures.d.ts.map +1 -1
  336. package/dist/testing/fixtures.js +1 -0
  337. package/dist/testing/fixtures.js.map +1 -1
  338. package/migrations/0037_drop_lists_consent_purpose_id.sql +2 -0
  339. package/migrations/0038_smart_white_queen.sql +2 -0
  340. package/migrations/0039_form_map_to_open.sql +1 -0
  341. package/migrations/0040_pipeline_converted_to.sql +20 -0
  342. package/migrations/0041_api_key_scopes.sql +1 -0
  343. package/migrations/0042_drop_workspace_identity.sql +2 -0
  344. package/migrations/meta/0038_snapshot.json +6554 -0
  345. package/migrations/meta/_journal.json +42 -0
  346. package/package.json +2 -2
  347. package/src/app.ts +3 -0
  348. package/src/lib/actor.ts +3 -1
  349. package/src/lib/apiKeyScopes.ts +213 -0
  350. package/src/modules/activities/repository.ts +24 -0
  351. package/src/modules/agent-tasks/repository.ts +24 -0
  352. package/src/modules/api-keys/routes.ts +5 -0
  353. package/src/modules/api-keys/schema.ts +2 -0
  354. package/src/modules/api-keys/scopeMiddleware.ts +30 -0
  355. package/src/modules/api-keys/service.ts +36 -2
  356. package/src/modules/auth/credentials.ts +4 -0
  357. package/src/modules/consent-purposes/index.ts +1 -1
  358. package/src/modules/consent-purposes/schema.ts +3 -3
  359. package/src/modules/consent-purposes/service.ts +7 -16
  360. package/src/modules/consent-purposes/starters.ts +1 -1
  361. package/src/modules/consent-purposes/tools.ts +1 -1
  362. package/src/modules/conversions/clearPointers.ts +81 -0
  363. package/src/modules/conversions/factory.ts +20 -0
  364. package/src/modules/conversions/fieldMap.ts +548 -0
  365. package/src/modules/conversions/index.ts +6 -0
  366. package/src/modules/conversions/mcp.ts +71 -0
  367. package/src/modules/conversions/repoint.ts +146 -0
  368. package/src/modules/conversions/routes.ts +68 -0
  369. package/src/modules/conversions/service.ts +310 -0
  370. package/src/modules/conversions/wire.ts +42 -0
  371. package/src/modules/deals/events.ts +9 -0
  372. package/src/modules/deals/index.ts +4 -2
  373. package/src/modules/deals/routes.ts +11 -1
  374. package/src/modules/deals/schema.ts +10 -2
  375. package/src/modules/deals/service.ts +3 -0
  376. package/src/modules/deals/tools.ts +9 -1
  377. package/src/modules/decisions/repository.ts +23 -1
  378. package/src/modules/enquiries/events.ts +8 -2
  379. package/src/modules/enquiries/index.ts +4 -2
  380. package/src/modules/enquiries/routes.ts +11 -13
  381. package/src/modules/enquiries/schema.ts +12 -3
  382. package/src/modules/enquiries/service.ts +3 -150
  383. package/src/modules/enquiries/tools.ts +9 -18
  384. package/src/modules/forms/applyMappedFields.ts +248 -0
  385. package/src/modules/forms/applySubmissionFields.ts +435 -0
  386. package/src/modules/forms/fields.ts +31 -7
  387. package/src/modules/forms/mapping.ts +20 -3
  388. package/src/modules/forms/repository.ts +0 -7
  389. package/src/modules/forms/routes.ts +1 -2
  390. package/src/modules/forms/schema.ts +0 -2
  391. package/src/modules/forms/service.ts +31 -4
  392. package/src/modules/forms/starters.ts +129 -0
  393. package/src/modules/forms/submission.ts +135 -69
  394. package/src/modules/import-export/customFieldCsv.ts +55 -0
  395. package/src/modules/import-export/customFieldImport.ts +111 -0
  396. package/src/modules/import-export/drafts.ts +151 -3
  397. package/src/modules/import-export/exportRows.ts +222 -68
  398. package/src/modules/import-export/plan.ts +321 -67
  399. package/src/modules/import-export/repository.ts +356 -14
  400. package/src/modules/import-export/routes.ts +8 -8
  401. package/src/modules/import-export/service.ts +208 -45
  402. package/src/modules/import-export/streams.ts +95 -13
  403. package/src/modules/import-export/tools.ts +14 -6
  404. package/src/modules/import-export/validation.ts +128 -0
  405. package/src/modules/import-export/writes.ts +559 -27
  406. package/src/modules/lists/repository.ts +0 -2
  407. package/src/modules/lists/routes.ts +0 -8
  408. package/src/modules/lists/schema.ts +0 -10
  409. package/src/modules/lists/service.ts +9 -107
  410. package/src/modules/lists/starters.ts +16 -0
  411. package/src/modules/mcp/protocol.ts +18 -0
  412. package/src/modules/notes/repository.ts +24 -0
  413. package/src/modules/opportunities/events.ts +9 -0
  414. package/src/modules/opportunities/index.ts +4 -2
  415. package/src/modules/opportunities/routes.ts +11 -1
  416. package/src/modules/opportunities/schema.ts +10 -2
  417. package/src/modules/opportunities/service.ts +3 -0
  418. package/src/modules/opportunities/tools.ts +9 -1
  419. package/src/modules/partnerships/events.ts +9 -0
  420. package/src/modules/partnerships/index.ts +4 -2
  421. package/src/modules/partnerships/routes.ts +11 -1
  422. package/src/modules/partnerships/schema.ts +10 -2
  423. package/src/modules/partnerships/service.ts +3 -0
  424. package/src/modules/partnerships/tools.ts +9 -1
  425. package/src/modules/people/personConsentWrites.ts +1 -1
  426. package/src/modules/people/schema.ts +1 -1
  427. package/src/modules/plans/repository.ts +24 -0
  428. package/src/modules/raises/events.ts +9 -0
  429. package/src/modules/raises/index.ts +4 -2
  430. package/src/modules/raises/routes.ts +11 -1
  431. package/src/modules/raises/schema.ts +10 -2
  432. package/src/modules/raises/service.ts +3 -0
  433. package/src/modules/raises/tools.ts +9 -1
  434. package/src/modules/workspace/routes.ts +0 -6
  435. package/src/modules/workspace/schema.ts +0 -2
  436. package/src/modules/workspace/seedStarterForms.ts +98 -0
  437. package/src/modules/workspace/service.ts +23 -15
  438. package/src/modules/workspace/tools.ts +1 -1
  439. package/src/testing/fixtures.ts +1 -0
@@ -0,0 +1,71 @@
1
+ import { convertEnquiryBody, convertPipelineRecordBody, PIPELINE_KINDS } from '@kelpie/schemas'
2
+ import type { PipelineKind } from '@kelpie/schemas'
3
+ import { z } from 'zod'
4
+
5
+ import type { McpToolRegistry } from '../../runtime/module.ts'
6
+ import { idArg } from '../crudTools.ts'
7
+ import type { ConversionsService } from './service.ts'
8
+ import { objectLabelFor } from './fieldMap.ts'
9
+ import { toConvertInput } from './routes.ts'
10
+ import { renderConvertedPipelineRecord } from './wire.ts'
11
+
12
+ const CONVERT_TOOL_RESOURCES: Readonly<Record<PipelineKind, string>> = {
13
+ enquiry: 'enquiries',
14
+ deal: 'deals',
15
+ opportunity: 'opportunities',
16
+ raise: 'raises',
17
+ partnership: 'partnerships',
18
+ }
19
+
20
+ export function registerPipelineConvertTool(
21
+ mcp: McpToolRegistry,
22
+ conversions: ConversionsService,
23
+ sourceKind: PipelineKind,
24
+ ): void {
25
+ const bodySchema =
26
+ sourceKind === 'enquiry'
27
+ ? convertEnquiryBody
28
+ : convertPipelineRecordBody
29
+
30
+ mcp.tool({
31
+ name: `${CONVERT_TOOL_RESOURCES[sourceKind]}_convert`,
32
+ description:
33
+ `Convert a ${objectLabelFor(sourceKind)} to another pipeline record type. ` +
34
+ 'Creates a new record, moves notes/activities/decisions/plans to it, copies ' +
35
+ 'linked people, and leaves the source in place with a conversion link. ' +
36
+ `Target types: ${PIPELINE_KINDS.join(', ')}. 409 if already converted.`,
37
+ inputSchema: bodySchema.and(z.strictObject({ id: idArg })),
38
+ invoke: async (args, actor) => {
39
+ const { id, ...body } = args
40
+ const { targetKind, target, personIds } = await conversions.convert(
41
+ actor,
42
+ sourceKind,
43
+ id,
44
+ toConvertInput(body),
45
+ )
46
+
47
+ return renderConvertedPipelineRecord(targetKind, target, personIds)
48
+ },
49
+ })
50
+ }
51
+
52
+ /** Backward-compatible alias for agents that still call enquiries_convert_to_deal. */
53
+ export function registerEnquiryConvertToDealTool(
54
+ mcp: McpToolRegistry,
55
+ conversions: ConversionsService,
56
+ ): void {
57
+ mcp.tool({
58
+ name: 'enquiries_convert_to_deal',
59
+ description:
60
+ 'Convert an enquiry to a Deal. Same as enquiries_convert with target_type deal. ' +
61
+ 'Mirrors POST /v1/enquiries/{id}/convert.',
62
+ inputSchema: z.strictObject({ id: idArg }),
63
+ invoke: async ({ id }, actor) => {
64
+ const { targetKind, target, personIds } = await conversions.convert(actor, 'enquiry', id, {
65
+ targetType: 'deal',
66
+ })
67
+
68
+ return renderConvertedPipelineRecord(targetKind, target, personIds)
69
+ },
70
+ })
71
+ }
@@ -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
  },