@kelpie/server 0.8.0 → 0.10.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 (594) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/ids.d.ts +11 -0
  6. package/dist/lib/ids.d.ts.map +1 -1
  7. package/dist/lib/ids.js +11 -0
  8. package/dist/lib/ids.js.map +1 -1
  9. package/dist/modules/activities/repository.d.ts.map +1 -1
  10. package/dist/modules/activities/repository.js +19 -20
  11. package/dist/modules/activities/repository.js.map +1 -1
  12. package/dist/modules/activities/wording.d.ts +12 -0
  13. package/dist/modules/activities/wording.d.ts.map +1 -1
  14. package/dist/modules/activities/wording.js +16 -0
  15. package/dist/modules/activities/wording.js.map +1 -1
  16. package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
  17. package/dist/modules/agent-tasks/catalog.js +62 -0
  18. package/dist/modules/agent-tasks/catalog.js.map +1 -1
  19. package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
  20. package/dist/modules/agent-tasks/resolve.js +42 -9
  21. package/dist/modules/agent-tasks/resolve.js.map +1 -1
  22. package/dist/modules/agent-tasks/routes.d.ts +2 -0
  23. package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
  24. package/dist/modules/attachedRecords.d.ts +6 -1
  25. package/dist/modules/attachedRecords.d.ts.map +1 -1
  26. package/dist/modules/attachedRecords.js +15 -1
  27. package/dist/modules/attachedRecords.js.map +1 -1
  28. package/dist/modules/companies/index.d.ts.map +1 -1
  29. package/dist/modules/companies/index.js +3 -1
  30. package/dist/modules/companies/index.js.map +1 -1
  31. package/dist/modules/companies/routes.d.ts +14 -0
  32. package/dist/modules/companies/routes.d.ts.map +1 -1
  33. package/dist/modules/companies/routes.js +7 -0
  34. package/dist/modules/companies/routes.js.map +1 -1
  35. package/dist/modules/companies/schema.d.ts +20 -0
  36. package/dist/modules/companies/schema.d.ts.map +1 -1
  37. package/dist/modules/companies/schema.js +6 -1
  38. package/dist/modules/companies/schema.js.map +1 -1
  39. package/dist/modules/companies/service.d.ts +5 -0
  40. package/dist/modules/companies/service.d.ts.map +1 -1
  41. package/dist/modules/companies/service.js +24 -12
  42. package/dist/modules/companies/service.js.map +1 -1
  43. package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
  44. package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
  45. package/dist/modules/consent-purposes/capabilities.js +10 -0
  46. package/dist/modules/consent-purposes/capabilities.js.map +1 -0
  47. package/dist/modules/consent-purposes/events.d.ts +38 -0
  48. package/dist/modules/consent-purposes/events.d.ts.map +1 -0
  49. package/dist/modules/consent-purposes/events.js +17 -0
  50. package/dist/modules/consent-purposes/events.js.map +1 -0
  51. package/dist/modules/consent-purposes/index.d.ts +13 -0
  52. package/dist/modules/consent-purposes/index.d.ts.map +1 -0
  53. package/dist/modules/consent-purposes/index.js +41 -0
  54. package/dist/modules/consent-purposes/index.js.map +1 -0
  55. package/dist/modules/consent-purposes/repository.d.ts +21 -0
  56. package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
  57. package/dist/modules/consent-purposes/repository.js +98 -0
  58. package/dist/modules/consent-purposes/repository.js.map +1 -0
  59. package/dist/modules/consent-purposes/routes.d.ts +39 -0
  60. package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
  61. package/dist/modules/consent-purposes/routes.js +79 -0
  62. package/dist/modules/consent-purposes/routes.js.map +1 -0
  63. package/dist/modules/consent-purposes/schema.d.ts +175 -0
  64. package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
  65. package/dist/modules/consent-purposes/schema.js +35 -0
  66. package/dist/modules/consent-purposes/schema.js.map +1 -0
  67. package/dist/modules/consent-purposes/service.d.ts +50 -0
  68. package/dist/modules/consent-purposes/service.d.ts.map +1 -0
  69. package/dist/modules/consent-purposes/service.js +263 -0
  70. package/dist/modules/consent-purposes/service.js.map +1 -0
  71. package/dist/modules/consent-purposes/starters.d.ts +17 -0
  72. package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
  73. package/dist/modules/consent-purposes/starters.js +15 -0
  74. package/dist/modules/consent-purposes/starters.js.map +1 -0
  75. package/dist/modules/consent-purposes/tools.d.ts +4 -0
  76. package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
  77. package/dist/modules/consent-purposes/tools.js +29 -0
  78. package/dist/modules/consent-purposes/tools.js.map +1 -0
  79. package/dist/modules/core.d.ts.map +1 -1
  80. package/dist/modules/core.js +10 -0
  81. package/dist/modules/core.js.map +1 -1
  82. package/dist/modules/custom-fields/capabilities.d.ts +12 -0
  83. package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
  84. package/dist/modules/custom-fields/capabilities.js +15 -0
  85. package/dist/modules/custom-fields/capabilities.js.map +1 -0
  86. package/dist/modules/custom-fields/events.d.ts +49 -0
  87. package/dist/modules/custom-fields/events.d.ts.map +1 -0
  88. package/dist/modules/custom-fields/events.js +25 -0
  89. package/dist/modules/custom-fields/events.js.map +1 -0
  90. package/dist/modules/custom-fields/index.d.ts +19 -0
  91. package/dist/modules/custom-fields/index.d.ts.map +1 -0
  92. package/dist/modules/custom-fields/index.js +46 -0
  93. package/dist/modules/custom-fields/index.js.map +1 -0
  94. package/dist/modules/custom-fields/repository.d.ts +37 -0
  95. package/dist/modules/custom-fields/repository.d.ts.map +1 -0
  96. package/dist/modules/custom-fields/repository.js +144 -0
  97. package/dist/modules/custom-fields/repository.js.map +1 -0
  98. package/dist/modules/custom-fields/routes.d.ts +44 -0
  99. package/dist/modules/custom-fields/routes.d.ts.map +1 -0
  100. package/dist/modules/custom-fields/routes.js +103 -0
  101. package/dist/modules/custom-fields/routes.js.map +1 -0
  102. package/dist/modules/custom-fields/schema.d.ts +215 -0
  103. package/dist/modules/custom-fields/schema.d.ts.map +1 -0
  104. package/dist/modules/custom-fields/schema.js +43 -0
  105. package/dist/modules/custom-fields/schema.js.map +1 -0
  106. package/dist/modules/custom-fields/service.d.ts +57 -0
  107. package/dist/modules/custom-fields/service.d.ts.map +1 -0
  108. package/dist/modules/custom-fields/service.js +273 -0
  109. package/dist/modules/custom-fields/service.js.map +1 -0
  110. package/dist/modules/custom-fields/tools.d.ts +4 -0
  111. package/dist/modules/custom-fields/tools.d.ts.map +1 -0
  112. package/dist/modules/custom-fields/tools.js +38 -0
  113. package/dist/modules/custom-fields/tools.js.map +1 -0
  114. package/dist/modules/custom-fields/values.d.ts +49 -0
  115. package/dist/modules/custom-fields/values.d.ts.map +1 -0
  116. package/dist/modules/custom-fields/values.js +249 -0
  117. package/dist/modules/custom-fields/values.js.map +1 -0
  118. package/dist/modules/custom-fields/wire.d.ts +12 -0
  119. package/dist/modules/custom-fields/wire.d.ts.map +1 -0
  120. package/dist/modules/custom-fields/wire.js +30 -0
  121. package/dist/modules/custom-fields/wire.js.map +1 -0
  122. package/dist/modules/dashboard/repository.d.ts.map +1 -1
  123. package/dist/modules/dashboard/repository.js +4 -3
  124. package/dist/modules/dashboard/repository.js.map +1 -1
  125. package/dist/modules/deals/index.d.ts +2 -1
  126. package/dist/modules/deals/index.d.ts.map +1 -1
  127. package/dist/modules/deals/index.js +5 -2
  128. package/dist/modules/deals/index.js.map +1 -1
  129. package/dist/modules/deals/repository.d.ts +0 -16
  130. package/dist/modules/deals/repository.d.ts.map +1 -1
  131. package/dist/modules/deals/repository.js +6 -76
  132. package/dist/modules/deals/repository.js.map +1 -1
  133. package/dist/modules/deals/routes.d.ts +14 -0
  134. package/dist/modules/deals/routes.d.ts.map +1 -1
  135. package/dist/modules/deals/routes.js +7 -0
  136. package/dist/modules/deals/routes.js.map +1 -1
  137. package/dist/modules/deals/schema.d.ts +20 -42
  138. package/dist/modules/deals/schema.d.ts.map +1 -1
  139. package/dist/modules/deals/schema.js +6 -11
  140. package/dist/modules/deals/schema.js.map +1 -1
  141. package/dist/modules/deals/service.d.ts +13 -2
  142. package/dist/modules/deals/service.d.ts.map +1 -1
  143. package/dist/modules/deals/service.js +43 -20
  144. package/dist/modules/deals/service.js.map +1 -1
  145. package/dist/modules/decisions/repository.d.ts.map +1 -1
  146. package/dist/modules/decisions/repository.js +2 -0
  147. package/dist/modules/decisions/repository.js.map +1 -1
  148. package/dist/modules/decisions/routes.d.ts +1 -0
  149. package/dist/modules/decisions/routes.d.ts.map +1 -1
  150. package/dist/modules/enquiries/events.d.ts +44 -0
  151. package/dist/modules/enquiries/events.d.ts.map +1 -0
  152. package/dist/modules/enquiries/events.js +19 -0
  153. package/dist/modules/enquiries/events.js.map +1 -0
  154. package/dist/modules/enquiries/index.d.ts +13 -0
  155. package/dist/modules/enquiries/index.d.ts.map +1 -0
  156. package/dist/modules/enquiries/index.js +44 -0
  157. package/dist/modules/enquiries/index.js.map +1 -0
  158. package/dist/modules/enquiries/repository.d.ts +30 -0
  159. package/dist/modules/enquiries/repository.d.ts.map +1 -0
  160. package/dist/modules/enquiries/repository.js +94 -0
  161. package/dist/modules/enquiries/repository.js.map +1 -0
  162. package/dist/modules/enquiries/routes.d.ts +52 -0
  163. package/dist/modules/enquiries/routes.d.ts.map +1 -0
  164. package/dist/modules/enquiries/routes.js +127 -0
  165. package/dist/modules/enquiries/routes.js.map +1 -0
  166. package/dist/modules/enquiries/schema.d.ts +290 -0
  167. package/dist/modules/enquiries/schema.d.ts.map +1 -0
  168. package/dist/modules/enquiries/schema.js +52 -0
  169. package/dist/modules/enquiries/schema.js.map +1 -0
  170. package/dist/modules/enquiries/service.d.ts +85 -0
  171. package/dist/modules/enquiries/service.d.ts.map +1 -0
  172. package/dist/modules/enquiries/service.js +370 -0
  173. package/dist/modules/enquiries/service.js.map +1 -0
  174. package/dist/modules/enquiries/tools.d.ts +4 -0
  175. package/dist/modules/enquiries/tools.d.ts.map +1 -0
  176. package/dist/modules/enquiries/tools.js +50 -0
  177. package/dist/modules/enquiries/tools.js.map +1 -0
  178. package/dist/modules/eventCatalogs.d.ts +3 -0
  179. package/dist/modules/eventCatalogs.d.ts.map +1 -1
  180. package/dist/modules/eventCatalogs.js +3 -0
  181. package/dist/modules/eventCatalogs.js.map +1 -1
  182. package/dist/modules/forms/embed.d.ts +20 -6
  183. package/dist/modules/forms/embed.d.ts.map +1 -1
  184. package/dist/modules/forms/embed.js +359 -43
  185. package/dist/modules/forms/embed.js.map +1 -1
  186. package/dist/modules/forms/events.d.ts +20 -7
  187. package/dist/modules/forms/events.d.ts.map +1 -1
  188. package/dist/modules/forms/events.js +20 -2
  189. package/dist/modules/forms/events.js.map +1 -1
  190. package/dist/modules/forms/fields.d.ts +14 -1
  191. package/dist/modules/forms/fields.d.ts.map +1 -1
  192. package/dist/modules/forms/fields.js +87 -3
  193. package/dist/modules/forms/fields.js.map +1 -1
  194. package/dist/modules/forms/index.d.ts.map +1 -1
  195. package/dist/modules/forms/index.js +12 -1
  196. package/dist/modules/forms/index.js.map +1 -1
  197. package/dist/modules/forms/mapping.d.ts +62 -5
  198. package/dist/modules/forms/mapping.d.ts.map +1 -1
  199. package/dist/modules/forms/mapping.js +139 -5
  200. package/dist/modules/forms/mapping.js.map +1 -1
  201. package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
  202. package/dist/modules/forms/publicRoutes.js +29 -1
  203. package/dist/modules/forms/publicRoutes.js.map +1 -1
  204. package/dist/modules/forms/repository.d.ts +31 -0
  205. package/dist/modules/forms/repository.d.ts.map +1 -1
  206. package/dist/modules/forms/repository.js +90 -1
  207. package/dist/modules/forms/repository.js.map +1 -1
  208. package/dist/modules/forms/routes.d.ts +83 -1
  209. package/dist/modules/forms/routes.d.ts.map +1 -1
  210. package/dist/modules/forms/routes.js +185 -2
  211. package/dist/modules/forms/routes.js.map +1 -1
  212. package/dist/modules/forms/schema.d.ts +672 -1
  213. package/dist/modules/forms/schema.d.ts.map +1 -1
  214. package/dist/modules/forms/schema.js +146 -3
  215. package/dist/modules/forms/schema.js.map +1 -1
  216. package/dist/modules/forms/service.d.ts +54 -1
  217. package/dist/modules/forms/service.d.ts.map +1 -1
  218. package/dist/modules/forms/service.js +338 -28
  219. package/dist/modules/forms/service.js.map +1 -1
  220. package/dist/modules/forms/submission.d.ts +15 -0
  221. package/dist/modules/forms/submission.d.ts.map +1 -1
  222. package/dist/modules/forms/submission.js +418 -40
  223. package/dist/modules/forms/submission.js.map +1 -1
  224. package/dist/modules/import-export/drafts.d.ts +10 -0
  225. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  226. package/dist/modules/import-export/drafts.js +16 -2
  227. package/dist/modules/import-export/drafts.js.map +1 -1
  228. package/dist/modules/import-export/exportRows.d.ts +7 -4
  229. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  230. package/dist/modules/import-export/exportRows.js +20 -5
  231. package/dist/modules/import-export/exportRows.js.map +1 -1
  232. package/dist/modules/import-export/plan.d.ts +12 -1
  233. package/dist/modules/import-export/plan.d.ts.map +1 -1
  234. package/dist/modules/import-export/plan.js +29 -2
  235. package/dist/modules/import-export/plan.js.map +1 -1
  236. package/dist/modules/import-export/presets.d.ts.map +1 -1
  237. package/dist/modules/import-export/presets.js +10 -0
  238. package/dist/modules/import-export/presets.js.map +1 -1
  239. package/dist/modules/import-export/repository.d.ts +11 -1
  240. package/dist/modules/import-export/repository.d.ts.map +1 -1
  241. package/dist/modules/import-export/repository.js +42 -9
  242. package/dist/modules/import-export/repository.js.map +1 -1
  243. package/dist/modules/import-export/routes.d.ts.map +1 -1
  244. package/dist/modules/import-export/routes.js +4 -0
  245. package/dist/modules/import-export/routes.js.map +1 -1
  246. package/dist/modules/import-export/schema.d.ts +17 -0
  247. package/dist/modules/import-export/schema.d.ts.map +1 -1
  248. package/dist/modules/import-export/schema.js +11 -0
  249. package/dist/modules/import-export/schema.js.map +1 -1
  250. package/dist/modules/import-export/service.d.ts +6 -0
  251. package/dist/modules/import-export/service.d.ts.map +1 -1
  252. package/dist/modules/import-export/service.js +14 -2
  253. package/dist/modules/import-export/service.js.map +1 -1
  254. package/dist/modules/import-export/streams.d.ts.map +1 -1
  255. package/dist/modules/import-export/streams.js +3 -3
  256. package/dist/modules/import-export/streams.js.map +1 -1
  257. package/dist/modules/import-export/tools.d.ts.map +1 -1
  258. package/dist/modules/import-export/tools.js +8 -0
  259. package/dist/modules/import-export/tools.js.map +1 -1
  260. package/dist/modules/import-export/validation.d.ts.map +1 -1
  261. package/dist/modules/import-export/validation.js +22 -1
  262. package/dist/modules/import-export/validation.js.map +1 -1
  263. package/dist/modules/import-export/writes.d.ts.map +1 -1
  264. package/dist/modules/import-export/writes.js +37 -4
  265. package/dist/modules/import-export/writes.js.map +1 -1
  266. package/dist/modules/lists/index.d.ts +38 -0
  267. package/dist/modules/lists/index.d.ts.map +1 -1
  268. package/dist/modules/lists/index.js +27 -0
  269. package/dist/modules/lists/index.js.map +1 -1
  270. package/dist/modules/lists/repository.d.ts +26 -0
  271. package/dist/modules/lists/repository.d.ts.map +1 -1
  272. package/dist/modules/lists/repository.js +32 -0
  273. package/dist/modules/lists/repository.js.map +1 -1
  274. package/dist/modules/lists/routes.d.ts +4 -0
  275. package/dist/modules/lists/routes.d.ts.map +1 -1
  276. package/dist/modules/lists/routes.js +8 -0
  277. package/dist/modules/lists/routes.js.map +1 -1
  278. package/dist/modules/lists/schema.d.ts +17 -0
  279. package/dist/modules/lists/schema.d.ts.map +1 -1
  280. package/dist/modules/lists/schema.js +10 -0
  281. package/dist/modules/lists/schema.js.map +1 -1
  282. package/dist/modules/lists/service.d.ts +14 -2
  283. package/dist/modules/lists/service.d.ts.map +1 -1
  284. package/dist/modules/lists/service.js +55 -7
  285. package/dist/modules/lists/service.js.map +1 -1
  286. package/dist/modules/mcp/index.d.ts.map +1 -1
  287. package/dist/modules/mcp/index.js +5 -0
  288. package/dist/modules/mcp/index.js.map +1 -1
  289. package/dist/modules/notes/routes.d.ts +1 -0
  290. package/dist/modules/notes/routes.d.ts.map +1 -1
  291. package/dist/modules/opportunities/index.d.ts.map +1 -1
  292. package/dist/modules/opportunities/index.js +3 -1
  293. package/dist/modules/opportunities/index.js.map +1 -1
  294. package/dist/modules/opportunities/repository.d.ts +2 -0
  295. package/dist/modules/opportunities/repository.d.ts.map +1 -1
  296. package/dist/modules/opportunities/repository.js +4 -0
  297. package/dist/modules/opportunities/repository.js.map +1 -1
  298. package/dist/modules/opportunities/routes.d.ts +16 -0
  299. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  300. package/dist/modules/opportunities/routes.js +13 -0
  301. package/dist/modules/opportunities/routes.js.map +1 -1
  302. package/dist/modules/opportunities/schema.d.ts +20 -0
  303. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  304. package/dist/modules/opportunities/schema.js +6 -1
  305. package/dist/modules/opportunities/schema.js.map +1 -1
  306. package/dist/modules/opportunities/service.d.ts +20 -3
  307. package/dist/modules/opportunities/service.d.ts.map +1 -1
  308. package/dist/modules/opportunities/service.js +99 -18
  309. package/dist/modules/opportunities/service.js.map +1 -1
  310. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  311. package/dist/modules/opportunities/tools.js +2 -0
  312. package/dist/modules/opportunities/tools.js.map +1 -1
  313. package/dist/modules/partnerships/index.d.ts.map +1 -1
  314. package/dist/modules/partnerships/index.js +3 -1
  315. package/dist/modules/partnerships/index.js.map +1 -1
  316. package/dist/modules/partnerships/repository.d.ts +0 -17
  317. package/dist/modules/partnerships/repository.d.ts.map +1 -1
  318. package/dist/modules/partnerships/repository.js +6 -82
  319. package/dist/modules/partnerships/repository.js.map +1 -1
  320. package/dist/modules/partnerships/routes.d.ts +14 -0
  321. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  322. package/dist/modules/partnerships/routes.js +7 -0
  323. package/dist/modules/partnerships/routes.js.map +1 -1
  324. package/dist/modules/partnerships/schema.d.ts +20 -41
  325. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  326. package/dist/modules/partnerships/schema.js +6 -10
  327. package/dist/modules/partnerships/schema.js.map +1 -1
  328. package/dist/modules/partnerships/service.d.ts +11 -1
  329. package/dist/modules/partnerships/service.d.ts.map +1 -1
  330. package/dist/modules/partnerships/service.js +43 -20
  331. package/dist/modules/partnerships/service.js.map +1 -1
  332. package/dist/modules/people/consentHydration.d.ts +26 -0
  333. package/dist/modules/people/consentHydration.d.ts.map +1 -0
  334. package/dist/modules/people/consentHydration.js +100 -0
  335. package/dist/modules/people/consentHydration.js.map +1 -0
  336. package/dist/modules/people/index.d.ts.map +1 -1
  337. package/dist/modules/people/index.js +3 -1
  338. package/dist/modules/people/index.js.map +1 -1
  339. package/dist/modules/people/personConsentWrites.d.ts +40 -0
  340. package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
  341. package/dist/modules/people/personConsentWrites.js +98 -0
  342. package/dist/modules/people/personConsentWrites.js.map +1 -0
  343. package/dist/modules/people/repository.d.ts.map +1 -1
  344. package/dist/modules/people/repository.js +5 -1
  345. package/dist/modules/people/repository.js.map +1 -1
  346. package/dist/modules/people/routes.d.ts +57 -4
  347. package/dist/modules/people/routes.d.ts.map +1 -1
  348. package/dist/modules/people/routes.js +104 -5
  349. package/dist/modules/people/routes.js.map +1 -1
  350. package/dist/modules/people/schema.d.ts +366 -1
  351. package/dist/modules/people/schema.d.ts.map +1 -1
  352. package/dist/modules/people/schema.js +92 -2
  353. package/dist/modules/people/schema.js.map +1 -1
  354. package/dist/modules/people/service.d.ts +30 -1
  355. package/dist/modules/people/service.d.ts.map +1 -1
  356. package/dist/modules/people/service.js +115 -38
  357. package/dist/modules/people/service.js.map +1 -1
  358. package/dist/modules/people/tools.d.ts.map +1 -1
  359. package/dist/modules/people/tools.js +4 -1
  360. package/dist/modules/people/tools.js.map +1 -1
  361. package/dist/modules/personLinks.d.ts +79 -0
  362. package/dist/modules/personLinks.d.ts.map +1 -0
  363. package/dist/modules/personLinks.js +155 -0
  364. package/dist/modules/personLinks.js.map +1 -0
  365. package/dist/modules/pipelines/routes.d.ts +1 -0
  366. package/dist/modules/pipelines/routes.d.ts.map +1 -1
  367. package/dist/modules/plans/routes.d.ts +1 -0
  368. package/dist/modules/plans/routes.d.ts.map +1 -1
  369. package/dist/modules/raises/index.d.ts.map +1 -1
  370. package/dist/modules/raises/index.js +3 -1
  371. package/dist/modules/raises/index.js.map +1 -1
  372. package/dist/modules/raises/repository.d.ts +0 -17
  373. package/dist/modules/raises/repository.d.ts.map +1 -1
  374. package/dist/modules/raises/repository.js +6 -77
  375. package/dist/modules/raises/repository.js.map +1 -1
  376. package/dist/modules/raises/routes.d.ts +14 -0
  377. package/dist/modules/raises/routes.d.ts.map +1 -1
  378. package/dist/modules/raises/routes.js +7 -0
  379. package/dist/modules/raises/routes.js.map +1 -1
  380. package/dist/modules/raises/schema.d.ts +20 -41
  381. package/dist/modules/raises/schema.d.ts.map +1 -1
  382. package/dist/modules/raises/schema.js +6 -10
  383. package/dist/modules/raises/schema.js.map +1 -1
  384. package/dist/modules/raises/service.d.ts +11 -1
  385. package/dist/modules/raises/service.d.ts.map +1 -1
  386. package/dist/modules/raises/service.js +41 -18
  387. package/dist/modules/raises/service.js.map +1 -1
  388. package/dist/modules/recordTargets.d.ts.map +1 -1
  389. package/dist/modules/recordTargets.js +2 -0
  390. package/dist/modules/recordTargets.js.map +1 -1
  391. package/dist/modules/references.d.ts +10 -0
  392. package/dist/modules/references.d.ts.map +1 -1
  393. package/dist/modules/references.js +27 -4
  394. package/dist/modules/references.js.map +1 -1
  395. package/dist/modules/sample-data/fixture.d.ts +21 -0
  396. package/dist/modules/sample-data/fixture.d.ts.map +1 -1
  397. package/dist/modules/sample-data/fixture.js +40 -0
  398. package/dist/modules/sample-data/fixture.js.map +1 -1
  399. package/dist/modules/sample-data/index.d.ts.map +1 -1
  400. package/dist/modules/sample-data/index.js +1 -0
  401. package/dist/modules/sample-data/index.js.map +1 -1
  402. package/dist/modules/sample-data/routes.d.ts.map +1 -1
  403. package/dist/modules/sample-data/routes.js +1 -0
  404. package/dist/modules/sample-data/routes.js.map +1 -1
  405. package/dist/modules/sample-data/service.d.ts +1 -0
  406. package/dist/modules/sample-data/service.d.ts.map +1 -1
  407. package/dist/modules/sample-data/service.js +77 -8
  408. package/dist/modules/sample-data/service.js.map +1 -1
  409. package/dist/modules/search/index.d.ts +1 -1
  410. package/dist/modules/search/index.d.ts.map +1 -1
  411. package/dist/modules/search/index.js +2 -1
  412. package/dist/modules/search/index.js.map +1 -1
  413. package/dist/modules/search/repository.d.ts +1 -0
  414. package/dist/modules/search/repository.d.ts.map +1 -1
  415. package/dist/modules/search/repository.js +23 -0
  416. package/dist/modules/search/repository.js.map +1 -1
  417. package/dist/modules/search/service.d.ts +3 -3
  418. package/dist/modules/search/service.d.ts.map +1 -1
  419. package/dist/modules/search/service.js +5 -4
  420. package/dist/modules/search/service.js.map +1 -1
  421. package/dist/modules/stagedRecords.d.ts +3 -3
  422. package/dist/modules/stagedRecords.d.ts.map +1 -1
  423. package/dist/modules/stagedRecords.js +9 -0
  424. package/dist/modules/stagedRecords.js.map +1 -1
  425. package/dist/modules/webhooks/payloads.d.ts.map +1 -1
  426. package/dist/modules/webhooks/payloads.js +15 -2
  427. package/dist/modules/webhooks/payloads.js.map +1 -1
  428. package/dist/modules/workspace/repository.d.ts +2 -0
  429. package/dist/modules/workspace/repository.d.ts.map +1 -1
  430. package/dist/modules/workspace/repository.js +7 -0
  431. package/dist/modules/workspace/repository.js.map +1 -1
  432. package/dist/modules/workspace/service.d.ts.map +1 -1
  433. package/dist/modules/workspace/service.js +10 -0
  434. package/dist/modules/workspace/service.js.map +1 -1
  435. package/dist/modules/workspace/starters.d.ts.map +1 -1
  436. package/dist/modules/workspace/starters.js +5 -0
  437. package/dist/modules/workspace/starters.js.map +1 -1
  438. package/dist/runtime/events.d.ts +1 -1
  439. package/dist/runtime/events.d.ts.map +1 -1
  440. package/dist/runtime/events.js +1 -0
  441. package/dist/runtime/events.js.map +1 -1
  442. package/dist/schema/index.d.ts +3 -0
  443. package/dist/schema/index.d.ts.map +1 -1
  444. package/dist/schema/index.js +3 -0
  445. package/dist/schema/index.js.map +1 -1
  446. package/dist/testing/database.d.ts +5 -1
  447. package/dist/testing/database.d.ts.map +1 -1
  448. package/dist/testing/database.js +81 -10
  449. package/dist/testing/database.js.map +1 -1
  450. package/migrations/0024_third_king_cobra.sql +46 -0
  451. package/migrations/0025_worthless_chimera.sql +3 -0
  452. package/migrations/0026_late_aqueduct.sql +46 -0
  453. package/migrations/0027_brainy_silver_sable.sql +3 -0
  454. package/migrations/0028_freezing_scrambler.sql +19 -0
  455. package/migrations/0029_custom_fields.sql +26 -0
  456. package/migrations/0030_enquiries.sql +79 -0
  457. package/migrations/0031_consent.sql +45 -0
  458. package/migrations/0032_form_field_statement.sql +1 -0
  459. package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
  460. package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
  461. package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
  462. package/migrations/0036_form_field_notice_type.sql +2 -0
  463. package/migrations/meta/0024_snapshot.json +5516 -0
  464. package/migrations/meta/0025_snapshot.json +5336 -0
  465. package/migrations/meta/0026_snapshot.json +5710 -0
  466. package/migrations/meta/0027_snapshot.json +5716 -0
  467. package/migrations/meta/0028_snapshot.json +5740 -0
  468. package/migrations/meta/0029_snapshot.json +5935 -0
  469. package/migrations/meta/0030_snapshot.json +6245 -0
  470. package/migrations/meta/0031_snapshot.json +6572 -0
  471. package/migrations/meta/0032_snapshot.json +6578 -0
  472. package/migrations/meta/0033_snapshot.json +6572 -0
  473. package/migrations/meta/0034_snapshot.json +6566 -0
  474. package/migrations/meta/0035_snapshot.json +6573 -0
  475. package/migrations/meta/0036_snapshot.json +6573 -0
  476. package/migrations/meta/_journal.json +91 -0
  477. package/package.json +2 -2
  478. package/src/index.ts +6 -0
  479. package/src/lib/ids.ts +11 -0
  480. package/src/modules/activities/repository.ts +22 -23
  481. package/src/modules/activities/wording.ts +18 -0
  482. package/src/modules/agent-tasks/catalog.ts +63 -0
  483. package/src/modules/agent-tasks/resolve.ts +64 -24
  484. package/src/modules/attachedRecords.ts +29 -2
  485. package/src/modules/companies/index.ts +3 -1
  486. package/src/modules/companies/routes.ts +7 -0
  487. package/src/modules/companies/schema.ts +7 -1
  488. package/src/modules/companies/service.ts +48 -13
  489. package/src/modules/consent-purposes/capabilities.ts +12 -0
  490. package/src/modules/consent-purposes/events.ts +38 -0
  491. package/src/modules/consent-purposes/index.ts +48 -0
  492. package/src/modules/consent-purposes/repository.ts +163 -0
  493. package/src/modules/consent-purposes/routes.ts +122 -0
  494. package/src/modules/consent-purposes/schema.ts +46 -0
  495. package/src/modules/consent-purposes/service.ts +423 -0
  496. package/src/modules/consent-purposes/starters.ts +32 -0
  497. package/src/modules/consent-purposes/tools.ts +44 -0
  498. package/src/modules/core.ts +10 -0
  499. package/src/modules/custom-fields/capabilities.ts +17 -0
  500. package/src/modules/custom-fields/events.ts +51 -0
  501. package/src/modules/custom-fields/index.ts +61 -0
  502. package/src/modules/custom-fields/repository.ts +225 -0
  503. package/src/modules/custom-fields/routes.ts +155 -0
  504. package/src/modules/custom-fields/schema.ts +61 -0
  505. package/src/modules/custom-fields/service.ts +439 -0
  506. package/src/modules/custom-fields/tools.ts +53 -0
  507. package/src/modules/custom-fields/values.ts +352 -0
  508. package/src/modules/custom-fields/wire.ts +32 -0
  509. package/src/modules/dashboard/repository.ts +4 -3
  510. package/src/modules/deals/index.ts +5 -2
  511. package/src/modules/deals/repository.ts +6 -106
  512. package/src/modules/deals/routes.ts +7 -0
  513. package/src/modules/deals/schema.ts +7 -15
  514. package/src/modules/deals/service.ts +92 -23
  515. package/src/modules/decisions/repository.ts +2 -0
  516. package/src/modules/enquiries/events.ts +45 -0
  517. package/src/modules/enquiries/index.ts +50 -0
  518. package/src/modules/enquiries/repository.ts +164 -0
  519. package/src/modules/enquiries/routes.ts +172 -0
  520. package/src/modules/enquiries/schema.ts +59 -0
  521. package/src/modules/enquiries/service.ts +644 -0
  522. package/src/modules/enquiries/tools.ts +66 -0
  523. package/src/modules/eventCatalogs.ts +3 -0
  524. package/src/modules/forms/embed.ts +391 -44
  525. package/src/modules/forms/events.ts +30 -2
  526. package/src/modules/forms/fields.ts +102 -2
  527. package/src/modules/forms/index.ts +12 -1
  528. package/src/modules/forms/mapping.ts +183 -6
  529. package/src/modules/forms/publicRoutes.ts +43 -1
  530. package/src/modules/forms/repository.ts +162 -1
  531. package/src/modules/forms/routes.ts +212 -2
  532. package/src/modules/forms/schema.ts +166 -4
  533. package/src/modules/forms/service.ts +565 -41
  534. package/src/modules/forms/submission.ts +718 -44
  535. package/src/modules/import-export/drafts.ts +20 -1
  536. package/src/modules/import-export/exportRows.ts +21 -5
  537. package/src/modules/import-export/plan.ts +47 -2
  538. package/src/modules/import-export/presets.ts +10 -0
  539. package/src/modules/import-export/repository.ts +73 -8
  540. package/src/modules/import-export/routes.ts +4 -0
  541. package/src/modules/import-export/schema.ts +11 -0
  542. package/src/modules/import-export/service.ts +28 -2
  543. package/src/modules/import-export/streams.ts +3 -1
  544. package/src/modules/import-export/tools.ts +10 -0
  545. package/src/modules/import-export/validation.ts +28 -0
  546. package/src/modules/import-export/writes.ts +70 -5
  547. package/src/modules/lists/index.ts +71 -0
  548. package/src/modules/lists/repository.ts +64 -0
  549. package/src/modules/lists/routes.ts +8 -0
  550. package/src/modules/lists/schema.ts +10 -0
  551. package/src/modules/lists/service.ts +110 -9
  552. package/src/modules/mcp/index.ts +5 -0
  553. package/src/modules/opportunities/index.ts +3 -1
  554. package/src/modules/opportunities/repository.ts +11 -0
  555. package/src/modules/opportunities/routes.ts +13 -0
  556. package/src/modules/opportunities/schema.ts +7 -1
  557. package/src/modules/opportunities/service.ts +188 -22
  558. package/src/modules/opportunities/tools.ts +2 -0
  559. package/src/modules/partnerships/index.ts +3 -1
  560. package/src/modules/partnerships/repository.ts +6 -117
  561. package/src/modules/partnerships/routes.ts +7 -0
  562. package/src/modules/partnerships/schema.ts +7 -14
  563. package/src/modules/partnerships/service.ts +93 -22
  564. package/src/modules/people/consentHydration.ts +167 -0
  565. package/src/modules/people/index.ts +3 -1
  566. package/src/modules/people/personConsentWrites.ts +177 -0
  567. package/src/modules/people/repository.ts +5 -0
  568. package/src/modules/people/routes.ts +127 -18
  569. package/src/modules/people/schema.ts +109 -3
  570. package/src/modules/people/service.ts +186 -40
  571. package/src/modules/people/tools.ts +5 -1
  572. package/src/modules/personLinks.ts +278 -0
  573. package/src/modules/raises/index.ts +3 -1
  574. package/src/modules/raises/repository.ts +6 -107
  575. package/src/modules/raises/routes.ts +7 -0
  576. package/src/modules/raises/schema.ts +7 -14
  577. package/src/modules/raises/service.ts +91 -20
  578. package/src/modules/recordTargets.ts +2 -0
  579. package/src/modules/references.ts +43 -4
  580. package/src/modules/sample-data/fixture.ts +63 -0
  581. package/src/modules/sample-data/index.ts +1 -0
  582. package/src/modules/sample-data/routes.ts +1 -0
  583. package/src/modules/sample-data/service.ts +97 -8
  584. package/src/modules/search/index.ts +2 -1
  585. package/src/modules/search/repository.ts +33 -1
  586. package/src/modules/search/service.ts +7 -5
  587. package/src/modules/stagedRecords.ts +18 -3
  588. package/src/modules/webhooks/payloads.ts +20 -2
  589. package/src/modules/workspace/repository.ts +12 -0
  590. package/src/modules/workspace/service.ts +14 -0
  591. package/src/modules/workspace/starters.ts +5 -0
  592. package/src/runtime/events.ts +1 -0
  593. package/src/schema/index.ts +3 -0
  594. package/src/testing/database.ts +97 -11
@@ -7,11 +7,14 @@ import type { ActivityRecorder } from '../activities/recorder.ts'
7
7
  import { describeCreationVia, describeLink, describeUpdateVia } from '../activities/wording.ts'
8
8
  import type { Actor } from '../auth/actor.ts'
9
9
  import * as companyRepository from '../companies/repository.ts'
10
+ import * as consentPurposesRepository from '../consent-purposes/repository.ts'
10
11
  import * as dealRepository from '../deals/repository.ts'
11
12
  import * as peopleRepository from '../people/repository.ts'
13
+ import { upsertPersonConsent } from '../people/personConsentWrites.ts'
14
+ import * as personLinks from '../personLinks.ts'
12
15
  import * as positionRepository from '../positions/repository.ts'
13
16
  import { IMPORT_DEAL_CURRENCY, NEW_COMPANY_DEFAULTS, NEW_PERSON_DEFAULTS } from './drafts.ts'
14
- import type { ImportWrite, PlannedAffiliation, RowPlan } from './plan.ts'
17
+ import type { ImportConsentGrant, ImportWrite, PlannedAffiliation, RowPlan } from './plan.ts'
15
18
 
16
19
  /**
17
20
  * Applying one planned row: the insert or update, and the timeline entry that
@@ -220,6 +223,9 @@ async function writePerson(
220
223
  tags: write.draft.tags === undefined ? undefined : [...write.draft.tags],
221
224
  id: dependencies.createId('person'),
222
225
  workspaceId,
226
+ // `name` is not a required column any more; the People row check is what
227
+ // guarantees one, from the row's own `name` or composed from its first and
228
+ // last name cells. A row reaching here without one never passed validation.
223
229
  name: write.draft.name ?? '',
224
230
  })
225
231
 
@@ -228,6 +234,10 @@ async function writePerson(
228
234
  ? []
229
235
  : await applyAffiliation(dependencies, created.id, write.affiliation)
230
236
 
237
+ if (write.consent !== undefined) {
238
+ await applyImportConsent(dependencies, created.id, write.consent)
239
+ }
240
+
231
241
  return { recordId: created.id, objectType: 'person', changedFields: [], sideRecords }
232
242
  }
233
243
 
@@ -257,9 +267,51 @@ async function writePerson(
257
267
  ? []
258
268
  : await applyAffiliation(dependencies, id, write.affiliation)
259
269
 
270
+ if (write.consent !== undefined) {
271
+ await applyImportConsent(dependencies, id, write.consent)
272
+ }
273
+
260
274
  return { recordId: id, objectType: 'person', changedFields, sideRecords }
261
275
  }
262
276
 
277
+ /**
278
+ * Applies the row's consent grant against the job's purpose. The purpose is
279
+ * looked up once per call rather than cached across rows — a commit runs one
280
+ * transaction and one row at a time — so the round trip is small and stays
281
+ * consistent with the current transaction's view.
282
+ */
283
+ async function applyImportConsent(
284
+ dependencies: WriteDependencies,
285
+ personId: string,
286
+ consent: ImportConsentGrant,
287
+ ): Promise<void> {
288
+ const [purpose] = await consentPurposesRepository.listPurposesByIds(
289
+ dependencies.tx,
290
+ dependencies.workspaceId,
291
+ [consent.purposeId],
292
+ )
293
+ if (purpose === undefined) return
294
+ const notedAt = consent.notedAt === null ? dependencies.now : new Date(`${consent.notedAt}T00:00:00Z`)
295
+ await upsertPersonConsent(
296
+ dependencies.tx,
297
+ dependencies.workspaceId,
298
+ personId,
299
+ consent.purposeId,
300
+ purpose.slug,
301
+ purpose.label,
302
+ consent.status,
303
+ 'import',
304
+ notedAt,
305
+ )
306
+ await dependencies.recordActivity(dependencies.tx, dependencies.workspaceId, dependencies.actor, {
307
+ targetType: 'person',
308
+ targetId: personId,
309
+ kind: 'updated',
310
+ action: `${consent.status === 'granted' ? 'granted' : 'withdrew'} ${purpose.label} consent via ${dependencies.sourceName}`,
311
+ detail: null,
312
+ })
313
+ }
314
+
263
315
  /**
264
316
  * A Position's only writable field is its title, so an update is a rename.
265
317
  *
@@ -318,12 +370,19 @@ async function reconcileDealPeople(
318
370
  dealId: string,
319
371
  personIds: readonly string[],
320
372
  ): Promise<boolean> {
321
- const current = await dealRepository.listPersonIds(dependencies.tx, dealId)
373
+ const target = { targetType: 'deal' as const, targetId: dealId }
374
+ const current = await personLinks.listPersonIds(dependencies.tx, dependencies.workspaceId, target)
322
375
  const added = personIds.filter((personId) => !current.includes(personId))
323
376
  const removed = current.filter((personId) => !personIds.includes(personId))
324
377
 
325
- await dealRepository.insertDealPeople(dependencies.tx, dealId, added)
326
- await dealRepository.deleteDealPeople(dependencies.tx, dealId, removed)
378
+ await personLinks.linkPeople(
379
+ dependencies.tx,
380
+ dependencies.createId,
381
+ dependencies.workspaceId,
382
+ target,
383
+ added,
384
+ )
385
+ await personLinks.unlinkPeople(dependencies.tx, dependencies.workspaceId, target, removed)
327
386
 
328
387
  return added.length > 0 || removed.length > 0
329
388
  }
@@ -352,7 +411,13 @@ async function writeDeal(
352
411
  // the same way, and no CSV column carries one.
353
412
  currency: IMPORT_DEAL_CURRENCY,
354
413
  })
355
- await dealRepository.insertDealPeople(tx, id, write.personIds)
414
+ await personLinks.linkPeople(
415
+ tx,
416
+ dependencies.createId,
417
+ workspaceId,
418
+ { targetType: 'deal', targetId: id },
419
+ write.personIds,
420
+ )
356
421
 
357
422
  return { recordId: id, objectType: 'deal', changedFields: [] }
358
423
  }
@@ -1,5 +1,11 @@
1
+ import type { EventActor } from '@kelpie/schemas'
2
+
3
+ import type { Database } from '../../lib/database.ts'
1
4
  import type { KelpieModule } from '../../runtime/module.ts'
5
+ import type { TransactionScope } from '../../runtime/transaction.ts'
6
+ import type { RecordTargetType } from '../recordTargets.ts'
2
7
  import { listsEvents } from './events.ts'
8
+ import * as repository from './repository.ts'
3
9
  import { mountListsRoutes } from './routes.ts'
4
10
  import * as schema from './schema.ts'
5
11
  import { createListsService } from './service.ts'
@@ -39,3 +45,68 @@ export function createListsModule(migrationsDirectory: string): KelpieModule {
39
45
  },
40
46
  }
41
47
  }
48
+
49
+ /** Dependencies a caller outside the lists module already holds. */
50
+ export interface RemoveListMemberByTargetDependencies {
51
+ readonly db: Database
52
+ readonly transaction: TransactionScope
53
+ }
54
+
55
+ export interface RemoveListMemberByTargetInput {
56
+ readonly workspaceId: string
57
+ readonly listId: string
58
+ readonly targetType: RecordTargetType
59
+ readonly targetId: string
60
+ /**
61
+ * The event actor to stamp on `lists.member.removed`. An integration webhook
62
+ * that has no signed-in user passes `{ kind: 'system' }`; a module acting on
63
+ * behalf of a user passes `{ kind: 'user', id: userId }`.
64
+ */
65
+ readonly actor: EventActor
66
+ }
67
+
68
+ /**
69
+ * Removes a person (or any record) from a list by target, from outside the lists module.
70
+ *
71
+ * The path an integration takes when a signal from an external system removes
72
+ * membership — a Resend unsubscribe removing the person from every mapped list,
73
+ * a compliance sweep evicting a record — and there is no signed-in user to
74
+ * hang a normal `removeMember(actor, listId, id)` call on. Every safeguard the
75
+ * REST route enforces (workspace membership, ownership of the list, presence
76
+ * of the member row) is skipped here on purpose: the caller has already
77
+ * decided, and the input is trusted because it comes from another module in
78
+ * the same assembly rather than a request body.
79
+ *
80
+ * @returns `true` if the row was on the list and is now gone (emits
81
+ * `lists.member.removed`), `false` if the target was not a member — a no-op
82
+ * so a delivery redelivered by an at-least-once webhook is safe.
83
+ */
84
+ export async function removeListMemberByTarget(
85
+ dependencies: RemoveListMemberByTargetDependencies,
86
+ input: RemoveListMemberByTargetInput,
87
+ ): Promise<boolean> {
88
+ return dependencies.transaction(
89
+ async ({ tx, events }) => {
90
+ const deleted = await repository.deleteListMemberByTarget(
91
+ tx,
92
+ input.workspaceId,
93
+ input.listId,
94
+ input.targetType,
95
+ input.targetId,
96
+ )
97
+
98
+ if (deleted === undefined) {
99
+ return false
100
+ }
101
+
102
+ events.emit(
103
+ 'lists.member.removed',
104
+ { type: input.targetType, id: input.targetId },
105
+ { listId: input.listId },
106
+ )
107
+
108
+ return true
109
+ },
110
+ { workspaceId: input.workspaceId, actor: input.actor },
111
+ )
112
+ }
@@ -103,6 +103,36 @@ export async function findList(
103
103
  return { ...found, memberCount: await countMembers(db, id) }
104
104
  }
105
105
 
106
+ /**
107
+ * Bare list rows for a bulk existence + target-type check, without the
108
+ * member-count round trip `findList` pays for. Used by the forms service to
109
+ * validate `list_ids` at write time in one query rather than N.
110
+ */
111
+ export interface ListIdRow {
112
+ readonly id: string
113
+ readonly targetType: string
114
+ readonly consentPurposeId: string | null
115
+ }
116
+
117
+ export async function listListsById(
118
+ db: Queryable,
119
+ workspaceId: string,
120
+ ids: readonly string[],
121
+ ): Promise<ListIdRow[]> {
122
+ if (ids.length === 0) {
123
+ return []
124
+ }
125
+
126
+ return db
127
+ .select({
128
+ id: lists.id,
129
+ targetType: lists.targetType,
130
+ consentPurposeId: lists.consentPurposeId,
131
+ })
132
+ .from(lists)
133
+ .where(and(eq(lists.workspaceId, workspaceId), inArray(lists.id, ids)))
134
+ }
135
+
106
136
  async function countMembers(db: Queryable, listId: string): Promise<number> {
107
137
  const [row] = await db
108
138
  .select({ count: sql<number>`count(*)::int` })
@@ -240,6 +270,40 @@ export async function deleteListMember(
240
270
  return deleted.length
241
271
  }
242
272
 
273
+ /**
274
+ * Removes the membership that points at a given target, if one is on the list.
275
+ *
276
+ * The addressed-by-target counterpart to `deleteListMember`, which addresses a
277
+ * row by its own id. An inbound integration webhook (Resend unsubscribe, for
278
+ * example) knows the person, not the list_member row that ties them to a list,
279
+ * and reading the row just to delete it is a round trip that adds nothing.
280
+ *
281
+ * @returns The removed row's id, or undefined if no member of that list points
282
+ * at that target — the same shape a caller wanting to decide whether to emit
283
+ * `lists.member.removed` needs.
284
+ */
285
+ export async function deleteListMemberByTarget(
286
+ db: Queryable,
287
+ workspaceId: string,
288
+ listId: string,
289
+ targetType: string,
290
+ targetId: string,
291
+ ): Promise<{ id: string } | undefined> {
292
+ const [deleted] = await db
293
+ .delete(listMembers)
294
+ .where(
295
+ and(
296
+ eq(listMembers.workspaceId, workspaceId),
297
+ eq(listMembers.listId, listId),
298
+ eq(listMembers.targetType, targetType),
299
+ eq(listMembers.targetId, targetId),
300
+ ),
301
+ )
302
+ .returning({ id: listMembers.id })
303
+
304
+ return deleted
305
+ }
306
+
243
307
  /** A membership row enriched with the list it points at. */
244
308
  export interface MembershipWithList {
245
309
  readonly id: string
@@ -31,12 +31,14 @@ 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),
34
35
  })
35
36
 
36
37
  export const updateBody = z
37
38
  .strictObject({
38
39
  name: z.string().min(1),
39
40
  description: z.string().nullable(),
41
+ consent_purpose_id: z.string().min(1).nullable(),
40
42
  })
41
43
  .partial()
42
44
 
@@ -54,6 +56,7 @@ export function toCreateInput(body: z.infer<typeof createBody>): CreateListInput
54
56
  name: body.name,
55
57
  targetType: body.target_type,
56
58
  description: body.description,
59
+ consentPurposeId: body.consent_purpose_id,
57
60
  }
58
61
  }
59
62
 
@@ -61,6 +64,9 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdateListInput
61
64
  return {
62
65
  ...(body.name === undefined ? {} : { name: body.name }),
63
66
  ...(body.description === undefined ? {} : { description: body.description }),
67
+ ...(body.consent_purpose_id === undefined
68
+ ? {}
69
+ : { consentPurposeId: body.consent_purpose_id }),
64
70
  }
65
71
  }
66
72
 
@@ -78,6 +84,8 @@ export function listResponse(list: ListView): Record<string, unknown> {
78
84
  description: list.description,
79
85
  target_type: list.targetType,
80
86
  member_count: list.memberCount,
87
+ consent_purpose_id: list.consentPurposeId,
88
+ consent_purpose_slug: list.consentPurposeSlug,
81
89
  created_at: list.createdAt.toISOString(),
82
90
  updated_at: list.updatedAt.toISOString(),
83
91
  }
@@ -2,6 +2,7 @@ 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'
5
6
  import { workspaces } from '../workspace/schema.ts'
6
7
 
7
8
  /**
@@ -34,6 +35,15 @@ export const lists = pgTable(
34
35
  name: text('name').notNull(),
35
36
  description: text('description'),
36
37
  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
+ }),
37
47
  createdAt: createdAt(),
38
48
  updatedAt: updatedAt(),
39
49
  },
@@ -9,6 +9,7 @@ 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'
12
13
  import { missingTargets, resolveTargetNames, targetKey } from '../recordTargets.ts'
13
14
  import type { RecordTargetType } from '../recordTargets.ts'
14
15
  import './events.ts'
@@ -43,8 +44,14 @@ export interface ListsDependencies {
43
44
  readonly now: () => Date
44
45
  }
45
46
 
46
- /** A list as the API returns one: the stored row minus the tenancy column. */
47
- export type ListView = Omit<ListWithCount, 'workspaceId'>
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
+ }
48
55
 
49
56
  /** A membership plus the list it points at, as `/v1/list-memberships` returns one. */
50
57
  export interface ListMembershipView {
@@ -71,12 +78,18 @@ export interface CreateListInput {
71
78
  readonly name: string
72
79
  readonly targetType: RecordTargetType
73
80
  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
74
86
  }
75
87
 
76
88
  /** PATCH semantics: an absent field is left alone. The type never moves. */
77
89
  export interface UpdateListInput {
78
90
  readonly name?: string | undefined
79
91
  readonly description?: string | null | undefined
92
+ readonly consentPurposeId?: string | null | undefined
80
93
  }
81
94
 
82
95
  export interface AddListMemberInput {
@@ -104,10 +117,10 @@ export interface ListsService {
104
117
  ): Promise<readonly ListMembershipView[]>
105
118
  }
106
119
 
107
- function toView(record: ListWithCount): ListView {
120
+ function toView(record: ListWithCount, consentPurposeSlug: string | null): ListView {
108
121
  const { workspaceId: _workspaceId, ...view } = record
109
122
 
110
- return view
123
+ return { ...view, consentPurposeSlug }
111
124
  }
112
125
 
113
126
  function toMembershipView(row: MembershipWithList): ListMembershipView {
@@ -157,6 +170,13 @@ function alreadyMember(): AppError {
157
170
  ])
158
171
  }
159
172
 
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
+
160
180
  export function createListsService(dependencies: ListsDependencies): ListsService {
161
181
  async function require(workspaceId: string, id: string): Promise<ListWithCount> {
162
182
  const list = await repository.findList(dependencies.db, workspaceId, id)
@@ -180,23 +200,77 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
180
200
  }
181
201
  }
182
202
 
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
+
183
232
  return {
184
233
  async list(actor, filters, query) {
185
234
  const workspaceId = requireWorkspaceId(actor)
186
235
  const window = readListWindow(query, LIST_SORTS, DEFAULT_LIST_SORT)
187
236
  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]))
188
250
 
189
- return mapPage(toPage(rows, window, (row) => row.id), toView)
251
+ return mapPage(toPage(rows, window, (row) => row.id), (row) =>
252
+ toView(row, row.consentPurposeId === null ? null : (slugByPurpose.get(row.consentPurposeId) ?? null)),
253
+ )
190
254
  },
191
255
 
192
256
  async get(actor, id) {
193
- return toView(await require(requireWorkspaceId(actor), id))
257
+ const workspaceId = requireWorkspaceId(actor)
258
+ const record = await require(workspaceId, id)
259
+ const slug = await resolveConsentPurposeSlug(workspaceId, record.consentPurposeId)
260
+ return toView(record, slug)
194
261
  },
195
262
 
196
263
  async create(actor, input) {
197
264
  const workspaceId = requireWorkspaceId(actor)
198
265
  const id = dependencies.createId('list')
199
266
 
267
+ if (input.consentPurposeId !== null) {
268
+ if (input.targetType !== 'person') {
269
+ throw purposeNotPersonList()
270
+ }
271
+ await requireConsentPurposeExists(workspaceId, input.consentPurposeId)
272
+ }
273
+
200
274
  return dependencies.transaction(
201
275
  async ({ tx, events }) => {
202
276
  let created
@@ -207,6 +281,7 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
207
281
  name: input.name,
208
282
  description: input.description,
209
283
  targetType: input.targetType,
284
+ consentPurposeId: input.consentPurposeId,
210
285
  })
211
286
  } catch (error: unknown) {
212
287
  if (postgresErrorCode(error) === UNIQUE_VIOLATION) {
@@ -218,7 +293,12 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
218
293
 
219
294
  events.emit('lists.list.created', { type: 'list', id: created.id }, {})
220
295
 
221
- return toView({ ...created, memberCount: 0 })
296
+ const slug = await resolveConsentPurposeSlug(
297
+ workspaceId,
298
+ created.consentPurposeId,
299
+ )
300
+
301
+ return toView({ ...created, memberCount: 0 }, slug)
222
302
  },
223
303
  { workspaceId, actor: toEventActor(actor) },
224
304
  )
@@ -227,14 +307,33 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
227
307
  async update(actor, id, changes) {
228
308
  const workspaceId = requireWorkspaceId(actor)
229
309
  const existing = await require(workspaceId, id)
310
+
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
+
230
325
  const columns: Partial<repository.ListColumns> = {
231
326
  ...(changes.name === undefined ? {} : { name: changes.name }),
232
327
  ...(changes.description === undefined ? {} : { description: changes.description }),
328
+ ...(changes.consentPurposeId === undefined
329
+ ? {}
330
+ : { consentPurposeId: changes.consentPurposeId }),
233
331
  }
234
332
  const changed = changedKeys(existing, columns)
235
333
 
236
334
  if (changed.length === 0) {
237
- return toView(existing)
335
+ const slug = await resolveConsentPurposeSlug(workspaceId, existing.consentPurposeId)
336
+ return toView(existing, slug)
238
337
  }
239
338
 
240
339
  return dependencies.transaction(
@@ -259,7 +358,9 @@ export function createListsService(dependencies: ListsDependencies): ListsServic
259
358
 
260
359
  events.emit('lists.list.updated', { type: 'list', id }, { changed })
261
360
 
262
- return toView({ ...updated, memberCount: existing.memberCount })
361
+ const slug = await resolveConsentPurposeSlug(workspaceId, updated.consentPurposeId)
362
+
363
+ return toView({ ...updated, memberCount: existing.memberCount }, slug)
263
364
  },
264
365
  { workspaceId, actor: toEventActor(actor) },
265
366
  )
@@ -44,6 +44,11 @@ export const MCP_INSTRUCTIONS = [
44
44
  '- The handbook holds voice, ICP, and how this company sells. Read handbook_pages_list',
45
45
  ' before writing anything a customer will see.',
46
46
  '- A job title belongs to a position, not a person. A person may hold several.',
47
+ '- A person has one name, which is what to call them and what every list shows.',
48
+ ' first_name, last_name, salutation and suffix are optional detail beside it. Send',
49
+ ' the parts when you know them; people_create composes a name from first_name and',
50
+ ' last_name when you send no name. Never split a name into parts yourself, and note',
51
+ ' that changing a part does not rename the person — send name to do that.',
47
52
  '- Next steps are plan_items with a date and an owner, not prose in a summary field.',
48
53
  ].join('\n')
49
54
 
@@ -1,5 +1,6 @@
1
1
  import type { KelpieModule } from '../../runtime/module.ts'
2
2
  import { createActivityRecorder } from '../activities/index.ts'
3
+ import { createCustomFieldValues } from '../custom-fields/index.ts'
3
4
  import { opportunitiesEvents } from './events.ts'
4
5
  import { mountOpportunitiesRoutes } from './routes.ts'
5
6
  import * as schema from './schema.ts'
@@ -17,7 +18,7 @@ import { registerOpportunitiesTools } from './tools.ts'
17
18
  export function createOpportunitiesModule(migrationsDirectory: string): KelpieModule {
18
19
  return {
19
20
  id: 'opportunities',
20
- requires: ['companies', 'pipelines', 'activities'],
21
+ requires: ['companies', 'pipelines', 'activities', 'custom-fields'],
21
22
  events: opportunitiesEvents,
22
23
 
23
24
  register(context) {
@@ -30,6 +31,7 @@ export function createOpportunitiesModule(migrationsDirectory: string): KelpieMo
30
31
  createId: context.createId,
31
32
  now: context.now,
32
33
  }),
34
+ customFields: createCustomFieldValues({ db: context.db }),
33
35
  })
34
36
 
35
37
  context.schema(schema, migrationsDirectory)
@@ -6,6 +6,7 @@ import type { ListWindow, SortableFields } from '../../lib/pagination.ts'
6
6
  import { arrayContainsPattern, containsPattern } from '../../lib/search.ts'
7
7
  import type { Queryable } from '../../runtime/transaction.ts'
8
8
  import { companies } from '../companies/schema.ts'
9
+ import { anyPersonLinked } from '../personLinks.ts'
9
10
  import { workspaceMembers } from '../workspace/schema.ts'
10
11
  import { opportunities } from './schema.ts'
11
12
 
@@ -32,6 +33,8 @@ export interface OpportunityFilters {
32
33
  readonly companyIds?: readonly string[] | undefined
33
34
  /** `?stage_id=`, repeatable: the board fetches one column with one of these. */
34
35
  readonly stageIds?: readonly string[] | undefined
36
+ /** `?person_id=`, repeatable: opportunities any of these people are on. */
37
+ readonly personIds?: readonly string[] | undefined
35
38
  }
36
39
 
37
40
  /**
@@ -69,6 +72,14 @@ function conditionsFor(workspaceId: string, filters: OpportunityFilters): (SQL |
69
72
  ? undefined
70
73
  : inArray(opportunities.companyId, filters.companyIds),
71
74
  filters.stageIds === undefined ? undefined : inArray(opportunities.stageId, filters.stageIds),
75
+ filters.personIds === undefined
76
+ ? undefined
77
+ : anyPersonLinked(
78
+ 'opportunity',
79
+ opportunities.id,
80
+ opportunities.workspaceId,
81
+ filters.personIds,
82
+ ),
72
83
  ]
73
84
  }
74
85