@kelpie/server 0.8.0 → 0.9.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 (584) hide show
  1. package/dist/lib/ids.d.ts +11 -0
  2. package/dist/lib/ids.d.ts.map +1 -1
  3. package/dist/lib/ids.js +11 -0
  4. package/dist/lib/ids.js.map +1 -1
  5. package/dist/modules/activities/repository.d.ts.map +1 -1
  6. package/dist/modules/activities/repository.js +19 -20
  7. package/dist/modules/activities/repository.js.map +1 -1
  8. package/dist/modules/activities/wording.d.ts +12 -0
  9. package/dist/modules/activities/wording.d.ts.map +1 -1
  10. package/dist/modules/activities/wording.js +16 -0
  11. package/dist/modules/activities/wording.js.map +1 -1
  12. package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
  13. package/dist/modules/agent-tasks/catalog.js +62 -0
  14. package/dist/modules/agent-tasks/catalog.js.map +1 -1
  15. package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
  16. package/dist/modules/agent-tasks/resolve.js +42 -9
  17. package/dist/modules/agent-tasks/resolve.js.map +1 -1
  18. package/dist/modules/agent-tasks/routes.d.ts +2 -0
  19. package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
  20. package/dist/modules/attachedRecords.d.ts +6 -1
  21. package/dist/modules/attachedRecords.d.ts.map +1 -1
  22. package/dist/modules/attachedRecords.js +15 -1
  23. package/dist/modules/attachedRecords.js.map +1 -1
  24. package/dist/modules/companies/index.d.ts.map +1 -1
  25. package/dist/modules/companies/index.js +3 -1
  26. package/dist/modules/companies/index.js.map +1 -1
  27. package/dist/modules/companies/routes.d.ts +14 -0
  28. package/dist/modules/companies/routes.d.ts.map +1 -1
  29. package/dist/modules/companies/routes.js +7 -0
  30. package/dist/modules/companies/routes.js.map +1 -1
  31. package/dist/modules/companies/schema.d.ts +20 -0
  32. package/dist/modules/companies/schema.d.ts.map +1 -1
  33. package/dist/modules/companies/schema.js +6 -1
  34. package/dist/modules/companies/schema.js.map +1 -1
  35. package/dist/modules/companies/service.d.ts +5 -0
  36. package/dist/modules/companies/service.d.ts.map +1 -1
  37. package/dist/modules/companies/service.js +24 -12
  38. package/dist/modules/companies/service.js.map +1 -1
  39. package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
  40. package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
  41. package/dist/modules/consent-purposes/capabilities.js +10 -0
  42. package/dist/modules/consent-purposes/capabilities.js.map +1 -0
  43. package/dist/modules/consent-purposes/events.d.ts +38 -0
  44. package/dist/modules/consent-purposes/events.d.ts.map +1 -0
  45. package/dist/modules/consent-purposes/events.js +17 -0
  46. package/dist/modules/consent-purposes/events.js.map +1 -0
  47. package/dist/modules/consent-purposes/index.d.ts +13 -0
  48. package/dist/modules/consent-purposes/index.d.ts.map +1 -0
  49. package/dist/modules/consent-purposes/index.js +41 -0
  50. package/dist/modules/consent-purposes/index.js.map +1 -0
  51. package/dist/modules/consent-purposes/repository.d.ts +21 -0
  52. package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
  53. package/dist/modules/consent-purposes/repository.js +98 -0
  54. package/dist/modules/consent-purposes/repository.js.map +1 -0
  55. package/dist/modules/consent-purposes/routes.d.ts +39 -0
  56. package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
  57. package/dist/modules/consent-purposes/routes.js +79 -0
  58. package/dist/modules/consent-purposes/routes.js.map +1 -0
  59. package/dist/modules/consent-purposes/schema.d.ts +175 -0
  60. package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
  61. package/dist/modules/consent-purposes/schema.js +35 -0
  62. package/dist/modules/consent-purposes/schema.js.map +1 -0
  63. package/dist/modules/consent-purposes/service.d.ts +50 -0
  64. package/dist/modules/consent-purposes/service.d.ts.map +1 -0
  65. package/dist/modules/consent-purposes/service.js +263 -0
  66. package/dist/modules/consent-purposes/service.js.map +1 -0
  67. package/dist/modules/consent-purposes/starters.d.ts +17 -0
  68. package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
  69. package/dist/modules/consent-purposes/starters.js +15 -0
  70. package/dist/modules/consent-purposes/starters.js.map +1 -0
  71. package/dist/modules/consent-purposes/tools.d.ts +4 -0
  72. package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
  73. package/dist/modules/consent-purposes/tools.js +29 -0
  74. package/dist/modules/consent-purposes/tools.js.map +1 -0
  75. package/dist/modules/core.d.ts.map +1 -1
  76. package/dist/modules/core.js +10 -0
  77. package/dist/modules/core.js.map +1 -1
  78. package/dist/modules/custom-fields/capabilities.d.ts +12 -0
  79. package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
  80. package/dist/modules/custom-fields/capabilities.js +15 -0
  81. package/dist/modules/custom-fields/capabilities.js.map +1 -0
  82. package/dist/modules/custom-fields/events.d.ts +49 -0
  83. package/dist/modules/custom-fields/events.d.ts.map +1 -0
  84. package/dist/modules/custom-fields/events.js +25 -0
  85. package/dist/modules/custom-fields/events.js.map +1 -0
  86. package/dist/modules/custom-fields/index.d.ts +19 -0
  87. package/dist/modules/custom-fields/index.d.ts.map +1 -0
  88. package/dist/modules/custom-fields/index.js +46 -0
  89. package/dist/modules/custom-fields/index.js.map +1 -0
  90. package/dist/modules/custom-fields/repository.d.ts +37 -0
  91. package/dist/modules/custom-fields/repository.d.ts.map +1 -0
  92. package/dist/modules/custom-fields/repository.js +144 -0
  93. package/dist/modules/custom-fields/repository.js.map +1 -0
  94. package/dist/modules/custom-fields/routes.d.ts +44 -0
  95. package/dist/modules/custom-fields/routes.d.ts.map +1 -0
  96. package/dist/modules/custom-fields/routes.js +103 -0
  97. package/dist/modules/custom-fields/routes.js.map +1 -0
  98. package/dist/modules/custom-fields/schema.d.ts +215 -0
  99. package/dist/modules/custom-fields/schema.d.ts.map +1 -0
  100. package/dist/modules/custom-fields/schema.js +43 -0
  101. package/dist/modules/custom-fields/schema.js.map +1 -0
  102. package/dist/modules/custom-fields/service.d.ts +57 -0
  103. package/dist/modules/custom-fields/service.d.ts.map +1 -0
  104. package/dist/modules/custom-fields/service.js +273 -0
  105. package/dist/modules/custom-fields/service.js.map +1 -0
  106. package/dist/modules/custom-fields/tools.d.ts +4 -0
  107. package/dist/modules/custom-fields/tools.d.ts.map +1 -0
  108. package/dist/modules/custom-fields/tools.js +38 -0
  109. package/dist/modules/custom-fields/tools.js.map +1 -0
  110. package/dist/modules/custom-fields/values.d.ts +49 -0
  111. package/dist/modules/custom-fields/values.d.ts.map +1 -0
  112. package/dist/modules/custom-fields/values.js +249 -0
  113. package/dist/modules/custom-fields/values.js.map +1 -0
  114. package/dist/modules/custom-fields/wire.d.ts +12 -0
  115. package/dist/modules/custom-fields/wire.d.ts.map +1 -0
  116. package/dist/modules/custom-fields/wire.js +30 -0
  117. package/dist/modules/custom-fields/wire.js.map +1 -0
  118. package/dist/modules/dashboard/repository.d.ts.map +1 -1
  119. package/dist/modules/dashboard/repository.js +4 -3
  120. package/dist/modules/dashboard/repository.js.map +1 -1
  121. package/dist/modules/deals/index.d.ts +2 -1
  122. package/dist/modules/deals/index.d.ts.map +1 -1
  123. package/dist/modules/deals/index.js +5 -2
  124. package/dist/modules/deals/index.js.map +1 -1
  125. package/dist/modules/deals/repository.d.ts +0 -16
  126. package/dist/modules/deals/repository.d.ts.map +1 -1
  127. package/dist/modules/deals/repository.js +6 -76
  128. package/dist/modules/deals/repository.js.map +1 -1
  129. package/dist/modules/deals/routes.d.ts +14 -0
  130. package/dist/modules/deals/routes.d.ts.map +1 -1
  131. package/dist/modules/deals/routes.js +7 -0
  132. package/dist/modules/deals/routes.js.map +1 -1
  133. package/dist/modules/deals/schema.d.ts +20 -42
  134. package/dist/modules/deals/schema.d.ts.map +1 -1
  135. package/dist/modules/deals/schema.js +6 -11
  136. package/dist/modules/deals/schema.js.map +1 -1
  137. package/dist/modules/deals/service.d.ts +13 -2
  138. package/dist/modules/deals/service.d.ts.map +1 -1
  139. package/dist/modules/deals/service.js +43 -20
  140. package/dist/modules/deals/service.js.map +1 -1
  141. package/dist/modules/decisions/repository.d.ts.map +1 -1
  142. package/dist/modules/decisions/repository.js +2 -0
  143. package/dist/modules/decisions/repository.js.map +1 -1
  144. package/dist/modules/decisions/routes.d.ts +1 -0
  145. package/dist/modules/decisions/routes.d.ts.map +1 -1
  146. package/dist/modules/enquiries/events.d.ts +44 -0
  147. package/dist/modules/enquiries/events.d.ts.map +1 -0
  148. package/dist/modules/enquiries/events.js +19 -0
  149. package/dist/modules/enquiries/events.js.map +1 -0
  150. package/dist/modules/enquiries/index.d.ts +13 -0
  151. package/dist/modules/enquiries/index.d.ts.map +1 -0
  152. package/dist/modules/enquiries/index.js +44 -0
  153. package/dist/modules/enquiries/index.js.map +1 -0
  154. package/dist/modules/enquiries/repository.d.ts +30 -0
  155. package/dist/modules/enquiries/repository.d.ts.map +1 -0
  156. package/dist/modules/enquiries/repository.js +94 -0
  157. package/dist/modules/enquiries/repository.js.map +1 -0
  158. package/dist/modules/enquiries/routes.d.ts +52 -0
  159. package/dist/modules/enquiries/routes.d.ts.map +1 -0
  160. package/dist/modules/enquiries/routes.js +127 -0
  161. package/dist/modules/enquiries/routes.js.map +1 -0
  162. package/dist/modules/enquiries/schema.d.ts +290 -0
  163. package/dist/modules/enquiries/schema.d.ts.map +1 -0
  164. package/dist/modules/enquiries/schema.js +52 -0
  165. package/dist/modules/enquiries/schema.js.map +1 -0
  166. package/dist/modules/enquiries/service.d.ts +85 -0
  167. package/dist/modules/enquiries/service.d.ts.map +1 -0
  168. package/dist/modules/enquiries/service.js +370 -0
  169. package/dist/modules/enquiries/service.js.map +1 -0
  170. package/dist/modules/enquiries/tools.d.ts +4 -0
  171. package/dist/modules/enquiries/tools.d.ts.map +1 -0
  172. package/dist/modules/enquiries/tools.js +50 -0
  173. package/dist/modules/enquiries/tools.js.map +1 -0
  174. package/dist/modules/eventCatalogs.d.ts +3 -0
  175. package/dist/modules/eventCatalogs.d.ts.map +1 -1
  176. package/dist/modules/eventCatalogs.js +3 -0
  177. package/dist/modules/eventCatalogs.js.map +1 -1
  178. package/dist/modules/forms/embed.d.ts +20 -6
  179. package/dist/modules/forms/embed.d.ts.map +1 -1
  180. package/dist/modules/forms/embed.js +359 -43
  181. package/dist/modules/forms/embed.js.map +1 -1
  182. package/dist/modules/forms/events.d.ts +20 -7
  183. package/dist/modules/forms/events.d.ts.map +1 -1
  184. package/dist/modules/forms/events.js +20 -2
  185. package/dist/modules/forms/events.js.map +1 -1
  186. package/dist/modules/forms/fields.d.ts +14 -1
  187. package/dist/modules/forms/fields.d.ts.map +1 -1
  188. package/dist/modules/forms/fields.js +87 -3
  189. package/dist/modules/forms/fields.js.map +1 -1
  190. package/dist/modules/forms/index.d.ts.map +1 -1
  191. package/dist/modules/forms/index.js +12 -1
  192. package/dist/modules/forms/index.js.map +1 -1
  193. package/dist/modules/forms/mapping.d.ts +62 -5
  194. package/dist/modules/forms/mapping.d.ts.map +1 -1
  195. package/dist/modules/forms/mapping.js +139 -5
  196. package/dist/modules/forms/mapping.js.map +1 -1
  197. package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
  198. package/dist/modules/forms/publicRoutes.js +29 -1
  199. package/dist/modules/forms/publicRoutes.js.map +1 -1
  200. package/dist/modules/forms/repository.d.ts +31 -0
  201. package/dist/modules/forms/repository.d.ts.map +1 -1
  202. package/dist/modules/forms/repository.js +90 -1
  203. package/dist/modules/forms/repository.js.map +1 -1
  204. package/dist/modules/forms/routes.d.ts +83 -1
  205. package/dist/modules/forms/routes.d.ts.map +1 -1
  206. package/dist/modules/forms/routes.js +185 -2
  207. package/dist/modules/forms/routes.js.map +1 -1
  208. package/dist/modules/forms/schema.d.ts +672 -1
  209. package/dist/modules/forms/schema.d.ts.map +1 -1
  210. package/dist/modules/forms/schema.js +146 -3
  211. package/dist/modules/forms/schema.js.map +1 -1
  212. package/dist/modules/forms/service.d.ts +54 -1
  213. package/dist/modules/forms/service.d.ts.map +1 -1
  214. package/dist/modules/forms/service.js +338 -28
  215. package/dist/modules/forms/service.js.map +1 -1
  216. package/dist/modules/forms/submission.d.ts +15 -0
  217. package/dist/modules/forms/submission.d.ts.map +1 -1
  218. package/dist/modules/forms/submission.js +418 -40
  219. package/dist/modules/forms/submission.js.map +1 -1
  220. package/dist/modules/import-export/drafts.d.ts +10 -0
  221. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  222. package/dist/modules/import-export/drafts.js +16 -2
  223. package/dist/modules/import-export/drafts.js.map +1 -1
  224. package/dist/modules/import-export/exportRows.d.ts +7 -4
  225. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  226. package/dist/modules/import-export/exportRows.js +20 -5
  227. package/dist/modules/import-export/exportRows.js.map +1 -1
  228. package/dist/modules/import-export/plan.d.ts +12 -1
  229. package/dist/modules/import-export/plan.d.ts.map +1 -1
  230. package/dist/modules/import-export/plan.js +29 -2
  231. package/dist/modules/import-export/plan.js.map +1 -1
  232. package/dist/modules/import-export/presets.d.ts.map +1 -1
  233. package/dist/modules/import-export/presets.js +10 -0
  234. package/dist/modules/import-export/presets.js.map +1 -1
  235. package/dist/modules/import-export/repository.d.ts +11 -1
  236. package/dist/modules/import-export/repository.d.ts.map +1 -1
  237. package/dist/modules/import-export/repository.js +42 -9
  238. package/dist/modules/import-export/repository.js.map +1 -1
  239. package/dist/modules/import-export/routes.d.ts.map +1 -1
  240. package/dist/modules/import-export/routes.js +4 -0
  241. package/dist/modules/import-export/routes.js.map +1 -1
  242. package/dist/modules/import-export/schema.d.ts +17 -0
  243. package/dist/modules/import-export/schema.d.ts.map +1 -1
  244. package/dist/modules/import-export/schema.js +11 -0
  245. package/dist/modules/import-export/schema.js.map +1 -1
  246. package/dist/modules/import-export/service.d.ts +6 -0
  247. package/dist/modules/import-export/service.d.ts.map +1 -1
  248. package/dist/modules/import-export/service.js +14 -2
  249. package/dist/modules/import-export/service.js.map +1 -1
  250. package/dist/modules/import-export/streams.d.ts.map +1 -1
  251. package/dist/modules/import-export/streams.js +3 -3
  252. package/dist/modules/import-export/streams.js.map +1 -1
  253. package/dist/modules/import-export/tools.d.ts.map +1 -1
  254. package/dist/modules/import-export/tools.js +8 -0
  255. package/dist/modules/import-export/tools.js.map +1 -1
  256. package/dist/modules/import-export/validation.d.ts.map +1 -1
  257. package/dist/modules/import-export/validation.js +22 -1
  258. package/dist/modules/import-export/validation.js.map +1 -1
  259. package/dist/modules/import-export/writes.d.ts.map +1 -1
  260. package/dist/modules/import-export/writes.js +37 -4
  261. package/dist/modules/import-export/writes.js.map +1 -1
  262. package/dist/modules/lists/repository.d.ts +11 -0
  263. package/dist/modules/lists/repository.d.ts.map +1 -1
  264. package/dist/modules/lists/repository.js +13 -0
  265. package/dist/modules/lists/repository.js.map +1 -1
  266. package/dist/modules/lists/routes.d.ts +4 -0
  267. package/dist/modules/lists/routes.d.ts.map +1 -1
  268. package/dist/modules/lists/routes.js +8 -0
  269. package/dist/modules/lists/routes.js.map +1 -1
  270. package/dist/modules/lists/schema.d.ts +17 -0
  271. package/dist/modules/lists/schema.d.ts.map +1 -1
  272. package/dist/modules/lists/schema.js +10 -0
  273. package/dist/modules/lists/schema.js.map +1 -1
  274. package/dist/modules/lists/service.d.ts +14 -2
  275. package/dist/modules/lists/service.d.ts.map +1 -1
  276. package/dist/modules/lists/service.js +55 -7
  277. package/dist/modules/lists/service.js.map +1 -1
  278. package/dist/modules/mcp/index.d.ts.map +1 -1
  279. package/dist/modules/mcp/index.js +5 -0
  280. package/dist/modules/mcp/index.js.map +1 -1
  281. package/dist/modules/notes/routes.d.ts +1 -0
  282. package/dist/modules/notes/routes.d.ts.map +1 -1
  283. package/dist/modules/opportunities/index.d.ts.map +1 -1
  284. package/dist/modules/opportunities/index.js +3 -1
  285. package/dist/modules/opportunities/index.js.map +1 -1
  286. package/dist/modules/opportunities/repository.d.ts +2 -0
  287. package/dist/modules/opportunities/repository.d.ts.map +1 -1
  288. package/dist/modules/opportunities/repository.js +4 -0
  289. package/dist/modules/opportunities/repository.js.map +1 -1
  290. package/dist/modules/opportunities/routes.d.ts +16 -0
  291. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  292. package/dist/modules/opportunities/routes.js +13 -0
  293. package/dist/modules/opportunities/routes.js.map +1 -1
  294. package/dist/modules/opportunities/schema.d.ts +20 -0
  295. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  296. package/dist/modules/opportunities/schema.js +6 -1
  297. package/dist/modules/opportunities/schema.js.map +1 -1
  298. package/dist/modules/opportunities/service.d.ts +20 -3
  299. package/dist/modules/opportunities/service.d.ts.map +1 -1
  300. package/dist/modules/opportunities/service.js +99 -18
  301. package/dist/modules/opportunities/service.js.map +1 -1
  302. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  303. package/dist/modules/opportunities/tools.js +2 -0
  304. package/dist/modules/opportunities/tools.js.map +1 -1
  305. package/dist/modules/partnerships/index.d.ts.map +1 -1
  306. package/dist/modules/partnerships/index.js +3 -1
  307. package/dist/modules/partnerships/index.js.map +1 -1
  308. package/dist/modules/partnerships/repository.d.ts +0 -17
  309. package/dist/modules/partnerships/repository.d.ts.map +1 -1
  310. package/dist/modules/partnerships/repository.js +6 -82
  311. package/dist/modules/partnerships/repository.js.map +1 -1
  312. package/dist/modules/partnerships/routes.d.ts +14 -0
  313. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  314. package/dist/modules/partnerships/routes.js +7 -0
  315. package/dist/modules/partnerships/routes.js.map +1 -1
  316. package/dist/modules/partnerships/schema.d.ts +20 -41
  317. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  318. package/dist/modules/partnerships/schema.js +6 -10
  319. package/dist/modules/partnerships/schema.js.map +1 -1
  320. package/dist/modules/partnerships/service.d.ts +11 -1
  321. package/dist/modules/partnerships/service.d.ts.map +1 -1
  322. package/dist/modules/partnerships/service.js +43 -20
  323. package/dist/modules/partnerships/service.js.map +1 -1
  324. package/dist/modules/people/consentHydration.d.ts +26 -0
  325. package/dist/modules/people/consentHydration.d.ts.map +1 -0
  326. package/dist/modules/people/consentHydration.js +100 -0
  327. package/dist/modules/people/consentHydration.js.map +1 -0
  328. package/dist/modules/people/index.d.ts.map +1 -1
  329. package/dist/modules/people/index.js +3 -1
  330. package/dist/modules/people/index.js.map +1 -1
  331. package/dist/modules/people/personConsentWrites.d.ts +40 -0
  332. package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
  333. package/dist/modules/people/personConsentWrites.js +98 -0
  334. package/dist/modules/people/personConsentWrites.js.map +1 -0
  335. package/dist/modules/people/repository.d.ts.map +1 -1
  336. package/dist/modules/people/repository.js +5 -1
  337. package/dist/modules/people/repository.js.map +1 -1
  338. package/dist/modules/people/routes.d.ts +57 -4
  339. package/dist/modules/people/routes.d.ts.map +1 -1
  340. package/dist/modules/people/routes.js +104 -5
  341. package/dist/modules/people/routes.js.map +1 -1
  342. package/dist/modules/people/schema.d.ts +366 -1
  343. package/dist/modules/people/schema.d.ts.map +1 -1
  344. package/dist/modules/people/schema.js +92 -2
  345. package/dist/modules/people/schema.js.map +1 -1
  346. package/dist/modules/people/service.d.ts +30 -1
  347. package/dist/modules/people/service.d.ts.map +1 -1
  348. package/dist/modules/people/service.js +115 -38
  349. package/dist/modules/people/service.js.map +1 -1
  350. package/dist/modules/people/tools.d.ts.map +1 -1
  351. package/dist/modules/people/tools.js +4 -1
  352. package/dist/modules/people/tools.js.map +1 -1
  353. package/dist/modules/personLinks.d.ts +79 -0
  354. package/dist/modules/personLinks.d.ts.map +1 -0
  355. package/dist/modules/personLinks.js +155 -0
  356. package/dist/modules/personLinks.js.map +1 -0
  357. package/dist/modules/pipelines/routes.d.ts +1 -0
  358. package/dist/modules/pipelines/routes.d.ts.map +1 -1
  359. package/dist/modules/plans/routes.d.ts +1 -0
  360. package/dist/modules/plans/routes.d.ts.map +1 -1
  361. package/dist/modules/raises/index.d.ts.map +1 -1
  362. package/dist/modules/raises/index.js +3 -1
  363. package/dist/modules/raises/index.js.map +1 -1
  364. package/dist/modules/raises/repository.d.ts +0 -17
  365. package/dist/modules/raises/repository.d.ts.map +1 -1
  366. package/dist/modules/raises/repository.js +6 -77
  367. package/dist/modules/raises/repository.js.map +1 -1
  368. package/dist/modules/raises/routes.d.ts +14 -0
  369. package/dist/modules/raises/routes.d.ts.map +1 -1
  370. package/dist/modules/raises/routes.js +7 -0
  371. package/dist/modules/raises/routes.js.map +1 -1
  372. package/dist/modules/raises/schema.d.ts +20 -41
  373. package/dist/modules/raises/schema.d.ts.map +1 -1
  374. package/dist/modules/raises/schema.js +6 -10
  375. package/dist/modules/raises/schema.js.map +1 -1
  376. package/dist/modules/raises/service.d.ts +11 -1
  377. package/dist/modules/raises/service.d.ts.map +1 -1
  378. package/dist/modules/raises/service.js +41 -18
  379. package/dist/modules/raises/service.js.map +1 -1
  380. package/dist/modules/recordTargets.d.ts.map +1 -1
  381. package/dist/modules/recordTargets.js +2 -0
  382. package/dist/modules/recordTargets.js.map +1 -1
  383. package/dist/modules/references.d.ts +10 -0
  384. package/dist/modules/references.d.ts.map +1 -1
  385. package/dist/modules/references.js +27 -4
  386. package/dist/modules/references.js.map +1 -1
  387. package/dist/modules/sample-data/fixture.d.ts +21 -0
  388. package/dist/modules/sample-data/fixture.d.ts.map +1 -1
  389. package/dist/modules/sample-data/fixture.js +40 -0
  390. package/dist/modules/sample-data/fixture.js.map +1 -1
  391. package/dist/modules/sample-data/index.d.ts.map +1 -1
  392. package/dist/modules/sample-data/index.js +1 -0
  393. package/dist/modules/sample-data/index.js.map +1 -1
  394. package/dist/modules/sample-data/routes.d.ts.map +1 -1
  395. package/dist/modules/sample-data/routes.js +1 -0
  396. package/dist/modules/sample-data/routes.js.map +1 -1
  397. package/dist/modules/sample-data/service.d.ts +1 -0
  398. package/dist/modules/sample-data/service.d.ts.map +1 -1
  399. package/dist/modules/sample-data/service.js +77 -8
  400. package/dist/modules/sample-data/service.js.map +1 -1
  401. package/dist/modules/search/index.d.ts +1 -1
  402. package/dist/modules/search/index.d.ts.map +1 -1
  403. package/dist/modules/search/index.js +2 -1
  404. package/dist/modules/search/index.js.map +1 -1
  405. package/dist/modules/search/repository.d.ts +1 -0
  406. package/dist/modules/search/repository.d.ts.map +1 -1
  407. package/dist/modules/search/repository.js +23 -0
  408. package/dist/modules/search/repository.js.map +1 -1
  409. package/dist/modules/search/service.d.ts +3 -3
  410. package/dist/modules/search/service.d.ts.map +1 -1
  411. package/dist/modules/search/service.js +5 -4
  412. package/dist/modules/search/service.js.map +1 -1
  413. package/dist/modules/stagedRecords.d.ts +3 -3
  414. package/dist/modules/stagedRecords.d.ts.map +1 -1
  415. package/dist/modules/stagedRecords.js +9 -0
  416. package/dist/modules/stagedRecords.js.map +1 -1
  417. package/dist/modules/webhooks/payloads.d.ts.map +1 -1
  418. package/dist/modules/webhooks/payloads.js +15 -2
  419. package/dist/modules/webhooks/payloads.js.map +1 -1
  420. package/dist/modules/workspace/repository.d.ts +2 -0
  421. package/dist/modules/workspace/repository.d.ts.map +1 -1
  422. package/dist/modules/workspace/repository.js +7 -0
  423. package/dist/modules/workspace/repository.js.map +1 -1
  424. package/dist/modules/workspace/service.d.ts.map +1 -1
  425. package/dist/modules/workspace/service.js +10 -0
  426. package/dist/modules/workspace/service.js.map +1 -1
  427. package/dist/modules/workspace/starters.d.ts.map +1 -1
  428. package/dist/modules/workspace/starters.js +5 -0
  429. package/dist/modules/workspace/starters.js.map +1 -1
  430. package/dist/runtime/events.d.ts +1 -1
  431. package/dist/runtime/events.d.ts.map +1 -1
  432. package/dist/runtime/events.js +1 -0
  433. package/dist/runtime/events.js.map +1 -1
  434. package/dist/schema/index.d.ts +3 -0
  435. package/dist/schema/index.d.ts.map +1 -1
  436. package/dist/schema/index.js +3 -0
  437. package/dist/schema/index.js.map +1 -1
  438. package/dist/testing/database.d.ts +5 -1
  439. package/dist/testing/database.d.ts.map +1 -1
  440. package/dist/testing/database.js +81 -10
  441. package/dist/testing/database.js.map +1 -1
  442. package/migrations/0024_third_king_cobra.sql +46 -0
  443. package/migrations/0025_worthless_chimera.sql +3 -0
  444. package/migrations/0026_late_aqueduct.sql +46 -0
  445. package/migrations/0027_brainy_silver_sable.sql +3 -0
  446. package/migrations/0028_freezing_scrambler.sql +19 -0
  447. package/migrations/0029_custom_fields.sql +26 -0
  448. package/migrations/0030_enquiries.sql +79 -0
  449. package/migrations/0031_consent.sql +45 -0
  450. package/migrations/0032_form_field_statement.sql +1 -0
  451. package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
  452. package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
  453. package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
  454. package/migrations/0036_form_field_notice_type.sql +2 -0
  455. package/migrations/meta/0024_snapshot.json +5516 -0
  456. package/migrations/meta/0025_snapshot.json +5336 -0
  457. package/migrations/meta/0026_snapshot.json +5710 -0
  458. package/migrations/meta/0027_snapshot.json +5716 -0
  459. package/migrations/meta/0028_snapshot.json +5740 -0
  460. package/migrations/meta/0029_snapshot.json +5935 -0
  461. package/migrations/meta/0030_snapshot.json +6245 -0
  462. package/migrations/meta/0031_snapshot.json +6572 -0
  463. package/migrations/meta/0032_snapshot.json +6578 -0
  464. package/migrations/meta/0033_snapshot.json +6572 -0
  465. package/migrations/meta/0034_snapshot.json +6566 -0
  466. package/migrations/meta/0035_snapshot.json +6573 -0
  467. package/migrations/meta/0036_snapshot.json +6573 -0
  468. package/migrations/meta/_journal.json +91 -0
  469. package/package.json +2 -2
  470. package/src/lib/ids.ts +11 -0
  471. package/src/modules/activities/repository.ts +22 -23
  472. package/src/modules/activities/wording.ts +18 -0
  473. package/src/modules/agent-tasks/catalog.ts +63 -0
  474. package/src/modules/agent-tasks/resolve.ts +64 -24
  475. package/src/modules/attachedRecords.ts +29 -2
  476. package/src/modules/companies/index.ts +3 -1
  477. package/src/modules/companies/routes.ts +7 -0
  478. package/src/modules/companies/schema.ts +7 -1
  479. package/src/modules/companies/service.ts +48 -13
  480. package/src/modules/consent-purposes/capabilities.ts +12 -0
  481. package/src/modules/consent-purposes/events.ts +38 -0
  482. package/src/modules/consent-purposes/index.ts +48 -0
  483. package/src/modules/consent-purposes/repository.ts +163 -0
  484. package/src/modules/consent-purposes/routes.ts +122 -0
  485. package/src/modules/consent-purposes/schema.ts +46 -0
  486. package/src/modules/consent-purposes/service.ts +423 -0
  487. package/src/modules/consent-purposes/starters.ts +32 -0
  488. package/src/modules/consent-purposes/tools.ts +44 -0
  489. package/src/modules/core.ts +10 -0
  490. package/src/modules/custom-fields/capabilities.ts +17 -0
  491. package/src/modules/custom-fields/events.ts +51 -0
  492. package/src/modules/custom-fields/index.ts +61 -0
  493. package/src/modules/custom-fields/repository.ts +225 -0
  494. package/src/modules/custom-fields/routes.ts +155 -0
  495. package/src/modules/custom-fields/schema.ts +61 -0
  496. package/src/modules/custom-fields/service.ts +439 -0
  497. package/src/modules/custom-fields/tools.ts +53 -0
  498. package/src/modules/custom-fields/values.ts +352 -0
  499. package/src/modules/custom-fields/wire.ts +32 -0
  500. package/src/modules/dashboard/repository.ts +4 -3
  501. package/src/modules/deals/index.ts +5 -2
  502. package/src/modules/deals/repository.ts +6 -106
  503. package/src/modules/deals/routes.ts +7 -0
  504. package/src/modules/deals/schema.ts +7 -15
  505. package/src/modules/deals/service.ts +92 -23
  506. package/src/modules/decisions/repository.ts +2 -0
  507. package/src/modules/enquiries/events.ts +45 -0
  508. package/src/modules/enquiries/index.ts +50 -0
  509. package/src/modules/enquiries/repository.ts +164 -0
  510. package/src/modules/enquiries/routes.ts +172 -0
  511. package/src/modules/enquiries/schema.ts +59 -0
  512. package/src/modules/enquiries/service.ts +644 -0
  513. package/src/modules/enquiries/tools.ts +66 -0
  514. package/src/modules/eventCatalogs.ts +3 -0
  515. package/src/modules/forms/embed.ts +391 -44
  516. package/src/modules/forms/events.ts +30 -2
  517. package/src/modules/forms/fields.ts +102 -2
  518. package/src/modules/forms/index.ts +12 -1
  519. package/src/modules/forms/mapping.ts +183 -6
  520. package/src/modules/forms/publicRoutes.ts +43 -1
  521. package/src/modules/forms/repository.ts +162 -1
  522. package/src/modules/forms/routes.ts +212 -2
  523. package/src/modules/forms/schema.ts +166 -4
  524. package/src/modules/forms/service.ts +565 -41
  525. package/src/modules/forms/submission.ts +718 -44
  526. package/src/modules/import-export/drafts.ts +20 -1
  527. package/src/modules/import-export/exportRows.ts +21 -5
  528. package/src/modules/import-export/plan.ts +47 -2
  529. package/src/modules/import-export/presets.ts +10 -0
  530. package/src/modules/import-export/repository.ts +73 -8
  531. package/src/modules/import-export/routes.ts +4 -0
  532. package/src/modules/import-export/schema.ts +11 -0
  533. package/src/modules/import-export/service.ts +28 -2
  534. package/src/modules/import-export/streams.ts +3 -1
  535. package/src/modules/import-export/tools.ts +10 -0
  536. package/src/modules/import-export/validation.ts +28 -0
  537. package/src/modules/import-export/writes.ts +70 -5
  538. package/src/modules/lists/repository.ts +30 -0
  539. package/src/modules/lists/routes.ts +8 -0
  540. package/src/modules/lists/schema.ts +10 -0
  541. package/src/modules/lists/service.ts +110 -9
  542. package/src/modules/mcp/index.ts +5 -0
  543. package/src/modules/opportunities/index.ts +3 -1
  544. package/src/modules/opportunities/repository.ts +11 -0
  545. package/src/modules/opportunities/routes.ts +13 -0
  546. package/src/modules/opportunities/schema.ts +7 -1
  547. package/src/modules/opportunities/service.ts +188 -22
  548. package/src/modules/opportunities/tools.ts +2 -0
  549. package/src/modules/partnerships/index.ts +3 -1
  550. package/src/modules/partnerships/repository.ts +6 -117
  551. package/src/modules/partnerships/routes.ts +7 -0
  552. package/src/modules/partnerships/schema.ts +7 -14
  553. package/src/modules/partnerships/service.ts +93 -22
  554. package/src/modules/people/consentHydration.ts +167 -0
  555. package/src/modules/people/index.ts +3 -1
  556. package/src/modules/people/personConsentWrites.ts +177 -0
  557. package/src/modules/people/repository.ts +5 -0
  558. package/src/modules/people/routes.ts +127 -18
  559. package/src/modules/people/schema.ts +109 -3
  560. package/src/modules/people/service.ts +186 -40
  561. package/src/modules/people/tools.ts +5 -1
  562. package/src/modules/personLinks.ts +278 -0
  563. package/src/modules/raises/index.ts +3 -1
  564. package/src/modules/raises/repository.ts +6 -107
  565. package/src/modules/raises/routes.ts +7 -0
  566. package/src/modules/raises/schema.ts +7 -14
  567. package/src/modules/raises/service.ts +91 -20
  568. package/src/modules/recordTargets.ts +2 -0
  569. package/src/modules/references.ts +43 -4
  570. package/src/modules/sample-data/fixture.ts +63 -0
  571. package/src/modules/sample-data/index.ts +1 -0
  572. package/src/modules/sample-data/routes.ts +1 -0
  573. package/src/modules/sample-data/service.ts +97 -8
  574. package/src/modules/search/index.ts +2 -1
  575. package/src/modules/search/repository.ts +33 -1
  576. package/src/modules/search/service.ts +7 -5
  577. package/src/modules/stagedRecords.ts +18 -3
  578. package/src/modules/webhooks/payloads.ts +20 -2
  579. package/src/modules/workspace/repository.ts +12 -0
  580. package/src/modules/workspace/service.ts +14 -0
  581. package/src/modules/workspace/starters.ts +5 -0
  582. package/src/runtime/events.ts +1 -0
  583. package/src/schema/index.ts +3 -0
  584. 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
  }
@@ -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` })
@@ -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
 
@@ -1,3 +1,4 @@
1
+ import { customFieldsPatchShape } from '@kelpie/schemas'
1
2
  import type { Context, Hono } from 'hono'
2
3
  import { z } from 'zod'
3
4
 
@@ -6,6 +7,7 @@ import { pageBody, readIdFilter, readJsonBody, readListParameters } from '../../
6
7
  import type { Actor } from '../auth/actor.ts'
7
8
  import { resolveActorFrom } from '../auth/credentials.ts'
8
9
  import type { CredentialDependencies } from '../auth/credentials.ts'
10
+ import { renderCustomFieldsForWire } from '../custom-fields/wire.ts'
9
11
  import type {
10
12
  CreateOpportunityInput,
11
13
  OpportunitiesService,
@@ -23,8 +25,10 @@ const opportunityShape = {
23
25
  company_id: z.string().min(1).nullable(),
24
26
  owner_id: z.string().min(1).nullable(),
25
27
  expected_close: isoDateSchema.nullable(),
28
+ person_ids: z.array(z.string().min(1)),
26
29
  summary: z.string(),
27
30
  tags: z.array(z.string().min(1)),
31
+ custom_fields: customFieldsPatchShape,
28
32
  }
29
33
 
30
34
  /**
@@ -41,8 +45,10 @@ export const createBody = z.strictObject({
41
45
  company_id: opportunityShape.company_id.default(null),
42
46
  owner_id: opportunityShape.owner_id.optional(),
43
47
  expected_close: opportunityShape.expected_close.default(null),
48
+ person_ids: opportunityShape.person_ids.default([]),
44
49
  summary: opportunityShape.summary.default(''),
45
50
  tags: opportunityShape.tags.default([]),
51
+ custom_fields: opportunityShape.custom_fields.default({}),
46
52
  })
47
53
 
48
54
  export const updateBody = z.strictObject(opportunityShape).partial()
@@ -59,8 +65,10 @@ export function toCreateInput(body: z.infer<typeof createBody>): CreateOpportuni
59
65
  companyId: body.company_id,
60
66
  ownerId: body.owner_id,
61
67
  expectedClose: body.expected_close,
68
+ personIds: body.person_ids,
62
69
  summary: body.summary,
63
70
  tags: body.tags,
71
+ customFields: body.custom_fields,
64
72
  }
65
73
  }
66
74
 
@@ -72,8 +80,10 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdateOpportuni
72
80
  ...(body.company_id === undefined ? {} : { companyId: body.company_id }),
73
81
  ...(body.owner_id === undefined ? {} : { ownerId: body.owner_id }),
74
82
  ...(body.expected_close === undefined ? {} : { expectedClose: body.expected_close }),
83
+ ...(body.person_ids === undefined ? {} : { personIds: body.person_ids }),
75
84
  ...(body.summary === undefined ? {} : { summary: body.summary }),
76
85
  ...(body.tags === undefined ? {} : { tags: body.tags }),
86
+ ...(body.custom_fields === undefined ? {} : { customFields: body.custom_fields }),
77
87
  }
78
88
  }
79
89
 
@@ -86,8 +96,10 @@ export function opportunityResponse(opportunity: OpportunityView): Record<string
86
96
  company_id: opportunity.companyId,
87
97
  owner_id: opportunity.ownerId,
88
98
  expected_close: opportunity.expectedClose,
99
+ person_ids: opportunity.personIds,
89
100
  summary: opportunity.summary,
90
101
  tags: opportunity.tags,
102
+ custom_fields: renderCustomFieldsForWire(opportunity.customFields),
91
103
  created_at: opportunity.createdAt.toISOString(),
92
104
  updated_at: opportunity.updatedAt.toISOString(),
93
105
  }
@@ -107,6 +119,7 @@ export function mountOpportunitiesRoutes(
107
119
  kinds: readIdFilter(context, 'kind'),
108
120
  companyIds: readIdFilter(context, 'company_id'),
109
121
  stageIds: readIdFilter(context, 'stage_id'),
122
+ personIds: readIdFilter(context, 'person_id'),
110
123
  },
111
124
  readListParameters(context),
112
125
  )
@@ -1,4 +1,5 @@
1
- import { date, index, pgTable, text } from 'drizzle-orm/pg-core'
1
+ import type { CustomFieldValue } from '@kelpie/schemas'
2
+ import { date, index, jsonb, pgTable, text } from 'drizzle-orm/pg-core'
2
3
 
3
4
  import { createdAt, primaryId, searchVector, updatedAt } from '../../lib/columns.ts'
4
5
  import type { SearchVectorPart } from '../../lib/columns.ts'
@@ -30,6 +31,11 @@ export const opportunities = pgTable(
30
31
  expectedClose: date('expected_close'),
31
32
  summary: text('summary').notNull().default(''),
32
33
  tags: text('tags').array().notNull().default([]),
34
+ // Workspace-defined fields, keyed by definition key. See people/schema.ts.
35
+ customFields: jsonb('custom_fields')
36
+ .$type<Readonly<Record<string, CustomFieldValue>>>()
37
+ .notNull()
38
+ .default({}),
33
39
  createdAt: createdAt(),
34
40
  updatedAt: updatedAt(),
35
41
  searchVector: searchVector((): readonly SearchVectorPart[] => [