@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
@@ -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[] => [
@@ -1,3 +1,5 @@
1
+ import type { CustomFieldWireValue } from '@kelpie/schemas'
2
+
1
3
  import { changedKeys } from '../../lib/changes.ts'
2
4
  import type { Database } from '../../lib/database.ts'
3
5
  import { AppError } from '../../lib/errors.ts'
@@ -6,7 +8,13 @@ import { readListWindow, toPage } from '../../lib/pagination.ts'
6
8
  import type { ListQueryParameters, Page } from '../../lib/pagination.ts'
7
9
  import type { TransactionScope } from '../../runtime/transaction.ts'
8
10
  import type { ActivityRecorder } from '../activities/recorder.ts'
9
- import { describeCreation, describeStageChange, describeUpdate } from '../activities/wording.ts'
11
+ import {
12
+ describeCreation,
13
+ describeLink,
14
+ describeStageChange,
15
+ describeUnlink,
16
+ describeUpdate,
17
+ } from '../activities/wording.ts'
10
18
  import type { FieldLabels } from '../activities/wording.ts'
11
19
  import { toEventActor } from '../../lib/actor.ts'
12
20
  import type { Actor } from '../auth/actor.ts'
@@ -14,6 +22,8 @@ import { actorMemberId, requireWorkspaceId } from '../auth/actor.ts'
14
22
  import './events.ts'
15
23
  import { deleteRecordsAttachedTo } from '../attachedRecords.ts'
16
24
  import * as companyRepository from '../companies/repository.ts'
25
+ import type { CustomFieldValuesValidator } from '../custom-fields/values.ts'
26
+ import * as personLinks from '../personLinks.ts'
17
27
  import * as pipelineRepository from '../pipelines/repository.ts'
18
28
  import type { PipelineStageRecord } from '../pipelines/repository.ts'
19
29
  import * as repository from './repository.ts'
@@ -22,7 +32,9 @@ import type { OpportunityFilters, OpportunityRecord } from './repository.ts'
22
32
 
23
33
  /**
24
34
  * Opportunities: the non-sales pipeline. Grants, accelerators, tenders, press,
25
- * speaking — same stage mechanics as Deals, different lens, and no people links.
35
+ * speaking — same stage mechanics as Deals, different lens. People attach
36
+ * through `person_links` and appear as `person_ids` on the wire, the same
37
+ * shape deals/partnerships/raises use.
26
38
  *
27
39
  * A stage move is an ordinary PATCH of `stage_id`, and it is the one change that
28
40
  * files a `stage_changed` activity and a `stage.changed` event instead of the
@@ -35,6 +47,7 @@ export interface OpportunitiesDependencies {
35
47
  readonly createId: IdFactory
36
48
  readonly now: () => Date
37
49
  readonly recordActivity: ActivityRecorder
50
+ readonly customFields: CustomFieldValuesValidator
38
51
  }
39
52
 
40
53
  /** What a changed column is called on a timeline. The mockup says "Target date", not "Expected close". */
@@ -48,8 +61,10 @@ const OPPORTUNITY_FIELD_LABELS: FieldLabels = {
48
61
  tags: 'Tags',
49
62
  }
50
63
 
51
- /** An opportunity as the API returns one: the stored row minus tenancy. */
52
- export type OpportunityView = Omit<OpportunityRecord, 'workspaceId'>
64
+ /** An opportunity as the API returns one: the stored row minus tenancy, plus its people. */
65
+ export type OpportunityView = Omit<OpportunityRecord, 'workspaceId'> & {
66
+ readonly personIds: readonly string[]
67
+ }
53
68
 
54
69
  export interface CreateOpportunityInput {
55
70
  readonly name: string
@@ -64,8 +79,11 @@ export interface CreateOpportunityInput {
64
79
  /** Absent means the caller: the member creating an opportunity starts as its owner. */
65
80
  readonly ownerId: string | null | undefined
66
81
  readonly expectedClose: string | null
82
+ readonly personIds: readonly string[]
67
83
  readonly summary: string
68
84
  readonly tags: readonly string[]
85
+ /** Wire shape for a create body: `null` values are ignored, non-null are validated. */
86
+ readonly customFields: Readonly<Record<string, CustomFieldWireValue | null>> | undefined
69
87
  }
70
88
 
71
89
  /** PATCH semantics: an absent field is left alone, and null clears a nullable one. */
@@ -76,8 +94,15 @@ export interface UpdateOpportunityInput {
76
94
  readonly companyId?: string | null | undefined
77
95
  readonly ownerId?: string | null | undefined
78
96
  readonly expectedClose?: string | null | undefined
97
+ /** Replaces the set. The service works out who was added and who left. */
98
+ readonly personIds?: readonly string[] | undefined
79
99
  readonly summary?: string | undefined
80
100
  readonly tags?: readonly string[] | undefined
101
+ /**
102
+ * Partial merge patch (wire shape): sent keys change, `null` clears a key,
103
+ * absent keys are left alone. Unknown keys are `422`.
104
+ */
105
+ readonly customFields?: Readonly<Record<string, CustomFieldWireValue | null>> | undefined
81
106
  }
82
107
 
83
108
  export interface OpportunitiesService {
@@ -92,10 +117,10 @@ export interface OpportunitiesService {
92
117
  remove(actor: Actor, id: string): Promise<void>
93
118
  }
94
119
 
95
- function toView(record: OpportunityRecord): OpportunityView {
120
+ function toView(record: OpportunityRecord, personIds: readonly string[]): OpportunityView {
96
121
  const { workspaceId: _workspaceId, ...view } = record
97
122
 
98
- return view
123
+ return { ...view, personIds }
99
124
  }
100
125
 
101
126
  function toStoredColumns(input: UpdateOpportunityInput): Partial<repository.OpportunityColumns> {
@@ -182,6 +207,40 @@ export function createOpportunitiesService(
182
207
  }
183
208
  }
184
209
 
210
+ /** @returns Each person's name, for the link activities. Any id missing here is a 404. */
211
+ async function requirePeople(
212
+ workspaceId: string,
213
+ personIds: readonly string[],
214
+ ): Promise<ReadonlyMap<string, string>> {
215
+ const named = await personLinks.findPeopleNamed(dependencies.db, workspaceId, personIds)
216
+ const missing = personIds.filter((id) => !named.has(id))
217
+
218
+ if (missing.length > 0) {
219
+ throw new AppError(
220
+ 'not_found',
221
+ 'Person not found',
222
+ missing.map((id) => ({ field: 'person_ids', message: `No person ${id} here` })),
223
+ )
224
+ }
225
+
226
+ return named
227
+ }
228
+
229
+ /** @returns The page's views, with every opportunity's people fetched in one query. */
230
+ async function toViews(
231
+ workspaceId: string,
232
+ records: readonly OpportunityRecord[],
233
+ ): Promise<OpportunityView[]> {
234
+ const peopleByOpportunity = await personLinks.listPersonIdsFor(
235
+ dependencies.db,
236
+ workspaceId,
237
+ 'opportunity',
238
+ records.map((record) => record.id),
239
+ )
240
+
241
+ return records.map((record) => toView(record, peopleByOpportunity.get(record.id) ?? []))
242
+ }
243
+
185
244
  return {
186
245
  async list(actor, filters, query) {
187
246
  const workspaceId = requireWorkspaceId(actor)
@@ -189,13 +248,20 @@ export function createOpportunitiesService(
189
248
  const rows = await repository.listOpportunities(dependencies.db, workspaceId, filters, window)
190
249
  const page = toPage(rows, window, (opportunity) => opportunity.id)
191
250
 
192
- return { items: page.items.map(toView), nextCursor: page.nextCursor }
251
+ return { items: await toViews(workspaceId, page.items), nextCursor: page.nextCursor }
193
252
  },
194
253
 
195
254
  async get(actor, id) {
196
255
  const workspaceId = requireWorkspaceId(actor)
256
+ const opportunity = await require(workspaceId, id)
197
257
 
198
- return toView(await require(workspaceId, id))
258
+ return toView(
259
+ opportunity,
260
+ await personLinks.listPersonIds(dependencies.db, workspaceId, {
261
+ targetType: 'opportunity',
262
+ targetId: id,
263
+ }),
264
+ )
199
265
  },
200
266
 
201
267
  async create(actor, input) {
@@ -215,9 +281,17 @@ export function createOpportunitiesService(
215
281
  await requireOwner(workspaceId, ownerId)
216
282
  }
217
283
 
284
+ const personIds = [...new Set(input.personIds)]
285
+ const named = await requirePeople(workspaceId, personIds)
218
286
  const id = dependencies.createId('opportunity')
219
287
 
220
288
  return dependencies.transaction(async ({ tx, events }) => {
289
+ const customFields = await dependencies.customFields.forCreate(
290
+ tx,
291
+ workspaceId,
292
+ 'opportunity',
293
+ input.customFields,
294
+ )
221
295
  const created = await repository.insertOpportunity(tx, {
222
296
  id,
223
297
  workspaceId,
@@ -229,8 +303,17 @@ export function createOpportunitiesService(
229
303
  expectedClose: input.expectedClose,
230
304
  summary: input.summary,
231
305
  tags: [...input.tags],
306
+ customFields,
232
307
  })
233
308
 
309
+ await personLinks.linkPeople(
310
+ tx,
311
+ dependencies.createId,
312
+ workspaceId,
313
+ { targetType: 'opportunity', targetId: id },
314
+ personIds,
315
+ )
316
+
234
317
  await dependencies.recordActivity(tx, workspaceId, actor, {
235
318
  targetType: 'opportunity',
236
319
  targetId: id,
@@ -238,9 +321,19 @@ export function createOpportunitiesService(
238
321
  ...describeCreation('Opportunity'),
239
322
  })
240
323
 
324
+ // One row per person, so the timeline names who was on it from day one.
325
+ for (const personId of personIds) {
326
+ await dependencies.recordActivity(tx, workspaceId, actor, {
327
+ targetType: 'opportunity',
328
+ targetId: id,
329
+ kind: 'linked',
330
+ ...describeLink('person', named.get(personId) ?? personId),
331
+ })
332
+ }
333
+
241
334
  events.emit('opportunities.opportunity.created', { type: 'opportunity', id }, {})
242
335
 
243
- return toView(created)
336
+ return toView(created, personIds)
244
337
  }, { workspaceId, actor: toEventActor(actor) })
245
338
  },
246
339
 
@@ -267,16 +360,43 @@ export function createOpportunitiesService(
267
360
  await requireOwner(workspaceId, changes.ownerId)
268
361
  }
269
362
 
270
- const columns = toStoredColumns(changes)
271
- const changed = changedKeys(existing, columns)
363
+ const currentPeople = await personLinks.listPersonIds(dependencies.db, workspaceId, {
364
+ targetType: 'opportunity',
365
+ targetId: id,
366
+ })
367
+ const nextPeople =
368
+ changes.personIds === undefined ? undefined : [...new Set(changes.personIds)]
369
+ const added =
370
+ nextPeople === undefined
371
+ ? []
372
+ : nextPeople.filter((personId) => !currentPeople.includes(personId))
373
+ const removed =
374
+ nextPeople === undefined
375
+ ? []
376
+ : currentPeople.filter((personId) => !nextPeople.includes(personId))
377
+ const named = await requirePeople(workspaceId, [...added, ...removed])
272
378
 
273
- if (changed.length === 0) {
274
- return toView(existing)
275
- }
379
+ const columns = toStoredColumns(changes)
380
+ const scalarChanged = changedKeys(existing, columns)
381
+ const linksChanged = added.length > 0 || removed.length > 0
276
382
 
277
383
  return dependencies.transaction(async ({ tx, events }) => {
384
+ const cf = await dependencies.customFields.forUpdate(
385
+ tx,
386
+ workspaceId,
387
+ 'opportunity',
388
+ existing.customFields,
389
+ changes.customFields,
390
+ )
391
+ const customFieldsChanged = cf !== undefined && cf.changedPaths.length > 0
392
+
393
+ if (scalarChanged.length === 0 && !linksChanged && !customFieldsChanged) {
394
+ return toView(existing, currentPeople)
395
+ }
396
+
278
397
  const updated = await repository.updateOpportunity(tx, workspaceId, id, {
279
398
  ...columns,
399
+ ...(customFieldsChanged ? { customFields: cf.merged } : {}),
280
400
  updatedAt: dependencies.now(),
281
401
  })
282
402
 
@@ -284,6 +404,20 @@ export function createOpportunitiesService(
284
404
  throw AppError.notFound('Opportunity not found')
285
405
  }
286
406
 
407
+ await personLinks.linkPeople(
408
+ tx,
409
+ dependencies.createId,
410
+ workspaceId,
411
+ { targetType: 'opportunity', targetId: id },
412
+ added,
413
+ )
414
+ await personLinks.unlinkPeople(
415
+ tx,
416
+ workspaceId,
417
+ { targetType: 'opportunity', targetId: id },
418
+ removed,
419
+ )
420
+
287
421
  if (stageMove !== undefined) {
288
422
  await dependencies.recordActivity(tx, workspaceId, actor, {
289
423
  targetType: 'opportunity',
@@ -293,21 +427,53 @@ export function createOpportunitiesService(
293
427
  })
294
428
  }
295
429
 
296
- const otherChanged = changed.filter((field) => field !== 'stageId')
430
+ const otherChanged = scalarChanged.filter((field) => field !== 'stageId')
431
+ const customFieldPaths = cf?.changedPaths ?? []
432
+ const activityChanged = [...otherChanged, ...customFieldPaths]
297
433
 
298
- if (otherChanged.length > 0) {
434
+ if (activityChanged.length > 0) {
435
+ const labels: Record<string, string> = { ...OPPORTUNITY_FIELD_LABELS, ...cf?.labels }
436
+ const before: Record<string, unknown> = { ...existing, ...cf?.flatBefore }
437
+ const after: Record<string, unknown> = { ...columns, ...cf?.flatAfter }
299
438
  await dependencies.recordActivity(tx, workspaceId, actor, {
300
439
  targetType: 'opportunity',
301
440
  targetId: id,
302
441
  kind: 'updated',
303
- ...describeUpdate(otherChanged, OPPORTUNITY_FIELD_LABELS, existing, columns),
442
+ ...describeUpdate(activityChanged, labels, before, after),
443
+ })
444
+ }
445
+
446
+ // Links land on the opportunity's timeline only: a person's page already
447
+ // rolls up the activity of every pipeline record they are on, so a
448
+ // second row targeted at the person would show them the same news twice.
449
+ for (const personId of added) {
450
+ await dependencies.recordActivity(tx, workspaceId, actor, {
451
+ targetType: 'opportunity',
452
+ targetId: id,
453
+ kind: 'linked',
454
+ ...describeLink('person', named.get(personId) ?? personId),
455
+ })
456
+ }
457
+
458
+ for (const personId of removed) {
459
+ await dependencies.recordActivity(tx, workspaceId, actor, {
460
+ targetType: 'opportunity',
461
+ targetId: id,
462
+ kind: 'unlinked',
463
+ ...describeUnlink('person', named.get(personId) ?? personId),
304
464
  })
305
465
  }
306
466
 
307
467
  events.emit(
308
468
  'opportunities.opportunity.updated',
309
469
  { type: 'opportunity', id },
310
- { changed },
470
+ {
471
+ changed: [
472
+ ...scalarChanged,
473
+ ...(linksChanged ? ['personIds'] : []),
474
+ ...customFieldPaths,
475
+ ],
476
+ },
311
477
  )
312
478
 
313
479
  if (stageMove !== undefined) {
@@ -318,7 +484,7 @@ export function createOpportunitiesService(
318
484
  )
319
485
  }
320
486
 
321
- return toView(updated)
487
+ return toView(updated, nextPeople ?? currentPeople)
322
488
  }, { workspaceId, actor: toEventActor(actor) })
323
489
  },
324
490
 
@@ -328,9 +494,9 @@ export function createOpportunitiesService(
328
494
  await dependencies.transaction(async ({ tx, events }) => {
329
495
  await require(workspaceId, id)
330
496
 
331
- // Notes, activities, decisions and plan items have no foreign key to
332
- // their target, so the deleting service removes them here, in the same
333
- // transaction. Nothing else references an opportunity.
497
+ // Notes, activities, decisions, plan items, and person_links have no
498
+ // foreign key to their target, so the deleting service removes them
499
+ // here, in the same transaction. Nothing else references an opportunity.
334
500
  await deleteRecordsAttachedTo(tx, workspaceId, 'opportunity', id)
335
501
  await repository.deleteOpportunity(tx, workspaceId, id)
336
502
 
@@ -13,6 +13,7 @@ const listArgs = z.strictObject({
13
13
  kind: idSetArg.optional().describe('Kinds are free text, so a match here is exact.'),
14
14
  company_id: idSetArg.optional().describe('Only opportunities with these companies.'),
15
15
  stage_id: idSetArg.optional().describe('Only opportunities in these pipeline stages.'),
16
+ person_id: idSetArg.optional().describe('Only opportunities any of these people are on.'),
16
17
  })
17
18
 
18
19
  export function registerOpportunitiesTools(mcp: McpToolRegistry, service: OpportunitiesService): void {
@@ -30,6 +31,7 @@ export function registerOpportunitiesTools(mcp: McpToolRegistry, service: Opport
30
31
  kinds: toSet(args.kind),
31
32
  companyIds: toSet(args.company_id),
32
33
  stageIds: toSet(args.stage_id),
34
+ personIds: toSet(args.person_id),
33
35
  }),
34
36
  createArgs: createBody,
35
37
  toCreateInput,
@@ -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 { partnershipsEvents } from './events.ts'
4
5
  import { mountPartnershipsRoutes } from './routes.ts'
5
6
  import * as schema from './schema.ts'
@@ -17,7 +18,7 @@ import { registerPartnershipsTools } from './tools.ts'
17
18
  export function createPartnershipsModule(migrationsDirectory: string): KelpieModule {
18
19
  return {
19
20
  id: 'partnerships',
20
- requires: ['companies', 'people', 'pipelines', 'activities'],
21
+ requires: ['companies', 'people', 'pipelines', 'activities', 'custom-fields'],
21
22
  events: partnershipsEvents,
22
23
 
23
24
  register(context) {
@@ -30,6 +31,7 @@ export function createPartnershipsModule(migrationsDirectory: string): KelpieMod
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)
@@ -1,4 +1,4 @@
1
- import { and, asc, eq, ilike, inArray, or, sql } from 'drizzle-orm'
1
+ import { and, eq, ilike, inArray, or, sql } from 'drizzle-orm'
2
2
  import type { SQL } from 'drizzle-orm'
3
3
 
4
4
  import { keysetCondition, orderByWindow, textSort, timestampSort } from '../../lib/pagination.ts'
@@ -6,9 +6,9 @@ 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 { people } from '../people/schema.ts'
9
+ import { anyPersonLinked } from '../personLinks.ts'
10
10
  import { workspaceMembers } from '../workspace/schema.ts'
11
- import { partnershipPeople, partnerships } from './schema.ts'
11
+ import { partnerships } from './schema.ts'
12
12
 
13
13
  export type PartnershipRecord = typeof partnerships.$inferSelect
14
14
 
@@ -51,15 +51,6 @@ function companyNameMatches(pattern: string): SQL {
51
51
  )`
52
52
  }
53
53
 
54
- function hasAnyOfPeople(personIds: readonly string[]): SQL {
55
- return sql`exists (
56
- select 1
57
- from ${partnershipPeople}
58
- where ${partnershipPeople.partnershipId} = ${partnerships.id}
59
- and ${inArray(partnershipPeople.personId, personIds)}
60
- )`
61
- }
62
-
63
54
  function matchesTerm(term: string): SQL | undefined {
64
55
  const pattern = containsPattern(term)
65
56
 
@@ -81,7 +72,9 @@ function conditionsFor(workspaceId: string, filters: PartnershipFilters): (SQL |
81
72
  ? undefined
82
73
  : inArray(partnerships.companyId, filters.companyIds),
83
74
  filters.stageIds === undefined ? undefined : inArray(partnerships.stageId, filters.stageIds),
84
- filters.personIds === undefined ? undefined : hasAnyOfPeople(filters.personIds),
75
+ filters.personIds === undefined
76
+ ? undefined
77
+ : anyPersonLinked('partnership', partnerships.id, partnerships.workspaceId, filters.personIds),
85
78
  ]
86
79
  }
87
80
 
@@ -155,110 +148,6 @@ export async function deletePartnership(
155
148
  return deleted.length
156
149
  }
157
150
 
158
- /** The key people on one partnership. Ordered by id so a response is stable across reads. */
159
- export async function listPersonIds(db: Queryable, partnershipId: string): Promise<string[]> {
160
- const rows = await db
161
- .select({ personId: partnershipPeople.personId })
162
- .from(partnershipPeople)
163
- .where(eq(partnershipPeople.partnershipId, partnershipId))
164
- .orderBy(asc(partnershipPeople.personId))
165
-
166
- return rows.map((row) => row.personId)
167
- }
168
-
169
- /**
170
- * The key people on each of a page of partnerships, in one query rather than one
171
- * per row.
172
- *
173
- * @returns Ids missing from the map have no people.
174
- */
175
- export async function listPersonIdsFor(
176
- db: Queryable,
177
- partnershipIds: readonly string[],
178
- ): Promise<ReadonlyMap<string, readonly string[]>> {
179
- if (partnershipIds.length === 0) {
180
- return new Map()
181
- }
182
-
183
- const rows = await db
184
- .select({
185
- partnershipId: partnershipPeople.partnershipId,
186
- personId: partnershipPeople.personId,
187
- })
188
- .from(partnershipPeople)
189
- .where(inArray(partnershipPeople.partnershipId, partnershipIds))
190
- .orderBy(asc(partnershipPeople.personId))
191
-
192
- const byPartnership = new Map<string, string[]>()
193
-
194
- for (const row of rows) {
195
- const existing = byPartnership.get(row.partnershipId)
196
-
197
- if (existing === undefined) {
198
- byPartnership.set(row.partnershipId, [row.personId])
199
- } else {
200
- existing.push(row.personId)
201
- }
202
- }
203
-
204
- return byPartnership
205
- }
206
-
207
- export async function insertPartnershipPeople(
208
- db: Queryable,
209
- partnershipId: string,
210
- personIds: readonly string[],
211
- ): Promise<void> {
212
- if (personIds.length === 0) {
213
- return
214
- }
215
-
216
- await db
217
- .insert(partnershipPeople)
218
- .values(personIds.map((personId) => ({ partnershipId, personId })))
219
- }
220
-
221
- export async function deletePartnershipPeople(
222
- db: Queryable,
223
- partnershipId: string,
224
- personIds: readonly string[],
225
- ): Promise<void> {
226
- if (personIds.length === 0) {
227
- return
228
- }
229
-
230
- await db
231
- .delete(partnershipPeople)
232
- .where(
233
- and(
234
- eq(partnershipPeople.partnershipId, partnershipId),
235
- inArray(partnershipPeople.personId, personIds),
236
- ),
237
- )
238
- }
239
-
240
- /**
241
- * The names of these people in this workspace, keyed by id. An id missing from
242
- * the map does not exist here, which is how `person_ids` is validated. Reads the
243
- * `people` *table*, per the cross-relation rule in `architecture.md`.
244
- */
245
- export async function findPeopleNamed(
246
- db: Queryable,
247
- workspaceId: string,
248
- personIds: readonly string[],
249
- ): Promise<ReadonlyMap<string, string>> {
250
- if (personIds.length === 0) {
251
- return new Map()
252
- }
253
-
254
- const rows = await db
255
- .select({ id: people.id, name: people.name })
256
- .from(people)
257
- .where(and(eq(people.workspaceId, workspaceId), inArray(people.id, personIds)))
258
-
259
- return new Map(rows.map((row) => [row.id, row.name]))
260
- }
261
-
262
151
  /** Whether a member belongs to this workspace, for validating `owner_id`. */
263
152
  export async function memberExists(
264
153
  db: Queryable,