@kelpie/server 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (594) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/ids.d.ts +11 -0
  6. package/dist/lib/ids.d.ts.map +1 -1
  7. package/dist/lib/ids.js +11 -0
  8. package/dist/lib/ids.js.map +1 -1
  9. package/dist/modules/activities/repository.d.ts.map +1 -1
  10. package/dist/modules/activities/repository.js +19 -20
  11. package/dist/modules/activities/repository.js.map +1 -1
  12. package/dist/modules/activities/wording.d.ts +12 -0
  13. package/dist/modules/activities/wording.d.ts.map +1 -1
  14. package/dist/modules/activities/wording.js +16 -0
  15. package/dist/modules/activities/wording.js.map +1 -1
  16. package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
  17. package/dist/modules/agent-tasks/catalog.js +62 -0
  18. package/dist/modules/agent-tasks/catalog.js.map +1 -1
  19. package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
  20. package/dist/modules/agent-tasks/resolve.js +42 -9
  21. package/dist/modules/agent-tasks/resolve.js.map +1 -1
  22. package/dist/modules/agent-tasks/routes.d.ts +2 -0
  23. package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
  24. package/dist/modules/attachedRecords.d.ts +6 -1
  25. package/dist/modules/attachedRecords.d.ts.map +1 -1
  26. package/dist/modules/attachedRecords.js +15 -1
  27. package/dist/modules/attachedRecords.js.map +1 -1
  28. package/dist/modules/companies/index.d.ts.map +1 -1
  29. package/dist/modules/companies/index.js +3 -1
  30. package/dist/modules/companies/index.js.map +1 -1
  31. package/dist/modules/companies/routes.d.ts +14 -0
  32. package/dist/modules/companies/routes.d.ts.map +1 -1
  33. package/dist/modules/companies/routes.js +7 -0
  34. package/dist/modules/companies/routes.js.map +1 -1
  35. package/dist/modules/companies/schema.d.ts +20 -0
  36. package/dist/modules/companies/schema.d.ts.map +1 -1
  37. package/dist/modules/companies/schema.js +6 -1
  38. package/dist/modules/companies/schema.js.map +1 -1
  39. package/dist/modules/companies/service.d.ts +5 -0
  40. package/dist/modules/companies/service.d.ts.map +1 -1
  41. package/dist/modules/companies/service.js +24 -12
  42. package/dist/modules/companies/service.js.map +1 -1
  43. package/dist/modules/consent-purposes/capabilities.d.ts +7 -0
  44. package/dist/modules/consent-purposes/capabilities.d.ts.map +1 -0
  45. package/dist/modules/consent-purposes/capabilities.js +10 -0
  46. package/dist/modules/consent-purposes/capabilities.js.map +1 -0
  47. package/dist/modules/consent-purposes/events.d.ts +38 -0
  48. package/dist/modules/consent-purposes/events.d.ts.map +1 -0
  49. package/dist/modules/consent-purposes/events.js +17 -0
  50. package/dist/modules/consent-purposes/events.js.map +1 -0
  51. package/dist/modules/consent-purposes/index.d.ts +13 -0
  52. package/dist/modules/consent-purposes/index.d.ts.map +1 -0
  53. package/dist/modules/consent-purposes/index.js +41 -0
  54. package/dist/modules/consent-purposes/index.js.map +1 -0
  55. package/dist/modules/consent-purposes/repository.d.ts +21 -0
  56. package/dist/modules/consent-purposes/repository.d.ts.map +1 -0
  57. package/dist/modules/consent-purposes/repository.js +98 -0
  58. package/dist/modules/consent-purposes/repository.js.map +1 -0
  59. package/dist/modules/consent-purposes/routes.d.ts +39 -0
  60. package/dist/modules/consent-purposes/routes.d.ts.map +1 -0
  61. package/dist/modules/consent-purposes/routes.js +79 -0
  62. package/dist/modules/consent-purposes/routes.js.map +1 -0
  63. package/dist/modules/consent-purposes/schema.d.ts +175 -0
  64. package/dist/modules/consent-purposes/schema.d.ts.map +1 -0
  65. package/dist/modules/consent-purposes/schema.js +35 -0
  66. package/dist/modules/consent-purposes/schema.js.map +1 -0
  67. package/dist/modules/consent-purposes/service.d.ts +50 -0
  68. package/dist/modules/consent-purposes/service.d.ts.map +1 -0
  69. package/dist/modules/consent-purposes/service.js +263 -0
  70. package/dist/modules/consent-purposes/service.js.map +1 -0
  71. package/dist/modules/consent-purposes/starters.d.ts +17 -0
  72. package/dist/modules/consent-purposes/starters.d.ts.map +1 -0
  73. package/dist/modules/consent-purposes/starters.js +15 -0
  74. package/dist/modules/consent-purposes/starters.js.map +1 -0
  75. package/dist/modules/consent-purposes/tools.d.ts +4 -0
  76. package/dist/modules/consent-purposes/tools.d.ts.map +1 -0
  77. package/dist/modules/consent-purposes/tools.js +29 -0
  78. package/dist/modules/consent-purposes/tools.js.map +1 -0
  79. package/dist/modules/core.d.ts.map +1 -1
  80. package/dist/modules/core.js +10 -0
  81. package/dist/modules/core.js.map +1 -1
  82. package/dist/modules/custom-fields/capabilities.d.ts +12 -0
  83. package/dist/modules/custom-fields/capabilities.d.ts.map +1 -0
  84. package/dist/modules/custom-fields/capabilities.js +15 -0
  85. package/dist/modules/custom-fields/capabilities.js.map +1 -0
  86. package/dist/modules/custom-fields/events.d.ts +49 -0
  87. package/dist/modules/custom-fields/events.d.ts.map +1 -0
  88. package/dist/modules/custom-fields/events.js +25 -0
  89. package/dist/modules/custom-fields/events.js.map +1 -0
  90. package/dist/modules/custom-fields/index.d.ts +19 -0
  91. package/dist/modules/custom-fields/index.d.ts.map +1 -0
  92. package/dist/modules/custom-fields/index.js +46 -0
  93. package/dist/modules/custom-fields/index.js.map +1 -0
  94. package/dist/modules/custom-fields/repository.d.ts +37 -0
  95. package/dist/modules/custom-fields/repository.d.ts.map +1 -0
  96. package/dist/modules/custom-fields/repository.js +144 -0
  97. package/dist/modules/custom-fields/repository.js.map +1 -0
  98. package/dist/modules/custom-fields/routes.d.ts +44 -0
  99. package/dist/modules/custom-fields/routes.d.ts.map +1 -0
  100. package/dist/modules/custom-fields/routes.js +103 -0
  101. package/dist/modules/custom-fields/routes.js.map +1 -0
  102. package/dist/modules/custom-fields/schema.d.ts +215 -0
  103. package/dist/modules/custom-fields/schema.d.ts.map +1 -0
  104. package/dist/modules/custom-fields/schema.js +43 -0
  105. package/dist/modules/custom-fields/schema.js.map +1 -0
  106. package/dist/modules/custom-fields/service.d.ts +57 -0
  107. package/dist/modules/custom-fields/service.d.ts.map +1 -0
  108. package/dist/modules/custom-fields/service.js +273 -0
  109. package/dist/modules/custom-fields/service.js.map +1 -0
  110. package/dist/modules/custom-fields/tools.d.ts +4 -0
  111. package/dist/modules/custom-fields/tools.d.ts.map +1 -0
  112. package/dist/modules/custom-fields/tools.js +38 -0
  113. package/dist/modules/custom-fields/tools.js.map +1 -0
  114. package/dist/modules/custom-fields/values.d.ts +49 -0
  115. package/dist/modules/custom-fields/values.d.ts.map +1 -0
  116. package/dist/modules/custom-fields/values.js +249 -0
  117. package/dist/modules/custom-fields/values.js.map +1 -0
  118. package/dist/modules/custom-fields/wire.d.ts +12 -0
  119. package/dist/modules/custom-fields/wire.d.ts.map +1 -0
  120. package/dist/modules/custom-fields/wire.js +30 -0
  121. package/dist/modules/custom-fields/wire.js.map +1 -0
  122. package/dist/modules/dashboard/repository.d.ts.map +1 -1
  123. package/dist/modules/dashboard/repository.js +4 -3
  124. package/dist/modules/dashboard/repository.js.map +1 -1
  125. package/dist/modules/deals/index.d.ts +2 -1
  126. package/dist/modules/deals/index.d.ts.map +1 -1
  127. package/dist/modules/deals/index.js +5 -2
  128. package/dist/modules/deals/index.js.map +1 -1
  129. package/dist/modules/deals/repository.d.ts +0 -16
  130. package/dist/modules/deals/repository.d.ts.map +1 -1
  131. package/dist/modules/deals/repository.js +6 -76
  132. package/dist/modules/deals/repository.js.map +1 -1
  133. package/dist/modules/deals/routes.d.ts +14 -0
  134. package/dist/modules/deals/routes.d.ts.map +1 -1
  135. package/dist/modules/deals/routes.js +7 -0
  136. package/dist/modules/deals/routes.js.map +1 -1
  137. package/dist/modules/deals/schema.d.ts +20 -42
  138. package/dist/modules/deals/schema.d.ts.map +1 -1
  139. package/dist/modules/deals/schema.js +6 -11
  140. package/dist/modules/deals/schema.js.map +1 -1
  141. package/dist/modules/deals/service.d.ts +13 -2
  142. package/dist/modules/deals/service.d.ts.map +1 -1
  143. package/dist/modules/deals/service.js +43 -20
  144. package/dist/modules/deals/service.js.map +1 -1
  145. package/dist/modules/decisions/repository.d.ts.map +1 -1
  146. package/dist/modules/decisions/repository.js +2 -0
  147. package/dist/modules/decisions/repository.js.map +1 -1
  148. package/dist/modules/decisions/routes.d.ts +1 -0
  149. package/dist/modules/decisions/routes.d.ts.map +1 -1
  150. package/dist/modules/enquiries/events.d.ts +44 -0
  151. package/dist/modules/enquiries/events.d.ts.map +1 -0
  152. package/dist/modules/enquiries/events.js +19 -0
  153. package/dist/modules/enquiries/events.js.map +1 -0
  154. package/dist/modules/enquiries/index.d.ts +13 -0
  155. package/dist/modules/enquiries/index.d.ts.map +1 -0
  156. package/dist/modules/enquiries/index.js +44 -0
  157. package/dist/modules/enquiries/index.js.map +1 -0
  158. package/dist/modules/enquiries/repository.d.ts +30 -0
  159. package/dist/modules/enquiries/repository.d.ts.map +1 -0
  160. package/dist/modules/enquiries/repository.js +94 -0
  161. package/dist/modules/enquiries/repository.js.map +1 -0
  162. package/dist/modules/enquiries/routes.d.ts +52 -0
  163. package/dist/modules/enquiries/routes.d.ts.map +1 -0
  164. package/dist/modules/enquiries/routes.js +127 -0
  165. package/dist/modules/enquiries/routes.js.map +1 -0
  166. package/dist/modules/enquiries/schema.d.ts +290 -0
  167. package/dist/modules/enquiries/schema.d.ts.map +1 -0
  168. package/dist/modules/enquiries/schema.js +52 -0
  169. package/dist/modules/enquiries/schema.js.map +1 -0
  170. package/dist/modules/enquiries/service.d.ts +85 -0
  171. package/dist/modules/enquiries/service.d.ts.map +1 -0
  172. package/dist/modules/enquiries/service.js +370 -0
  173. package/dist/modules/enquiries/service.js.map +1 -0
  174. package/dist/modules/enquiries/tools.d.ts +4 -0
  175. package/dist/modules/enquiries/tools.d.ts.map +1 -0
  176. package/dist/modules/enquiries/tools.js +50 -0
  177. package/dist/modules/enquiries/tools.js.map +1 -0
  178. package/dist/modules/eventCatalogs.d.ts +3 -0
  179. package/dist/modules/eventCatalogs.d.ts.map +1 -1
  180. package/dist/modules/eventCatalogs.js +3 -0
  181. package/dist/modules/eventCatalogs.js.map +1 -1
  182. package/dist/modules/forms/embed.d.ts +20 -6
  183. package/dist/modules/forms/embed.d.ts.map +1 -1
  184. package/dist/modules/forms/embed.js +359 -43
  185. package/dist/modules/forms/embed.js.map +1 -1
  186. package/dist/modules/forms/events.d.ts +20 -7
  187. package/dist/modules/forms/events.d.ts.map +1 -1
  188. package/dist/modules/forms/events.js +20 -2
  189. package/dist/modules/forms/events.js.map +1 -1
  190. package/dist/modules/forms/fields.d.ts +14 -1
  191. package/dist/modules/forms/fields.d.ts.map +1 -1
  192. package/dist/modules/forms/fields.js +87 -3
  193. package/dist/modules/forms/fields.js.map +1 -1
  194. package/dist/modules/forms/index.d.ts.map +1 -1
  195. package/dist/modules/forms/index.js +12 -1
  196. package/dist/modules/forms/index.js.map +1 -1
  197. package/dist/modules/forms/mapping.d.ts +62 -5
  198. package/dist/modules/forms/mapping.d.ts.map +1 -1
  199. package/dist/modules/forms/mapping.js +139 -5
  200. package/dist/modules/forms/mapping.js.map +1 -1
  201. package/dist/modules/forms/publicRoutes.d.ts.map +1 -1
  202. package/dist/modules/forms/publicRoutes.js +29 -1
  203. package/dist/modules/forms/publicRoutes.js.map +1 -1
  204. package/dist/modules/forms/repository.d.ts +31 -0
  205. package/dist/modules/forms/repository.d.ts.map +1 -1
  206. package/dist/modules/forms/repository.js +90 -1
  207. package/dist/modules/forms/repository.js.map +1 -1
  208. package/dist/modules/forms/routes.d.ts +83 -1
  209. package/dist/modules/forms/routes.d.ts.map +1 -1
  210. package/dist/modules/forms/routes.js +185 -2
  211. package/dist/modules/forms/routes.js.map +1 -1
  212. package/dist/modules/forms/schema.d.ts +672 -1
  213. package/dist/modules/forms/schema.d.ts.map +1 -1
  214. package/dist/modules/forms/schema.js +146 -3
  215. package/dist/modules/forms/schema.js.map +1 -1
  216. package/dist/modules/forms/service.d.ts +54 -1
  217. package/dist/modules/forms/service.d.ts.map +1 -1
  218. package/dist/modules/forms/service.js +338 -28
  219. package/dist/modules/forms/service.js.map +1 -1
  220. package/dist/modules/forms/submission.d.ts +15 -0
  221. package/dist/modules/forms/submission.d.ts.map +1 -1
  222. package/dist/modules/forms/submission.js +418 -40
  223. package/dist/modules/forms/submission.js.map +1 -1
  224. package/dist/modules/import-export/drafts.d.ts +10 -0
  225. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  226. package/dist/modules/import-export/drafts.js +16 -2
  227. package/dist/modules/import-export/drafts.js.map +1 -1
  228. package/dist/modules/import-export/exportRows.d.ts +7 -4
  229. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  230. package/dist/modules/import-export/exportRows.js +20 -5
  231. package/dist/modules/import-export/exportRows.js.map +1 -1
  232. package/dist/modules/import-export/plan.d.ts +12 -1
  233. package/dist/modules/import-export/plan.d.ts.map +1 -1
  234. package/dist/modules/import-export/plan.js +29 -2
  235. package/dist/modules/import-export/plan.js.map +1 -1
  236. package/dist/modules/import-export/presets.d.ts.map +1 -1
  237. package/dist/modules/import-export/presets.js +10 -0
  238. package/dist/modules/import-export/presets.js.map +1 -1
  239. package/dist/modules/import-export/repository.d.ts +11 -1
  240. package/dist/modules/import-export/repository.d.ts.map +1 -1
  241. package/dist/modules/import-export/repository.js +42 -9
  242. package/dist/modules/import-export/repository.js.map +1 -1
  243. package/dist/modules/import-export/routes.d.ts.map +1 -1
  244. package/dist/modules/import-export/routes.js +4 -0
  245. package/dist/modules/import-export/routes.js.map +1 -1
  246. package/dist/modules/import-export/schema.d.ts +17 -0
  247. package/dist/modules/import-export/schema.d.ts.map +1 -1
  248. package/dist/modules/import-export/schema.js +11 -0
  249. package/dist/modules/import-export/schema.js.map +1 -1
  250. package/dist/modules/import-export/service.d.ts +6 -0
  251. package/dist/modules/import-export/service.d.ts.map +1 -1
  252. package/dist/modules/import-export/service.js +14 -2
  253. package/dist/modules/import-export/service.js.map +1 -1
  254. package/dist/modules/import-export/streams.d.ts.map +1 -1
  255. package/dist/modules/import-export/streams.js +3 -3
  256. package/dist/modules/import-export/streams.js.map +1 -1
  257. package/dist/modules/import-export/tools.d.ts.map +1 -1
  258. package/dist/modules/import-export/tools.js +8 -0
  259. package/dist/modules/import-export/tools.js.map +1 -1
  260. package/dist/modules/import-export/validation.d.ts.map +1 -1
  261. package/dist/modules/import-export/validation.js +22 -1
  262. package/dist/modules/import-export/validation.js.map +1 -1
  263. package/dist/modules/import-export/writes.d.ts.map +1 -1
  264. package/dist/modules/import-export/writes.js +37 -4
  265. package/dist/modules/import-export/writes.js.map +1 -1
  266. package/dist/modules/lists/index.d.ts +38 -0
  267. package/dist/modules/lists/index.d.ts.map +1 -1
  268. package/dist/modules/lists/index.js +27 -0
  269. package/dist/modules/lists/index.js.map +1 -1
  270. package/dist/modules/lists/repository.d.ts +26 -0
  271. package/dist/modules/lists/repository.d.ts.map +1 -1
  272. package/dist/modules/lists/repository.js +32 -0
  273. package/dist/modules/lists/repository.js.map +1 -1
  274. package/dist/modules/lists/routes.d.ts +4 -0
  275. package/dist/modules/lists/routes.d.ts.map +1 -1
  276. package/dist/modules/lists/routes.js +8 -0
  277. package/dist/modules/lists/routes.js.map +1 -1
  278. package/dist/modules/lists/schema.d.ts +17 -0
  279. package/dist/modules/lists/schema.d.ts.map +1 -1
  280. package/dist/modules/lists/schema.js +10 -0
  281. package/dist/modules/lists/schema.js.map +1 -1
  282. package/dist/modules/lists/service.d.ts +14 -2
  283. package/dist/modules/lists/service.d.ts.map +1 -1
  284. package/dist/modules/lists/service.js +55 -7
  285. package/dist/modules/lists/service.js.map +1 -1
  286. package/dist/modules/mcp/index.d.ts.map +1 -1
  287. package/dist/modules/mcp/index.js +5 -0
  288. package/dist/modules/mcp/index.js.map +1 -1
  289. package/dist/modules/notes/routes.d.ts +1 -0
  290. package/dist/modules/notes/routes.d.ts.map +1 -1
  291. package/dist/modules/opportunities/index.d.ts.map +1 -1
  292. package/dist/modules/opportunities/index.js +3 -1
  293. package/dist/modules/opportunities/index.js.map +1 -1
  294. package/dist/modules/opportunities/repository.d.ts +2 -0
  295. package/dist/modules/opportunities/repository.d.ts.map +1 -1
  296. package/dist/modules/opportunities/repository.js +4 -0
  297. package/dist/modules/opportunities/repository.js.map +1 -1
  298. package/dist/modules/opportunities/routes.d.ts +16 -0
  299. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  300. package/dist/modules/opportunities/routes.js +13 -0
  301. package/dist/modules/opportunities/routes.js.map +1 -1
  302. package/dist/modules/opportunities/schema.d.ts +20 -0
  303. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  304. package/dist/modules/opportunities/schema.js +6 -1
  305. package/dist/modules/opportunities/schema.js.map +1 -1
  306. package/dist/modules/opportunities/service.d.ts +20 -3
  307. package/dist/modules/opportunities/service.d.ts.map +1 -1
  308. package/dist/modules/opportunities/service.js +99 -18
  309. package/dist/modules/opportunities/service.js.map +1 -1
  310. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  311. package/dist/modules/opportunities/tools.js +2 -0
  312. package/dist/modules/opportunities/tools.js.map +1 -1
  313. package/dist/modules/partnerships/index.d.ts.map +1 -1
  314. package/dist/modules/partnerships/index.js +3 -1
  315. package/dist/modules/partnerships/index.js.map +1 -1
  316. package/dist/modules/partnerships/repository.d.ts +0 -17
  317. package/dist/modules/partnerships/repository.d.ts.map +1 -1
  318. package/dist/modules/partnerships/repository.js +6 -82
  319. package/dist/modules/partnerships/repository.js.map +1 -1
  320. package/dist/modules/partnerships/routes.d.ts +14 -0
  321. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  322. package/dist/modules/partnerships/routes.js +7 -0
  323. package/dist/modules/partnerships/routes.js.map +1 -1
  324. package/dist/modules/partnerships/schema.d.ts +20 -41
  325. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  326. package/dist/modules/partnerships/schema.js +6 -10
  327. package/dist/modules/partnerships/schema.js.map +1 -1
  328. package/dist/modules/partnerships/service.d.ts +11 -1
  329. package/dist/modules/partnerships/service.d.ts.map +1 -1
  330. package/dist/modules/partnerships/service.js +43 -20
  331. package/dist/modules/partnerships/service.js.map +1 -1
  332. package/dist/modules/people/consentHydration.d.ts +26 -0
  333. package/dist/modules/people/consentHydration.d.ts.map +1 -0
  334. package/dist/modules/people/consentHydration.js +100 -0
  335. package/dist/modules/people/consentHydration.js.map +1 -0
  336. package/dist/modules/people/index.d.ts.map +1 -1
  337. package/dist/modules/people/index.js +3 -1
  338. package/dist/modules/people/index.js.map +1 -1
  339. package/dist/modules/people/personConsentWrites.d.ts +40 -0
  340. package/dist/modules/people/personConsentWrites.d.ts.map +1 -0
  341. package/dist/modules/people/personConsentWrites.js +98 -0
  342. package/dist/modules/people/personConsentWrites.js.map +1 -0
  343. package/dist/modules/people/repository.d.ts.map +1 -1
  344. package/dist/modules/people/repository.js +5 -1
  345. package/dist/modules/people/repository.js.map +1 -1
  346. package/dist/modules/people/routes.d.ts +57 -4
  347. package/dist/modules/people/routes.d.ts.map +1 -1
  348. package/dist/modules/people/routes.js +104 -5
  349. package/dist/modules/people/routes.js.map +1 -1
  350. package/dist/modules/people/schema.d.ts +366 -1
  351. package/dist/modules/people/schema.d.ts.map +1 -1
  352. package/dist/modules/people/schema.js +92 -2
  353. package/dist/modules/people/schema.js.map +1 -1
  354. package/dist/modules/people/service.d.ts +30 -1
  355. package/dist/modules/people/service.d.ts.map +1 -1
  356. package/dist/modules/people/service.js +115 -38
  357. package/dist/modules/people/service.js.map +1 -1
  358. package/dist/modules/people/tools.d.ts.map +1 -1
  359. package/dist/modules/people/tools.js +4 -1
  360. package/dist/modules/people/tools.js.map +1 -1
  361. package/dist/modules/personLinks.d.ts +79 -0
  362. package/dist/modules/personLinks.d.ts.map +1 -0
  363. package/dist/modules/personLinks.js +155 -0
  364. package/dist/modules/personLinks.js.map +1 -0
  365. package/dist/modules/pipelines/routes.d.ts +1 -0
  366. package/dist/modules/pipelines/routes.d.ts.map +1 -1
  367. package/dist/modules/plans/routes.d.ts +1 -0
  368. package/dist/modules/plans/routes.d.ts.map +1 -1
  369. package/dist/modules/raises/index.d.ts.map +1 -1
  370. package/dist/modules/raises/index.js +3 -1
  371. package/dist/modules/raises/index.js.map +1 -1
  372. package/dist/modules/raises/repository.d.ts +0 -17
  373. package/dist/modules/raises/repository.d.ts.map +1 -1
  374. package/dist/modules/raises/repository.js +6 -77
  375. package/dist/modules/raises/repository.js.map +1 -1
  376. package/dist/modules/raises/routes.d.ts +14 -0
  377. package/dist/modules/raises/routes.d.ts.map +1 -1
  378. package/dist/modules/raises/routes.js +7 -0
  379. package/dist/modules/raises/routes.js.map +1 -1
  380. package/dist/modules/raises/schema.d.ts +20 -41
  381. package/dist/modules/raises/schema.d.ts.map +1 -1
  382. package/dist/modules/raises/schema.js +6 -10
  383. package/dist/modules/raises/schema.js.map +1 -1
  384. package/dist/modules/raises/service.d.ts +11 -1
  385. package/dist/modules/raises/service.d.ts.map +1 -1
  386. package/dist/modules/raises/service.js +41 -18
  387. package/dist/modules/raises/service.js.map +1 -1
  388. package/dist/modules/recordTargets.d.ts.map +1 -1
  389. package/dist/modules/recordTargets.js +2 -0
  390. package/dist/modules/recordTargets.js.map +1 -1
  391. package/dist/modules/references.d.ts +10 -0
  392. package/dist/modules/references.d.ts.map +1 -1
  393. package/dist/modules/references.js +27 -4
  394. package/dist/modules/references.js.map +1 -1
  395. package/dist/modules/sample-data/fixture.d.ts +21 -0
  396. package/dist/modules/sample-data/fixture.d.ts.map +1 -1
  397. package/dist/modules/sample-data/fixture.js +40 -0
  398. package/dist/modules/sample-data/fixture.js.map +1 -1
  399. package/dist/modules/sample-data/index.d.ts.map +1 -1
  400. package/dist/modules/sample-data/index.js +1 -0
  401. package/dist/modules/sample-data/index.js.map +1 -1
  402. package/dist/modules/sample-data/routes.d.ts.map +1 -1
  403. package/dist/modules/sample-data/routes.js +1 -0
  404. package/dist/modules/sample-data/routes.js.map +1 -1
  405. package/dist/modules/sample-data/service.d.ts +1 -0
  406. package/dist/modules/sample-data/service.d.ts.map +1 -1
  407. package/dist/modules/sample-data/service.js +77 -8
  408. package/dist/modules/sample-data/service.js.map +1 -1
  409. package/dist/modules/search/index.d.ts +1 -1
  410. package/dist/modules/search/index.d.ts.map +1 -1
  411. package/dist/modules/search/index.js +2 -1
  412. package/dist/modules/search/index.js.map +1 -1
  413. package/dist/modules/search/repository.d.ts +1 -0
  414. package/dist/modules/search/repository.d.ts.map +1 -1
  415. package/dist/modules/search/repository.js +23 -0
  416. package/dist/modules/search/repository.js.map +1 -1
  417. package/dist/modules/search/service.d.ts +3 -3
  418. package/dist/modules/search/service.d.ts.map +1 -1
  419. package/dist/modules/search/service.js +5 -4
  420. package/dist/modules/search/service.js.map +1 -1
  421. package/dist/modules/stagedRecords.d.ts +3 -3
  422. package/dist/modules/stagedRecords.d.ts.map +1 -1
  423. package/dist/modules/stagedRecords.js +9 -0
  424. package/dist/modules/stagedRecords.js.map +1 -1
  425. package/dist/modules/webhooks/payloads.d.ts.map +1 -1
  426. package/dist/modules/webhooks/payloads.js +15 -2
  427. package/dist/modules/webhooks/payloads.js.map +1 -1
  428. package/dist/modules/workspace/repository.d.ts +2 -0
  429. package/dist/modules/workspace/repository.d.ts.map +1 -1
  430. package/dist/modules/workspace/repository.js +7 -0
  431. package/dist/modules/workspace/repository.js.map +1 -1
  432. package/dist/modules/workspace/service.d.ts.map +1 -1
  433. package/dist/modules/workspace/service.js +10 -0
  434. package/dist/modules/workspace/service.js.map +1 -1
  435. package/dist/modules/workspace/starters.d.ts.map +1 -1
  436. package/dist/modules/workspace/starters.js +5 -0
  437. package/dist/modules/workspace/starters.js.map +1 -1
  438. package/dist/runtime/events.d.ts +1 -1
  439. package/dist/runtime/events.d.ts.map +1 -1
  440. package/dist/runtime/events.js +1 -0
  441. package/dist/runtime/events.js.map +1 -1
  442. package/dist/schema/index.d.ts +3 -0
  443. package/dist/schema/index.d.ts.map +1 -1
  444. package/dist/schema/index.js +3 -0
  445. package/dist/schema/index.js.map +1 -1
  446. package/dist/testing/database.d.ts +5 -1
  447. package/dist/testing/database.d.ts.map +1 -1
  448. package/dist/testing/database.js +81 -10
  449. package/dist/testing/database.js.map +1 -1
  450. package/migrations/0024_third_king_cobra.sql +46 -0
  451. package/migrations/0025_worthless_chimera.sql +3 -0
  452. package/migrations/0026_late_aqueduct.sql +46 -0
  453. package/migrations/0027_brainy_silver_sable.sql +3 -0
  454. package/migrations/0028_freezing_scrambler.sql +19 -0
  455. package/migrations/0029_custom_fields.sql +26 -0
  456. package/migrations/0030_enquiries.sql +79 -0
  457. package/migrations/0031_consent.sql +45 -0
  458. package/migrations/0032_form_field_statement.sql +1 -0
  459. package/migrations/0033_form_field_consent_purpose_ids.sql +5 -0
  460. package/migrations/0034_drop_form_field_consent_purpose_id.sql +1 -0
  461. package/migrations/0035_form_field_consent_purpose_labels.sql +1 -0
  462. package/migrations/0036_form_field_notice_type.sql +2 -0
  463. package/migrations/meta/0024_snapshot.json +5516 -0
  464. package/migrations/meta/0025_snapshot.json +5336 -0
  465. package/migrations/meta/0026_snapshot.json +5710 -0
  466. package/migrations/meta/0027_snapshot.json +5716 -0
  467. package/migrations/meta/0028_snapshot.json +5740 -0
  468. package/migrations/meta/0029_snapshot.json +5935 -0
  469. package/migrations/meta/0030_snapshot.json +6245 -0
  470. package/migrations/meta/0031_snapshot.json +6572 -0
  471. package/migrations/meta/0032_snapshot.json +6578 -0
  472. package/migrations/meta/0033_snapshot.json +6572 -0
  473. package/migrations/meta/0034_snapshot.json +6566 -0
  474. package/migrations/meta/0035_snapshot.json +6573 -0
  475. package/migrations/meta/0036_snapshot.json +6573 -0
  476. package/migrations/meta/_journal.json +91 -0
  477. package/package.json +2 -2
  478. package/src/index.ts +6 -0
  479. package/src/lib/ids.ts +11 -0
  480. package/src/modules/activities/repository.ts +22 -23
  481. package/src/modules/activities/wording.ts +18 -0
  482. package/src/modules/agent-tasks/catalog.ts +63 -0
  483. package/src/modules/agent-tasks/resolve.ts +64 -24
  484. package/src/modules/attachedRecords.ts +29 -2
  485. package/src/modules/companies/index.ts +3 -1
  486. package/src/modules/companies/routes.ts +7 -0
  487. package/src/modules/companies/schema.ts +7 -1
  488. package/src/modules/companies/service.ts +48 -13
  489. package/src/modules/consent-purposes/capabilities.ts +12 -0
  490. package/src/modules/consent-purposes/events.ts +38 -0
  491. package/src/modules/consent-purposes/index.ts +48 -0
  492. package/src/modules/consent-purposes/repository.ts +163 -0
  493. package/src/modules/consent-purposes/routes.ts +122 -0
  494. package/src/modules/consent-purposes/schema.ts +46 -0
  495. package/src/modules/consent-purposes/service.ts +423 -0
  496. package/src/modules/consent-purposes/starters.ts +32 -0
  497. package/src/modules/consent-purposes/tools.ts +44 -0
  498. package/src/modules/core.ts +10 -0
  499. package/src/modules/custom-fields/capabilities.ts +17 -0
  500. package/src/modules/custom-fields/events.ts +51 -0
  501. package/src/modules/custom-fields/index.ts +61 -0
  502. package/src/modules/custom-fields/repository.ts +225 -0
  503. package/src/modules/custom-fields/routes.ts +155 -0
  504. package/src/modules/custom-fields/schema.ts +61 -0
  505. package/src/modules/custom-fields/service.ts +439 -0
  506. package/src/modules/custom-fields/tools.ts +53 -0
  507. package/src/modules/custom-fields/values.ts +352 -0
  508. package/src/modules/custom-fields/wire.ts +32 -0
  509. package/src/modules/dashboard/repository.ts +4 -3
  510. package/src/modules/deals/index.ts +5 -2
  511. package/src/modules/deals/repository.ts +6 -106
  512. package/src/modules/deals/routes.ts +7 -0
  513. package/src/modules/deals/schema.ts +7 -15
  514. package/src/modules/deals/service.ts +92 -23
  515. package/src/modules/decisions/repository.ts +2 -0
  516. package/src/modules/enquiries/events.ts +45 -0
  517. package/src/modules/enquiries/index.ts +50 -0
  518. package/src/modules/enquiries/repository.ts +164 -0
  519. package/src/modules/enquiries/routes.ts +172 -0
  520. package/src/modules/enquiries/schema.ts +59 -0
  521. package/src/modules/enquiries/service.ts +644 -0
  522. package/src/modules/enquiries/tools.ts +66 -0
  523. package/src/modules/eventCatalogs.ts +3 -0
  524. package/src/modules/forms/embed.ts +391 -44
  525. package/src/modules/forms/events.ts +30 -2
  526. package/src/modules/forms/fields.ts +102 -2
  527. package/src/modules/forms/index.ts +12 -1
  528. package/src/modules/forms/mapping.ts +183 -6
  529. package/src/modules/forms/publicRoutes.ts +43 -1
  530. package/src/modules/forms/repository.ts +162 -1
  531. package/src/modules/forms/routes.ts +212 -2
  532. package/src/modules/forms/schema.ts +166 -4
  533. package/src/modules/forms/service.ts +565 -41
  534. package/src/modules/forms/submission.ts +718 -44
  535. package/src/modules/import-export/drafts.ts +20 -1
  536. package/src/modules/import-export/exportRows.ts +21 -5
  537. package/src/modules/import-export/plan.ts +47 -2
  538. package/src/modules/import-export/presets.ts +10 -0
  539. package/src/modules/import-export/repository.ts +73 -8
  540. package/src/modules/import-export/routes.ts +4 -0
  541. package/src/modules/import-export/schema.ts +11 -0
  542. package/src/modules/import-export/service.ts +28 -2
  543. package/src/modules/import-export/streams.ts +3 -1
  544. package/src/modules/import-export/tools.ts +10 -0
  545. package/src/modules/import-export/validation.ts +28 -0
  546. package/src/modules/import-export/writes.ts +70 -5
  547. package/src/modules/lists/index.ts +71 -0
  548. package/src/modules/lists/repository.ts +64 -0
  549. package/src/modules/lists/routes.ts +8 -0
  550. package/src/modules/lists/schema.ts +10 -0
  551. package/src/modules/lists/service.ts +110 -9
  552. package/src/modules/mcp/index.ts +5 -0
  553. package/src/modules/opportunities/index.ts +3 -1
  554. package/src/modules/opportunities/repository.ts +11 -0
  555. package/src/modules/opportunities/routes.ts +13 -0
  556. package/src/modules/opportunities/schema.ts +7 -1
  557. package/src/modules/opportunities/service.ts +188 -22
  558. package/src/modules/opportunities/tools.ts +2 -0
  559. package/src/modules/partnerships/index.ts +3 -1
  560. package/src/modules/partnerships/repository.ts +6 -117
  561. package/src/modules/partnerships/routes.ts +7 -0
  562. package/src/modules/partnerships/schema.ts +7 -14
  563. package/src/modules/partnerships/service.ts +93 -22
  564. package/src/modules/people/consentHydration.ts +167 -0
  565. package/src/modules/people/index.ts +3 -1
  566. package/src/modules/people/personConsentWrites.ts +177 -0
  567. package/src/modules/people/repository.ts +5 -0
  568. package/src/modules/people/routes.ts +127 -18
  569. package/src/modules/people/schema.ts +109 -3
  570. package/src/modules/people/service.ts +186 -40
  571. package/src/modules/people/tools.ts +5 -1
  572. package/src/modules/personLinks.ts +278 -0
  573. package/src/modules/raises/index.ts +3 -1
  574. package/src/modules/raises/repository.ts +6 -107
  575. package/src/modules/raises/routes.ts +7 -0
  576. package/src/modules/raises/schema.ts +7 -14
  577. package/src/modules/raises/service.ts +91 -20
  578. package/src/modules/recordTargets.ts +2 -0
  579. package/src/modules/references.ts +43 -4
  580. package/src/modules/sample-data/fixture.ts +63 -0
  581. package/src/modules/sample-data/index.ts +1 -0
  582. package/src/modules/sample-data/routes.ts +1 -0
  583. package/src/modules/sample-data/service.ts +97 -8
  584. package/src/modules/search/index.ts +2 -1
  585. package/src/modules/search/repository.ts +33 -1
  586. package/src/modules/search/service.ts +7 -5
  587. package/src/modules/stagedRecords.ts +18 -3
  588. package/src/modules/webhooks/payloads.ts +20 -2
  589. package/src/modules/workspace/repository.ts +12 -0
  590. package/src/modules/workspace/service.ts +14 -0
  591. package/src/modules/workspace/starters.ts +5 -0
  592. package/src/runtime/events.ts +1 -0
  593. package/src/schema/index.ts +3 -0
  594. package/src/testing/database.ts +97 -11
@@ -1,3 +1,4 @@
1
+ import { UNIQUE_VIOLATION, postgresErrorCode } from '../../lib/database.js';
1
2
  import { AppError } from '../../lib/errors.js';
2
3
  import { requireCapability } from '../../runtime/entitlements.js';
3
4
  import { moduleCapabilityName } from '../../runtime/moduleConfig.js';
@@ -6,14 +7,26 @@ import '../companies/events.js';
6
7
  import * as companyRepository from '../companies/repository.js';
7
8
  import * as dealRepository from '../deals/repository.js';
8
9
  import '../deals/events.js';
10
+ import * as enquiryRepository from '../enquiries/repository.js';
11
+ import '../enquiries/events.js';
12
+ import '../lists/events.js';
13
+ import * as listsRepository from '../lists/repository.js';
14
+ import * as opportunityRepository from '../opportunities/repository.js';
15
+ import '../opportunities/events.js';
16
+ import * as partnershipRepository from '../partnerships/repository.js';
17
+ import '../partnerships/events.js';
18
+ import * as consentPurposesRepository from '../consent-purposes/repository.js';
9
19
  import '../people/events.js';
20
+ import { upsertPersonConsent } from '../people/personConsentWrites.js';
10
21
  import * as peopleRepository from '../people/repository.js';
22
+ import * as personLinks from '../personLinks.js';
11
23
  import * as pipelineRepository from '../pipelines/repository.js';
12
24
  import '../positions/events.js';
13
25
  import * as positionRepository from '../positions/repository.js';
26
+ import { targetExists } from '../recordTargets.js';
14
27
  import * as workspaceRepository from '../workspace/repository.js';
15
28
  import './events.js';
16
- import { DEAL_CLOSE_HORIZON_DAYS, companyNameFrom, describeAnswers, expandDealNameTemplate, expectedCloseFrom, fillBlank, findAnswerProblems, mapAnswers, readIntent, } from './mapping.js';
29
+ import { DEAL_CLOSE_HORIZON_DAYS, companyNameFrom, describeAnswers, expandNameTemplate, expectedCloseFrom, fillBlank, findAnswerProblems, mapAnswers, mergeTags, readConsentGrants, readIntent, } from './mapping.js';
17
30
  import * as repository from './repository.js';
18
31
  /**
19
32
  * The public submit: `forms.md` rules 1 to 7, server-side.
@@ -63,30 +76,24 @@ const NEW_PERSON_DEFAULTS = {
63
76
  influence: 'influencer',
64
77
  };
65
78
  /**
66
- * One `record.created` per record this submit invented, and one
67
- * `record.updated` per record it filled a blank on.
79
+ * One `record.created` per record this submit invented (person, company,
80
+ * position), and one `record.updated` per record it filled a blank on. The
81
+ * pipeline creates (deal, opportunity, partnership) publish their own
82
+ * `*.created` events from inside their action's shim so a rolled-back
83
+ * savepoint drops the event alongside the row.
68
84
  *
69
- * A submit that matched an existing person and changed nothing about them emits
70
- * neither: a consumer mirroring the CRM has nothing to mirror, and
85
+ * A submit that matched an existing person and changed nothing about them
86
+ * emits neither: a consumer mirroring the CRM has nothing to mirror, and
71
87
  * `form.submitted` already says the submission happened.
72
- *
73
- * The Deal has no `Upserted` because it is only ever created, and its people
74
- * link rides along with it rather than as a separate `record.updated`, the same
75
- * way the deals service treats a create.
76
88
  */
77
89
  function emitRecordEvents(events, workspaceId, touched) {
78
- if (touched.person !== undefined) {
79
- emitUpsertEvent(events, 'person', touched.person);
80
- }
90
+ emitUpsertEvent(events, 'person', touched.person);
81
91
  if (touched.company !== undefined) {
82
92
  emitUpsertEvent(events, 'company', touched.company);
83
93
  }
84
94
  if (touched.position !== undefined) {
85
95
  emitUpsertEvent(events, 'position', touched.position);
86
96
  }
87
- if (touched.dealId !== null) {
88
- events.emit('deals.deal.created', { type: 'deal', id: touched.dealId }, {});
89
- }
90
97
  // workspaceId is used by the transaction scope's envelope stamping; the
91
98
  // parameter stays on the signature so future call sites keep the same shape.
92
99
  void workspaceId;
@@ -144,22 +151,34 @@ export function createFormSubmitService(dependencies) {
144
151
  id: dependencies.createId('person'),
145
152
  workspaceId,
146
153
  name: intent.personName,
154
+ firstName: intent.personFirstName ?? null,
155
+ lastName: intent.personLastName ?? null,
147
156
  email: intent.email,
148
157
  lastContactedAt: now,
149
158
  ...NEW_PERSON_DEFAULTS,
150
159
  });
151
160
  return { record: created, created: true, filled: [] };
152
161
  }
153
- const name = fillBlank(existing.name, intent.personName);
162
+ // Each part fills its own blank. A stored first name is what the team has
163
+ // learned and an inbound one is what a visitor typed, so the rule that keeps
164
+ // an inbound "Alex" off a stored "Alex Rivera" covers these unchanged.
165
+ const filledName = fillBlank(existing.name, intent.personName);
166
+ const filledFirstName = fillBlank(existing.firstName, intent.personFirstName);
167
+ const filledLastName = fillBlank(existing.lastName, intent.personLastName);
168
+ const changes = {
169
+ ...(filledName === undefined ? {} : { name: filledName }),
170
+ ...(filledFirstName === undefined ? {} : { firstName: filledFirstName }),
171
+ ...(filledLastName === undefined ? {} : { lastName: filledLastName }),
172
+ };
154
173
  const updated = await peopleRepository.updatePerson(tx, workspaceId, existing.id, {
155
- ...(name === undefined ? {} : { name }),
174
+ ...changes,
156
175
  lastContactedAt: now,
157
176
  updatedAt: now,
158
177
  });
159
178
  if (updated === undefined) {
160
179
  throw new Error(`Person ${existing.id} disappeared during a form submit`);
161
180
  }
162
- return { record: updated, created: false, filled: name === undefined ? [] : ['name'] };
181
+ return { record: updated, created: false, filled: Object.keys(changes) };
163
182
  }
164
183
  /**
165
184
  * Upserts the Company, by domain when there is one and by name otherwise
@@ -233,20 +252,57 @@ export function createFormSubmitService(dependencies) {
233
252
  });
234
253
  return { record: created, created: true, filled: [] };
235
254
  }
236
- /** The stage a form's deals open in: the one it names, or the pipeline's first open one. */
237
- async function openingStageId(tx, workspaceId, form) {
238
- if (form.dealStageId !== null) {
239
- return form.dealStageId;
255
+ /**
256
+ * The stage a form's created record opens in: the one the form names, or
257
+ * the pipeline's first open stage. Shared by the three create-triggers.
258
+ */
259
+ async function openingStageId(tx, workspaceId, kind, configured) {
260
+ if (configured !== null) {
261
+ return configured;
240
262
  }
241
- const stages = await pipelineRepository.listStagesOfKind(tx, workspaceId, 'deal');
263
+ const stages = await pipelineRepository.listStagesOfKind(tx, workspaceId, kind);
242
264
  const first = stages.find((stage) => stage.open) ?? stages[0];
243
265
  if (first === undefined) {
244
266
  // Unreachable through the API: a workspace seeds its stages at creation
245
267
  // and the last stage of a pipeline cannot be removed.
246
- throw AppError.conflict('This workspace has no deal stages');
268
+ throw AppError.conflict(`This workspace has no ${kind} stages`);
247
269
  }
248
270
  return first.id;
249
271
  }
272
+ /**
273
+ * Runs `work` under a nested `tx.transaction()` — a SAVEPOINT in
274
+ * postgres-js — and captures every event the action emits into a local
275
+ * buffer. On success (`ok` or `skipped`) the events are forwarded to the
276
+ * real `BufferedEvents`; on throw the savepoint has already rolled back so
277
+ * the events are discarded and a `{status: 'error'}` entry lands on the log.
278
+ * Either way the outer transaction stays alive: the next action runs, and
279
+ * the visitor's 201 survives.
280
+ */
281
+ async function runAction(tx, events, log, action, work) {
282
+ const pending = [];
283
+ const emit = (name, target, data) => {
284
+ pending.push({ name, target, data });
285
+ };
286
+ try {
287
+ const result = await tx.transaction(async (inner) => work(inner, emit));
288
+ log.push({ action, status: result.status, detail: result.detail });
289
+ for (const event of pending) {
290
+ // The typed emit rejects an unrelated (name, data) pair; the shim
291
+ // captured them as one call so the pair is already validated.
292
+ events.emit(event.name, event.target, event.data);
293
+ }
294
+ return result.value;
295
+ }
296
+ catch (error) {
297
+ const detail = error instanceof AppError
298
+ ? error.message
299
+ : error instanceof Error
300
+ ? error.message
301
+ : 'unknown error';
302
+ log.push({ action, status: 'error', detail });
303
+ return undefined;
304
+ }
305
+ }
250
306
  /**
251
307
  * Creates the Deal, when the form makes them and a company was resolved.
252
308
  *
@@ -254,25 +310,144 @@ export function createFormSubmitService(dependencies) {
254
310
  * that resolved none creates no deal and says so through a null `deal_id` on
255
311
  * the submission rather than by inventing one.
256
312
  */
257
- async function createDeal(tx, workspaceId, form, intent, company, personId) {
313
+ async function createDeal(tx, emit, workspaceId, form, intent, company, personId) {
258
314
  const id = dependencies.createId('deal');
259
315
  const owner = await workspaceRepository.findDefaultMember(tx, workspaceId);
260
316
  await dealRepository.insertDeal(tx, {
261
317
  id,
262
318
  workspaceId,
263
319
  name: intent.dealName ??
264
- expandDealNameTemplate(form.dealNameTemplate ?? DEFAULT_DEAL_NAME_TEMPLATE, {
320
+ expandNameTemplate(form.dealNameTemplate ?? DEFAULT_DEAL_NAME_TEMPLATE, {
265
321
  companyName: company.name,
266
322
  personName: intent.personName,
267
323
  }),
268
324
  companyId: company.id,
269
- stageId: await openingStageId(tx, workspaceId, form),
325
+ stageId: await openingStageId(tx, workspaceId, 'deal', form.dealStageId),
270
326
  valueCents: 0,
271
327
  currency: null,
272
328
  ownerId: owner?.id ?? null,
273
329
  expectedClose: expectedCloseFrom(dependencies.now(), DEAL_CLOSE_HORIZON_DAYS),
274
330
  });
275
- await dealRepository.insertDealPeople(tx, id, [personId]);
331
+ await personLinks.linkPeople(tx, dependencies.createId, workspaceId, { targetType: 'deal', targetId: id }, [personId]);
332
+ await dependencies.recordActivity(tx, workspaceId, FORM_ACTOR, {
333
+ targetType: 'deal',
334
+ targetId: id,
335
+ kind: 'created',
336
+ ...describeCreationVia('Deal', form.name),
337
+ });
338
+ emit('deals.deal.created', { type: 'deal', id }, {});
339
+ return id;
340
+ }
341
+ /**
342
+ * Creates the Opportunity, when the form makes them.
343
+ *
344
+ * `opportunities.company_id` is nullable, so a submit that resolved no
345
+ * company still creates the opportunity, with the company link null. The
346
+ * kind is required at form-write time (see `service.ts`), so it is always
347
+ * present here.
348
+ */
349
+ async function createOpportunity(tx, emit, workspaceId, form, intent, company, personId) {
350
+ const id = dependencies.createId('opportunity');
351
+ const owner = form.opportunityOwnerId === null
352
+ ? await workspaceRepository.findDefaultMember(tx, workspaceId)
353
+ : { id: form.opportunityOwnerId };
354
+ await opportunityRepository.insertOpportunity(tx, {
355
+ id,
356
+ workspaceId,
357
+ name: intent.opportunityName ??
358
+ expandNameTemplate(form.opportunityNameTemplate ?? DEFAULT_DEAL_NAME_TEMPLATE, {
359
+ companyName: company?.name ?? '',
360
+ personName: intent.personName,
361
+ }),
362
+ // requireKindWhenCreating refuses an empty kind at write; the ?? is a
363
+ // narrowing convenience, not a runtime fallback.
364
+ kind: form.opportunityKind ?? '',
365
+ stageId: await openingStageId(tx, workspaceId, 'opportunity', form.opportunityStageId),
366
+ companyId: company?.id ?? null,
367
+ ownerId: owner?.id ?? null,
368
+ expectedClose: expectedCloseFrom(dependencies.now(), DEAL_CLOSE_HORIZON_DAYS),
369
+ });
370
+ await personLinks.linkPeople(tx, dependencies.createId, workspaceId, { targetType: 'opportunity', targetId: id }, [personId]);
371
+ await dependencies.recordActivity(tx, workspaceId, FORM_ACTOR, {
372
+ targetType: 'opportunity',
373
+ targetId: id,
374
+ kind: 'created',
375
+ ...describeCreationVia('Opportunity', form.name),
376
+ });
377
+ emit('opportunities.opportunity.created', { type: 'opportunity', id }, {});
378
+ return id;
379
+ }
380
+ /**
381
+ * Creates the Partnership, when the form makes them and a company was
382
+ * resolved. `partnerships.company_id` is `NOT NULL`, matching Deal.
383
+ */
384
+ async function createPartnership(tx, emit, workspaceId, form, intent, company, personId) {
385
+ const id = dependencies.createId('partnership');
386
+ const owner = form.partnershipOwnerId === null
387
+ ? await workspaceRepository.findDefaultMember(tx, workspaceId)
388
+ : { id: form.partnershipOwnerId };
389
+ const nextTouchpoint = expectedCloseFrom(dependencies.now(), DEAL_CLOSE_HORIZON_DAYS);
390
+ await partnershipRepository.insertPartnership(tx, {
391
+ id,
392
+ workspaceId,
393
+ name: intent.partnershipName ??
394
+ expandNameTemplate(form.partnershipNameTemplate ?? DEFAULT_DEAL_NAME_TEMPLATE, {
395
+ companyName: company.name,
396
+ personName: intent.personName,
397
+ }),
398
+ companyId: company.id,
399
+ stageId: await openingStageId(tx, workspaceId, 'partnership', form.partnershipStageId),
400
+ kind: form.partnershipKind ?? '',
401
+ nextTouchpoint,
402
+ ownerId: owner?.id ?? null,
403
+ goals: '',
404
+ successLooksLike: '',
405
+ });
406
+ await personLinks.linkPeople(tx, dependencies.createId, workspaceId, { targetType: 'partnership', targetId: id }, [personId]);
407
+ await dependencies.recordActivity(tx, workspaceId, FORM_ACTOR, {
408
+ targetType: 'partnership',
409
+ targetId: id,
410
+ kind: 'created',
411
+ ...describeCreationVia('Partnership', form.name),
412
+ });
413
+ emit('partnerships.partnership.created', { type: 'partnership', id }, {});
414
+ return id;
415
+ }
416
+ /**
417
+ * Creates the Enquiry, when the form makes them.
418
+ *
419
+ * `enquiries.company_id` is nullable, so a submit that resolved no company
420
+ * still creates the enquiry. Enquiries have no `kind`; the form's optional
421
+ * `enquirySource` is written to the enquiry's `source` column, or empty when
422
+ * unset — an unclassified source reads as unclassified.
423
+ */
424
+ async function createEnquiry(tx, emit, workspaceId, form, intent, company, personId) {
425
+ const id = dependencies.createId('enquiry');
426
+ const owner = form.enquiryOwnerId === null
427
+ ? await workspaceRepository.findDefaultMember(tx, workspaceId)
428
+ : { id: form.enquiryOwnerId };
429
+ await enquiryRepository.insertEnquiry(tx, {
430
+ id,
431
+ workspaceId,
432
+ name: intent.enquiryName ??
433
+ expandNameTemplate(form.enquiryNameTemplate ?? DEFAULT_DEAL_NAME_TEMPLATE, {
434
+ companyName: company?.name ?? '',
435
+ personName: intent.personName,
436
+ }),
437
+ source: form.enquirySource ?? '',
438
+ stageId: await openingStageId(tx, workspaceId, 'enquiry', form.enquiryStageId),
439
+ companyId: company?.id ?? null,
440
+ ownerId: owner?.id ?? null,
441
+ convertedDealId: null,
442
+ });
443
+ await personLinks.linkPeople(tx, dependencies.createId, workspaceId, { targetType: 'enquiry', targetId: id }, [personId]);
444
+ await dependencies.recordActivity(tx, workspaceId, FORM_ACTOR, {
445
+ targetType: 'enquiry',
446
+ targetId: id,
447
+ kind: 'created',
448
+ ...describeCreationVia('Enquiry', form.name),
449
+ });
450
+ emit('enquiries.enquiry.created', { type: 'enquiry', id }, {});
276
451
  return id;
277
452
  }
278
453
  /**
@@ -310,21 +485,217 @@ export function createFormSubmitService(dependencies) {
310
485
  }
311
486
  return intent;
312
487
  }
488
+ /**
489
+ * The purposes any grants name, keyed by id, so the submit transaction
490
+ * knows the slug and label without a per-grant round trip.
491
+ */
492
+ async function loadPurposesForGrants(db, workspaceId, grants) {
493
+ if (grants.length === 0)
494
+ return new Map();
495
+ const ids = Array.from(new Set(grants.map((grant) => grant.purposeId)));
496
+ const rows = await consentPurposesRepository.listPurposesByIds(db, workspaceId, ids);
497
+ return new Map(rows.map((row) => [row.id, { slug: row.slug, label: row.label }]));
498
+ }
499
+ /**
500
+ * Writes each ticked grant as a `person_consents` row and appends an
501
+ * Activity to the person carrying the verbatim statement. A grant whose
502
+ * purpose has since been removed is silently skipped — the form's own
503
+ * consent field would have been left dangling anyway, and the submit
504
+ * cannot know that from the answer alone.
505
+ */
506
+ async function applyFormConsentGrants(tx, workspaceId, formId, formName, personId, grants, purposes, deps) {
507
+ if (grants.length === 0)
508
+ return;
509
+ const now = deps.now();
510
+ const source = `form:${formId}`;
511
+ for (const grant of grants) {
512
+ const purpose = purposes.get(grant.purposeId);
513
+ if (purpose === undefined)
514
+ continue;
515
+ await upsertPersonConsent(tx, workspaceId, personId, grant.purposeId, purpose.slug, purpose.label, 'granted', source, now);
516
+ // The exact text the visitor ticked — the field's per-purpose override
517
+ // when set, else the workspace purpose's label. Recorded as the
518
+ // Activity detail so the timeline shows what they actually saw.
519
+ const ticked = grant.customLabel.length > 0 ? grant.customLabel : purpose.label;
520
+ const detail = grant.statement.length > 0 ? `${grant.statement} — ${ticked}` : ticked;
521
+ await deps.recordActivity(tx, workspaceId, FORM_ACTOR, {
522
+ targetType: 'person',
523
+ targetId: personId,
524
+ kind: 'updated',
525
+ action: `granted ${purpose.label} consent via ${formName}`,
526
+ detail,
527
+ });
528
+ }
529
+ }
313
530
  return {
314
531
  async submit(publicKey, answers) {
315
532
  const form = await requireOpenForm(publicKey);
316
533
  const { workspaceId } = form;
317
534
  const fields = await repository.listFields(dependencies.db, form.id);
318
535
  const intent = readAnswers(fields, answers);
536
+ const consentGrants = readConsentGrants(fields, answers);
537
+ const [formListRows, attachTargets, consentPurposesForGrants] = await Promise.all([
538
+ repository.listFormLists(dependencies.db, form.id),
539
+ repository.listAttachTargets(dependencies.db, form.id),
540
+ loadPurposesForGrants(dependencies.db, workspaceId, consentGrants),
541
+ ]);
319
542
  return dependencies.transaction(async ({ tx, events }) => {
543
+ // Core capture: atomic. A failure here fails the submit; every
544
+ // post-action below runs under its own savepoint and logs.
320
545
  const person = await upsertPerson(tx, workspaceId, intent);
321
546
  const company = await upsertCompany(tx, workspaceId, intent);
322
547
  const position = company === undefined || intent.positionTitle === undefined
323
548
  ? undefined
324
549
  : await upsertPosition(tx, workspaceId, person.record.id, company.record.id, intent.positionTitle);
325
- const dealId = form.createDeal && company !== undefined
326
- ? await createDeal(tx, workspaceId, form, intent, company.record, person.record.id)
550
+ // Consent grants (from ticked `consent` fields) are core capture, not
551
+ // post-actions: they commit with the person, and an Activity records
552
+ // the exact statement text as it was shown to the visitor.
553
+ await applyFormConsentGrants(tx, workspaceId, form.id, form.name, person.record.id, consentGrants, consentPurposesForGrants, dependencies);
554
+ const actionLog = [];
555
+ // --- Create triggers ---
556
+ const dealId = form.createDeal
557
+ ? ((await runAction(tx, events, actionLog, 'create_deal', async (inner, emit) => {
558
+ if (company === undefined) {
559
+ return { status: 'skipped', detail: 'no company resolved' };
560
+ }
561
+ const id = await createDeal(inner, emit, workspaceId, form, intent, company.record, person.record.id);
562
+ return { status: 'ok', detail: id, value: id };
563
+ })) ?? null)
564
+ : null;
565
+ const opportunityId = form.createOpportunity
566
+ ? ((await runAction(tx, events, actionLog, 'create_opportunity', async (inner, emit) => {
567
+ const id = await createOpportunity(inner, emit, workspaceId, form, intent, company?.record, person.record.id);
568
+ return { status: 'ok', detail: id, value: id };
569
+ })) ?? null)
327
570
  : null;
571
+ const partnershipId = form.createPartnership
572
+ ? ((await runAction(tx, events, actionLog, 'create_partnership', async (inner, emit) => {
573
+ if (company === undefined) {
574
+ return { status: 'skipped', detail: 'no company resolved' };
575
+ }
576
+ const id = await createPartnership(inner, emit, workspaceId, form, intent, company.record, person.record.id);
577
+ return { status: 'ok', detail: id, value: id };
578
+ })) ?? null)
579
+ : null;
580
+ const enquiryId = form.createEnquiry
581
+ ? ((await runAction(tx, events, actionLog, 'create_enquiry', async (inner, emit) => {
582
+ const id = await createEnquiry(inner, emit, workspaceId, form, intent, company?.record, person.record.id);
583
+ return { status: 'ok', detail: id, value: id };
584
+ })) ?? null)
585
+ : null;
586
+ // --- Tag merges ---
587
+ if (form.personTags.length > 0) {
588
+ await runAction(tx, events, actionLog, 'tag_person', async (inner, emit) => {
589
+ const merged = mergeTags(person.record.tags, form.personTags);
590
+ if (!merged.changed) {
591
+ return { status: 'ok', detail: 'no new tags' };
592
+ }
593
+ const now = dependencies.now();
594
+ await peopleRepository.updatePerson(inner, workspaceId, person.record.id, {
595
+ tags: [...merged.next],
596
+ updatedAt: now,
597
+ });
598
+ emit('people.person.updated', { type: 'person', id: person.record.id }, { changed: ['tags'] });
599
+ return { status: 'ok', detail: `merged ${String(merged.next.length - person.record.tags.length)}` };
600
+ });
601
+ }
602
+ if (form.companyTags.length > 0) {
603
+ await runAction(tx, events, actionLog, 'tag_company', async (inner, emit) => {
604
+ if (company === undefined) {
605
+ return { status: 'skipped', detail: 'no company resolved' };
606
+ }
607
+ const merged = mergeTags(company.record.tags, form.companyTags);
608
+ if (!merged.changed) {
609
+ return { status: 'ok', detail: 'no new tags' };
610
+ }
611
+ const now = dependencies.now();
612
+ await companyRepository.updateCompany(inner, workspaceId, company.record.id, {
613
+ tags: [...merged.next],
614
+ updatedAt: now,
615
+ });
616
+ emit('companies.company.updated', { type: 'company', id: company.record.id }, { changed: ['tags'] });
617
+ return { status: 'ok', detail: `merged ${String(merged.next.length - company.record.tags.length)}` };
618
+ });
619
+ }
620
+ // --- List memberships ---
621
+ // Every purpose named by a person list on this form, so consent
622
+ // capture below needs no per-row round trip.
623
+ const listConsentPurposeIds = Array.from(new Set(formListRows
624
+ .map((row) => row.consentPurposeId)
625
+ .filter((id) => id !== null)));
626
+ const listConsentPurposes = listConsentPurposeIds.length === 0
627
+ ? new Map()
628
+ : new Map((await consentPurposesRepository.listPurposesByIds(tx, workspaceId, listConsentPurposeIds)).map((row) => [row.id, { slug: row.slug, label: row.label }]));
629
+ for (const row of formListRows) {
630
+ const inserted = await runAction(tx, events, actionLog, `add_list:${row.listId}`, async (inner, emit) => {
631
+ const targetId = row.targetType === 'person'
632
+ ? person.record.id
633
+ : row.targetType === 'company' && company !== undefined
634
+ ? company.record.id
635
+ : undefined;
636
+ if (targetId === undefined) {
637
+ return { status: 'skipped', detail: 'no company resolved', value: false };
638
+ }
639
+ try {
640
+ await listsRepository.insertListMember(inner, {
641
+ id: dependencies.createId('listMember'),
642
+ workspaceId,
643
+ listId: row.listId,
644
+ targetType: row.targetType,
645
+ targetId,
646
+ addedAt: dependencies.now(),
647
+ });
648
+ }
649
+ catch (error) {
650
+ if (postgresErrorCode(error) === UNIQUE_VIOLATION) {
651
+ return { status: 'ok', detail: 'already a member', value: false };
652
+ }
653
+ throw error;
654
+ }
655
+ emit('lists.member.added', { type: row.targetType, id: targetId }, { listId: row.listId });
656
+ return { status: 'ok', detail: targetId, value: true };
657
+ });
658
+ // Consent capture rides with the add — only on person lists, only
659
+ // when the list carries a purpose, and only when we actually added
660
+ // (or the person was already on it, since a returning submitter
661
+ // did the same thing again). A record already on the list has
662
+ // already been consented for its purpose; the upsert reflects
663
+ // that a fresh submit is fresh evidence.
664
+ if (row.targetType === 'person' &&
665
+ row.consentPurposeId !== null &&
666
+ inserted !== null) {
667
+ const purpose = listConsentPurposes.get(row.consentPurposeId);
668
+ if (purpose !== undefined) {
669
+ await runAction(tx, events, actionLog, `consent:${row.listId}`, async (inner) => {
670
+ await upsertPersonConsent(inner, workspaceId, person.record.id, row.consentPurposeId, purpose.slug, purpose.label, 'granted', `list:${row.listId}`, dependencies.now());
671
+ await dependencies.recordActivity(inner, workspaceId, FORM_ACTOR, {
672
+ targetType: 'person',
673
+ targetId: person.record.id,
674
+ kind: 'updated',
675
+ action: `granted ${purpose.label} consent via ${form.name}`,
676
+ detail: `Added to list membership`,
677
+ });
678
+ return { status: 'ok', detail: purpose.slug };
679
+ });
680
+ }
681
+ }
682
+ }
683
+ // --- Attach the submitter to pre-existing pipeline records ---
684
+ for (const target of attachTargets) {
685
+ await runAction(tx, events, actionLog, `attach:${target.targetType}:${target.targetId}`, async (inner) => {
686
+ // Racing a target delete would fail the FK-less insert with the
687
+ // same effect as an existence check: log an error, continue.
688
+ if (!(await targetExists(inner, workspaceId, target.targetType, target.targetId))) {
689
+ throw AppError.notFound(`${target.targetType} ${target.targetId} not found`);
690
+ }
691
+ const inserted = await personLinks.linkPersonIfAbsent(inner, dependencies.createId, workspaceId, target, person.record.id);
692
+ return {
693
+ status: 'ok',
694
+ detail: inserted ? 'linked' : 'already linked',
695
+ };
696
+ });
697
+ }
698
+ // --- Persist submission + core activity + record events ---
328
699
  const submission = await repository.insertSubmission(tx, {
329
700
  id: dependencies.createId('formSubmission'),
330
701
  workspaceId,
@@ -334,7 +705,11 @@ export function createFormSubmitService(dependencies) {
334
705
  companyId: company?.record.id ?? null,
335
706
  positionId: position?.record.id ?? null,
336
707
  dealId,
708
+ opportunityId,
709
+ partnershipId,
710
+ enquiryId,
337
711
  submittedAt: dependencies.now(),
712
+ actionLog,
338
713
  });
339
714
  await dependencies.recordActivity(tx, workspaceId, FORM_ACTOR, {
340
715
  targetType: 'person',
@@ -342,16 +717,15 @@ export function createFormSubmitService(dependencies) {
342
717
  kind: 'created',
343
718
  ...describeFormSubmission(form.name, describeAnswers(fields, answers)),
344
719
  });
345
- if (dealId !== null) {
346
- await dependencies.recordActivity(tx, workspaceId, FORM_ACTOR, {
347
- targetType: 'deal',
348
- targetId: dealId,
349
- kind: 'created',
350
- ...describeCreationVia('Deal', form.name),
351
- });
352
- }
353
- emitRecordEvents(events, workspaceId, { person, company, position, dealId });
354
- events.emit('forms.submission.submitted', { type: 'submission', id: submission.id }, { formId: form.id, submissionId: submission.id });
720
+ emitRecordEvents(events, workspaceId, { person, company, position });
721
+ events.emit('forms.submission.submitted', { type: 'submission', id: submission.id }, {
722
+ formId: form.id,
723
+ submissionId: submission.id,
724
+ opportunityId,
725
+ partnershipId,
726
+ enquiryId,
727
+ actions: actionLog.map((entry) => ({ action: entry.action, status: entry.status })),
728
+ });
355
729
  return {
356
730
  submissionId: submission.id,
357
731
  formId: form.id,
@@ -359,8 +733,12 @@ export function createFormSubmitService(dependencies) {
359
733
  companyId: company?.record.id ?? null,
360
734
  positionId: position?.record.id ?? null,
361
735
  dealId,
736
+ opportunityId,
737
+ partnershipId,
738
+ enquiryId,
362
739
  submittedAt: submission.submittedAt,
363
740
  thankYouMessage: form.thankYouMessage,
741
+ actionLog,
364
742
  };
365
743
  }, { workspaceId });
366
744
  },