@kelpie/server 0.12.0 → 0.14.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 (420) hide show
  1. package/dist/app.d.ts +13 -0
  2. package/dist/app.d.ts.map +1 -1
  3. package/dist/app.js +8 -1
  4. package/dist/app.js.map +1 -1
  5. package/dist/boot.d.ts +9 -0
  6. package/dist/boot.d.ts.map +1 -1
  7. package/dist/boot.js +12 -2
  8. package/dist/boot.js.map +1 -1
  9. package/dist/index.d.ts +6 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +3 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/lib/apiKeyScopes.d.ts.map +1 -1
  14. package/dist/lib/apiKeyScopes.js +6 -0
  15. package/dist/lib/apiKeyScopes.js.map +1 -1
  16. package/dist/lib/columns.d.ts +6 -0
  17. package/dist/lib/columns.d.ts.map +1 -1
  18. package/dist/lib/columns.js +5 -3
  19. package/dist/lib/columns.js.map +1 -1
  20. package/dist/lib/config.d.ts +17 -0
  21. package/dist/lib/config.d.ts.map +1 -1
  22. package/dist/lib/config.js +3 -0
  23. package/dist/lib/config.js.map +1 -1
  24. package/dist/lib/egress.d.ts.map +1 -1
  25. package/dist/lib/egress.js +8 -4
  26. package/dist/lib/egress.js.map +1 -1
  27. package/dist/lib/errors.d.ts +3 -3
  28. package/dist/lib/errors.d.ts.map +1 -1
  29. package/dist/lib/errors.js +13 -5
  30. package/dist/lib/errors.js.map +1 -1
  31. package/dist/lib/ids.d.ts +11 -0
  32. package/dist/lib/ids.d.ts.map +1 -1
  33. package/dist/lib/ids.js +11 -0
  34. package/dist/lib/ids.js.map +1 -1
  35. package/dist/lib/jobs.d.ts +110 -0
  36. package/dist/lib/jobs.d.ts.map +1 -0
  37. package/dist/lib/jobs.js +5 -0
  38. package/dist/lib/jobs.js.map +1 -0
  39. package/dist/lib/kelpieConfigFile.d.ts +15 -1
  40. package/dist/lib/kelpieConfigFile.d.ts.map +1 -1
  41. package/dist/lib/kelpieConfigFile.js +33 -1
  42. package/dist/lib/kelpieConfigFile.js.map +1 -1
  43. package/dist/modules/agent-tasks/catalog.d.ts.map +1 -1
  44. package/dist/modules/agent-tasks/catalog.js +32 -1
  45. package/dist/modules/agent-tasks/catalog.js.map +1 -1
  46. package/dist/modules/agent-tasks/index.d.ts.map +1 -1
  47. package/dist/modules/agent-tasks/index.js +1 -0
  48. package/dist/modules/agent-tasks/index.js.map +1 -1
  49. package/dist/modules/agent-tasks/resolve.d.ts.map +1 -1
  50. package/dist/modules/agent-tasks/resolve.js +5 -0
  51. package/dist/modules/agent-tasks/resolve.js.map +1 -1
  52. package/dist/modules/agent-tasks/routes.d.ts +2 -0
  53. package/dist/modules/agent-tasks/routes.d.ts.map +1 -1
  54. package/dist/modules/attachedRecords.d.ts +22 -8
  55. package/dist/modules/attachedRecords.d.ts.map +1 -1
  56. package/dist/modules/attachedRecords.js +42 -5
  57. package/dist/modules/attachedRecords.js.map +1 -1
  58. package/dist/modules/auth/index.d.ts.map +1 -1
  59. package/dist/modules/auth/index.js +1 -0
  60. package/dist/modules/auth/index.js.map +1 -1
  61. package/dist/modules/auth/repository.d.ts +14 -0
  62. package/dist/modules/auth/repository.d.ts.map +1 -1
  63. package/dist/modules/auth/repository.js +20 -2
  64. package/dist/modules/auth/repository.js.map +1 -1
  65. package/dist/modules/auth/routes.d.ts.map +1 -1
  66. package/dist/modules/auth/routes.js +30 -0
  67. package/dist/modules/auth/routes.js.map +1 -1
  68. package/dist/modules/auth/service.d.ts +28 -0
  69. package/dist/modules/auth/service.d.ts.map +1 -1
  70. package/dist/modules/auth/service.js +72 -4
  71. package/dist/modules/auth/service.js.map +1 -1
  72. package/dist/modules/companies/repository.d.ts.map +1 -1
  73. package/dist/modules/companies/repository.js +1 -1
  74. package/dist/modules/companies/repository.js.map +1 -1
  75. package/dist/modules/companies/routes.d.ts +2 -4
  76. package/dist/modules/companies/routes.d.ts.map +1 -1
  77. package/dist/modules/companies/routes.js +6 -11
  78. package/dist/modules/companies/routes.js.map +1 -1
  79. package/dist/modules/companies/schema.d.ts +13 -28
  80. package/dist/modules/companies/schema.d.ts.map +1 -1
  81. package/dist/modules/companies/schema.js +2 -2
  82. package/dist/modules/companies/schema.js.map +1 -1
  83. package/dist/modules/companies/service.d.ts +2 -3
  84. package/dist/modules/companies/service.d.ts.map +1 -1
  85. package/dist/modules/companies/service.js +4 -7
  86. package/dist/modules/companies/service.js.map +1 -1
  87. package/dist/modules/core.d.ts.map +1 -1
  88. package/dist/modules/core.js +2 -0
  89. package/dist/modules/core.js.map +1 -1
  90. package/dist/modules/custom-fields/repository.d.ts.map +1 -1
  91. package/dist/modules/custom-fields/repository.js +2 -0
  92. package/dist/modules/custom-fields/repository.js.map +1 -1
  93. package/dist/modules/custom-fields/routes.d.ts +1 -0
  94. package/dist/modules/custom-fields/routes.d.ts.map +1 -1
  95. package/dist/modules/dashboard/index.d.ts.map +1 -1
  96. package/dist/modules/dashboard/index.js +1 -0
  97. package/dist/modules/dashboard/index.js.map +1 -1
  98. package/dist/modules/dashboard/repository.d.ts +13 -0
  99. package/dist/modules/dashboard/repository.d.ts.map +1 -1
  100. package/dist/modules/dashboard/repository.js +36 -0
  101. package/dist/modules/dashboard/repository.js.map +1 -1
  102. package/dist/modules/dashboard/routes.d.ts.map +1 -1
  103. package/dist/modules/dashboard/routes.js +13 -0
  104. package/dist/modules/dashboard/routes.js.map +1 -1
  105. package/dist/modules/dashboard/service.d.ts +11 -0
  106. package/dist/modules/dashboard/service.d.ts.map +1 -1
  107. package/dist/modules/dashboard/service.js +24 -1
  108. package/dist/modules/dashboard/service.js.map +1 -1
  109. package/dist/modules/decisions/repository.d.ts.map +1 -1
  110. package/dist/modules/decisions/repository.js +2 -0
  111. package/dist/modules/decisions/repository.js.map +1 -1
  112. package/dist/modules/decisions/routes.d.ts +2 -0
  113. package/dist/modules/decisions/routes.d.ts.map +1 -1
  114. package/dist/modules/events/attendances.d.ts +35 -0
  115. package/dist/modules/events/attendances.d.ts.map +1 -0
  116. package/dist/modules/events/attendances.js +157 -0
  117. package/dist/modules/events/attendances.js.map +1 -0
  118. package/dist/modules/events/catalog.d.ts +35 -0
  119. package/dist/modules/events/catalog.d.ts.map +1 -0
  120. package/dist/modules/events/catalog.js +11 -0
  121. package/dist/modules/events/catalog.js.map +1 -0
  122. package/dist/modules/events/index.d.ts +10 -0
  123. package/dist/modules/events/index.d.ts.map +1 -0
  124. package/dist/modules/events/index.js +47 -0
  125. package/dist/modules/events/index.js.map +1 -0
  126. package/dist/modules/events/repository.d.ts +67 -0
  127. package/dist/modules/events/repository.d.ts.map +1 -0
  128. package/dist/modules/events/repository.js +212 -0
  129. package/dist/modules/events/repository.js.map +1 -0
  130. package/dist/modules/events/routes.d.ts +136 -0
  131. package/dist/modules/events/routes.d.ts.map +1 -0
  132. package/dist/modules/events/routes.js +280 -0
  133. package/dist/modules/events/routes.js.map +1 -0
  134. package/dist/modules/events/schema.d.ts +626 -0
  135. package/dist/modules/events/schema.d.ts.map +1 -0
  136. package/dist/modules/events/schema.js +93 -0
  137. package/dist/modules/events/schema.js.map +1 -0
  138. package/dist/modules/events/service.d.ts +68 -0
  139. package/dist/modules/events/service.d.ts.map +1 -0
  140. package/dist/modules/events/service.js +262 -0
  141. package/dist/modules/events/service.js.map +1 -0
  142. package/dist/modules/events/tools.d.ts +8 -0
  143. package/dist/modules/events/tools.d.ts.map +1 -0
  144. package/dist/modules/events/tools.js +80 -0
  145. package/dist/modules/events/tools.js.map +1 -0
  146. package/dist/modules/forms/applySubmissionFields.d.ts.map +1 -1
  147. package/dist/modules/forms/applySubmissionFields.js +7 -5
  148. package/dist/modules/forms/applySubmissionFields.js.map +1 -1
  149. package/dist/modules/forms/fillAddresses.d.ts +4 -0
  150. package/dist/modules/forms/fillAddresses.d.ts.map +1 -0
  151. package/dist/modules/forms/fillAddresses.js +93 -0
  152. package/dist/modules/forms/fillAddresses.js.map +1 -0
  153. package/dist/modules/forms/repository.d.ts +2 -2
  154. package/dist/modules/forms/repository.d.ts.map +1 -1
  155. package/dist/modules/forms/repository.js.map +1 -1
  156. package/dist/modules/forms/routes.d.ts +2 -0
  157. package/dist/modules/forms/routes.d.ts.map +1 -1
  158. package/dist/modules/forms/routes.js +2 -2
  159. package/dist/modules/forms/routes.js.map +1 -1
  160. package/dist/modules/forms/schema.js +2 -2
  161. package/dist/modules/forms/schema.js.map +1 -1
  162. package/dist/modules/forms/service.js +2 -2
  163. package/dist/modules/forms/service.js.map +1 -1
  164. package/dist/modules/forms/submission.d.ts +1 -0
  165. package/dist/modules/forms/submission.d.ts.map +1 -1
  166. package/dist/modules/forms/submission.js +27 -4
  167. package/dist/modules/forms/submission.js.map +1 -1
  168. package/dist/modules/hiring/roles.d.ts.map +1 -1
  169. package/dist/modules/hiring/roles.js +2 -1
  170. package/dist/modules/hiring/roles.js.map +1 -1
  171. package/dist/modules/import-export/addresses.d.ts +22 -0
  172. package/dist/modules/import-export/addresses.d.ts.map +1 -0
  173. package/dist/modules/import-export/addresses.js +83 -0
  174. package/dist/modules/import-export/addresses.js.map +1 -0
  175. package/dist/modules/import-export/drafts.d.ts +3 -4
  176. package/dist/modules/import-export/drafts.d.ts.map +1 -1
  177. package/dist/modules/import-export/drafts.js +4 -5
  178. package/dist/modules/import-export/drafts.js.map +1 -1
  179. package/dist/modules/import-export/exportRows.d.ts.map +1 -1
  180. package/dist/modules/import-export/exportRows.js +3 -3
  181. package/dist/modules/import-export/exportRows.js.map +1 -1
  182. package/dist/modules/import-export/plan.d.ts.map +1 -1
  183. package/dist/modules/import-export/plan.js +17 -2
  184. package/dist/modules/import-export/plan.js.map +1 -1
  185. package/dist/modules/import-export/presets.d.ts.map +1 -1
  186. package/dist/modules/import-export/presets.js +52 -7
  187. package/dist/modules/import-export/presets.js.map +1 -1
  188. package/dist/modules/import-export/repository.d.ts +3 -4
  189. package/dist/modules/import-export/repository.d.ts.map +1 -1
  190. package/dist/modules/import-export/repository.js +2 -3
  191. package/dist/modules/import-export/repository.js.map +1 -1
  192. package/dist/modules/import-export/writes.d.ts.map +1 -1
  193. package/dist/modules/import-export/writes.js +8 -4
  194. package/dist/modules/import-export/writes.js.map +1 -1
  195. package/dist/modules/lists/routes.d.ts +4 -0
  196. package/dist/modules/lists/routes.d.ts.map +1 -1
  197. package/dist/modules/notes/routes.d.ts +2 -0
  198. package/dist/modules/notes/routes.d.ts.map +1 -1
  199. package/dist/modules/people/repository.d.ts.map +1 -1
  200. package/dist/modules/people/repository.js +1 -1
  201. package/dist/modules/people/repository.js.map +1 -1
  202. package/dist/modules/people/routes.d.ts +2 -2
  203. package/dist/modules/people/routes.js +6 -6
  204. package/dist/modules/people/routes.js.map +1 -1
  205. package/dist/modules/people/schema.d.ts +17 -14
  206. package/dist/modules/people/schema.d.ts.map +1 -1
  207. package/dist/modules/people/schema.js +6 -4
  208. package/dist/modules/people/schema.js.map +1 -1
  209. package/dist/modules/people/service.d.ts +2 -2
  210. package/dist/modules/people/service.d.ts.map +1 -1
  211. package/dist/modules/people/service.js +5 -4
  212. package/dist/modules/people/service.js.map +1 -1
  213. package/dist/modules/plans/repository.d.ts +2 -2
  214. package/dist/modules/plans/repository.d.ts.map +1 -1
  215. package/dist/modules/plans/routes.d.ts +1 -0
  216. package/dist/modules/plans/routes.d.ts.map +1 -1
  217. package/dist/modules/plans/routes.js +4 -4
  218. package/dist/modules/plans/routes.js.map +1 -1
  219. package/dist/modules/plans/schema.d.ts +2 -2
  220. package/dist/modules/plans/schema.d.ts.map +1 -1
  221. package/dist/modules/plans/schema.js +3 -3
  222. package/dist/modules/plans/schema.js.map +1 -1
  223. package/dist/modules/plans/service.d.ts +2 -2
  224. package/dist/modules/plans/service.d.ts.map +1 -1
  225. package/dist/modules/plans/service.js.map +1 -1
  226. package/dist/modules/plans/tools.js +2 -2
  227. package/dist/modules/plans/tools.js.map +1 -1
  228. package/dist/modules/recordTargets.d.ts.map +1 -1
  229. package/dist/modules/recordTargets.js +11 -0
  230. package/dist/modules/recordTargets.js.map +1 -1
  231. package/dist/modules/references.d.ts.map +1 -1
  232. package/dist/modules/references.js +2 -0
  233. package/dist/modules/references.js.map +1 -1
  234. package/dist/modules/sample-data/fixture.d.ts +26 -4
  235. package/dist/modules/sample-data/fixture.d.ts.map +1 -1
  236. package/dist/modules/sample-data/fixture.js +157 -23
  237. package/dist/modules/sample-data/fixture.js.map +1 -1
  238. package/dist/modules/sample-data/index.d.ts +5 -2
  239. package/dist/modules/sample-data/index.d.ts.map +1 -1
  240. package/dist/modules/sample-data/index.js +7 -2
  241. package/dist/modules/sample-data/index.js.map +1 -1
  242. package/dist/modules/sample-data/routes.d.ts.map +1 -1
  243. package/dist/modules/sample-data/routes.js +2 -0
  244. package/dist/modules/sample-data/routes.js.map +1 -1
  245. package/dist/modules/sample-data/service.d.ts +11 -3
  246. package/dist/modules/sample-data/service.d.ts.map +1 -1
  247. package/dist/modules/sample-data/service.js +452 -363
  248. package/dist/modules/sample-data/service.js.map +1 -1
  249. package/dist/modules/sample-data/tools.d.ts.map +1 -1
  250. package/dist/modules/sample-data/tools.js +4 -3
  251. package/dist/modules/sample-data/tools.js.map +1 -1
  252. package/dist/modules/search/index.d.ts +1 -1
  253. package/dist/modules/search/index.d.ts.map +1 -1
  254. package/dist/modules/search/index.js +2 -1
  255. package/dist/modules/search/index.js.map +1 -1
  256. package/dist/modules/search/repository.d.ts +1 -0
  257. package/dist/modules/search/repository.d.ts.map +1 -1
  258. package/dist/modules/search/repository.js +22 -0
  259. package/dist/modules/search/repository.js.map +1 -1
  260. package/dist/modules/search/service.d.ts +2 -2
  261. package/dist/modules/search/service.d.ts.map +1 -1
  262. package/dist/modules/search/service.js +4 -3
  263. package/dist/modules/search/service.js.map +1 -1
  264. package/dist/modules/smtp-email/index.d.ts +12 -4
  265. package/dist/modules/smtp-email/index.d.ts.map +1 -1
  266. package/dist/modules/smtp-email/index.js +25 -5
  267. package/dist/modules/smtp-email/index.js.map +1 -1
  268. package/dist/modules/workspace/repository.d.ts +2 -0
  269. package/dist/modules/workspace/repository.d.ts.map +1 -1
  270. package/dist/modules/workspace/repository.js +12 -0
  271. package/dist/modules/workspace/repository.js.map +1 -1
  272. package/dist/modules/workspace/routes.d.ts.map +1 -1
  273. package/dist/modules/workspace/routes.js +13 -0
  274. package/dist/modules/workspace/routes.js.map +1 -1
  275. package/dist/modules/workspace/service.d.ts +10 -0
  276. package/dist/modules/workspace/service.d.ts.map +1 -1
  277. package/dist/modules/workspace/service.js +34 -10
  278. package/dist/modules/workspace/service.js.map +1 -1
  279. package/dist/modules/workspace/starters.d.ts +17 -2
  280. package/dist/modules/workspace/starters.d.ts.map +1 -1
  281. package/dist/modules/workspace/starters.js +141 -14
  282. package/dist/modules/workspace/starters.js.map +1 -1
  283. package/dist/modules/workspace/workspaceAccessMiddleware.d.ts.map +1 -1
  284. package/dist/modules/workspace/workspaceAccessMiddleware.js +3 -4
  285. package/dist/modules/workspace/workspaceAccessMiddleware.js.map +1 -1
  286. package/dist/runtime/events.d.ts +1 -1
  287. package/dist/runtime/events.d.ts.map +1 -1
  288. package/dist/runtime/events.js +2 -0
  289. package/dist/runtime/events.js.map +1 -1
  290. package/dist/runtime/jobs.d.ts +63 -0
  291. package/dist/runtime/jobs.d.ts.map +1 -0
  292. package/dist/runtime/jobs.js +231 -0
  293. package/dist/runtime/jobs.js.map +1 -0
  294. package/dist/runtime/module.d.ts +20 -0
  295. package/dist/runtime/module.d.ts.map +1 -1
  296. package/dist/runtime/registry.d.ts +8 -0
  297. package/dist/runtime/registry.d.ts.map +1 -1
  298. package/dist/runtime/registry.js +117 -7
  299. package/dist/runtime/registry.js.map +1 -1
  300. package/dist/runtime/transaction.d.ts +19 -0
  301. package/dist/runtime/transaction.d.ts.map +1 -1
  302. package/dist/runtime/transaction.js +7 -0
  303. package/dist/runtime/transaction.js.map +1 -1
  304. package/dist/schema/index.d.ts +1 -0
  305. package/dist/schema/index.d.ts.map +1 -1
  306. package/dist/schema/index.js +1 -0
  307. package/dist/schema/index.js.map +1 -1
  308. package/dist/testing/app.d.ts +15 -0
  309. package/dist/testing/app.d.ts.map +1 -1
  310. package/dist/testing/app.js +7 -1
  311. package/dist/testing/app.js.map +1 -1
  312. package/dist/testing/client.d.ts.map +1 -1
  313. package/dist/testing/client.js +9 -1
  314. package/dist/testing/client.js.map +1 -1
  315. package/dist/testing/database.d.ts +7 -0
  316. package/dist/testing/database.d.ts.map +1 -1
  317. package/dist/testing/database.js +26 -2
  318. package/dist/testing/database.js.map +1 -1
  319. package/dist/testing/services.d.ts +7 -0
  320. package/dist/testing/services.d.ts.map +1 -1
  321. package/dist/testing/services.js +8 -1
  322. package/dist/testing/services.js.map +1 -1
  323. package/dist/worker.d.ts +15 -0
  324. package/dist/worker.d.ts.map +1 -0
  325. package/dist/worker.js +19 -0
  326. package/dist/worker.js.map +1 -0
  327. package/migrations/0044_events.sql +79 -0
  328. package/migrations/0045_addresses.sql +66 -0
  329. package/migrations/0046_drop_company_website.sql +66 -0
  330. package/migrations/meta/_journal.json +21 -0
  331. package/package.json +4 -3
  332. package/src/app.ts +25 -1
  333. package/src/boot.ts +21 -2
  334. package/src/index.ts +17 -0
  335. package/src/lib/apiKeyScopes.ts +6 -0
  336. package/src/lib/columns.ts +12 -3
  337. package/src/lib/config.ts +21 -0
  338. package/src/lib/egress.ts +8 -4
  339. package/src/lib/errors.ts +16 -9
  340. package/src/lib/ids.ts +11 -0
  341. package/src/lib/jobs.ts +126 -0
  342. package/src/lib/kelpieConfigFile.ts +69 -1
  343. package/src/modules/agent-tasks/catalog.ts +33 -1
  344. package/src/modules/agent-tasks/index.ts +1 -0
  345. package/src/modules/agent-tasks/resolve.ts +11 -0
  346. package/src/modules/attachedRecords.ts +85 -13
  347. package/src/modules/auth/index.ts +1 -0
  348. package/src/modules/auth/repository.ts +34 -3
  349. package/src/modules/auth/routes.ts +44 -1
  350. package/src/modules/auth/service.ts +118 -4
  351. package/src/modules/companies/repository.ts +1 -0
  352. package/src/modules/companies/routes.ts +6 -11
  353. package/src/modules/companies/schema.ts +3 -3
  354. package/src/modules/companies/service.ts +6 -10
  355. package/src/modules/core.ts +2 -0
  356. package/src/modules/custom-fields/repository.ts +2 -0
  357. package/src/modules/dashboard/index.ts +1 -0
  358. package/src/modules/dashboard/repository.ts +64 -0
  359. package/src/modules/dashboard/routes.ts +15 -0
  360. package/src/modules/dashboard/service.ts +48 -0
  361. package/src/modules/decisions/repository.ts +2 -0
  362. package/src/modules/events/attendances.ts +245 -0
  363. package/src/modules/events/catalog.ts +36 -0
  364. package/src/modules/events/index.ts +54 -0
  365. package/src/modules/events/repository.ts +396 -0
  366. package/src/modules/events/routes.ts +405 -0
  367. package/src/modules/events/schema.ts +148 -0
  368. package/src/modules/events/service.ts +443 -0
  369. package/src/modules/events/tools.ts +118 -0
  370. package/src/modules/forms/applySubmissionFields.ts +7 -5
  371. package/src/modules/forms/fillAddresses.ts +185 -0
  372. package/src/modules/forms/repository.ts +3 -3
  373. package/src/modules/forms/routes.ts +2 -2
  374. package/src/modules/forms/schema.ts +2 -2
  375. package/src/modules/forms/service.ts +2 -2
  376. package/src/modules/forms/submission.ts +34 -4
  377. package/src/modules/hiring/roles.ts +2 -1
  378. package/src/modules/import-export/addresses.ts +150 -0
  379. package/src/modules/import-export/drafts.ts +7 -9
  380. package/src/modules/import-export/exportRows.ts +3 -3
  381. package/src/modules/import-export/plan.ts +30 -2
  382. package/src/modules/import-export/presets.ts +55 -7
  383. package/src/modules/import-export/repository.ts +5 -7
  384. package/src/modules/import-export/writes.ts +8 -4
  385. package/src/modules/people/repository.ts +1 -0
  386. package/src/modules/people/routes.ts +6 -6
  387. package/src/modules/people/schema.ts +7 -5
  388. package/src/modules/people/service.ts +7 -5
  389. package/src/modules/plans/repository.ts +2 -2
  390. package/src/modules/plans/routes.ts +6 -6
  391. package/src/modules/plans/schema.ts +4 -4
  392. package/src/modules/plans/service.ts +3 -3
  393. package/src/modules/plans/tools.ts +2 -2
  394. package/src/modules/recordTargets.ts +14 -0
  395. package/src/modules/references.ts +2 -0
  396. package/src/modules/sample-data/fixture.ts +208 -27
  397. package/src/modules/sample-data/index.ts +7 -2
  398. package/src/modules/sample-data/routes.ts +2 -0
  399. package/src/modules/sample-data/service.ts +166 -49
  400. package/src/modules/sample-data/tools.ts +4 -3
  401. package/src/modules/search/index.ts +2 -1
  402. package/src/modules/search/repository.ts +32 -1
  403. package/src/modules/search/service.ts +6 -4
  404. package/src/modules/smtp-email/index.ts +32 -10
  405. package/src/modules/workspace/repository.ts +18 -0
  406. package/src/modules/workspace/routes.ts +16 -0
  407. package/src/modules/workspace/service.ts +59 -14
  408. package/src/modules/workspace/starters.ts +275 -14
  409. package/src/modules/workspace/workspaceAccessMiddleware.ts +3 -4
  410. package/src/runtime/events.ts +2 -0
  411. package/src/runtime/jobs.ts +358 -0
  412. package/src/runtime/module.ts +20 -0
  413. package/src/runtime/registry.ts +146 -8
  414. package/src/runtime/transaction.ts +43 -0
  415. package/src/schema/index.ts +1 -0
  416. package/src/testing/app.ts +22 -1
  417. package/src/testing/client.ts +11 -1
  418. package/src/testing/database.ts +35 -2
  419. package/src/testing/services.ts +15 -1
  420. package/src/worker.ts +20 -0
@@ -22,8 +22,12 @@ export const SOURCE_PRESETS: Readonly<Record<ImportSource, SourcePreset>> = {
22
22
  name: 'Name',
23
23
  domain: 'Company Domain Name',
24
24
  industry: 'Industry',
25
- website: 'Website URL',
26
- hq: 'City',
25
+ hq_line1: 'Address',
26
+ hq_line2: 'Address 2',
27
+ hq_city: 'City',
28
+ hq_region: 'State/Region',
29
+ hq_postal_code: 'Postal Code',
30
+ hq_country: 'Country',
27
31
  description: 'Description',
28
32
  },
29
33
  people: {
@@ -35,7 +39,12 @@ export const SOURCE_PRESETS: Readonly<Record<ImportSource, SourcePreset>> = {
35
39
  last_name: 'Last Name',
36
40
  email: 'Email',
37
41
  phones: 'Phone Number',
38
- location: 'City',
42
+ mailing_line1: 'Address',
43
+ mailing_line2: 'Address 2',
44
+ mailing_city: 'City',
45
+ mailing_region: 'State/Region',
46
+ mailing_postal_code: 'Postal Code',
47
+ mailing_country: 'Country',
39
48
  company_domain: 'Company Domain Name',
40
49
  title: 'Job Title',
41
50
  },
@@ -59,7 +68,16 @@ export const SOURCE_PRESETS: Readonly<Record<ImportSource, SourcePreset>> = {
59
68
  name: 'Account Name',
60
69
  domain: 'Website',
61
70
  industry: 'Industry',
62
- hq: 'Billing City',
71
+ billing_line1: 'Billing Street',
72
+ billing_city: 'Billing City',
73
+ billing_region: 'Billing State/Province',
74
+ billing_postal_code: 'Billing Zip/Postal Code',
75
+ billing_country: 'Billing Country',
76
+ shipping_line1: 'Shipping Street',
77
+ shipping_city: 'Shipping City',
78
+ shipping_region: 'Shipping State/Province',
79
+ shipping_postal_code: 'Shipping Zip/Postal Code',
80
+ shipping_country: 'Shipping Country',
63
81
  description: 'Description',
64
82
  },
65
83
  people: {
@@ -69,7 +87,16 @@ export const SOURCE_PRESETS: Readonly<Record<ImportSource, SourcePreset>> = {
69
87
  last_name: 'Last Name',
70
88
  email: 'Email',
71
89
  phones: 'Phone',
72
- location: 'Mailing City',
90
+ mailing_line1: 'Mailing Street',
91
+ mailing_city: 'Mailing City',
92
+ mailing_region: 'Mailing State/Province',
93
+ mailing_postal_code: 'Mailing Zip/Postal Code',
94
+ mailing_country: 'Mailing Country',
95
+ other_line1: 'Other Street',
96
+ other_city: 'Other City',
97
+ other_region: 'Other State/Province',
98
+ other_postal_code: 'Other Zip/Postal Code',
99
+ other_country: 'Other Country',
73
100
  company_name: 'Account Name',
74
101
  // Salesforce's Contact.Title is the job title, and a job title is a
75
102
  // Position. It is not this object's `suffix`, which stays unmapped.
@@ -101,12 +128,22 @@ export const SOURCE_PRESETS: Readonly<Record<ImportSource, SourcePreset>> = {
101
128
  domain: 'Domains',
102
129
  industry: 'Categories',
103
130
  description: 'Description',
104
- hq: 'Primary location > Country',
131
+ hq_line1: 'Primary location > Line 1',
132
+ hq_line2: 'Primary location > Line 2',
133
+ hq_city: 'Primary location > Locality',
134
+ hq_region: 'Primary location > Region',
135
+ hq_postal_code: 'Primary location > Postcode',
136
+ hq_country: 'Primary location > Country',
105
137
  },
106
138
  people: {
107
139
  name: 'Record',
108
140
  email: 'Email addresses',
109
- location: 'Primary location > Country',
141
+ mailing_line1: 'Primary location > Line 1',
142
+ mailing_line2: 'Primary location > Line 2',
143
+ mailing_city: 'Primary location > Locality',
144
+ mailing_region: 'Primary location > Region',
145
+ mailing_postal_code: 'Primary location > Postcode',
146
+ mailing_country: 'Primary location > Country',
110
147
  company_name: 'Company > Name',
111
148
  title: 'Job title',
112
149
  },
@@ -184,6 +221,9 @@ export function aliasedStageSlug(raw: string): string | undefined {
184
221
  return ALIASES_BY_SQUASHED_NAME.get(squash(raw))
185
222
  }
186
223
 
224
+ /** A file that names a website but not a domain still has a homepage. */
225
+ const DOMAIN_HEADER_ALIASES = new Set(['website', 'website url', 'url'])
226
+
187
227
  /**
188
228
  * The column map to use when a request sends none.
189
229
  *
@@ -214,5 +254,13 @@ export function defaultColumnMap(
214
254
  headers.find((header) => header.toLowerCase() === column.key.toLowerCase()) ?? null
215
255
  }
216
256
 
257
+ if (object === 'companies' && map.domain === null) {
258
+ const alias = headers.find((header) => DOMAIN_HEADER_ALIASES.has(header.toLowerCase()))
259
+
260
+ if (alias !== undefined) {
261
+ map.domain = alias
262
+ }
263
+ }
264
+
217
265
  return map
218
266
  }
@@ -1,6 +1,6 @@
1
1
  import { and, asc, eq, gt, inArray, sql } from 'drizzle-orm'
2
2
 
3
- import type { CustomFieldValue } from '@kelpie/schemas'
3
+ import type { CompanyAddress, CustomFieldValue, PersonAddress } from '@kelpie/schemas'
4
4
  import type { Queryable } from '../../runtime/transaction.ts'
5
5
  import { users } from '../auth/schema.ts'
6
6
  import { companies } from '../companies/schema.ts'
@@ -614,8 +614,7 @@ export interface ExportCompanyRow {
614
614
  readonly description: string
615
615
  readonly summary: string
616
616
  readonly tags: readonly string[]
617
- readonly website: string | null
618
- readonly hq: string | null
617
+ readonly addresses: readonly CompanyAddress[]
619
618
  readonly customFields: Readonly<Record<string, CustomFieldValue>>
620
619
  }
621
620
 
@@ -637,8 +636,7 @@ export function readCompanies(
637
636
  description: companies.description,
638
637
  summary: companies.summary,
639
638
  tags: companies.tags,
640
- website: companies.website,
641
- hq: companies.hq,
639
+ addresses: companies.addresses,
642
640
  customFields: companies.customFields,
643
641
  })
644
642
  .from(companies)
@@ -656,7 +654,7 @@ export interface ExportPersonRow {
656
654
  readonly suffix: string | null
657
655
  readonly email: string | null
658
656
  readonly timezone: string | null
659
- readonly location: string | null
657
+ readonly addresses: readonly PersonAddress[]
660
658
  readonly preferredChannel: string
661
659
  readonly influence: string
662
660
  readonly relationship: string
@@ -687,7 +685,7 @@ export async function readPeople(
687
685
  suffix: people.suffix,
688
686
  email: people.email,
689
687
  timezone: people.timezone,
690
- location: people.location,
688
+ addresses: people.addresses,
691
689
  preferredChannel: people.preferredChannel,
692
690
  influence: people.influence,
693
691
  relationship: people.relationship,
@@ -148,11 +148,12 @@ async function writeCompany(
148
148
  'company',
149
149
  write.draft.customFields,
150
150
  )
151
- const { customFields: _draftCustomFields, tags, ...rest } = write.draft
151
+ const { customFields: _draftCustomFields, tags, addresses, ...rest } = write.draft
152
152
  const created = await companyRepository.insertCompany(tx, {
153
153
  ...NEW_COMPANY_DEFAULTS,
154
154
  ...rest,
155
155
  tags: tags === undefined ? undefined : [...tags],
156
+ addresses: addresses === undefined ? undefined : [...addresses],
156
157
  ...(customFields === undefined ? {} : { customFields }),
157
158
  id: dependencies.createId('company'),
158
159
  workspaceId,
@@ -169,7 +170,7 @@ async function writeCompany(
169
170
  throw AppError.notFound('Company not found')
170
171
  }
171
172
 
172
- const { customFields: draftCustomFields, tags, ...rest } = write.draft
173
+ const { customFields: draftCustomFields, tags, addresses, ...rest } = write.draft
173
174
  const customMerge = await validatedCustomFieldsForUpdate(
174
175
  tx,
175
176
  workspaceId,
@@ -180,6 +181,7 @@ async function writeCompany(
180
181
  const columns = {
181
182
  ...rest,
182
183
  tags: tags === undefined ? undefined : [...tags],
184
+ addresses: addresses === undefined ? undefined : [...addresses],
183
185
  ...(customMerge === undefined ? {} : { customFields: customMerge.merged }),
184
186
  }
185
187
  const changedFields = [
@@ -298,12 +300,13 @@ async function writePerson(
298
300
  'person',
299
301
  write.draft.customFields,
300
302
  )
301
- const { customFields: _draftCustomFields, phones, tags, ...rest } = write.draft
303
+ const { customFields: _draftCustomFields, phones, tags, addresses, ...rest } = write.draft
302
304
  const created = await peopleRepository.insertPerson(tx, {
303
305
  ...NEW_PERSON_DEFAULTS,
304
306
  ...rest,
305
307
  phones: phones === undefined ? undefined : [...phones],
306
308
  tags: tags === undefined ? undefined : [...tags],
309
+ addresses: addresses === undefined ? undefined : [...addresses],
307
310
  ...(customFields === undefined ? {} : { customFields }),
308
311
  id: dependencies.createId('person'),
309
312
  workspaceId,
@@ -332,7 +335,7 @@ async function writePerson(
332
335
  throw AppError.notFound('Person not found')
333
336
  }
334
337
 
335
- const { customFields: draftCustomFields, phones, tags, ...rest } = write.draft
338
+ const { customFields: draftCustomFields, phones, tags, addresses, ...rest } = write.draft
336
339
  const customMerge = await validatedCustomFieldsForUpdate(
337
340
  tx,
338
341
  workspaceId,
@@ -344,6 +347,7 @@ async function writePerson(
344
347
  ...rest,
345
348
  phones: phones === undefined ? undefined : [...phones],
346
349
  tags: tags === undefined ? undefined : [...tags],
350
+ addresses: addresses === undefined ? undefined : [...addresses],
347
351
  ...(customMerge === undefined ? {} : { customFields: customMerge.merged }),
348
352
  }
349
353
  const changedFields = [
@@ -74,6 +74,7 @@ function matchesTerm(term: string): SQL | undefined {
74
74
  ilike(people.email, pattern),
75
75
  ilike(people.summary, pattern),
76
76
  arrayContainsPattern(people.tags, pattern),
77
+ sql`kelpie_addresses_search_text(${people.addresses}) ilike ${pattern}`,
77
78
  heldPositionMatches(pattern),
78
79
  )
79
80
  }
@@ -1,4 +1,4 @@
1
- import { CONSENT_STATUSES, composeName, customFieldsPatchShape } from '@kelpie/schemas'
1
+ import { CONSENT_STATUSES, composeName, customFieldsPatchShape, personAddressesSchema, addressBody } from '@kelpie/schemas'
2
2
  import type { NameParts } from '@kelpie/schemas'
3
3
  import type { Context, Hono } from 'hono'
4
4
  import { z } from 'zod'
@@ -60,7 +60,7 @@ const personShape = {
60
60
  phones: z.array(z.string().min(1)),
61
61
  social_profiles: z.array(socialProfileBody),
62
62
  timezone: z.string().nullable(),
63
- location: z.string().nullable(),
63
+ addresses: personAddressesSchema,
64
64
  preferred_channel: z.enum(PREFERRED_CHANNELS),
65
65
  influence: z.enum(INFLUENCE_LEVELS),
66
66
  relationship: z.enum(RELATIONSHIP_LEVELS),
@@ -95,7 +95,7 @@ export const createBody = z
95
95
  phones: personShape.phones.default([]),
96
96
  social_profiles: personShape.social_profiles.default([]),
97
97
  timezone: personShape.timezone.default(null),
98
- location: personShape.location.default(null),
98
+ addresses: personShape.addresses.default([]),
99
99
  preferred_channel: personShape.preferred_channel.default('email'),
100
100
  influence: personShape.influence.default('influencer'),
101
101
  relationship: personShape.relationship.default('cold'),
@@ -137,7 +137,7 @@ export function toCreateInput(body: z.infer<typeof createBody>): CreatePersonInp
137
137
  phones: body.phones,
138
138
  socialProfiles: body.social_profiles,
139
139
  timezone: body.timezone,
140
- location: body.location,
140
+ addresses: body.addresses,
141
141
  preferredChannel: body.preferred_channel,
142
142
  influence: body.influence,
143
143
  relationship: body.relationship,
@@ -173,7 +173,7 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdatePersonInp
173
173
  ...(body.phones === undefined ? {} : { phones: body.phones }),
174
174
  ...(body.social_profiles === undefined ? {} : { socialProfiles: body.social_profiles }),
175
175
  ...(body.timezone === undefined ? {} : { timezone: body.timezone }),
176
- ...(body.location === undefined ? {} : { location: body.location }),
176
+ ...(body.addresses === undefined ? {} : { addresses: body.addresses }),
177
177
  ...(body.preferred_channel === undefined ? {} : { preferredChannel: body.preferred_channel }),
178
178
  ...(body.influence === undefined ? {} : { influence: body.influence }),
179
179
  ...(body.relationship === undefined ? {} : { relationship: body.relationship }),
@@ -221,7 +221,7 @@ export function personResponse(person: PersonView): Record<string, unknown> {
221
221
  phones: person.phones,
222
222
  social_profiles: person.socialProfiles,
223
223
  timezone: person.timezone,
224
- location: person.location,
224
+ addresses: person.addresses.map(addressBody),
225
225
  preferred_channel: person.preferredChannel,
226
226
  influence: person.influence,
227
227
  relationship: person.relationship,
@@ -5,7 +5,7 @@ import {
5
5
  PREFERRED_CHANNELS,
6
6
  RELATIONSHIP_LEVELS,
7
7
  } from '@kelpie/schemas'
8
- import type { CustomFieldValue, SocialProfile } from '@kelpie/schemas'
8
+ import type { CustomFieldValue, PersonAddress, SocialProfile } from '@kelpie/schemas'
9
9
  import { boolean, index, jsonb, pgTable, primaryKey, text, unique } from 'drizzle-orm/pg-core'
10
10
 
11
11
  import {
@@ -48,9 +48,10 @@ export type { SocialProfile }
48
48
  * Who you know. Job title is not here: it lives on Position, because a person can
49
49
  * hold titles at more than one company.
50
50
  *
51
- * `phones` and `social_profiles` are jsonb because nothing queries into them.
52
- * They are typed rather than left as `unknown`, and the route layer parses what
53
- * goes in, so a row read back is the shape it claims to be.
51
+ * `phones`, `social_profiles`, and `addresses` are jsonb because nothing
52
+ * queries into them. They are typed rather than left as `unknown`, and the
53
+ * route layer parses what goes in, so a row read back is the shape it claims
54
+ * to be.
54
55
  */
55
56
  export const people = pgTable(
56
57
  'people',
@@ -75,7 +76,7 @@ export const people = pgTable(
75
76
  .notNull()
76
77
  .default([]),
77
78
  timezone: text('timezone'),
78
- location: text('location'),
79
+ addresses: jsonb('addresses').$type<readonly PersonAddress[]>().notNull().default([]),
79
80
  preferredChannel: text('preferred_channel').notNull(),
80
81
  influence: text('influence').notNull(),
81
82
  relationship: text('relationship').notNull(),
@@ -110,6 +111,7 @@ export const people = pgTable(
110
111
  { column: people.email, weight: 'B' },
111
112
  { column: people.summary, weight: 'B' },
112
113
  { column: people.tags, weight: 'C', array: true },
114
+ { column: people.addresses, weight: 'C', addresses: true },
113
115
  ]),
114
116
  },
115
117
  (table) => [
@@ -1,4 +1,4 @@
1
- import type { ConsentStatus, CustomFieldWireValue } from '@kelpie/schemas'
1
+ import type { ConsentStatus, CustomFieldWireValue, PersonAddress } from '@kelpie/schemas'
2
2
 
3
3
  import { changedKeys } from '../../lib/changes.ts'
4
4
  import { UNIQUE_VIOLATION, isReferenceViolation, postgresErrorCode } from '../../lib/database.ts'
@@ -19,6 +19,7 @@ import { requireWorkspaceId } from '../auth/actor.ts'
19
19
  import './events.ts'
20
20
  import {
21
21
  deleteRecordsAttachedTo,
22
+ deleteRecordsAttachedToAttendancesOf,
22
23
  deleteRecordsAttachedToCandidaciesOf,
23
24
  } from '../attachedRecords.ts'
24
25
  import type { CustomFieldValuesValidator } from '../custom-fields/values.ts'
@@ -69,7 +70,7 @@ const PERSON_FIELD_LABELS: FieldLabels = {
69
70
  phones: 'Phone numbers',
70
71
  socialProfiles: 'Social profiles',
71
72
  timezone: 'Timezone',
72
- location: 'Location',
73
+ addresses: 'Addresses',
73
74
  preferredChannel: 'Preferred channel',
74
75
  influence: 'Influence',
75
76
  relationship: 'Relationship',
@@ -110,7 +111,7 @@ export interface CreatePersonInput {
110
111
  readonly phones: readonly string[]
111
112
  readonly socialProfiles: readonly SocialProfile[]
112
113
  readonly timezone: string | null
113
- readonly location: string | null
114
+ readonly addresses: readonly PersonAddress[]
114
115
  readonly preferredChannel: PreferredChannel
115
116
  readonly influence: Influence
116
117
  readonly relationship: Relationship
@@ -161,7 +162,7 @@ function toStoredColumns(input: UpdatePersonInput): Partial<repository.PersonCol
161
162
  ...(input.phones === undefined ? {} : { phones: input.phones }),
162
163
  ...(input.socialProfiles === undefined ? {} : { socialProfiles: input.socialProfiles }),
163
164
  ...(input.timezone === undefined ? {} : { timezone: input.timezone }),
164
- ...(input.location === undefined ? {} : { location: input.location }),
165
+ ...(input.addresses === undefined ? {} : { addresses: input.addresses }),
165
166
  ...(input.preferredChannel === undefined ? {} : { preferredChannel: input.preferredChannel }),
166
167
  ...(input.influence === undefined ? {} : { influence: input.influence }),
167
168
  ...(input.relationship === undefined ? {} : { relationship: input.relationship }),
@@ -241,7 +242,7 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
241
242
  phones: input.phones,
242
243
  socialProfiles: input.socialProfiles,
243
244
  timezone: input.timezone,
244
- location: input.location,
245
+ addresses: input.addresses,
245
246
  preferredChannel: input.preferredChannel,
246
247
  influence: input.influence,
247
248
  relationship: input.relationship,
@@ -421,6 +422,7 @@ export function createPeopleService(dependencies: PeopleDependencies): PeopleSer
421
422
  // The candidacy rows themselves cascade, which is why their interview
422
423
  // notes have to be taken here: no hiring service sees that delete.
423
424
  await deleteRecordsAttachedToCandidaciesOf(tx, workspaceId, id)
425
+ await deleteRecordsAttachedToAttendancesOf(tx, workspaceId, { personId: id })
424
426
 
425
427
  // A person delete failing on a foreign key aborts the enclosing
426
428
  // transaction, so the follow-up read that names the referring pipeline
@@ -11,7 +11,7 @@ import type { ListWindow, SortableFields } from '../../lib/pagination.ts'
11
11
  import type { Queryable } from '../../runtime/transaction.ts'
12
12
  import { workspaceMembers } from '../workspace/schema.ts'
13
13
  import { planItems } from './schema.ts'
14
- import type { PipelineKind, PlanItemStatus } from './schema.ts'
14
+ import type { PlanItemStatus, PlanItemTargetType } from './schema.ts'
15
15
 
16
16
  export type PlanItemRecord = typeof planItems.$inferSelect
17
17
 
@@ -39,7 +39,7 @@ export const DEFAULT_PLAN_ITEM_SORT = 'date'
39
39
 
40
40
  export interface PlanItemFilters {
41
41
  /** `?target_type=`: one pipeline. The Planning page's type filter. */
42
- readonly targetType?: PipelineKind | undefined
42
+ readonly targetType?: PlanItemTargetType | undefined
43
43
  /** `?target_id=`, repeatable: one record's panel, or a page of records' next steps. */
44
44
  readonly targetIds?: readonly string[] | undefined
45
45
  /** `?status=`, repeatable. Naming the two open ones is how a caller asks for outstanding work. */
@@ -8,8 +8,8 @@ import type { Actor } from '../auth/actor.ts'
8
8
  import { resolveActorFrom } from '../auth/credentials.ts'
9
9
  import type { CredentialDependencies } from '../auth/credentials.ts'
10
10
  import type { PlanItemFilters } from './repository.ts'
11
- import { PIPELINE_KINDS, PLAN_ITEM_STATUSES } from './schema.ts'
12
- import type { PipelineKind, PlanItemStatus } from './schema.ts'
11
+ import { PLAN_ITEM_STATUSES, PLAN_ITEM_TARGET_TYPES } from './schema.ts'
12
+ import type { PlanItemStatus, PlanItemTargetType } from './schema.ts'
13
13
  import type {
14
14
  CreatePlanItemInput,
15
15
  PlanItemView,
@@ -40,7 +40,7 @@ const planItemShape = {
40
40
  */
41
41
  export const createBody = z.strictObject({
42
42
  ...planItemShape,
43
- target_type: z.enum(PIPELINE_KINDS),
43
+ target_type: z.enum(PLAN_ITEM_TARGET_TYPES),
44
44
  target_id: z.string().min(1),
45
45
  owner_id: planItemShape.owner_id.default(null),
46
46
  status: planItemShape.status.default('todo'),
@@ -94,18 +94,18 @@ export function toUpdateInput(body: z.infer<typeof updateBody>): UpdatePlanItemI
94
94
  * cannot attach to a Person, so answering the person question with an empty
95
95
  * list would read as "none yet" instead of "that is not a thing".
96
96
  */
97
- function readTargetType(context: Context): PipelineKind | undefined {
97
+ function readTargetType(context: Context): PlanItemTargetType | undefined {
98
98
  const raw = context.req.query('target_type')
99
99
 
100
100
  if (raw === undefined) {
101
101
  return undefined
102
102
  }
103
103
 
104
- const parsed = z.enum(PIPELINE_KINDS).safeParse(raw)
104
+ const parsed = z.enum(PLAN_ITEM_TARGET_TYPES).safeParse(raw)
105
105
 
106
106
  if (!parsed.success) {
107
107
  throw AppError.validationFailed('That is not a record type a plan item attaches to', [
108
- { field: 'target_type', message: `Use one of: ${PIPELINE_KINDS.join(', ')}` },
108
+ { field: 'target_type', message: `Use one of: ${PLAN_ITEM_TARGET_TYPES.join(', ')}` },
109
109
  ])
110
110
  }
111
111
 
@@ -1,4 +1,4 @@
1
- import { PIPELINE_KINDS, PLAN_ITEM_STATUSES } from '@kelpie/schemas'
1
+ import { PLAN_ITEM_STATUSES, PLAN_ITEM_TARGET_TYPES } from '@kelpie/schemas'
2
2
  import { date, index, pgTable, text } from 'drizzle-orm/pg-core'
3
3
 
4
4
  import { checkOneOf, createdAt, primaryId, searchVector, updatedAt } from '../../lib/columns.ts'
@@ -6,8 +6,8 @@ import type { SearchVectorPart } from '../../lib/columns.ts'
6
6
  import { workspaceMembers, workspaces } from '../workspace/schema.ts'
7
7
 
8
8
  /** Re-exported for the routes and service that constrain themselves to this table. */
9
- export { PIPELINE_KINDS, PLAN_ITEM_STATUSES } from '@kelpie/schemas'
10
- export type { PipelineKind, PlanItemStatus } from '@kelpie/schemas'
9
+ export { PLAN_ITEM_STATUSES, PLAN_ITEM_TARGET_TYPES } from '@kelpie/schemas'
10
+ export type { PlanItemStatus, PlanItemTargetType } from '@kelpie/schemas'
11
11
 
12
12
  /**
13
13
  * Dated action items on the four pipelines. These replace any next-step text
@@ -39,7 +39,7 @@ export const planItems = pgTable(
39
39
  index('plan_items_target_idx').on(table.workspaceId, table.targetType, table.targetId),
40
40
  index('plan_items_date_idx').on(table.workspaceId, table.date),
41
41
  index('plan_items_search_idx').using('gin', table.searchVector),
42
- checkOneOf('plan_items_target_type_check', table.targetType, PIPELINE_KINDS),
42
+ checkOneOf('plan_items_target_type_check', table.targetType, PLAN_ITEM_TARGET_TYPES),
43
43
  checkOneOf('plan_items_status_check', table.status, PLAN_ITEM_STATUSES),
44
44
  ],
45
45
  )
@@ -13,7 +13,7 @@ import { targetExists } from '../recordTargets.ts'
13
13
  import * as repository from './repository.ts'
14
14
  import { DEFAULT_PLAN_ITEM_SORT, PLAN_ITEM_SORTS } from './repository.ts'
15
15
  import type { PlanItemFilters, PlanItemRecord } from './repository.ts'
16
- import type { PipelineKind, PlanItemStatus } from './schema.ts'
16
+ import type { PlanItemStatus, PlanItemTargetType } from './schema.ts'
17
17
 
18
18
  /**
19
19
  * Plan items: the dated next steps on a Deal, Opportunity, Raise or Partnership.
@@ -39,7 +39,7 @@ export interface PlansDependencies {
39
39
  export type PlanItemView = Omit<PlanItemRecord, 'workspaceId'>
40
40
 
41
41
  export interface CreatePlanItemInput {
42
- readonly targetType: PipelineKind
42
+ readonly targetType: PlanItemTargetType
43
43
  readonly targetId: string
44
44
  /** `YYYY-MM-DD`. Validated as a real calendar date at the boundary. */
45
45
  readonly date: string
@@ -94,7 +94,7 @@ export function createPlansService(dependencies: PlansDependencies): PlansServic
94
94
 
95
95
  async function requireTarget(
96
96
  workspaceId: string,
97
- targetType: PipelineKind,
97
+ targetType: PlanItemTargetType,
98
98
  targetId: string,
99
99
  ): Promise<void> {
100
100
  if (!(await targetExists(dependencies.db, workspaceId, targetType, targetId))) {
@@ -1,4 +1,4 @@
1
- import { PIPELINE_KINDS, PLAN_ITEM_STATUSES } from '@kelpie/schemas'
1
+ import { PLAN_ITEM_STATUSES, PLAN_ITEM_TARGET_TYPES } from '@kelpie/schemas'
2
2
  import { isoDateSchema } from '../../lib/dates.ts'
3
3
  import { z } from 'zod'
4
4
 
@@ -11,7 +11,7 @@ import type { PlansService } from './service.ts'
11
11
 
12
12
  const listArgs = z.strictObject({
13
13
  ...listWindowShape,
14
- target_type: z.enum(PIPELINE_KINDS).optional().describe('One pipeline\'s plan items.'),
14
+ target_type: z.enum(PLAN_ITEM_TARGET_TYPES).optional().describe("One target type's plan items."),
15
15
  target_id: idSetArg.optional().describe('The plan items on these records.'),
16
16
  status: enumSetArg(PLAN_ITEM_STATUSES)
17
17
  .optional()
@@ -5,6 +5,7 @@ import type { Queryable } from '../runtime/transaction.ts'
5
5
  import { companies } from './companies/schema.ts'
6
6
  import { deals } from './deals/schema.ts'
7
7
  import { enquiries } from './enquiries/schema.ts'
8
+ import { attendances, events } from './events/schema.ts'
8
9
  import { candidates } from './hiring/schema.ts'
9
10
  import { RECORD_TARGET_TYPES } from './notes/schema.ts'
10
11
  import { opportunities } from './opportunities/schema.ts'
@@ -67,6 +68,8 @@ const TABLES: Readonly<Record<RecordTargetType, TargetTable>> = {
67
68
  raise: targetTable(raises, raises.id, raises.workspaceId, raises.name),
68
69
  enquiry: targetTable(enquiries, enquiries.id, enquiries.workspaceId, enquiries.name),
69
70
  candidate: targetTable(candidates, candidates.id, candidates.workspaceId),
71
+ event: targetTable(events, events.id, events.workspaceId, events.name),
72
+ attendance: targetTable(attendances, attendances.id, attendances.workspaceId),
70
73
  }
71
74
 
72
75
  export function isRecordTargetType(value: string): value is RecordTargetType {
@@ -141,7 +144,18 @@ async function namesOfType(
141
144
  // A Candidate's label is the person's name. The role it is for is the other
142
145
  // half of the answer, but a timeline row already says which record it is on,
143
146
  // so repeating the title in the name would read as "Ada Lovelace" twice over.
147
+ // An Attendance is the same shape: Person↔Event, labelled by the person.
144
148
  if (target.name === undefined) {
149
+ if (targetType === 'attendance') {
150
+ return db
151
+ .select({ id: attendances.id, name: people.name })
152
+ .from(attendances)
153
+ .innerJoin(people, eq(attendances.personId, people.id))
154
+ .where(
155
+ and(eq(attendances.workspaceId, workspaceId), inArray(attendances.id, [...targetIds])),
156
+ )
157
+ }
158
+
145
159
  return db
146
160
  .select({ id: candidates.id, name: people.name })
147
161
  .from(candidates)
@@ -23,6 +23,8 @@ import { AppError } from '../lib/errors.ts'
23
23
  */
24
24
  const REFERENCING_TYPE_BY_TABLE: Readonly<Record<string, string>> = {
25
25
  candidates: 'candidate',
26
+ events: 'event',
27
+ attendances: 'attendance',
26
28
  deals: 'deal',
27
29
  enquiries: 'enquiry',
28
30
  form_submissions: 'form submission',