@kelpie/server 0.10.0 → 0.11.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 (439) hide show
  1. package/dist/app.d.ts.map +1 -1
  2. package/dist/app.js +2 -0
  3. package/dist/app.js.map +1 -1
  4. package/dist/lib/actor.d.ts +3 -1
  5. package/dist/lib/actor.d.ts.map +1 -1
  6. package/dist/lib/actor.js.map +1 -1
  7. package/dist/lib/apiKeyScopes.d.ts +8 -0
  8. package/dist/lib/apiKeyScopes.d.ts.map +1 -0
  9. package/dist/lib/apiKeyScopes.js +166 -0
  10. package/dist/lib/apiKeyScopes.js.map +1 -0
  11. package/dist/modules/activities/repository.d.ts +2 -0
  12. package/dist/modules/activities/repository.d.ts.map +1 -1
  13. package/dist/modules/activities/repository.js +9 -0
  14. package/dist/modules/activities/repository.js.map +1 -1
  15. package/dist/modules/agent-tasks/repository.d.ts +2 -0
  16. package/dist/modules/agent-tasks/repository.d.ts.map +1 -1
  17. package/dist/modules/agent-tasks/repository.js +9 -0
  18. package/dist/modules/agent-tasks/repository.js.map +1 -1
  19. package/dist/modules/api-keys/routes.d.ts.map +1 -1
  20. package/dist/modules/api-keys/routes.js +4 -1
  21. package/dist/modules/api-keys/routes.js.map +1 -1
  22. package/dist/modules/api-keys/schema.d.ts +43 -0
  23. package/dist/modules/api-keys/schema.d.ts.map +1 -1
  24. package/dist/modules/api-keys/schema.js +2 -0
  25. package/dist/modules/api-keys/schema.js.map +1 -1
  26. package/dist/modules/api-keys/scopeMiddleware.d.ts +8 -0
  27. package/dist/modules/api-keys/scopeMiddleware.d.ts.map +1 -0
  28. package/dist/modules/api-keys/scopeMiddleware.js +21 -0
  29. package/dist/modules/api-keys/scopeMiddleware.js.map +1 -0
  30. package/dist/modules/api-keys/service.d.ts +3 -1
  31. package/dist/modules/api-keys/service.d.ts.map +1 -1
  32. package/dist/modules/api-keys/service.js +26 -1
  33. package/dist/modules/api-keys/service.js.map +1 -1
  34. package/dist/modules/auth/credentials.d.ts.map +1 -1
  35. package/dist/modules/auth/credentials.js +2 -0
  36. package/dist/modules/auth/credentials.js.map +1 -1
  37. package/dist/modules/consent-purposes/index.d.ts +1 -1
  38. package/dist/modules/consent-purposes/index.js +1 -1
  39. package/dist/modules/consent-purposes/schema.d.ts +3 -3
  40. package/dist/modules/consent-purposes/schema.js +3 -3
  41. package/dist/modules/consent-purposes/service.d.ts +1 -1
  42. package/dist/modules/consent-purposes/service.d.ts.map +1 -1
  43. package/dist/modules/consent-purposes/service.js +7 -16
  44. package/dist/modules/consent-purposes/service.js.map +1 -1
  45. package/dist/modules/consent-purposes/starters.d.ts +1 -1
  46. package/dist/modules/consent-purposes/tools.js +1 -1
  47. package/dist/modules/consent-purposes/tools.js.map +1 -1
  48. package/dist/modules/conversions/clearPointers.d.ts +10 -0
  49. package/dist/modules/conversions/clearPointers.d.ts.map +1 -0
  50. package/dist/modules/conversions/clearPointers.js +40 -0
  51. package/dist/modules/conversions/clearPointers.js.map +1 -0
  52. package/dist/modules/conversions/factory.d.ts +5 -0
  53. package/dist/modules/conversions/factory.d.ts.map +1 -0
  54. package/dist/modules/conversions/factory.js +18 -0
  55. package/dist/modules/conversions/factory.js.map +1 -0
  56. package/dist/modules/conversions/fieldMap.d.ts +55 -0
  57. package/dist/modules/conversions/fieldMap.d.ts.map +1 -0
  58. package/dist/modules/conversions/fieldMap.js +398 -0
  59. package/dist/modules/conversions/fieldMap.js.map +1 -0
  60. package/dist/modules/conversions/index.d.ts +7 -0
  61. package/dist/modules/conversions/index.d.ts.map +1 -0
  62. package/dist/modules/conversions/index.js +6 -0
  63. package/dist/modules/conversions/index.js.map +1 -0
  64. package/dist/modules/conversions/mcp.d.ts +7 -0
  65. package/dist/modules/conversions/mcp.d.ts.map +1 -0
  66. package/dist/modules/conversions/mcp.js +47 -0
  67. package/dist/modules/conversions/mcp.js.map +1 -0
  68. package/dist/modules/conversions/repoint.d.ts +19 -0
  69. package/dist/modules/conversions/repoint.d.ts.map +1 -0
  70. package/dist/modules/conversions/repoint.js +51 -0
  71. package/dist/modules/conversions/repoint.js.map +1 -0
  72. package/dist/modules/conversions/routes.d.ts +26 -0
  73. package/dist/modules/conversions/routes.d.ts.map +1 -0
  74. package/dist/modules/conversions/routes.js +23 -0
  75. package/dist/modules/conversions/routes.js.map +1 -0
  76. package/dist/modules/conversions/service.d.ts +28 -0
  77. package/dist/modules/conversions/service.d.ts.map +1 -0
  78. package/dist/modules/conversions/service.js +170 -0
  79. package/dist/modules/conversions/service.js.map +1 -0
  80. package/dist/modules/conversions/wire.d.ts +4 -0
  81. package/dist/modules/conversions/wire.d.ts.map +1 -0
  82. package/dist/modules/conversions/wire.js +28 -0
  83. package/dist/modules/conversions/wire.js.map +1 -0
  84. package/dist/modules/deals/events.d.ts +9 -0
  85. package/dist/modules/deals/events.d.ts.map +1 -1
  86. package/dist/modules/deals/events.js +4 -0
  87. package/dist/modules/deals/events.js.map +1 -1
  88. package/dist/modules/deals/index.d.ts.map +1 -1
  89. package/dist/modules/deals/index.js +4 -2
  90. package/dist/modules/deals/index.js.map +1 -1
  91. package/dist/modules/deals/routes.d.ts +2 -0
  92. package/dist/modules/deals/routes.d.ts.map +1 -1
  93. package/dist/modules/deals/routes.js +8 -1
  94. package/dist/modules/deals/routes.js.map +1 -1
  95. package/dist/modules/deals/schema.d.ts +34 -0
  96. package/dist/modules/deals/schema.d.ts.map +1 -1
  97. package/dist/modules/deals/schema.js +7 -2
  98. package/dist/modules/deals/schema.js.map +1 -1
  99. package/dist/modules/deals/service.d.ts.map +1 -1
  100. package/dist/modules/deals/service.js +2 -0
  101. package/dist/modules/deals/service.js.map +1 -1
  102. package/dist/modules/deals/tools.d.ts +2 -1
  103. package/dist/modules/deals/tools.d.ts.map +1 -1
  104. package/dist/modules/deals/tools.js +3 -1
  105. package/dist/modules/deals/tools.js.map +1 -1
  106. package/dist/modules/decisions/repository.d.ts +2 -1
  107. package/dist/modules/decisions/repository.d.ts.map +1 -1
  108. package/dist/modules/decisions/repository.js +9 -1
  109. package/dist/modules/decisions/repository.js.map +1 -1
  110. package/dist/modules/enquiries/events.d.ts +6 -2
  111. package/dist/modules/enquiries/events.d.ts.map +1 -1
  112. package/dist/modules/enquiries/events.js +5 -1
  113. package/dist/modules/enquiries/events.js.map +1 -1
  114. package/dist/modules/enquiries/index.d.ts.map +1 -1
  115. package/dist/modules/enquiries/index.js +4 -2
  116. package/dist/modules/enquiries/index.js.map +1 -1
  117. package/dist/modules/enquiries/routes.d.ts +2 -0
  118. package/dist/modules/enquiries/routes.d.ts.map +1 -1
  119. package/dist/modules/enquiries/routes.js +9 -9
  120. package/dist/modules/enquiries/routes.js.map +1 -1
  121. package/dist/modules/enquiries/schema.d.ts +36 -1
  122. package/dist/modules/enquiries/schema.d.ts.map +1 -1
  123. package/dist/modules/enquiries/schema.js +9 -3
  124. package/dist/modules/enquiries/schema.js.map +1 -1
  125. package/dist/modules/enquiries/service.d.ts +0 -8
  126. package/dist/modules/enquiries/service.d.ts.map +1 -1
  127. package/dist/modules/enquiries/service.js +3 -95
  128. package/dist/modules/enquiries/service.js.map +1 -1
  129. package/dist/modules/enquiries/tools.d.ts +2 -1
  130. package/dist/modules/enquiries/tools.d.ts.map +1 -1
  131. package/dist/modules/enquiries/tools.js +4 -16
  132. package/dist/modules/enquiries/tools.js.map +1 -1
  133. package/dist/modules/forms/applyMappedFields.d.ts +20 -0
  134. package/dist/modules/forms/applyMappedFields.d.ts.map +1 -0
  135. package/dist/modules/forms/applyMappedFields.js +169 -0
  136. package/dist/modules/forms/applyMappedFields.js.map +1 -0
  137. package/dist/modules/forms/applySubmissionFields.d.ts +18 -0
  138. package/dist/modules/forms/applySubmissionFields.d.ts.map +1 -0
  139. package/dist/modules/forms/applySubmissionFields.js +230 -0
  140. package/dist/modules/forms/applySubmissionFields.js.map +1 -0
  141. package/dist/modules/forms/fields.d.ts +7 -2
  142. package/dist/modules/forms/fields.d.ts.map +1 -1
  143. package/dist/modules/forms/fields.js +17 -6
  144. package/dist/modules/forms/fields.js.map +1 -1
  145. package/dist/modules/forms/mapping.d.ts +8 -2
  146. package/dist/modules/forms/mapping.d.ts.map +1 -1
  147. package/dist/modules/forms/mapping.js +11 -0
  148. package/dist/modules/forms/mapping.js.map +1 -1
  149. package/dist/modules/forms/repository.d.ts +0 -5
  150. package/dist/modules/forms/repository.d.ts.map +1 -1
  151. package/dist/modules/forms/repository.js +0 -2
  152. package/dist/modules/forms/repository.js.map +1 -1
  153. package/dist/modules/forms/routes.d.ts +2 -30
  154. package/dist/modules/forms/routes.d.ts.map +1 -1
  155. package/dist/modules/forms/routes.js +2 -2
  156. package/dist/modules/forms/routes.js.map +1 -1
  157. package/dist/modules/forms/schema.d.ts.map +1 -1
  158. package/dist/modules/forms/schema.js +1 -2
  159. package/dist/modules/forms/schema.js.map +1 -1
  160. package/dist/modules/forms/service.d.ts.map +1 -1
  161. package/dist/modules/forms/service.js +18 -3
  162. package/dist/modules/forms/service.js.map +1 -1
  163. package/dist/modules/forms/starters.d.ts +31 -0
  164. package/dist/modules/forms/starters.d.ts.map +1 -0
  165. package/dist/modules/forms/starters.js +94 -0
  166. package/dist/modules/forms/starters.js.map +1 -0
  167. package/dist/modules/forms/submission.d.ts +1 -0
  168. package/dist/modules/forms/submission.d.ts.map +1 -1
  169. package/dist/modules/forms/submission.js +58 -37
  170. package/dist/modules/forms/submission.js.map +1 -1
  171. package/dist/modules/import-export/customFieldCsv.d.ts +9 -0
  172. package/dist/modules/import-export/customFieldCsv.d.ts.map +1 -0
  173. package/dist/modules/import-export/customFieldCsv.js +39 -0
  174. package/dist/modules/import-export/customFieldCsv.js.map +1 -0
  175. package/dist/modules/import-export/customFieldImport.d.ts +19 -0
  176. package/dist/modules/import-export/customFieldImport.d.ts.map +1 -0
  177. package/dist/modules/import-export/customFieldImport.js +76 -0
  178. package/dist/modules/import-export/customFieldImport.js.map +1 -0
  179. package/dist/modules/import-export/drafts.d.ts +57 -3
  180. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  181. package/dist/modules/import-export/drafts.js +65 -3
  182. package/dist/modules/import-export/drafts.js.map +1 -1
  183. package/dist/modules/import-export/exportRows.d.ts +15 -13
  184. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  185. package/dist/modules/import-export/exportRows.js +99 -26
  186. package/dist/modules/import-export/exportRows.js.map +1 -1
  187. package/dist/modules/import-export/plan.d.ts +42 -11
  188. package/dist/modules/import-export/plan.d.ts.map +1 -1
  189. package/dist/modules/import-export/plan.js +198 -56
  190. package/dist/modules/import-export/plan.js.map +1 -1
  191. package/dist/modules/import-export/repository.d.ts +58 -2
  192. package/dist/modules/import-export/repository.d.ts.map +1 -1
  193. package/dist/modules/import-export/repository.js +201 -12
  194. package/dist/modules/import-export/repository.js.map +1 -1
  195. package/dist/modules/import-export/routes.d.ts.map +1 -1
  196. package/dist/modules/import-export/routes.js +5 -5
  197. package/dist/modules/import-export/routes.js.map +1 -1
  198. package/dist/modules/import-export/service.d.ts +8 -3
  199. package/dist/modules/import-export/service.d.ts.map +1 -1
  200. package/dist/modules/import-export/service.js +133 -40
  201. package/dist/modules/import-export/service.js.map +1 -1
  202. package/dist/modules/import-export/streams.d.ts +2 -2
  203. package/dist/modules/import-export/streams.d.ts.map +1 -1
  204. package/dist/modules/import-export/streams.js +50 -9
  205. package/dist/modules/import-export/streams.js.map +1 -1
  206. package/dist/modules/import-export/tools.d.ts.map +1 -1
  207. package/dist/modules/import-export/tools.js +13 -7
  208. package/dist/modules/import-export/tools.js.map +1 -1
  209. package/dist/modules/import-export/validation.d.ts +5 -1
  210. package/dist/modules/import-export/validation.d.ts.map +1 -1
  211. package/dist/modules/import-export/validation.js +89 -2
  212. package/dist/modules/import-export/validation.js.map +1 -1
  213. package/dist/modules/import-export/writes.d.ts +2 -1
  214. package/dist/modules/import-export/writes.d.ts.map +1 -1
  215. package/dist/modules/import-export/writes.js +358 -25
  216. package/dist/modules/import-export/writes.js.map +1 -1
  217. package/dist/modules/lists/repository.d.ts +0 -1
  218. package/dist/modules/lists/repository.d.ts.map +1 -1
  219. package/dist/modules/lists/repository.js +0 -1
  220. package/dist/modules/lists/repository.js.map +1 -1
  221. package/dist/modules/lists/routes.d.ts +0 -2
  222. package/dist/modules/lists/routes.d.ts.map +1 -1
  223. package/dist/modules/lists/routes.js +0 -8
  224. package/dist/modules/lists/routes.js.map +1 -1
  225. package/dist/modules/lists/schema.d.ts +0 -17
  226. package/dist/modules/lists/schema.d.ts.map +1 -1
  227. package/dist/modules/lists/schema.js +0 -10
  228. package/dist/modules/lists/schema.js.map +1 -1
  229. package/dist/modules/lists/service.d.ts +2 -14
  230. package/dist/modules/lists/service.d.ts.map +1 -1
  231. package/dist/modules/lists/service.js +7 -53
  232. package/dist/modules/lists/service.js.map +1 -1
  233. package/dist/modules/lists/starters.d.ts +12 -0
  234. package/dist/modules/lists/starters.d.ts.map +1 -0
  235. package/dist/modules/lists/starters.js +4 -0
  236. package/dist/modules/lists/starters.js.map +1 -0
  237. package/dist/modules/mcp/protocol.d.ts.map +1 -1
  238. package/dist/modules/mcp/protocol.js +13 -0
  239. package/dist/modules/mcp/protocol.js.map +1 -1
  240. package/dist/modules/notes/repository.d.ts +2 -0
  241. package/dist/modules/notes/repository.d.ts.map +1 -1
  242. package/dist/modules/notes/repository.js +9 -0
  243. package/dist/modules/notes/repository.js.map +1 -1
  244. package/dist/modules/opportunities/events.d.ts +9 -0
  245. package/dist/modules/opportunities/events.d.ts.map +1 -1
  246. package/dist/modules/opportunities/events.js +4 -0
  247. package/dist/modules/opportunities/events.js.map +1 -1
  248. package/dist/modules/opportunities/index.d.ts.map +1 -1
  249. package/dist/modules/opportunities/index.js +4 -2
  250. package/dist/modules/opportunities/index.js.map +1 -1
  251. package/dist/modules/opportunities/routes.d.ts +2 -0
  252. package/dist/modules/opportunities/routes.d.ts.map +1 -1
  253. package/dist/modules/opportunities/routes.js +8 -1
  254. package/dist/modules/opportunities/routes.js.map +1 -1
  255. package/dist/modules/opportunities/schema.d.ts +34 -0
  256. package/dist/modules/opportunities/schema.d.ts.map +1 -1
  257. package/dist/modules/opportunities/schema.js +7 -2
  258. package/dist/modules/opportunities/schema.js.map +1 -1
  259. package/dist/modules/opportunities/service.d.ts.map +1 -1
  260. package/dist/modules/opportunities/service.js +2 -0
  261. package/dist/modules/opportunities/service.js.map +1 -1
  262. package/dist/modules/opportunities/tools.d.ts +2 -1
  263. package/dist/modules/opportunities/tools.d.ts.map +1 -1
  264. package/dist/modules/opportunities/tools.js +3 -1
  265. package/dist/modules/opportunities/tools.js.map +1 -1
  266. package/dist/modules/partnerships/events.d.ts +9 -0
  267. package/dist/modules/partnerships/events.d.ts.map +1 -1
  268. package/dist/modules/partnerships/events.js +4 -0
  269. package/dist/modules/partnerships/events.js.map +1 -1
  270. package/dist/modules/partnerships/index.d.ts.map +1 -1
  271. package/dist/modules/partnerships/index.js +4 -2
  272. package/dist/modules/partnerships/index.js.map +1 -1
  273. package/dist/modules/partnerships/routes.d.ts +2 -0
  274. package/dist/modules/partnerships/routes.d.ts.map +1 -1
  275. package/dist/modules/partnerships/routes.js +8 -1
  276. package/dist/modules/partnerships/routes.js.map +1 -1
  277. package/dist/modules/partnerships/schema.d.ts +34 -0
  278. package/dist/modules/partnerships/schema.d.ts.map +1 -1
  279. package/dist/modules/partnerships/schema.js +7 -2
  280. package/dist/modules/partnerships/schema.js.map +1 -1
  281. package/dist/modules/partnerships/service.d.ts.map +1 -1
  282. package/dist/modules/partnerships/service.js +2 -0
  283. package/dist/modules/partnerships/service.js.map +1 -1
  284. package/dist/modules/partnerships/tools.d.ts +2 -1
  285. package/dist/modules/partnerships/tools.d.ts.map +1 -1
  286. package/dist/modules/partnerships/tools.js +3 -1
  287. package/dist/modules/partnerships/tools.js.map +1 -1
  288. package/dist/modules/people/personConsentWrites.d.ts +1 -1
  289. package/dist/modules/people/schema.js +1 -1
  290. package/dist/modules/people/schema.js.map +1 -1
  291. package/dist/modules/plans/repository.d.ts +2 -0
  292. package/dist/modules/plans/repository.d.ts.map +1 -1
  293. package/dist/modules/plans/repository.js +9 -0
  294. package/dist/modules/plans/repository.js.map +1 -1
  295. package/dist/modules/raises/events.d.ts +9 -0
  296. package/dist/modules/raises/events.d.ts.map +1 -1
  297. package/dist/modules/raises/events.js +4 -0
  298. package/dist/modules/raises/events.js.map +1 -1
  299. package/dist/modules/raises/index.d.ts.map +1 -1
  300. package/dist/modules/raises/index.js +4 -2
  301. package/dist/modules/raises/index.js.map +1 -1
  302. package/dist/modules/raises/routes.d.ts +2 -0
  303. package/dist/modules/raises/routes.d.ts.map +1 -1
  304. package/dist/modules/raises/routes.js +8 -1
  305. package/dist/modules/raises/routes.js.map +1 -1
  306. package/dist/modules/raises/schema.d.ts +34 -0
  307. package/dist/modules/raises/schema.d.ts.map +1 -1
  308. package/dist/modules/raises/schema.js +7 -2
  309. package/dist/modules/raises/schema.js.map +1 -1
  310. package/dist/modules/raises/service.d.ts.map +1 -1
  311. package/dist/modules/raises/service.js +2 -0
  312. package/dist/modules/raises/service.js.map +1 -1
  313. package/dist/modules/raises/tools.d.ts +2 -1
  314. package/dist/modules/raises/tools.d.ts.map +1 -1
  315. package/dist/modules/raises/tools.js +3 -1
  316. package/dist/modules/raises/tools.js.map +1 -1
  317. package/dist/modules/workspace/routes.d.ts +0 -2
  318. package/dist/modules/workspace/routes.d.ts.map +1 -1
  319. package/dist/modules/workspace/routes.js +0 -6
  320. package/dist/modules/workspace/routes.js.map +1 -1
  321. package/dist/modules/workspace/schema.d.ts +0 -34
  322. package/dist/modules/workspace/schema.d.ts.map +1 -1
  323. package/dist/modules/workspace/schema.js +0 -2
  324. package/dist/modules/workspace/schema.js.map +1 -1
  325. package/dist/modules/workspace/seedStarterForms.d.ts +17 -0
  326. package/dist/modules/workspace/seedStarterForms.d.ts.map +1 -0
  327. package/dist/modules/workspace/seedStarterForms.js +71 -0
  328. package/dist/modules/workspace/seedStarterForms.js.map +1 -0
  329. package/dist/modules/workspace/service.d.ts +0 -4
  330. package/dist/modules/workspace/service.d.ts.map +1 -1
  331. package/dist/modules/workspace/service.js +20 -10
  332. package/dist/modules/workspace/service.js.map +1 -1
  333. package/dist/modules/workspace/tools.js +1 -1
  334. package/dist/modules/workspace/tools.js.map +1 -1
  335. package/dist/testing/fixtures.d.ts.map +1 -1
  336. package/dist/testing/fixtures.js +1 -0
  337. package/dist/testing/fixtures.js.map +1 -1
  338. package/migrations/0037_drop_lists_consent_purpose_id.sql +2 -0
  339. package/migrations/0038_smart_white_queen.sql +2 -0
  340. package/migrations/0039_form_map_to_open.sql +1 -0
  341. package/migrations/0040_pipeline_converted_to.sql +20 -0
  342. package/migrations/0041_api_key_scopes.sql +1 -0
  343. package/migrations/0042_drop_workspace_identity.sql +2 -0
  344. package/migrations/meta/0038_snapshot.json +6554 -0
  345. package/migrations/meta/_journal.json +42 -0
  346. package/package.json +2 -2
  347. package/src/app.ts +3 -0
  348. package/src/lib/actor.ts +3 -1
  349. package/src/lib/apiKeyScopes.ts +213 -0
  350. package/src/modules/activities/repository.ts +24 -0
  351. package/src/modules/agent-tasks/repository.ts +24 -0
  352. package/src/modules/api-keys/routes.ts +5 -0
  353. package/src/modules/api-keys/schema.ts +2 -0
  354. package/src/modules/api-keys/scopeMiddleware.ts +30 -0
  355. package/src/modules/api-keys/service.ts +36 -2
  356. package/src/modules/auth/credentials.ts +4 -0
  357. package/src/modules/consent-purposes/index.ts +1 -1
  358. package/src/modules/consent-purposes/schema.ts +3 -3
  359. package/src/modules/consent-purposes/service.ts +7 -16
  360. package/src/modules/consent-purposes/starters.ts +1 -1
  361. package/src/modules/consent-purposes/tools.ts +1 -1
  362. package/src/modules/conversions/clearPointers.ts +81 -0
  363. package/src/modules/conversions/factory.ts +20 -0
  364. package/src/modules/conversions/fieldMap.ts +548 -0
  365. package/src/modules/conversions/index.ts +6 -0
  366. package/src/modules/conversions/mcp.ts +71 -0
  367. package/src/modules/conversions/repoint.ts +146 -0
  368. package/src/modules/conversions/routes.ts +68 -0
  369. package/src/modules/conversions/service.ts +310 -0
  370. package/src/modules/conversions/wire.ts +42 -0
  371. package/src/modules/deals/events.ts +9 -0
  372. package/src/modules/deals/index.ts +4 -2
  373. package/src/modules/deals/routes.ts +11 -1
  374. package/src/modules/deals/schema.ts +10 -2
  375. package/src/modules/deals/service.ts +3 -0
  376. package/src/modules/deals/tools.ts +9 -1
  377. package/src/modules/decisions/repository.ts +23 -1
  378. package/src/modules/enquiries/events.ts +8 -2
  379. package/src/modules/enquiries/index.ts +4 -2
  380. package/src/modules/enquiries/routes.ts +11 -13
  381. package/src/modules/enquiries/schema.ts +12 -3
  382. package/src/modules/enquiries/service.ts +3 -150
  383. package/src/modules/enquiries/tools.ts +9 -18
  384. package/src/modules/forms/applyMappedFields.ts +248 -0
  385. package/src/modules/forms/applySubmissionFields.ts +435 -0
  386. package/src/modules/forms/fields.ts +31 -7
  387. package/src/modules/forms/mapping.ts +20 -3
  388. package/src/modules/forms/repository.ts +0 -7
  389. package/src/modules/forms/routes.ts +1 -2
  390. package/src/modules/forms/schema.ts +0 -2
  391. package/src/modules/forms/service.ts +31 -4
  392. package/src/modules/forms/starters.ts +129 -0
  393. package/src/modules/forms/submission.ts +135 -69
  394. package/src/modules/import-export/customFieldCsv.ts +55 -0
  395. package/src/modules/import-export/customFieldImport.ts +111 -0
  396. package/src/modules/import-export/drafts.ts +151 -3
  397. package/src/modules/import-export/exportRows.ts +222 -68
  398. package/src/modules/import-export/plan.ts +321 -67
  399. package/src/modules/import-export/repository.ts +356 -14
  400. package/src/modules/import-export/routes.ts +8 -8
  401. package/src/modules/import-export/service.ts +208 -45
  402. package/src/modules/import-export/streams.ts +95 -13
  403. package/src/modules/import-export/tools.ts +14 -6
  404. package/src/modules/import-export/validation.ts +128 -0
  405. package/src/modules/import-export/writes.ts +559 -27
  406. package/src/modules/lists/repository.ts +0 -2
  407. package/src/modules/lists/routes.ts +0 -8
  408. package/src/modules/lists/schema.ts +0 -10
  409. package/src/modules/lists/service.ts +9 -107
  410. package/src/modules/lists/starters.ts +16 -0
  411. package/src/modules/mcp/protocol.ts +18 -0
  412. package/src/modules/notes/repository.ts +24 -0
  413. package/src/modules/opportunities/events.ts +9 -0
  414. package/src/modules/opportunities/index.ts +4 -2
  415. package/src/modules/opportunities/routes.ts +11 -1
  416. package/src/modules/opportunities/schema.ts +10 -2
  417. package/src/modules/opportunities/service.ts +3 -0
  418. package/src/modules/opportunities/tools.ts +9 -1
  419. package/src/modules/partnerships/events.ts +9 -0
  420. package/src/modules/partnerships/index.ts +4 -2
  421. package/src/modules/partnerships/routes.ts +11 -1
  422. package/src/modules/partnerships/schema.ts +10 -2
  423. package/src/modules/partnerships/service.ts +3 -0
  424. package/src/modules/partnerships/tools.ts +9 -1
  425. package/src/modules/people/personConsentWrites.ts +1 -1
  426. package/src/modules/people/schema.ts +1 -1
  427. package/src/modules/plans/repository.ts +24 -0
  428. package/src/modules/raises/events.ts +9 -0
  429. package/src/modules/raises/index.ts +4 -2
  430. package/src/modules/raises/routes.ts +11 -1
  431. package/src/modules/raises/schema.ts +10 -2
  432. package/src/modules/raises/service.ts +3 -0
  433. package/src/modules/raises/tools.ts +9 -1
  434. package/src/modules/workspace/routes.ts +0 -6
  435. package/src/modules/workspace/schema.ts +0 -2
  436. package/src/modules/workspace/seedStarterForms.ts +98 -0
  437. package/src/modules/workspace/service.ts +23 -15
  438. package/src/modules/workspace/tools.ts +1 -1
  439. package/src/testing/fixtures.ts +1 -0
@@ -0,0 +1,248 @@
1
+ import {
2
+ FORM_STANDARD_MAP_FIELDS,
3
+ parseFormMapTarget,
4
+ resolveMapTargetEntry,
5
+ } from '@kelpie/schemas'
6
+ import type { CustomFieldDefinitionRef, FormMapObjectType, FormMapValueType } from '@kelpie/schemas'
7
+
8
+ import type { MappedAnswers } from './mapping.ts'
9
+ import { fillBlank, isConsentTicked, mergeTags } from './mapping.ts'
10
+
11
+ /** Targets handled explicitly by `readIntent` and the core upsert paths. */
12
+ export const INTENT_HANDLED_TARGETS: ReadonlySet<string> = new Set([
13
+ 'person.name',
14
+ 'person.first_name',
15
+ 'person.last_name',
16
+ 'person.email',
17
+ 'person.phones',
18
+ 'company.name',
19
+ 'company.domain',
20
+ 'position.title',
21
+ 'deal.name',
22
+ 'opportunity.name',
23
+ 'partnership.name',
24
+ 'enquiry.name',
25
+ 'person.consent',
26
+ 'submission',
27
+ ])
28
+
29
+ export interface ObjectMappedValues {
30
+ readonly standard: Readonly<Record<string, string>>
31
+ readonly custom: Readonly<Record<string, string>>
32
+ }
33
+
34
+ /** Groups mapped answers by object type, skipping intent-handled and special targets. */
35
+ export function valuesForObject(mapped: MappedAnswers, objectType: FormMapObjectType): ObjectMappedValues {
36
+ const standard: Record<string, string> = {}
37
+ const custom: Record<string, string> = {}
38
+
39
+ for (const [target, value] of Object.entries(mapped)) {
40
+ if (INTENT_HANDLED_TARGETS.has(target)) {
41
+ continue
42
+ }
43
+
44
+ const parsed = parseFormMapTarget(target)
45
+
46
+ if (parsed === undefined || parsed.objectType !== objectType) {
47
+ continue
48
+ }
49
+
50
+ if (parsed.isCustomField && parsed.customFieldKey !== undefined) {
51
+ custom[parsed.customFieldKey] = value
52
+ } else {
53
+ standard[parsed.fieldPath] = value
54
+ }
55
+ }
56
+
57
+ return { standard, custom }
58
+ }
59
+
60
+ function valueTypeForStandardField(
61
+ objectType: FormMapObjectType,
62
+ field: string,
63
+ ): FormMapValueType | undefined {
64
+ return FORM_STANDARD_MAP_FIELDS[objectType].find((entry) => entry.field === field)?.valueType
65
+ }
66
+
67
+ function parseStringArray(raw: string): readonly string[] {
68
+ return raw
69
+ .split(',')
70
+ .map((part) => part.trim())
71
+ .filter((part) => part.length > 0)
72
+ }
73
+
74
+ function parseBoolean(raw: string): boolean | undefined {
75
+ return isConsentTicked(raw) ? true : raw.trim().toLowerCase() === 'false' ? false : undefined
76
+ }
77
+
78
+ function parseNumber(raw: string): number | undefined {
79
+ const trimmed = raw.trim()
80
+
81
+ if (trimmed.length === 0) {
82
+ return undefined
83
+ }
84
+
85
+ const parsed = Number(trimmed)
86
+
87
+ return Number.isFinite(parsed) ? parsed : undefined
88
+ }
89
+
90
+ /** Parses a form answer string into a value suitable for a standard field write. */
91
+ export function parseStandardAnswer(
92
+ objectType: FormMapObjectType,
93
+ field: string,
94
+ raw: string,
95
+ ): unknown {
96
+ const valueType = valueTypeForStandardField(objectType, field)
97
+
98
+ if (valueType === undefined) {
99
+ return raw
100
+ }
101
+
102
+ switch (valueType) {
103
+ case 'tags':
104
+ case 'string_array':
105
+ case 'phones':
106
+ return parseStringArray(raw)
107
+ case 'boolean':
108
+ return parseBoolean(raw)
109
+ case 'number':
110
+ return parseNumber(raw)
111
+ default:
112
+ return raw.trim()
113
+ }
114
+ }
115
+
116
+ function isBlankStored(value: unknown): boolean {
117
+ if (value === null || value === undefined) {
118
+ return true
119
+ }
120
+
121
+ if (typeof value === 'string') {
122
+ return value.trim().length === 0
123
+ }
124
+
125
+ if (Array.isArray(value)) {
126
+ return value.length === 0
127
+ }
128
+
129
+ return false
130
+ }
131
+
132
+ /** Applies fill-blank for one standard field onto a patch object keyed by repository column names. */
133
+ export function applyStandardFillBlank<T extends Record<string, unknown>>(
134
+ stored: T,
135
+ objectType: FormMapObjectType,
136
+ mapped: ObjectMappedValues,
137
+ columnForField: (field: string) => string | undefined,
138
+ ): Record<string, unknown> {
139
+ const patch: Record<string, unknown> = {}
140
+
141
+ for (const [field, raw] of Object.entries(mapped.standard)) {
142
+ const column = columnForField(field)
143
+
144
+ if (column === undefined) {
145
+ continue
146
+ }
147
+
148
+ const storedValue = stored[column as keyof T]
149
+
150
+ const parsed = parseStandardAnswer(objectType, field, raw)
151
+ const entry = resolveMapTargetEntry(`${objectType}.${field}`)
152
+
153
+ if (entry?.valueType === 'tags' && Array.isArray(parsed)) {
154
+ const merge = mergeTags(
155
+ Array.isArray(storedValue) ? (storedValue as readonly string[]) : [],
156
+ parsed,
157
+ )
158
+
159
+ if (merge.changed) {
160
+ patch[column] = merge.next
161
+ }
162
+
163
+ continue
164
+ }
165
+
166
+ if (Array.isArray(parsed)) {
167
+ if (!Array.isArray(storedValue) || storedValue.length === 0) {
168
+ patch[column] = parsed
169
+ }
170
+
171
+ continue
172
+ }
173
+
174
+ if (typeof parsed === 'boolean') {
175
+ if (storedValue === false && parsed === true) {
176
+ patch[column] = parsed
177
+ }
178
+
179
+ continue
180
+ }
181
+
182
+ if (typeof parsed === 'number') {
183
+ if (storedValue === null || storedValue === undefined) {
184
+ patch[column] = parsed
185
+ }
186
+
187
+ continue
188
+ }
189
+
190
+ const filled = fillBlank(
191
+ typeof storedValue === 'string' ? storedValue : storedValue === null ? null : String(storedValue),
192
+ typeof parsed === 'string' ? parsed : undefined,
193
+ )
194
+
195
+ if (filled !== undefined) {
196
+ patch[column] = filled
197
+ }
198
+ }
199
+
200
+ return patch
201
+ }
202
+
203
+ /** Keys in stored custom_fields that are blank and may be filled from a submit. */
204
+ export function customFieldsFillBlankPatch(
205
+ stored: Readonly<Record<string, unknown>>,
206
+ inbound: Readonly<Record<string, string>>,
207
+ ): Readonly<Record<string, string>> {
208
+ const patch: Record<string, string> = {}
209
+
210
+ for (const [key, raw] of Object.entries(inbound)) {
211
+ if (raw.trim().length === 0) {
212
+ continue
213
+ }
214
+
215
+ if (!isBlankStored(stored[key])) {
216
+ continue
217
+ }
218
+
219
+ patch[key] = raw.trim()
220
+ }
221
+
222
+ return patch
223
+ }
224
+
225
+ /** Parses inbound custom-field strings into wire values for validation. */
226
+ export function parseCustomFieldAnswer(
227
+ definition: CustomFieldDefinitionRef,
228
+ raw: string,
229
+ ): unknown {
230
+ switch (definition.type) {
231
+ case 'checkbox':
232
+ return isConsentTicked(raw)
233
+ case 'number': {
234
+ const parsed = parseNumber(raw)
235
+ return parsed ?? raw
236
+ }
237
+ case 'multi_select':
238
+ return parseStringArray(raw)
239
+ case 'currency':
240
+ return raw.trim()
241
+ default:
242
+ return raw.trim()
243
+ }
244
+ }
245
+
246
+ export function hasObjectMappedValues(values: ObjectMappedValues): boolean {
247
+ return Object.keys(values.standard).length > 0 || Object.keys(values.custom).length > 0
248
+ }
@@ -0,0 +1,435 @@
1
+ import type { CustomFieldObjectType, CustomFieldType, CustomFieldValue, CustomFieldWireValue } from '@kelpie/schemas'
2
+
3
+ import type { Transaction } from '../../runtime/transaction.ts'
4
+ import { createCustomFieldValues } from '../custom-fields/values.ts'
5
+ import type { CustomFieldDefinitionRecord } from '../custom-fields/repository.ts'
6
+ import * as companyRepository from '../companies/repository.ts'
7
+ import type { CompanyRecord } from '../companies/repository.ts'
8
+ import * as dealRepository from '../deals/repository.ts'
9
+ import type { DealRecord } from '../deals/repository.ts'
10
+ import * as enquiryRepository from '../enquiries/repository.ts'
11
+ import type { EnquiryRecord } from '../enquiries/repository.ts'
12
+ import * as opportunityRepository from '../opportunities/repository.ts'
13
+ import type { OpportunityRecord } from '../opportunities/repository.ts'
14
+ import * as partnershipRepository from '../partnerships/repository.ts'
15
+ import type { PartnershipRecord } from '../partnerships/repository.ts'
16
+ import * as peopleRepository from '../people/repository.ts'
17
+ import type { PersonRecord } from '../people/repository.ts'
18
+ import * as raiseRepository from '../raises/repository.ts'
19
+ import type { RaiseRecord } from '../raises/repository.ts'
20
+ import {
21
+ applyStandardFillBlank,
22
+ customFieldsFillBlankPatch,
23
+ hasObjectMappedValues,
24
+ parseCustomFieldAnswer,
25
+ valuesForObject,
26
+ } from './applyMappedFields.ts'
27
+ import type { MappedAnswers } from './mapping.ts'
28
+
29
+ const customFieldValues = createCustomFieldValues({ db: null as never })
30
+
31
+ const PERSON_FIELD_COLUMNS: Readonly<Record<string, keyof PersonRecord>> = {
32
+ salutation: 'salutation',
33
+ suffix: 'suffix',
34
+ timezone: 'timezone',
35
+ location: 'location',
36
+ preferred_channel: 'preferredChannel',
37
+ influence: 'influence',
38
+ relationship: 'relationship',
39
+ summary: 'summary',
40
+ tags: 'tags',
41
+ do_not_contact: 'doNotContact',
42
+ }
43
+
44
+ const COMPANY_FIELD_COLUMNS: Readonly<Record<string, keyof CompanyRecord>> = {
45
+ industry: 'industry',
46
+ description: 'description',
47
+ stage: 'stage',
48
+ size_band: 'sizeBand',
49
+ hq: 'hq',
50
+ website: 'website',
51
+ account_type: 'accountType',
52
+ icp_fit: 'icpFit',
53
+ tech_stack: 'techStack',
54
+ summary: 'summary',
55
+ tags: 'tags',
56
+ }
57
+
58
+ const DEAL_FIELD_COLUMNS: Readonly<Record<string, keyof DealRecord>> = {
59
+ value_cents: 'valueCents',
60
+ currency: 'currency',
61
+ expected_close: 'expectedClose',
62
+ competitors: 'competitors',
63
+ risks: 'risks',
64
+ why_win: 'whyWin',
65
+ summary: 'summary',
66
+ tags: 'tags',
67
+ external_id: 'externalId',
68
+ }
69
+
70
+ const OPPORTUNITY_FIELD_COLUMNS: Readonly<Record<string, keyof OpportunityRecord>> = {
71
+ kind: 'kind',
72
+ expected_close: 'expectedClose',
73
+ summary: 'summary',
74
+ tags: 'tags',
75
+ }
76
+
77
+ const PARTNERSHIP_FIELD_COLUMNS: Readonly<Record<string, keyof PartnershipRecord>> = {
78
+ kind: 'kind',
79
+ next_touchpoint: 'nextTouchpoint',
80
+ goals: 'goals',
81
+ success_looks_like: 'successLooksLike',
82
+ summary: 'summary',
83
+ tags: 'tags',
84
+ }
85
+
86
+ const ENQUIRY_FIELD_COLUMNS: Readonly<Record<string, keyof EnquiryRecord>> = {
87
+ source: 'source',
88
+ summary: 'summary',
89
+ tags: 'tags',
90
+ }
91
+
92
+ const RAISE_FIELD_COLUMNS: Readonly<Record<string, keyof RaiseRecord>> = {
93
+ check_size_cents: 'checkSizeCents',
94
+ currency: 'currency',
95
+ thesis_fit: 'thesisFit',
96
+ pass_reason: 'passReason',
97
+ expected_close: 'expectedClose',
98
+ summary: 'summary',
99
+ tags: 'tags',
100
+ }
101
+
102
+ async function buildCustomFieldsPatch(
103
+ tx: Transaction,
104
+ workspaceId: string,
105
+ objectType: CustomFieldObjectType,
106
+ stored: Readonly<Record<string, CustomFieldValue>>,
107
+ inbound: Readonly<Record<string, string>>,
108
+ definitions: readonly CustomFieldDefinitionRecord[],
109
+ ): Promise<Readonly<Record<string, CustomFieldValue>> | undefined> {
110
+ const blanks = customFieldsFillBlankPatch(stored, inbound)
111
+
112
+ if (Object.keys(blanks).length === 0) {
113
+ return undefined
114
+ }
115
+
116
+ const byKey = new Map(definitions.map((definition) => [definition.key, definition]))
117
+ const sent: Record<string, CustomFieldWireValue | null> = {}
118
+
119
+ for (const [key, raw] of Object.entries(blanks)) {
120
+ const definition = byKey.get(key)
121
+
122
+ if (definition === undefined) {
123
+ continue
124
+ }
125
+
126
+ sent[key] = parseCustomFieldAnswer(
127
+ {
128
+ objectType: definition.objectType as CustomFieldObjectType,
129
+ key: definition.key,
130
+ label: definition.label,
131
+ type: definition.type as CustomFieldType,
132
+ },
133
+ raw,
134
+ ) as CustomFieldWireValue
135
+ }
136
+
137
+ if (Object.keys(sent).length === 0) {
138
+ return undefined
139
+ }
140
+
141
+ try {
142
+ const merged = await customFieldValues.forUpdate(tx, workspaceId, objectType, stored, sent)
143
+ return merged?.merged
144
+ } catch {
145
+ // A form answer that does not validate as the custom field's type is skipped
146
+ // rather than failing the whole submit — the visitor typed something the
147
+ // field type cannot store.
148
+ return undefined
149
+ }
150
+ }
151
+
152
+ function columnLookup(
153
+ map: Readonly<Record<string, string>>,
154
+ ): (field: string) => string | undefined {
155
+ return (field: string) => map[field]
156
+ }
157
+
158
+ export async function applyPersonMappedFields(
159
+ tx: Transaction,
160
+ workspaceId: string,
161
+ person: PersonRecord,
162
+ mapped: MappedAnswers,
163
+ definitions: readonly CustomFieldDefinitionRecord[],
164
+ now: Date,
165
+ ): Promise<PersonRecord> {
166
+ const values = valuesForObject(mapped, 'person')
167
+
168
+ if (!hasObjectMappedValues(values)) {
169
+ return person
170
+ }
171
+
172
+ const standardPatch = applyStandardFillBlank(person, 'person', values, columnLookup(PERSON_FIELD_COLUMNS))
173
+ const customFields = await buildCustomFieldsPatch(
174
+ tx,
175
+ workspaceId,
176
+ 'person',
177
+ person.customFields,
178
+ values.custom,
179
+ definitions,
180
+ )
181
+
182
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
183
+ return person
184
+ }
185
+
186
+ const updated = await peopleRepository.updatePerson(tx, workspaceId, person.id, {
187
+ ...standardPatch,
188
+ ...(customFields === undefined ? {} : { customFields }),
189
+ updatedAt: now,
190
+ })
191
+
192
+ return updated ?? person
193
+ }
194
+
195
+ export async function applyCompanyMappedFields(
196
+ tx: Transaction,
197
+ workspaceId: string,
198
+ company: CompanyRecord,
199
+ mapped: MappedAnswers,
200
+ definitions: readonly CustomFieldDefinitionRecord[],
201
+ now: Date,
202
+ ): Promise<CompanyRecord> {
203
+ const values = valuesForObject(mapped, 'company')
204
+
205
+ if (!hasObjectMappedValues(values)) {
206
+ return company
207
+ }
208
+
209
+ const standardPatch = applyStandardFillBlank(
210
+ company,
211
+ 'company',
212
+ values,
213
+ columnLookup(COMPANY_FIELD_COLUMNS),
214
+ )
215
+ const customFields = await buildCustomFieldsPatch(
216
+ tx,
217
+ workspaceId,
218
+ 'company',
219
+ company.customFields,
220
+ values.custom,
221
+ definitions,
222
+ )
223
+
224
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
225
+ return company
226
+ }
227
+
228
+ const updated = await companyRepository.updateCompany(tx, workspaceId, company.id, {
229
+ ...standardPatch,
230
+ ...(customFields === undefined ? {} : { customFields }),
231
+ updatedAt: now,
232
+ })
233
+
234
+ return updated ?? company
235
+ }
236
+
237
+ export async function applyDealMappedFields(
238
+ tx: Transaction,
239
+ workspaceId: string,
240
+ deal: DealRecord,
241
+ mapped: MappedAnswers,
242
+ definitions: readonly CustomFieldDefinitionRecord[],
243
+ now: Date,
244
+ ): Promise<DealRecord> {
245
+ const values = valuesForObject(mapped, 'deal')
246
+
247
+ if (!hasObjectMappedValues(values)) {
248
+ return deal
249
+ }
250
+
251
+ const standardPatch = applyStandardFillBlank(deal, 'deal', values, columnLookup(DEAL_FIELD_COLUMNS))
252
+ const customFields = await buildCustomFieldsPatch(
253
+ tx,
254
+ workspaceId,
255
+ 'deal',
256
+ deal.customFields,
257
+ values.custom,
258
+ definitions,
259
+ )
260
+
261
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
262
+ return deal
263
+ }
264
+
265
+ const updated = await dealRepository.updateDeal(tx, workspaceId, deal.id, {
266
+ ...standardPatch,
267
+ ...(customFields === undefined ? {} : { customFields }),
268
+ updatedAt: now,
269
+ })
270
+
271
+ return updated ?? deal
272
+ }
273
+
274
+ export async function applyOpportunityMappedFields(
275
+ tx: Transaction,
276
+ workspaceId: string,
277
+ opportunity: OpportunityRecord,
278
+ mapped: MappedAnswers,
279
+ definitions: readonly CustomFieldDefinitionRecord[],
280
+ now: Date,
281
+ ): Promise<OpportunityRecord> {
282
+ const values = valuesForObject(mapped, 'opportunity')
283
+
284
+ if (!hasObjectMappedValues(values)) {
285
+ return opportunity
286
+ }
287
+
288
+ const standardPatch = applyStandardFillBlank(
289
+ opportunity,
290
+ 'opportunity',
291
+ values,
292
+ columnLookup(OPPORTUNITY_FIELD_COLUMNS),
293
+ )
294
+ const customFields = await buildCustomFieldsPatch(
295
+ tx,
296
+ workspaceId,
297
+ 'opportunity',
298
+ opportunity.customFields,
299
+ values.custom,
300
+ definitions,
301
+ )
302
+
303
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
304
+ return opportunity
305
+ }
306
+
307
+ const updated = await opportunityRepository.updateOpportunity(tx, workspaceId, opportunity.id, {
308
+ ...standardPatch,
309
+ ...(customFields === undefined ? {} : { customFields }),
310
+ updatedAt: now,
311
+ })
312
+
313
+ return updated ?? opportunity
314
+ }
315
+
316
+ export async function applyPartnershipMappedFields(
317
+ tx: Transaction,
318
+ workspaceId: string,
319
+ partnership: PartnershipRecord,
320
+ mapped: MappedAnswers,
321
+ definitions: readonly CustomFieldDefinitionRecord[],
322
+ now: Date,
323
+ ): Promise<PartnershipRecord> {
324
+ const values = valuesForObject(mapped, 'partnership')
325
+
326
+ if (!hasObjectMappedValues(values)) {
327
+ return partnership
328
+ }
329
+
330
+ const standardPatch = applyStandardFillBlank(
331
+ partnership,
332
+ 'partnership',
333
+ values,
334
+ columnLookup(PARTNERSHIP_FIELD_COLUMNS),
335
+ )
336
+ const customFields = await buildCustomFieldsPatch(
337
+ tx,
338
+ workspaceId,
339
+ 'partnership',
340
+ partnership.customFields,
341
+ values.custom,
342
+ definitions,
343
+ )
344
+
345
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
346
+ return partnership
347
+ }
348
+
349
+ const updated = await partnershipRepository.updatePartnership(tx, workspaceId, partnership.id, {
350
+ ...standardPatch,
351
+ ...(customFields === undefined ? {} : { customFields }),
352
+ updatedAt: now,
353
+ })
354
+
355
+ return updated ?? partnership
356
+ }
357
+
358
+ export async function applyEnquiryMappedFields(
359
+ tx: Transaction,
360
+ workspaceId: string,
361
+ enquiry: EnquiryRecord,
362
+ mapped: MappedAnswers,
363
+ definitions: readonly CustomFieldDefinitionRecord[],
364
+ now: Date,
365
+ ): Promise<EnquiryRecord> {
366
+ const values = valuesForObject(mapped, 'enquiry')
367
+
368
+ if (!hasObjectMappedValues(values)) {
369
+ return enquiry
370
+ }
371
+
372
+ const standardPatch = applyStandardFillBlank(
373
+ enquiry,
374
+ 'enquiry',
375
+ values,
376
+ columnLookup(ENQUIRY_FIELD_COLUMNS),
377
+ )
378
+ const customFields = await buildCustomFieldsPatch(
379
+ tx,
380
+ workspaceId,
381
+ 'enquiry',
382
+ enquiry.customFields,
383
+ values.custom,
384
+ definitions,
385
+ )
386
+
387
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
388
+ return enquiry
389
+ }
390
+
391
+ const updated = await enquiryRepository.updateEnquiry(tx, workspaceId, enquiry.id, {
392
+ ...standardPatch,
393
+ ...(customFields === undefined ? {} : { customFields }),
394
+ updatedAt: now,
395
+ })
396
+
397
+ return updated ?? enquiry
398
+ }
399
+
400
+ export async function applyRaiseMappedFields(
401
+ tx: Transaction,
402
+ workspaceId: string,
403
+ raise: RaiseRecord,
404
+ mapped: MappedAnswers,
405
+ definitions: readonly CustomFieldDefinitionRecord[],
406
+ now: Date,
407
+ ): Promise<RaiseRecord> {
408
+ const values = valuesForObject(mapped, 'raise')
409
+
410
+ if (!hasObjectMappedValues(values)) {
411
+ return raise
412
+ }
413
+
414
+ const standardPatch = applyStandardFillBlank(raise, 'raise', values, columnLookup(RAISE_FIELD_COLUMNS))
415
+ const customFields = await buildCustomFieldsPatch(
416
+ tx,
417
+ workspaceId,
418
+ 'raise',
419
+ raise.customFields,
420
+ values.custom,
421
+ definitions,
422
+ )
423
+
424
+ if (Object.keys(standardPatch).length === 0 && customFields === undefined) {
425
+ return raise
426
+ }
427
+
428
+ const updated = await raiseRepository.updateRaise(tx, workspaceId, raise.id, {
429
+ ...standardPatch,
430
+ ...(customFields === undefined ? {} : { customFields }),
431
+ updatedAt: now,
432
+ })
433
+
434
+ return updated ?? raise
435
+ }