@dakkitor/api-contracts 1.1.153 → 1.4.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 (340) hide show
  1. package/dist/abilities/abilities.contract.d.ts +53 -1
  2. package/dist/abilities/abilities.contract.d.ts.map +1 -1
  3. package/dist/abilities/abilities.contract.js +92 -1
  4. package/dist/abilities/abilities.contract.spec.d.ts +2 -0
  5. package/dist/abilities/abilities.contract.spec.d.ts.map +1 -0
  6. package/dist/abilities/abilities.contract.spec.js +145 -0
  7. package/dist/abilities/admin-dashboard.abilities.test.d.ts +2 -0
  8. package/dist/abilities/admin-dashboard.abilities.test.d.ts.map +1 -0
  9. package/dist/abilities/admin-dashboard.abilities.test.js +33 -0
  10. package/dist/abilities/admin.abilities.json +19 -0
  11. package/dist/abilities/bot.abilities.json +13 -4
  12. package/dist/abilities/first-agent.abilities.json +317 -70
  13. package/dist/abilities/interconnection.abilities.json +75 -0
  14. package/dist/abilities/kpi.abilities.json +68 -0
  15. package/dist/abilities/office-manager.abilities.json +111 -0
  16. package/dist/abilities/second-agent.abilities.json +417 -43
  17. package/dist/abilities/team-leads.json +71 -6
  18. package/dist/abilities/worker-curator.abilities.json +233 -0
  19. package/dist/actives/actives.contract.d.ts +19379 -23651
  20. package/dist/actives/actives.contract.d.ts.map +1 -1
  21. package/dist/actives/actives.contract.js +517 -114
  22. package/dist/agent-client-links/agent-client-links.contract.d.ts +1431 -291
  23. package/dist/agent-client-links/agent-client-links.contract.d.ts.map +1 -1
  24. package/dist/auth/auth.contract.d.ts +1050 -81
  25. package/dist/auth/auth.contract.d.ts.map +1 -1
  26. package/dist/auth/auth.contract.js +115 -3
  27. package/dist/bookings/booking-worker-summary.spec.d.ts +2 -0
  28. package/dist/bookings/booking-worker-summary.spec.d.ts.map +1 -0
  29. package/dist/bookings/booking-worker-summary.spec.js +25 -0
  30. package/dist/bookings/bookings.contract.d.ts +20643 -26117
  31. package/dist/bookings/bookings.contract.d.ts.map +1 -1
  32. package/dist/bookings/bookings.contract.js +383 -91
  33. package/dist/bookings/bookings.contract.spec.d.ts +2 -0
  34. package/dist/bookings/bookings.contract.spec.d.ts.map +1 -0
  35. package/dist/bookings/bookings.contract.spec.js +11 -0
  36. package/dist/bookings/job-lock.spec.d.ts +2 -0
  37. package/dist/bookings/job-lock.spec.d.ts.map +1 -0
  38. package/dist/bookings/job-lock.spec.js +56 -0
  39. package/dist/bot-parse-cache/bot-parse-cache.contract.d.ts +232 -0
  40. package/dist/bot-parse-cache/bot-parse-cache.contract.d.ts.map +1 -0
  41. package/dist/bot-parse-cache/bot-parse-cache.contract.js +64 -0
  42. package/dist/call-history/call-history.contract.d.ts +1336 -767
  43. package/dist/call-history/call-history.contract.d.ts.map +1 -1
  44. package/dist/call-history/call-history.contract.js +86 -10
  45. package/dist/calls-feed/calls-feed.contract.d.ts +417 -0
  46. package/dist/calls-feed/calls-feed.contract.d.ts.map +1 -0
  47. package/dist/calls-feed/calls-feed.contract.js +32 -0
  48. package/dist/client-contacts/client-contacts.contract.d.ts +410 -226
  49. package/dist/client-contacts/client-contacts.contract.d.ts.map +1 -1
  50. package/dist/client-contacts/client-contacts.contract.js +35 -4
  51. package/dist/clients/clients.contract.d.ts +227 -73
  52. package/dist/clients/clients.contract.d.ts.map +1 -1
  53. package/dist/clients/clients.contract.js +45 -21
  54. package/dist/collaboration-checkings/collaboration-checkings.contract.d.ts +2908 -1834
  55. package/dist/collaboration-checkings/collaboration-checkings.contract.d.ts.map +1 -1
  56. package/dist/collaboration-checkings/collaboration-checkings.contract.js +14 -9
  57. package/dist/collaborations/collaborations.contract.d.ts +2676 -1409
  58. package/dist/collaborations/collaborations.contract.d.ts.map +1 -1
  59. package/dist/collaborations/collaborations.contract.js +33 -9
  60. package/dist/common/call-rating.schema.d.ts.map +1 -1
  61. package/dist/common/call-rating.schema.js +4 -2
  62. package/dist/common/common-schemas.d.ts +59 -11
  63. package/dist/common/common-schemas.d.ts.map +1 -1
  64. package/dist/common/common-schemas.js +55 -29
  65. package/dist/common/error-schemas.d.ts +2 -2
  66. package/dist/common/pagination-query.schema.d.ts +13 -2
  67. package/dist/common/pagination-query.schema.d.ts.map +1 -1
  68. package/dist/common/pagination-query.schema.js +21 -2
  69. package/dist/common/pagination-query.schema.spec.d.ts +2 -0
  70. package/dist/common/pagination-query.schema.spec.d.ts.map +1 -0
  71. package/dist/common/pagination-query.schema.spec.js +53 -0
  72. package/dist/companies/companies.contract.d.ts +53 -28
  73. package/dist/companies/companies.contract.d.ts.map +1 -1
  74. package/dist/companies/companies.contract.js +11 -10
  75. package/dist/crews/crews.contract.d.ts +1010 -196
  76. package/dist/crews/crews.contract.d.ts.map +1 -1
  77. package/dist/crews/crews.contract.js +98 -17
  78. package/dist/crews/crews.contract.spec.d.ts +2 -0
  79. package/dist/crews/crews.contract.spec.d.ts.map +1 -0
  80. package/dist/crews/crews.contract.spec.js +67 -0
  81. package/dist/cron-executions/cron-executions.contract.d.ts +988 -59
  82. package/dist/cron-executions/cron-executions.contract.d.ts.map +1 -1
  83. package/dist/cron-executions/cron-executions.contract.js +127 -7
  84. package/dist/curated-worker-leads/__tests__/disposition-reason.spec.d.ts +2 -0
  85. package/dist/curated-worker-leads/__tests__/disposition-reason.spec.d.ts.map +1 -0
  86. package/dist/curated-worker-leads/__tests__/disposition-reason.spec.js +40 -0
  87. package/dist/curated-worker-leads/candidate-coordination-snapshot.spec.d.ts +2 -0
  88. package/dist/curated-worker-leads/candidate-coordination-snapshot.spec.d.ts.map +1 -0
  89. package/dist/curated-worker-leads/candidate-coordination-snapshot.spec.js +16 -0
  90. package/dist/curated-worker-leads/candidate-coordination.contract.d.ts +21650 -0
  91. package/dist/curated-worker-leads/candidate-coordination.contract.d.ts.map +1 -0
  92. package/dist/curated-worker-leads/candidate-coordination.contract.js +921 -0
  93. package/dist/curated-worker-leads/candidate-coordination.contract.spec.d.ts +2 -0
  94. package/dist/curated-worker-leads/candidate-coordination.contract.spec.d.ts.map +1 -0
  95. package/dist/curated-worker-leads/candidate-coordination.contract.spec.js +51 -0
  96. package/dist/curated-worker-leads/candidate-edit-session.contract.d.ts +2364 -0
  97. package/dist/curated-worker-leads/candidate-edit-session.contract.d.ts.map +1 -0
  98. package/dist/curated-worker-leads/candidate-edit-session.contract.js +173 -0
  99. package/dist/curated-worker-leads/consent-queue.contract.d.ts +4497 -0
  100. package/dist/curated-worker-leads/consent-queue.contract.d.ts.map +1 -0
  101. package/dist/curated-worker-leads/consent-queue.contract.js +201 -0
  102. package/dist/curated-worker-leads/contact-history.spec.d.ts +2 -0
  103. package/dist/curated-worker-leads/contact-history.spec.d.ts.map +1 -0
  104. package/dist/curated-worker-leads/contact-history.spec.js +88 -0
  105. package/dist/curated-worker-leads/contact-session.contract.spec.d.ts +2 -0
  106. package/dist/curated-worker-leads/contact-session.contract.spec.d.ts.map +1 -0
  107. package/dist/curated-worker-leads/contact-session.contract.spec.js +315 -0
  108. package/dist/curated-worker-leads/curated-worker-lead-config.contract.d.ts +489 -0
  109. package/dist/curated-worker-leads/curated-worker-lead-config.contract.d.ts.map +1 -0
  110. package/dist/curated-worker-leads/curated-worker-lead-config.contract.js +88 -0
  111. package/dist/curated-worker-leads/curated-worker-leads.contract.d.ts +135 -0
  112. package/dist/curated-worker-leads/curated-worker-leads.contract.d.ts.map +1 -0
  113. package/dist/curated-worker-leads/curated-worker-leads.contract.js +32 -0
  114. package/dist/curated-worker-leads/job-candidate-cards.spec.d.ts +2 -0
  115. package/dist/curated-worker-leads/job-candidate-cards.spec.d.ts.map +1 -0
  116. package/dist/curated-worker-leads/job-candidate-cards.spec.js +157 -0
  117. package/dist/curated-worker-leads/job-candidates.spec.d.ts +2 -0
  118. package/dist/curated-worker-leads/job-candidates.spec.d.ts.map +1 -0
  119. package/dist/curated-worker-leads/job-candidates.spec.js +140 -0
  120. package/dist/curated-worker-leads/job-feed-match-counts.contract.spec.d.ts +2 -0
  121. package/dist/curated-worker-leads/job-feed-match-counts.contract.spec.d.ts.map +1 -0
  122. package/dist/curated-worker-leads/job-feed-match-counts.contract.spec.js +19 -0
  123. package/dist/curated-worker-leads/jobs-tab.contract.d.ts +18365 -0
  124. package/dist/curated-worker-leads/jobs-tab.contract.d.ts.map +1 -0
  125. package/dist/curated-worker-leads/jobs-tab.contract.js +642 -0
  126. package/dist/curated-worker-leads/lead-agent-area.contract.d.ts +348 -0
  127. package/dist/curated-worker-leads/lead-agent-area.contract.d.ts.map +1 -0
  128. package/dist/curated-worker-leads/lead-agent-area.contract.js +51 -0
  129. package/dist/curated-worker-leads/owned-jobs-tab.contract.d.ts +1116 -0
  130. package/dist/curated-worker-leads/owned-jobs-tab.contract.d.ts.map +1 -0
  131. package/dist/curated-worker-leads/owned-jobs-tab.contract.js +93 -0
  132. package/dist/curated-workers/curated-filter-additions.spec.d.ts +2 -0
  133. package/dist/curated-workers/curated-filter-additions.spec.d.ts.map +1 -0
  134. package/dist/curated-workers/curated-filter-additions.spec.js +17 -0
  135. package/dist/curated-workers/curated-job-seeking.spec.d.ts +2 -0
  136. package/dist/curated-workers/curated-job-seeking.spec.d.ts.map +1 -0
  137. package/dist/curated-workers/curated-job-seeking.spec.js +53 -0
  138. package/dist/curated-workers/curated-workers-id-documents.spec.d.ts +2 -0
  139. package/dist/curated-workers/curated-workers-id-documents.spec.d.ts.map +1 -0
  140. package/dist/curated-workers/curated-workers-id-documents.spec.js +38 -0
  141. package/dist/curated-workers/curated-workers.contract.d.ts +6160 -1906
  142. package/dist/curated-workers/curated-workers.contract.d.ts.map +1 -1
  143. package/dist/curated-workers/curated-workers.contract.js +333 -51
  144. package/dist/dashboards/agent-daily-metrics.contract.d.ts +10 -10
  145. package/dist/dashboards/agent-daily-metrics.contract.js +1 -1
  146. package/dist/dashboards/dashboard-widgets.contract.d.ts +3800 -496
  147. package/dist/dashboards/dashboard-widgets.contract.d.ts.map +1 -1
  148. package/dist/dashboards/dashboard-widgets.contract.js +527 -29
  149. package/dist/dashboards/dashboard.contract.d.ts +8 -8
  150. package/dist/document-intake/document-intake.contract.d.ts +3132 -0
  151. package/dist/document-intake/document-intake.contract.d.ts.map +1 -0
  152. package/dist/document-intake/document-intake.contract.js +418 -0
  153. package/dist/export-jobs/export-jobs.contract.d.ts +3918 -0
  154. package/dist/export-jobs/export-jobs.contract.d.ts.map +1 -0
  155. package/dist/export-jobs/export-jobs.contract.js +240 -0
  156. package/dist/exports-events/exports-events.schemas.d.ts +90 -0
  157. package/dist/exports-events/exports-events.schemas.d.ts.map +1 -0
  158. package/dist/exports-events/exports-events.schemas.js +56 -0
  159. package/dist/files/files.contract.d.ts +133 -126
  160. package/dist/files/files.contract.d.ts.map +1 -1
  161. package/dist/files/files.contract.js +8 -0
  162. package/dist/health/health.contract.d.ts +4 -4
  163. package/dist/index.d.ts +82 -0
  164. package/dist/index.d.ts.map +1 -1
  165. package/dist/index.js +87 -1
  166. package/dist/interactions/interactions.contract.d.ts +162 -0
  167. package/dist/interactions/interactions.contract.d.ts.map +1 -0
  168. package/dist/interactions/interactions.contract.js +42 -0
  169. package/dist/job-clusters/job-clusters.contract.d.ts +1584 -0
  170. package/dist/job-clusters/job-clusters.contract.d.ts.map +1 -0
  171. package/dist/job-clusters/job-clusters.contract.js +133 -0
  172. package/dist/jobs/jobs.contract.d.ts +16517 -8495
  173. package/dist/jobs/jobs.contract.d.ts.map +1 -1
  174. package/dist/jobs/jobs.contract.js +394 -190
  175. package/dist/jobs/jobs.contract.spec.d.ts +2 -0
  176. package/dist/jobs/jobs.contract.spec.d.ts.map +1 -0
  177. package/dist/jobs/jobs.contract.spec.js +70 -0
  178. package/dist/kpi-impersonation/kpi-impersonation.contract.d.ts +75 -75
  179. package/dist/lead-assignments/lead-assignments.contract.d.ts +2933 -1122
  180. package/dist/lead-assignments/lead-assignments.contract.d.ts.map +1 -1
  181. package/dist/lead-assignments/lead-assignments.contract.js +29 -7
  182. package/dist/lead-distribution/agent-lead-distribution.contract.d.ts +328 -64
  183. package/dist/lead-distribution/agent-lead-distribution.contract.d.ts.map +1 -1
  184. package/dist/lead-distribution/agent-lead-distribution.contract.js +1 -1
  185. package/dist/lead-distribution/lead-distribution-config.contract.d.ts +31 -31
  186. package/dist/leads/leads.contract.d.ts +830 -368
  187. package/dist/leads/leads.contract.d.ts.map +1 -1
  188. package/dist/leads/leads.contract.js +106 -26
  189. package/dist/locations/locations.contract.d.ts +36 -36
  190. package/dist/notifications/notifications.contract.d.ts +1039 -0
  191. package/dist/notifications/notifications.contract.d.ts.map +1 -0
  192. package/dist/notifications/notifications.contract.js +110 -0
  193. package/dist/offices/offices.contract.d.ts +210 -60
  194. package/dist/offices/offices.contract.d.ts.map +1 -1
  195. package/dist/offices/offices.contract.js +18 -4
  196. package/dist/outreach/__tests__/outreach-claim.test.d.ts +2 -0
  197. package/dist/outreach/__tests__/outreach-claim.test.d.ts.map +1 -0
  198. package/dist/outreach/__tests__/outreach-claim.test.js +97 -0
  199. package/dist/outreach/__tests__/outreach-confirm-release.test.d.ts +2 -0
  200. package/dist/outreach/__tests__/outreach-confirm-release.test.d.ts.map +1 -0
  201. package/dist/outreach/__tests__/outreach-confirm-release.test.js +98 -0
  202. package/dist/outreach/__tests__/outreach-routes.test.d.ts +2 -0
  203. package/dist/outreach/__tests__/outreach-routes.test.d.ts.map +1 -0
  204. package/dist/outreach/__tests__/outreach-routes.test.js +57 -0
  205. package/dist/outreach/__tests__/outreach.schemas.test.d.ts +2 -0
  206. package/dist/outreach/__tests__/outreach.schemas.test.d.ts.map +1 -0
  207. package/dist/outreach/__tests__/outreach.schemas.test.js +140 -0
  208. package/dist/outreach/outreach.contract.d.ts +809 -0
  209. package/dist/outreach/outreach.contract.d.ts.map +1 -0
  210. package/dist/outreach/outreach.contract.js +195 -0
  211. package/dist/outreach/outreach.schemas.d.ts +113 -0
  212. package/dist/outreach/outreach.schemas.d.ts.map +1 -0
  213. package/dist/outreach/outreach.schemas.js +132 -0
  214. package/dist/own-research/own-research.contract.d.ts +1356 -552
  215. package/dist/own-research/own-research.contract.d.ts.map +1 -1
  216. package/dist/own-research/own-research.contract.js +14 -3
  217. package/dist/postcodes/postcodes.contract.d.ts +16 -16
  218. package/dist/proofs/proof-category.enum.d.ts +4 -0
  219. package/dist/proofs/proof-category.enum.d.ts.map +1 -0
  220. package/dist/proofs/proof-category.enum.js +5 -0
  221. package/dist/proofs/proof-entity-type.enum.d.ts +4 -0
  222. package/dist/proofs/proof-entity-type.enum.d.ts.map +1 -0
  223. package/dist/proofs/proof-entity-type.enum.js +5 -0
  224. package/dist/proofs/proof-type.enum.d.ts +28 -0
  225. package/dist/proofs/proof-type.enum.d.ts.map +1 -0
  226. package/dist/proofs/proof-type.enum.js +14 -0
  227. package/dist/proofs/proofs.contract.d.ts +3009 -0
  228. package/dist/proofs/proofs.contract.d.ts.map +1 -0
  229. package/dist/proofs/proofs.contract.js +92 -0
  230. package/dist/proofs/proofs.dtos.d.ts +1319 -0
  231. package/dist/proofs/proofs.dtos.d.ts.map +1 -0
  232. package/dist/proofs/proofs.dtos.js +178 -0
  233. package/dist/qualifications/qualifications.contract.d.ts +94 -94
  234. package/dist/realtime/data-changed.d.ts +21 -0
  235. package/dist/realtime/data-changed.d.ts.map +1 -0
  236. package/dist/realtime/data-changed.js +37 -0
  237. package/dist/shared/booking-history.schema.d.ts +27 -0
  238. package/dist/shared/booking-history.schema.d.ts.map +1 -0
  239. package/dist/shared/booking-history.schema.js +22 -0
  240. package/dist/shared/booking-history.spec.d.ts +2 -0
  241. package/dist/shared/booking-history.spec.d.ts.map +1 -0
  242. package/dist/shared/booking-history.spec.js +44 -0
  243. package/dist/shared/contact-suppressions.contract.d.ts +22 -0
  244. package/dist/shared/contact-suppressions.contract.d.ts.map +1 -0
  245. package/dist/shared/contact-suppressions.contract.js +13 -0
  246. package/dist/shared/live-booking.schema.d.ts +57 -0
  247. package/dist/shared/live-booking.schema.d.ts.map +1 -0
  248. package/dist/shared/live-booking.schema.js +34 -0
  249. package/dist/shared/summary-schemas.d.ts +218 -0
  250. package/dist/shared/summary-schemas.d.ts.map +1 -0
  251. package/dist/shared/summary-schemas.js +56 -0
  252. package/dist/sheets-sync/__tests__/sheets-sync-events.schemas.test.d.ts +2 -0
  253. package/dist/sheets-sync/__tests__/sheets-sync-events.schemas.test.d.ts.map +1 -0
  254. package/dist/sheets-sync/__tests__/sheets-sync-events.schemas.test.js +20 -0
  255. package/dist/sheets-sync/__tests__/tab-sync-config.schema.test.d.ts +2 -0
  256. package/dist/sheets-sync/__tests__/tab-sync-config.schema.test.d.ts.map +1 -0
  257. package/dist/sheets-sync/__tests__/tab-sync-config.schema.test.js +41 -0
  258. package/dist/sheets-sync/sheets-sync-events.schemas.d.ts +43 -0
  259. package/dist/sheets-sync/sheets-sync-events.schemas.d.ts.map +1 -0
  260. package/dist/sheets-sync/sheets-sync-events.schemas.js +29 -0
  261. package/dist/sheets-sync/sheets-sync.contract.d.ts +7258 -0
  262. package/dist/sheets-sync/sheets-sync.contract.d.ts.map +1 -0
  263. package/dist/sheets-sync/sheets-sync.contract.js +323 -0
  264. package/dist/telegram/telegram.contract.d.ts +727 -0
  265. package/dist/telegram/telegram.contract.d.ts.map +1 -0
  266. package/dist/telegram/telegram.contract.js +75 -0
  267. package/dist/trades/trade-rate-assessment.d.ts +18 -0
  268. package/dist/trades/trade-rate-assessment.d.ts.map +1 -0
  269. package/dist/trades/trade-rate-assessment.js +46 -0
  270. package/dist/trades/trade-rate-assessment.spec.d.ts +2 -0
  271. package/dist/trades/trade-rate-assessment.spec.d.ts.map +1 -0
  272. package/dist/trades/trade-rate-assessment.spec.js +223 -0
  273. package/dist/trades/trades.contract.d.ts +111 -0
  274. package/dist/trades/trades.contract.d.ts.map +1 -1
  275. package/dist/trades/trades.contract.js +49 -1
  276. package/dist/trades/trades.contract.spec.d.ts +2 -0
  277. package/dist/trades/trades.contract.spec.d.ts.map +1 -0
  278. package/dist/trades/trades.contract.spec.js +173 -0
  279. package/dist/user-access-grants/build-user-access-grant-rules.d.ts +10 -0
  280. package/dist/user-access-grants/build-user-access-grant-rules.d.ts.map +1 -0
  281. package/dist/user-access-grants/build-user-access-grant-rules.js +69 -0
  282. package/dist/user-access-grants/build-user-access-grant-rules.spec.d.ts +2 -0
  283. package/dist/user-access-grants/build-user-access-grant-rules.spec.d.ts.map +1 -0
  284. package/dist/user-access-grants/build-user-access-grant-rules.spec.js +77 -0
  285. package/dist/user-access-grants/user-access-grant-templates.json +454 -0
  286. package/dist/user-access-grants/user-access-grants.contract.d.ts +3886 -0
  287. package/dist/user-access-grants/user-access-grants.contract.d.ts.map +1 -0
  288. package/dist/user-access-grants/user-access-grants.contract.js +189 -0
  289. package/dist/user-access-grants/user-access-grants.contract.spec.d.ts +2 -0
  290. package/dist/user-access-grants/user-access-grants.contract.spec.d.ts.map +1 -0
  291. package/dist/user-access-grants/user-access-grants.contract.spec.js +149 -0
  292. package/dist/users/users.contract.d.ts +1959 -349
  293. package/dist/users/users.contract.d.ts.map +1 -1
  294. package/dist/users/users.contract.js +222 -37
  295. package/dist/users/users.contract.spec.d.ts +2 -0
  296. package/dist/users/users.contract.spec.d.ts.map +1 -0
  297. package/dist/users/users.contract.spec.js +103 -0
  298. package/dist/worker-identity-cases/worker-identity-cases.contract.d.ts +4609 -0
  299. package/dist/worker-identity-cases/worker-identity-cases.contract.d.ts.map +1 -0
  300. package/dist/worker-identity-cases/worker-identity-cases.contract.js +409 -0
  301. package/dist/worker-merge-proposals/worker-merge-proposals.contract.d.ts +1511 -0
  302. package/dist/worker-merge-proposals/worker-merge-proposals.contract.d.ts.map +1 -0
  303. package/dist/worker-merge-proposals/worker-merge-proposals.contract.js +150 -0
  304. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.contract.d.ts +1106 -0
  305. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.contract.d.ts.map +1 -0
  306. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.contract.js +85 -0
  307. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.contract.spec.d.ts +2 -0
  308. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.contract.spec.d.ts.map +1 -0
  309. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.contract.spec.js +216 -0
  310. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.schemas.d.ts +453 -0
  311. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.schemas.d.ts.map +1 -0
  312. package/dist/worker-source-identity-conflicts/worker-source-identity-conflicts.schemas.js +109 -0
  313. package/dist/workers/do-not-contact.contract.d.ts +46 -0
  314. package/dist/workers/do-not-contact.contract.d.ts.map +1 -0
  315. package/dist/workers/do-not-contact.contract.js +41 -0
  316. package/dist/workers/do-not-contact.contract.spec.d.ts +2 -0
  317. package/dist/workers/do-not-contact.contract.spec.d.ts.map +1 -0
  318. package/dist/workers/do-not-contact.contract.spec.js +47 -0
  319. package/dist/workers/duplicate-group-worker.spec.d.ts +2 -0
  320. package/dist/workers/duplicate-group-worker.spec.d.ts.map +1 -0
  321. package/dist/workers/duplicate-group-worker.spec.js +34 -0
  322. package/dist/workers/filter-exact-flags.spec.d.ts +2 -0
  323. package/dist/workers/filter-exact-flags.spec.d.ts.map +1 -0
  324. package/dist/workers/filter-exact-flags.spec.js +37 -0
  325. package/dist/workers/worker-source-attribution.contract.spec.d.ts +2 -0
  326. package/dist/workers/worker-source-attribution.contract.spec.d.ts.map +1 -0
  327. package/dist/workers/worker-source-attribution.contract.spec.js +442 -0
  328. package/dist/workers/worker-source.spec.d.ts +2 -0
  329. package/dist/workers/worker-source.spec.d.ts.map +1 -0
  330. package/dist/workers/worker-source.spec.js +13 -0
  331. package/dist/workers/worker-status-facets.spec.d.ts +2 -0
  332. package/dist/workers/worker-status-facets.spec.d.ts.map +1 -0
  333. package/dist/workers/worker-status-facets.spec.js +34 -0
  334. package/dist/workers/workers.contract.d.ts +19534 -5969
  335. package/dist/workers/workers.contract.d.ts.map +1 -1
  336. package/dist/workers/workers.contract.js +1096 -113
  337. package/dist/workers/workers.contract.spec.d.ts +2 -0
  338. package/dist/workers/workers.contract.spec.d.ts.map +1 -0
  339. package/dist/workers/workers.contract.spec.js +31 -0
  340. package/package.json +5 -4
@@ -1,24 +1,117 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PaginatedWorkerResponseSchema = exports.FilterWorkerSchema = exports.MergeDuplicatesResponseSchema = exports.MergeDuplicatesRequestSchema = exports.MergeDuplicateCuratedWorkerSchema = exports.FindDuplicatesSummaryResponseSchema = exports.DuplicateGroupSummarySchema = exports.DuplicateGroupSummaryWorkerSchema = exports.FindDuplicatesResponseSchema = exports.DuplicateGroupSchema = exports.DuplicateGroupWorkerSchema = exports.FilterDuplicatesSchema = exports.FilterSuggestedMatchesSchema = exports.PromoteWorkerResponseSchema = exports.BulkLinkWorkersResponseSchema = exports.BulkLinkWorkersSchema = exports.LinkWithMergeResponseSchema = exports.LinkWithMergeSchema = exports.MergeFieldSchema = exports.LinkWorkerResponseSchema = exports.LinkWorkerSchema = exports.SuggestCuratedMatchesResponseSchema = exports.MatchFieldCountsSchema = exports.SuggestedMatchSchema = exports.MatchConfidenceSchema = exports.MatchFieldSchema = exports.CuratedWorkerMatchSummarySchema = exports.WorkerMatchSummarySchema = exports.UpdateWorkerSchema = exports.CreateWorkerBodySchema = exports.CreateWorkerSchema = exports.WorkerSchema = exports.WorkerLiveStatusSchema = exports.WorkerUserSchema = exports.TradeFilterSchema = exports.ShareCodeSchema = exports.UpdateWorkerIdDocumentSchema = exports.CreateWorkerIdDocumentSchema = exports.WorkerIdDocumentSchema = exports.IdDocumentTypeSchema = exports.CreateWorkerQualificationSchema = exports.WorkerQualificationSchema = exports.CreateWorkerTradeSchema = exports.WorkerTradeSchema = exports.UpsertWorkerPhoneNumberSchema = exports.CreateWorkerPhoneNumberSchema = exports.WorkerPhoneNumberSchema = exports.BooleanFilterSchema = exports.WorkerSortableFieldsSchema = exports.AvailabilitySchema = void 0;
4
- exports.workersContractRouter = exports.WorkerImportResultSchema = exports.WorkerImportJobSchema = exports.StartWorkerImportSchema = exports.WorkerImportJobStatusSchema = void 0;
3
+ exports.SuggestCuratedMatchGroupsResponseSchema = exports.CuratedMatchGroupSchema = exports.SuggestCuratedMatchesResponseSchema = exports.MatchFieldCountsSchema = exports.SuggestedMatchSchema = exports.MatchConfidenceSchema = exports.MatchFieldSchema = exports.CuratedWorkerMatchSummarySchema = exports.WorkerMatchSummarySchema = exports.UpdateWorkerBodySchema = exports.UpdateWorkerSchema = exports.CreateSingleWorkerBodySchema = exports.CreateWorkerBodySchema = exports.CreateWorkerSchema = exports.WorkerListItemSchema = exports.WorkerSchema = exports.WorkerLiveStatusSchema = exports.WorkerUserSchema = exports.TradeFilterSchema = exports.ShareCodeSchema = exports.UpdateWorkerIdDocumentSchema = exports.CreateWorkerIdDocumentSchema = exports.WorkerIdDocumentSchema = exports.CreateWorkerQualificationSchema = exports.WorkerQualificationSchema = exports.CreateWorkerTradeSchema = exports.WorkerTradeSchema = exports.CheckWorkerAvailabilityResponseSchema = exports.CheckWorkerAvailabilityQuerySchema = exports.AvailabilityConflictWorkerSchema = exports.UpsertWorkerPhoneNumberSchema = exports.CreateWorkerPhoneNumberSchema = exports.WorkerPhoneNumberSchema = exports.OfferOpennessSchema = exports.BooleanFilterSchema = exports.WorkerSortFieldMapping = exports.WorkerSortableFieldsSchema = exports.OccupancyStatusSchema = exports.WorkerCreateConflictResponseSchema = exports.WorkerCreateGenericConflictResponseSchema = exports.WorkerCreateGenericConflictCodeSchema = exports.WorkerLeadAttributionRequiredResponseSchema = exports.ResolveWorkerSourceAttributionBodySchema = exports.WorkerSourceAttributionChallengeSchema = exports.WorkerLeadAttributionMatchSchema = exports.WorkerSourceAttributionAnswerSchema = exports.WorkerSourceAttributionStatusSchema = exports.WorkerSourceAttributionContextSchema = exports.WorkerSourceSchema = exports.IdDocumentTypeSchema = void 0;
4
+ exports.workersContractRouter = exports.InvalidateWorkerSourceAttributionChallengeBodySchema = exports.ResolveWorkerSourceAttributionChallengesBatchResponseSchema = exports.ResolveWorkerSourceAttributionChallengeResultSchema = exports.ResolveWorkerSourceAttributionChallengesBatchBodySchema = exports.WorkerSourceAttributionChallengeListResponseSchema = exports.AdminListWorkerSourceAttributionChallengesQuerySchema = exports.ListWorkerSourceAttributionChallengesQuerySchema = exports.WorkerImportResultSchema = exports.WorkerImportJobSchema = exports.StartWorkerImportSchema = exports.WorkerImportJobStatusSchema = exports.FindAllWorkersResponseSchema = exports.PaginatedWorkerListResponseSchema = exports.PaginatedWorkerResponseSchema = exports.FilterWorkerSchema = exports.MergeDuplicatesResponseSchema = exports.MergeDuplicatesRequestSchema = exports.MergeDuplicateCuratedWorkerSchema = exports.FindWorkersByPhonesResponseSchema = exports.WorkerPhoneLookupResultSchema = exports.FindWorkersByPhonesBodySchema = exports.FindDuplicatesSummaryResponseSchema = exports.DuplicateGroupSummarySchema = exports.DuplicateGroupSummaryWorkerSchema = exports.FindDuplicatesResponseSchema = exports.DuplicateGroupSchema = exports.DuplicateGroupWorkerSchema = exports.FilterDuplicatesSchema = exports.FilterSuggestedMatchesSchema = exports.BulkPromoteUnmatchedResponseSchema = exports.BulkPromoteUnmatchedPreviewResponseSchema = exports.PromoteWorkerResponseSchema = exports.BatchCreateWorkersResponseSchema = exports.BatchCreateWorkerResultSchema = exports.BatchCreateWorkersBodySchema = exports.BulkLinkWorkersResponseSchema = exports.BulkLinkWorkersSchema = exports.LinkWorkersWithMergeResponseSchema = exports.LinkWorkersWithMergeSchema = exports.LinkWithMergeResponseSchema = exports.LinkWithMergeSchema = exports.ScalarMergeFieldSchema = exports.LinkWorkerResponseSchema = exports.LinkWorkerSchema = void 0;
5
5
  const zod_openapi_1 = require("@anatine/zod-openapi");
6
6
  const core_1 = require("@ts-rest/core");
7
7
  const zod_1 = require("zod");
8
8
  const common_schemas_1 = require("../common/common-schemas");
9
+ var common_schemas_2 = require("../common/common-schemas");
10
+ Object.defineProperty(exports, "IdDocumentTypeSchema", { enumerable: true, get: function () { return common_schemas_2.IdDocumentTypeSchema; } });
9
11
  const error_schemas_1 = require("../common/error-schemas");
10
12
  const pagination_query_schema_1 = require("../common/pagination-query.schema");
11
13
  const pagination_schema_1 = require("../common/pagination.schema");
12
- const curated_workers_contract_1 = require("../curated-workers/curated-workers.contract");
14
+ const booking_history_schema_1 = require("../shared/booking-history.schema");
15
+ const contact_suppressions_contract_1 = require("../shared/contact-suppressions.contract");
13
16
  const crews_contract_1 = require("../crews/crews.contract");
17
+ const summary_schemas_1 = require("../shared/summary-schemas");
14
18
  const users_contract_1 = require("../users/users.contract");
19
+ const worker_source_identity_conflicts_schemas_1 = require("../worker-source-identity-conflicts/worker-source-identity-conflicts.schemas");
15
20
  (0, zod_openapi_1.extendZodWithOpenApi)(zod_1.z);
16
- // --- Enums ---
17
- exports.AvailabilitySchema = zod_1.z.enum([
18
- 'AVAILABLE',
19
- 'PARTIALLY_AVAILABLE',
20
- 'UNAVAILABLE',
21
+ exports.WorkerSourceSchema = zod_1.z.enum([
22
+ 'MANUAL',
23
+ 'LEAD_MATCH',
24
+ 'PROMOTED',
25
+ 'IMPORT',
21
26
  ]);
27
+ exports.WorkerSourceAttributionContextSchema = zod_1.z.enum([
28
+ 'SINGLE',
29
+ 'BATCH',
30
+ 'IMPORT',
31
+ ]);
32
+ exports.WorkerSourceAttributionStatusSchema = zod_1.z.enum([
33
+ 'PENDING',
34
+ 'RESOLVED_YES',
35
+ 'RESOLVED_NO',
36
+ 'INVALIDATED',
37
+ ]);
38
+ exports.WorkerSourceAttributionAnswerSchema = zod_1.z.enum(['YES', 'NO']);
39
+ exports.WorkerLeadAttributionMatchSchema = zod_1.z
40
+ .object({
41
+ curatedWorker: zod_1.z
42
+ .object({
43
+ id: zod_1.z.string().uuid(),
44
+ firstName: zod_1.z.string(),
45
+ lastName: zod_1.z.string().nullable(),
46
+ })
47
+ .strict(),
48
+ phoneMasked: worker_source_identity_conflicts_schemas_1.WorkerSourceIdentityConflictPhoneMaskSchema,
49
+ contactedAt: zod_1.z.string().datetime(),
50
+ channel: zod_1.z.enum(['PHONE', 'WHATSAPP']),
51
+ outcome: zod_1.z.string().min(1),
52
+ qualifyingContactCount: zod_1.z.number().int().positive(),
53
+ })
54
+ .strict();
55
+ exports.WorkerSourceAttributionChallengeSchema = zod_1.z
56
+ .object({
57
+ id: zod_1.z.string().uuid(),
58
+ context: exports.WorkerSourceAttributionContextSchema,
59
+ status: exports.WorkerSourceAttributionStatusSchema,
60
+ submittedWorkerName: zod_1.z.string(),
61
+ match: exports.WorkerLeadAttributionMatchSchema,
62
+ expiresAt: zod_1.z.string().datetime(),
63
+ createdAt: zod_1.z.string().datetime(),
64
+ identityReviewAdjustment: worker_source_identity_conflicts_schemas_1.WorkerSourceIdentityReviewAdjustmentSchema.nullable().optional(),
65
+ })
66
+ .strict();
67
+ exports.ResolveWorkerSourceAttributionBodySchema = zod_1.z.object({
68
+ answer: exports.WorkerSourceAttributionAnswerSchema,
69
+ explanation: zod_1.z.string().trim().max(500).optional(),
70
+ });
71
+ exports.WorkerLeadAttributionRequiredResponseSchema = zod_1.z
72
+ .object({
73
+ message: zod_1.z.string(),
74
+ code: zod_1.z.literal('WORKER_LEAD_ATTRIBUTION_REQUIRED'),
75
+ statusCode: zod_1.z.literal(409),
76
+ details: zod_1.z
77
+ .object({
78
+ challengeId: zod_1.z.string().uuid(),
79
+ expiresAt: zod_1.z.string().datetime(),
80
+ submittedWorkerName: zod_1.z.string(),
81
+ match: exports.WorkerLeadAttributionMatchSchema,
82
+ identityReviewAdjustment: worker_source_identity_conflicts_schemas_1.WorkerSourceIdentityReviewAdjustmentSchema.nullable(),
83
+ })
84
+ .strict(),
85
+ })
86
+ .strict();
87
+ // CLOSED enumeration of every ErrorCode the worker-create path may return
88
+ // with HTTP 409. Adding a new 409 to POST /v2/workers (or its batch/import
89
+ // variants) without listing the code here makes strict parsers of
90
+ // WorkerCreateConflictResponseSchema reject the response — update this enum
91
+ // (and its contract spec) together with the API change.
92
+ exports.WorkerCreateGenericConflictCodeSchema = zod_1.z.enum([
93
+ 'BAD_REQUEST',
94
+ 'CREW_MEMBER_LIMIT_REACHED',
95
+ 'ENTITY_HAS_RELATED_RECORDS',
96
+ 'FILE_ATTACHMENT_INVALID',
97
+ 'INVALID_WORKER_DATA',
98
+ 'VALIDATION_ERROR',
99
+ 'WORKER_ALREADY_EXISTS',
100
+ 'WORKER_ALREADY_HAS_QUALIFICATION',
101
+ ]);
102
+ exports.WorkerCreateGenericConflictResponseSchema = zod_1.z
103
+ .object({
104
+ ...error_schemas_1.ErrorResponseSchema.shape,
105
+ statusCode: zod_1.z.literal(409),
106
+ code: exports.WorkerCreateGenericConflictCodeSchema,
107
+ })
108
+ .strict();
109
+ exports.WorkerCreateConflictResponseSchema = zod_1.z.discriminatedUnion('code', [
110
+ exports.WorkerLeadAttributionRequiredResponseSchema,
111
+ worker_source_identity_conflicts_schemas_1.WorkerSourceIdentityConflictRequiredResponseSchema,
112
+ exports.WorkerCreateGenericConflictResponseSchema,
113
+ ]);
114
+ exports.OccupancyStatusSchema = zod_1.z.enum(['ACTIVE', 'BOOKED']).nullable();
22
115
  // EnglishLevelSchema and NationalitySchema are now imported from common-schemas
23
116
  exports.WorkerSortableFieldsSchema = zod_1.z
24
117
  .enum([
@@ -28,7 +121,6 @@ exports.WorkerSortableFieldsSchema = zod_1.z
28
121
  'email',
29
122
  'phone',
30
123
  'postcode',
31
- 'availability',
32
124
  'englishLevel',
33
125
  'nationality',
34
126
  'hasTools',
@@ -43,12 +135,42 @@ exports.WorkerSortableFieldsSchema = zod_1.z
43
135
  'createdByName',
44
136
  'createdAt',
45
137
  'updatedAt',
138
+ 'workedCount',
139
+ 'noShowCount',
46
140
  ])
47
141
  .openapi({ title: 'WorkerSortableFields' });
142
+ /** Maps sort field values to ability field paths on SortWorkerSchema. */
143
+ exports.WorkerSortFieldMapping = {
144
+ nameSimilarity: 'nameSimilarity',
145
+ fullName: 'fullName',
146
+ distance: 'distance',
147
+ email: 'email',
148
+ phone: 'phone',
149
+ postcode: 'postcode',
150
+ englishLevel: 'englishLevel',
151
+ nationality: 'nationality',
152
+ hasTools: 'hasTools',
153
+ hasPpe: 'hasPpe',
154
+ transportation: 'transportation',
155
+ dateOfBirth: 'dateOfBirth',
156
+ mainTrade: 'mainTrade',
157
+ bio: 'bio',
158
+ qualificationsCount: 'qualificationsCount',
159
+ nino: 'nino',
160
+ shareCodeExpiry: 'shareCodeExpiry',
161
+ createdByName: 'createdByName',
162
+ createdAt: 'createdAt',
163
+ updatedAt: 'updatedAt',
164
+ };
48
165
  exports.BooleanFilterSchema = zod_1.z
49
- .enum(['only_with', 'only_without', 'all'])
166
+ .enum(['only_with', 'only_without', 'unknown', 'all'])
50
167
  .default('all')
51
168
  .openapi({ title: 'BooleanFilter' });
169
+ exports.OfferOpennessSchema = zod_1.z.enum([
170
+ 'ACTIVELY_LOOKING',
171
+ 'OPEN',
172
+ 'NOT_INTERESTED',
173
+ ]);
52
174
  // --- Nested Schemas ---
53
175
  exports.WorkerPhoneNumberSchema = common_schemas_1.PhoneNumberResponseSchema.openapi({
54
176
  title: 'WorkerPhoneNumber',
@@ -59,6 +181,33 @@ exports.CreateWorkerPhoneNumberSchema = common_schemas_1.CreatePhoneNumberSchema
59
181
  exports.UpsertWorkerPhoneNumberSchema = common_schemas_1.UpsertPhoneNumberSchema.openapi({
60
182
  title: 'UpsertWorkerPhoneNumber',
61
183
  });
184
+ exports.AvailabilityConflictWorkerSchema = zod_1.z
185
+ .object({
186
+ id: zod_1.z.string().uuid(),
187
+ firstName: zod_1.z.string(),
188
+ lastName: zod_1.z.string().nullable().optional(),
189
+ createdByUserId: zod_1.z.string().uuid().nullable().optional(),
190
+ /**
191
+ * True when a submit using this email/phone would be rejected by the
192
+ * database (workers.email is globally unique; worker_phone_numbers is
193
+ * unique per (phoneNumber, createdByUserId)). When false the conflict is
194
+ * informational and submission is allowed.
195
+ */
196
+ blocking: zod_1.z.boolean(),
197
+ })
198
+ .openapi({ title: 'AvailabilityConflictWorker' });
199
+ exports.CheckWorkerAvailabilityQuerySchema = zod_1.z.object({
200
+ email: zod_1.z.string().trim().email().optional(),
201
+ phoneNumber: zod_1.z.string().min(1).optional(),
202
+ excludeWorkerId: zod_1.z.string().uuid().optional(),
203
+ });
204
+ exports.CheckWorkerAvailabilityResponseSchema = zod_1.z
205
+ .object({
206
+ email: exports.AvailabilityConflictWorkerSchema.nullable(),
207
+ phoneNumber: exports.AvailabilityConflictWorkerSchema.nullable(),
208
+ workerLeadAttributionMatch: exports.WorkerLeadAttributionMatchSchema.nullable().optional(),
209
+ })
210
+ .openapi({ title: 'CheckWorkerAvailabilityResponse' });
62
211
  exports.WorkerTradeSchema = zod_1.z
63
212
  .object({
64
213
  id: zod_1.z.string().uuid().optional(),
@@ -93,6 +242,7 @@ exports.WorkerQualificationSchema = zod_1.z
93
242
  .nullable()
94
243
  .describe('Reference Number'),
95
244
  proofDocumentFileId: zod_1.z.string().uuid().optional().nullable(),
245
+ createdAt: zod_1.z.coerce.date().optional(),
96
246
  })
97
247
  .openapi({ title: 'WorkerQualification' });
98
248
  exports.CreateWorkerQualificationSchema = zod_1.z
@@ -111,17 +261,11 @@ exports.CreateWorkerQualificationSchema = zod_1.z
111
261
  })
112
262
  .openapi({ title: 'CreateWorkerQualification' });
113
263
  // ─── ID Document ────────────────────────────────────────────────────────────
114
- exports.IdDocumentTypeSchema = zod_1.z.enum([
115
- 'passport',
116
- 'id_card',
117
- 'driving_license',
118
- 'unknown',
119
- ]);
120
264
  exports.WorkerIdDocumentSchema = zod_1.z
121
265
  .object({
122
266
  id: zod_1.z.string().uuid().optional(),
123
267
  fileId: zod_1.z.string().uuid().nullable().optional(),
124
- documentType: exports.IdDocumentTypeSchema.nullable().optional(),
268
+ documentType: common_schemas_1.IdDocumentTypeSchema.nullable().optional(),
125
269
  expiryDate: zod_1.z
126
270
  .union([zod_1.z.string().date(), zod_1.z.date()])
127
271
  .transform((val) => val instanceof Date ? val.toISOString().split('T')[0] : val)
@@ -141,7 +285,7 @@ exports.WorkerIdDocumentSchema = zod_1.z
141
285
  exports.CreateWorkerIdDocumentSchema = zod_1.z
142
286
  .object({
143
287
  fileId: zod_1.z.string().uuid().nullable().optional(),
144
- documentType: exports.IdDocumentTypeSchema.nullable().optional(),
288
+ documentType: common_schemas_1.IdDocumentTypeSchema.nullable().optional(),
145
289
  expiryDate: zod_1.z.string().date().nullable().optional(),
146
290
  documentNumber: zod_1.z.string().max(100).nullable().optional(),
147
291
  })
@@ -165,6 +309,7 @@ exports.ShareCodeSchema = zod_1.z
165
309
  .optional()
166
310
  .nullable()
167
311
  .describe('Enter expiry date for the share code'),
312
+ fileId: zod_1.z.string().uuid().optional().nullable(),
168
313
  })
169
314
  .openapi({
170
315
  title: 'ShareCode',
@@ -214,16 +359,7 @@ exports.WorkerLiveStatusSchema = zod_1.z.object({
214
359
  bookingId: zod_1.z.string().uuid().nullable().optional(),
215
360
  active: zod_1.z
216
361
  .object({
217
- statusSa: zod_1.z.enum([
218
- 'PENDING',
219
- 'ACTIVE',
220
- 'VACATION',
221
- 'LEFT_THE_SITE',
222
- 'MEDICAL_LEAVE',
223
- 'DAY_OFF',
224
- 'INJURY',
225
- ]),
226
- statusFa: zod_1.z.enum([
362
+ status: zod_1.z.enum([
227
363
  'PENDING',
228
364
  'ACTIVE',
229
365
  'VACATION',
@@ -231,11 +367,21 @@ exports.WorkerLiveStatusSchema = zod_1.z.object({
231
367
  'MEDICAL_LEAVE',
232
368
  'DAY_OFF',
233
369
  'INJURY',
370
+ 'OFF_SCHEDULE',
234
371
  ]),
235
372
  })
236
373
  .nullable()
237
374
  .optional(),
238
375
  activeId: zod_1.z.string().uuid().nullable().optional(),
376
+ bookingAgent: zod_1.z
377
+ .object({
378
+ id: zod_1.z.string().uuid(),
379
+ firstName: zod_1.z.string(),
380
+ lastName: zod_1.z.string(),
381
+ })
382
+ .nullable()
383
+ .optional()
384
+ .describe('Agent who created the active booking'),
239
385
  });
240
386
  // --- Main Schemas ---
241
387
  exports.WorkerSchema = zod_1.z
@@ -276,25 +422,48 @@ exports.WorkerSchema = zod_1.z
276
422
  nationality: common_schemas_1.NationalitySchema.nullable()
277
423
  .optional()
278
424
  .describe('Nationality'),
279
- hasTools: zod_1.z.boolean().describe('Has Tools'),
280
- hasPpe: zod_1.z.boolean().describe('Has PPE'),
425
+ hasTools: zod_1.z.boolean().nullable().describe('Has Tools'),
426
+ hasPpe: zod_1.z.boolean().nullable().describe('Has PPE'),
281
427
  transportation: common_schemas_1.TransportationSchema.nullable()
282
428
  .optional()
283
429
  .describe('Transportation'),
284
430
  location: common_schemas_1.LocationDetailsSchema.nullable().optional().describe('Location'),
431
+ locationId: zod_1.z
432
+ .string()
433
+ .uuid()
434
+ .nullable()
435
+ .optional()
436
+ .describe('Location ID (FK) — lets a picked worker location be copied on merge'),
285
437
  shareCode: exports.ShareCodeSchema.optional().nullable().describe('Share Code'),
286
438
  liveStatus: exports.WorkerLiveStatusSchema.optional().describe('Live Status'),
287
- availability: exports.AvailabilitySchema.describe('Availability'),
439
+ offerOpenness: exports.OfferOpennessSchema.default('OPEN'),
440
+ offerOpennessSetAt: zod_1.z
441
+ .union([zod_1.z.string().datetime(), zod_1.z.date()])
442
+ .transform((v) => (v instanceof Date ? v.toISOString() : v))
443
+ .nullable()
444
+ .optional(),
445
+ offerNote: zod_1.z.string().nullable().optional(),
446
+ offerNoteUpdatedAt: zod_1.z
447
+ .union([zod_1.z.string().datetime(), zod_1.z.date()])
448
+ .transform((v) => (v instanceof Date ? v.toISOString() : v))
449
+ .nullable()
450
+ .optional(),
288
451
  curatedWorkerId: zod_1.z
289
452
  .string()
290
453
  .uuid()
291
454
  .nullable()
292
455
  .optional()
293
456
  .describe('Curated Worker ID'),
294
- effectiveStatus: zod_1.z
295
- .union([exports.AvailabilitySchema, curated_workers_contract_1.CuratedWorkerStatusSchema])
457
+ blacklistReason: zod_1.z
458
+ .string()
459
+ .nullable()
296
460
  .optional()
297
- .describe('Effective status (inherited from curated worker when linked)'),
461
+ .describe('Blacklist reason from curated worker'),
462
+ occupancyStatus: exports.OccupancyStatusSchema.describe('Booking-derived occupancy; null when the worker has no live booking').optional(),
463
+ suppression: contact_suppressions_contract_1.SuppressionStateSchema,
464
+ // findAll parses with this schema (not WorkerListItemSchema) — list
465
+ // fields must exist here too or Zod strips them from every row.
466
+ source: exports.WorkerSourceSchema.optional(),
298
467
  createdByUserId: zod_1.z
299
468
  .string()
300
469
  .uuid()
@@ -303,6 +472,25 @@ exports.WorkerSchema = zod_1.z
303
472
  .describe('Created By User ID'),
304
473
  createdBy: users_contract_1.UserSchema.nullable().optional().describe('Created By User'),
305
474
  distanceKm: zod_1.z.number().nullable().optional().describe('Distance in KM'),
475
+ // Travel time to the proximityJobId job (book-workers flow). Mirrored from
476
+ // WorkerListItemSchema because the findAll controller parses its response with
477
+ // PaginatedWorkerResponseSchema (built on THIS schema) — fields absent here are
478
+ // stripped before the response is sent, even though the contract declares
479
+ // WorkerListItemSchema for findAll.
480
+ driveMinutes: zod_1.z
481
+ .number()
482
+ .nullable()
483
+ .optional()
484
+ .describe('Driving minutes (free-flow) to the proximityJobId job; null = beyond the routing cap.'),
485
+ transitMinutes: zod_1.z
486
+ .number()
487
+ .nullable()
488
+ .optional()
489
+ .describe('Public-transport minutes to the proximityJobId job; null = beyond the routing cap.'),
490
+ travelTimeEnriched: zod_1.z
491
+ .boolean()
492
+ .optional()
493
+ .describe('True when the (proximityJobId, worker) lead_proximity_owned row is enriched; gates the travel chips.'),
306
494
  crew: crews_contract_1.CrewSummarySchema.nullable().optional().describe('Crew'),
307
495
  createdAt: zod_1.z
308
496
  .union([zod_1.z.string().datetime(), zod_1.z.date()])
@@ -312,33 +500,144 @@ exports.WorkerSchema = zod_1.z
312
500
  .union([zod_1.z.string().datetime(), zod_1.z.date()])
313
501
  .transform((val) => (val instanceof Date ? val.toISOString() : val))
314
502
  .describe('Last Update Date'),
503
+ bookingHistory: booking_history_schema_1.BookingHistorySchema.optional(),
315
504
  })
316
505
  .openapi({ title: 'Worker' });
506
+ /**
507
+ * Lightweight schema for worker list views (table rows / cards).
508
+ * Excludes heavy fields not needed in lists: curatedWorkerId, createdByUserId.
509
+ * Uses UserSummarySchema for createdBy instead of full UserSchema.
510
+ * Includes idDocuments (already batch-loaded by findAll, no N+1) so rows can
511
+ * decide whether to show the "Documents" button without a per-row fetch.
512
+ */
513
+ exports.WorkerListItemSchema = zod_1.z
514
+ .object({
515
+ id: zod_1.z.string().uuid().describe('Worker ID'),
516
+ firstName: zod_1.z.string().describe('First Name'),
517
+ lastName: zod_1.z.string().optional().nullable().describe('Last Name'),
518
+ email: zod_1.z.string().email().nullable().optional().describe('Email'),
519
+ phoneNumbers: zod_1.z
520
+ .array(exports.WorkerPhoneNumberSchema)
521
+ .optional()
522
+ .default([])
523
+ .describe('Phone Numbers'),
524
+ nino: zod_1.z
525
+ .string()
526
+ .nullable()
527
+ .optional()
528
+ .describe('National Insurance Number'),
529
+ dateOfBirth: zod_1.z
530
+ .union([zod_1.z.string().date(), zod_1.z.date()])
531
+ .transform((val) => val instanceof Date ? val.toISOString().split('T')[0] : val)
532
+ .nullable()
533
+ .optional()
534
+ .describe('Date of Birth'),
535
+ bio: zod_1.z.string().nullable().optional().describe('Bio'),
536
+ trades: zod_1.z.array(exports.WorkerTradeSchema).optional().describe('Trades'),
537
+ qualifications: zod_1.z
538
+ .array(exports.WorkerQualificationSchema)
539
+ .optional()
540
+ .describe('Qualifications'),
541
+ idDocuments: zod_1.z
542
+ .array(exports.WorkerIdDocumentSchema)
543
+ .optional()
544
+ .describe('ID Documents'),
545
+ englishLevel: common_schemas_1.EnglishLevelSchema.nullable()
546
+ .optional()
547
+ .describe('English Level'),
548
+ nationality: common_schemas_1.NationalitySchema.nullable()
549
+ .optional()
550
+ .describe('Nationality'),
551
+ hasTools: zod_1.z.boolean().nullable().describe('Has Tools'),
552
+ hasPpe: zod_1.z.boolean().nullable().describe('Has PPE'),
553
+ transportation: common_schemas_1.TransportationSchema.nullable()
554
+ .optional()
555
+ .describe('Transportation'),
556
+ location: common_schemas_1.LocationDetailsSchema.nullable().optional().describe('Location'),
557
+ shareCode: exports.ShareCodeSchema.optional().nullable().describe('Share Code'),
558
+ liveStatus: exports.WorkerLiveStatusSchema.optional().describe('Live Status'),
559
+ offerOpenness: exports.OfferOpennessSchema.default('OPEN'),
560
+ offerOpennessSetAt: zod_1.z
561
+ .union([zod_1.z.string().datetime(), zod_1.z.date()])
562
+ .transform((v) => (v instanceof Date ? v.toISOString() : v))
563
+ .nullable()
564
+ .optional(),
565
+ offerNote: zod_1.z.string().nullable().optional(),
566
+ offerNoteUpdatedAt: zod_1.z
567
+ .union([zod_1.z.string().datetime(), zod_1.z.date()])
568
+ .transform((v) => (v instanceof Date ? v.toISOString() : v))
569
+ .nullable()
570
+ .optional(),
571
+ blacklistReason: zod_1.z
572
+ .string()
573
+ .nullable()
574
+ .optional()
575
+ .describe('Blacklist reason from curated worker'),
576
+ occupancyStatus: exports.OccupancyStatusSchema.describe('Booking-derived occupancy; null when the worker has no live booking').optional(),
577
+ suppression: contact_suppressions_contract_1.SuppressionStateSchema,
578
+ createdBy: summary_schemas_1.UserSummarySchema.nullable().optional().describe('Created By'),
579
+ createdByUserId: zod_1.z
580
+ .string()
581
+ .uuid()
582
+ .nullable()
583
+ .optional()
584
+ .describe('Owning agent id — needed client-side for the CASL "update Worker" ownership check (createdByUserId === user.id) that gates inline edit controls + the Edit action.'),
585
+ distanceKm: zod_1.z.number().nullable().optional().describe('Distance in KM'),
586
+ crew: crews_contract_1.CrewSummarySchema.nullable().optional().describe('Crew'),
587
+ createdAt: zod_1.z
588
+ .union([zod_1.z.string().datetime(), zod_1.z.date()])
589
+ .transform((val) => (val instanceof Date ? val.toISOString() : val))
590
+ .describe('Creation Date'),
591
+ updatedAt: zod_1.z
592
+ .union([zod_1.z.string().datetime(), zod_1.z.date()])
593
+ .transform((val) => (val instanceof Date ? val.toISOString() : val))
594
+ .describe('Last Update Date'),
595
+ source: exports.WorkerSourceSchema.optional(),
596
+ driveMinutes: zod_1.z
597
+ .number()
598
+ .nullable()
599
+ .optional()
600
+ .describe('Driving minutes (free-flow) to the proximityJobId job; null = beyond the routing cap. Only present when proximityJobId was queried and the (job, worker) pair is travel-time enriched.'),
601
+ transitMinutes: zod_1.z
602
+ .number()
603
+ .nullable()
604
+ .optional()
605
+ .describe('Public-transport minutes to the proximityJobId job; null = beyond the routing cap. Only present when proximityJobId was queried and the (job, worker) pair is travel-time enriched.'),
606
+ travelTimeEnriched: zod_1.z
607
+ .boolean()
608
+ .optional()
609
+ .describe('True when a lead_proximity_owned row for (proximityJobId, worker) exists and has been enriched (enriched_at set). Gates whether the travel chips render — distinguishes "beyond cap" (null minutes) from "no data yet".'),
610
+ bookingHistory: booking_history_schema_1.BookingHistorySchema.optional(),
611
+ })
612
+ .openapi({ title: 'WorkerListItem' });
317
613
  exports.CreateWorkerSchema = zod_1.z
318
614
  .object({
319
- firstName: zod_1.z.string().min(3).max(100).describe('First Name'),
615
+ firstName: zod_1.z.string().trim().min(3).max(100).describe('First Name'),
320
616
  lastName: zod_1.z
321
- .string()
322
- .min(3)
323
- .max(100)
324
- .nullish()
325
- .or(zod_1.z.literal(''))
617
+ .preprocess((val) => (typeof val === 'string' ? val.trim() : val), zod_1.z.string().min(3).max(100).nullish().or(zod_1.z.literal('')))
326
618
  .transform((val) => (val === '' ? null : val))
327
619
  .describe('Last Name'),
328
620
  email: zod_1.z
621
+ .preprocess((val) => (typeof val === 'string' ? val.trim() : val), zod_1.z.string().email().nullish().or(zod_1.z.literal('')))
622
+ .transform((val) => (val === '' ? undefined : val))
623
+ .describe('Email'),
624
+ nationality: common_schemas_1.NationalitySchema.optional()
625
+ .nullable()
626
+ .describe('Nationality'),
627
+ crewId: zod_1.z
329
628
  .string()
330
- .email()
331
- .nullish()
629
+ .uuid()
630
+ .optional()
332
631
  .or(zod_1.z.literal(''))
333
632
  .transform((val) => (val === '' ? undefined : val))
334
- .describe('Email'),
633
+ .describe('Crew ID'),
335
634
  phoneNumbers: zod_1.z
336
635
  .array(exports.CreateWorkerPhoneNumberSchema)
337
636
  .describe('Phone Numbers'),
338
- crewId: zod_1.z.string().uuid().optional().describe('Crew ID'),
339
637
  nino: zod_1.z
340
638
  .string()
341
- .regex(/^(?:[A-Z]{2}[0-9]{6}[A-D])?$/)
639
+ .regex(/^(?:(?!BG|GB|NK|KN|TN|NT|ZZ)[A-CEGHJ-PR-TW-Z][A-CEGHJ-NPR-TW-Z]\s?[0-9]{2}\s?[0-9]{2}\s?[0-9]{2}\s?[A-Z])?$/)
640
+ .transform((val) => val?.replace(/\s/g, ''))
342
641
  .optional()
343
642
  .nullable()
344
643
  .describe('National Insurance Number'),
@@ -365,19 +664,15 @@ exports.CreateWorkerSchema = zod_1.z
365
664
  englishLevel: common_schemas_1.EnglishLevelSchema.optional()
366
665
  .nullable()
367
666
  .describe('English Level'),
368
- nationality: common_schemas_1.NationalitySchema.optional()
369
- .nullable()
370
- .describe('Nationality'),
371
- hasTools: zod_1.z.boolean().describe('Has Tools'),
372
- hasPpe: zod_1.z.boolean().describe('Has PPE'),
667
+ hasTools: zod_1.z.boolean().nullable().optional().describe('Has Tools'),
668
+ hasPpe: zod_1.z.boolean().nullable().optional().describe('Has PPE'),
373
669
  transportation: common_schemas_1.TransportationSchema.optional()
374
670
  .nullable()
375
671
  .describe('Transportation'),
376
672
  location: common_schemas_1.CreateLocationSchema.optional().nullable().describe('Location'),
377
673
  shareCode: exports.ShareCodeSchema.optional().nullable().describe('Share Code'),
378
- availability: exports.AvailabilitySchema.optional()
379
- .default('AVAILABLE')
380
- .describe('Availability'),
674
+ offerOpenness: exports.OfferOpennessSchema.optional().default('OPEN'),
675
+ offerNote: zod_1.z.string().nullable().optional(),
381
676
  })
382
677
  .openapi({ title: 'CreateWorker' });
383
678
  /**
@@ -385,7 +680,7 @@ exports.CreateWorkerSchema = zod_1.z
385
680
  * Used as the contract endpoint body. The base CreateWorkerSchema remains
386
681
  * a plain ZodObject so it can be .extend()-ed in the frontend.
387
682
  */
388
- exports.CreateWorkerBodySchema = exports.CreateWorkerSchema.superRefine((data, ctx) => {
683
+ function validateCreateWorkerPhones(data, ctx) {
389
684
  if (!data.crewId) {
390
685
  if (data.phoneNumbers.length < 1) {
391
686
  ctx.addIssue({
@@ -393,7 +688,7 @@ exports.CreateWorkerBodySchema = exports.CreateWorkerSchema.superRefine((data, c
393
688
  minimum: 1,
394
689
  type: 'array',
395
690
  inclusive: true,
396
- message: 'At least one phone number is required',
691
+ message: 'A worker phone number is required when worker is not part of a crew',
397
692
  path: ['phoneNumbers'],
398
693
  });
399
694
  }
@@ -413,36 +708,56 @@ exports.CreateWorkerBodySchema = exports.CreateWorkerSchema.superRefine((data, c
413
708
  path: ['phoneNumbers'],
414
709
  });
415
710
  }
416
- });
711
+ }
712
+ exports.CreateWorkerBodySchema = exports.CreateWorkerSchema.superRefine(validateCreateWorkerPhones);
713
+ /**
714
+ * The single-create request may explicitly retire a challenge returned by its
715
+ * preceding submit. This attempt metadata is never part of the worker payload
716
+ * and is intentionally unavailable to batch/import requests.
717
+ */
718
+ exports.CreateSingleWorkerBodySchema = exports.CreateWorkerSchema.extend({
719
+ supersedesAttributionChallengeId: zod_1.z.string().uuid().optional(),
720
+ }).superRefine(validateCreateWorkerPhones);
417
721
  exports.UpdateWorkerSchema = zod_1.z
418
722
  .object({
419
- firstName: zod_1.z.string().min(3).max(100).optional().describe('First Name'),
420
- lastName: zod_1.z
723
+ firstName: zod_1.z
421
724
  .string()
725
+ .trim()
422
726
  .min(3)
423
727
  .max(100)
424
- .nullish()
425
- .or(zod_1.z.literal(''))
728
+ .optional()
729
+ .describe('First Name'),
730
+ lastName: zod_1.z
731
+ .preprocess((val) => (typeof val === 'string' ? val.trim() : val), zod_1.z.string().min(3).max(100).nullish().or(zod_1.z.literal('')))
426
732
  .transform((val) => (val === '' ? null : val))
427
733
  .describe('Last Name'),
428
734
  email: zod_1.z
429
- .string()
430
- .email()
431
- .nullish()
432
- .or(zod_1.z.literal(''))
735
+ .preprocess((val) => (typeof val === 'string' ? val.trim() : val), zod_1.z.string().email().nullish().or(zod_1.z.literal('')))
433
736
  .transform((val) => (val === '' ? undefined : val))
434
737
  .describe('Email'),
738
+ nationality: common_schemas_1.NationalitySchema.optional()
739
+ .nullable()
740
+ .describe('Nationality'),
741
+ crewId: zod_1.z
742
+ .string()
743
+ .uuid()
744
+ .optional()
745
+ .nullable()
746
+ .or(zod_1.z.literal(''))
747
+ .transform((val) => (val === '' ? null : val))
748
+ .describe('Crew ID'),
435
749
  phoneNumbers: zod_1.z
436
750
  .array(exports.UpsertWorkerPhoneNumberSchema)
437
- .min(1, { message: 'At least one phone number is required' })
438
- .refine((phoneNumbers) => phoneNumbers.some((phone) => phone.isPrimary), {
751
+ .refine((phoneNumbers) => phoneNumbers.length === 0 ||
752
+ phoneNumbers.some((phone) => phone.isPrimary), {
439
753
  message: 'Must have at least one primary phone number',
440
754
  })
441
755
  .optional()
442
756
  .describe('Phone Numbers'),
443
757
  nino: zod_1.z
444
758
  .string()
445
- .regex(/^(?:[A-Z]{2}[0-9]{6}[A-D])?$/)
759
+ .regex(/^(?:(?!BG|GB|NK|KN|TN|NT|ZZ)[A-CEGHJ-PR-TW-Z][A-CEGHJ-NPR-TW-Z]\s?[0-9]{2}\s?[0-9]{2}\s?[0-9]{2}\s?[A-Z])?$/)
760
+ .transform((val) => val?.replace(/\s/g, ''))
446
761
  .optional()
447
762
  .nullable()
448
763
  .describe('National Insurance Number'),
@@ -469,19 +784,46 @@ exports.UpdateWorkerSchema = zod_1.z
469
784
  englishLevel: common_schemas_1.EnglishLevelSchema.optional()
470
785
  .nullable()
471
786
  .describe('English Level'),
472
- nationality: common_schemas_1.NationalitySchema.optional()
473
- .nullable()
474
- .describe('Nationality'),
475
- hasTools: zod_1.z.boolean().optional().describe('Has Tools'),
476
- hasPpe: zod_1.z.boolean().optional().describe('Has PPE'),
787
+ hasTools: zod_1.z.boolean().nullable().optional().describe('Has Tools'),
788
+ hasPpe: zod_1.z.boolean().nullable().optional().describe('Has PPE'),
477
789
  transportation: common_schemas_1.TransportationSchema.optional()
478
790
  .nullable()
479
791
  .describe('Transportation'),
480
792
  location: common_schemas_1.CreateLocationSchema.optional().nullable().describe('Location'),
481
793
  shareCode: exports.ShareCodeSchema.optional().nullable().describe('Share Code'),
482
- availability: exports.AvailabilitySchema.optional().describe('Availability'),
794
+ offerOpenness: exports.OfferOpennessSchema.optional(),
795
+ offerNote: zod_1.z.string().nullable().optional(),
483
796
  })
484
797
  .openapi({ title: 'UpdateWorker' });
798
+ /**
799
+ * UpdateWorkerSchema with crew-aware phone number validation.
800
+ * Used as the contract endpoint body. Mirrors CreateWorkerBodySchema pattern.
801
+ *
802
+ * When phoneNumbers is provided (not undefined):
803
+ * - Standalone workers (no crewId): must have at least 1 phone with a primary
804
+ * - Crew members (has crewId): phone numbers optional, but if provided must have a primary
805
+ *
806
+ * When phoneNumbers is omitted (undefined): no phone validation runs.
807
+ */
808
+ exports.UpdateWorkerBodySchema = exports.UpdateWorkerSchema.superRefine((data, ctx) => {
809
+ // Only validate phone numbers if they are explicitly provided
810
+ if (data.phoneNumbers === undefined)
811
+ return;
812
+ if (!data.crewId) {
813
+ // Standalone worker: must have at least one phone number
814
+ if (data.phoneNumbers.length < 1) {
815
+ ctx.addIssue({
816
+ code: zod_1.z.ZodIssueCode.too_small,
817
+ minimum: 1,
818
+ type: 'array',
819
+ inclusive: true,
820
+ message: 'At least one phone number is required',
821
+ path: ['phoneNumbers'],
822
+ });
823
+ }
824
+ }
825
+ // Primary phone check is already handled by the base schema's refine
826
+ });
485
827
  // --- Curated Worker Linking Schemas ---
486
828
  exports.WorkerMatchSummarySchema = zod_1.z
487
829
  .object({
@@ -519,7 +861,9 @@ exports.CuratedWorkerMatchSummarySchema = zod_1.z
519
861
  .optional()
520
862
  .default([])
521
863
  .describe('Phone Numbers'),
522
- status: curated_workers_contract_1.CuratedWorkerStatusSchema.describe('Status'),
864
+ blacklisted: zod_1.z
865
+ .boolean()
866
+ .describe('Whether the curated worker is blacklisted'),
523
867
  })
524
868
  .openapi({ title: 'CuratedWorkerMatchSummary' });
525
869
  exports.MatchFieldSchema = zod_1.z.enum(['NINO', 'EMAIL', 'PHONE']);
@@ -549,6 +893,25 @@ exports.SuggestCuratedMatchesResponseSchema = zod_1.z
549
893
  limit: zod_1.z.number().describe('Items per page'),
550
894
  })
551
895
  .openapi({ title: 'SuggestCuratedMatchesResponse' });
896
+ exports.CuratedMatchGroupSchema = zod_1.z
897
+ .object({
898
+ curatedWorker: exports.CuratedWorkerMatchSummarySchema,
899
+ workers: zod_1.z.array(zod_1.z.object({
900
+ worker: exports.WorkerMatchSummarySchema,
901
+ matchedOn: zod_1.z.array(exports.MatchFieldSchema),
902
+ confidence: exports.MatchConfidenceSchema,
903
+ })),
904
+ })
905
+ .openapi({ title: 'CuratedMatchGroup' });
906
+ exports.SuggestCuratedMatchGroupsResponseSchema = zod_1.z
907
+ .object({
908
+ groups: zod_1.z.array(exports.CuratedMatchGroupSchema),
909
+ totalGroups: zod_1.z.number(),
910
+ totalPages: zod_1.z.number(),
911
+ page: zod_1.z.number(),
912
+ limit: zod_1.z.number(),
913
+ })
914
+ .openapi({ title: 'SuggestCuratedMatchGroupsResponse' });
552
915
  exports.LinkWorkerSchema = zod_1.z
553
916
  .object({
554
917
  curatedWorkerId: zod_1.z.string().uuid().describe('Curated Worker ID to link to'),
@@ -560,40 +923,162 @@ exports.LinkWorkerResponseSchema = zod_1.z
560
923
  curatedWorkerId: zod_1.z.string().uuid().describe('Linked Curated Worker ID'),
561
924
  })
562
925
  .openapi({ title: 'LinkWorkerResponse' });
563
- exports.MergeFieldSchema = zod_1.z.enum([
926
+ exports.ScalarMergeFieldSchema = zod_1.z.enum([
564
927
  'firstName',
565
928
  'lastName',
566
929
  'email',
567
930
  'nino',
568
931
  'dateOfBirth',
569
932
  'bio',
570
- 'rating',
571
933
  'hasTools',
572
934
  'hasPpe',
573
935
  'englishLevel',
574
936
  'nationality',
575
937
  'locationId',
576
938
  'transportation',
577
- 'phoneNumbers',
578
- 'trades',
579
- 'qualifications',
580
939
  ]);
581
940
  exports.LinkWithMergeSchema = zod_1.z
582
941
  .object({
583
942
  curatedWorkerId: zod_1.z.string().uuid().describe('Curated Worker ID to link to'),
584
- mergeFields: zod_1.z
585
- .array(exports.MergeFieldSchema)
586
- .min(0)
587
- .describe('Fields to overwrite on curated worker from worker data'),
943
+ scalarFields: zod_1.z
944
+ .array(exports.ScalarMergeFieldSchema)
945
+ .optional()
946
+ .default([])
947
+ .describe('Scalar fields to overwrite on curated worker from worker data'),
948
+ phoneNumbers: zod_1.z
949
+ .array(zod_1.z.object({
950
+ phoneNumber: common_schemas_1.PhoneSchema,
951
+ isPrimary: zod_1.z.boolean(),
952
+ description: zod_1.z.string().nullable().optional(),
953
+ }))
954
+ .optional()
955
+ .default([]),
956
+ trades: zod_1.z
957
+ .array(zod_1.z.object({
958
+ tradeId: zod_1.z.string().uuid(),
959
+ mainTrade: zod_1.z.boolean(),
960
+ }))
961
+ .optional()
962
+ .default([]),
963
+ qualifications: zod_1.z
964
+ .array(zod_1.z.object({
965
+ qualificationId: zod_1.z.string().uuid(),
966
+ qualificationTypeId: zod_1.z.string().uuid().nullable().optional(),
967
+ issueDate: zod_1.z.string().date().nullable().optional(),
968
+ expiryDate: zod_1.z.string().date().nullable().optional(),
969
+ referenceNumber: zod_1.z.string().nullable().optional(),
970
+ proofDocumentFileId: zod_1.z.string().uuid().nullable().optional(),
971
+ }))
972
+ .optional()
973
+ .default([]),
974
+ idDocuments: zod_1.z
975
+ .array(zod_1.z.object({
976
+ fileId: zod_1.z.string().uuid().nullable().optional(),
977
+ documentType: common_schemas_1.IdDocumentTypeSchema.nullable().optional(),
978
+ expiryDate: zod_1.z.string().date().nullable().optional(),
979
+ documentNumber: zod_1.z.string().max(100).nullable().optional(),
980
+ }))
981
+ .optional()
982
+ .default([]),
983
+ shareCode: zod_1.z
984
+ .object({
985
+ code: zod_1.z.string().nullable().optional(),
986
+ expiryDate: zod_1.z.string().nullable().optional(),
987
+ fileId: zod_1.z.string().uuid().nullable().optional(),
988
+ })
989
+ .nullable()
990
+ .optional(),
588
991
  })
589
992
  .openapi({ title: 'LinkWithMerge' });
590
993
  exports.LinkWithMergeResponseSchema = zod_1.z
591
994
  .object({
592
995
  workerId: zod_1.z.string().uuid().describe('Worker ID'),
593
996
  curatedWorkerId: zod_1.z.string().uuid().describe('Linked Curated Worker ID'),
594
- mergedFields: zod_1.z.array(exports.MergeFieldSchema).describe('Fields that were merged'),
997
+ mergedScalarFields: zod_1.z
998
+ .array(exports.ScalarMergeFieldSchema)
999
+ .describe('Scalar fields that were merged'),
1000
+ added: zod_1.z
1001
+ .object({
1002
+ phoneNumbers: zod_1.z.number().int(),
1003
+ trades: zod_1.z.number().int(),
1004
+ qualifications: zod_1.z.number().int(),
1005
+ idDocuments: zod_1.z.number().int(),
1006
+ })
1007
+ .describe('Counts of relation items added to the curated worker'),
595
1008
  })
596
1009
  .openapi({ title: 'LinkWithMergeResponse' });
1010
+ exports.LinkWorkersWithMergeSchema = zod_1.z
1011
+ .object({
1012
+ curatedWorkerId: zod_1.z
1013
+ .string()
1014
+ .uuid()
1015
+ .describe('Existing curated worker to update + link to'),
1016
+ workerIds: zod_1.z
1017
+ .array(zod_1.z.string().uuid())
1018
+ .min(1)
1019
+ .max(100)
1020
+ .describe('Unmatched workers to link to the curated worker'),
1021
+ // Resolved final values for the curated record (picked across workers + curated)
1022
+ firstName: zod_1.z.string(),
1023
+ lastName: zod_1.z.string(),
1024
+ email: zod_1.z.string().nullable().optional(),
1025
+ nino: zod_1.z.string().nullable().optional(),
1026
+ dateOfBirth: zod_1.z.string().date().nullable().optional(),
1027
+ bio: zod_1.z.string().nullable().optional(),
1028
+ hasTools: zod_1.z.boolean().nullable(),
1029
+ hasPpe: zod_1.z.boolean().nullable(),
1030
+ englishLevel: zod_1.z.string().nullable().optional(),
1031
+ nationality: zod_1.z.string().nullable().optional(),
1032
+ locationId: zod_1.z.string().uuid().nullable().optional(),
1033
+ transportation: common_schemas_1.TransportationSchema.nullable().optional(),
1034
+ phoneNumbers: zod_1.z
1035
+ .array(zod_1.z.object({
1036
+ phoneNumber: common_schemas_1.PhoneSchema,
1037
+ isPrimary: zod_1.z.boolean(),
1038
+ description: zod_1.z.string().nullable().optional(),
1039
+ }))
1040
+ .optional()
1041
+ .default([]),
1042
+ trades: zod_1.z
1043
+ .array(zod_1.z.object({ tradeId: zod_1.z.string().uuid(), mainTrade: zod_1.z.boolean() }))
1044
+ .optional()
1045
+ .default([]),
1046
+ qualifications: zod_1.z
1047
+ .array(zod_1.z.object({
1048
+ qualificationId: zod_1.z.string().uuid(),
1049
+ qualificationTypeId: zod_1.z.string().uuid().nullable().optional(),
1050
+ issueDate: zod_1.z.string().date().nullable().optional(),
1051
+ expiryDate: zod_1.z.string().date().nullable().optional(),
1052
+ referenceNumber: zod_1.z.string().nullable().optional(),
1053
+ proofDocumentFileId: zod_1.z.string().uuid().nullable().optional(),
1054
+ }))
1055
+ .optional()
1056
+ .default([]),
1057
+ idDocuments: zod_1.z
1058
+ .array(zod_1.z.object({
1059
+ fileId: zod_1.z.string().uuid().nullable().optional(),
1060
+ documentType: common_schemas_1.IdDocumentTypeSchema.nullable().optional(),
1061
+ expiryDate: zod_1.z.string().date().nullable().optional(),
1062
+ documentNumber: zod_1.z.string().max(100).nullable().optional(),
1063
+ }))
1064
+ .optional()
1065
+ .default([]),
1066
+ shareCode: zod_1.z
1067
+ .object({
1068
+ code: zod_1.z.string().nullable().optional(),
1069
+ expiryDate: zod_1.z.string().nullable().optional(),
1070
+ fileId: zod_1.z.string().uuid().nullable().optional(),
1071
+ })
1072
+ .nullable()
1073
+ .optional(),
1074
+ })
1075
+ .openapi({ title: 'LinkWorkersWithMerge' });
1076
+ exports.LinkWorkersWithMergeResponseSchema = zod_1.z
1077
+ .object({
1078
+ curatedWorkerId: zod_1.z.string().uuid(),
1079
+ linkedWorkerIds: zod_1.z.array(zod_1.z.string().uuid()),
1080
+ })
1081
+ .openapi({ title: 'LinkWorkersWithMergeResponse' });
597
1082
  exports.BulkLinkWorkersSchema = zod_1.z
598
1083
  .object({
599
1084
  links: zod_1.z
@@ -611,6 +1096,59 @@ exports.BulkLinkWorkersResponseSchema = zod_1.z
611
1096
  linked: zod_1.z.number().describe('Number of workers linked'),
612
1097
  })
613
1098
  .openapi({ title: 'BulkLinkWorkersResponse' });
1099
+ // ---------------------------------------------------------------------------
1100
+ // Batch create
1101
+ // ---------------------------------------------------------------------------
1102
+ exports.BatchCreateWorkersBodySchema = zod_1.z
1103
+ .object({
1104
+ workers: zod_1.z
1105
+ .array(exports.CreateWorkerBodySchema)
1106
+ .min(1)
1107
+ .max(100)
1108
+ .describe('Array of workers to create'),
1109
+ })
1110
+ .openapi({ title: 'BatchCreateWorkers' });
1111
+ exports.BatchCreateWorkerResultSchema = zod_1.z
1112
+ .discriminatedUnion('status', [
1113
+ zod_1.z
1114
+ .object({
1115
+ index: zod_1.z.number().int().min(0),
1116
+ status: zod_1.z.literal('SUCCESS'),
1117
+ workerId: zod_1.z.string().uuid(),
1118
+ })
1119
+ .strict(),
1120
+ zod_1.z
1121
+ .object({
1122
+ index: zod_1.z.number().int().min(0),
1123
+ status: zod_1.z.literal('FAILED'),
1124
+ error: zod_1.z.string(),
1125
+ })
1126
+ .strict(),
1127
+ zod_1.z
1128
+ .object({
1129
+ index: zod_1.z.number().int().min(0),
1130
+ status: zod_1.z.literal('ATTRIBUTION_REQUIRED'),
1131
+ challenge: exports.WorkerSourceAttributionChallengeSchema,
1132
+ })
1133
+ .strict(),
1134
+ zod_1.z
1135
+ .object({
1136
+ index: zod_1.z.number().int().min(0),
1137
+ status: zod_1.z.literal('IDENTITY_CONFLICT'),
1138
+ identityConflict: worker_source_identity_conflicts_schemas_1.WorkerSourceIdentityConflictReferenceSchema,
1139
+ })
1140
+ .strict(),
1141
+ ])
1142
+ .openapi({ title: 'BatchCreateWorkerResult' });
1143
+ exports.BatchCreateWorkersResponseSchema = zod_1.z
1144
+ .object({
1145
+ results: zod_1.z
1146
+ .array(exports.BatchCreateWorkerResultSchema)
1147
+ .describe('Per-worker results'),
1148
+ created: zod_1.z.number().describe('Total workers successfully created'),
1149
+ })
1150
+ .strict()
1151
+ .openapi({ title: 'BatchCreateWorkersResponse' });
614
1152
  exports.PromoteWorkerResponseSchema = zod_1.z
615
1153
  .object({
616
1154
  workerId: zod_1.z.string().uuid().describe('Worker ID'),
@@ -620,6 +1158,69 @@ exports.PromoteWorkerResponseSchema = zod_1.z
620
1158
  .describe('Newly created Curated Worker ID'),
621
1159
  })
622
1160
  .openapi({ title: 'PromoteWorkerResponse' });
1161
+ exports.BulkPromoteUnmatchedPreviewResponseSchema = zod_1.z
1162
+ .object({
1163
+ unmatchedWorkerCount: zod_1.z
1164
+ .number()
1165
+ .int()
1166
+ .min(0)
1167
+ .describe('Unlinked workers with no suggested curated match'),
1168
+ skippedNoPhoneCount: zod_1.z
1169
+ .number()
1170
+ .int()
1171
+ .min(0)
1172
+ .describe('Unmatched workers excluded because they have no phone number'),
1173
+ skippedSharedPhoneCount: zod_1.z
1174
+ .number()
1175
+ .int()
1176
+ .min(0)
1177
+ .describe('Unmatched, phone-bearing workers excluded because their phone is shared with another worker (need manual merge)'),
1178
+ eligibleWorkerCount: zod_1.z
1179
+ .number()
1180
+ .int()
1181
+ .min(0)
1182
+ .describe('Unmatched workers with a unique phone number that will be promoted'),
1183
+ resultingCuratedWorkerCount: zod_1.z
1184
+ .number()
1185
+ .int()
1186
+ .min(0)
1187
+ .describe('Curated workers that would be created (one per unique-phone worker)'),
1188
+ })
1189
+ .openapi({ title: 'BulkPromoteUnmatchedPreviewResponse' });
1190
+ exports.BulkPromoteUnmatchedResponseSchema = zod_1.z
1191
+ .object({
1192
+ createdCuratedWorkerCount: zod_1.z
1193
+ .number()
1194
+ .int()
1195
+ .min(0)
1196
+ .describe('Curated workers created'),
1197
+ linkedWorkerCount: zod_1.z
1198
+ .number()
1199
+ .int()
1200
+ .min(0)
1201
+ .describe('Workers linked to a newly created curated worker'),
1202
+ skippedNoPhoneCount: zod_1.z
1203
+ .number()
1204
+ .int()
1205
+ .min(0)
1206
+ .describe('Unmatched workers skipped for having no phone number'),
1207
+ skippedSharedPhoneCount: zod_1.z
1208
+ .number()
1209
+ .int()
1210
+ .min(0)
1211
+ .describe('Unmatched workers skipped because their phone is shared with another worker (need manual merge)'),
1212
+ skippedAlreadyLinkedCount: zod_1.z
1213
+ .number()
1214
+ .int()
1215
+ .min(0)
1216
+ .describe('Workers skipped because they were linked between preview and execute'),
1217
+ failedGroupCount: zod_1.z
1218
+ .number()
1219
+ .int()
1220
+ .min(0)
1221
+ .describe('Groups whose transaction failed and were rolled back'),
1222
+ })
1223
+ .openapi({ title: 'BulkPromoteUnmatchedResponse' });
623
1224
  exports.FilterSuggestedMatchesSchema = pagination_query_schema_1.PaginationQuerySchema.extend({
624
1225
  matchField: exports.MatchFieldSchema.optional().describe('Filter by match field tab'),
625
1226
  sortBy: zod_1.z
@@ -644,18 +1245,23 @@ exports.DuplicateGroupWorkerSchema = zod_1.z
644
1245
  email: zod_1.z.string().nullable().optional(),
645
1246
  nino: zod_1.z.string().nullable().optional(),
646
1247
  dateOfBirth: zod_1.z.coerce.date().nullable().optional(),
647
- hasTools: zod_1.z.boolean().optional().default(false),
648
- hasPpe: zod_1.z.boolean().optional().default(false),
1248
+ hasTools: zod_1.z.boolean().nullable().optional().default(null),
1249
+ hasPpe: zod_1.z.boolean().nullable().optional().default(null),
649
1250
  bio: zod_1.z.string().nullable().optional(),
650
1251
  englishLevel: common_schemas_1.EnglishLevelSchema.nullable().optional(),
651
1252
  nationality: common_schemas_1.NationalitySchema.nullable().optional(),
652
1253
  locationId: zod_1.z.string().uuid().nullable().optional(),
1254
+ location: summary_schemas_1.LocationSummarySchema.nullable().optional(),
653
1255
  transportation: common_schemas_1.TransportationSchema.nullable().optional(),
654
1256
  phoneNumbers: zod_1.z.array(exports.WorkerPhoneNumberSchema).optional().default([]),
655
1257
  trades: zod_1.z.array(exports.WorkerTradeSchema).optional().default([]),
656
1258
  qualifications: zod_1.z.array(exports.WorkerQualificationSchema).optional().default([]),
1259
+ idDocuments: zod_1.z.array(exports.WorkerIdDocumentSchema).optional().default([]),
1260
+ shareCode: exports.ShareCodeSchema.nullable().optional().describe('Share Code'),
657
1261
  createdByUserId: zod_1.z.string().uuid().nullable().optional(),
1262
+ createdBy: summary_schemas_1.UserSummarySchema.nullable().optional().describe('Created By'),
658
1263
  createdAt: zod_1.z.coerce.date(),
1264
+ updatedAt: zod_1.z.coerce.date(),
659
1265
  })
660
1266
  .openapi({ title: 'DuplicateGroupWorker' });
661
1267
  exports.DuplicateGroupSchema = zod_1.z
@@ -696,6 +1302,31 @@ exports.FindDuplicatesSummaryResponseSchema = zod_1.z
696
1302
  limit: zod_1.z.number(),
697
1303
  })
698
1304
  .openapi({ title: 'FindDuplicatesSummaryResponse' });
1305
+ exports.FindWorkersByPhonesBodySchema = zod_1.z
1306
+ .object({
1307
+ phones: zod_1.z
1308
+ .array(zod_1.z.string())
1309
+ .min(1)
1310
+ .max(500)
1311
+ .describe('Phone numbers to look up'),
1312
+ })
1313
+ .openapi({ title: 'FindWorkersByPhonesBody' });
1314
+ exports.WorkerPhoneLookupResultSchema = zod_1.z
1315
+ .object({
1316
+ phone: zod_1.z.string().describe('The phone number that was queried'),
1317
+ workerId: zod_1.z.string().uuid().describe('ID of the matched worker'),
1318
+ postcode: zod_1.z
1319
+ .string()
1320
+ .nullable()
1321
+ .describe('Denormalized postcode from worker location, null if no location'),
1322
+ bio: zod_1.z.string().nullable().describe('Worker bio, null if not set'),
1323
+ })
1324
+ .openapi({ title: 'WorkerPhoneLookupResult' });
1325
+ exports.FindWorkersByPhonesResponseSchema = zod_1.z
1326
+ .object({
1327
+ results: zod_1.z.array(exports.WorkerPhoneLookupResultSchema),
1328
+ })
1329
+ .openapi({ title: 'FindWorkersByPhonesResponse' });
699
1330
  exports.MergeDuplicateCuratedWorkerSchema = zod_1.z
700
1331
  .object({
701
1332
  firstName: zod_1.z.string(),
@@ -704,15 +1335,15 @@ exports.MergeDuplicateCuratedWorkerSchema = zod_1.z
704
1335
  nino: zod_1.z.string().nullable().optional(),
705
1336
  dateOfBirth: zod_1.z.coerce.date().nullable().optional(),
706
1337
  bio: zod_1.z.string().nullable().optional(),
707
- hasTools: zod_1.z.boolean(),
708
- hasPpe: zod_1.z.boolean(),
1338
+ hasTools: zod_1.z.boolean().nullable(),
1339
+ hasPpe: zod_1.z.boolean().nullable(),
709
1340
  englishLevel: common_schemas_1.EnglishLevelSchema.nullable().optional(),
710
1341
  nationality: common_schemas_1.NationalitySchema.nullable().optional(),
711
1342
  locationId: zod_1.z.string().uuid().nullable().optional(),
712
1343
  transportation: common_schemas_1.TransportationSchema.nullable().optional(),
713
1344
  phoneNumbers: zod_1.z
714
1345
  .array(zod_1.z.object({
715
- phoneNumber: zod_1.z.string(),
1346
+ phoneNumber: common_schemas_1.PhoneSchema,
716
1347
  isPrimary: zod_1.z.boolean(),
717
1348
  description: zod_1.z.string().nullable().optional(),
718
1349
  }))
@@ -736,6 +1367,23 @@ exports.MergeDuplicateCuratedWorkerSchema = zod_1.z
736
1367
  }))
737
1368
  .optional()
738
1369
  .default([]),
1370
+ idDocuments: zod_1.z
1371
+ .array(zod_1.z.object({
1372
+ fileId: zod_1.z.string().uuid().nullable().optional(),
1373
+ documentType: common_schemas_1.IdDocumentTypeSchema.nullable().optional(),
1374
+ expiryDate: zod_1.z.string().date().nullable().optional(),
1375
+ documentNumber: zod_1.z.string().max(100).nullable().optional(),
1376
+ }))
1377
+ .optional()
1378
+ .default([]),
1379
+ shareCode: zod_1.z
1380
+ .object({
1381
+ code: zod_1.z.string().nullable().optional(),
1382
+ expiryDate: zod_1.z.string().date().nullable().optional(),
1383
+ })
1384
+ .nullable()
1385
+ .optional()
1386
+ .describe('Share Code'),
739
1387
  })
740
1388
  .openapi({ title: 'MergeDuplicateCuratedWorker' });
741
1389
  exports.MergeDuplicatesRequestSchema = zod_1.z
@@ -751,46 +1399,88 @@ exports.MergeDuplicatesResponseSchema = zod_1.z
751
1399
  })
752
1400
  .openapi({ title: 'MergeDuplicatesResponse' });
753
1401
  exports.FilterWorkerSchema = pagination_query_schema_1.PaginationQuerySchema.extend({
754
- name: zod_1.z.string().optional().describe('Search by name'),
1402
+ createdBy: zod_1.z.string().uuid().optional().describe('Search Second Agent'),
1403
+ name: common_schemas_1.NameFilterSchema.optional().describe('Search by name (value) with optional exact match'),
755
1404
  email: zod_1.z.string().optional().describe('Filter by email'),
756
1405
  phone: zod_1.z.string().optional().describe('Filter by phone'),
757
- createdBy: zod_1.z.string().uuid().optional().describe('Search Second Agent'),
758
- availability: exports.AvailabilitySchema.optional()
759
- .nullable()
760
- .describe('Availability'),
761
- englishLevel: common_schemas_1.EnglishLevelSchema.optional()
762
- .nullable()
763
- .describe('English level'),
1406
+ location: common_schemas_1.LocationFilterSchema.extend({
1407
+ autoRadius: zod_1.z
1408
+ .union([zod_1.z.boolean(), zod_1.z.enum(['true', 'false'])])
1409
+ .transform((v) => v === true || v === 'true')
1410
+ .optional()
1411
+ .describe('When true, the server picks the radius from local worker supply'),
1412
+ })
1413
+ .optional()
1414
+ .describe('Filter by location'),
1415
+ tradeFilters: zod_1.z.array(exports.TradeFilterSchema).optional().describe('Trades'),
1416
+ qualificationFilters: zod_1.z
1417
+ .array(common_schemas_1.QualificationFilterSchema)
1418
+ .optional()
1419
+ .describe('Qualifications'),
1420
+ occupancy: zod_1.z
1421
+ .enum(['ACTIVE', 'BOOKED', 'FREE'])
1422
+ .optional()
1423
+ .describe('Filter by booking-derived occupancy'),
1424
+ contact: zod_1.z
1425
+ .enum(['CHASEABLE', 'PAUSED', 'BLACKLISTED'])
1426
+ .optional()
1427
+ .describe('Filter by active contact suppression state'),
764
1428
  nationality: common_schemas_1.NationalitySchema.optional()
765
1429
  .nullable()
766
1430
  .describe('Filter by nationality'),
767
- location: common_schemas_1.LocationFilterSchema.optional().describe('Filter by location'),
1431
+ englishLevels: zod_1.z
1432
+ .array(common_schemas_1.EnglishLevelSchema)
1433
+ .optional()
1434
+ .describe('Filter by English levels'),
768
1435
  hasTools: exports.BooleanFilterSchema.optional().describe('Has Tools (default All)'),
769
1436
  hasPpe: exports.BooleanFilterSchema.optional().describe('Has PPE (default All)'),
1437
+ workedBefore: exports.BooleanFilterSchema.optional().describe('Worked before (default All)'),
1438
+ noShows: exports.BooleanFilterSchema.optional().describe('No-shows (default All)'),
770
1439
  transportationMethods: zod_1.z
771
1440
  .array(common_schemas_1.TransportationMethodSchema)
772
1441
  .optional()
773
1442
  .describe('Filter by transportation methods'),
774
- tradeFilters: zod_1.z.array(exports.TradeFilterSchema).optional().describe('Trades'),
775
- qualificationFilters: zod_1.z
776
- .array(curated_workers_contract_1.QualificationFilterSchema)
777
- .optional()
778
- .describe('Qualifications'),
779
1443
  createdAt: common_schemas_1.DateRangeSchema.optional().describe('Filter by creation date'),
780
1444
  updatedAt: common_schemas_1.DateRangeSchema.optional().describe('Filter by update date'),
781
- sortBy: exports.WorkerSortableFieldsSchema.optional()
782
- .nullable()
783
- .describe('Sort by field'),
784
- sortOrder: common_schemas_1.SortOrderSchema.optional().nullable().describe('Sort order'),
1445
+ sort: (0, common_schemas_1.createSortArraySchema)(exports.WorkerSortableFieldsSchema),
785
1446
  curatedWorkerId: zod_1.z
786
1447
  .enum(['linked', 'unlinked'])
787
1448
  .optional()
788
1449
  .describe('Filter by curated worker link status'),
789
1450
  crewId: zod_1.z.string().uuid().optional().describe('Filter by crew ID'),
1451
+ parked: zod_1.z.coerce
1452
+ .boolean()
1453
+ .optional()
1454
+ .describe('Filter to parked-only workers'),
1455
+ offerOpenness: zod_1.z.array(exports.OfferOpennessSchema).optional(),
1456
+ source: zod_1.z
1457
+ .array(exports.WorkerSourceSchema)
1458
+ .optional()
1459
+ .describe('Filter by how the worker was added'),
1460
+ proximityJobId: zod_1.z
1461
+ .string()
1462
+ .uuid()
1463
+ .optional()
1464
+ .describe('Book-workers context: when set, each worker row is enriched with its precomputed travel time to this job (from lead_proximity_owned) — driveMinutes/transitMinutes/travelTimeEnriched.'),
790
1465
  });
791
1466
  exports.PaginatedWorkerResponseSchema = (0, pagination_schema_1.createPaginatedResponseSchema)(exports.WorkerSchema)
792
1467
  .describe('Workers retrieved successfully.')
793
1468
  .openapi({ title: 'WorkersPaginatedResponse' });
1469
+ exports.PaginatedWorkerListResponseSchema = (0, pagination_schema_1.createPaginatedResponseSchema)(exports.WorkerListItemSchema)
1470
+ .describe('Workers list retrieved successfully.')
1471
+ .openapi({ title: 'WorkerListPaginatedResponse' });
1472
+ exports.FindAllWorkersResponseSchema = exports.PaginatedWorkerListResponseSchema.extend({
1473
+ appliedRadius: zod_1.z
1474
+ .number()
1475
+ .nullable()
1476
+ .optional()
1477
+ .describe('Radius (km) the server actually applied; null when no distance filter ran'),
1478
+ suggestedRadius: zod_1.z
1479
+ .number()
1480
+ .nullable()
1481
+ .optional()
1482
+ .describe('Supply-tiered radius (km) for the filtered postcode, independent of the applied radius; null when no postcode resolved. Lets the client offer "Auto" without a round trip.'),
1483
+ }).openapi({ title: 'WorkerListPaginatedResponseWithRadius' });
794
1484
  // --- Worker Import Schemas ---
795
1485
  exports.WorkerImportJobStatusSchema = zod_1.z
796
1486
  .enum(['PENDING', 'PROCESSING', 'COMPLETED', 'FAILED'])
@@ -800,6 +1490,18 @@ exports.StartWorkerImportSchema = zod_1.z
800
1490
  fileId: zod_1.z.string().uuid().describe('ID of the uploaded CSV file'),
801
1491
  })
802
1492
  .openapi({ title: 'StartWorkerImport' });
1493
+ const WORKER_IMPORT_IDENTITY_CONFLICT_REVIEW_URL_PREFIX = '/workers/identity-matches?workerSourceIdentityConflictContext=IMPORT&workerSourceIdentityConflictContextId=';
1494
+ const WorkerImportIdentityConflictReviewUrlSchema = zod_1.z
1495
+ .string()
1496
+ .refine((value) => {
1497
+ if (!value.startsWith(WORKER_IMPORT_IDENTITY_CONFLICT_REVIEW_URL_PREFIX)) {
1498
+ return false;
1499
+ }
1500
+ return zod_1.z
1501
+ .string()
1502
+ .uuid()
1503
+ .safeParse(value.slice(WORKER_IMPORT_IDENTITY_CONFLICT_REVIEW_URL_PREFIX.length)).success;
1504
+ }, 'Must be a relative, import-scoped Identity Matches review URL');
803
1505
  exports.WorkerImportJobSchema = zod_1.z
804
1506
  .object({
805
1507
  id: zod_1.z.string().uuid().describe('Import Job ID'),
@@ -808,6 +1510,21 @@ exports.WorkerImportJobSchema = zod_1.z
808
1510
  successCount: zod_1.z.number().describe('Successfully imported rows'),
809
1511
  failedCount: zod_1.z.number().describe('Failed rows'),
810
1512
  skippedCount: zod_1.z.number().describe('Skipped rows (duplicates)'),
1513
+ awaitingAttributionCount: zod_1.z
1514
+ .number()
1515
+ .int()
1516
+ .min(0)
1517
+ .describe('Current pending, unexpired source attribution challenges'),
1518
+ identityConflictCount: zod_1.z
1519
+ .number()
1520
+ .int()
1521
+ .min(0)
1522
+ .describe('Current OPEN identity conflict cases'),
1523
+ identityConflictReviewUrl: WorkerImportIdentityConflictReviewUrlSchema.nullable().describe('Identity Matches review URL for current OPEN conflict cases'),
1524
+ identityConflictCaseIds: zod_1.z
1525
+ .array(zod_1.z.string().uuid())
1526
+ .max(100)
1527
+ .describe('Up to 100 current OPEN identity conflict case IDs'),
811
1528
  errorMessage: zod_1.z
812
1529
  .string()
813
1530
  .nullable()
@@ -831,6 +1548,17 @@ exports.WorkerImportJobSchema = zod_1.z
831
1548
  .nullable()
832
1549
  .optional()
833
1550
  .describe('Completion timestamp'),
1551
+ })
1552
+ .strict()
1553
+ .superRefine((job, context) => {
1554
+ if (job.identityConflictReviewUrl !== null &&
1555
+ job.identityConflictReviewUrl.slice(WORKER_IMPORT_IDENTITY_CONFLICT_REVIEW_URL_PREFIX.length) !== job.id) {
1556
+ context.addIssue({
1557
+ code: 'custom',
1558
+ path: ['identityConflictReviewUrl'],
1559
+ message: 'Identity Matches review URL must be scoped to this import job',
1560
+ });
1561
+ }
834
1562
  })
835
1563
  .openapi({ title: 'WorkerImportJob' });
836
1564
  exports.WorkerImportResultSchema = zod_1.z
@@ -839,6 +1567,64 @@ exports.WorkerImportResultSchema = zod_1.z
839
1567
  mimeType: zod_1.z.string().describe('MIME type (text/csv)'),
840
1568
  })
841
1569
  .openapi({ title: 'WorkerImportResult' });
1570
+ exports.ListWorkerSourceAttributionChallengesQuerySchema = zod_1.z.object({
1571
+ page: zod_1.z.coerce.number().int().min(1).default(1),
1572
+ limit: zod_1.z.coerce.number().int().min(1).max(100).default(50),
1573
+ context: exports.WorkerSourceAttributionContextSchema.optional(),
1574
+ contextId: zod_1.z.string().uuid().optional(),
1575
+ sourceIdentityConflictId: zod_1.z.string().uuid().optional(),
1576
+ });
1577
+ exports.AdminListWorkerSourceAttributionChallengesQuerySchema = exports.ListWorkerSourceAttributionChallengesQuerySchema.extend({
1578
+ status: exports.WorkerSourceAttributionStatusSchema.optional(),
1579
+ });
1580
+ exports.WorkerSourceAttributionChallengeListResponseSchema = zod_1.z.object({
1581
+ data: zod_1.z.array(exports.WorkerSourceAttributionChallengeSchema),
1582
+ total: zod_1.z.number().int().min(0),
1583
+ page: zod_1.z.number().int().positive(),
1584
+ limit: zod_1.z.number().int().positive(),
1585
+ });
1586
+ exports.ResolveWorkerSourceAttributionChallengesBatchBodySchema = zod_1.z.object({
1587
+ items: zod_1.z
1588
+ .array(exports.ResolveWorkerSourceAttributionBodySchema.extend({
1589
+ challengeId: zod_1.z.string().uuid(),
1590
+ }))
1591
+ .min(1)
1592
+ .max(100),
1593
+ });
1594
+ exports.ResolveWorkerSourceAttributionChallengeResultSchema = zod_1.z.discriminatedUnion('status', [
1595
+ zod_1.z
1596
+ .object({
1597
+ challengeId: zod_1.z.string().uuid(),
1598
+ status: zod_1.z.literal('SUCCESS'),
1599
+ workerId: zod_1.z.string().uuid(),
1600
+ })
1601
+ .strict(),
1602
+ zod_1.z
1603
+ .object({
1604
+ challengeId: zod_1.z.string().uuid(),
1605
+ status: zod_1.z.literal('FAILED'),
1606
+ error: zod_1.z.string(),
1607
+ terminal: zod_1.z.boolean(),
1608
+ })
1609
+ .strict(),
1610
+ zod_1.z
1611
+ .object({
1612
+ challengeId: zod_1.z.string().uuid(),
1613
+ status: zod_1.z.literal('IDENTITY_CONFLICT'),
1614
+ error: zod_1.z.string(),
1615
+ terminal: zod_1.z.literal(true),
1616
+ identityConflict: worker_source_identity_conflicts_schemas_1.WorkerSourceIdentityConflictReferenceSchema,
1617
+ })
1618
+ .strict(),
1619
+ ]);
1620
+ exports.ResolveWorkerSourceAttributionChallengesBatchResponseSchema = zod_1.z
1621
+ .object({
1622
+ results: zod_1.z.array(exports.ResolveWorkerSourceAttributionChallengeResultSchema),
1623
+ })
1624
+ .strict();
1625
+ exports.InvalidateWorkerSourceAttributionChallengeBodySchema = zod_1.z.object({
1626
+ reason: zod_1.z.string().trim().min(1).max(500),
1627
+ });
842
1628
  // --- Contract ---
843
1629
  const c = (0, core_1.initContract)();
844
1630
  exports.workersContractRouter = c.router({
@@ -847,9 +1633,9 @@ exports.workersContractRouter = c.router({
847
1633
  path: '/v2/workers',
848
1634
  responses: {
849
1635
  201: exports.WorkerSchema,
850
- 409: error_schemas_1.ErrorResponseSchema,
1636
+ 409: exports.WorkerCreateConflictResponseSchema,
851
1637
  },
852
- body: exports.CreateWorkerBodySchema,
1638
+ body: exports.CreateSingleWorkerBodySchema,
853
1639
  summary: 'Create a new worker',
854
1640
  metadata: { tags: ['Workers'], openApi: { operationId: 'createWorker' } },
855
1641
  },
@@ -857,7 +1643,7 @@ exports.workersContractRouter = c.router({
857
1643
  method: 'GET',
858
1644
  path: '/v2/workers',
859
1645
  responses: {
860
- 200: exports.PaginatedWorkerResponseSchema,
1646
+ 200: exports.FindAllWorkersResponseSchema,
861
1647
  },
862
1648
  query: exports.FilterWorkerSchema,
863
1649
  summary: 'Get all workers',
@@ -912,6 +1698,85 @@ exports.workersContractRouter = c.router({
912
1698
  openApi: { operationId: 'getWorkerImportResult' },
913
1699
  },
914
1700
  },
1701
+ listSourceAttributionChallenges: {
1702
+ method: 'GET',
1703
+ path: '/v2/workers/source-attribution-challenges',
1704
+ query: exports.ListWorkerSourceAttributionChallengesQuerySchema,
1705
+ responses: {
1706
+ 200: exports.WorkerSourceAttributionChallengeListResponseSchema,
1707
+ },
1708
+ summary: "List the current user's pending source attribution challenges",
1709
+ metadata: {
1710
+ tags: ['Workers'],
1711
+ openApi: { operationId: 'listWorkerSourceAttributionChallenges' },
1712
+ },
1713
+ },
1714
+ resolveSourceAttributionChallengesBatch: {
1715
+ method: 'POST',
1716
+ path: '/v2/workers/source-attribution-challenges/resolve-batch',
1717
+ body: exports.ResolveWorkerSourceAttributionChallengesBatchBodySchema,
1718
+ responses: {
1719
+ 200: exports.ResolveWorkerSourceAttributionChallengesBatchResponseSchema,
1720
+ },
1721
+ summary: 'Resolve multiple source attribution challenges',
1722
+ metadata: {
1723
+ tags: ['Workers'],
1724
+ openApi: {
1725
+ operationId: 'resolveWorkerSourceAttributionChallengesBatch',
1726
+ },
1727
+ },
1728
+ },
1729
+ resolveSourceAttributionChallenge: {
1730
+ method: 'POST',
1731
+ path: '/v2/workers/source-attribution-challenges/:id/resolve',
1732
+ pathParams: zod_1.z.object({
1733
+ id: zod_1.z.string().uuid().describe('Source attribution challenge ID'),
1734
+ }),
1735
+ body: exports.ResolveWorkerSourceAttributionBodySchema,
1736
+ responses: {
1737
+ 201: exports.WorkerSchema,
1738
+ 404: error_schemas_1.ErrorResponseSchema,
1739
+ 409: error_schemas_1.ErrorResponseSchema,
1740
+ },
1741
+ summary: 'Resolve a source attribution challenge',
1742
+ metadata: {
1743
+ tags: ['Workers'],
1744
+ openApi: { operationId: 'resolveWorkerSourceAttributionChallenge' },
1745
+ },
1746
+ },
1747
+ adminListSourceAttributionChallenges: {
1748
+ method: 'GET',
1749
+ path: '/v2/workers/admin/source-attribution-challenges',
1750
+ query: exports.AdminListWorkerSourceAttributionChallengesQuerySchema,
1751
+ responses: {
1752
+ 200: exports.WorkerSourceAttributionChallengeListResponseSchema,
1753
+ },
1754
+ summary: 'List worker source attribution challenges for administrators',
1755
+ metadata: {
1756
+ tags: ['Workers'],
1757
+ openApi: { operationId: 'adminListWorkerSourceAttributionChallenges' },
1758
+ },
1759
+ },
1760
+ adminInvalidateSourceAttributionChallenge: {
1761
+ method: 'POST',
1762
+ path: '/v2/workers/admin/source-attribution-challenges/:id/invalidate',
1763
+ pathParams: zod_1.z.object({
1764
+ id: zod_1.z.string().uuid().describe('Source attribution challenge ID'),
1765
+ }),
1766
+ body: exports.InvalidateWorkerSourceAttributionChallengeBodySchema,
1767
+ responses: {
1768
+ 200: exports.WorkerSourceAttributionChallengeSchema,
1769
+ 404: error_schemas_1.ErrorResponseSchema,
1770
+ 409: error_schemas_1.ErrorResponseSchema,
1771
+ },
1772
+ summary: 'Invalidate a pending worker source attribution challenge',
1773
+ metadata: {
1774
+ tags: ['Workers'],
1775
+ openApi: {
1776
+ operationId: 'adminInvalidateWorkerSourceAttributionChallenge',
1777
+ },
1778
+ },
1779
+ },
915
1780
  suggestCuratedMatches: {
916
1781
  method: 'GET',
917
1782
  path: '/v2/workers/suggest-curated-matches',
@@ -925,6 +1790,21 @@ exports.workersContractRouter = c.router({
925
1790
  openApi: { operationId: 'suggestCuratedMatches' },
926
1791
  },
927
1792
  },
1793
+ suggestCuratedMatchGroups: {
1794
+ method: 'GET',
1795
+ path: '/v2/workers/suggest-curated-match-groups',
1796
+ query: zod_1.z.object({
1797
+ page: zod_1.z.coerce.number().int().min(1).default(1),
1798
+ limit: zod_1.z.coerce.number().int().min(1).max(200).default(50),
1799
+ matchField: exports.MatchFieldSchema.optional(),
1800
+ }),
1801
+ responses: { 200: exports.SuggestCuratedMatchGroupsResponseSchema },
1802
+ summary: 'Suggested curated matches grouped by curated worker (paginated by group)',
1803
+ metadata: {
1804
+ tags: ['Workers'],
1805
+ openApi: { operationId: 'suggestCuratedMatchGroups' },
1806
+ },
1807
+ },
928
1808
  findDuplicates: {
929
1809
  method: 'GET',
930
1810
  path: '/v2/workers/find-duplicates',
@@ -939,7 +1819,11 @@ exports.workersContractRouter = c.router({
939
1819
  findDuplicateGroupWorkers: {
940
1820
  method: 'GET',
941
1821
  path: '/v2/workers/find-duplicates/by-phone',
942
- query: zod_1.z.object({ phoneNumber: zod_1.z.string().describe('Phone number to find duplicate workers for') }),
1822
+ query: zod_1.z.object({
1823
+ phoneNumber: zod_1.z
1824
+ .string()
1825
+ .describe('Phone number to find duplicate workers for'),
1826
+ }),
943
1827
  responses: {
944
1828
  200: zod_1.z.object({
945
1829
  phoneNumber: zod_1.z.string(),
@@ -947,7 +1831,23 @@ exports.workersContractRouter = c.router({
947
1831
  }),
948
1832
  },
949
1833
  summary: 'Get full worker details for a duplicate group by phone number',
950
- metadata: { tags: ['Workers'], openApi: { operationId: 'findDuplicateGroupWorkers' } },
1834
+ metadata: {
1835
+ tags: ['Workers'],
1836
+ openApi: { operationId: 'findDuplicateGroupWorkers' },
1837
+ },
1838
+ },
1839
+ findByPhones: {
1840
+ method: 'POST',
1841
+ path: '/v2/workers/find-by-phones',
1842
+ body: exports.FindWorkersByPhonesBodySchema,
1843
+ responses: {
1844
+ 200: exports.FindWorkersByPhonesResponseSchema,
1845
+ },
1846
+ summary: 'Find multiple workers by phone numbers in a single batch request',
1847
+ metadata: {
1848
+ tags: ['Workers'],
1849
+ openApi: { operationId: 'findWorkersByPhones' },
1850
+ },
951
1851
  },
952
1852
  mergeDuplicates: {
953
1853
  method: 'POST',
@@ -978,6 +1878,49 @@ exports.workersContractRouter = c.router({
978
1878
  openApi: { operationId: 'bulkLinkWorkers' },
979
1879
  },
980
1880
  },
1881
+ batchCreate: {
1882
+ method: 'POST',
1883
+ path: '/v2/workers/batch-create',
1884
+ responses: {
1885
+ 201: exports.BatchCreateWorkersResponseSchema,
1886
+ 400: error_schemas_1.ErrorResponseSchema,
1887
+ },
1888
+ body: exports.BatchCreateWorkersBodySchema,
1889
+ summary: 'Create multiple workers in a single batch',
1890
+ metadata: {
1891
+ tags: ['Workers'],
1892
+ openApi: { operationId: 'batchCreateWorkers' },
1893
+ },
1894
+ },
1895
+ jobMatchCount: {
1896
+ method: 'GET',
1897
+ path: '/v2/workers/job-match-count',
1898
+ query: zod_1.z.object({
1899
+ tradeId: zod_1.z.string().uuid().optional(),
1900
+ postcode: zod_1.z.string().optional(),
1901
+ }),
1902
+ responses: {
1903
+ 200: zod_1.z.object({ count: zod_1.z.number().int().min(0) }),
1904
+ },
1905
+ summary: "Count workers matching a job's trade and location filters",
1906
+ metadata: {
1907
+ tags: ['Workers'],
1908
+ openApi: { operationId: 'getWorkerJobMatchCount' },
1909
+ },
1910
+ },
1911
+ checkAvailability: {
1912
+ method: 'GET',
1913
+ path: '/v2/workers/availability',
1914
+ query: exports.CheckWorkerAvailabilityQuerySchema,
1915
+ responses: {
1916
+ 200: exports.CheckWorkerAvailabilityResponseSchema,
1917
+ },
1918
+ summary: 'Look up a worker currently associated with the given phone number',
1919
+ metadata: {
1920
+ tags: ['Workers'],
1921
+ openApi: { operationId: 'checkWorkerAvailability' },
1922
+ },
1923
+ },
981
1924
  findOne: {
982
1925
  method: 'GET',
983
1926
  path: '/v2/workers/:id',
@@ -1005,7 +1948,7 @@ exports.workersContractRouter = c.router({
1005
1948
  pathParams: zod_1.z.object({
1006
1949
  id: zod_1.z.string().uuid().describe('Worker ID'),
1007
1950
  }),
1008
- body: exports.UpdateWorkerSchema,
1951
+ body: exports.UpdateWorkerBodySchema,
1009
1952
  summary: 'Update a worker',
1010
1953
  metadata: { tags: ['Workers'], openApi: { operationId: 'updateWorker' } },
1011
1954
  },
@@ -1059,6 +2002,21 @@ exports.workersContractRouter = c.router({
1059
2002
  openApi: { operationId: 'linkWorkerWithMerge' },
1060
2003
  },
1061
2004
  },
2005
+ linkWorkersWithMerge: {
2006
+ method: 'POST',
2007
+ path: '/v2/workers/link-workers-with-merge',
2008
+ responses: {
2009
+ 200: exports.LinkWorkersWithMergeResponseSchema,
2010
+ 404: error_schemas_1.ErrorResponseSchema,
2011
+ 409: error_schemas_1.ErrorResponseSchema,
2012
+ },
2013
+ body: exports.LinkWorkersWithMergeSchema,
2014
+ summary: 'Link multiple workers to an existing curated worker with merge',
2015
+ metadata: {
2016
+ tags: ['Workers'],
2017
+ openApi: { operationId: 'linkWorkersWithMerge' },
2018
+ },
2019
+ },
1062
2020
  promoteWorker: {
1063
2021
  method: 'POST',
1064
2022
  path: '/v2/workers/:id/promote',
@@ -1077,6 +2035,31 @@ exports.workersContractRouter = c.router({
1077
2035
  openApi: { operationId: 'promoteWorkerToCuratedWorker' },
1078
2036
  },
1079
2037
  },
2038
+ bulkPromoteUnmatchedPreview: {
2039
+ method: 'GET',
2040
+ path: '/v2/workers/bulk-promote-unmatched/preview',
2041
+ responses: {
2042
+ 200: exports.BulkPromoteUnmatchedPreviewResponseSchema,
2043
+ },
2044
+ summary: 'Preview the bulk-promote of unmatched workers to curated workers',
2045
+ metadata: {
2046
+ tags: ['Workers'],
2047
+ openApi: { operationId: 'previewBulkPromoteUnmatchedWorkers' },
2048
+ },
2049
+ },
2050
+ bulkPromoteUnmatched: {
2051
+ method: 'POST',
2052
+ path: '/v2/workers/bulk-promote-unmatched',
2053
+ body: c.noBody(),
2054
+ responses: {
2055
+ 201: exports.BulkPromoteUnmatchedResponseSchema,
2056
+ },
2057
+ summary: 'Promote all unmatched workers (with a phone) to curated workers',
2058
+ metadata: {
2059
+ tags: ['Workers'],
2060
+ openApi: { operationId: 'bulkPromoteUnmatchedWorkers' },
2061
+ },
2062
+ },
1080
2063
  }, {
1081
2064
  commonResponses: {
1082
2065
  400: error_schemas_1.ErrorResponseSchema,