@kelpie/server 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (584) hide show
  1. package/dist/lib/ids.d.ts +11 -0
  2. package/dist/lib/ids.d.ts.map +1 -1
  3. package/dist/lib/ids.js +11 -0
  4. package/dist/lib/ids.js.map +1 -1
  5. package/dist/modules/activities/repository.d.ts.map +1 -1
  6. package/dist/modules/activities/repository.js +19 -20
  7. package/dist/modules/activities/repository.js.map +1 -1
  8. package/dist/modules/activities/wording.d.ts +12 -0
  9. package/dist/modules/activities/wording.d.ts.map +1 -1
  10. package/dist/modules/activities/wording.js +16 -0
  11. package/dist/modules/activities/wording.js.map +1 -1
  12. package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
  13. package/dist/modules/agent-tasks/catalog.js +62 -0
  14. package/dist/modules/agent-tasks/catalog.js.map +1 -1
  15. package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
  16. package/dist/modules/agent-tasks/resolve.js +42 -9
  17. package/dist/modules/agent-tasks/resolve.js.map +1 -1
  18. package/dist/modules/agent-tasks/routes.d.ts +2 -0
  19. package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
  20. package/dist/modules/attachedRecords.d.ts +6 -1
  21. package/dist/modules/attachedRecords.d.ts.map +1 -1
  22. package/dist/modules/attachedRecords.js +15 -1
  23. package/dist/modules/attachedRecords.js.map +1 -1
  24. package/dist/modules/companies/index.d.ts.map +1 -1
  25. package/dist/modules/companies/index.js +3 -1
  26. package/dist/modules/companies/index.js.map +1 -1
  27. package/dist/modules/companies/routes.d.ts +14 -0
  28. package/dist/modules/companies/routes.d.ts.map +1 -1
  29. package/dist/modules/companies/routes.js +7 -0
  30. package/dist/modules/companies/routes.js.map +1 -1
  31. package/dist/modules/companies/schema.d.ts +20 -0
  32. package/dist/modules/companies/schema.d.ts.map +1 -1
  33. package/dist/modules/companies/schema.js +6 -1
  34. package/dist/modules/companies/schema.js.map +1 -1
  35. package/dist/modules/companies/service.d.ts +5 -0
  36. package/dist/modules/companies/service.d.ts.map +1 -1
  37. package/dist/modules/companies/service.js +24 -12
  38. package/dist/modules/companies/service.js.map +1 -1
  39. package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
  40. package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
  41. package/dist/modules/consent-purposes/capabilities.js +10 -0
  42. package/dist/modules/consent-purposes/capabilities.js.map +1 -0
  43. package/dist/modules/consent-purposes/events.d.ts +38 -0
  44. package/dist/modules/consent-purposes/events.d.ts.map +1 -0
  45. package/dist/modules/consent-purposes/events.js +17 -0
  46. package/dist/modules/consent-purposes/events.js.map +1 -0
  47. package/dist/modules/consent-purposes/index.d.ts +13 -0
  48. package/dist/modules/consent-purposes/index.d.ts.map +1 -0
  49. package/dist/modules/consent-purposes/index.js +41 -0
  50. package/dist/modules/consent-purposes/index.js.map +1 -0
  51. package/dist/modules/consent-purposes/repository.d.ts +21 -0
  52. package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
  53. package/dist/modules/consent-purposes/repository.js +98 -0
  54. package/dist/modules/consent-purposes/repository.js.map +1 -0
  55. package/dist/modules/consent-purposes/routes.d.ts +39 -0
  56. package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
  57. package/dist/modules/consent-purposes/routes.js +79 -0
  58. package/dist/modules/consent-purposes/routes.js.map +1 -0
  59. package/dist/modules/consent-purposes/schema.d.ts +175 -0
  60. package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
  61. package/dist/modules/consent-purposes/schema.js +35 -0
  62. package/dist/modules/consent-purposes/schema.js.map +1 -0
  63. package/dist/modules/consent-purposes/service.d.ts +50 -0
  64. package/dist/modules/consent-purposes/service.d.ts.map +1 -0
  65. package/dist/modules/consent-purposes/service.js +263 -0
  66. package/dist/modules/consent-purposes/service.js.map +1 -0
  67. package/dist/modules/consent-purposes/starters.d.ts +17 -0
  68. package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
  69. package/dist/modules/consent-purposes/starters.js +15 -0
  70. package/dist/modules/consent-purposes/starters.js.map +1 -0
  71. package/dist/modules/consent-purposes/tools.d.ts +4 -0
  72. package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
  73. package/dist/modules/consent-purposes/tools.js +29 -0
  74. package/dist/modules/consent-purposes/tools.js.map +1 -0
  75. package/dist/modules/core.d.ts.map +1 -1
  76. package/dist/modules/core.js +10 -0
  77. package/dist/modules/core.js.map +1 -1
  78. package/dist/modules/custom-fields/capabilities.d.ts +12 -0
  79. package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
  80. package/dist/modules/custom-fields/capabilities.js +15 -0
  81. package/dist/modules/custom-fields/capabilities.js.map +1 -0
  82. package/dist/modules/custom-fields/events.d.ts +49 -0
  83. package/dist/modules/custom-fields/events.d.ts.map +1 -0
  84. package/dist/modules/custom-fields/events.js +25 -0
  85. package/dist/modules/custom-fields/events.js.map +1 -0
  86. package/dist/modules/custom-fields/index.d.ts +19 -0
  87. package/dist/modules/custom-fields/index.d.ts.map +1 -0
  88. package/dist/modules/custom-fields/index.js +46 -0
  89. package/dist/modules/custom-fields/index.js.map +1 -0
  90. package/dist/modules/custom-fields/repository.d.ts +37 -0
  91. package/dist/modules/custom-fields/repository.d.ts.map +1 -0
  92. package/dist/modules/custom-fields/repository.js +144 -0
  93. package/dist/modules/custom-fields/repository.js.map +1 -0
  94. package/dist/modules/custom-fields/routes.d.ts +44 -0
  95. package/dist/modules/custom-fields/routes.d.ts.map +1 -0
  96. package/dist/modules/custom-fields/routes.js +103 -0
  97. package/dist/modules/custom-fields/routes.js.map +1 -0
  98. package/dist/modules/custom-fields/schema.d.ts +215 -0
  99. package/dist/modules/custom-fields/schema.d.ts.map +1 -0
  100. package/dist/modules/custom-fields/schema.js +43 -0
  101. package/dist/modules/custom-fields/schema.js.map +1 -0
  102. package/dist/modules/custom-fields/service.d.ts +57 -0
  103. package/dist/modules/custom-fields/service.d.ts.map +1 -0
  104. package/dist/modules/custom-fields/service.js +273 -0
  105. package/dist/modules/custom-fields/service.js.map +1 -0
  106. package/dist/modules/custom-fields/tools.d.ts +4 -0
  107. package/dist/modules/custom-fields/tools.d.ts.map +1 -0
  108. package/dist/modules/custom-fields/tools.js +38 -0
  109. package/dist/modules/custom-fields/tools.js.map +1 -0
  110. package/dist/modules/custom-fields/values.d.ts +49 -0
  111. package/dist/modules/custom-fields/values.d.ts.map +1 -0
  112. package/dist/modules/custom-fields/values.js +249 -0
  113. package/dist/modules/custom-fields/values.js.map +1 -0
  114. package/dist/modules/custom-fields/wire.d.ts +12 -0
  115. package/dist/modules/custom-fields/wire.d.ts.map +1 -0
  116. package/dist/modules/custom-fields/wire.js +30 -0
  117. package/dist/modules/custom-fields/wire.js.map +1 -0
  118. package/dist/modules/dashboard/repository.d.ts.map +1 -1
  119. package/dist/modules/dashboard/repository.js +4 -3
  120. package/dist/modules/dashboard/repository.js.map +1 -1
  121. package/dist/modules/deals/index.d.ts +2 -1
  122. package/dist/modules/deals/index.d.ts.map +1 -1
  123. package/dist/modules/deals/index.js +5 -2
  124. package/dist/modules/deals/index.js.map +1 -1
  125. package/dist/modules/deals/repository.d.ts +0 -16
  126. package/dist/modules/deals/repository.d.ts.map +1 -1
  127. package/dist/modules/deals/repository.js +6 -76
  128. package/dist/modules/deals/repository.js.map +1 -1
  129. package/dist/modules/deals/routes.d.ts +14 -0
  130. package/dist/modules/deals/routes.d.ts.map +1 -1
  131. package/dist/modules/deals/routes.js +7 -0
  132. package/dist/modules/deals/routes.js.map +1 -1
  133. package/dist/modules/deals/schema.d.ts +20 -42
  134. package/dist/modules/deals/schema.d.ts.map +1 -1
  135. package/dist/modules/deals/schema.js +6 -11
  136. package/dist/modules/deals/schema.js.map +1 -1
  137. package/dist/modules/deals/service.d.ts +13 -2
  138. package/dist/modules/deals/service.d.ts.map +1 -1
  139. package/dist/modules/deals/service.js +43 -20
  140. package/dist/modules/deals/service.js.map +1 -1
  141. package/dist/modules/decisions/repository.d.ts.map +1 -1
  142. package/dist/modules/decisions/repository.js +2 -0
  143. package/dist/modules/decisions/repository.js.map +1 -1
  144. package/dist/modules/decisions/routes.d.ts +1 -0
  145. package/dist/modules/decisions/routes.d.ts.map +1 -1
  146. package/dist/modules/enquiries/events.d.ts +44 -0
  147. package/dist/modules/enquiries/events.d.ts.map +1 -0
  148. package/dist/modules/enquiries/events.js +19 -0
  149. package/dist/modules/enquiries/events.js.map +1 -0
  150. package/dist/modules/enquiries/index.d.ts +13 -0
  151. package/dist/modules/enquiries/index.d.ts.map +1 -0
  152. package/dist/modules/enquiries/index.js +44 -0
  153. package/dist/modules/enquiries/index.js.map +1 -0
  154. package/dist/modules/enquiries/repository.d.ts +30 -0
  155. package/dist/modules/enquiries/repository.d.ts.map +1 -0
  156. package/dist/modules/enquiries/repository.js +94 -0
  157. package/dist/modules/enquiries/repository.js.map +1 -0
  158. package/dist/modules/enquiries/routes.d.ts +52 -0
  159. package/dist/modules/enquiries/routes.d.ts.map +1 -0
  160. package/dist/modules/enquiries/routes.js +127 -0
  161. package/dist/modules/enquiries/routes.js.map +1 -0
  162. package/dist/modules/enquiries/schema.d.ts +290 -0
  163. package/dist/modules/enquiries/schema.d.ts.map +1 -0
  164. package/dist/modules/enquiries/schema.js +52 -0
  165. package/dist/modules/enquiries/schema.js.map +1 -0
  166. package/dist/modules/enquiries/service.d.ts +85 -0
  167. package/dist/modules/enquiries/service.d.ts.map +1 -0
  168. package/dist/modules/enquiries/service.js +370 -0
  169. package/dist/modules/enquiries/service.js.map +1 -0
  170. package/dist/modules/enquiries/tools.d.ts +4 -0
  171. package/dist/modules/enquiries/tools.d.ts.map +1 -0
  172. package/dist/modules/enquiries/tools.js +50 -0
  173. package/dist/modules/enquiries/tools.js.map +1 -0
  174. package/dist/modules/eventCatalogs.d.ts +3 -0
  175. package/dist/modules/eventCatalogs.d.ts.map +1 -1
  176. package/dist/modules/eventCatalogs.js +3 -0
  177. package/dist/modules/eventCatalogs.js.map +1 -1
  178. package/dist/modules/forms/embed.d.ts +20 -6
  179. package/dist/modules/forms/embed.d.ts.map +1 -1
  180. package/dist/modules/forms/embed.js +359 -43
  181. package/dist/modules/forms/embed.js.map +1 -1
  182. package/dist/modules/forms/events.d.ts +20 -7
  183. package/dist/modules/forms/events.d.ts.map +1 -1
  184. package/dist/modules/forms/events.js +20 -2
  185. package/dist/modules/forms/events.js.map +1 -1
  186. package/dist/modules/forms/fields.d.ts +14 -1
  187. package/dist/modules/forms/fields.d.ts.map +1 -1
  188. package/dist/modules/forms/fields.js +87 -3
  189. package/dist/modules/forms/fields.js.map +1 -1
  190. package/dist/modules/forms/index.d.ts.map +1 -1
  191. package/dist/modules/forms/index.js +12 -1
  192. package/dist/modules/forms/index.js.map +1 -1
  193. package/dist/modules/forms/mapping.d.ts +62 -5
  194. package/dist/modules/forms/mapping.d.ts.map +1 -1
  195. package/dist/modules/forms/mapping.js +139 -5
  196. package/dist/modules/forms/mapping.js.map +1 -1
  197. package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
  198. package/dist/modules/forms/publicRoutes.js +29 -1
  199. package/dist/modules/forms/publicRoutes.js.map +1 -1
  200. package/dist/modules/forms/repository.d.ts +31 -0
  201. package/dist/modules/forms/repository.d.ts.map +1 -1
  202. package/dist/modules/forms/repository.js +90 -1
  203. package/dist/modules/forms/repository.js.map +1 -1
  204. package/dist/modules/forms/routes.d.ts +83 -1
  205. package/dist/modules/forms/routes.d.ts.map +1 -1
  206. package/dist/modules/forms/routes.js +185 -2
  207. package/dist/modules/forms/routes.js.map +1 -1
  208. package/dist/modules/forms/schema.d.ts +672 -1
  209. package/dist/modules/forms/schema.d.ts.map +1 -1
  210. package/dist/modules/forms/schema.js +146 -3
  211. package/dist/modules/forms/schema.js.map +1 -1
  212. package/dist/modules/forms/service.d.ts +54 -1
  213. package/dist/modules/forms/service.d.ts.map +1 -1
  214. package/dist/modules/forms/service.js +338 -28
  215. package/dist/modules/forms/service.js.map +1 -1
  216. package/dist/modules/forms/submission.d.ts +15 -0
  217. package/dist/modules/forms/submission.d.ts.map +1 -1
  218. package/dist/modules/forms/submission.js +418 -40
  219. package/dist/modules/forms/submission.js.map +1 -1
  220. package/dist/modules/import-export/drafts.d.ts +10 -0
  221. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  222. package/dist/modules/import-export/drafts.js +16 -2
  223. package/dist/modules/import-export/drafts.js.map +1 -1
  224. package/dist/modules/import-export/exportRows.d.ts +7 -4
  225. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  226. package/dist/modules/import-export/exportRows.js +20 -5
  227. package/dist/modules/import-export/exportRows.js.map +1 -1
  228. package/dist/modules/import-export/plan.d.ts +12 -1
  229. package/dist/modules/import-export/plan.d.ts.map +1 -1
  230. package/dist/modules/import-export/plan.js +29 -2
  231. package/dist/modules/import-export/plan.js.map +1 -1
  232. package/dist/modules/import-export/presets.d.ts.map +1 -1
  233. package/dist/modules/import-export/presets.js +10 -0
  234. package/dist/modules/import-export/presets.js.map +1 -1
  235. package/dist/modules/import-export/repository.d.ts +11 -1
  236. package/dist/modules/import-export/repository.d.ts.map +1 -1
  237. package/dist/modules/import-export/repository.js +42 -9
  238. package/dist/modules/import-export/repository.js.map +1 -1
  239. package/dist/modules/import-export/routes.d.ts.map +1 -1
  240. package/dist/modules/import-export/routes.js +4 -0
  241. package/dist/modules/import-export/routes.js.map +1 -1
  242. package/dist/modules/import-export/schema.d.ts +17 -0
  243. package/dist/modules/import-export/schema.d.ts.map +1 -1
  244. package/dist/modules/import-export/schema.js +11 -0
  245. package/dist/modules/import-export/schema.js.map +1 -1
  246. package/dist/modules/import-export/service.d.ts +6 -0
  247. package/dist/modules/import-export/service.d.ts.map +1 -1
  248. package/dist/modules/import-export/service.js +14 -2
  249. package/dist/modules/import-export/service.js.map +1 -1
  250. package/dist/modules/import-export/streams.d.ts.map +1 -1
  251. package/dist/modules/import-export/streams.js +3 -3
  252. package/dist/modules/import-export/streams.js.map +1 -1
  253. package/dist/modules/import-export/tools.d.ts.map +1 -1
  254. package/dist/modules/import-export/tools.js +8 -0
  255. package/dist/modules/import-export/tools.js.map +1 -1
  256. package/dist/modules/import-export/validation.d.ts.map +1 -1
  257. package/dist/modules/import-export/validation.js +22 -1
  258. package/dist/modules/import-export/validation.js.map +1 -1
  259. package/dist/modules/import-export/writes.d.ts.map +1 -1
  260. package/dist/modules/import-export/writes.js +37 -4
  261. package/dist/modules/import-export/writes.js.map +1 -1
  262. package/dist/modules/lists/repository.d.ts +11 -0
  263. package/dist/modules/lists/repository.d.ts.map +1 -1
  264. package/dist/modules/lists/repository.js +13 -0
  265. package/dist/modules/lists/repository.js.map +1 -1
  266. package/dist/modules/lists/routes.d.ts +4 -0
  267. package/dist/modules/lists/routes.d.ts.map +1 -1
  268. package/dist/modules/lists/routes.js +8 -0
  269. package/dist/modules/lists/routes.js.map +1 -1
  270. package/dist/modules/lists/schema.d.ts +17 -0
  271. package/dist/modules/lists/schema.d.ts.map +1 -1
  272. package/dist/modules/lists/schema.js +10 -0
  273. package/dist/modules/lists/schema.js.map +1 -1
  274. package/dist/modules/lists/service.d.ts +14 -2
  275. package/dist/modules/lists/service.d.ts.map +1 -1
  276. package/dist/modules/lists/service.js +55 -7
  277. package/dist/modules/lists/service.js.map +1 -1
  278. package/dist/modules/mcp/index.d.ts.map +1 -1
  279. package/dist/modules/mcp/index.js +5 -0
  280. package/dist/modules/mcp/index.js.map +1 -1
  281. package/dist/modules/notes/routes.d.ts +1 -0
  282. package/dist/modules/notes/routes.d.ts.map +1 -1
  283. package/dist/modules/opportunities/index.d.ts.map +1 -1
  284. package/dist/modules/opportunities/index.js +3 -1
  285. package/dist/modules/opportunities/index.js.map +1 -1
  286. package/dist/modules/opportunities/repository.d.ts +2 -0
  287. package/dist/modules/opportunities/repository.d.ts.map +1 -1
  288. package/dist/modules/opportunities/repository.js +4 -0
  289. package/dist/modules/opportunities/repository.js.map +1 -1
  290. package/dist/modules/opportunities/routes.d.ts +16 -0
  291. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  292. package/dist/modules/opportunities/routes.js +13 -0
  293. package/dist/modules/opportunities/routes.js.map +1 -1
  294. package/dist/modules/opportunities/schema.d.ts +20 -0
  295. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  296. package/dist/modules/opportunities/schema.js +6 -1
  297. package/dist/modules/opportunities/schema.js.map +1 -1
  298. package/dist/modules/opportunities/service.d.ts +20 -3
  299. package/dist/modules/opportunities/service.d.ts.map +1 -1
  300. package/dist/modules/opportunities/service.js +99 -18
  301. package/dist/modules/opportunities/service.js.map +1 -1
  302. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  303. package/dist/modules/opportunities/tools.js +2 -0
  304. package/dist/modules/opportunities/tools.js.map +1 -1
  305. package/dist/modules/partnerships/index.d.ts.map +1 -1
  306. package/dist/modules/partnerships/index.js +3 -1
  307. package/dist/modules/partnerships/index.js.map +1 -1
  308. package/dist/modules/partnerships/repository.d.ts +0 -17
  309. package/dist/modules/partnerships/repository.d.ts.map +1 -1
  310. package/dist/modules/partnerships/repository.js +6 -82
  311. package/dist/modules/partnerships/repository.js.map +1 -1
  312. package/dist/modules/partnerships/routes.d.ts +14 -0
  313. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  314. package/dist/modules/partnerships/routes.js +7 -0
  315. package/dist/modules/partnerships/routes.js.map +1 -1
  316. package/dist/modules/partnerships/schema.d.ts +20 -41
  317. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  318. package/dist/modules/partnerships/schema.js +6 -10
  319. package/dist/modules/partnerships/schema.js.map +1 -1
  320. package/dist/modules/partnerships/service.d.ts +11 -1
  321. package/dist/modules/partnerships/service.d.ts.map +1 -1
  322. package/dist/modules/partnerships/service.js +43 -20
  323. package/dist/modules/partnerships/service.js.map +1 -1
  324. package/dist/modules/people/consentHydration.d.ts +26 -0
  325. package/dist/modules/people/consentHydration.d.ts.map +1 -0
  326. package/dist/modules/people/consentHydration.js +100 -0
  327. package/dist/modules/people/consentHydration.js.map +1 -0
  328. package/dist/modules/people/index.d.ts.map +1 -1
  329. package/dist/modules/people/index.js +3 -1
  330. package/dist/modules/people/index.js.map +1 -1
  331. package/dist/modules/people/personConsentWrites.d.ts +40 -0
  332. package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
  333. package/dist/modules/people/personConsentWrites.js +98 -0
  334. package/dist/modules/people/personConsentWrites.js.map +1 -0
  335. package/dist/modules/people/repository.d.ts.map +1 -1
  336. package/dist/modules/people/repository.js +5 -1
  337. package/dist/modules/people/repository.js.map +1 -1
  338. package/dist/modules/people/routes.d.ts +57 -4
  339. package/dist/modules/people/routes.d.ts.map +1 -1
  340. package/dist/modules/people/routes.js +104 -5
  341. package/dist/modules/people/routes.js.map +1 -1
  342. package/dist/modules/people/schema.d.ts +366 -1
  343. package/dist/modules/people/schema.d.ts.map +1 -1
  344. package/dist/modules/people/schema.js +92 -2
  345. package/dist/modules/people/schema.js.map +1 -1
  346. package/dist/modules/people/service.d.ts +30 -1
  347. package/dist/modules/people/service.d.ts.map +1 -1
  348. package/dist/modules/people/service.js +115 -38
  349. package/dist/modules/people/service.js.map +1 -1
  350. package/dist/modules/people/tools.d.ts.map +1 -1
  351. package/dist/modules/people/tools.js +4 -1
  352. package/dist/modules/people/tools.js.map +1 -1
  353. package/dist/modules/personLinks.d.ts +79 -0
  354. package/dist/modules/personLinks.d.ts.map +1 -0
  355. package/dist/modules/personLinks.js +155 -0
  356. package/dist/modules/personLinks.js.map +1 -0
  357. package/dist/modules/pipelines/routes.d.ts +1 -0
  358. package/dist/modules/pipelines/routes.d.ts.map +1 -1
  359. package/dist/modules/plans/routes.d.ts +1 -0
  360. package/dist/modules/plans/routes.d.ts.map +1 -1
  361. package/dist/modules/raises/index.d.ts.map +1 -1
  362. package/dist/modules/raises/index.js +3 -1
  363. package/dist/modules/raises/index.js.map +1 -1
  364. package/dist/modules/raises/repository.d.ts +0 -17
  365. package/dist/modules/raises/repository.d.ts.map +1 -1
  366. package/dist/modules/raises/repository.js +6 -77
  367. package/dist/modules/raises/repository.js.map +1 -1
  368. package/dist/modules/raises/routes.d.ts +14 -0
  369. package/dist/modules/raises/routes.d.ts.map +1 -1
  370. package/dist/modules/raises/routes.js +7 -0
  371. package/dist/modules/raises/routes.js.map +1 -1
  372. package/dist/modules/raises/schema.d.ts +20 -41
  373. package/dist/modules/raises/schema.d.ts.map +1 -1
  374. package/dist/modules/raises/schema.js +6 -10
  375. package/dist/modules/raises/schema.js.map +1 -1
  376. package/dist/modules/raises/service.d.ts +11 -1
  377. package/dist/modules/raises/service.d.ts.map +1 -1
  378. package/dist/modules/raises/service.js +41 -18
  379. package/dist/modules/raises/service.js.map +1 -1
  380. package/dist/modules/recordTargets.d.ts.map +1 -1
  381. package/dist/modules/recordTargets.js +2 -0
  382. package/dist/modules/recordTargets.js.map +1 -1
  383. package/dist/modules/references.d.ts +10 -0
  384. package/dist/modules/references.d.ts.map +1 -1
  385. package/dist/modules/references.js +27 -4
  386. package/dist/modules/references.js.map +1 -1
  387. package/dist/modules/sample-data/fixture.d.ts +21 -0
  388. package/dist/modules/sample-data/fixture.d.ts.map +1 -1
  389. package/dist/modules/sample-data/fixture.js +40 -0
  390. package/dist/modules/sample-data/fixture.js.map +1 -1
  391. package/dist/modules/sample-data/index.d.ts.map +1 -1
  392. package/dist/modules/sample-data/index.js +1 -0
  393. package/dist/modules/sample-data/index.js.map +1 -1
  394. package/dist/modules/sample-data/routes.d.ts.map +1 -1
  395. package/dist/modules/sample-data/routes.js +1 -0
  396. package/dist/modules/sample-data/routes.js.map +1 -1
  397. package/dist/modules/sample-data/service.d.ts +1 -0
  398. package/dist/modules/sample-data/service.d.ts.map +1 -1
  399. package/dist/modules/sample-data/service.js +77 -8
  400. package/dist/modules/sample-data/service.js.map +1 -1
  401. package/dist/modules/search/index.d.ts +1 -1
  402. package/dist/modules/search/index.d.ts.map +1 -1
  403. package/dist/modules/search/index.js +2 -1
  404. package/dist/modules/search/index.js.map +1 -1
  405. package/dist/modules/search/repository.d.ts +1 -0
  406. package/dist/modules/search/repository.d.ts.map +1 -1
  407. package/dist/modules/search/repository.js +23 -0
  408. package/dist/modules/search/repository.js.map +1 -1
  409. package/dist/modules/search/service.d.ts +3 -3
  410. package/dist/modules/search/service.d.ts.map +1 -1
  411. package/dist/modules/search/service.js +5 -4
  412. package/dist/modules/search/service.js.map +1 -1
  413. package/dist/modules/stagedRecords.d.ts +3 -3
  414. package/dist/modules/stagedRecords.d.ts.map +1 -1
  415. package/dist/modules/stagedRecords.js +9 -0
  416. package/dist/modules/stagedRecords.js.map +1 -1
  417. package/dist/modules/webhooks/payloads.d.ts.map +1 -1
  418. package/dist/modules/webhooks/payloads.js +15 -2
  419. package/dist/modules/webhooks/payloads.js.map +1 -1
  420. package/dist/modules/workspace/repository.d.ts +2 -0
  421. package/dist/modules/workspace/repository.d.ts.map +1 -1
  422. package/dist/modules/workspace/repository.js +7 -0
  423. package/dist/modules/workspace/repository.js.map +1 -1
  424. package/dist/modules/workspace/service.d.ts.map +1 -1
  425. package/dist/modules/workspace/service.js +10 -0
  426. package/dist/modules/workspace/service.js.map +1 -1
  427. package/dist/modules/workspace/starters.d.ts.map +1 -1
  428. package/dist/modules/workspace/starters.js +5 -0
  429. package/dist/modules/workspace/starters.js.map +1 -1
  430. package/dist/runtime/events.d.ts +1 -1
  431. package/dist/runtime/events.d.ts.map +1 -1
  432. package/dist/runtime/events.js +1 -0
  433. package/dist/runtime/events.js.map +1 -1
  434. package/dist/schema/index.d.ts +3 -0
  435. package/dist/schema/index.d.ts.map +1 -1
  436. package/dist/schema/index.js +3 -0
  437. package/dist/schema/index.js.map +1 -1
  438. package/dist/testing/database.d.ts +5 -1
  439. package/dist/testing/database.d.ts.map +1 -1
  440. package/dist/testing/database.js +81 -10
  441. package/dist/testing/database.js.map +1 -1
  442. package/migrations/0024_third_king_cobra.sql +46 -0
  443. package/migrations/0025_worthless_chimera.sql +3 -0
  444. package/migrations/0026_late_aqueduct.sql +46 -0
  445. package/migrations/0027_brainy_silver_sable.sql +3 -0
  446. package/migrations/0028_freezing_scrambler.sql +19 -0
  447. package/migrations/0029_custom_fields.sql +26 -0
  448. package/migrations/0030_enquiries.sql +79 -0
  449. package/migrations/0031_consent.sql +45 -0
  450. package/migrations/0032_form_field_statement.sql +1 -0
  451. package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
  452. package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
  453. package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
  454. package/migrations/0036_form_field_notice_type.sql +2 -0
  455. package/migrations/meta/0024_snapshot.json +5516 -0
  456. package/migrations/meta/0025_snapshot.json +5336 -0
  457. package/migrations/meta/0026_snapshot.json +5710 -0
  458. package/migrations/meta/0027_snapshot.json +5716 -0
  459. package/migrations/meta/0028_snapshot.json +5740 -0
  460. package/migrations/meta/0029_snapshot.json +5935 -0
  461. package/migrations/meta/0030_snapshot.json +6245 -0
  462. package/migrations/meta/0031_snapshot.json +6572 -0
  463. package/migrations/meta/0032_snapshot.json +6578 -0
  464. package/migrations/meta/0033_snapshot.json +6572 -0
  465. package/migrations/meta/0034_snapshot.json +6566 -0
  466. package/migrations/meta/0035_snapshot.json +6573 -0
  467. package/migrations/meta/0036_snapshot.json +6573 -0
  468. package/migrations/meta/_journal.json +91 -0
  469. package/package.json +2 -2
  470. package/src/lib/ids.ts +11 -0
  471. package/src/modules/activities/repository.ts +22 -23
  472. package/src/modules/activities/wording.ts +18 -0
  473. package/src/modules/agent-tasks/catalog.ts +63 -0
  474. package/src/modules/agent-tasks/resolve.ts +64 -24
  475. package/src/modules/attachedRecords.ts +29 -2
  476. package/src/modules/companies/index.ts +3 -1
  477. package/src/modules/companies/routes.ts +7 -0
  478. package/src/modules/companies/schema.ts +7 -1
  479. package/src/modules/companies/service.ts +48 -13
  480. package/src/modules/consent-purposes/capabilities.ts +12 -0
  481. package/src/modules/consent-purposes/events.ts +38 -0
  482. package/src/modules/consent-purposes/index.ts +48 -0
  483. package/src/modules/consent-purposes/repository.ts +163 -0
  484. package/src/modules/consent-purposes/routes.ts +122 -0
  485. package/src/modules/consent-purposes/schema.ts +46 -0
  486. package/src/modules/consent-purposes/service.ts +423 -0
  487. package/src/modules/consent-purposes/starters.ts +32 -0
  488. package/src/modules/consent-purposes/tools.ts +44 -0
  489. package/src/modules/core.ts +10 -0
  490. package/src/modules/custom-fields/capabilities.ts +17 -0
  491. package/src/modules/custom-fields/events.ts +51 -0
  492. package/src/modules/custom-fields/index.ts +61 -0
  493. package/src/modules/custom-fields/repository.ts +225 -0
  494. package/src/modules/custom-fields/routes.ts +155 -0
  495. package/src/modules/custom-fields/schema.ts +61 -0
  496. package/src/modules/custom-fields/service.ts +439 -0
  497. package/src/modules/custom-fields/tools.ts +53 -0
  498. package/src/modules/custom-fields/values.ts +352 -0
  499. package/src/modules/custom-fields/wire.ts +32 -0
  500. package/src/modules/dashboard/repository.ts +4 -3
  501. package/src/modules/deals/index.ts +5 -2
  502. package/src/modules/deals/repository.ts +6 -106
  503. package/src/modules/deals/routes.ts +7 -0
  504. package/src/modules/deals/schema.ts +7 -15
  505. package/src/modules/deals/service.ts +92 -23
  506. package/src/modules/decisions/repository.ts +2 -0
  507. package/src/modules/enquiries/events.ts +45 -0
  508. package/src/modules/enquiries/index.ts +50 -0
  509. package/src/modules/enquiries/repository.ts +164 -0
  510. package/src/modules/enquiries/routes.ts +172 -0
  511. package/src/modules/enquiries/schema.ts +59 -0
  512. package/src/modules/enquiries/service.ts +644 -0
  513. package/src/modules/enquiries/tools.ts +66 -0
  514. package/src/modules/eventCatalogs.ts +3 -0
  515. package/src/modules/forms/embed.ts +391 -44
  516. package/src/modules/forms/events.ts +30 -2
  517. package/src/modules/forms/fields.ts +102 -2
  518. package/src/modules/forms/index.ts +12 -1
  519. package/src/modules/forms/mapping.ts +183 -6
  520. package/src/modules/forms/publicRoutes.ts +43 -1
  521. package/src/modules/forms/repository.ts +162 -1
  522. package/src/modules/forms/routes.ts +212 -2
  523. package/src/modules/forms/schema.ts +166 -4
  524. package/src/modules/forms/service.ts +565 -41
  525. package/src/modules/forms/submission.ts +718 -44
  526. package/src/modules/import-export/drafts.ts +20 -1
  527. package/src/modules/import-export/exportRows.ts +21 -5
  528. package/src/modules/import-export/plan.ts +47 -2
  529. package/src/modules/import-export/presets.ts +10 -0
  530. package/src/modules/import-export/repository.ts +73 -8
  531. package/src/modules/import-export/routes.ts +4 -0
  532. package/src/modules/import-export/schema.ts +11 -0
  533. package/src/modules/import-export/service.ts +28 -2
  534. package/src/modules/import-export/streams.ts +3 -1
  535. package/src/modules/import-export/tools.ts +10 -0
  536. package/src/modules/import-export/validation.ts +28 -0
  537. package/src/modules/import-export/writes.ts +70 -5
  538. package/src/modules/lists/repository.ts +30 -0
  539. package/src/modules/lists/routes.ts +8 -0
  540. package/src/modules/lists/schema.ts +10 -0
  541. package/src/modules/lists/service.ts +110 -9
  542. package/src/modules/mcp/index.ts +5 -0
  543. package/src/modules/opportunities/index.ts +3 -1
  544. package/src/modules/opportunities/repository.ts +11 -0
  545. package/src/modules/opportunities/routes.ts +13 -0
  546. package/src/modules/opportunities/schema.ts +7 -1
  547. package/src/modules/opportunities/service.ts +188 -22
  548. package/src/modules/opportunities/tools.ts +2 -0
  549. package/src/modules/partnerships/index.ts +3 -1
  550. package/src/modules/partnerships/repository.ts +6 -117
  551. package/src/modules/partnerships/routes.ts +7 -0
  552. package/src/modules/partnerships/schema.ts +7 -14
  553. package/src/modules/partnerships/service.ts +93 -22
  554. package/src/modules/people/consentHydration.ts +167 -0
  555. package/src/modules/people/index.ts +3 -1
  556. package/src/modules/people/personConsentWrites.ts +177 -0
  557. package/src/modules/people/repository.ts +5 -0
  558. package/src/modules/people/routes.ts +127 -18
  559. package/src/modules/people/schema.ts +109 -3
  560. package/src/modules/people/service.ts +186 -40
  561. package/src/modules/people/tools.ts +5 -1
  562. package/src/modules/personLinks.ts +278 -0
  563. package/src/modules/raises/index.ts +3 -1
  564. package/src/modules/raises/repository.ts +6 -107
  565. package/src/modules/raises/routes.ts +7 -0
  566. package/src/modules/raises/schema.ts +7 -14
  567. package/src/modules/raises/service.ts +91 -20
  568. package/src/modules/recordTargets.ts +2 -0
  569. package/src/modules/references.ts +43 -4
  570. package/src/modules/sample-data/fixture.ts +63 -0
  571. package/src/modules/sample-data/index.ts +1 -0
  572. package/src/modules/sample-data/routes.ts +1 -0
  573. package/src/modules/sample-data/service.ts +97 -8
  574. package/src/modules/search/index.ts +2 -1
  575. package/src/modules/search/repository.ts +33 -1
  576. package/src/modules/search/service.ts +7 -5
  577. package/src/modules/stagedRecords.ts +18 -3
  578. package/src/modules/webhooks/payloads.ts +20 -2
  579. package/src/modules/workspace/repository.ts +12 -0
  580. package/src/modules/workspace/service.ts +14 -0
  581. package/src/modules/workspace/starters.ts +5 -0
  582. package/src/runtime/events.ts +1 -0
  583. package/src/schema/index.ts +3 -0
  584. package/src/testing/database.ts +97 -11
@@ -1,3 +1,10 @@
1
+ import type {
2
+ FormAttachTarget,
3
+ FormSubmissionLinkTarget,
4
+ PipelineKind,
5
+ } from '@kelpie/schemas'
6
+ import { PIPELINE_KINDS } from '@kelpie/schemas'
7
+
1
8
  import { changedKeys } from '../../lib/changes.ts'
2
9
  import type { Database } from '../../lib/database.ts'
3
10
  import { AppError } from '../../lib/errors.ts'
@@ -10,7 +17,10 @@ import { toEventActor } from '../../lib/actor.ts'
10
17
  import type { Actor } from '../auth/actor.ts'
11
18
  import { requireWorkspaceId } from '../auth/actor.ts'
12
19
  import './events.ts'
20
+ import * as consentPurposesRepository from '../consent-purposes/repository.ts'
21
+ import * as listsRepository from '../lists/repository.ts'
13
22
  import * as pipelineRepository from '../pipelines/repository.ts'
23
+ import { missingTargets } from '../recordTargets.ts'
14
24
  import { fieldsDiffer, findFieldProblems, storedOptions } from './fields.ts'
15
25
  import type { FieldDraft, FieldShape } from './fields.ts'
16
26
  import * as repository from './repository.ts'
@@ -46,9 +56,17 @@ export interface FormsDependencies {
46
56
  readonly generatePublicKey?: () => string
47
57
  }
48
58
 
49
- /** A form as the API returns one: the stored row minus tenancy, with its fields. */
59
+ /**
60
+ * A form as the API returns one: the stored row minus tenancy, with its
61
+ * fields, its list memberships, and its attach targets. `list_ids` and
62
+ * `attach_targets` are not columns of `forms` — they live in the joined
63
+ * `form_lists` / `form_attach_targets` tables — but they cross the wire
64
+ * nested under the form to keep write and read shapes symmetric.
65
+ */
50
66
  export type FormView = Omit<FormRecord, 'workspaceId'> & {
51
67
  readonly fields: readonly FormFieldView[]
68
+ readonly listIds: readonly string[]
69
+ readonly attachTargets: readonly FormAttachTarget[]
52
70
  }
53
71
 
54
72
  export type FormFieldView = Omit<FormFieldRecord, 'workspaceId' | 'formId'>
@@ -57,6 +75,7 @@ export type FormSubmissionView = Omit<FormSubmissionRecord, 'workspaceId'>
57
75
 
58
76
  export interface CreateFormInput {
59
77
  readonly name: string
78
+ readonly title: string
60
79
  readonly description: string | null
61
80
  readonly status: FormStatus
62
81
  readonly fields: readonly FieldDraft[]
@@ -64,11 +83,31 @@ export interface CreateFormInput {
64
83
  readonly createDeal: boolean
65
84
  readonly dealStageId: string | null
66
85
  readonly dealNameTemplate: string | null
86
+ readonly createOpportunity: boolean
87
+ readonly opportunityKind: string | null
88
+ readonly opportunityStageId: string | null
89
+ readonly opportunityNameTemplate: string | null
90
+ readonly opportunityOwnerId: string | null
91
+ readonly createPartnership: boolean
92
+ readonly partnershipKind: string | null
93
+ readonly partnershipStageId: string | null
94
+ readonly partnershipNameTemplate: string | null
95
+ readonly partnershipOwnerId: string | null
96
+ readonly createEnquiry: boolean
97
+ readonly enquirySource: string | null
98
+ readonly enquiryStageId: string | null
99
+ readonly enquiryNameTemplate: string | null
100
+ readonly enquiryOwnerId: string | null
101
+ readonly personTags: readonly string[]
102
+ readonly companyTags: readonly string[]
103
+ readonly listIds: readonly string[]
104
+ readonly attachTargets: readonly FormAttachTarget[]
67
105
  }
68
106
 
69
107
  /** PATCH semantics: an absent field is left alone, and null clears a nullable one. */
70
108
  export interface UpdateFormInput {
71
109
  readonly name?: string | undefined
110
+ readonly title?: string | undefined
72
111
  readonly description?: string | null | undefined
73
112
  readonly status?: FormStatus | undefined
74
113
  /** Absent leaves the field list alone. Present replaces all of it. */
@@ -77,6 +116,27 @@ export interface UpdateFormInput {
77
116
  readonly createDeal?: boolean | undefined
78
117
  readonly dealStageId?: string | null | undefined
79
118
  readonly dealNameTemplate?: string | null | undefined
119
+ readonly createOpportunity?: boolean | undefined
120
+ readonly opportunityKind?: string | null | undefined
121
+ readonly opportunityStageId?: string | null | undefined
122
+ readonly opportunityNameTemplate?: string | null | undefined
123
+ readonly opportunityOwnerId?: string | null | undefined
124
+ readonly createPartnership?: boolean | undefined
125
+ readonly partnershipKind?: string | null | undefined
126
+ readonly partnershipStageId?: string | null | undefined
127
+ readonly partnershipNameTemplate?: string | null | undefined
128
+ readonly partnershipOwnerId?: string | null | undefined
129
+ readonly createEnquiry?: boolean | undefined
130
+ readonly enquirySource?: string | null | undefined
131
+ readonly enquiryStageId?: string | null | undefined
132
+ readonly enquiryNameTemplate?: string | null | undefined
133
+ readonly enquiryOwnerId?: string | null | undefined
134
+ readonly personTags?: readonly string[] | undefined
135
+ readonly companyTags?: readonly string[] | undefined
136
+ /** Absent leaves list memberships alone. Present replaces the whole set. */
137
+ readonly listIds?: readonly string[] | undefined
138
+ /** Absent leaves attach targets alone. Present replaces the whole set. */
139
+ readonly attachTargets?: readonly FormAttachTarget[] | undefined
80
140
  }
81
141
 
82
142
  export interface FormsService {
@@ -90,6 +150,13 @@ export interface FormsService {
90
150
  formId: string,
91
151
  query: ListQueryParameters,
92
152
  ): Promise<Page<FormSubmissionView>>
153
+ listSubmissionsLinkedTo(
154
+ actor: Actor,
155
+ target: FormSubmissionLinkTarget,
156
+ targetId: string,
157
+ query: ListQueryParameters,
158
+ ): Promise<Page<FormSubmissionView>>
159
+ getSubmission(actor: Actor, formId: string, submissionId: string): Promise<FormSubmissionView>
93
160
  }
94
161
 
95
162
  function toFieldView(record: FormFieldRecord): FormFieldView {
@@ -98,10 +165,15 @@ function toFieldView(record: FormFieldRecord): FormFieldView {
98
165
  return view
99
166
  }
100
167
 
101
- function toView(record: FormRecord, fields: readonly FormFieldRecord[]): FormView {
168
+ function toView(
169
+ record: FormRecord,
170
+ fields: readonly FormFieldRecord[],
171
+ listIds: readonly string[],
172
+ attachTargets: readonly FormAttachTarget[],
173
+ ): FormView {
102
174
  const { workspaceId: _workspaceId, ...view } = record
103
175
 
104
- return { ...view, fields: fields.map(toFieldView) }
176
+ return { ...view, fields: fields.map(toFieldView), listIds, attachTargets }
105
177
  }
106
178
 
107
179
  function toSubmissionView(record: FormSubmissionRecord): FormSubmissionView {
@@ -113,13 +185,98 @@ function toSubmissionView(record: FormSubmissionRecord): FormSubmissionView {
113
185
  function toStoredColumns(input: UpdateFormInput): Partial<repository.FormColumns> {
114
186
  return {
115
187
  ...(input.name === undefined ? {} : { name: input.name }),
188
+ ...(input.title === undefined ? {} : { title: input.title }),
116
189
  ...(input.description === undefined ? {} : { description: input.description }),
117
190
  ...(input.status === undefined ? {} : { status: input.status }),
118
191
  ...(input.thankYouMessage === undefined ? {} : { thankYouMessage: input.thankYouMessage }),
119
192
  ...(input.createDeal === undefined ? {} : { createDeal: input.createDeal }),
120
193
  ...(input.dealStageId === undefined ? {} : { dealStageId: input.dealStageId }),
121
194
  ...(input.dealNameTemplate === undefined ? {} : { dealNameTemplate: input.dealNameTemplate }),
195
+ ...(input.createOpportunity === undefined
196
+ ? {}
197
+ : { createOpportunity: input.createOpportunity }),
198
+ ...(input.opportunityKind === undefined ? {} : { opportunityKind: input.opportunityKind }),
199
+ ...(input.opportunityStageId === undefined
200
+ ? {}
201
+ : { opportunityStageId: input.opportunityStageId }),
202
+ ...(input.opportunityNameTemplate === undefined
203
+ ? {}
204
+ : { opportunityNameTemplate: input.opportunityNameTemplate }),
205
+ ...(input.opportunityOwnerId === undefined
206
+ ? {}
207
+ : { opportunityOwnerId: input.opportunityOwnerId }),
208
+ ...(input.createPartnership === undefined
209
+ ? {}
210
+ : { createPartnership: input.createPartnership }),
211
+ ...(input.partnershipKind === undefined ? {} : { partnershipKind: input.partnershipKind }),
212
+ ...(input.partnershipStageId === undefined
213
+ ? {}
214
+ : { partnershipStageId: input.partnershipStageId }),
215
+ ...(input.partnershipNameTemplate === undefined
216
+ ? {}
217
+ : { partnershipNameTemplate: input.partnershipNameTemplate }),
218
+ ...(input.partnershipOwnerId === undefined
219
+ ? {}
220
+ : { partnershipOwnerId: input.partnershipOwnerId }),
221
+ ...(input.createEnquiry === undefined ? {} : { createEnquiry: input.createEnquiry }),
222
+ ...(input.enquirySource === undefined ? {} : { enquirySource: input.enquirySource }),
223
+ ...(input.enquiryStageId === undefined ? {} : { enquiryStageId: input.enquiryStageId }),
224
+ ...(input.enquiryNameTemplate === undefined
225
+ ? {}
226
+ : { enquiryNameTemplate: input.enquiryNameTemplate }),
227
+ ...(input.enquiryOwnerId === undefined ? {} : { enquiryOwnerId: input.enquiryOwnerId }),
228
+ ...(input.personTags === undefined ? {} : { personTags: [...input.personTags] }),
229
+ ...(input.companyTags === undefined ? {} : { companyTags: [...input.companyTags] }),
230
+ }
231
+ }
232
+
233
+ /** Where the resulting-state validation puts its answers. */
234
+ interface ResultingState {
235
+ readonly fields: readonly FieldShape[]
236
+ readonly createDeal: boolean
237
+ readonly createOpportunity: boolean
238
+ readonly opportunityKind: string | null
239
+ readonly createPartnership: boolean
240
+ readonly partnershipKind: string | null
241
+ readonly listIds: readonly string[]
242
+ readonly attachTargets: readonly FormAttachTarget[]
243
+ }
244
+
245
+ /** Sorts an attach-target list so a resent identical set is not a write. */
246
+ function sortAttachTargets(
247
+ targets: readonly FormAttachTarget[],
248
+ ): readonly FormAttachTarget[] {
249
+ return [...targets].sort((left, right) => {
250
+ if (left.targetType !== right.targetType) {
251
+ return left.targetType < right.targetType ? -1 : 1
252
+ }
253
+
254
+ return left.targetId < right.targetId ? -1 : left.targetId > right.targetId ? 1 : 0
255
+ })
256
+ }
257
+
258
+ function sameStringSet(current: readonly string[], next: readonly string[]): boolean {
259
+ if (current.length !== next.length) {
260
+ return false
261
+ }
262
+
263
+ const currentSet = new Set(current)
264
+
265
+ return next.every((value) => currentSet.has(value))
266
+ }
267
+
268
+ function sameAttachTargets(
269
+ current: readonly FormAttachTarget[],
270
+ next: readonly FormAttachTarget[],
271
+ ): boolean {
272
+ if (current.length !== next.length) {
273
+ return false
122
274
  }
275
+
276
+ const key = (target: FormAttachTarget): string => `${target.targetType}:${target.targetId}`
277
+ const currentSet = new Set(current.map(key))
278
+
279
+ return next.every((target) => currentSet.has(key(target)))
123
280
  }
124
281
 
125
282
  export function createFormsService(dependencies: FormsDependencies): FormsService {
@@ -138,41 +295,196 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
138
295
  }
139
296
 
140
297
  /**
141
- * A stage a form's deals may open in: in this workspace, and in the deal
142
- * pipeline.
298
+ * A stage a form's created records of `kind` may open in: in this workspace,
299
+ * and in the matching pipeline.
143
300
  *
144
301
  * The wrong-workspace case reads as missing, per `api.md`. The wrong-pipeline
145
- * case is a request naming a real stage that can never hold a deal, which is a
146
- * validation error rather than a missing record. Same rule the deals service
147
- * applies to `stage_id`.
302
+ * case is a request naming a real stage that can never hold a record of
303
+ * `kind`, which is a validation error rather than a missing record. Same rule
304
+ * the deals service applies to `stage_id`.
305
+ *
306
+ * @param field The body-field name (`deal_stage_id`, `opportunity_stage_id`,
307
+ * `partnership_stage_id`) that the 422 detail should point at.
148
308
  */
149
- async function requireDealStage(workspaceId: string, stageId: string): Promise<void> {
309
+ async function requireStageOfKind(
310
+ workspaceId: string,
311
+ kind: PipelineKind,
312
+ stageId: string,
313
+ field: string,
314
+ ): Promise<void> {
150
315
  const stage = await pipelineRepository.findStage(dependencies.db, workspaceId, stageId)
151
316
 
152
317
  if (stage === undefined) {
153
318
  throw AppError.notFound('Pipeline stage not found')
154
319
  }
155
320
 
156
- if (stage.kind !== 'deal') {
157
- throw AppError.validationFailed('That stage is not part of the deal pipeline', [
158
- { field: 'deal_stage_id', message: `It belongs to the ${stage.kind} pipeline` },
321
+ if (stage.kind !== kind) {
322
+ throw AppError.validationFailed(`That stage is not part of the ${kind} pipeline`, [
323
+ { field, message: `It belongs to the ${stage.kind} pipeline` },
159
324
  ])
160
325
  }
161
326
  }
162
327
 
163
328
  /**
164
- * @param createsDeal Part of the check, not context: whether a form needs a
165
- * company mapping depends on it, so the two are validated together.
166
329
  * @throws AppError 422 listing every problem with the field list at once.
167
330
  */
168
- function requireUsableFields(fields: readonly FieldShape[], createsDeal: boolean): void {
169
- const problems = findFieldProblems(fields, createsDeal)
331
+ function requireUsableFields(
332
+ fields: readonly FieldShape[],
333
+ createsDeal: boolean,
334
+ createsPartnership: boolean,
335
+ ): void {
336
+ const problems = findFieldProblems(fields, createsDeal, createsPartnership)
170
337
 
171
338
  if (problems.length > 0) {
172
339
  throw AppError.validationFailed('That field list cannot process a submission', problems)
173
340
  }
174
341
  }
175
342
 
343
+ /**
344
+ * The lists an action-configured form names must exist in this workspace and
345
+ * target `person` or `company`. A list of another target type would never
346
+ * receive a submitter or a company — a form only knows how to feed those two
347
+ * — so accepting it would misdirect the visitor's inbound landing.
348
+ */
349
+ async function requireActionLists(
350
+ workspaceId: string,
351
+ listIds: readonly string[],
352
+ ): Promise<void> {
353
+ if (listIds.length === 0) {
354
+ return
355
+ }
356
+
357
+ const rows = await listsRepository.listListsById(dependencies.db, workspaceId, listIds)
358
+ const found = new Map(rows.map((row) => [row.id, row.targetType]))
359
+ const problems = listIds
360
+ .map((listId, index) => {
361
+ const targetType = found.get(listId)
362
+
363
+ if (targetType === undefined) {
364
+ return { field: `list_ids.${String(index)}`, message: `No list ${listId} here` }
365
+ }
366
+
367
+ if (targetType !== 'person' && targetType !== 'company') {
368
+ return {
369
+ field: `list_ids.${String(index)}`,
370
+ message: `A list feeding a form must target person or company (got ${targetType})`,
371
+ }
372
+ }
373
+
374
+ return undefined
375
+ })
376
+ .filter((problem): problem is NonNullable<typeof problem> => problem !== undefined)
377
+
378
+ if (problems.length > 0) {
379
+ throw AppError.validationFailed(`Some list_ids cannot receive a submission`, problems)
380
+ }
381
+ }
382
+
383
+ /**
384
+ * Every attach target must exist in this workspace. Same `missingTargets`
385
+ * check notes and list members use, grouped per type so one query per
386
+ * pipeline kind resolves the whole set instead of one per row.
387
+ */
388
+ async function requireAttachTargets(
389
+ workspaceId: string,
390
+ targets: readonly FormAttachTarget[],
391
+ ): Promise<void> {
392
+ if (targets.length === 0) {
393
+ return
394
+ }
395
+
396
+ const problems: { field: string; message: string }[] = []
397
+
398
+ for (const kind of PIPELINE_KINDS) {
399
+ const ofKind = targets.filter((target) => target.targetType === kind)
400
+
401
+ if (ofKind.length === 0) {
402
+ continue
403
+ }
404
+
405
+ const missing = await missingTargets(
406
+ dependencies.db,
407
+ workspaceId,
408
+ kind,
409
+ ofKind.map((target) => target.targetId),
410
+ )
411
+
412
+ if (missing.length === 0) {
413
+ continue
414
+ }
415
+
416
+ const missingSet = new Set(missing)
417
+
418
+ targets.forEach((target, index) => {
419
+ if (target.targetType === kind && missingSet.has(target.targetId)) {
420
+ problems.push({
421
+ field: `attach_targets.${String(index)}`,
422
+ message: `No ${kind} ${target.targetId} here`,
423
+ })
424
+ }
425
+ })
426
+ }
427
+
428
+ if (problems.length > 0) {
429
+ throw new AppError('not_found', 'Attach target not found', problems)
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Every consent field's `consent_purpose_id` must exist in this workspace.
435
+ * The FK on `form_fields.consent_purpose_id` catches this at the database
436
+ * on write; running the check here first turns the failure into a 422 with
437
+ * the offending field pinpointed instead of a foreign-key 500.
438
+ */
439
+ async function requireConsentPurposes(
440
+ workspaceId: string,
441
+ fields: readonly FieldShape[],
442
+ ): Promise<void> {
443
+ const consentIds = Array.from(
444
+ new Set(fields.flatMap((field) => [...field.consentPurposeIds])),
445
+ )
446
+ if (consentIds.length === 0) return
447
+
448
+ const rows = await consentPurposesRepository.listPurposesByIds(
449
+ dependencies.db,
450
+ workspaceId,
451
+ consentIds,
452
+ )
453
+ const found = new Set(rows.map((row) => row.id))
454
+ const problems: { field: string; message: string }[] = []
455
+ fields.forEach((field, index) => {
456
+ for (const purposeId of field.consentPurposeIds) {
457
+ if (!found.has(purposeId)) {
458
+ problems.push({
459
+ field: `fields.${String(index)}.consent_purpose_ids`,
460
+ message: `No consent purpose ${purposeId} in this workspace`,
461
+ })
462
+ }
463
+ }
464
+ })
465
+ if (problems.length > 0) {
466
+ throw AppError.validationFailed(
467
+ 'One or more consent fields name a purpose that does not exist',
468
+ problems,
469
+ )
470
+ }
471
+ }
472
+
473
+ /**
474
+ * Resulting-state validation for everything except the three stage-id
475
+ * checks: those depend on whether the id actually changed, which is only
476
+ * known at the call site, so they stay inline in create() and update().
477
+ */
478
+ async function validateResultingState(
479
+ workspaceId: string,
480
+ state: ResultingState,
481
+ ): Promise<void> {
482
+ requireUsableFields(state.fields, state.createDeal, state.createPartnership)
483
+ await requireConsentPurposes(workspaceId, state.fields)
484
+ await requireActionLists(workspaceId, state.listIds)
485
+ await requireAttachTargets(workspaceId, state.attachTargets)
486
+ }
487
+
176
488
  /** Writes a field list as positions 0..n-1, which is the order it arrived in. */
177
489
  function writeFields(
178
490
  tx: Transaction,
@@ -192,11 +504,29 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
192
504
  mapTo: field.mapTo,
193
505
  options: storedOptions(field.options),
194
506
  placeholder: field.placeholder,
507
+ statement: field.statement,
508
+ consentPurposeIds: [...field.consentPurposeIds],
509
+ // Prune the override map to just the purposes the field lists, so
510
+ // deselecting one clears its custom text rather than keeping it
511
+ // stored against a purpose the field no longer offers.
512
+ consentPurposeLabels: pruneLabels(field.consentPurposeIds, field.consentPurposeLabels),
195
513
  sortOrder: index,
196
514
  })),
197
515
  )
198
516
  }
199
517
 
518
+ function pruneLabels(
519
+ ids: readonly string[],
520
+ labels: Readonly<Record<string, string>>,
521
+ ): Readonly<Record<string, string>> {
522
+ const allowed = new Set(ids)
523
+ const pruned: Record<string, string> = {}
524
+ for (const [key, value] of Object.entries(labels)) {
525
+ if (allowed.has(key) && value.length > 0) pruned[key] = value
526
+ }
527
+ return pruned
528
+ }
529
+
200
530
  /** @returns The page's views, with every form's fields fetched in one query. */
201
531
  async function toViews(records: readonly FormRecord[]): Promise<FormView[]> {
202
532
  const fields = await repository.listFieldsFor(
@@ -204,11 +534,38 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
204
534
  records.map((record) => record.id),
205
535
  )
206
536
 
207
- return records.map((record) =>
208
- toView(
209
- record,
210
- fields.filter((field) => field.formId === record.id),
211
- ),
537
+ // list_ids and attach_targets are per-form, so a list-page fetch takes them
538
+ // in one round trip per form. In practice a list page is small (25 rows by
539
+ // default, per api.md), and the sets themselves are short.
540
+ return Promise.all(
541
+ records.map(async (record) => {
542
+ const [listRows, attachTargets] = await Promise.all([
543
+ repository.listFormLists(dependencies.db, record.id),
544
+ repository.listAttachTargets(dependencies.db, record.id),
545
+ ])
546
+
547
+ return toView(
548
+ record,
549
+ fields.filter((field) => field.formId === record.id),
550
+ listRows.map((row) => row.listId),
551
+ attachTargets,
552
+ )
553
+ }),
554
+ )
555
+ }
556
+
557
+ async function hydrateOne(record: FormRecord): Promise<FormView> {
558
+ const [fields, listRows, attachTargets] = await Promise.all([
559
+ repository.listFields(dependencies.db, record.id),
560
+ repository.listFormLists(dependencies.db, record.id),
561
+ repository.listAttachTargets(dependencies.db, record.id),
562
+ ])
563
+
564
+ return toView(
565
+ record,
566
+ fields,
567
+ listRows.map((row) => row.listId),
568
+ attachTargets,
212
569
  )
213
570
  }
214
571
 
@@ -226,38 +583,87 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
226
583
  const workspaceId = requireWorkspaceId(actor)
227
584
  const form = await require(workspaceId, id)
228
585
 
229
- return toView(form, await repository.listFields(dependencies.db, id))
586
+ return hydrateOne(form)
230
587
  },
231
588
 
232
589
  async create(actor, input) {
233
590
  const workspaceId = requireWorkspaceId(actor)
234
591
 
235
- requireUsableFields(input.fields, input.createDeal)
592
+ await validateResultingState(workspaceId, {
593
+ fields: input.fields,
594
+ createDeal: input.createDeal,
595
+ createOpportunity: input.createOpportunity,
596
+ opportunityKind: input.opportunityKind,
597
+ createPartnership: input.createPartnership,
598
+ partnershipKind: input.partnershipKind,
599
+ listIds: input.listIds,
600
+ attachTargets: input.attachTargets,
601
+ })
236
602
 
237
603
  if (input.dealStageId !== null) {
238
- await requireDealStage(workspaceId, input.dealStageId)
604
+ await requireStageOfKind(workspaceId, 'deal', input.dealStageId, 'deal_stage_id')
605
+ }
606
+ if (input.opportunityStageId !== null) {
607
+ await requireStageOfKind(
608
+ workspaceId,
609
+ 'opportunity',
610
+ input.opportunityStageId,
611
+ 'opportunity_stage_id',
612
+ )
613
+ }
614
+ if (input.partnershipStageId !== null) {
615
+ await requireStageOfKind(
616
+ workspaceId,
617
+ 'partnership',
618
+ input.partnershipStageId,
619
+ 'partnership_stage_id',
620
+ )
621
+ }
622
+ if (input.enquiryStageId !== null) {
623
+ await requireStageOfKind(workspaceId, 'enquiry', input.enquiryStageId, 'enquiry_stage_id')
239
624
  }
240
625
 
241
626
  const id = dependencies.createId('form')
627
+ const sortedAttachTargets = sortAttachTargets(input.attachTargets)
242
628
 
243
629
  return dependencies.transaction(async ({ tx, events }) => {
244
630
  const created = await repository.insertForm(tx, {
245
631
  id,
246
632
  workspaceId,
247
633
  name: input.name,
634
+ title: input.title,
248
635
  description: input.description,
249
636
  status: input.status,
250
637
  thankYouMessage: input.thankYouMessage,
251
638
  createDeal: input.createDeal,
252
639
  dealStageId: input.dealStageId,
253
640
  dealNameTemplate: input.dealNameTemplate,
641
+ createOpportunity: input.createOpportunity,
642
+ opportunityKind: input.opportunityKind,
643
+ opportunityStageId: input.opportunityStageId,
644
+ opportunityNameTemplate: input.opportunityNameTemplate,
645
+ opportunityOwnerId: input.opportunityOwnerId,
646
+ createPartnership: input.createPartnership,
647
+ partnershipKind: input.partnershipKind,
648
+ partnershipStageId: input.partnershipStageId,
649
+ partnershipNameTemplate: input.partnershipNameTemplate,
650
+ partnershipOwnerId: input.partnershipOwnerId,
651
+ createEnquiry: input.createEnquiry,
652
+ enquirySource: input.enquirySource,
653
+ enquiryStageId: input.enquiryStageId,
654
+ enquiryNameTemplate: input.enquiryNameTemplate,
655
+ enquiryOwnerId: input.enquiryOwnerId,
656
+ personTags: [...input.personTags],
657
+ companyTags: [...input.companyTags],
254
658
  publicKey: generatePublicKey(),
255
659
  })
256
660
  const fields = await writeFields(tx, workspaceId, id, input.fields)
661
+ await repository.replaceFormLists(tx, workspaceId, id, input.listIds)
662
+ await repository.replaceAttachTargets(tx, workspaceId, id, sortedAttachTargets)
257
663
 
258
664
  events.emit('forms.form.created', { type: 'form', id }, {})
259
665
 
260
- return toView(created, fields)
666
+ return toView(created, fields, [...input.listIds], sortedAttachTargets)
261
667
  }, { workspaceId, actor: toEventActor(actor) })
262
668
  },
263
669
 
@@ -265,17 +671,68 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
265
671
  const workspaceId = requireWorkspaceId(actor)
266
672
  const existing = await require(workspaceId, id)
267
673
  const stored = await repository.listFields(dependencies.db, id)
674
+ const storedListRows = await repository.listFormLists(dependencies.db, id)
675
+ const storedListIds = storedListRows.map((row) => row.listId)
676
+ const storedAttachTargets = await repository.listAttachTargets(dependencies.db, id)
677
+
678
+ const nextListIds = changes.listIds ?? storedListIds
679
+ const nextAttachTargets = sortAttachTargets(changes.attachTargets ?? storedAttachTargets)
268
680
 
269
681
  // Validated against the state the request would leave behind, not against
270
682
  // what it carried. Turning `create_deal` on is what makes a form with no
271
683
  // company mapping unusable, and that request names no fields at all.
272
- requireUsableFields(
273
- changes.fields ?? stored,
274
- changes.createDeal ?? existing.createDeal,
275
- )
684
+ await validateResultingState(workspaceId, {
685
+ fields: changes.fields ?? stored,
686
+ createDeal: changes.createDeal ?? existing.createDeal,
687
+ createOpportunity: changes.createOpportunity ?? existing.createOpportunity,
688
+ opportunityKind:
689
+ changes.opportunityKind === undefined
690
+ ? existing.opportunityKind
691
+ : changes.opportunityKind,
692
+ createPartnership: changes.createPartnership ?? existing.createPartnership,
693
+ partnershipKind:
694
+ changes.partnershipKind === undefined
695
+ ? existing.partnershipKind
696
+ : changes.partnershipKind,
697
+ listIds: nextListIds,
698
+ attachTargets: nextAttachTargets,
699
+ })
276
700
 
277
701
  if (typeof changes.dealStageId === 'string' && changes.dealStageId !== existing.dealStageId) {
278
- await requireDealStage(workspaceId, changes.dealStageId)
702
+ await requireStageOfKind(workspaceId, 'deal', changes.dealStageId, 'deal_stage_id')
703
+ }
704
+ if (
705
+ typeof changes.opportunityStageId === 'string' &&
706
+ changes.opportunityStageId !== existing.opportunityStageId
707
+ ) {
708
+ await requireStageOfKind(
709
+ workspaceId,
710
+ 'opportunity',
711
+ changes.opportunityStageId,
712
+ 'opportunity_stage_id',
713
+ )
714
+ }
715
+ if (
716
+ typeof changes.partnershipStageId === 'string' &&
717
+ changes.partnershipStageId !== existing.partnershipStageId
718
+ ) {
719
+ await requireStageOfKind(
720
+ workspaceId,
721
+ 'partnership',
722
+ changes.partnershipStageId,
723
+ 'partnership_stage_id',
724
+ )
725
+ }
726
+ if (
727
+ typeof changes.enquiryStageId === 'string' &&
728
+ changes.enquiryStageId !== existing.enquiryStageId
729
+ ) {
730
+ await requireStageOfKind(
731
+ workspaceId,
732
+ 'enquiry',
733
+ changes.enquiryStageId,
734
+ 'enquiry_stage_id',
735
+ )
279
736
  }
280
737
 
281
738
  const columns = toStoredColumns(changes)
@@ -285,14 +742,25 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
285
742
  // it would move every field id and publish a `record.updated` no consumer
286
743
  // can act on, which is the same reason `changedKeys` guards the columns.
287
744
  const rewritesFields = changes.fields !== undefined && fieldsDiffer(stored, changes.fields)
288
-
289
- if (written.length === 0 && !rewritesFields) {
290
- return toView(existing, stored)
745
+ const rewritesLists =
746
+ changes.listIds !== undefined && !sameStringSet(storedListIds, changes.listIds)
747
+ const rewritesAttachTargets =
748
+ changes.attachTargets !== undefined &&
749
+ !sameAttachTargets(storedAttachTargets, changes.attachTargets)
750
+
751
+ if (
752
+ written.length === 0 &&
753
+ !rewritesFields &&
754
+ !rewritesLists &&
755
+ !rewritesAttachTargets
756
+ ) {
757
+ return toView(existing, stored, storedListIds, storedAttachTargets)
291
758
  }
292
759
 
293
760
  return dependencies.transaction(async ({ tx, events }) => {
294
- // A changed field list is a change to the form, so it stamps
295
- // `updated_at` even when no column of the form itself moved.
761
+ // A changed field list, list set, or attach-target set is a change to
762
+ // the form, so it stamps `updated_at` even when no column of the form
763
+ // itself moved.
296
764
  const updated = await repository.updateForm(tx, workspaceId, id, {
297
765
  ...columns,
298
766
  updatedAt: dependencies.now(),
@@ -312,13 +780,28 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
312
780
  return writeFields(tx, workspaceId, id, changes.fields)
313
781
  })()
314
782
 
315
- events.emit(
316
- 'forms.form.updated',
317
- { type: 'form', id },
318
- { changed: rewritesFields ? [...written, 'fields'] : written },
319
- )
783
+ if (rewritesLists) {
784
+ await repository.replaceFormLists(tx, workspaceId, id, nextListIds)
785
+ }
786
+ if (rewritesAttachTargets) {
787
+ await repository.replaceAttachTargets(tx, workspaceId, id, nextAttachTargets)
788
+ }
789
+
790
+ const changedFields: string[] = [...written]
791
+
792
+ if (rewritesFields) {
793
+ changedFields.push('fields')
794
+ }
795
+ if (rewritesLists) {
796
+ changedFields.push('listIds')
797
+ }
798
+ if (rewritesAttachTargets) {
799
+ changedFields.push('attachTargets')
800
+ }
801
+
802
+ events.emit('forms.form.updated', { type: 'form', id }, { changed: changedFields })
320
803
 
321
- return toView(updated, fields)
804
+ return toView(updated, fields, nextListIds, nextAttachTargets)
322
805
  }, { workspaceId, actor: toEventActor(actor) })
323
806
  },
324
807
 
@@ -359,5 +842,46 @@ export function createFormsService(dependencies: FormsDependencies): FormsServic
359
842
  toSubmissionView,
360
843
  )
361
844
  },
845
+
846
+ async listSubmissionsLinkedTo(actor, target, targetId, query) {
847
+ const workspaceId = requireWorkspaceId(actor)
848
+
849
+ // The target's existence is not checked here — a missing or cross-workspace
850
+ // target reads as an empty page, the same answer any other cross-workspace
851
+ // list returns. Adding a per-type existence check would need seven queries
852
+ // for one behaviour that the FK filter already produces.
853
+ const window = readListWindow(query, FORM_SUBMISSION_SORTS, DEFAULT_FORM_SUBMISSION_SORT)
854
+ const rows = await repository.listSubmissionsLinkedTo(
855
+ dependencies.db,
856
+ workspaceId,
857
+ target,
858
+ targetId,
859
+ window,
860
+ )
861
+
862
+ return mapPage(
863
+ toPage(rows, window, (submission) => submission.id),
864
+ toSubmissionView,
865
+ )
866
+ },
867
+
868
+ async getSubmission(actor, formId, submissionId) {
869
+ const workspaceId = requireWorkspaceId(actor)
870
+
871
+ await require(workspaceId, formId)
872
+
873
+ const row = await repository.findSubmission(
874
+ dependencies.db,
875
+ workspaceId,
876
+ formId,
877
+ submissionId,
878
+ )
879
+
880
+ if (row === undefined) {
881
+ throw AppError.notFound('Submission not found')
882
+ }
883
+
884
+ return toSubmissionView(row)
885
+ },
362
886
  }
363
887
  }