@freighttech/shipment-tracking 0.6.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 (456) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +25 -0
  3. package/dist/generated/entities/bic_config/index.js +21 -0
  4. package/dist/generated/entities/bic_config/index.js.map +7 -0
  5. package/dist/generated/entities/carrier_config/index.js +27 -0
  6. package/dist/generated/entities/carrier_config/index.js.map +7 -0
  7. package/dist/generated/entities/location_override/index.js +33 -0
  8. package/dist/generated/entities/location_override/index.js.map +7 -0
  9. package/dist/generated/entities/shipment/index.js +73 -0
  10. package/dist/generated/entities/shipment/index.js.map +7 -0
  11. package/dist/generated/entities/ships_go_config/index.js +31 -0
  12. package/dist/generated/entities/ships_go_config/index.js.map +7 -0
  13. package/dist/generated/entities/tracking_event/index.js +101 -0
  14. package/dist/generated/entities/tracking_event/index.js.map +7 -0
  15. package/dist/generated/entities/tracking_job/index.js +47 -0
  16. package/dist/generated/entities/tracking_job/index.js.map +7 -0
  17. package/dist/generated/entities/webhook/index.js +25 -0
  18. package/dist/generated/entities/webhook/index.js.map +7 -0
  19. package/dist/generated/entities/webhook_delivery/index.js +25 -0
  20. package/dist/generated/entities/webhook_delivery/index.js.map +7 -0
  21. package/dist/generated/entities.ids.generated.js +21 -0
  22. package/dist/generated/entities.ids.generated.js.map +7 -0
  23. package/dist/index.js +41 -0
  24. package/dist/index.js.map +7 -0
  25. package/dist/modules/shipment_tracking/acl.js +22 -0
  26. package/dist/modules/shipment_tracking/acl.js.map +7 -0
  27. package/dist/modules/shipment_tracking/api/bic-configs/route.js +176 -0
  28. package/dist/modules/shipment_tracking/api/bic-configs/route.js.map +7 -0
  29. package/dist/modules/shipment_tracking/api/bic-configs/test/route.js +95 -0
  30. package/dist/modules/shipment_tracking/api/bic-configs/test/route.js.map +7 -0
  31. package/dist/modules/shipment_tracking/api/cargo-events/route.js +93 -0
  32. package/dist/modules/shipment_tracking/api/cargo-events/route.js.map +7 -0
  33. package/dist/modules/shipment_tracking/api/carrier-configs/route.js +139 -0
  34. package/dist/modules/shipment_tracking/api/carrier-configs/route.js.map +7 -0
  35. package/dist/modules/shipment_tracking/api/dashboard/ships-map/route.js +177 -0
  36. package/dist/modules/shipment_tracking/api/dashboard/ships-map/route.js.map +7 -0
  37. package/dist/modules/shipment_tracking/api/location-overrides/route.js +179 -0
  38. package/dist/modules/shipment_tracking/api/location-overrides/route.js.map +7 -0
  39. package/dist/modules/shipment_tracking/api/openapi.js +27 -0
  40. package/dist/modules/shipment_tracking/api/openapi.js.map +7 -0
  41. package/dist/modules/shipment_tracking/api/shipments/route.js +192 -0
  42. package/dist/modules/shipment_tracking/api/shipments/route.js.map +7 -0
  43. package/dist/modules/shipment_tracking/api/shipsgo-configs/route.js +185 -0
  44. package/dist/modules/shipment_tracking/api/shipsgo-configs/route.js.map +7 -0
  45. package/dist/modules/shipment_tracking/api/tracking-jobs/route.js +144 -0
  46. package/dist/modules/shipment_tracking/api/tracking-jobs/route.js.map +7 -0
  47. package/dist/modules/shipment_tracking/api/tracking-jobs/sync/route.js +107 -0
  48. package/dist/modules/shipment_tracking/api/tracking-jobs/sync/route.js.map +7 -0
  49. package/dist/modules/shipment_tracking/api/utils.js +12 -0
  50. package/dist/modules/shipment_tracking/api/utils.js.map +7 -0
  51. package/dist/modules/shipment_tracking/api/webhooks/deliveries/route.js +76 -0
  52. package/dist/modules/shipment_tracking/api/webhooks/deliveries/route.js.map +7 -0
  53. package/dist/modules/shipment_tracking/api/webhooks/route.js +135 -0
  54. package/dist/modules/shipment_tracking/api/webhooks/route.js.map +7 -0
  55. package/dist/modules/shipment_tracking/api/webhooks/test/route.js +71 -0
  56. package/dist/modules/shipment_tracking/api/webhooks/test/route.js.map +7 -0
  57. package/dist/modules/shipment_tracking/assets/carriers/cma_cgm.png +0 -0
  58. package/dist/modules/shipment_tracking/assets/carriers/cosco.png +0 -0
  59. package/dist/modules/shipment_tracking/assets/carriers/evergreen.png +0 -0
  60. package/dist/modules/shipment_tracking/assets/carriers/hapag_lloyd.png +0 -0
  61. package/dist/modules/shipment_tracking/assets/carriers/maersk.png +0 -0
  62. package/dist/modules/shipment_tracking/assets/carriers/msc.png +0 -0
  63. package/dist/modules/shipment_tracking/assets/carriers/one.png +0 -0
  64. package/dist/modules/shipment_tracking/assets/carriers/oocl.png +0 -0
  65. package/dist/modules/shipment_tracking/assets/carriers/yang_ming.png +0 -0
  66. package/dist/modules/shipment_tracking/assets/carriers/zim.png +0 -0
  67. package/dist/modules/shipment_tracking/assets/index.js +52 -0
  68. package/dist/modules/shipment_tracking/assets/index.js.map +7 -0
  69. package/dist/modules/shipment_tracking/backend/carrier-configs/page.js +621 -0
  70. package/dist/modules/shipment_tracking/backend/carrier-configs/page.js.map +7 -0
  71. package/dist/modules/shipment_tracking/backend/carrier-configs/page.meta.js +19 -0
  72. package/dist/modules/shipment_tracking/backend/carrier-configs/page.meta.js.map +7 -0
  73. package/dist/modules/shipment_tracking/backend/location-overrides/page.js +198 -0
  74. package/dist/modules/shipment_tracking/backend/location-overrides/page.js.map +7 -0
  75. package/dist/modules/shipment_tracking/backend/location-overrides/page.meta.js +19 -0
  76. package/dist/modules/shipment_tracking/backend/location-overrides/page.meta.js.map +7 -0
  77. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.js +279 -0
  78. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.js.map +7 -0
  79. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.meta.js +19 -0
  80. package/dist/modules/shipment_tracking/backend/shipment-tracking/page.meta.js.map +7 -0
  81. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.js +10 -0
  82. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.js.map +7 -0
  83. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.meta.js +19 -0
  84. package/dist/modules/shipment_tracking/backend/tracking-jobs/page.meta.js.map +7 -0
  85. package/dist/modules/shipment_tracking/backend/webhooks/page.js +198 -0
  86. package/dist/modules/shipment_tracking/backend/webhooks/page.js.map +7 -0
  87. package/dist/modules/shipment_tracking/backend/webhooks/page.meta.js +19 -0
  88. package/dist/modules/shipment_tracking/backend/webhooks/page.meta.js.map +7 -0
  89. package/dist/modules/shipment_tracking/ce.js +52 -0
  90. package/dist/modules/shipment_tracking/ce.js.map +7 -0
  91. package/dist/modules/shipment_tracking/cli.js +229 -0
  92. package/dist/modules/shipment_tracking/cli.js.map +7 -0
  93. package/dist/modules/shipment_tracking/commands/bic-configs.js +66 -0
  94. package/dist/modules/shipment_tracking/commands/bic-configs.js.map +7 -0
  95. package/dist/modules/shipment_tracking/commands/carrier-configs.js +65 -0
  96. package/dist/modules/shipment_tracking/commands/carrier-configs.js.map +7 -0
  97. package/dist/modules/shipment_tracking/commands/index.js +9 -0
  98. package/dist/modules/shipment_tracking/commands/index.js.map +7 -0
  99. package/dist/modules/shipment_tracking/commands/location-overrides.js +93 -0
  100. package/dist/modules/shipment_tracking/commands/location-overrides.js.map +7 -0
  101. package/dist/modules/shipment_tracking/commands/shipments.js +200 -0
  102. package/dist/modules/shipment_tracking/commands/shipments.js.map +7 -0
  103. package/dist/modules/shipment_tracking/commands/shipsgo-configs.js +75 -0
  104. package/dist/modules/shipment_tracking/commands/shipsgo-configs.js.map +7 -0
  105. package/dist/modules/shipment_tracking/commands/tracking-jobs.js +120 -0
  106. package/dist/modules/shipment_tracking/commands/tracking-jobs.js.map +7 -0
  107. package/dist/modules/shipment_tracking/commands/tracking.js +140 -0
  108. package/dist/modules/shipment_tracking/commands/tracking.js.map +7 -0
  109. package/dist/modules/shipment_tracking/commands/webhooks.js +115 -0
  110. package/dist/modules/shipment_tracking/commands/webhooks.js.map +7 -0
  111. package/dist/modules/shipment_tracking/components/CombinedTimestampCell.js +168 -0
  112. package/dist/modules/shipment_tracking/components/CombinedTimestampCell.js.map +7 -0
  113. package/dist/modules/shipment_tracking/components/FacilityLocationInput.js +202 -0
  114. package/dist/modules/shipment_tracking/components/FacilityLocationInput.js.map +7 -0
  115. package/dist/modules/shipment_tracking/components/LocationOverrideDrawer.js +501 -0
  116. package/dist/modules/shipment_tracking/components/LocationOverrideDrawer.js.map +7 -0
  117. package/dist/modules/shipment_tracking/components/ShipmentDetailsDrawer.js +818 -0
  118. package/dist/modules/shipment_tracking/components/ShipmentDetailsDrawer.js.map +7 -0
  119. package/dist/modules/shipment_tracking/components/ShipmentDrawer.js +404 -0
  120. package/dist/modules/shipment_tracking/components/ShipmentDrawer.js.map +7 -0
  121. package/dist/modules/shipment_tracking/components/ShipsGoConfigSection.js +200 -0
  122. package/dist/modules/shipment_tracking/components/ShipsGoConfigSection.js.map +7 -0
  123. package/dist/modules/shipment_tracking/components/TimestampCell.js +108 -0
  124. package/dist/modules/shipment_tracking/components/TimestampCell.js.map +7 -0
  125. package/dist/modules/shipment_tracking/components/TrackingJobDrawer.js +343 -0
  126. package/dist/modules/shipment_tracking/components/TrackingJobDrawer.js.map +7 -0
  127. package/dist/modules/shipment_tracking/components/VesselTrackingMap.js +496 -0
  128. package/dist/modules/shipment_tracking/components/VesselTrackingMap.js.map +7 -0
  129. package/dist/modules/shipment_tracking/components/WebhookDrawer.js +332 -0
  130. package/dist/modules/shipment_tracking/components/WebhookDrawer.js.map +7 -0
  131. package/dist/modules/shipment_tracking/data/entities.js +686 -0
  132. package/dist/modules/shipment_tracking/data/entities.js.map +7 -0
  133. package/dist/modules/shipment_tracking/data/validators.js +434 -0
  134. package/dist/modules/shipment_tracking/data/validators.js.map +7 -0
  135. package/dist/modules/shipment_tracking/di.js +60 -0
  136. package/dist/modules/shipment_tracking/di.js.map +7 -0
  137. package/dist/modules/shipment_tracking/encryption.js +12 -0
  138. package/dist/modules/shipment_tracking/encryption.js.map +7 -0
  139. package/dist/modules/shipment_tracking/events.js +87 -0
  140. package/dist/modules/shipment_tracking/events.js.map +7 -0
  141. package/dist/modules/shipment_tracking/hooks/useVesselTracking.js +137 -0
  142. package/dist/modules/shipment_tracking/hooks/useVesselTracking.js.map +7 -0
  143. package/dist/modules/shipment_tracking/i18n/de.json +327 -0
  144. package/dist/modules/shipment_tracking/i18n/en.json +327 -0
  145. package/dist/modules/shipment_tracking/i18n/es.json +327 -0
  146. package/dist/modules/shipment_tracking/i18n/pl.json +327 -0
  147. package/dist/modules/shipment_tracking/index.js +15 -0
  148. package/dist/modules/shipment_tracking/index.js.map +7 -0
  149. package/dist/modules/shipment_tracking/lib/adapters/cma-cgm.js +66 -0
  150. package/dist/modules/shipment_tracking/lib/adapters/cma-cgm.js.map +7 -0
  151. package/dist/modules/shipment_tracking/lib/adapters/cosco-types.js +1 -0
  152. package/dist/modules/shipment_tracking/lib/adapters/cosco-types.js.map +7 -0
  153. package/dist/modules/shipment_tracking/lib/adapters/cosco.js +236 -0
  154. package/dist/modules/shipment_tracking/lib/adapters/cosco.js.map +7 -0
  155. package/dist/modules/shipment_tracking/lib/adapters/evergreen.js +87 -0
  156. package/dist/modules/shipment_tracking/lib/adapters/evergreen.js.map +7 -0
  157. package/dist/modules/shipment_tracking/lib/adapters/hapag-lloyd.js +68 -0
  158. package/dist/modules/shipment_tracking/lib/adapters/hapag-lloyd.js.map +7 -0
  159. package/dist/modules/shipment_tracking/lib/adapters/index.js +20 -0
  160. package/dist/modules/shipment_tracking/lib/adapters/index.js.map +7 -0
  161. package/dist/modules/shipment_tracking/lib/adapters/maersk.js +84 -0
  162. package/dist/modules/shipment_tracking/lib/adapters/maersk.js.map +7 -0
  163. package/dist/modules/shipment_tracking/lib/adapters/msc.js +170 -0
  164. package/dist/modules/shipment_tracking/lib/adapters/msc.js.map +7 -0
  165. package/dist/modules/shipment_tracking/lib/adapters/zim.js +85 -0
  166. package/dist/modules/shipment_tracking/lib/adapters/zim.js.map +7 -0
  167. package/dist/modules/shipment_tracking/lib/audit-helpers.js +20 -0
  168. package/dist/modules/shipment_tracking/lib/audit-helpers.js.map +7 -0
  169. package/dist/modules/shipment_tracking/lib/auth/base64url.js +8 -0
  170. package/dist/modules/shipment_tracking/lib/auth/base64url.js.map +7 -0
  171. package/dist/modules/shipment_tracking/lib/auth/oauth-client.js +38 -0
  172. package/dist/modules/shipment_tracking/lib/auth/oauth-client.js.map +7 -0
  173. package/dist/modules/shipment_tracking/lib/background.js +15 -0
  174. package/dist/modules/shipment_tracking/lib/background.js.map +7 -0
  175. package/dist/modules/shipment_tracking/lib/bic-api-client.js +106 -0
  176. package/dist/modules/shipment_tracking/lib/bic-api-client.js.map +7 -0
  177. package/dist/modules/shipment_tracking/lib/carrier-adapter.js +17 -0
  178. package/dist/modules/shipment_tracking/lib/carrier-adapter.js.map +7 -0
  179. package/dist/modules/shipment_tracking/lib/current-vessel.js +149 -0
  180. package/dist/modules/shipment_tracking/lib/current-vessel.js.map +7 -0
  181. package/dist/modules/shipment_tracking/lib/dcsa-event-mapping.js +124 -0
  182. package/dist/modules/shipment_tracking/lib/dcsa-event-mapping.js.map +7 -0
  183. package/dist/modules/shipment_tracking/lib/dcsa-event-parser.js +112 -0
  184. package/dist/modules/shipment_tracking/lib/dcsa-event-parser.js.map +7 -0
  185. package/dist/modules/shipment_tracking/lib/dcsa-params.js +16 -0
  186. package/dist/modules/shipment_tracking/lib/dcsa-params.js.map +7 -0
  187. package/dist/modules/shipment_tracking/lib/empty-return.js +48 -0
  188. package/dist/modules/shipment_tracking/lib/empty-return.js.map +7 -0
  189. package/dist/modules/shipment_tracking/lib/location-overrides.js +85 -0
  190. package/dist/modules/shipment_tracking/lib/location-overrides.js.map +7 -0
  191. package/dist/modules/shipment_tracking/lib/location-types.js +59 -0
  192. package/dist/modules/shipment_tracking/lib/location-types.js.map +7 -0
  193. package/dist/modules/shipment_tracking/lib/logger.js +113 -0
  194. package/dist/modules/shipment_tracking/lib/logger.js.map +7 -0
  195. package/dist/modules/shipment_tracking/lib/poi-event-processor.js +183 -0
  196. package/dist/modules/shipment_tracking/lib/poi-event-processor.js.map +7 -0
  197. package/dist/modules/shipment_tracking/lib/poi-nats-config.js +52 -0
  198. package/dist/modules/shipment_tracking/lib/poi-nats-config.js.map +7 -0
  199. package/dist/modules/shipment_tracking/lib/poi-types.js +43 -0
  200. package/dist/modules/shipment_tracking/lib/poi-types.js.map +7 -0
  201. package/dist/modules/shipment_tracking/lib/rate-limiter.js +31 -0
  202. package/dist/modules/shipment_tracking/lib/rate-limiter.js.map +7 -0
  203. package/dist/modules/shipment_tracking/lib/route-extraction.js +187 -0
  204. package/dist/modules/shipment_tracking/lib/route-extraction.js.map +7 -0
  205. package/dist/modules/shipment_tracking/lib/route-inference.js +106 -0
  206. package/dist/modules/shipment_tracking/lib/route-inference.js.map +7 -0
  207. package/dist/modules/shipment_tracking/lib/schedule-generator.js +63 -0
  208. package/dist/modules/shipment_tracking/lib/schedule-generator.js.map +7 -0
  209. package/dist/modules/shipment_tracking/lib/shipsgo-client.js +143 -0
  210. package/dist/modules/shipment_tracking/lib/shipsgo-client.js.map +7 -0
  211. package/dist/modules/shipment_tracking/lib/shipsgo-mapper.js +204 -0
  212. package/dist/modules/shipment_tracking/lib/shipsgo-mapper.js.map +7 -0
  213. package/dist/modules/shipment_tracking/lib/status-machine.js +131 -0
  214. package/dist/modules/shipment_tracking/lib/status-machine.js.map +7 -0
  215. package/dist/modules/shipment_tracking/lib/time-extraction.js +41 -0
  216. package/dist/modules/shipment_tracking/lib/time-extraction.js.map +7 -0
  217. package/dist/modules/shipment_tracking/lib/timestamp-utils.js +100 -0
  218. package/dist/modules/shipment_tracking/lib/timestamp-utils.js.map +7 -0
  219. package/dist/modules/shipment_tracking/lib/vessel-api.js +111 -0
  220. package/dist/modules/shipment_tracking/lib/vessel-api.js.map +7 -0
  221. package/dist/modules/shipment_tracking/lib/vessel-cache.js +50 -0
  222. package/dist/modules/shipment_tracking/lib/vessel-cache.js.map +7 -0
  223. package/dist/modules/shipment_tracking/lib/vessel-extraction.js +13 -0
  224. package/dist/modules/shipment_tracking/lib/vessel-extraction.js.map +7 -0
  225. package/dist/modules/shipment_tracking/lib/webhook-dispatcher.js +62 -0
  226. package/dist/modules/shipment_tracking/lib/webhook-dispatcher.js.map +7 -0
  227. package/dist/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.js +48 -0
  228. package/dist/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.js.map +7 -0
  229. package/dist/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.js +15 -0
  230. package/dist/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.js.map +7 -0
  231. package/dist/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.js +47 -0
  232. package/dist/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.js.map +7 -0
  233. package/dist/modules/shipment_tracking/notifications.js +145 -0
  234. package/dist/modules/shipment_tracking/notifications.js.map +7 -0
  235. package/dist/modules/shipment_tracking/services/carrierRegistry.js +24 -0
  236. package/dist/modules/shipment_tracking/services/carrierRegistry.js.map +7 -0
  237. package/dist/modules/shipment_tracking/services/poiNatsService.js +397 -0
  238. package/dist/modules/shipment_tracking/services/poiNatsService.js.map +7 -0
  239. package/dist/modules/shipment_tracking/services/shipsGoProvider.js +163 -0
  240. package/dist/modules/shipment_tracking/services/shipsGoProvider.js.map +7 -0
  241. package/dist/modules/shipment_tracking/services/trackingService.js +1283 -0
  242. package/dist/modules/shipment_tracking/services/trackingService.js.map +7 -0
  243. package/dist/modules/shipment_tracking/services/webhookService.js +263 -0
  244. package/dist/modules/shipment_tracking/services/webhookService.js.map +7 -0
  245. package/dist/modules/shipment_tracking/setup.js +72 -0
  246. package/dist/modules/shipment_tracking/setup.js.map +7 -0
  247. package/dist/modules/shipment_tracking/subscribers/cargo-event-created.js +60 -0
  248. package/dist/modules/shipment_tracking/subscribers/cargo-event-created.js.map +7 -0
  249. package/dist/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.js +58 -0
  250. package/dist/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.js.map +7 -0
  251. package/dist/modules/shipment_tracking/subscribers/poi-event-notification.js +82 -0
  252. package/dist/modules/shipment_tracking/subscribers/poi-event-notification.js.map +7 -0
  253. package/dist/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.js +53 -0
  254. package/dist/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.js.map +7 -0
  255. package/dist/modules/shipment_tracking/subscribers/shipment-status-changed.js +28 -0
  256. package/dist/modules/shipment_tracking/subscribers/shipment-status-changed.js.map +7 -0
  257. package/dist/modules/shipment_tracking/subscribers/terminal-event-ingest.js +67 -0
  258. package/dist/modules/shipment_tracking/subscribers/terminal-event-ingest.js.map +7 -0
  259. package/dist/modules/shipment_tracking/subscribers/tracking-job-initial-poll.js +30 -0
  260. package/dist/modules/shipment_tracking/subscribers/tracking-job-initial-poll.js.map +7 -0
  261. package/dist/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.js +19 -0
  262. package/dist/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.js.map +7 -0
  263. package/dist/modules/shipment_tracking/tables/index.js +6 -0
  264. package/dist/modules/shipment_tracking/tables/index.js.map +7 -0
  265. package/dist/modules/shipment_tracking/tables/tracking_job/table.client.js +284 -0
  266. package/dist/modules/shipment_tracking/tables/tracking_job/table.client.js.map +7 -0
  267. package/dist/modules/shipment_tracking/tables/tracking_job/table.js +36 -0
  268. package/dist/modules/shipment_tracking/tables/tracking_job/table.js.map +7 -0
  269. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/config.js +25 -0
  270. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/config.js.map +7 -0
  271. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.js +355 -0
  272. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.js.map +7 -0
  273. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.js +26 -0
  274. package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.js.map +7 -0
  275. package/dist/types/assets.d.js +1 -0
  276. package/dist/types/assets.d.js.map +7 -0
  277. package/generated/entities/bic_config/index.ts +20 -0
  278. package/generated/entities/carrier_config/index.ts +23 -0
  279. package/generated/entities/location_override/index.ts +26 -0
  280. package/generated/entities/shipment/index.ts +46 -0
  281. package/generated/entities/ships_go_config/index.ts +25 -0
  282. package/generated/entities/tracking_event/index.ts +60 -0
  283. package/generated/entities/tracking_job/index.ts +33 -0
  284. package/generated/entities/webhook/index.ts +22 -0
  285. package/generated/entities/webhook_delivery/index.ts +22 -0
  286. package/generated/entities.ids.generated.ts +47 -0
  287. package/package.json +81 -0
  288. package/src/index.ts +39 -0
  289. package/src/modules/shipment_tracking/__integration__/TC-TRACK-410-shipsgo-config-api.spec.ts +133 -0
  290. package/src/modules/shipment_tracking/__integration__/meta.ts +4 -0
  291. package/src/modules/shipment_tracking/__tests__/empty-return-stop.test.ts +231 -0
  292. package/src/modules/shipment_tracking/__tests__/fixtures/hapag-lloyd-transship-container.json +702 -0
  293. package/src/modules/shipment_tracking/__tests__/fixtures/index.ts +434 -0
  294. package/src/modules/shipment_tracking/__tests__/fixtures/maersk-multi-transship-completed.json +1518 -0
  295. package/src/modules/shipment_tracking/__tests__/fixtures/maersk-transship-intransit.json +558 -0
  296. package/src/modules/shipment_tracking/__tests__/fixtures/msc-direct.json +222 -0
  297. package/src/modules/shipment_tracking/__tests__/fixtures/msc-multi-transship-completed.json +974 -0
  298. package/src/modules/shipment_tracking/__tests__/fixtures/msc-multi.json +4846 -0
  299. package/src/modules/shipment_tracking/__tests__/fixtures/msc-transship.json +409 -0
  300. package/src/modules/shipment_tracking/__tests__/fixtures/poi-events.json +240 -0
  301. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic/index.ts +138 -0
  302. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-eta-updates.json +288 -0
  303. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-route-inference.json +201 -0
  304. package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-voyage-progression.json +410 -0
  305. package/src/modules/shipment_tracking/__tests__/shipsgo-air-mapper.test.ts +157 -0
  306. package/src/modules/shipment_tracking/__tests__/shipsgo-client.test.ts +155 -0
  307. package/src/modules/shipment_tracking/__tests__/shipsgo-mapper.test.ts +201 -0
  308. package/src/modules/shipment_tracking/__tests__/shipsgo-poll.test.ts +357 -0
  309. package/src/modules/shipment_tracking/__tests__/shipsgo-provider.test.ts +364 -0
  310. package/src/modules/shipment_tracking/__tests__/trackingService.integration.test.ts +2248 -0
  311. package/src/modules/shipment_tracking/__tests__/webhookPayload.test.ts +151 -0
  312. package/src/modules/shipment_tracking/acl.ts +18 -0
  313. package/src/modules/shipment_tracking/api/bic-configs/route.ts +206 -0
  314. package/src/modules/shipment_tracking/api/bic-configs/test/route.ts +108 -0
  315. package/src/modules/shipment_tracking/api/cargo-events/route.ts +101 -0
  316. package/src/modules/shipment_tracking/api/carrier-configs/route.ts +142 -0
  317. package/src/modules/shipment_tracking/api/dashboard/ships-map/route.ts +246 -0
  318. package/src/modules/shipment_tracking/api/location-overrides/route.ts +185 -0
  319. package/src/modules/shipment_tracking/api/openapi.ts +28 -0
  320. package/src/modules/shipment_tracking/api/shipments/route.ts +197 -0
  321. package/src/modules/shipment_tracking/api/shipsgo-configs/route.ts +215 -0
  322. package/src/modules/shipment_tracking/api/tracking-jobs/route.ts +149 -0
  323. package/src/modules/shipment_tracking/api/tracking-jobs/sync/route.ts +116 -0
  324. package/src/modules/shipment_tracking/api/utils.ts +10 -0
  325. package/src/modules/shipment_tracking/api/webhooks/deliveries/route.ts +82 -0
  326. package/src/modules/shipment_tracking/api/webhooks/route.ts +138 -0
  327. package/src/modules/shipment_tracking/api/webhooks/test/route.ts +84 -0
  328. package/src/modules/shipment_tracking/assets/carriers/cma_cgm.png +0 -0
  329. package/src/modules/shipment_tracking/assets/carriers/cosco.png +0 -0
  330. package/src/modules/shipment_tracking/assets/carriers/evergreen.png +0 -0
  331. package/src/modules/shipment_tracking/assets/carriers/hapag_lloyd.png +0 -0
  332. package/src/modules/shipment_tracking/assets/carriers/maersk.png +0 -0
  333. package/src/modules/shipment_tracking/assets/carriers/msc.png +0 -0
  334. package/src/modules/shipment_tracking/assets/carriers/one.png +0 -0
  335. package/src/modules/shipment_tracking/assets/carriers/oocl.png +0 -0
  336. package/src/modules/shipment_tracking/assets/carriers/yang_ming.png +0 -0
  337. package/src/modules/shipment_tracking/assets/carriers/zim.png +0 -0
  338. package/src/modules/shipment_tracking/assets/index.ts +66 -0
  339. package/src/modules/shipment_tracking/backend/carrier-configs/page.meta.ts +16 -0
  340. package/src/modules/shipment_tracking/backend/carrier-configs/page.tsx +782 -0
  341. package/src/modules/shipment_tracking/backend/location-overrides/page.meta.ts +16 -0
  342. package/src/modules/shipment_tracking/backend/location-overrides/page.tsx +241 -0
  343. package/src/modules/shipment_tracking/backend/shipment-tracking/page.meta.ts +16 -0
  344. package/src/modules/shipment_tracking/backend/shipment-tracking/page.tsx +340 -0
  345. package/src/modules/shipment_tracking/backend/tracking-jobs/page.meta.ts +16 -0
  346. package/src/modules/shipment_tracking/backend/tracking-jobs/page.tsx +16 -0
  347. package/src/modules/shipment_tracking/backend/webhooks/page.meta.ts +16 -0
  348. package/src/modules/shipment_tracking/backend/webhooks/page.tsx +228 -0
  349. package/src/modules/shipment_tracking/ce.ts +48 -0
  350. package/src/modules/shipment_tracking/cli.ts +321 -0
  351. package/src/modules/shipment_tracking/commands/bic-configs.ts +94 -0
  352. package/src/modules/shipment_tracking/commands/carrier-configs.ts +89 -0
  353. package/src/modules/shipment_tracking/commands/index.ts +8 -0
  354. package/src/modules/shipment_tracking/commands/location-overrides.ts +119 -0
  355. package/src/modules/shipment_tracking/commands/shipments.ts +247 -0
  356. package/src/modules/shipment_tracking/commands/shipsgo-configs.ts +101 -0
  357. package/src/modules/shipment_tracking/commands/tracking-jobs.ts +158 -0
  358. package/src/modules/shipment_tracking/commands/tracking.ts +230 -0
  359. package/src/modules/shipment_tracking/commands/webhooks.ts +159 -0
  360. package/src/modules/shipment_tracking/components/CombinedTimestampCell.tsx +236 -0
  361. package/src/modules/shipment_tracking/components/FacilityLocationInput.tsx +235 -0
  362. package/src/modules/shipment_tracking/components/LocationOverrideDrawer.tsx +586 -0
  363. package/src/modules/shipment_tracking/components/ShipmentDetailsDrawer.tsx +1364 -0
  364. package/src/modules/shipment_tracking/components/ShipmentDrawer.tsx +498 -0
  365. package/src/modules/shipment_tracking/components/ShipsGoConfigSection.tsx +266 -0
  366. package/src/modules/shipment_tracking/components/TimestampCell.tsx +146 -0
  367. package/src/modules/shipment_tracking/components/TrackingJobDrawer.tsx +467 -0
  368. package/src/modules/shipment_tracking/components/VesselTrackingMap.tsx +761 -0
  369. package/src/modules/shipment_tracking/components/WebhookDrawer.tsx +434 -0
  370. package/src/modules/shipment_tracking/data/entities.ts +748 -0
  371. package/src/modules/shipment_tracking/data/validators.ts +523 -0
  372. package/src/modules/shipment_tracking/di.ts +73 -0
  373. package/src/modules/shipment_tracking/encryption.ts +17 -0
  374. package/src/modules/shipment_tracking/events.ts +122 -0
  375. package/src/modules/shipment_tracking/hooks/useVesselTracking.ts +297 -0
  376. package/src/modules/shipment_tracking/i18n/de.json +327 -0
  377. package/src/modules/shipment_tracking/i18n/en.json +327 -0
  378. package/src/modules/shipment_tracking/i18n/es.json +327 -0
  379. package/src/modules/shipment_tracking/i18n/pl.json +327 -0
  380. package/src/modules/shipment_tracking/index.ts +13 -0
  381. package/src/modules/shipment_tracking/lib/__tests__/dcsa-event-mapping.test.ts +385 -0
  382. package/src/modules/shipment_tracking/lib/__tests__/dcsa-event-parser.test.ts +398 -0
  383. package/src/modules/shipment_tracking/lib/__tests__/empty-return.test.ts +174 -0
  384. package/src/modules/shipment_tracking/lib/__tests__/poi-event-processor.test.ts +699 -0
  385. package/src/modules/shipment_tracking/lib/__tests__/route-inference.test.ts +402 -0
  386. package/src/modules/shipment_tracking/lib/__tests__/status-machine.test.ts +447 -0
  387. package/src/modules/shipment_tracking/lib/__tests__/time-extraction.test.ts +331 -0
  388. package/src/modules/shipment_tracking/lib/__tests__/timestamp-utils.test.ts +260 -0
  389. package/src/modules/shipment_tracking/lib/__tests__/vessel-api.test.ts +125 -0
  390. package/src/modules/shipment_tracking/lib/__tests__/vessel-extraction.test.ts +108 -0
  391. package/src/modules/shipment_tracking/lib/adapters/cma-cgm.ts +84 -0
  392. package/src/modules/shipment_tracking/lib/adapters/cosco-types.ts +145 -0
  393. package/src/modules/shipment_tracking/lib/adapters/cosco.ts +314 -0
  394. package/src/modules/shipment_tracking/lib/adapters/evergreen.ts +107 -0
  395. package/src/modules/shipment_tracking/lib/adapters/hapag-lloyd.ts +88 -0
  396. package/src/modules/shipment_tracking/lib/adapters/index.ts +18 -0
  397. package/src/modules/shipment_tracking/lib/adapters/maersk.ts +104 -0
  398. package/src/modules/shipment_tracking/lib/adapters/msc.ts +223 -0
  399. package/src/modules/shipment_tracking/lib/adapters/zim.ts +106 -0
  400. package/src/modules/shipment_tracking/lib/audit-helpers.ts +29 -0
  401. package/src/modules/shipment_tracking/lib/auth/base64url.ts +4 -0
  402. package/src/modules/shipment_tracking/lib/auth/oauth-client.ts +53 -0
  403. package/src/modules/shipment_tracking/lib/background.ts +24 -0
  404. package/src/modules/shipment_tracking/lib/bic-api-client.ts +199 -0
  405. package/src/modules/shipment_tracking/lib/carrier-adapter.ts +136 -0
  406. package/src/modules/shipment_tracking/lib/current-vessel.ts +274 -0
  407. package/src/modules/shipment_tracking/lib/dcsa-event-mapping.ts +202 -0
  408. package/src/modules/shipment_tracking/lib/dcsa-event-parser.ts +163 -0
  409. package/src/modules/shipment_tracking/lib/dcsa-params.ts +14 -0
  410. package/src/modules/shipment_tracking/lib/empty-return.ts +122 -0
  411. package/src/modules/shipment_tracking/lib/location-overrides.ts +150 -0
  412. package/src/modules/shipment_tracking/lib/location-types.ts +154 -0
  413. package/src/modules/shipment_tracking/lib/logger.ts +195 -0
  414. package/src/modules/shipment_tracking/lib/poi-event-processor.ts +302 -0
  415. package/src/modules/shipment_tracking/lib/poi-nats-config.ts +134 -0
  416. package/src/modules/shipment_tracking/lib/poi-types.ts +198 -0
  417. package/src/modules/shipment_tracking/lib/rate-limiter.ts +58 -0
  418. package/src/modules/shipment_tracking/lib/route-extraction.ts +439 -0
  419. package/src/modules/shipment_tracking/lib/route-inference.ts +238 -0
  420. package/src/modules/shipment_tracking/lib/schedule-generator.ts +92 -0
  421. package/src/modules/shipment_tracking/lib/shipsgo-client.ts +350 -0
  422. package/src/modules/shipment_tracking/lib/shipsgo-mapper.ts +296 -0
  423. package/src/modules/shipment_tracking/lib/status-machine.ts +230 -0
  424. package/src/modules/shipment_tracking/lib/time-extraction.ts +85 -0
  425. package/src/modules/shipment_tracking/lib/timestamp-utils.ts +244 -0
  426. package/src/modules/shipment_tracking/lib/vessel-api.ts +299 -0
  427. package/src/modules/shipment_tracking/lib/vessel-cache.ts +102 -0
  428. package/src/modules/shipment_tracking/lib/vessel-extraction.ts +39 -0
  429. package/src/modules/shipment_tracking/lib/webhook-dispatcher.ts +93 -0
  430. package/src/modules/shipment_tracking/migrations/.snapshot-open-mercato.json +2914 -0
  431. package/src/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.ts +60 -0
  432. package/src/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.ts +22 -0
  433. package/src/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.ts +65 -0
  434. package/src/modules/shipment_tracking/notifications.ts +151 -0
  435. package/src/modules/shipment_tracking/services/carrierRegistry.ts +29 -0
  436. package/src/modules/shipment_tracking/services/poiNatsService.ts +526 -0
  437. package/src/modules/shipment_tracking/services/shipsGoProvider.ts +231 -0
  438. package/src/modules/shipment_tracking/services/trackingService.ts +1777 -0
  439. package/src/modules/shipment_tracking/services/webhookService.ts +347 -0
  440. package/src/modules/shipment_tracking/setup.ts +99 -0
  441. package/src/modules/shipment_tracking/subscribers/__tests__/terminal-event-ingest.test.ts +141 -0
  442. package/src/modules/shipment_tracking/subscribers/cargo-event-created.ts +115 -0
  443. package/src/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.ts +115 -0
  444. package/src/modules/shipment_tracking/subscribers/poi-event-notification.ts +144 -0
  445. package/src/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.ts +94 -0
  446. package/src/modules/shipment_tracking/subscribers/shipment-status-changed.ts +41 -0
  447. package/src/modules/shipment_tracking/subscribers/terminal-event-ingest.ts +109 -0
  448. package/src/modules/shipment_tracking/subscribers/tracking-job-initial-poll.ts +53 -0
  449. package/src/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.ts +50 -0
  450. package/src/modules/shipment_tracking/tables/index.ts +4 -0
  451. package/src/modules/shipment_tracking/tables/tracking_job/table.client.tsx +337 -0
  452. package/src/modules/shipment_tracking/tables/tracking_job/table.ts +34 -0
  453. package/src/modules/shipment_tracking/widgets/dashboard/ships-map/config.ts +32 -0
  454. package/src/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.tsx +448 -0
  455. package/src/modules/shipment_tracking/widgets/dashboard/ships-map/widget.ts +25 -0
  456. package/src/types/assets.d.ts +5 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Maps ShipsGo shipment responses into the internal `CarrierFetchResult` shape,
3
+ * so the existing ingestion pipeline (Shipment upsert, timestamps, status
4
+ * machine, route inference, unit-sync) consumes ShipsGo exactly like a DCSA
5
+ * carrier adapter.
6
+ *
7
+ * Ocean movement codes are translated onto the DCSA equipment/transport
8
+ * vocabulary the downstream event-mapping already understands
9
+ * (see dcsa-event-mapping.ts), so notifier events resolve unchanged.
10
+ */
11
+ import type { CarrierFetchResult, CarrierFetchedEvent } from './carrier-adapter'
12
+ import type {
13
+ TrackingEventType,
14
+ TrackingEventClassifierCode,
15
+ ModeOfTransport,
16
+ } from '../data/entities'
17
+ import type {
18
+ ShipsGoOceanContainer,
19
+ ShipsGoOceanMovement,
20
+ ShipsGoOceanShipment,
21
+ ShipsGoAirMovement,
22
+ ShipsGoAirShipment,
23
+ } from './shipsgo-client'
24
+
25
+ // ShipsGo ocean event → { internal DCSA-style eventType + eventCode }.
26
+ // GTIN/LOAD/DISC/GTOT map 1:1; ARRV→ARRI (DCSA spelling); EMSH/EMRT use the
27
+ // closest DCSA equipment code so the notifier resolves (pick-up / drop-off).
28
+ const OCEAN_EVENT_MAP: Record<string, { eventType: TrackingEventType; eventCode: string }> = {
29
+ EMSH: { eventType: 'EQUIPMENT', eventCode: 'PICK' }, // empty released to shipper
30
+ GTIN: { eventType: 'EQUIPMENT', eventCode: 'GTIN' },
31
+ LOAD: { eventType: 'EQUIPMENT', eventCode: 'LOAD' },
32
+ DEPA: { eventType: 'TRANSPORT', eventCode: 'DEPA' },
33
+ ARRV: { eventType: 'TRANSPORT', eventCode: 'ARRI' },
34
+ DISC: { eventType: 'EQUIPMENT', eventCode: 'DISC' },
35
+ GTOT: { eventType: 'EQUIPMENT', eventCode: 'GTOT' },
36
+ EMRT: { eventType: 'EQUIPMENT', eventCode: 'DROP' }, // empty returned to depot
37
+ }
38
+
39
+ function classifier(status: 'EST' | 'ACT'): TrackingEventClassifierCode {
40
+ return status === 'ACT' ? 'ACT' : 'EST'
41
+ }
42
+
43
+ /**
44
+ * Deterministic id for dedup — ShipsGo movements have no stable identifier.
45
+ * ACT (actual) movements key on their timestamp (immutable once they happen);
46
+ * EST (estimated) movements OMIT the timestamp so a shifting estimate maps to
47
+ * the same row and is refreshed in place (see the persistence loop) rather than
48
+ * inserting a new event every poll.
49
+ */
50
+ function movementId(container: string, m: ShipsGoOceanMovement): string {
51
+ const tsKey = m.status === 'EST' ? 'EST' : m.timestamp
52
+ return `${container}:${m.event}:${m.status}:${tsKey}`
53
+ }
54
+
55
+ function isLocode(code: string | null | undefined): boolean {
56
+ return typeof code === 'string' && /^[A-Z]{2}[A-Z0-9]{3}$/.test(code)
57
+ }
58
+
59
+ /**
60
+ * Extracts the local UTC offset from a ShipsGo ISO-8601 timestamp. ShipsGo dates
61
+ * carry the movement's local (port/airport) offset — e.g. `+08:00` for a Beijing
62
+ * departure — so `eventDateTime` (the UTC instant) alone loses the local wall
63
+ * clock the carrier reported. We persist the offset in `eventDateTimeOffset` for
64
+ * local-time display, matching the DCSA adapters. Returns null for UTC (`Z` or
65
+ * `+00:00`), which is already the default.
66
+ */
67
+ function isoOffset(ts: string): string | null {
68
+ const match = ts.match(/([+-]\d{2}:\d{2})$/)
69
+ if (!match || match[1] === '+00:00') return null
70
+ return match[1]
71
+ }
72
+
73
+ /**
74
+ * ShipsGo container size (feet, e.g. 40) + type (e.g. HC, GP, RF) → a readable
75
+ * equipment code ("40HC"). Not a true ISO 6346 code, but it's the container-type
76
+ * display slot and ShipsGo doesn't return the ISO code. Null when neither given.
77
+ */
78
+ function equipmentCode(container: ShipsGoOceanContainer): string | null {
79
+ const size = container.size != null ? String(container.size) : ''
80
+ const type = container.type ?? ''
81
+ const code = `${size}${type}`.trim()
82
+ return code || null
83
+ }
84
+
85
+ function mapOceanMovement(
86
+ container: ShipsGoOceanContainer,
87
+ m: ShipsGoOceanMovement,
88
+ ): CarrierFetchedEvent | null {
89
+ const mapping = OCEAN_EVENT_MAP[m.event]
90
+ if (!mapping) return null
91
+
92
+ const ts = new Date(m.timestamp)
93
+ if (Number.isNaN(ts.getTime())) return null
94
+
95
+ const loc = m.location
96
+ const hasVessel = Boolean(m.vessel?.name || m.vessel?.imo)
97
+
98
+ return {
99
+ source: 'shipsgo',
100
+ sourceEventId: movementId(container.number, m),
101
+ eventType: mapping.eventType,
102
+ eventCode: mapping.eventCode,
103
+ eventClassifierCode: classifier(m.status),
104
+ eventDateTime: ts,
105
+ eventDateTimeOffset: isoOffset(m.timestamp),
106
+ description: `ShipsGo ${m.event} (${m.status})`,
107
+ rawData: { provider: 'shipsgo', ...m },
108
+ equipmentReference: container.number,
109
+ isoEquipmentCode: equipmentCode(container),
110
+ locationName: loc?.name ?? null,
111
+ locationUnlocode: isLocode(loc?.code) ? loc?.code ?? null : null,
112
+ locationCountry: loc?.country?.code ?? null,
113
+ modeOfTransport: hasVessel ? ('VESSEL' as ModeOfTransport) : null,
114
+ vesselName: m.vessel?.name ?? null,
115
+ vesselImo: m.vessel?.imo != null ? String(m.vessel.imo) : null,
116
+ voyageNumber: m.voyage ?? null,
117
+ }
118
+ }
119
+
120
+ /**
121
+ * ShipsGo shipment-level route summary → a compact object for `Shipment.extra`.
122
+ * Origin/destination UNLOCODEs are already inferred from movement locations, so
123
+ * this captures the extras: POL/POD names + planned/predicted dates, transit
124
+ * time, transit %, transshipment count and CO2. Returns null when route is absent.
125
+ */
126
+ function oceanRouteExtra(shipment: ShipsGoOceanShipment): Record<string, unknown> | null {
127
+ const route = shipment.route
128
+ if (!route) return null
129
+ const pol = route.port_of_loading
130
+ const pod = route.port_of_discharge
131
+ const extra: Record<string, unknown> = {}
132
+ if (pol?.location) extra.portOfLoading = { unlocode: pol.location.code ?? null, name: pol.location.name ?? null }
133
+ if (pol?.date_of_loading) extra.dateOfLoading = pol.date_of_loading
134
+ if (pod?.location) extra.portOfDischarge = { unlocode: pod.location.code ?? null, name: pod.location.name ?? null }
135
+ if (pod?.date_of_discharge) extra.dateOfDischarge = pod.date_of_discharge
136
+ if (pod?.date_of_discharge_predicted) extra.dateOfDischargePredicted = pod.date_of_discharge_predicted
137
+ if (route.transit_time != null) extra.transitTimeDays = route.transit_time
138
+ if (route.transit_percentage != null) extra.transitPercentage = route.transit_percentage
139
+ if (route.ts_count != null) extra.transshipmentCount = route.ts_count
140
+ if (route.co2_emission != null) extra.co2Emission = route.co2_emission
141
+ return Object.keys(extra).length ? { shipsgoRoute: extra } : null
142
+ }
143
+
144
+ /**
145
+ * Maps a full ShipsGo ocean shipment (with containers + movements) into a
146
+ * `CarrierFetchResult`. Emits one event per movement per container; the
147
+ * downstream pipeline discovers containers from `equipmentReference`.
148
+ */
149
+ export function mapOceanShipmentToEvents(shipment: ShipsGoOceanShipment): CarrierFetchResult {
150
+ const events: CarrierFetchedEvent[] = []
151
+ let vesselName: string | null = null
152
+ let vesselImo: string | null = null
153
+
154
+ const containers = shipment.containers ?? []
155
+ for (const container of containers) {
156
+ const movements = container.movements ?? []
157
+ for (const m of movements) {
158
+ const event = mapOceanMovement(container, m)
159
+ if (!event) continue
160
+ events.push(event)
161
+ // Track the most recent vessel seen (movements are chronological).
162
+ if (event.vesselName) vesselName = event.vesselName
163
+ if (event.vesselImo) vesselImo = event.vesselImo
164
+ }
165
+ }
166
+
167
+ return {
168
+ events,
169
+ containerNumber: shipment.container_number ?? containers[0]?.number ?? null,
170
+ bookingNumber: shipment.booking_number ?? null,
171
+ bolNumber: null,
172
+ vesselName,
173
+ vesselImo,
174
+ extra: oceanRouteExtra(shipment),
175
+ }
176
+ }
177
+
178
+ // ─── Air ─────────────────────────────────────────────────────────────────────
179
+
180
+ // ShipsGo air event → internal event code. DEP/ARR are translated to the DCSA
181
+ // departure/arrival codes so the shared time-extraction (ATD/ATA) and timeline
182
+ // reuse unchanged; the rest keep their native code (informational only — air
183
+ // status is derived from ShipsGo's top-level status, see deriveAirShipmentStatus).
184
+ const AIR_EVENT_MAP: Record<string, string> = {
185
+ RCS: 'RCS', // received from shipper
186
+ MAN: 'MAN', // manifested
187
+ DEP: 'DEPA', // departed
188
+ ARR: 'ARRI', // arrived
189
+ RCF: 'RCF', // received from flight
190
+ DLV: 'DLVR', // delivered
191
+ }
192
+
193
+ /** Deterministic id for dedup — air movements have no stable identifier.
194
+ * EST omits the timestamp (refreshed in place); ACT keys on it (immutable). */
195
+ function airMovementId(awb: string, m: ShipsGoAirMovement): string {
196
+ const tsKey = m.status === 'EST' ? 'EST' : m.timestamp
197
+ return `${awb}:${m.event}:${m.status}:${tsKey}`
198
+ }
199
+
200
+ function mapAirMovement(awb: string, m: ShipsGoAirMovement): CarrierFetchedEvent | null {
201
+ const eventCode = AIR_EVENT_MAP[m.event]
202
+ if (!eventCode) return null
203
+
204
+ const ts = new Date(m.timestamp)
205
+ if (Number.isNaN(ts.getTime())) return null
206
+
207
+ const loc = m.location
208
+ return {
209
+ source: 'shipsgo',
210
+ sourceEventId: airMovementId(awb, m),
211
+ // Air movements are all transport-leg events (no container/equipment model).
212
+ eventType: 'TRANSPORT',
213
+ eventCode,
214
+ eventClassifierCode: classifier(m.status),
215
+ eventDateTime: ts,
216
+ eventDateTimeOffset: isoOffset(m.timestamp),
217
+ description: `ShipsGo air ${m.event} (${m.status})`,
218
+ rawData: { provider: 'shipsgo', mode: 'air', ...m },
219
+ // Air locations are IATA airports, not UN/LOCODEs — keep only the name/country.
220
+ locationName: loc?.name ?? loc?.iata ?? null,
221
+ locationUnlocode: null,
222
+ locationCountry: loc?.country?.code ?? null,
223
+ modeOfTransport: m.flight ? ('AIR' as ModeOfTransport) : null,
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Maps a full ShipsGo air shipment into a `CarrierFetchResult`. Emits one event
229
+ * per movement (no container fan-out); the downstream air branch creates a
230
+ * single AWB-keyed Shipment and fills flight/airline + the top-level air status.
231
+ */
232
+ export function mapAirShipmentToEvents(shipment: ShipsGoAirShipment): CarrierFetchResult {
233
+ const awb = shipment.awb_number ?? shipment.reference ?? ''
234
+ const events: CarrierFetchedEvent[] = []
235
+ let flightNumber: string | null = null
236
+
237
+ const movements = shipment.movements ?? []
238
+ for (const m of movements) {
239
+ const event = mapAirMovement(awb, m)
240
+ if (!event) continue
241
+ events.push(event)
242
+ // Track the most recent flight seen (movements are chronological).
243
+ if (m.flight) flightNumber = m.flight
244
+ }
245
+
246
+ return {
247
+ events,
248
+ containerNumber: null,
249
+ bookingNumber: null,
250
+ bolNumber: null,
251
+ awbNumber: shipment.awb_number ?? null,
252
+ flightNumber,
253
+ airlineCode: shipment.airline?.iata ?? null,
254
+ airlineName: shipment.airline?.name ?? null,
255
+ airStatus: shipment.status ?? null,
256
+ extra: airExtra(shipment),
257
+ }
258
+ }
259
+
260
+ /**
261
+ * ShipsGo air shipment-level extras → `Shipment.extra`: cargo (pieces/weight/
262
+ * volume) and the pieces-per-status breakdown. Returns null when neither given.
263
+ */
264
+ function airExtra(shipment: ShipsGoAirShipment): Record<string, unknown> | null {
265
+ const extra: Record<string, unknown> = {}
266
+ const c = shipment.cargo
267
+ if (c && (c.pieces != null || c.weight != null || c.volume != null)) {
268
+ extra.cargo = {
269
+ pieces: c.pieces ?? null,
270
+ weight: c.weight ?? null,
271
+ weightUnit: c.weight_unit ?? null,
272
+ volume: c.volume ?? null,
273
+ volumeUnit: c.volume_unit ?? null,
274
+ }
275
+ }
276
+ // Air route mirrors the ocean route (see oceanRouteExtra). Air locations are
277
+ // IATA airports (not UN/LOCODEs), so event-based origin/destination inference
278
+ // yields nothing — this is the only place origin/destination surface for air.
279
+ const route = shipment.route
280
+ if (route) {
281
+ const r: Record<string, unknown> = {}
282
+ const orig = route.origin
283
+ const dest = route.destination
284
+ if (orig?.location) r.origin = { iata: orig.location.iata ?? null, name: orig.location.name ?? null }
285
+ if (orig?.date_of_dep) r.dateOfDeparture = orig.date_of_dep
286
+ if (dest?.location) r.destination = { iata: dest.location.iata ?? null, name: dest.location.name ?? null }
287
+ if (dest?.date_of_rcf) r.dateOfArrival = dest.date_of_rcf
288
+ if (route.transit_time != null) r.transitTimeDays = route.transit_time
289
+ if (route.transit_percentage != null) r.transitPercentage = route.transit_percentage
290
+ if (route.ts_count != null) r.transshipmentCount = route.ts_count
291
+ if (route.co2_emission != null) r.co2Emission = route.co2_emission
292
+ if (Object.keys(r).length) extra.route = r
293
+ }
294
+ if (shipment.status_extended != null) extra.statusExtended = shipment.status_extended
295
+ return Object.keys(extra).length ? { shipsgoAir: extra } : null
296
+ }
@@ -0,0 +1,230 @@
1
+ import type { ShipmentStatusEnum, TrackingEventClassifierCode } from '../data/entities'
2
+
3
+ export type ShipmentStatus = ShipmentStatusEnum
4
+
5
+ type EventInput = {
6
+ eventCode: string
7
+ eventClassifierCode?: TrackingEventClassifierCode | null
8
+ locationUnlocode?: string | null
9
+ }
10
+
11
+ type ShipmentContext = {
12
+ originUnlocode?: string | null
13
+ destinationUnlocode?: string | null
14
+ }
15
+
16
+ type TimeContext = {
17
+ eta?: Date | null
18
+ ata?: Date | null
19
+ }
20
+
21
+ /**
22
+ * Number of days before ETA when a shipment transitions to PRE_ARRIVAL status.
23
+ * Shipment becomes PRE_ARRIVAL when: ETA is within this many days AND no ATA yet.
24
+ */
25
+ export const PRE_ARRIVAL_DAYS_THRESHOLD = 7
26
+
27
+ const STATUS_ORDER: ShipmentStatus[] = [
28
+ 'PENDING',
29
+ 'BOOKED',
30
+ 'DEPARTED',
31
+ 'IN_TRANSIT',
32
+ 'PRE_ARRIVAL',
33
+ 'ARRIVED',
34
+ 'DELIVERED',
35
+ ]
36
+
37
+ function statusRank(status: ShipmentStatus): number {
38
+ return STATUS_ORDER.indexOf(status)
39
+ }
40
+
41
+ function isAtDestination(eventLocation: string | null | undefined, destination: string | null | undefined): boolean {
42
+ if (!eventLocation || !destination) return false
43
+ return eventLocation.toUpperCase() === destination.toUpperCase()
44
+ }
45
+
46
+ function isAtOrigin(eventLocation: string | null | undefined, origin: string | null | undefined): boolean {
47
+ if (!eventLocation || !origin) return false
48
+ return eventLocation.toUpperCase() === origin.toUpperCase()
49
+ }
50
+
51
+ function deriveStatusFromEvent(event: EventInput, context: ShipmentContext): ShipmentStatus | null {
52
+ const code = event.eventCode.toUpperCase()
53
+ const classifierCode = event.eventClassifierCode
54
+
55
+ // DEPA at origin = DEPARTED
56
+ if (code === 'DEPA') {
57
+ if (classifierCode === 'ACT') {
58
+ return 'DEPARTED'
59
+ }
60
+ if (classifierCode === 'PLN' || classifierCode === 'EST') {
61
+ return 'BOOKED'
62
+ }
63
+ }
64
+
65
+ // ARRI at destination = ARRIVED (actual) or IN_TRANSIT (planned/estimated approaching)
66
+ if (code === 'ARRI' && isAtDestination(event.locationUnlocode, context.destinationUnlocode)) {
67
+ if (classifierCode === 'ACT') {
68
+ return 'ARRIVED'
69
+ }
70
+ return 'IN_TRANSIT'
71
+ }
72
+
73
+ // ARRI at non-destination with actual = IN_TRANSIT (transshipment)
74
+ if (code === 'ARRI' && classifierCode === 'ACT') {
75
+ return 'IN_TRANSIT'
76
+ }
77
+
78
+ // DISC (discharge) at destination = ARRIVED
79
+ if (code === 'DISC' && isAtDestination(event.locationUnlocode, context.destinationUnlocode)) {
80
+ if (classifierCode === 'ACT') {
81
+ return 'ARRIVED'
82
+ }
83
+ }
84
+
85
+ // LOAD at origin = BOOKED (loaded onto vessel)
86
+ if (code === 'LOAD' && isAtOrigin(event.locationUnlocode, context.originUnlocode)) {
87
+ if (classifierCode === 'ACT') {
88
+ return 'BOOKED'
89
+ }
90
+ }
91
+
92
+ // Gate out at destination = DELIVERED (GTOT = Gate Out Terminal, PICK = Pick-up)
93
+ if ((code === 'GTOT' || code === 'PICK') && isAtDestination(event.locationUnlocode, context.destinationUnlocode)) {
94
+ if (classifierCode === 'ACT') {
95
+ return 'DELIVERED'
96
+ }
97
+ }
98
+
99
+ // Gate in at destination = DELIVERED (empty return means cargo was delivered)
100
+ if (code === 'GTIN' && isAtDestination(event.locationUnlocode, context.destinationUnlocode)) {
101
+ if (classifierCode === 'ACT') {
102
+ return 'DELIVERED'
103
+ }
104
+ }
105
+
106
+ // Available for pick-up at destination = ARRIVED
107
+ if (code === 'AVPU' && isAtDestination(event.locationUnlocode, context.destinationUnlocode)) {
108
+ if (classifierCode === 'ACT') {
109
+ return 'ARRIVED'
110
+ }
111
+ }
112
+
113
+ // Customs released at destination = ARRIVED
114
+ if (code === 'CUSR' && isAtDestination(event.locationUnlocode, context.destinationUnlocode)) {
115
+ if (classifierCode === 'ACT') {
116
+ return 'ARRIVED'
117
+ }
118
+ }
119
+
120
+ // Delivery event = DELIVERED
121
+ if (code === 'DLVR' && classifierCode === 'ACT') {
122
+ return 'DELIVERED'
123
+ }
124
+
125
+ return null
126
+ }
127
+
128
+ /**
129
+ * Checks if a shipment qualifies for PRE_ARRIVAL status based on time.
130
+ * PRE_ARRIVAL = ETA is within threshold days AND no ATA yet.
131
+ */
132
+ function shouldUpgradeToPreArrival(timeContext: TimeContext | undefined): boolean {
133
+ if (!timeContext?.eta || timeContext.ata) {
134
+ return false
135
+ }
136
+
137
+ const now = new Date()
138
+ const daysUntilEta = (timeContext.eta.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)
139
+
140
+ return daysUntilEta <= PRE_ARRIVAL_DAYS_THRESHOLD && daysUntilEta >= 0
141
+ }
142
+
143
+ /**
144
+ * Derives the highest-priority shipment status from a set of tracking events.
145
+ * Status only moves forward (never downgrades), based on DCSA event codes.
146
+ *
147
+ * @param events - Array of tracking events to evaluate
148
+ * @param context - Location context (origin/destination UNLOCODEs)
149
+ * @param currentStatus - Current shipment status (defaults to PENDING)
150
+ * @param timeContext - Optional time context for PRE_ARRIVAL evaluation (ETA/ATA)
151
+ */
152
+ export function deriveShipmentStatus(
153
+ events: EventInput[],
154
+ context: ShipmentContext,
155
+ currentStatus: ShipmentStatus = 'PENDING',
156
+ timeContext?: TimeContext,
157
+ ): ShipmentStatus {
158
+ let best = currentStatus
159
+
160
+ for (const event of events) {
161
+ const derived = deriveStatusFromEvent(event, context)
162
+ if (derived && statusRank(derived) > statusRank(best)) {
163
+ best = derived
164
+ }
165
+ }
166
+
167
+ // Time-based PRE_ARRIVAL upgrade:
168
+ // If event-derived status is IN_TRANSIT (or lower) and time conditions are met,
169
+ // upgrade to PRE_ARRIVAL
170
+ if (statusRank(best) <= statusRank('IN_TRANSIT') && shouldUpgradeToPreArrival(timeContext)) {
171
+ const preArrivalRank = statusRank('PRE_ARRIVAL')
172
+ if (preArrivalRank > statusRank(best)) {
173
+ best = 'PRE_ARRIVAL'
174
+ }
175
+ }
176
+
177
+ return best
178
+ }
179
+
180
+ /**
181
+ * ShipsGo air top-level status → internal ShipmentStatusEnum.
182
+ * Air has no container/vessel movement model, so status is driven by ShipsGo's
183
+ * aggregate `status` field rather than event-location matching:
184
+ * NEW/UNTRACKED → PENDING, BOOKED → BOOKED, EN_ROUTE → IN_TRANSIT,
185
+ * LANDED → ARRIVED, DELIVERED → DELIVERED. (INPROGRESS ≈ BOOKED.)
186
+ * Monotonic: never downgrades below the current status.
187
+ */
188
+ const AIR_STATUS_MAP: Record<string, ShipmentStatus> = {
189
+ NEW: 'PENDING',
190
+ UNTRACKED: 'PENDING',
191
+ INPROGRESS: 'BOOKED',
192
+ BOOKED: 'BOOKED',
193
+ EN_ROUTE: 'IN_TRANSIT',
194
+ LANDED: 'ARRIVED',
195
+ DELIVERED: 'DELIVERED',
196
+ }
197
+
198
+ export function deriveAirShipmentStatus(
199
+ airStatus: string | null | undefined,
200
+ currentStatus: ShipmentStatus = 'PENDING',
201
+ ): ShipmentStatus {
202
+ if (!airStatus) return currentStatus
203
+ const mapped = AIR_STATUS_MAP[airStatus.toUpperCase()]
204
+ if (!mapped) return currentStatus
205
+ return statusRank(mapped) > statusRank(currentStatus) ? mapped : currentStatus
206
+ }
207
+
208
+ /**
209
+ * Evaluates if a shipment should be upgraded to PRE_ARRIVAL status.
210
+ * Used by the scheduled job to check IN_TRANSIT shipments.
211
+ *
212
+ * @param currentStatus - Current shipment status
213
+ * @param timeContext - Time context with ETA and ATA
214
+ * @returns The new status (PRE_ARRIVAL if conditions met, otherwise currentStatus)
215
+ */
216
+ export function evaluatePreArrivalUpgrade(
217
+ currentStatus: ShipmentStatus,
218
+ timeContext: TimeContext,
219
+ ): ShipmentStatus {
220
+ // Only upgrade from IN_TRANSIT to PRE_ARRIVAL
221
+ if (currentStatus !== 'IN_TRANSIT') {
222
+ return currentStatus
223
+ }
224
+
225
+ if (shouldUpgradeToPreArrival(timeContext)) {
226
+ return 'PRE_ARRIVAL'
227
+ }
228
+
229
+ return currentStatus
230
+ }
@@ -0,0 +1,85 @@
1
+ import type { TrackingEventClassifierCode } from '../data/entities'
2
+
3
+ type EventInput = {
4
+ eventCode: string
5
+ eventClassifierCode?: TrackingEventClassifierCode | null
6
+ eventDateTime: Date
7
+ eventDateTimeOffset?: string | null
8
+ eventCreatedDateTime?: Date | null
9
+ locationUnlocode?: string | null
10
+ }
11
+
12
+ type ShipmentContext = {
13
+ originUnlocode?: string | null
14
+ destinationUnlocode?: string | null
15
+ }
16
+
17
+ export type ExtractedTimes = {
18
+ etd?: Date | null
19
+ etdOffset?: string | null
20
+ eta?: Date | null
21
+ etaOffset?: string | null
22
+ atd?: Date | null
23
+ atdOffset?: string | null
24
+ ata?: Date | null
25
+ ataOffset?: string | null
26
+ }
27
+
28
+ function isAtLocation(eventLocation: string | null | undefined, target: string | null | undefined): boolean {
29
+ if (!eventLocation || !target) return false
30
+ return eventLocation.toUpperCase() === target.toUpperCase()
31
+ }
32
+
33
+ /**
34
+ * Extracts ETD/ETA/ATD/ATA from cargo events.
35
+ *
36
+ * Logic:
37
+ * - DEPA ACT at origin -> ATD
38
+ * - DEPA PLN/EST at origin -> ETD
39
+ * - ARRI ACT at destination -> ATA
40
+ * - ARRI PLN/EST at destination -> ETA
41
+ *
42
+ * When multiple events match the same field, the latest one wins.
43
+ * For EST/PLN events, we use eventCreatedDateTime (when estimate was published)
44
+ * to ensure revised estimates supersede earlier ones.
45
+ */
46
+ export function extractShipmentTimes(events: EventInput[], context: ShipmentContext): ExtractedTimes {
47
+ const result: ExtractedTimes = {}
48
+
49
+ // Sort events by createdDateTime (when published) if available, else eventDateTime
50
+ // This ensures revised estimates (published later) supersede earlier ones
51
+ const sorted = [...events].sort((eventA, eventB) => {
52
+ const timeA = eventA.eventCreatedDateTime?.getTime() ?? eventA.eventDateTime.getTime()
53
+ const timeB = eventB.eventCreatedDateTime?.getTime() ?? eventB.eventDateTime.getTime()
54
+ return timeA - timeB
55
+ })
56
+
57
+ for (const event of sorted) {
58
+ const code = event.eventCode.toUpperCase()
59
+ const classifierCode = event.eventClassifierCode
60
+ const atOrigin = isAtLocation(event.locationUnlocode, context.originUnlocode)
61
+ const atDestination = isAtLocation(event.locationUnlocode, context.destinationUnlocode)
62
+
63
+ if (code === 'DEPA') {
64
+ if (classifierCode === 'ACT' && (atOrigin || !context.originUnlocode)) {
65
+ result.atd = event.eventDateTime
66
+ result.atdOffset = event.eventDateTimeOffset ?? null
67
+ } else if ((classifierCode === 'PLN' || classifierCode === 'EST') && (atOrigin || !context.originUnlocode)) {
68
+ result.etd = event.eventDateTime
69
+ result.etdOffset = event.eventDateTimeOffset ?? null
70
+ }
71
+ }
72
+
73
+ if (code === 'ARRI') {
74
+ if (classifierCode === 'ACT' && (atDestination || !context.destinationUnlocode)) {
75
+ result.ata = event.eventDateTime
76
+ result.ataOffset = event.eventDateTimeOffset ?? null
77
+ } else if ((classifierCode === 'PLN' || classifierCode === 'EST') && (atDestination || !context.destinationUnlocode)) {
78
+ result.eta = event.eventDateTime
79
+ result.etaOffset = event.eventDateTimeOffset ?? null
80
+ }
81
+ }
82
+ }
83
+
84
+ return result
85
+ }