@kelpie/server 0.7.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 (679) hide show
  1. package/dist/lib/consumerEmailDomains.d.ts +2 -0
  2. package/dist/lib/consumerEmailDomains.d.ts.map +1 -0
  3. package/dist/lib/consumerEmailDomains.js +62 -0
  4. package/dist/lib/consumerEmailDomains.js.map +1 -0
  5. package/dist/lib/email.d.ts +7 -0
  6. package/dist/lib/email.d.ts.map +1 -1
  7. package/dist/lib/email.js.map +1 -1
  8. package/dist/lib/emailContent.d.ts +33 -0
  9. package/dist/lib/emailContent.d.ts.map +1 -0
  10. package/dist/lib/emailContent.js +54 -0
  11. package/dist/lib/emailContent.js.map +1 -0
  12. package/dist/lib/emailDomainAutoLink.d.ts +27 -0
  13. package/dist/lib/emailDomainAutoLink.d.ts.map +1 -0
  14. package/dist/lib/emailDomainAutoLink.js +119 -0
  15. package/dist/lib/emailDomainAutoLink.js.map +1 -0
  16. package/dist/lib/ids.d.ts +13 -0
  17. package/dist/lib/ids.d.ts.map +1 -1
  18. package/dist/lib/ids.js +13 -0
  19. package/dist/lib/ids.js.map +1 -1
  20. package/dist/modules/activities/repository.d.ts.map +1 -1
  21. package/dist/modules/activities/repository.js +19 -20
  22. package/dist/modules/activities/repository.js.map +1 -1
  23. package/dist/modules/activities/wording.d.ts +12 -0
  24. package/dist/modules/activities/wording.d.ts.map +1 -1
  25. package/dist/modules/activities/wording.js +16 -0
  26. package/dist/modules/activities/wording.js.map +1 -1
  27. package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
  28. package/dist/modules/agent-tasks/catalog.js +62 -0
  29. package/dist/modules/agent-tasks/catalog.js.map +1 -1
  30. package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
  31. package/dist/modules/agent-tasks/resolve.js +42 -9
  32. package/dist/modules/agent-tasks/resolve.js.map +1 -1
  33. package/dist/modules/agent-tasks/routes.d.ts +2 -0
  34. package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
  35. package/dist/modules/attachedRecords.d.ts +6 -1
  36. package/dist/modules/attachedRecords.d.ts.map +1 -1
  37. package/dist/modules/attachedRecords.js +18 -2
  38. package/dist/modules/attachedRecords.js.map +1 -1
  39. package/dist/modules/auth/preferences.d.ts +11 -1
  40. package/dist/modules/auth/preferences.d.ts.map +1 -1
  41. package/dist/modules/auth/preferences.js +11 -0
  42. package/dist/modules/auth/preferences.js.map +1 -1
  43. package/dist/modules/auth/routes.d.ts.map +1 -1
  44. package/dist/modules/auth/routes.js +18 -0
  45. package/dist/modules/auth/routes.js.map +1 -1
  46. package/dist/modules/auth/schema.d.ts +20 -0
  47. package/dist/modules/auth/schema.d.ts.map +1 -1
  48. package/dist/modules/auth/schema.js +11 -1
  49. package/dist/modules/auth/schema.js.map +1 -1
  50. package/dist/modules/auth/service.d.ts.map +1 -1
  51. package/dist/modules/auth/service.js +27 -3
  52. package/dist/modules/auth/service.js.map +1 -1
  53. package/dist/modules/companies/index.d.ts.map +1 -1
  54. package/dist/modules/companies/index.js +3 -1
  55. package/dist/modules/companies/index.js.map +1 -1
  56. package/dist/modules/companies/repository.d.ts +2 -0
  57. package/dist/modules/companies/repository.d.ts.map +1 -1
  58. package/dist/modules/companies/repository.js +1 -0
  59. package/dist/modules/companies/repository.js.map +1 -1
  60. package/dist/modules/companies/routes.d.ts +16 -0
  61. package/dist/modules/companies/routes.d.ts.map +1 -1
  62. package/dist/modules/companies/routes.js +18 -0
  63. package/dist/modules/companies/routes.js.map +1 -1
  64. package/dist/modules/companies/schema.d.ts +37 -0
  65. package/dist/modules/companies/schema.d.ts.map +1 -1
  66. package/dist/modules/companies/schema.js +10 -1
  67. package/dist/modules/companies/schema.js.map +1 -1
  68. package/dist/modules/companies/service.d.ts +6 -0
  69. package/dist/modules/companies/service.d.ts.map +1 -1
  70. package/dist/modules/companies/service.js +45 -11
  71. package/dist/modules/companies/service.js.map +1 -1
  72. package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
  73. package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
  74. package/dist/modules/consent-purposes/capabilities.js +10 -0
  75. package/dist/modules/consent-purposes/capabilities.js.map +1 -0
  76. package/dist/modules/consent-purposes/events.d.ts +38 -0
  77. package/dist/modules/consent-purposes/events.d.ts.map +1 -0
  78. package/dist/modules/consent-purposes/events.js +17 -0
  79. package/dist/modules/consent-purposes/events.js.map +1 -0
  80. package/dist/modules/consent-purposes/index.d.ts +13 -0
  81. package/dist/modules/consent-purposes/index.d.ts.map +1 -0
  82. package/dist/modules/consent-purposes/index.js +41 -0
  83. package/dist/modules/consent-purposes/index.js.map +1 -0
  84. package/dist/modules/consent-purposes/repository.d.ts +21 -0
  85. package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
  86. package/dist/modules/consent-purposes/repository.js +98 -0
  87. package/dist/modules/consent-purposes/repository.js.map +1 -0
  88. package/dist/modules/consent-purposes/routes.d.ts +39 -0
  89. package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
  90. package/dist/modules/consent-purposes/routes.js +79 -0
  91. package/dist/modules/consent-purposes/routes.js.map +1 -0
  92. package/dist/modules/consent-purposes/schema.d.ts +175 -0
  93. package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
  94. package/dist/modules/consent-purposes/schema.js +35 -0
  95. package/dist/modules/consent-purposes/schema.js.map +1 -0
  96. package/dist/modules/consent-purposes/service.d.ts +50 -0
  97. package/dist/modules/consent-purposes/service.d.ts.map +1 -0
  98. package/dist/modules/consent-purposes/service.js +263 -0
  99. package/dist/modules/consent-purposes/service.js.map +1 -0
  100. package/dist/modules/consent-purposes/starters.d.ts +17 -0
  101. package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
  102. package/dist/modules/consent-purposes/starters.js +15 -0
  103. package/dist/modules/consent-purposes/starters.js.map +1 -0
  104. package/dist/modules/consent-purposes/tools.d.ts +4 -0
  105. package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
  106. package/dist/modules/consent-purposes/tools.js +29 -0
  107. package/dist/modules/consent-purposes/tools.js.map +1 -0
  108. package/dist/modules/core.d.ts.map +1 -1
  109. package/dist/modules/core.js +21 -0
  110. package/dist/modules/core.js.map +1 -1
  111. package/dist/modules/custom-fields/capabilities.d.ts +12 -0
  112. package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
  113. package/dist/modules/custom-fields/capabilities.js +15 -0
  114. package/dist/modules/custom-fields/capabilities.js.map +1 -0
  115. package/dist/modules/custom-fields/events.d.ts +49 -0
  116. package/dist/modules/custom-fields/events.d.ts.map +1 -0
  117. package/dist/modules/custom-fields/events.js +25 -0
  118. package/dist/modules/custom-fields/events.js.map +1 -0
  119. package/dist/modules/custom-fields/index.d.ts +19 -0
  120. package/dist/modules/custom-fields/index.d.ts.map +1 -0
  121. package/dist/modules/custom-fields/index.js +46 -0
  122. package/dist/modules/custom-fields/index.js.map +1 -0
  123. package/dist/modules/custom-fields/repository.d.ts +37 -0
  124. package/dist/modules/custom-fields/repository.d.ts.map +1 -0
  125. package/dist/modules/custom-fields/repository.js +144 -0
  126. package/dist/modules/custom-fields/repository.js.map +1 -0
  127. package/dist/modules/custom-fields/routes.d.ts +44 -0
  128. package/dist/modules/custom-fields/routes.d.ts.map +1 -0
  129. package/dist/modules/custom-fields/routes.js +103 -0
  130. package/dist/modules/custom-fields/routes.js.map +1 -0
  131. package/dist/modules/custom-fields/schema.d.ts +215 -0
  132. package/dist/modules/custom-fields/schema.d.ts.map +1 -0
  133. package/dist/modules/custom-fields/schema.js +43 -0
  134. package/dist/modules/custom-fields/schema.js.map +1 -0
  135. package/dist/modules/custom-fields/service.d.ts +57 -0
  136. package/dist/modules/custom-fields/service.d.ts.map +1 -0
  137. package/dist/modules/custom-fields/service.js +273 -0
  138. package/dist/modules/custom-fields/service.js.map +1 -0
  139. package/dist/modules/custom-fields/tools.d.ts +4 -0
  140. package/dist/modules/custom-fields/tools.d.ts.map +1 -0
  141. package/dist/modules/custom-fields/tools.js +38 -0
  142. package/dist/modules/custom-fields/tools.js.map +1 -0
  143. package/dist/modules/custom-fields/values.d.ts +49 -0
  144. package/dist/modules/custom-fields/values.d.ts.map +1 -0
  145. package/dist/modules/custom-fields/values.js +249 -0
  146. package/dist/modules/custom-fields/values.js.map +1 -0
  147. package/dist/modules/custom-fields/wire.d.ts +12 -0
  148. package/dist/modules/custom-fields/wire.d.ts.map +1 -0
  149. package/dist/modules/custom-fields/wire.js +30 -0
  150. package/dist/modules/custom-fields/wire.js.map +1 -0
  151. package/dist/modules/dashboard/repository.d.ts.map +1 -1
  152. package/dist/modules/dashboard/repository.js +4 -3
  153. package/dist/modules/dashboard/repository.js.map +1 -1
  154. package/dist/modules/deals/index.d.ts +2 -1
  155. package/dist/modules/deals/index.d.ts.map +1 -1
  156. package/dist/modules/deals/index.js +5 -2
  157. package/dist/modules/deals/index.js.map +1 -1
  158. package/dist/modules/deals/repository.d.ts +0 -16
  159. package/dist/modules/deals/repository.d.ts.map +1 -1
  160. package/dist/modules/deals/repository.js +6 -76
  161. package/dist/modules/deals/repository.js.map +1 -1
  162. package/dist/modules/deals/routes.d.ts +14 -0
  163. package/dist/modules/deals/routes.d.ts.map +1 -1
  164. package/dist/modules/deals/routes.js +7 -0
  165. package/dist/modules/deals/routes.js.map +1 -1
  166. package/dist/modules/deals/schema.d.ts +20 -42
  167. package/dist/modules/deals/schema.d.ts.map +1 -1
  168. package/dist/modules/deals/schema.js +6 -11
  169. package/dist/modules/deals/schema.js.map +1 -1
  170. package/dist/modules/deals/service.d.ts +13 -2
  171. package/dist/modules/deals/service.d.ts.map +1 -1
  172. package/dist/modules/deals/service.js +43 -20
  173. package/dist/modules/deals/service.js.map +1 -1
  174. package/dist/modules/decisions/repository.d.ts.map +1 -1
  175. package/dist/modules/decisions/repository.js +2 -0
  176. package/dist/modules/decisions/repository.js.map +1 -1
  177. package/dist/modules/decisions/routes.d.ts +1 -0
  178. package/dist/modules/decisions/routes.d.ts.map +1 -1
  179. package/dist/modules/email-domain-linker/index.d.ts +12 -0
  180. package/dist/modules/email-domain-linker/index.d.ts.map +1 -0
  181. package/dist/modules/email-domain-linker/index.js +34 -0
  182. package/dist/modules/email-domain-linker/index.js.map +1 -0
  183. package/dist/modules/email-domain-linker/routes.d.ts +14 -0
  184. package/dist/modules/email-domain-linker/routes.d.ts.map +1 -0
  185. package/dist/modules/email-domain-linker/routes.js +15 -0
  186. package/dist/modules/email-domain-linker/routes.js.map +1 -0
  187. package/dist/modules/email-domain-linker/service.d.ts +37 -0
  188. package/dist/modules/email-domain-linker/service.d.ts.map +1 -0
  189. package/dist/modules/email-domain-linker/service.js +63 -0
  190. package/dist/modules/email-domain-linker/service.js.map +1 -0
  191. package/dist/modules/enquiries/events.d.ts +44 -0
  192. package/dist/modules/enquiries/events.d.ts.map +1 -0
  193. package/dist/modules/enquiries/events.js +19 -0
  194. package/dist/modules/enquiries/events.js.map +1 -0
  195. package/dist/modules/enquiries/index.d.ts +13 -0
  196. package/dist/modules/enquiries/index.d.ts.map +1 -0
  197. package/dist/modules/enquiries/index.js +44 -0
  198. package/dist/modules/enquiries/index.js.map +1 -0
  199. package/dist/modules/enquiries/repository.d.ts +30 -0
  200. package/dist/modules/enquiries/repository.d.ts.map +1 -0
  201. package/dist/modules/enquiries/repository.js +94 -0
  202. package/dist/modules/enquiries/repository.js.map +1 -0
  203. package/dist/modules/enquiries/routes.d.ts +52 -0
  204. package/dist/modules/enquiries/routes.d.ts.map +1 -0
  205. package/dist/modules/enquiries/routes.js +127 -0
  206. package/dist/modules/enquiries/routes.js.map +1 -0
  207. package/dist/modules/enquiries/schema.d.ts +290 -0
  208. package/dist/modules/enquiries/schema.d.ts.map +1 -0
  209. package/dist/modules/enquiries/schema.js +52 -0
  210. package/dist/modules/enquiries/schema.js.map +1 -0
  211. package/dist/modules/enquiries/service.d.ts +85 -0
  212. package/dist/modules/enquiries/service.d.ts.map +1 -0
  213. package/dist/modules/enquiries/service.js +370 -0
  214. package/dist/modules/enquiries/service.js.map +1 -0
  215. package/dist/modules/enquiries/tools.d.ts +4 -0
  216. package/dist/modules/enquiries/tools.d.ts.map +1 -0
  217. package/dist/modules/enquiries/tools.js +50 -0
  218. package/dist/modules/enquiries/tools.js.map +1 -0
  219. package/dist/modules/eventCatalogs.d.ts +4 -0
  220. package/dist/modules/eventCatalogs.d.ts.map +1 -1
  221. package/dist/modules/eventCatalogs.js +4 -0
  222. package/dist/modules/eventCatalogs.js.map +1 -1
  223. package/dist/modules/forms/embed.d.ts +20 -6
  224. package/dist/modules/forms/embed.d.ts.map +1 -1
  225. package/dist/modules/forms/embed.js +359 -43
  226. package/dist/modules/forms/embed.js.map +1 -1
  227. package/dist/modules/forms/events.d.ts +20 -7
  228. package/dist/modules/forms/events.d.ts.map +1 -1
  229. package/dist/modules/forms/events.js +20 -2
  230. package/dist/modules/forms/events.js.map +1 -1
  231. package/dist/modules/forms/fields.d.ts +14 -1
  232. package/dist/modules/forms/fields.d.ts.map +1 -1
  233. package/dist/modules/forms/fields.js +87 -3
  234. package/dist/modules/forms/fields.js.map +1 -1
  235. package/dist/modules/forms/index.d.ts.map +1 -1
  236. package/dist/modules/forms/index.js +12 -1
  237. package/dist/modules/forms/index.js.map +1 -1
  238. package/dist/modules/forms/mapping.d.ts +62 -5
  239. package/dist/modules/forms/mapping.d.ts.map +1 -1
  240. package/dist/modules/forms/mapping.js +139 -5
  241. package/dist/modules/forms/mapping.js.map +1 -1
  242. package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
  243. package/dist/modules/forms/publicRoutes.js +29 -1
  244. package/dist/modules/forms/publicRoutes.js.map +1 -1
  245. package/dist/modules/forms/repository.d.ts +31 -0
  246. package/dist/modules/forms/repository.d.ts.map +1 -1
  247. package/dist/modules/forms/repository.js +90 -1
  248. package/dist/modules/forms/repository.js.map +1 -1
  249. package/dist/modules/forms/routes.d.ts +83 -1
  250. package/dist/modules/forms/routes.d.ts.map +1 -1
  251. package/dist/modules/forms/routes.js +185 -2
  252. package/dist/modules/forms/routes.js.map +1 -1
  253. package/dist/modules/forms/schema.d.ts +672 -1
  254. package/dist/modules/forms/schema.d.ts.map +1 -1
  255. package/dist/modules/forms/schema.js +146 -3
  256. package/dist/modules/forms/schema.js.map +1 -1
  257. package/dist/modules/forms/service.d.ts +54 -1
  258. package/dist/modules/forms/service.d.ts.map +1 -1
  259. package/dist/modules/forms/service.js +338 -28
  260. package/dist/modules/forms/service.js.map +1 -1
  261. package/dist/modules/forms/submission.d.ts +15 -0
  262. package/dist/modules/forms/submission.d.ts.map +1 -1
  263. package/dist/modules/forms/submission.js +418 -40
  264. package/dist/modules/forms/submission.js.map +1 -1
  265. package/dist/modules/import-export/drafts.d.ts +10 -0
  266. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  267. package/dist/modules/import-export/drafts.js +16 -2
  268. package/dist/modules/import-export/drafts.js.map +1 -1
  269. package/dist/modules/import-export/exportRows.d.ts +7 -4
  270. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  271. package/dist/modules/import-export/exportRows.js +20 -5
  272. package/dist/modules/import-export/exportRows.js.map +1 -1
  273. package/dist/modules/import-export/plan.d.ts +12 -1
  274. package/dist/modules/import-export/plan.d.ts.map +1 -1
  275. package/dist/modules/import-export/plan.js +29 -2
  276. package/dist/modules/import-export/plan.js.map +1 -1
  277. package/dist/modules/import-export/presets.d.ts.map +1 -1
  278. package/dist/modules/import-export/presets.js +10 -0
  279. package/dist/modules/import-export/presets.js.map +1 -1
  280. package/dist/modules/import-export/repository.d.ts +11 -1
  281. package/dist/modules/import-export/repository.d.ts.map +1 -1
  282. package/dist/modules/import-export/repository.js +42 -9
  283. package/dist/modules/import-export/repository.js.map +1 -1
  284. package/dist/modules/import-export/routes.d.ts.map +1 -1
  285. package/dist/modules/import-export/routes.js +4 -0
  286. package/dist/modules/import-export/routes.js.map +1 -1
  287. package/dist/modules/import-export/schema.d.ts +17 -0
  288. package/dist/modules/import-export/schema.d.ts.map +1 -1
  289. package/dist/modules/import-export/schema.js +11 -0
  290. package/dist/modules/import-export/schema.js.map +1 -1
  291. package/dist/modules/import-export/service.d.ts +6 -0
  292. package/dist/modules/import-export/service.d.ts.map +1 -1
  293. package/dist/modules/import-export/service.js +14 -2
  294. package/dist/modules/import-export/service.js.map +1 -1
  295. package/dist/modules/import-export/streams.d.ts.map +1 -1
  296. package/dist/modules/import-export/streams.js +3 -3
  297. package/dist/modules/import-export/streams.js.map +1 -1
  298. package/dist/modules/import-export/tools.d.ts.map +1 -1
  299. package/dist/modules/import-export/tools.js +8 -0
  300. package/dist/modules/import-export/tools.js.map +1 -1
  301. package/dist/modules/import-export/validation.d.ts.map +1 -1
  302. package/dist/modules/import-export/validation.js +22 -1
  303. package/dist/modules/import-export/validation.js.map +1 -1
  304. package/dist/modules/import-export/writes.d.ts.map +1 -1
  305. package/dist/modules/import-export/writes.js +37 -4
  306. package/dist/modules/import-export/writes.js.map +1 -1
  307. package/dist/modules/lists/events.d.ts +42 -0
  308. package/dist/modules/lists/events.d.ts.map +1 -0
  309. package/dist/modules/lists/events.js +16 -0
  310. package/dist/modules/lists/events.js.map +1 -0
  311. package/dist/modules/lists/index.d.ts +10 -0
  312. package/dist/modules/lists/index.d.ts.map +1 -0
  313. package/dist/modules/lists/index.js +35 -0
  314. package/dist/modules/lists/index.js.map +1 -0
  315. package/dist/modules/lists/repository.d.ts +80 -0
  316. package/dist/modules/lists/repository.d.ts.map +1 -0
  317. package/dist/modules/lists/repository.js +178 -0
  318. package/dist/modules/lists/repository.js.map +1 -0
  319. package/dist/modules/lists/routes.d.ts +55 -0
  320. package/dist/modules/lists/routes.d.ts.map +1 -0
  321. package/dist/modules/lists/routes.js +168 -0
  322. package/dist/modules/lists/routes.js.map +1 -0
  323. package/dist/modules/lists/schema.d.ts +281 -0
  324. package/dist/modules/lists/schema.d.ts.map +1 -0
  325. package/dist/modules/lists/schema.js +83 -0
  326. package/dist/modules/lists/schema.js.map +1 -0
  327. package/dist/modules/lists/service.d.ts +82 -0
  328. package/dist/modules/lists/service.d.ts.map +1 -0
  329. package/dist/modules/lists/service.js +262 -0
  330. package/dist/modules/lists/service.js.map +1 -0
  331. package/dist/modules/lists/tools.d.ts +4 -0
  332. package/dist/modules/lists/tools.d.ts.map +1 -0
  333. package/dist/modules/lists/tools.js +86 -0
  334. package/dist/modules/lists/tools.js.map +1 -0
  335. package/dist/modules/mcp/index.d.ts.map +1 -1
  336. package/dist/modules/mcp/index.js +5 -0
  337. package/dist/modules/mcp/index.js.map +1 -1
  338. package/dist/modules/notes/routes.d.ts +1 -0
  339. package/dist/modules/notes/routes.d.ts.map +1 -1
  340. package/dist/modules/opportunities/index.d.ts.map +1 -1
  341. package/dist/modules/opportunities/index.js +3 -1
  342. package/dist/modules/opportunities/index.js.map +1 -1
  343. package/dist/modules/opportunities/repository.d.ts +2 -0
  344. package/dist/modules/opportunities/repository.d.ts.map +1 -1
  345. package/dist/modules/opportunities/repository.js +4 -0
  346. package/dist/modules/opportunities/repository.js.map +1 -1
  347. package/dist/modules/opportunities/routes.d.ts +16 -0
  348. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  349. package/dist/modules/opportunities/routes.js +13 -0
  350. package/dist/modules/opportunities/routes.js.map +1 -1
  351. package/dist/modules/opportunities/schema.d.ts +20 -0
  352. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  353. package/dist/modules/opportunities/schema.js +6 -1
  354. package/dist/modules/opportunities/schema.js.map +1 -1
  355. package/dist/modules/opportunities/service.d.ts +20 -3
  356. package/dist/modules/opportunities/service.d.ts.map +1 -1
  357. package/dist/modules/opportunities/service.js +99 -18
  358. package/dist/modules/opportunities/service.js.map +1 -1
  359. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  360. package/dist/modules/opportunities/tools.js +2 -0
  361. package/dist/modules/opportunities/tools.js.map +1 -1
  362. package/dist/modules/partnerships/index.d.ts.map +1 -1
  363. package/dist/modules/partnerships/index.js +3 -1
  364. package/dist/modules/partnerships/index.js.map +1 -1
  365. package/dist/modules/partnerships/repository.d.ts +0 -17
  366. package/dist/modules/partnerships/repository.d.ts.map +1 -1
  367. package/dist/modules/partnerships/repository.js +6 -82
  368. package/dist/modules/partnerships/repository.js.map +1 -1
  369. package/dist/modules/partnerships/routes.d.ts +14 -0
  370. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  371. package/dist/modules/partnerships/routes.js +7 -0
  372. package/dist/modules/partnerships/routes.js.map +1 -1
  373. package/dist/modules/partnerships/schema.d.ts +20 -41
  374. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  375. package/dist/modules/partnerships/schema.js +6 -10
  376. package/dist/modules/partnerships/schema.js.map +1 -1
  377. package/dist/modules/partnerships/service.d.ts +11 -1
  378. package/dist/modules/partnerships/service.d.ts.map +1 -1
  379. package/dist/modules/partnerships/service.js +43 -20
  380. package/dist/modules/partnerships/service.js.map +1 -1
  381. package/dist/modules/people/consentHydration.d.ts +26 -0
  382. package/dist/modules/people/consentHydration.d.ts.map +1 -0
  383. package/dist/modules/people/consentHydration.js +100 -0
  384. package/dist/modules/people/consentHydration.js.map +1 -0
  385. package/dist/modules/people/index.d.ts.map +1 -1
  386. package/dist/modules/people/index.js +3 -1
  387. package/dist/modules/people/index.js.map +1 -1
  388. package/dist/modules/people/personConsentWrites.d.ts +40 -0
  389. package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
  390. package/dist/modules/people/personConsentWrites.js +98 -0
  391. package/dist/modules/people/personConsentWrites.js.map +1 -0
  392. package/dist/modules/people/repository.d.ts +11 -0
  393. package/dist/modules/people/repository.d.ts.map +1 -1
  394. package/dist/modules/people/repository.js +21 -1
  395. package/dist/modules/people/repository.js.map +1 -1
  396. package/dist/modules/people/routes.d.ts +57 -4
  397. package/dist/modules/people/routes.d.ts.map +1 -1
  398. package/dist/modules/people/routes.js +104 -5
  399. package/dist/modules/people/routes.js.map +1 -1
  400. package/dist/modules/people/schema.d.ts +366 -1
  401. package/dist/modules/people/schema.d.ts.map +1 -1
  402. package/dist/modules/people/schema.js +92 -2
  403. package/dist/modules/people/schema.js.map +1 -1
  404. package/dist/modules/people/service.d.ts +30 -1
  405. package/dist/modules/people/service.d.ts.map +1 -1
  406. package/dist/modules/people/service.js +131 -36
  407. package/dist/modules/people/service.js.map +1 -1
  408. package/dist/modules/people/tools.d.ts.map +1 -1
  409. package/dist/modules/people/tools.js +4 -1
  410. package/dist/modules/people/tools.js.map +1 -1
  411. package/dist/modules/personLinks.d.ts +79 -0
  412. package/dist/modules/personLinks.d.ts.map +1 -0
  413. package/dist/modules/personLinks.js +155 -0
  414. package/dist/modules/personLinks.js.map +1 -0
  415. package/dist/modules/pipelines/routes.d.ts +1 -0
  416. package/dist/modules/pipelines/routes.d.ts.map +1 -1
  417. package/dist/modules/plans/routes.d.ts +1 -0
  418. package/dist/modules/plans/routes.d.ts.map +1 -1
  419. package/dist/modules/positions/routes.d.ts.map +1 -1
  420. package/dist/modules/positions/routes.js +4 -2
  421. package/dist/modules/positions/routes.js.map +1 -1
  422. package/dist/modules/raises/index.d.ts.map +1 -1
  423. package/dist/modules/raises/index.js +3 -1
  424. package/dist/modules/raises/index.js.map +1 -1
  425. package/dist/modules/raises/repository.d.ts +0 -17
  426. package/dist/modules/raises/repository.d.ts.map +1 -1
  427. package/dist/modules/raises/repository.js +6 -77
  428. package/dist/modules/raises/repository.js.map +1 -1
  429. package/dist/modules/raises/routes.d.ts +14 -0
  430. package/dist/modules/raises/routes.d.ts.map +1 -1
  431. package/dist/modules/raises/routes.js +7 -0
  432. package/dist/modules/raises/routes.js.map +1 -1
  433. package/dist/modules/raises/schema.d.ts +20 -41
  434. package/dist/modules/raises/schema.d.ts.map +1 -1
  435. package/dist/modules/raises/schema.js +6 -10
  436. package/dist/modules/raises/schema.js.map +1 -1
  437. package/dist/modules/raises/service.d.ts +11 -1
  438. package/dist/modules/raises/service.d.ts.map +1 -1
  439. package/dist/modules/raises/service.js +41 -18
  440. package/dist/modules/raises/service.js.map +1 -1
  441. package/dist/modules/recordTargets.d.ts.map +1 -1
  442. package/dist/modules/recordTargets.js +2 -0
  443. package/dist/modules/recordTargets.js.map +1 -1
  444. package/dist/modules/references.d.ts +10 -0
  445. package/dist/modules/references.d.ts.map +1 -1
  446. package/dist/modules/references.js +27 -4
  447. package/dist/modules/references.js.map +1 -1
  448. package/dist/modules/sample-data/fixture.d.ts +160 -0
  449. package/dist/modules/sample-data/fixture.d.ts.map +1 -0
  450. package/dist/modules/sample-data/fixture.js +501 -0
  451. package/dist/modules/sample-data/fixture.js.map +1 -0
  452. package/dist/modules/sample-data/index.d.ts +11 -0
  453. package/dist/modules/sample-data/index.d.ts.map +1 -0
  454. package/dist/modules/sample-data/index.js +44 -0
  455. package/dist/modules/sample-data/index.js.map +1 -0
  456. package/dist/modules/sample-data/routes.d.ts +15 -0
  457. package/dist/modules/sample-data/routes.d.ts.map +1 -0
  458. package/dist/modules/sample-data/routes.js +25 -0
  459. package/dist/modules/sample-data/routes.js.map +1 -0
  460. package/dist/modules/sample-data/service.d.ts +39 -0
  461. package/dist/modules/sample-data/service.d.ts.map +1 -0
  462. package/dist/modules/sample-data/service.js +481 -0
  463. package/dist/modules/sample-data/service.js.map +1 -0
  464. package/dist/modules/sample-data/tools.d.ts +4 -0
  465. package/dist/modules/sample-data/tools.d.ts.map +1 -0
  466. package/dist/modules/sample-data/tools.js +22 -0
  467. package/dist/modules/sample-data/tools.js.map +1 -0
  468. package/dist/modules/search/index.d.ts +1 -1
  469. package/dist/modules/search/index.d.ts.map +1 -1
  470. package/dist/modules/search/index.js +2 -1
  471. package/dist/modules/search/index.js.map +1 -1
  472. package/dist/modules/search/repository.d.ts +1 -0
  473. package/dist/modules/search/repository.d.ts.map +1 -1
  474. package/dist/modules/search/repository.js +23 -0
  475. package/dist/modules/search/repository.js.map +1 -1
  476. package/dist/modules/search/service.d.ts +3 -3
  477. package/dist/modules/search/service.d.ts.map +1 -1
  478. package/dist/modules/search/service.js +5 -4
  479. package/dist/modules/search/service.js.map +1 -1
  480. package/dist/modules/smtp-email/index.d.ts +1 -0
  481. package/dist/modules/smtp-email/index.d.ts.map +1 -1
  482. package/dist/modules/smtp-email/index.js +1 -0
  483. package/dist/modules/smtp-email/index.js.map +1 -1
  484. package/dist/modules/stagedRecords.d.ts +3 -3
  485. package/dist/modules/stagedRecords.d.ts.map +1 -1
  486. package/dist/modules/stagedRecords.js +9 -0
  487. package/dist/modules/stagedRecords.js.map +1 -1
  488. package/dist/modules/webhooks/payloads.d.ts.map +1 -1
  489. package/dist/modules/webhooks/payloads.js +15 -2
  490. package/dist/modules/webhooks/payloads.js.map +1 -1
  491. package/dist/modules/workspace/repository.d.ts +2 -0
  492. package/dist/modules/workspace/repository.d.ts.map +1 -1
  493. package/dist/modules/workspace/repository.js +7 -0
  494. package/dist/modules/workspace/repository.js.map +1 -1
  495. package/dist/modules/workspace/service.d.ts.map +1 -1
  496. package/dist/modules/workspace/service.js +20 -1
  497. package/dist/modules/workspace/service.js.map +1 -1
  498. package/dist/modules/workspace/starters.d.ts.map +1 -1
  499. package/dist/modules/workspace/starters.js +5 -0
  500. package/dist/modules/workspace/starters.js.map +1 -1
  501. package/dist/runtime/events.d.ts +1 -1
  502. package/dist/runtime/events.d.ts.map +1 -1
  503. package/dist/runtime/events.js +1 -0
  504. package/dist/runtime/events.js.map +1 -1
  505. package/dist/schema/index.d.ts +4 -0
  506. package/dist/schema/index.d.ts.map +1 -1
  507. package/dist/schema/index.js +4 -0
  508. package/dist/schema/index.js.map +1 -1
  509. package/dist/testing/database.d.ts +5 -1
  510. package/dist/testing/database.d.ts.map +1 -1
  511. package/dist/testing/database.js +81 -10
  512. package/dist/testing/database.js.map +1 -1
  513. package/migrations/0021_certain_maggott.sql +30 -0
  514. package/migrations/0022_stormy_manta.sql +1 -0
  515. package/migrations/0023_funny_maddog.sql +1 -0
  516. package/migrations/0024_third_king_cobra.sql +46 -0
  517. package/migrations/0025_worthless_chimera.sql +3 -0
  518. package/migrations/0026_late_aqueduct.sql +46 -0
  519. package/migrations/0027_brainy_silver_sable.sql +3 -0
  520. package/migrations/0028_freezing_scrambler.sql +19 -0
  521. package/migrations/0029_custom_fields.sql +26 -0
  522. package/migrations/0030_enquiries.sql +79 -0
  523. package/migrations/0031_consent.sql +45 -0
  524. package/migrations/0032_form_field_statement.sql +1 -0
  525. package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
  526. package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
  527. package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
  528. package/migrations/0036_form_field_notice_type.sql +2 -0
  529. package/migrations/meta/0021_snapshot.json +5389 -0
  530. package/migrations/meta/0022_snapshot.json +5396 -0
  531. package/migrations/meta/0023_snapshot.json +5403 -0
  532. package/migrations/meta/0024_snapshot.json +5516 -0
  533. package/migrations/meta/0025_snapshot.json +5336 -0
  534. package/migrations/meta/0026_snapshot.json +5710 -0
  535. package/migrations/meta/0027_snapshot.json +5716 -0
  536. package/migrations/meta/0028_snapshot.json +5740 -0
  537. package/migrations/meta/0029_snapshot.json +5935 -0
  538. package/migrations/meta/0030_snapshot.json +6245 -0
  539. package/migrations/meta/0031_snapshot.json +6572 -0
  540. package/migrations/meta/0032_snapshot.json +6578 -0
  541. package/migrations/meta/0033_snapshot.json +6572 -0
  542. package/migrations/meta/0034_snapshot.json +6566 -0
  543. package/migrations/meta/0035_snapshot.json +6573 -0
  544. package/migrations/meta/0036_snapshot.json +6573 -0
  545. package/migrations/meta/_journal.json +112 -0
  546. package/package.json +3 -2
  547. package/src/lib/consumerEmailDomains.ts +62 -0
  548. package/src/lib/email.ts +7 -0
  549. package/src/lib/emailContent.ts +91 -0
  550. package/src/lib/emailDomainAutoLink.ts +165 -0
  551. package/src/lib/ids.ts +13 -0
  552. package/src/modules/activities/repository.ts +22 -23
  553. package/src/modules/activities/wording.ts +18 -0
  554. package/src/modules/agent-tasks/catalog.ts +63 -0
  555. package/src/modules/agent-tasks/resolve.ts +64 -24
  556. package/src/modules/attachedRecords.ts +37 -3
  557. package/src/modules/auth/preferences.ts +13 -1
  558. package/src/modules/auth/routes.ts +22 -0
  559. package/src/modules/auth/schema.ts +12 -2
  560. package/src/modules/auth/service.ts +37 -3
  561. package/src/modules/companies/index.ts +3 -1
  562. package/src/modules/companies/repository.ts +3 -0
  563. package/src/modules/companies/routes.ts +20 -0
  564. package/src/modules/companies/schema.ts +11 -1
  565. package/src/modules/companies/service.ts +72 -12
  566. package/src/modules/consent-purposes/capabilities.ts +12 -0
  567. package/src/modules/consent-purposes/events.ts +38 -0
  568. package/src/modules/consent-purposes/index.ts +48 -0
  569. package/src/modules/consent-purposes/repository.ts +163 -0
  570. package/src/modules/consent-purposes/routes.ts +122 -0
  571. package/src/modules/consent-purposes/schema.ts +46 -0
  572. package/src/modules/consent-purposes/service.ts +423 -0
  573. package/src/modules/consent-purposes/starters.ts +32 -0
  574. package/src/modules/consent-purposes/tools.ts +44 -0
  575. package/src/modules/core.ts +21 -0
  576. package/src/modules/custom-fields/capabilities.ts +17 -0
  577. package/src/modules/custom-fields/events.ts +51 -0
  578. package/src/modules/custom-fields/index.ts +61 -0
  579. package/src/modules/custom-fields/repository.ts +225 -0
  580. package/src/modules/custom-fields/routes.ts +155 -0
  581. package/src/modules/custom-fields/schema.ts +61 -0
  582. package/src/modules/custom-fields/service.ts +439 -0
  583. package/src/modules/custom-fields/tools.ts +53 -0
  584. package/src/modules/custom-fields/values.ts +352 -0
  585. package/src/modules/custom-fields/wire.ts +32 -0
  586. package/src/modules/dashboard/repository.ts +4 -3
  587. package/src/modules/deals/index.ts +5 -2
  588. package/src/modules/deals/repository.ts +6 -106
  589. package/src/modules/deals/routes.ts +7 -0
  590. package/src/modules/deals/schema.ts +7 -15
  591. package/src/modules/deals/service.ts +92 -23
  592. package/src/modules/decisions/repository.ts +2 -0
  593. package/src/modules/email-domain-linker/index.ts +40 -0
  594. package/src/modules/email-domain-linker/routes.ts +40 -0
  595. package/src/modules/email-domain-linker/service.ts +122 -0
  596. package/src/modules/enquiries/events.ts +45 -0
  597. package/src/modules/enquiries/index.ts +50 -0
  598. package/src/modules/enquiries/repository.ts +164 -0
  599. package/src/modules/enquiries/routes.ts +172 -0
  600. package/src/modules/enquiries/schema.ts +59 -0
  601. package/src/modules/enquiries/service.ts +644 -0
  602. package/src/modules/enquiries/tools.ts +66 -0
  603. package/src/modules/eventCatalogs.ts +4 -0
  604. package/src/modules/forms/embed.ts +391 -44
  605. package/src/modules/forms/events.ts +30 -2
  606. package/src/modules/forms/fields.ts +102 -2
  607. package/src/modules/forms/index.ts +12 -1
  608. package/src/modules/forms/mapping.ts +183 -6
  609. package/src/modules/forms/publicRoutes.ts +43 -1
  610. package/src/modules/forms/repository.ts +162 -1
  611. package/src/modules/forms/routes.ts +212 -2
  612. package/src/modules/forms/schema.ts +166 -4
  613. package/src/modules/forms/service.ts +565 -41
  614. package/src/modules/forms/submission.ts +718 -44
  615. package/src/modules/import-export/drafts.ts +20 -1
  616. package/src/modules/import-export/exportRows.ts +21 -5
  617. package/src/modules/import-export/plan.ts +47 -2
  618. package/src/modules/import-export/presets.ts +10 -0
  619. package/src/modules/import-export/repository.ts +73 -8
  620. package/src/modules/import-export/routes.ts +4 -0
  621. package/src/modules/import-export/schema.ts +11 -0
  622. package/src/modules/import-export/service.ts +28 -2
  623. package/src/modules/import-export/streams.ts +3 -1
  624. package/src/modules/import-export/tools.ts +10 -0
  625. package/src/modules/import-export/validation.ts +28 -0
  626. package/src/modules/import-export/writes.ts +70 -5
  627. package/src/modules/lists/events.ts +41 -0
  628. package/src/modules/lists/index.ts +41 -0
  629. package/src/modules/lists/repository.ts +343 -0
  630. package/src/modules/lists/routes.ts +255 -0
  631. package/src/modules/lists/schema.ts +95 -0
  632. package/src/modules/lists/service.ts +505 -0
  633. package/src/modules/lists/tools.ts +128 -0
  634. package/src/modules/mcp/index.ts +5 -0
  635. package/src/modules/opportunities/index.ts +3 -1
  636. package/src/modules/opportunities/repository.ts +11 -0
  637. package/src/modules/opportunities/routes.ts +13 -0
  638. package/src/modules/opportunities/schema.ts +7 -1
  639. package/src/modules/opportunities/service.ts +188 -22
  640. package/src/modules/opportunities/tools.ts +2 -0
  641. package/src/modules/partnerships/index.ts +3 -1
  642. package/src/modules/partnerships/repository.ts +6 -117
  643. package/src/modules/partnerships/routes.ts +7 -0
  644. package/src/modules/partnerships/schema.ts +7 -14
  645. package/src/modules/partnerships/service.ts +93 -22
  646. package/src/modules/people/consentHydration.ts +167 -0
  647. package/src/modules/people/index.ts +3 -1
  648. package/src/modules/people/personConsentWrites.ts +177 -0
  649. package/src/modules/people/repository.ts +31 -0
  650. package/src/modules/people/routes.ts +127 -18
  651. package/src/modules/people/schema.ts +109 -3
  652. package/src/modules/people/service.ts +205 -39
  653. package/src/modules/people/tools.ts +5 -1
  654. package/src/modules/personLinks.ts +278 -0
  655. package/src/modules/positions/routes.ts +4 -2
  656. package/src/modules/raises/index.ts +3 -1
  657. package/src/modules/raises/repository.ts +6 -107
  658. package/src/modules/raises/routes.ts +7 -0
  659. package/src/modules/raises/schema.ts +7 -14
  660. package/src/modules/raises/service.ts +91 -20
  661. package/src/modules/recordTargets.ts +2 -0
  662. package/src/modules/references.ts +43 -4
  663. package/src/modules/sample-data/fixture.ts +690 -0
  664. package/src/modules/sample-data/index.ts +51 -0
  665. package/src/modules/sample-data/routes.ts +50 -0
  666. package/src/modules/sample-data/service.ts +679 -0
  667. package/src/modules/sample-data/tools.ts +32 -0
  668. package/src/modules/search/index.ts +2 -1
  669. package/src/modules/search/repository.ts +33 -1
  670. package/src/modules/search/service.ts +7 -5
  671. package/src/modules/smtp-email/index.ts +8 -1
  672. package/src/modules/stagedRecords.ts +18 -3
  673. package/src/modules/webhooks/payloads.ts +20 -2
  674. package/src/modules/workspace/repository.ts +12 -0
  675. package/src/modules/workspace/service.ts +27 -1
  676. package/src/modules/workspace/starters.ts +5 -0
  677. package/src/runtime/events.ts +1 -0
  678. package/src/schema/index.ts +4 -0
  679. package/src/testing/database.ts +97 -11
@@ -0,0 +1,352 @@
1
+ import type { CustomFieldValue, CustomFieldWireValue } from '@kelpie/schemas'
2
+
3
+ import { AppError } from '../../lib/errors.ts'
4
+ import type { ErrorDetail } from '../../lib/errors.ts'
5
+ import type { Queryable } from '../../runtime/transaction.ts'
6
+ import { definitionsForObject } from './repository.ts'
7
+ import type { CustomFieldDefinitionRecord } from './repository.ts'
8
+ import type { CustomFieldObjectType } from './schema.ts'
9
+
10
+ /**
11
+ * The service half of custom-field values: definition-aware validation, merge
12
+ * semantics, and the per-key diff a `record.updated` event carries.
13
+ *
14
+ * The Zod layer on the record's route body only checks structure (that a value
15
+ * looks like text/number/boolean/list/money). Everything below reads the
16
+ * workspace's definitions and enforces the concrete type, the select-option
17
+ * membership, and the caps every type carries. Mismatches throw the same
18
+ * `AppError.validationFailed(msg, [{field: 'custom_fields.<key>', message}])`
19
+ * `readJsonBody` produces, so an unknown key and a wrong-type value read alike
20
+ * to a client.
21
+ */
22
+
23
+ const MAX_TEXT_LENGTH = 4096
24
+ const MAX_LONG_TEXT_LENGTH = 65536
25
+ const MAX_URL_LENGTH = 2048
26
+ const MAX_MULTI_SELECT_ENTRIES = 100
27
+
28
+ /** The stored jsonb value for one custom field, as the record carries it. */
29
+ export type StoredCustomFieldValue = CustomFieldValue
30
+
31
+ /** The result of merging a `PATCH` into the stored `custom_fields` object. */
32
+ export interface CustomFieldsMerge {
33
+ /** The whole custom_fields object to write, with keys sorted for stable diffs. */
34
+ readonly merged: Readonly<Record<string, StoredCustomFieldValue>>
35
+ /** Per-key change paths, `customFields.<key>`, for the `.updated` event's `changed`. */
36
+ readonly changedPaths: readonly string[]
37
+ /** Definition labels for the keys that changed, keyed by their `customFields.<key>` path. */
38
+ readonly labels: Readonly<Record<string, string>>
39
+ /** Flat before-values for `describeUpdate`, keyed by `customFields.<key>`. */
40
+ readonly flatBefore: Readonly<Record<string, StoredCustomFieldValue | undefined>>
41
+ /** Flat after-values for `describeUpdate`, keyed by `customFields.<key>`. */
42
+ readonly flatAfter: Readonly<Record<string, StoredCustomFieldValue | undefined>>
43
+ }
44
+
45
+ export interface CustomFieldValuesDependencies {
46
+ readonly db: Queryable
47
+ }
48
+
49
+ export interface CustomFieldValuesValidator {
50
+ /**
51
+ * Validates and normalises the `custom_fields` a record is being created with.
52
+ * `null` keys are ignored. Missing keys are simply absent from the result.
53
+ */
54
+ forCreate(
55
+ tx: Queryable,
56
+ workspaceId: string,
57
+ objectType: CustomFieldObjectType,
58
+ sent: Readonly<Record<string, CustomFieldWireValue | null>> | undefined,
59
+ ): Promise<Readonly<Record<string, StoredCustomFieldValue>>>
60
+
61
+ /**
62
+ * Merges a `PATCH` into the stored `custom_fields`, validating every sent
63
+ * key against the workspace's definitions. `null` clears a key. An unknown
64
+ * key is `422`.
65
+ */
66
+ forUpdate(
67
+ tx: Queryable,
68
+ workspaceId: string,
69
+ objectType: CustomFieldObjectType,
70
+ stored: Readonly<Record<string, StoredCustomFieldValue>>,
71
+ sent: Readonly<Record<string, CustomFieldWireValue | null>> | undefined,
72
+ ): Promise<CustomFieldsMerge | undefined>
73
+ }
74
+
75
+ export function createCustomFieldValues(
76
+ _dependencies: CustomFieldValuesDependencies,
77
+ ): CustomFieldValuesValidator {
78
+ return {
79
+ async forCreate(tx, workspaceId, objectType, sent) {
80
+ if (sent === undefined) {
81
+ return {}
82
+ }
83
+ const definitions = await definitionsForObject(tx, workspaceId, objectType)
84
+ const byKey = new Map(definitions.map((definition) => [definition.key, definition]))
85
+ const out: Record<string, StoredCustomFieldValue> = {}
86
+
87
+ for (const [key, value] of Object.entries(sent)) {
88
+ if (value === null) {
89
+ // A create with a `null` value has nothing to store; skip.
90
+ continue
91
+ }
92
+ const definition = byKey.get(key)
93
+ if (definition === undefined) {
94
+ throw unknownKey(key)
95
+ }
96
+ out[key] = validateValue(definition, value)
97
+ }
98
+
99
+ return normaliseCustomFields(out)
100
+ },
101
+
102
+ async forUpdate(tx, workspaceId, objectType, stored, sent) {
103
+ if (sent === undefined) {
104
+ return undefined
105
+ }
106
+ const definitions = await definitionsForObject(tx, workspaceId, objectType)
107
+ const byKey = new Map(definitions.map((definition) => [definition.key, definition]))
108
+ const next: Record<string, StoredCustomFieldValue> = { ...stored }
109
+ const changedPaths: string[] = []
110
+ const labels: Record<string, string> = {}
111
+ const flatBefore: Record<string, StoredCustomFieldValue | undefined> = {}
112
+ const flatAfter: Record<string, StoredCustomFieldValue | undefined> = {}
113
+
114
+ for (const [key, value] of Object.entries(sent)) {
115
+ const definition = byKey.get(key)
116
+ if (definition === undefined) {
117
+ throw unknownKey(key)
118
+ }
119
+ const path = `customFields.${key}`
120
+ const before = stored[key]
121
+
122
+ if (value === null) {
123
+ if (before === undefined) {
124
+ continue
125
+ }
126
+ delete next[key]
127
+ changedPaths.push(path)
128
+ labels[path] = definition.label
129
+ flatBefore[path] = before
130
+ flatAfter[path] = undefined
131
+ continue
132
+ }
133
+
134
+ const validated = validateValue(definition, value)
135
+ if (!sameValue(before, validated)) {
136
+ next[key] = validated
137
+ changedPaths.push(path)
138
+ labels[path] = definition.label
139
+ flatBefore[path] = before
140
+ flatAfter[path] = validated
141
+ } else {
142
+ // Sent again with the identical value: no change, no path, but keep
143
+ // the value in `next` (a shallow copy already did that).
144
+ next[key] = validated
145
+ }
146
+ }
147
+
148
+ return {
149
+ merged: normaliseCustomFields(next),
150
+ changedPaths,
151
+ labels,
152
+ flatBefore,
153
+ flatAfter,
154
+ }
155
+ },
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Rebuilds the object with keys in sorted order.
161
+ *
162
+ * `changedKeys` in `lib/changes.ts` compares by `JSON.stringify`, so two
163
+ * objects with the same entries but different insertion order would look
164
+ * different. Every stored write and every diffed comparison passes through
165
+ * this so the two agree.
166
+ */
167
+ export function normaliseCustomFields(
168
+ values: Readonly<Record<string, StoredCustomFieldValue>>,
169
+ ): Readonly<Record<string, StoredCustomFieldValue>> {
170
+ const sorted: Record<string, StoredCustomFieldValue> = {}
171
+ for (const key of Object.keys(values).sort()) {
172
+ sorted[key] = values[key] as StoredCustomFieldValue
173
+ }
174
+ return sorted
175
+ }
176
+
177
+ function unknownKey(key: string): AppError {
178
+ return AppError.validationFailed('That custom field is not defined for this record type', [
179
+ { field: `custom_fields.${key}`, message: 'Unknown field' },
180
+ ])
181
+ }
182
+
183
+ function typeError(key: string, message: string): AppError {
184
+ return AppError.validationFailed('That value does not match the custom field', [
185
+ { field: `custom_fields.${key}`, message },
186
+ ])
187
+ }
188
+
189
+ function validateValue(
190
+ definition: CustomFieldDefinitionRecord,
191
+ value: CustomFieldWireValue,
192
+ ): StoredCustomFieldValue {
193
+ switch (definition.type) {
194
+ case 'text':
195
+ return validateString(definition.key, value, MAX_TEXT_LENGTH)
196
+
197
+ case 'long_text':
198
+ return validateString(definition.key, value, MAX_LONG_TEXT_LENGTH)
199
+
200
+ case 'url':
201
+ return validateUrl(definition.key, value)
202
+
203
+ case 'date':
204
+ return validateDate(definition.key, value)
205
+
206
+ case 'number':
207
+ return validateNumber(definition.key, value)
208
+
209
+ case 'checkbox':
210
+ if (typeof value !== 'boolean') {
211
+ throw typeError(definition.key, 'Expected true or false')
212
+ }
213
+ return value
214
+
215
+ case 'select':
216
+ return validateSelect(definition, value)
217
+
218
+ case 'multi_select':
219
+ return validateMultiSelect(definition, value)
220
+
221
+ case 'currency':
222
+ return validateCurrency(definition.key, value)
223
+
224
+ default:
225
+ throw new Error(`custom-field type "${definition.type}" has no validator`)
226
+ }
227
+ }
228
+
229
+ function validateString(key: string, value: CustomFieldWireValue, max: number): string {
230
+ if (typeof value !== 'string') {
231
+ throw typeError(key, 'Expected a string')
232
+ }
233
+ if (value.length > max) {
234
+ throw typeError(key, `At most ${String(max)} characters`)
235
+ }
236
+ return value
237
+ }
238
+
239
+ function validateUrl(key: string, value: CustomFieldWireValue): string {
240
+ const raw = validateString(key, value, MAX_URL_LENGTH)
241
+ let parsed: URL
242
+ try {
243
+ parsed = new URL(raw)
244
+ } catch {
245
+ throw typeError(key, 'Expected an http or https URL')
246
+ }
247
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
248
+ throw typeError(key, 'Expected an http or https URL')
249
+ }
250
+ return raw
251
+ }
252
+
253
+ const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u
254
+
255
+ function validateDate(key: string, value: CustomFieldWireValue): string {
256
+ if (typeof value !== 'string' || !DATE_PATTERN.test(value)) {
257
+ throw typeError(key, 'Expected a YYYY-MM-DD date')
258
+ }
259
+ const [year, month, day] = value.split('-').map((part) => Number(part))
260
+ const parsed = new Date(Date.UTC(year!, (month ?? 1) - 1, day ?? 1))
261
+ if (
262
+ parsed.getUTCFullYear() !== year ||
263
+ parsed.getUTCMonth() !== (month ?? 1) - 1 ||
264
+ parsed.getUTCDate() !== (day ?? 1)
265
+ ) {
266
+ throw typeError(key, 'That date does not exist')
267
+ }
268
+ return value
269
+ }
270
+
271
+ function validateNumber(key: string, value: CustomFieldWireValue): number {
272
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
273
+ throw typeError(key, 'Expected a finite number')
274
+ }
275
+ if (Math.abs(value) > Number.MAX_SAFE_INTEGER) {
276
+ throw typeError(key, 'Number is out of range')
277
+ }
278
+ return value
279
+ }
280
+
281
+ function validateSelect(
282
+ definition: CustomFieldDefinitionRecord,
283
+ value: CustomFieldWireValue,
284
+ ): string {
285
+ if (typeof value !== 'string') {
286
+ throw typeError(definition.key, 'Expected a string')
287
+ }
288
+ if (!definition.options.includes(value)) {
289
+ throw typeError(definition.key, `Not one of the field's options`)
290
+ }
291
+ return value
292
+ }
293
+
294
+ function validateMultiSelect(
295
+ definition: CustomFieldDefinitionRecord,
296
+ value: CustomFieldWireValue,
297
+ ): readonly string[] {
298
+ if (!Array.isArray(value)) {
299
+ throw typeError(definition.key, 'Expected a list of option keys')
300
+ }
301
+ if (value.length > MAX_MULTI_SELECT_ENTRIES) {
302
+ throw typeError(definition.key, `At most ${String(MAX_MULTI_SELECT_ENTRIES)} entries`)
303
+ }
304
+ const seen = new Set<string>()
305
+ for (const entry of value) {
306
+ if (typeof entry !== 'string') {
307
+ throw typeError(definition.key, 'Each entry must be a string')
308
+ }
309
+ if (!definition.options.includes(entry)) {
310
+ throw typeError(definition.key, `"${entry}" is not one of the field's options`)
311
+ }
312
+ if (seen.has(entry)) {
313
+ throw typeError(definition.key, `"${entry}" appears more than once`)
314
+ }
315
+ seen.add(entry)
316
+ }
317
+ // A stored multi_select is a plain array; sort for stable JSON comparison.
318
+ return [...value].sort()
319
+ }
320
+
321
+ function validateCurrency(
322
+ key: string,
323
+ value: CustomFieldWireValue,
324
+ ): { readonly amountCents: number; readonly currency: string } {
325
+ if (
326
+ typeof value !== 'object' ||
327
+ value === null ||
328
+ Array.isArray(value) ||
329
+ !('amount_cents' in value) ||
330
+ !('currency' in value)
331
+ ) {
332
+ throw typeError(key, 'Expected { amount_cents, currency }')
333
+ }
334
+ const cents = value.amount_cents
335
+ if (typeof cents !== 'number' || !Number.isInteger(cents)) {
336
+ throw typeError(key, 'amount_cents must be a whole number of cents')
337
+ }
338
+ const currency = value.currency
339
+ if (typeof currency !== 'string' || !/^[A-Z]{3}$/u.test(currency)) {
340
+ throw typeError(key, 'currency must be a 3-letter uppercase code')
341
+ }
342
+ return { amountCents: cents, currency }
343
+ }
344
+
345
+ function sameValue(before: unknown, after: unknown): boolean {
346
+ return JSON.stringify(before) === JSON.stringify(after)
347
+ }
348
+
349
+ /** Collects one detail-list from several field-level rejections. Unused today; kept for future bulk validators. */
350
+ export function collectDetails(errors: readonly AppError[]): readonly ErrorDetail[] {
351
+ return errors.flatMap((error) => error.details ?? [])
352
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Renders the stored `custom_fields` for a record's wire body.
3
+ *
4
+ * Every value type serialises as itself with one exception: currency lives in
5
+ * the store as `{amountCents, currency}` (camelCase, from
6
+ * `customFieldValuesSchema`'s transform) and goes back over the wire as
7
+ * `{amount_cents, currency}` per the api.md snake_case rule. Every record
8
+ * module's response mapper calls this from one place so the two shapes cannot
9
+ * drift.
10
+ */
11
+ export function renderCustomFieldsForWire(
12
+ values: Readonly<Record<string, unknown>>,
13
+ ): Record<string, unknown> {
14
+ const out: Record<string, unknown> = {}
15
+ for (const [key, value] of Object.entries(values)) {
16
+ if (
17
+ typeof value === 'object' &&
18
+ value !== null &&
19
+ !Array.isArray(value) &&
20
+ 'amountCents' in value &&
21
+ 'currency' in value
22
+ ) {
23
+ out[key] = {
24
+ amount_cents: (value as { amountCents: number }).amountCents,
25
+ currency: (value as { currency: string }).currency,
26
+ }
27
+ } else {
28
+ out[key] = value
29
+ }
30
+ }
31
+ return out
32
+ }
@@ -8,6 +8,7 @@ import type { Queryable } from '../../runtime/transaction.ts'
8
8
  import { activities } from '../activities/schema.ts'
9
9
  import { decisions } from '../decisions/schema.ts'
10
10
  import { deals } from '../deals/schema.ts'
11
+ import { enquiries } from '../enquiries/schema.ts'
11
12
  import { notes } from '../notes/schema.ts'
12
13
  import { opportunities } from '../opportunities/schema.ts'
13
14
  import { partnerships } from '../partnerships/schema.ts'
@@ -88,11 +89,11 @@ function pipelineTable(table: PgTable, workspaceId: PgColumn, stageId: PgColumn)
88
89
  }
89
90
 
90
91
  /**
91
- * Which table each pipeline kind lives in. Partnership is a pipeline like the
92
- * other three: `pipeline_stages.kind` carries all four, and its board columns
93
- * are configured the same way.
92
+ * Which table each pipeline kind lives in. `pipeline_stages.kind` carries all
93
+ * five, and every pipeline's board columns are configured the same way.
94
94
  */
95
95
  const PIPELINE_TABLES: Readonly<Record<PipelineKind, PipelineTable>> = {
96
+ enquiry: pipelineTable(enquiries, enquiries.workspaceId, enquiries.stageId),
96
97
  deal: pipelineTable(deals, deals.workspaceId, deals.stageId),
97
98
  opportunity: pipelineTable(opportunities, opportunities.workspaceId, opportunities.stageId),
98
99
  raise: pipelineTable(raises, raises.workspaceId, raises.stageId),
@@ -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 { dealsEvents } from './events.ts'
4
5
  import { mountDealsRoutes } from './routes.ts'
5
6
  import * as schema from './schema.ts'
@@ -12,12 +13,13 @@ import { registerDealsTools } from './tools.ts'
12
13
  * Requires its relations because creating one checks that the company, stage,
13
14
  * owner, and people are all in the caller's workspace before linking them, and
14
15
  * `activities` because every write leaves its timeline entry in the same
15
- * transaction.
16
+ * transaction. Also requires `custom-fields` so the validator is present when
17
+ * this service constructs.
16
18
  */
17
19
  export function createDealsModule(migrationsDirectory: string): KelpieModule {
18
20
  return {
19
21
  id: 'deals',
20
- requires: ['companies', 'people', 'pipelines', 'activities'],
22
+ requires: ['companies', 'people', 'pipelines', 'activities', 'custom-fields'],
21
23
  events: dealsEvents,
22
24
 
23
25
  register(context) {
@@ -30,6 +32,7 @@ export function createDealsModule(migrationsDirectory: string): KelpieModule {
30
32
  createId: context.createId,
31
33
  now: context.now,
32
34
  }),
35
+ customFields: createCustomFieldValues({ db: context.db }),
33
36
  })
34
37
 
35
38
  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 { dealPeople, deals } from './schema.ts'
11
+ import { deals } from './schema.ts'
12
12
 
13
13
  export type DealRecord = typeof deals.$inferSelect
14
14
 
@@ -49,15 +49,6 @@ function companyNameMatches(pattern: string): SQL {
49
49
  )`
50
50
  }
51
51
 
52
- function hasAnyOfPeople(personIds: readonly string[]): SQL {
53
- return sql`exists (
54
- select 1
55
- from ${dealPeople}
56
- where ${dealPeople.dealId} = ${deals.id}
57
- and ${inArray(dealPeople.personId, personIds)}
58
- )`
59
- }
60
-
61
52
  function matchesTerm(term: string): SQL | undefined {
62
53
  const pattern = containsPattern(term)
63
54
 
@@ -76,7 +67,9 @@ function conditionsFor(workspaceId: string, filters: DealFilters): (SQL | undefi
76
67
  filters.term === undefined ? undefined : matchesTerm(filters.term),
77
68
  filters.companyIds === undefined ? undefined : inArray(deals.companyId, filters.companyIds),
78
69
  filters.stageIds === undefined ? undefined : inArray(deals.stageId, filters.stageIds),
79
- filters.personIds === undefined ? undefined : hasAnyOfPeople(filters.personIds),
70
+ filters.personIds === undefined
71
+ ? undefined
72
+ : anyPersonLinked('deal', deals.id, deals.workspaceId, filters.personIds),
80
73
  ]
81
74
  }
82
75
 
@@ -143,99 +136,6 @@ export async function deleteDeal(db: Queryable, workspaceId: string, id: string)
143
136
  return deleted.length
144
137
  }
145
138
 
146
- /** The people on one deal. Ordered by id so a response is stable across reads. */
147
- export async function listPersonIds(db: Queryable, dealId: string): Promise<string[]> {
148
- const rows = await db
149
- .select({ personId: dealPeople.personId })
150
- .from(dealPeople)
151
- .where(eq(dealPeople.dealId, dealId))
152
- .orderBy(asc(dealPeople.personId))
153
-
154
- return rows.map((row) => row.personId)
155
- }
156
-
157
- /**
158
- * The people on each of a page of deals, in one query rather than one per row.
159
- *
160
- * @returns Ids missing from the map have no people.
161
- */
162
- export async function listPersonIdsFor(
163
- db: Queryable,
164
- dealIds: readonly string[],
165
- ): Promise<ReadonlyMap<string, readonly string[]>> {
166
- if (dealIds.length === 0) {
167
- return new Map()
168
- }
169
-
170
- const rows = await db
171
- .select({ dealId: dealPeople.dealId, personId: dealPeople.personId })
172
- .from(dealPeople)
173
- .where(inArray(dealPeople.dealId, dealIds))
174
- .orderBy(asc(dealPeople.personId))
175
-
176
- const byDeal = new Map<string, string[]>()
177
-
178
- for (const row of rows) {
179
- const existing = byDeal.get(row.dealId)
180
-
181
- if (existing === undefined) {
182
- byDeal.set(row.dealId, [row.personId])
183
- } else {
184
- existing.push(row.personId)
185
- }
186
- }
187
-
188
- return byDeal
189
- }
190
-
191
- export async function insertDealPeople(
192
- db: Queryable,
193
- dealId: string,
194
- personIds: readonly string[],
195
- ): Promise<void> {
196
- if (personIds.length === 0) {
197
- return
198
- }
199
-
200
- await db.insert(dealPeople).values(personIds.map((personId) => ({ dealId, personId })))
201
- }
202
-
203
- export async function deleteDealPeople(
204
- db: Queryable,
205
- dealId: string,
206
- personIds: readonly string[],
207
- ): Promise<void> {
208
- if (personIds.length === 0) {
209
- return
210
- }
211
-
212
- await db
213
- .delete(dealPeople)
214
- .where(and(eq(dealPeople.dealId, dealId), inArray(dealPeople.personId, personIds)))
215
- }
216
-
217
- /**
218
- * The names of these people in this workspace, keyed by id. An id missing from
219
- * the map does not exist here, which is how `person_ids` is validated. Reads the
220
- * `people` *table*, per the cross-relation rule in `architecture.md`.
221
- */
222
- export async function findPeopleNamed(
223
- db: Queryable,
224
- workspaceId: string,
225
- personIds: readonly string[],
226
- ): Promise<ReadonlyMap<string, string>> {
227
- if (personIds.length === 0) {
228
- return new Map()
229
- }
230
-
231
- const rows = await db
232
- .select({ id: people.id, name: people.name })
233
- .from(people)
234
- .where(and(eq(people.workspaceId, workspaceId), inArray(people.id, personIds)))
235
-
236
- return new Map(rows.map((row) => [row.id, row.name]))
237
- }
238
-
239
139
  /** Whether a member belongs to this workspace, for validating `owner_id`. */
240
140
  export async function memberExists(
241
141
  db: Queryable,
@@ -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 { CreateDealInput, DealView, DealsService, UpdateDealInput } from './service.ts'
10
12
 
11
13
  /** Wire shapes for `/v1/deals`. Bodies are strict; an unknown field is a 422, per `api.md`. */
@@ -26,6 +28,7 @@ const dealShape = {
26
28
  summary: z.string(),
27
29
  tags: z.array(z.string().min(1)),
28
30
  external_id: z.string().min(1).nullable(),
31
+ custom_fields: customFieldsPatchShape,
29
32
  }
30
33
 
31
34
  /**
@@ -48,6 +51,7 @@ export const createBody = z.strictObject({
48
51
  summary: dealShape.summary.default(''),
49
52
  tags: dealShape.tags.default([]),
50
53
  external_id: dealShape.external_id.default(null),
54
+ custom_fields: dealShape.custom_fields.default({}),
51
55
  })
52
56
 
53
57
  export const updateBody = z.strictObject(dealShape).partial()
@@ -72,6 +76,7 @@ export function toCreateInput(body: z.infer<typeof createBody>): CreateDealInput
72
76
  summary: body.summary,
73
77
  tags: body.tags,
74
78
  externalId: body.external_id,
79
+ customFields: body.custom_fields,
75
80
  }
76
81
  }
77
82
 
@@ -91,6 +96,7 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdateDealInput
91
96
  ...(body.summary === undefined ? {} : { summary: body.summary }),
92
97
  ...(body.tags === undefined ? {} : { tags: body.tags }),
93
98
  ...(body.external_id === undefined ? {} : { externalId: body.external_id }),
99
+ ...(body.custom_fields === undefined ? {} : { customFields: body.custom_fields }),
94
100
  }
95
101
  }
96
102
 
@@ -111,6 +117,7 @@ export function dealResponse(deal: DealView): Record<string, unknown> {
111
117
  summary: deal.summary,
112
118
  tags: deal.tags,
113
119
  external_id: deal.externalId,
120
+ custom_fields: renderCustomFieldsForWire(deal.customFields),
114
121
  created_at: deal.createdAt.toISOString(),
115
122
  updated_at: deal.updatedAt.toISOString(),
116
123
  }
@@ -1,9 +1,9 @@
1
- import { bigint, date, index, pgTable, primaryKey, text } from 'drizzle-orm/pg-core'
1
+ import type { CustomFieldValue } from '@kelpie/schemas'
2
+ import { bigint, 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'
5
6
  import { companies } from '../companies/schema.ts'
6
- import { people } from '../people/schema.ts'
7
7
  import { pipelineStages } from '../pipelines/schema.ts'
8
8
  import { workspaceMembers, workspaces } from '../workspace/schema.ts'
9
9
 
@@ -38,6 +38,11 @@ export const deals = pgTable(
38
38
  summary: text('summary').notNull().default(''),
39
39
  tags: text('tags').array().notNull().default([]),
40
40
  externalId: text('external_id'),
41
+ // Workspace-defined fields, keyed by definition key. See people/schema.ts.
42
+ customFields: jsonb('custom_fields')
43
+ .$type<Readonly<Record<string, CustomFieldValue>>>()
44
+ .notNull()
45
+ .default({}),
41
46
  createdAt: createdAt(),
42
47
  updatedAt: updatedAt(),
43
48
  searchVector: searchVector((): readonly SearchVectorPart[] => [
@@ -57,16 +62,3 @@ export const deals = pgTable(
57
62
  ],
58
63
  )
59
64
 
60
- /** People attached to a deal. Restrict on person: a deal contact cannot vanish. */
61
- export const dealPeople = pgTable(
62
- 'deal_people',
63
- {
64
- dealId: text('deal_id')
65
- .notNull()
66
- .references(() => deals.id, { onDelete: 'cascade' }),
67
- personId: text('person_id')
68
- .notNull()
69
- .references(() => people.id, { onDelete: 'restrict' }),
70
- },
71
- (table) => [primaryKey({ columns: [table.dealId, table.personId] })],
72
- )