@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
@@ -111,7 +111,6 @@ export async function findList(
111
111
  export interface ListIdRow {
112
112
  readonly id: string
113
113
  readonly targetType: string
114
- readonly consentPurposeId: string | null
115
114
  }
116
115
 
117
116
  export async function listListsById(
@@ -127,7 +126,6 @@ export async function listListsById(
127
126
  .select({
128
127
  id: lists.id,
129
128
  targetType: lists.targetType,
130
- consentPurposeId: lists.consentPurposeId,
131
129
  })
132
130
  .from(lists)
133
131
  .where(and(eq(lists.workspaceId, workspaceId), inArray(lists.id, ids)))
@@ -31,14 +31,12 @@ export const createBody = z.strictObject({
31
31
  name: z.string().min(1),
32
32
  target_type: z.enum(RECORD_TARGET_TYPES),
33
33
  description: z.string().nullable().default(null),
34
- consent_purpose_id: z.string().min(1).nullable().default(null),
35
34
  })
36
35
 
37
36
  export const updateBody = z
38
37
  .strictObject({
39
38
  name: z.string().min(1),
40
39
  description: z.string().nullable(),
41
- consent_purpose_id: z.string().min(1).nullable(),
42
40
  })
43
41
  .partial()
44
42
 
@@ -56,7 +54,6 @@ export function toCreateInput(body: z.infer<typeof createBody>): CreateListInput
56
54
  name: body.name,
57
55
  targetType: body.target_type,
58
56
  description: body.description,
59
- consentPurposeId: body.consent_purpose_id,
60
57
  }
61
58
  }
62
59
 
@@ -64,9 +61,6 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdateListInput
64
61
  return {
65
62
  ...(body.name === undefined ? {} : { name: body.name }),
66
63
  ...(body.description === undefined ? {} : { description: body.description }),
67
- ...(body.consent_purpose_id === undefined
68
- ? {}
69
- : { consentPurposeId: body.consent_purpose_id }),
70
64
  }
71
65
  }
72
66
 
@@ -84,8 +78,6 @@ export function listResponse(list: ListView): Record<string, unknown> {
84
78
  description: list.description,
85
79
  target_type: list.targetType,
86
80
  member_count: list.memberCount,
87
- consent_purpose_id: list.consentPurposeId,
88
- consent_purpose_slug: list.consentPurposeSlug,
89
81
  created_at: list.createdAt.toISOString(),
90
82
  updated_at: list.updatedAt.toISOString(),
91
83
  }
@@ -2,7 +2,6 @@ import { RECORD_TARGET_TYPES } from '@kelpie/schemas'
2
2
  import { foreignKey, index, pgTable, text, timestamp, unique } from 'drizzle-orm/pg-core'
3
3
 
4
4
  import { checkOneOf, createdAt, primaryId, updatedAt } from '../../lib/columns.ts'
5
- import { consentPurposes } from '../consent-purposes/schema.ts'
6
5
  import { workspaces } from '../workspace/schema.ts'
7
6
 
8
7
  /**
@@ -35,15 +34,6 @@ export const lists = pgTable(
35
34
  name: text('name').notNull(),
36
35
  description: text('description'),
37
36
  targetType: text('target_type').notNull(),
38
- /**
39
- * The consent purpose captured when a form submit adds a person to this
40
- * list. Person lists only — the service refuses a non-null value on any
41
- * other target type. `restrict` on delete so a purpose in use is not
42
- * silently unset behind the list's back.
43
- */
44
- consentPurposeId: text('consent_purpose_id').references(() => consentPurposes.id, {
45
- onDelete: 'restrict',
46
- }),
47
37
  createdAt: createdAt(),
48
38
  updatedAt: updatedAt(),
49
39
  },
@@ -9,7 +9,6 @@ import type { TransactionScope } from '../../runtime/transaction.ts'
9
9
  import { toEventActor } from '../../lib/actor.ts'
10
10
  import type { Actor } from '../auth/actor.ts'
11
11
  import { requireWorkspaceId } from '../auth/actor.ts'
12
- import * as consentPurposesRepository from '../consent-purposes/repository.ts'
13
12
  import { missingTargets, resolveTargetNames, targetKey } from '../recordTargets.ts'
14
13
  import type { RecordTargetType } from '../recordTargets.ts'
15
14
  import './events.ts'
@@ -44,14 +43,8 @@ export interface ListsDependencies {
44
43
  readonly now: () => Date
45
44
  }
46
45
 
47
- /**
48
- * A list as the API returns one: the stored row minus the tenancy column,
49
- * plus the denormalised slug of the consent purpose (when set) so a reader
50
- * needs no second call.
51
- */
52
- export type ListView = Omit<ListWithCount, 'workspaceId'> & {
53
- readonly consentPurposeSlug: string | null
54
- }
46
+ /** A list as the API returns one: the stored row minus the tenancy column. */
47
+ export type ListView = Omit<ListWithCount, 'workspaceId'>
55
48
 
56
49
  /** A membership plus the list it points at, as `/v1/list-memberships` returns one. */
57
50
  export interface ListMembershipView {
@@ -78,18 +71,12 @@ export interface CreateListInput {
78
71
  readonly name: string
79
72
  readonly targetType: RecordTargetType
80
73
  readonly description: string | null
81
- /**
82
- * Optional consent purpose captured on form-driven adds. Person lists only.
83
- * A non-null value on any other target type is refused at 422.
84
- */
85
- readonly consentPurposeId: string | null
86
74
  }
87
75
 
88
76
  /** PATCH semantics: an absent field is left alone. The type never moves. */
89
77
  export interface UpdateListInput {
90
78
  readonly name?: string | undefined
91
79
  readonly description?: string | null | undefined
92
- readonly consentPurposeId?: string | null | undefined
93
80
  }
94
81
 
95
82
  export interface AddListMemberInput {
@@ -117,10 +104,10 @@ export interface ListsService {
117
104
  ): Promise<readonly ListMembershipView[]>
118
105
  }
119
106
 
120
- function toView(record: ListWithCount, consentPurposeSlug: string | null): ListView {
107
+ function toView(record: ListWithCount): ListView {
121
108
  const { workspaceId: _workspaceId, ...view } = record
122
109
 
123
- return { ...view, consentPurposeSlug }
110
+ return view
124
111
  }
125
112
 
126
113
  function toMembershipView(row: MembershipWithList): ListMembershipView {
@@ -170,13 +157,6 @@ function alreadyMember(): AppError {
170
157
  ])
171
158
  }
172
159
 
173
- function purposeNotPersonList(): AppError {
174
- return AppError.validationFailed(
175
- 'Only person lists capture consent — remove consent_purpose_id or change the list type',
176
- [{ field: 'consent_purpose_id', message: 'Person lists only' }],
177
- )
178
- }
179
-
180
160
  export function createListsService(dependencies: ListsDependencies): ListsService {
181
161
  async function require(workspaceId: string, id: string): Promise<ListWithCount> {
182
162
  const list = await repository.findList(dependencies.db, workspaceId, id)
@@ -200,77 +180,25 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
200
180
  }
201
181
  }
202
182
 
203
- async function resolveConsentPurposeSlug(
204
- workspaceId: string,
205
- purposeId: string | null,
206
- ): Promise<string | null> {
207
- if (purposeId === null) return null
208
- const [row] = await consentPurposesRepository.listPurposesByIds(
209
- dependencies.db,
210
- workspaceId,
211
- [purposeId],
212
- )
213
- return row?.slug ?? null
214
- }
215
-
216
- async function requireConsentPurposeExists(
217
- workspaceId: string,
218
- purposeId: string,
219
- ): Promise<void> {
220
- const rows = await consentPurposesRepository.listPurposesByIds(
221
- dependencies.db,
222
- workspaceId,
223
- [purposeId],
224
- )
225
- if (rows.length === 0) {
226
- throw AppError.validationFailed('That consent purpose was not found', [
227
- { field: 'consent_purpose_id', message: `No purpose ${purposeId} here` },
228
- ])
229
- }
230
- }
231
-
232
183
  return {
233
184
  async list(actor, filters, query) {
234
185
  const workspaceId = requireWorkspaceId(actor)
235
186
  const window = readListWindow(query, LIST_SORTS, DEFAULT_LIST_SORT)
236
187
  const rows = await repository.listLists(dependencies.db, workspaceId, filters, window)
237
- const purposeIds = Array.from(
238
- new Set(
239
- rows
240
- .map((row) => row.consentPurposeId)
241
- .filter((id): id is string => id !== null),
242
- ),
243
- )
244
- const purposes = await consentPurposesRepository.listPurposesByIds(
245
- dependencies.db,
246
- workspaceId,
247
- purposeIds,
248
- )
249
- const slugByPurpose = new Map(purposes.map((purpose) => [purpose.id, purpose.slug]))
250
188
 
251
- return mapPage(toPage(rows, window, (row) => row.id), (row) =>
252
- toView(row, row.consentPurposeId === null ? null : (slugByPurpose.get(row.consentPurposeId) ?? null)),
253
- )
189
+ return mapPage(toPage(rows, window, (row) => row.id), (row) => toView(row))
254
190
  },
255
191
 
256
192
  async get(actor, id) {
257
193
  const workspaceId = requireWorkspaceId(actor)
258
194
  const record = await require(workspaceId, id)
259
- const slug = await resolveConsentPurposeSlug(workspaceId, record.consentPurposeId)
260
- return toView(record, slug)
195
+ return toView(record)
261
196
  },
262
197
 
263
198
  async create(actor, input) {
264
199
  const workspaceId = requireWorkspaceId(actor)
265
200
  const id = dependencies.createId('list')
266
201
 
267
- if (input.consentPurposeId !== null) {
268
- if (input.targetType !== 'person') {
269
- throw purposeNotPersonList()
270
- }
271
- await requireConsentPurposeExists(workspaceId, input.consentPurposeId)
272
- }
273
-
274
202
  return dependencies.transaction(
275
203
  async ({ tx, events }) => {
276
204
  let created
@@ -281,7 +209,6 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
281
209
  name: input.name,
282
210
  description: input.description,
283
211
  targetType: input.targetType,
284
- consentPurposeId: input.consentPurposeId,
285
212
  })
286
213
  } catch (error: unknown) {
287
214
  if (postgresErrorCode(error) === UNIQUE_VIOLATION) {
@@ -293,12 +220,7 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
293
220
 
294
221
  events.emit('lists.list.created', { type: 'list', id: created.id }, {})
295
222
 
296
- const slug = await resolveConsentPurposeSlug(
297
- workspaceId,
298
- created.consentPurposeId,
299
- )
300
-
301
- return toView({ ...created, memberCount: 0 }, slug)
223
+ return toView({ ...created, memberCount: 0 })
302
224
  },
303
225
  { workspaceId, actor: toEventActor(actor) },
304
226
  )
@@ -308,32 +230,14 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
308
230
  const workspaceId = requireWorkspaceId(actor)
309
231
  const existing = await require(workspaceId, id)
310
232
 
311
- if (
312
- changes.consentPurposeId !== undefined &&
313
- changes.consentPurposeId !== null &&
314
- existing.targetType !== 'person'
315
- ) {
316
- throw purposeNotPersonList()
317
- }
318
- if (
319
- changes.consentPurposeId !== undefined &&
320
- changes.consentPurposeId !== null
321
- ) {
322
- await requireConsentPurposeExists(workspaceId, changes.consentPurposeId)
323
- }
324
-
325
233
  const columns: Partial<repository.ListColumns> = {
326
234
  ...(changes.name === undefined ? {} : { name: changes.name }),
327
235
  ...(changes.description === undefined ? {} : { description: changes.description }),
328
- ...(changes.consentPurposeId === undefined
329
- ? {}
330
- : { consentPurposeId: changes.consentPurposeId }),
331
236
  }
332
237
  const changed = changedKeys(existing, columns)
333
238
 
334
239
  if (changed.length === 0) {
335
- const slug = await resolveConsentPurposeSlug(workspaceId, existing.consentPurposeId)
336
- return toView(existing, slug)
240
+ return toView(existing)
337
241
  }
338
242
 
339
243
  return dependencies.transaction(
@@ -358,9 +262,7 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
358
262
 
359
263
  events.emit('lists.list.updated', { type: 'list', id }, { changed })
360
264
 
361
- const slug = await resolveConsentPurposeSlug(workspaceId, updated.consentPurposeId)
362
-
363
- return toView({ ...updated, memberCount: existing.memberCount }, slug)
265
+ return toView({ ...updated, memberCount: existing.memberCount })
364
266
  },
365
267
  { workspaceId, actor: toEventActor(actor) },
366
268
  )
@@ -0,0 +1,16 @@
1
+ import type { RecordTargetType } from '@kelpie/schemas'
2
+
3
+ /**
4
+ * The lists a new workspace starts with. Data, not migrations: a workspace
5
+ * owner may rename or delete them, and add any others they need.
6
+ */
7
+
8
+ export interface StarterList {
9
+ readonly slug: string
10
+ readonly name: string
11
+ readonly targetType: RecordTargetType
12
+ }
13
+
14
+ export const STARTER_LISTS: readonly StarterList[] = [
15
+ { slug: 'newsletter', name: 'Newsletter', targetType: 'person' },
16
+ ]
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod'
2
2
 
3
3
  import type { Actor } from '../../lib/actor.ts'
4
+ import { requireApiKeyScope, resolveMcpScope } from '../../lib/apiKeyScopes.ts'
4
5
  import { AppError, describeThrown, internalErrorBody, toErrorBody } from '../../lib/errors.ts'
5
6
  import type { Logger } from '../../lib/logger.ts'
6
7
  import type { McpTool } from '../../runtime/module.ts'
@@ -317,6 +318,23 @@ async function callTool(
317
318
  return failure(id, INVALID_PARAMS, `Unknown tool "${parsed.data.name}"`)
318
319
  }
319
320
 
321
+ const requiredScope = resolveMcpScope(parsed.data.name)
322
+
323
+ if (requiredScope !== null) {
324
+ try {
325
+ requireApiKeyScope(actor, requiredScope)
326
+ } catch (error: unknown) {
327
+ if (error instanceof AppError && error.code === 'forbidden') {
328
+ return success(
329
+ id,
330
+ completeResult(dependencies, era, toolFailure(dependencies.logger, tool.name, error)),
331
+ )
332
+ }
333
+
334
+ throw error
335
+ }
336
+ }
337
+
320
338
  try {
321
339
  // `arguments` is optional on the wire and every tool schema is an object, so
322
340
  // an absent one is an empty object rather than a validation failure the
@@ -128,3 +128,27 @@ export async function deleteForTarget(
128
128
 
129
129
  return deleted.length
130
130
  }
131
+
132
+ /** Moves every note from one target to another inside a conversion transaction. */
133
+ export async function repointForTarget(
134
+ db: Queryable,
135
+ workspaceId: string,
136
+ fromType: string,
137
+ fromId: string,
138
+ toType: string,
139
+ toId: string,
140
+ ): Promise<number> {
141
+ const updated = await db
142
+ .update(notes)
143
+ .set({ targetType: toType, targetId: toId })
144
+ .where(
145
+ and(
146
+ eq(notes.workspaceId, workspaceId),
147
+ eq(notes.targetType, fromType),
148
+ eq(notes.targetId, fromId),
149
+ ),
150
+ )
151
+ .returning({ id: notes.id })
152
+
153
+ return updated.length
154
+ }
@@ -12,6 +12,10 @@ export const opportunitiesEvents = {
12
12
  fromStageId: z.string().nullable(),
13
13
  toStageId: z.string(),
14
14
  }),
15
+ 'opportunities.opportunity.converted': z.object({
16
+ targetType: z.string(),
17
+ targetId: z.string(),
18
+ }),
15
19
  } satisfies ModuleEventCatalog
16
20
 
17
21
  export type OpportunityCreatedData = Record<string, never>
@@ -23,6 +27,10 @@ export interface OpportunityStageChangedData {
23
27
  readonly fromStageId: string | null
24
28
  readonly toStageId: string
25
29
  }
30
+ export interface OpportunityConvertedData {
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
  'opportunities.opportunity.updated': OpportunityUpdatedData
31
39
  'opportunities.opportunity.deleted': OpportunityDeletedData
32
40
  'opportunities.opportunity.stage_changed': OpportunityStageChangedData
41
+ 'opportunities.opportunity.converted': OpportunityConvertedData
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 { opportunitiesEvents } from './events.ts'
5
6
  import { mountOpportunitiesRoutes } from './routes.ts'
@@ -22,6 +23,7 @@ export function createOpportunitiesModule(migrationsDirectory: string): KelpieMo
22
23
  events: opportunitiesEvents,
23
24
 
24
25
  register(context) {
26
+ const conversions = createConversionsFromContext(context)
25
27
  const service = createOpportunitiesService({
26
28
  db: context.db,
27
29
  transaction: context.transaction,
@@ -37,10 +39,10 @@ export function createOpportunitiesModule(migrationsDirectory: string): KelpieMo
37
39
  context.schema(schema, migrationsDirectory)
38
40
 
39
41
  context.routes((router) => {
40
- mountOpportunitiesRoutes(router, { db: context.db, now: context.now, service })
42
+ mountOpportunitiesRoutes(router, { db: context.db, now: context.now, service, conversions })
41
43
  })
42
44
 
43
- registerOpportunitiesTools(context.mcp, service)
45
+ registerOpportunitiesTools(context.mcp, service, conversions)
44
46
 
45
47
  return Promise.resolve()
46
48
  },
@@ -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 {
12
14
  CreateOpportunityInput,
13
15
  OpportunitiesService,
@@ -55,6 +57,7 @@ export const updateBody = z.strictObject(opportunityShape).partial()
55
57
 
56
58
  export interface OpportunitiesRoutesDependencies extends CredentialDependencies {
57
59
  readonly service: OpportunitiesService
60
+ readonly conversions: ConversionsService
58
61
  }
59
62
 
60
63
  export function toCreateInput(body: z.infer<typeof createBody>): CreateOpportunityInput {
@@ -99,6 +102,7 @@ export function opportunityResponse(opportunity: OpportunityView): Record<string
99
102
  person_ids: opportunity.personIds,
100
103
  summary: opportunity.summary,
101
104
  tags: opportunity.tags,
105
+ converted_to: convertedToResponse(opportunity.convertedTargetType, opportunity.convertedTargetId),
102
106
  custom_fields: renderCustomFieldsForWire(opportunity.customFields),
103
107
  created_at: opportunity.createdAt.toISOString(),
104
108
  updated_at: opportunity.updatedAt.toISOString(),
@@ -162,4 +166,10 @@ export function mountOpportunitiesRoutes(
162
166
 
163
167
  return context.body(null, 204)
164
168
  })
169
+
170
+ mountPipelineConvertRoute(router, '/opportunities/:id/convert', {
171
+ ...dependencies,
172
+ sourceKind: 'opportunity',
173
+ bodySchema: convertPipelineRecordBody,
174
+ })
165
175
  }
@@ -1,7 +1,9 @@
1
+ import { sql } from 'drizzle-orm'
2
+ import { check, 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 { 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'
@@ -31,6 +33,8 @@ export const opportunities = pgTable(
31
33
  expectedClose: date('expected_close'),
32
34
  summary: text('summary').notNull().default(''),
33
35
  tags: text('tags').array().notNull().default([]),
36
+ convertedTargetType: text('converted_target_type'),
37
+ convertedTargetId: text('converted_target_id'),
34
38
  // Workspace-defined fields, keyed by definition key. See people/schema.ts.
35
39
  customFields: jsonb('custom_fields')
36
40
  .$type<Readonly<Record<string, CustomFieldValue>>>()
@@ -49,5 +53,9 @@ export const opportunities = pgTable(
49
53
  index('opportunities_workspace_idx').on(table.workspaceId),
50
54
  index('opportunities_stage_idx').on(table.stageId),
51
55
  index('opportunities_search_idx').using('gin', table.searchVector),
56
+ check(
57
+ 'opportunities_converted_target_type_check',
58
+ sql`${table.convertedTargetType} is null or ${oneOf('opportunities_converted_target_type_check', table.convertedTargetType, PIPELINE_KINDS)}`,
59
+ ),
52
60
  ],
53
61
  )
@@ -21,6 +21,7 @@ import type { Actor } from '../auth/actor.ts'
21
21
  import { actorMemberId, requireWorkspaceId } from '../auth/actor.ts'
22
22
  import './events.ts'
23
23
  import { deleteRecordsAttachedTo } from '../attachedRecords.ts'
24
+ import { clearConversionPointersToTarget } from '../conversions/clearPointers.ts'
24
25
  import * as companyRepository from '../companies/repository.ts'
25
26
  import type { CustomFieldValuesValidator } from '../custom-fields/values.ts'
26
27
  import * as personLinks from '../personLinks.ts'
@@ -494,6 +495,8 @@ export function createOpportunitiesService(
494
495
  await dependencies.transaction(async ({ tx, events }) => {
495
496
  await require(workspaceId, id)
496
497
 
498
+ await clearConversionPointersToTarget(tx, workspaceId, 'opportunity', id)
499
+
497
500
  // Notes, activities, decisions, plan items, and person_links have no
498
501
  // foreign key to their target, so the deleting service removes them
499
502
  // here, in the same transaction. Nothing else references an opportunity.
@@ -2,6 +2,8 @@ import { z } from 'zod'
2
2
 
3
3
  import type { McpToolRegistry } from '../../runtime/module.ts'
4
4
  import { idArg, idSetArg, listWindowShape, registerCrudTools, termArg, toSet } from '../crudTools.ts'
5
+ import type { ConversionsService } from '../conversions/index.ts'
6
+ import { registerPipelineConvertTool } from '../conversions/mcp.ts'
5
7
  import { createBody, opportunityResponse, toCreateInput, toUpdateInput, updateBody } from './routes.ts'
6
8
  import type { OpportunitiesService } from './service.ts'
7
9
 
@@ -16,7 +18,11 @@ const listArgs = z.strictObject({
16
18
  person_id: idSetArg.optional().describe('Only opportunities any of these people are on.'),
17
19
  })
18
20
 
19
- export function registerOpportunitiesTools(mcp: McpToolRegistry, service: OpportunitiesService): void {
21
+ export function registerOpportunitiesTools(
22
+ mcp: McpToolRegistry,
23
+ service: OpportunitiesService,
24
+ conversions: ConversionsService,
25
+ ): void {
20
26
  registerCrudTools(mcp, {
21
27
  resource: 'opportunities',
22
28
  subject: 'opportunity',
@@ -38,4 +44,6 @@ export function registerOpportunitiesTools(mcp: McpToolRegistry, service: Opport
38
44
  updateArgs: updateBody.extend({ id: idArg }),
39
45
  toUpdateInput,
40
46
  })
47
+
48
+ registerPipelineConvertTool(mcp, conversions, 'opportunity')
41
49
  }
@@ -12,6 +12,10 @@ export const partnershipsEvents = {
12
12
  fromStageId: z.string().nullable(),
13
13
  toStageId: z.string(),
14
14
  }),
15
+ 'partnerships.partnership.converted': z.object({
16
+ targetType: z.string(),
17
+ targetId: z.string(),
18
+ }),
15
19
  } satisfies ModuleEventCatalog
16
20
 
17
21
  export type PartnershipCreatedData = Record<string, never>
@@ -23,6 +27,10 @@ export interface PartnershipStageChangedData {
23
27
  readonly fromStageId: string | null
24
28
  readonly toStageId: string
25
29
  }
30
+ export interface PartnershipConvertedData {
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
  'partnerships.partnership.updated': PartnershipUpdatedData
31
39
  'partnerships.partnership.deleted': PartnershipDeletedData
32
40
  'partnerships.partnership.stage_changed': PartnershipStageChangedData
41
+ 'partnerships.partnership.converted': PartnershipConvertedData
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 { partnershipsEvents } from './events.ts'
5
6
  import { mountPartnershipsRoutes } from './routes.ts'
@@ -22,6 +23,7 @@ export function createPartnershipsModule(migrationsDirectory: string): KelpieMod
22
23
  events: partnershipsEvents,
23
24
 
24
25
  register(context) {
26
+ const conversions = createConversionsFromContext(context)
25
27
  const service = createPartnershipsService({
26
28
  db: context.db,
27
29
  transaction: context.transaction,
@@ -37,10 +39,10 @@ export function createPartnershipsModule(migrationsDirectory: string): KelpieMod
37
39
  context.schema(schema, migrationsDirectory)
38
40
 
39
41
  context.routes((router) => {
40
- mountPartnershipsRoutes(router, { db: context.db, now: context.now, service })
42
+ mountPartnershipsRoutes(router, { db: context.db, now: context.now, service, conversions })
41
43
  })
42
44
 
43
- registerPartnershipsTools(context.mcp, service)
45
+ registerPartnershipsTools(context.mcp, service, conversions)
44
46
 
45
47
  return Promise.resolve()
46
48
  },
@@ -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 {
12
14
  CreatePartnershipInput,
13
15
  PartnershipView,
@@ -59,6 +61,7 @@ export const updateBody = z.strictObject(partnershipShape).partial()
59
61
 
60
62
  export interface PartnershipsRoutesDependencies extends CredentialDependencies {
61
63
  readonly service: PartnershipsService
64
+ readonly conversions: ConversionsService
62
65
  }
63
66
 
64
67
  export function toCreateInput(body: z.infer<typeof createBody>): CreatePartnershipInput {
@@ -111,6 +114,7 @@ export function partnershipResponse(partnership: PartnershipView): Record<string
111
114
  person_ids: partnership.personIds,
112
115
  summary: partnership.summary,
113
116
  tags: partnership.tags,
117
+ converted_to: convertedToResponse(partnership.convertedTargetType, partnership.convertedTargetId),
114
118
  custom_fields: renderCustomFieldsForWire(partnership.customFields),
115
119
  created_at: partnership.createdAt.toISOString(),
116
120
  updated_at: partnership.updatedAt.toISOString(),
@@ -174,4 +178,10 @@ export function mountPartnershipsRoutes(
174
178
 
175
179
  return context.body(null, 204)
176
180
  })
181
+
182
+ mountPipelineConvertRoute(router, '/partnerships/:id/convert', {
183
+ ...dependencies,
184
+ sourceKind: 'partnership',
185
+ bodySchema: convertPipelineRecordBody,
186
+ })
177
187
  }