@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,149 @@
1
+ function getSevenDaysAgo() {
2
+ const date = /* @__PURE__ */ new Date();
3
+ date.setDate(date.getDate() - 7);
4
+ return date.toISOString();
5
+ }
6
+ function findLastVesselFromStops(routeStops, cargoEvents) {
7
+ for (let i = routeStops.length - 1; i >= 0; i--) {
8
+ const stop = routeStops[i];
9
+ if (stop.vesselName) {
10
+ const vesselImo = stop.vesselImo || findVesselImoFromEvents(stop.vesselName, cargoEvents);
11
+ return { vesselName: stop.vesselName, vesselImo };
12
+ }
13
+ }
14
+ return { vesselName: null, vesselImo: null };
15
+ }
16
+ function getCurrentVessel(routeStops, cargoEvents, fallbackVessel) {
17
+ const defaultResult = {
18
+ vesselName: fallbackVessel?.vesselName ?? null,
19
+ vesselImo: fallbackVessel?.vesselImo ?? null,
20
+ status: "not_departed",
21
+ isPlannedVessel: true,
22
+ traceFrom: getSevenDaysAgo()
23
+ };
24
+ if (!routeStops || routeStops.length === 0) {
25
+ return defaultResult;
26
+ }
27
+ const destination = routeStops.find((s) => s.type === "destination");
28
+ if (destination?.ata) {
29
+ const lastVesselInfo = findLastVesselFromStops(routeStops, cargoEvents);
30
+ return {
31
+ vesselName: lastVesselInfo.vesselName,
32
+ vesselImo: lastVesselInfo.vesselImo,
33
+ status: "delivered",
34
+ currentPort: destination.location,
35
+ isPlannedVessel: false
36
+ // No traceFrom needed for delivered containers (map not shown)
37
+ };
38
+ }
39
+ for (let i = routeStops.length - 1; i >= 0; i--) {
40
+ const stop = routeStops[i];
41
+ const nextStop = routeStops[i + 1];
42
+ if (stop.atd && nextStop && !nextStop.ata) {
43
+ const vesselImo2 = stop.vesselImo || findVesselImoFromEvents(stop.vesselName, cargoEvents) || fallbackVessel?.vesselImo || null;
44
+ return {
45
+ vesselName: stop.vesselName ?? null,
46
+ vesselImo: vesselImo2,
47
+ status: "in_transit",
48
+ currentLeg: {
49
+ fromPort: stop.location,
50
+ toPort: nextStop.location
51
+ },
52
+ isPlannedVessel: false,
53
+ traceFrom: stop.atd
54
+ // Use ATD from departure port
55
+ };
56
+ }
57
+ if (stop.ata && !stop.atd) {
58
+ if (nextStop) {
59
+ const vesselImo2 = nextStop.vesselImo || findVesselImoFromEvents(nextStop.vesselName, cargoEvents) || fallbackVessel?.vesselImo || null;
60
+ return {
61
+ vesselName: nextStop.vesselName ?? null,
62
+ vesselImo: vesselImo2,
63
+ status: "at_port",
64
+ currentPort: stop.location,
65
+ isPlannedVessel: true,
66
+ traceFrom: getSevenDaysAgo()
67
+ // Last 7 days for planned vessel
68
+ };
69
+ }
70
+ return {
71
+ vesselName: null,
72
+ vesselImo: null,
73
+ status: "at_port",
74
+ currentPort: stop.location,
75
+ isPlannedVessel: false,
76
+ traceFrom: getSevenDaysAgo()
77
+ };
78
+ }
79
+ }
80
+ const origin = routeStops[0];
81
+ const vesselImo = origin?.vesselImo || findVesselImoFromEvents(origin?.vesselName, cargoEvents);
82
+ return {
83
+ vesselName: origin?.vesselName ?? fallbackVessel?.vesselName ?? null,
84
+ vesselImo: vesselImo ?? fallbackVessel?.vesselImo ?? null,
85
+ status: "not_departed",
86
+ currentPort: origin?.location,
87
+ isPlannedVessel: true,
88
+ traceFrom: getSevenDaysAgo()
89
+ // Last 7 days for planned vessel
90
+ };
91
+ }
92
+ function findVesselImoFromEvents(vesselName, events) {
93
+ if (!vesselName || !events || events.length === 0) {
94
+ return null;
95
+ }
96
+ const eventWithImo = events.find(
97
+ (e) => e.vesselName === vesselName && e.vesselImo
98
+ );
99
+ return eventWithImo?.vesselImo ?? null;
100
+ }
101
+ function getVesselStatusDescription(info) {
102
+ switch (info.status) {
103
+ case "in_transit":
104
+ return {
105
+ key: "shipment_tracking.map.inTransit",
106
+ params: {
107
+ destination: info.currentLeg?.toPort ?? ""
108
+ }
109
+ };
110
+ case "at_port":
111
+ if (info.vesselName) {
112
+ return {
113
+ key: "shipment_tracking.map.atPortAwaitingVessel",
114
+ params: {
115
+ port: info.currentPort ?? "",
116
+ vessel: info.vesselName
117
+ }
118
+ };
119
+ }
120
+ return {
121
+ key: "shipment_tracking.map.atPort",
122
+ params: {
123
+ port: info.currentPort ?? ""
124
+ }
125
+ };
126
+ case "not_departed":
127
+ if (info.vesselName) {
128
+ return {
129
+ key: "shipment_tracking.map.awaitingDeparture",
130
+ params: {
131
+ vessel: info.vesselName
132
+ }
133
+ };
134
+ }
135
+ return {
136
+ key: "shipment_tracking.map.notDeparted"
137
+ };
138
+ case "delivered":
139
+ return {
140
+ key: "shipment_tracking.map.delivered"
141
+ };
142
+ }
143
+ }
144
+ export {
145
+ findVesselImoFromEvents,
146
+ getCurrentVessel,
147
+ getVesselStatusDescription
148
+ };
149
+ //# sourceMappingURL=current-vessel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/shipment_tracking/lib/current-vessel.ts"],
4
+ "sourcesContent": ["/**\n * Current vessel derivation utilities for shipment tracking.\n *\n * Determines which vessel the container is currently on (or waiting for)\n * based on shipment progress through route stops.\n */\n\nimport type { RouteStopEntry, CargoEventEntry } from './route-extraction'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Container's current tracking status.\n */\nexport type VesselTrackingStatus =\n | 'in_transit' // Container is on a vessel moving between ports\n | 'at_port' // Container is at a port (waiting for next vessel or just arrived)\n | 'not_departed' // Container hasn't started journey yet (at origin)\n | 'delivered' // Container has arrived at final destination\n\n/**\n * Information about the current or planned vessel for tracking.\n */\nexport interface CurrentVesselInfo {\n /** Current or planned vessel name */\n vesselName: string | null\n /** Current or planned vessel IMO for tracking */\n vesselImo: string | null\n /** Container's current status */\n status: VesselTrackingStatus\n /** Current leg info (if in transit) */\n currentLeg?: {\n fromPort: string\n toPort: string\n }\n /** Port name where container currently is (if at_port or not_departed) */\n currentPort?: string\n /** Whether the vessel shown is planned (not yet departed) vs currently carrying container */\n isPlannedVessel: boolean\n /** Start date for trace - ATD from departure port (in_transit) or 7 days ago (planned) */\n traceFrom?: string\n}\n\n// \u2500\u2500\u2500 Helper Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Returns ISO 8601 date string for 7 days ago.\n * Used as default trace start time for planned vessels.\n */\nfunction getSevenDaysAgo(): string {\n const date = new Date()\n date.setDate(date.getDate() - 7)\n return date.toISOString()\n}\n\n// \u2500\u2500\u2500 Helper Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Finds the last vessel that carried the container by searching route stops backwards.\n * Used for delivered shipments to show which vessel completed the journey.\n */\nfunction findLastVesselFromStops(\n routeStops: RouteStopEntry[],\n cargoEvents: CargoEventEntry[] | null | undefined\n): { vesselName: string | null; vesselImo: string | null } {\n // Work backwards from the last stop to find a stop with vessel info\n for (let i = routeStops.length - 1; i >= 0; i--) {\n const stop = routeStops[i]\n if (stop.vesselName) {\n const vesselImo = stop.vesselImo || findVesselImoFromEvents(stop.vesselName, cargoEvents)\n return { vesselName: stop.vesselName, vesselImo }\n }\n }\n return { vesselName: null, vesselImo: null }\n}\n\n// \u2500\u2500\u2500 Main Function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Determines the current vessel based on shipment progress through route stops.\n *\n * Algorithm:\n * 1. If final destination has ATA \u2192 Container delivered, no vessel to track\n * 2. Find the latest stop with ATD where next stop doesn't have ATA\n * \u2192 Container is in transit on this leg's vessel\n * 3. Find stop with ATA but no ATD (container at port waiting)\n * \u2192 Return next leg's planned vessel if available\n * 4. No stops have ATD \u2192 Container not departed yet\n * \u2192 Return first leg's planned vessel\n *\n * @param routeStops - Array of route stops from shipment\n * @param cargoEvents - Array of cargo events (used to find vessel IMO if not in stops)\n * @param fallbackVessel - Fallback vessel info from shipment entity\n * @returns CurrentVesselInfo with vessel details and status\n */\nexport function getCurrentVessel(\n routeStops: RouteStopEntry[] | null | undefined,\n cargoEvents: CargoEventEntry[] | null | undefined,\n fallbackVessel?: { vesselName?: string | null; vesselImo?: string | null }\n): CurrentVesselInfo {\n // Default result when no data available\n const defaultResult: CurrentVesselInfo = {\n vesselName: fallbackVessel?.vesselName ?? null,\n vesselImo: fallbackVessel?.vesselImo ?? null,\n status: 'not_departed',\n isPlannedVessel: true,\n traceFrom: getSevenDaysAgo(),\n }\n\n if (!routeStops || routeStops.length === 0) {\n return defaultResult\n }\n\n // Check if container is delivered (final destination has ATA)\n const destination = routeStops.find((s) => s.type === 'destination')\n if (destination?.ata) {\n // Find the last vessel that carried the container (for display purposes)\n // Work backwards from destination to find a stop with vessel info\n const lastVesselInfo = findLastVesselFromStops(routeStops, cargoEvents)\n return {\n vesselName: lastVesselInfo.vesselName,\n vesselImo: lastVesselInfo.vesselImo,\n status: 'delivered',\n currentPort: destination.location,\n isPlannedVessel: false,\n // No traceFrom needed for delivered containers (map not shown)\n }\n }\n\n // Find where the container currently is\n // Look for the latest stop with ATD where the next stop doesn't have ATA yet\n for (let i = routeStops.length - 1; i >= 0; i--) {\n const stop = routeStops[i]\n const nextStop = routeStops[i + 1]\n\n // Case 1: Stop has ATD and next stop exists but doesn't have ATA\n // \u2192 Container is in transit between these stops\n if (stop.atd && nextStop && !nextStop.ata) {\n const vesselImo = stop.vesselImo || findVesselImoFromEvents(stop.vesselName, cargoEvents) || fallbackVessel?.vesselImo || null\n return {\n vesselName: stop.vesselName ?? null,\n vesselImo,\n status: 'in_transit',\n currentLeg: {\n fromPort: stop.location,\n toPort: nextStop.location,\n },\n isPlannedVessel: false,\n traceFrom: stop.atd, // Use ATD from departure port\n }\n }\n\n // Case 2: Stop has ATA but no ATD (container is at this port)\n // \u2192 Return the next leg's vessel as planned vessel\n if (stop.ata && !stop.atd) {\n // Look for next stop's vessel\n if (nextStop) {\n const vesselImo =\n nextStop.vesselImo || findVesselImoFromEvents(nextStop.vesselName, cargoEvents) || fallbackVessel?.vesselImo || null\n return {\n vesselName: nextStop.vesselName ?? null,\n vesselImo,\n status: 'at_port',\n currentPort: stop.location,\n isPlannedVessel: true,\n traceFrom: getSevenDaysAgo(), // Last 7 days for planned vessel\n }\n }\n // At final stop but no ATA on destination (shouldn't happen normally)\n return {\n vesselName: null,\n vesselImo: null,\n status: 'at_port',\n currentPort: stop.location,\n isPlannedVessel: false,\n traceFrom: getSevenDaysAgo(),\n }\n }\n }\n\n // Case 3: No stops have ATD \u2192 Container hasn't departed yet\n // Return first leg's vessel as planned\n const origin = routeStops[0]\n const vesselImo = origin?.vesselImo || findVesselImoFromEvents(origin?.vesselName, cargoEvents)\n\n return {\n vesselName: origin?.vesselName ?? fallbackVessel?.vesselName ?? null,\n vesselImo: vesselImo ?? fallbackVessel?.vesselImo ?? null,\n status: 'not_departed',\n currentPort: origin?.location,\n isPlannedVessel: true,\n traceFrom: getSevenDaysAgo(), // Last 7 days for planned vessel\n }\n}\n\n// \u2500\u2500\u2500 More Helper Functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Find vessel IMO from cargo events by vessel name.\n * Used when RouteStopEntry only has vesselName but needs IMO.\n *\n * @param vesselName - Vessel name to search for\n * @param events - Array of cargo events\n * @returns Vessel IMO if found, null otherwise\n */\nexport function findVesselImoFromEvents(\n vesselName: string | null | undefined,\n events: CargoEventEntry[] | null | undefined\n): string | null {\n if (!vesselName || !events || events.length === 0) {\n return null\n }\n\n // Find any event with matching vessel name that has an IMO\n const eventWithImo = events.find(\n (e) => e.vesselName === vesselName && e.vesselImo\n )\n\n return eventWithImo?.vesselImo ?? null\n}\n\n/**\n * Get a human-readable description of the current vessel status.\n * Useful for UI display.\n *\n * @param info - Current vessel info\n * @returns Status description object with keys for i18n\n */\nexport function getVesselStatusDescription(info: CurrentVesselInfo): {\n key: string\n params?: Record<string, string>\n} {\n switch (info.status) {\n case 'in_transit':\n return {\n key: 'shipment_tracking.map.inTransit',\n params: {\n destination: info.currentLeg?.toPort ?? '',\n },\n }\n case 'at_port':\n if (info.vesselName) {\n return {\n key: 'shipment_tracking.map.atPortAwaitingVessel',\n params: {\n port: info.currentPort ?? '',\n vessel: info.vesselName,\n },\n }\n }\n return {\n key: 'shipment_tracking.map.atPort',\n params: {\n port: info.currentPort ?? '',\n },\n }\n case 'not_departed':\n if (info.vesselName) {\n return {\n key: 'shipment_tracking.map.awaitingDeparture',\n params: {\n vessel: info.vesselName,\n },\n }\n }\n return {\n key: 'shipment_tracking.map.notDeparted',\n }\n case 'delivered':\n return {\n key: 'shipment_tracking.map.delivered',\n }\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["vesselImo"]
7
+ }
@@ -0,0 +1,124 @@
1
+ function mapDcsaEventToWebhookType(input) {
2
+ const { eventType, eventCode, eventClassifierCode } = input;
3
+ const code = eventCode.toUpperCase();
4
+ const isActual = eventClassifierCode === "ACT";
5
+ const isEstimatedOrPlanned = eventClassifierCode === "EST" || eventClassifierCode === "PLN";
6
+ if (eventType === "TRANSPORT") {
7
+ switch (code) {
8
+ case "DEPA":
9
+ if (isActual) return "shipment_tracking.transport.departed";
10
+ if (isEstimatedOrPlanned) return "shipment_tracking.transport.etd_updated";
11
+ return "shipment_tracking.transport.etd_updated";
12
+ // Default to ETD update
13
+ case "ARRI":
14
+ if (isActual) return "shipment_tracking.transport.arrived";
15
+ if (isEstimatedOrPlanned) return "shipment_tracking.transport.eta_updated";
16
+ return "shipment_tracking.transport.eta_updated";
17
+ // Default to ETA update
18
+ case "OMIT":
19
+ return "shipment_tracking.transport.omitted";
20
+ }
21
+ }
22
+ if (eventType === "EQUIPMENT") {
23
+ switch (code) {
24
+ // Loading/Discharge
25
+ case "LOAD":
26
+ return "shipment_tracking.equipment.loaded";
27
+ case "DISC":
28
+ return "shipment_tracking.equipment.discharged";
29
+ // Gate movements
30
+ case "GTIN":
31
+ return "shipment_tracking.equipment.gate_in";
32
+ case "GTOT":
33
+ return "shipment_tracking.equipment.gate_out";
34
+ // Availability
35
+ case "AVPU":
36
+ return "shipment_tracking.equipment.available_pickup";
37
+ case "AVDO":
38
+ return "shipment_tracking.equipment.gate_in";
39
+ // Customs
40
+ case "CUSR":
41
+ return "shipment_tracking.equipment.customs_released";
42
+ case "CUSS":
43
+ // Customs selected for scan
44
+ case "CUSI":
45
+ return "shipment_tracking.equipment.inspected";
46
+ // Inspection
47
+ case "INSP":
48
+ return "shipment_tracking.equipment.inspected";
49
+ // Delivery
50
+ case "DLVR":
51
+ if (isActual) return "shipment_tracking.shipment.delivered";
52
+ break;
53
+ // Pick-up/Drop-off (physical movement)
54
+ case "PICK":
55
+ return "shipment_tracking.equipment.gate_out";
56
+ case "DROP":
57
+ return "shipment_tracking.equipment.gate_in";
58
+ // Stuffing/Stripping
59
+ case "STUF":
60
+ // Stuffed (cargo loaded into container)
61
+ case "STRP":
62
+ break;
63
+ // Sealing
64
+ case "RSEA":
65
+ // Resealed
66
+ case "RMVD":
67
+ break;
68
+ // Transshipment crossing
69
+ case "CROS":
70
+ return "shipment_tracking.equipment.discharged";
71
+ }
72
+ }
73
+ if (eventType === "SHIPMENT") {
74
+ switch (code) {
75
+ case "CONF":
76
+ // Confirmed
77
+ case "BOOK":
78
+ return "shipment_tracking.shipment.booked";
79
+ }
80
+ }
81
+ return "shipment_tracking.tracking_event.created";
82
+ }
83
+ function isSignificantMilestone(input) {
84
+ const webhookType = mapDcsaEventToWebhookType(input);
85
+ return webhookType !== "shipment_tracking.tracking_event.created";
86
+ }
87
+ const DCSA_EQUIPMENT_EVENT_CODES = {
88
+ LOAD: "Loaded onto transport",
89
+ DISC: "Discharged from transport",
90
+ GTIN: "Gated in (entered facility)",
91
+ GTOT: "Gated out (terminal)",
92
+ STUF: "Stuffed (cargo loaded into container)",
93
+ STRP: "Stripped (cargo removed from container)",
94
+ PICK: "Pick-up by consignee/trucker",
95
+ DROP: "Drop-off at facility",
96
+ INSP: "Inspected",
97
+ RSEA: "Resealed",
98
+ RMVD: "Seal removed",
99
+ AVPU: "Available for pick-up",
100
+ AVDO: "Available for drop-off",
101
+ CUSS: "Customs selected for scan",
102
+ CUSI: "Customs selected for inspection",
103
+ CUSR: "Customs released",
104
+ CROS: "Crossed (transshipment)",
105
+ DLVR: "Delivered to consignee"
106
+ };
107
+ const DCSA_TRANSPORT_EVENT_CODES = {
108
+ ARRI: "Arrived at location",
109
+ DEPA: "Departed from location",
110
+ OMIT: "Port/location omitted from schedule"
111
+ };
112
+ const DCSA_EVENT_CLASSIFIERS = {
113
+ ACT: "Actual (event has occurred)",
114
+ PLN: "Planned",
115
+ EST: "Estimated"
116
+ };
117
+ export {
118
+ DCSA_EQUIPMENT_EVENT_CODES,
119
+ DCSA_EVENT_CLASSIFIERS,
120
+ DCSA_TRANSPORT_EVENT_CODES,
121
+ isSignificantMilestone,
122
+ mapDcsaEventToWebhookType
123
+ };
124
+ //# sourceMappingURL=dcsa-event-mapping.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/shipment_tracking/lib/dcsa-event-mapping.ts"],
4
+ "sourcesContent": ["import type { TrackingEventType, TrackingEventClassifierCode } from '../data/entities'\n\n/**\n * DCSA Track & Trace Event Code Mapping\n *\n * Maps DCSA standard event codes to internal webhook event types.\n * Reference: DCSA T&T v3.0 specification\n *\n * Event Types:\n * - TRANSPORT: Vessel/transport movement events (ARRI, DEPA, OMIT)\n * - EQUIPMENT: Container handling events (LOAD, DISC, GTIN, GTOT, etc.)\n * - SHIPMENT: Document lifecycle events (not typically from carrier tracking)\n *\n * Event Classifiers:\n * - ACT: Actual (event has happened)\n * - PLN: Planned\n * - EST: Estimated\n */\n\nexport type DcsaWebhookEventType =\n // Transport events\n | 'shipment_tracking.transport.departed'\n | 'shipment_tracking.transport.arrived'\n | 'shipment_tracking.transport.eta_updated'\n | 'shipment_tracking.transport.etd_updated'\n | 'shipment_tracking.transport.omitted'\n // Equipment events\n | 'shipment_tracking.equipment.loaded'\n | 'shipment_tracking.equipment.discharged'\n | 'shipment_tracking.equipment.gate_in'\n | 'shipment_tracking.equipment.gate_out'\n | 'shipment_tracking.equipment.available_pickup'\n | 'shipment_tracking.equipment.customs_released'\n | 'shipment_tracking.equipment.inspected'\n // Shipment lifecycle\n | 'shipment_tracking.shipment.booked'\n | 'shipment_tracking.shipment.delivered'\n // Generic fallback\n | 'shipment_tracking.tracking_event.created'\n\nexport type EventMappingInput = {\n eventType: TrackingEventType\n eventCode: string\n eventClassifierCode?: TrackingEventClassifierCode | null\n}\n\n/**\n * Maps a DCSA cargo event to the appropriate webhook event type.\n *\n * @param input - The cargo event details from carrier API\n * @returns The internal webhook event type to emit\n */\nexport function mapDcsaEventToWebhookType(input: EventMappingInput): DcsaWebhookEventType {\n const { eventType, eventCode, eventClassifierCode } = input\n const code = eventCode.toUpperCase()\n const isActual = eventClassifierCode === 'ACT'\n const isEstimatedOrPlanned = eventClassifierCode === 'EST' || eventClassifierCode === 'PLN'\n\n // \u2500\u2500\u2500 Transport Events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (eventType === 'TRANSPORT') {\n switch (code) {\n case 'DEPA': // Departure\n if (isActual) return 'shipment_tracking.transport.departed'\n if (isEstimatedOrPlanned) return 'shipment_tracking.transport.etd_updated'\n return 'shipment_tracking.transport.etd_updated' // Default to ETD update\n case 'ARRI': // Arrival\n if (isActual) return 'shipment_tracking.transport.arrived'\n if (isEstimatedOrPlanned) return 'shipment_tracking.transport.eta_updated'\n return 'shipment_tracking.transport.eta_updated' // Default to ETA update\n case 'OMIT': // Port omitted\n return 'shipment_tracking.transport.omitted'\n }\n }\n\n // \u2500\u2500\u2500 Equipment Events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (eventType === 'EQUIPMENT') {\n switch (code) {\n // Loading/Discharge\n case 'LOAD': // Loaded onto vessel\n return 'shipment_tracking.equipment.loaded'\n case 'DISC': // Discharged from vessel\n return 'shipment_tracking.equipment.discharged'\n\n // Gate movements\n case 'GTIN': // Gate in\n return 'shipment_tracking.equipment.gate_in'\n case 'GTOT': // Gate out (terminal)\n return 'shipment_tracking.equipment.gate_out'\n\n // Availability\n case 'AVPU': // Available for pick-up\n return 'shipment_tracking.equipment.available_pickup'\n case 'AVDO': // Available for drop-off (less common, map to gate_in context)\n return 'shipment_tracking.equipment.gate_in'\n\n // Customs\n case 'CUSR': // Customs released\n return 'shipment_tracking.equipment.customs_released'\n case 'CUSS': // Customs selected for scan\n case 'CUSI': // Customs selected for inspection\n return 'shipment_tracking.equipment.inspected'\n\n // Inspection\n case 'INSP': // Inspected\n return 'shipment_tracking.equipment.inspected'\n\n // Delivery\n case 'DLVR': // Delivered\n if (isActual) return 'shipment_tracking.shipment.delivered'\n break\n\n // Pick-up/Drop-off (physical movement)\n case 'PICK': // Pick-up\n return 'shipment_tracking.equipment.gate_out'\n case 'DROP': // Drop-off\n return 'shipment_tracking.equipment.gate_in'\n\n // Stuffing/Stripping\n case 'STUF': // Stuffed (cargo loaded into container)\n case 'STRP': // Stripped (cargo unloaded from container)\n // These are container content events, map to generic\n break\n\n // Sealing\n case 'RSEA': // Resealed\n case 'RMVD': // Seal removed\n // Seal events, map to generic\n break\n\n // Transshipment crossing\n case 'CROS': // Crossed (transshipment)\n // Map to discharge as it indicates container moved\n return 'shipment_tracking.equipment.discharged'\n }\n }\n\n // \u2500\u2500\u2500 Shipment Events \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (eventType === 'SHIPMENT') {\n // Shipment events are typically document-related (booking, BL issuance)\n // These come from different APIs, not container tracking\n // Map common booking-related codes\n switch (code) {\n case 'CONF': // Confirmed\n case 'BOOK': // Booked (non-standard but common)\n return 'shipment_tracking.shipment.booked'\n }\n }\n\n // \u2500\u2500\u2500 Fallback \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n return 'shipment_tracking.tracking_event.created'\n}\n\n/**\n * Determines if a tracking event represents a significant milestone\n * that warrants a specific webhook event (vs generic tracking_event.created).\n */\nexport function isSignificantMilestone(input: EventMappingInput): boolean {\n const webhookType = mapDcsaEventToWebhookType(input)\n return webhookType !== 'shipment_tracking.tracking_event.created'\n}\n\n/**\n * DCSA Equipment Event Type Codes reference\n */\nexport const DCSA_EQUIPMENT_EVENT_CODES = {\n LOAD: 'Loaded onto transport',\n DISC: 'Discharged from transport',\n GTIN: 'Gated in (entered facility)',\n GTOT: 'Gated out (terminal)',\n STUF: 'Stuffed (cargo loaded into container)',\n STRP: 'Stripped (cargo removed from container)',\n PICK: 'Pick-up by consignee/trucker',\n DROP: 'Drop-off at facility',\n INSP: 'Inspected',\n RSEA: 'Resealed',\n RMVD: 'Seal removed',\n AVPU: 'Available for pick-up',\n AVDO: 'Available for drop-off',\n CUSS: 'Customs selected for scan',\n CUSI: 'Customs selected for inspection',\n CUSR: 'Customs released',\n CROS: 'Crossed (transshipment)',\n DLVR: 'Delivered to consignee',\n} as const\n\n/**\n * DCSA Transport Event Type Codes reference\n */\nexport const DCSA_TRANSPORT_EVENT_CODES = {\n ARRI: 'Arrived at location',\n DEPA: 'Departed from location',\n OMIT: 'Port/location omitted from schedule',\n} as const\n\n/**\n * DCSA Event Classifier Codes reference\n */\nexport const DCSA_EVENT_CLASSIFIERS = {\n ACT: 'Actual (event has occurred)',\n PLN: 'Planned',\n EST: 'Estimated',\n} as const\n"],
5
+ "mappings": "AAoDO,SAAS,0BAA0B,OAAgD;AACxF,QAAM,EAAE,WAAW,WAAW,oBAAoB,IAAI;AACtD,QAAM,OAAO,UAAU,YAAY;AACnC,QAAM,WAAW,wBAAwB;AACzC,QAAM,uBAAuB,wBAAwB,SAAS,wBAAwB;AAGtF,MAAI,cAAc,aAAa;AAC7B,YAAQ,MAAM;AAAA,MACZ,KAAK;AACH,YAAI,SAAU,QAAO;AACrB,YAAI,qBAAsB,QAAO;AACjC,eAAO;AAAA;AAAA,MACT,KAAK;AACH,YAAI,SAAU,QAAO;AACrB,YAAI,qBAAsB,QAAO;AACjC,eAAO;AAAA;AAAA,MACT,KAAK;AACH,eAAO;AAAA,IACX;AAAA,EACF;AAGA,MAAI,cAAc,aAAa;AAC7B,YAAQ,MAAM;AAAA;AAAA,MAEZ,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MAGT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MAGT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MAGT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA;AAAA,MACL,KAAK;AACH,eAAO;AAAA;AAAA,MAGT,KAAK;AACH,eAAO;AAAA;AAAA,MAGT,KAAK;AACH,YAAI,SAAU,QAAO;AACrB;AAAA;AAAA,MAGF,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA;AAAA,MAGT,KAAK;AAAA;AAAA,MACL,KAAK;AAEH;AAAA;AAAA,MAGF,KAAK;AAAA;AAAA,MACL,KAAK;AAEH;AAAA;AAAA,MAGF,KAAK;AAEH,eAAO;AAAA,IACX;AAAA,EACF;AAGA,MAAI,cAAc,YAAY;AAI5B,YAAQ,MAAM;AAAA,MACZ,KAAK;AAAA;AAAA,MACL,KAAK;AACH,eAAO;AAAA,IACX;AAAA,EACF;AAGA,SAAO;AACT;AAMO,SAAS,uBAAuB,OAAmC;AACxE,QAAM,cAAc,0BAA0B,KAAK;AACnD,SAAO,gBAAgB;AACzB;AAKO,MAAM,6BAA6B;AAAA,EACxC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AACR;AAKO,MAAM,6BAA6B;AAAA,EACxC,MAAM;AAAA,EACN,MAAM;AAAA,EACN,MAAM;AACR;AAKO,MAAM,yBAAyB;AAAA,EACpC,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;",
6
+ "names": []
7
+ }
@@ -0,0 +1,112 @@
1
+ import crypto from "node:crypto";
2
+ function parseCoordinate(value) {
3
+ if (value == null) return null;
4
+ if (typeof value === "number") return Number.isNaN(value) ? null : value;
5
+ if (typeof value === "string") {
6
+ const trimmed = value.trim();
7
+ if (trimmed === "") return null;
8
+ const parsed = parseFloat(trimmed);
9
+ return Number.isNaN(parsed) ? null : parsed;
10
+ }
11
+ return null;
12
+ }
13
+ function extractDcsaEventArray(data) {
14
+ if (Array.isArray(data)) return data;
15
+ if (data && typeof data === "object" && "events" in data && Array.isArray(data.events)) {
16
+ return data.events;
17
+ }
18
+ return [];
19
+ }
20
+ function parseDcsaEvents(data, _carrierName) {
21
+ const events = extractDcsaEventArray(data);
22
+ return events.map((event) => {
23
+ const metadata = event.metadata;
24
+ const payload = event.payload;
25
+ const effectiveEvent = payload ?? event;
26
+ const transportCall = effectiveEvent.transportCall;
27
+ const vessel = transportCall?.vessel;
28
+ const location = effectiveEvent.eventLocation ?? transportCall?.location;
29
+ const geoLocation = location?.geoLocation;
30
+ const address = location?.address;
31
+ const publisher = metadata?.publisher ?? event.publisher;
32
+ const sourceEventId = metadata?.eventID ?? event.eventID ?? event.eventId ?? crypto.randomUUID();
33
+ const eventType = metadata?.eventType ?? event.eventType;
34
+ const eventCode = effectiveEvent.equipmentEventTypeCode ?? effectiveEvent.transportEventTypeCode ?? effectiveEvent.shipmentEventTypeCode;
35
+ const eventClassifierCode = effectiveEvent.eventClassifierCode ?? null;
36
+ const eventDateTime = new Date(effectiveEvent.eventDateTime ?? event.eventDateTime);
37
+ const rawDocRefs = effectiveEvent.relatedDocumentReferences ?? effectiveEvent.documentReferences;
38
+ const relatedDocumentReferences = rawDocRefs?.map((ref) => ({
39
+ type: ref.type ?? ref.documentReferenceType,
40
+ value: ref.value ?? ref.documentReferenceValue
41
+ })) ?? null;
42
+ const rawSeals = effectiveEvent.seals;
43
+ const seals = rawSeals?.map((seal) => ({
44
+ number: seal.sealNumber ?? seal.number,
45
+ source: seal.sealSource ?? seal.source ?? null,
46
+ type: seal.sealType ?? seal.type ?? null
47
+ })) ?? null;
48
+ const eventCreatedDateTimeRaw = metadata?.eventCreatedDateTime ?? event.eventCreatedDateTime;
49
+ const eventCreatedDateTime = eventCreatedDateTimeRaw ? new Date(eventCreatedDateTimeRaw) : null;
50
+ return {
51
+ // ─── Event Source ──────────────────────────────────────────────
52
+ source: "dcsa",
53
+ sourceEventId,
54
+ // ─── Core Event Fields ─────────────────────────────────────────
55
+ eventType,
56
+ eventCode,
57
+ eventClassifierCode,
58
+ eventDateTime,
59
+ eventDateTimeOffset: null,
60
+ // Not typically in DCSA response, derived from datetime
61
+ description: effectiveEvent.description ?? null,
62
+ rawData: event,
63
+ // ─── Equipment Fields ──────────────────────────────────────────
64
+ equipmentReference: effectiveEvent.equipmentReference ?? null,
65
+ isoEquipmentCode: effectiveEvent.ISOEquipmentCode ?? null,
66
+ emptyIndicatorCode: effectiveEvent.emptyIndicatorCode ?? null,
67
+ isTransshipmentMove: effectiveEvent.isTransshipmentMove ?? null,
68
+ // ─── Location Fields ───────────────────────────────────────────
69
+ locationName: location?.locationName ?? null,
70
+ locationUnlocode: location?.UNLocationCode ?? location?.unLocationCode ?? transportCall?.UNLocationCode ?? transportCall?.unLocationCode ?? null,
71
+ locationCountry: address?.country ?? null,
72
+ // Facility code - transportCall has priority (where most carriers put it), then location
73
+ facilityCode: transportCall?.facilityCode ?? location?.facilityCode ?? null,
74
+ facilityCodeListProvider: transportCall?.facilityCodeListProvider ?? location?.facilityCodeListProvider ?? null,
75
+ facilityTypeCode: transportCall?.facilityTypeCode ?? effectiveEvent.facilityTypeCode ?? location?.facilityTypeCode ?? null,
76
+ // Address from otherFacility (full address string from DCSA)
77
+ facilityAddress: transportCall?.otherFacility ?? null,
78
+ // Coordinates - check location directly (as strings), then geoLocation nested
79
+ latitude: parseCoordinate(location?.latitude) ?? parseCoordinate(geoLocation?.latitude),
80
+ longitude: parseCoordinate(location?.longitude) ?? parseCoordinate(geoLocation?.longitude),
81
+ // ─── Transport Call Fields ─────────────────────────────────────
82
+ transportCallReference: transportCall?.transportCallReference ?? null,
83
+ modeOfTransport: transportCall?.modeOfTransport ?? null,
84
+ vesselName: vessel?.vesselName ?? vessel?.name ?? null,
85
+ vesselImo: vessel?.vesselIMONumber ?? null,
86
+ voyageNumber: transportCall?.carrierExportVoyageNumber ?? transportCall?.exportVoyageNumber ?? transportCall?.importVoyageNumber ?? transportCall?.voyageNumber ?? vessel?.voyage ?? null,
87
+ carrierServiceCode: transportCall?.carrierServiceCode ?? null,
88
+ carrierExportVoyageNumber: transportCall?.carrierExportVoyageNumber ?? transportCall?.exportVoyageNumber ?? null,
89
+ carrierImportVoyageNumber: transportCall?.carrierImportVoyageNumber ?? transportCall?.importVoyageNumber ?? null,
90
+ universalServiceReference: transportCall?.universalServiceReference ?? null,
91
+ universalExportVoyageReference: transportCall?.universalExportVoyageReference ?? null,
92
+ universalImportVoyageReference: transportCall?.universalImportVoyageReference ?? null,
93
+ portVisitReference: transportCall?.portVisitReference ?? null,
94
+ // ─── Document References ───────────────────────────────────────
95
+ relatedDocumentReferences,
96
+ // ─── Metadata Fields ───────────────────────────────────────────
97
+ eventCreatedDateTime,
98
+ retractedEventId: metadata?.retractedEventID ?? null,
99
+ publisherName: publisher?.partyName ?? _carrierName,
100
+ publisherRole: metadata?.publisherRole ?? event.publisherRole ?? null,
101
+ // ─── Additional Event Fields ───────────────────────────────────
102
+ delayReasonCode: effectiveEvent.delayReasonCode ?? null,
103
+ changeRemark: effectiveEvent.changeRemark ?? null,
104
+ seals
105
+ };
106
+ });
107
+ }
108
+ export {
109
+ extractDcsaEventArray,
110
+ parseDcsaEvents
111
+ };
112
+ //# sourceMappingURL=dcsa-event-parser.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/shipment_tracking/lib/dcsa-event-parser.ts"],
4
+ "sourcesContent": ["import crypto from 'node:crypto'\nimport type { CarrierFetchedEvent, DocumentReference, SealInfo } from './carrier-adapter'\nimport type { TrackingEventType, TrackingEventClassifierCode } from '../data/entities'\n\ntype RawDcsaEvent = Record<string, unknown>\n\n/**\n * Parse coordinate value - handles both number and string formats from DCSA APIs.\n * Some carriers return coordinates as strings (e.g., \"54.381628\"), others as numbers.\n */\nfunction parseCoordinate(value: unknown): number | null {\n if (value == null) return null\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed === '') return null\n const parsed = parseFloat(trimmed)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\ntype DcsaResponseShape =\n | { events: RawDcsaEvent[] }\n | RawDcsaEvent[]\n\nexport function extractDcsaEventArray(data: unknown): RawDcsaEvent[] {\n if (Array.isArray(data)) return data\n if (data && typeof data === 'object' && 'events' in data && Array.isArray((data as Record<string, unknown>).events)) {\n return (data as { events: RawDcsaEvent[] }).events\n }\n return []\n}\n\n/**\n * Parses DCSA T&T v3.0 events into normalized CarrierFetchedEvent objects.\n * Handles both flat event structure and nested metadata/payload structure.\n */\nexport function parseDcsaEvents(data: DcsaResponseShape, _carrierName: string): CarrierFetchedEvent[] {\n const events = extractDcsaEventArray(data)\n\n return events.map((event) => {\n // DCSA v3.0 can have nested metadata/payload or flat structure\n const metadata = event.metadata as Record<string, unknown> | undefined\n const payload = event.payload as Record<string, unknown> | undefined\n const effectiveEvent = payload ?? event // Use payload if present, otherwise use flat event\n\n // Extract nested objects\n const transportCall = effectiveEvent.transportCall as Record<string, unknown> | undefined\n const vessel = transportCall?.vessel as Record<string, unknown> | undefined\n const location = (effectiveEvent.eventLocation ??\n transportCall?.location) as Record<string, unknown> | undefined\n const geoLocation = location?.geoLocation as Record<string, unknown> | undefined\n const address = location?.address as Record<string, unknown> | undefined\n const publisher = (metadata?.publisher ?? event.publisher) as Record<string, unknown> | undefined\n\n // \u2500\u2500\u2500 Event Source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const sourceEventId = (metadata?.eventID ?? event.eventID ?? event.eventId ?? crypto.randomUUID()) as string\n\n // \u2500\u2500\u2500 Core Event Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const eventType = (metadata?.eventType ?? event.eventType) as TrackingEventType\n const eventCode = (effectiveEvent.equipmentEventTypeCode ??\n effectiveEvent.transportEventTypeCode ??\n effectiveEvent.shipmentEventTypeCode) as string\n const eventClassifierCode = (effectiveEvent.eventClassifierCode ?? null) as TrackingEventClassifierCode | null\n const eventDateTime = new Date((effectiveEvent.eventDateTime ?? event.eventDateTime) as string)\n\n // \u2500\u2500\u2500 Document References \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const rawDocRefs = (effectiveEvent.relatedDocumentReferences ?? effectiveEvent.documentReferences) as Array<Record<string, unknown>> | undefined\n const relatedDocumentReferences: DocumentReference[] | null = rawDocRefs?.map((ref) => ({\n type: (ref.type ?? ref.documentReferenceType) as string,\n value: (ref.value ?? ref.documentReferenceValue) as string,\n })) ?? null\n\n // \u2500\u2500\u2500 Seals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const rawSeals = effectiveEvent.seals as Array<Record<string, unknown>> | undefined\n const seals: SealInfo[] | null = rawSeals?.map((seal) => ({\n number: (seal.sealNumber ?? seal.number) as string,\n source: (seal.sealSource ?? seal.source) as string | null ?? null,\n type: (seal.sealType ?? seal.type) as string | null ?? null,\n })) ?? null\n\n // \u2500\u2500\u2500 Event Created DateTime \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const eventCreatedDateTimeRaw = metadata?.eventCreatedDateTime ?? event.eventCreatedDateTime\n const eventCreatedDateTime = eventCreatedDateTimeRaw\n ? new Date(eventCreatedDateTimeRaw as string)\n : null\n\n return {\n // \u2500\u2500\u2500 Event Source \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n source: 'dcsa' as const,\n sourceEventId,\n\n // \u2500\u2500\u2500 Core Event Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n eventType,\n eventCode,\n eventClassifierCode,\n eventDateTime,\n eventDateTimeOffset: null, // Not typically in DCSA response, derived from datetime\n description: (effectiveEvent.description as string) ?? null,\n rawData: event,\n\n // \u2500\u2500\u2500 Equipment Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n equipmentReference: (effectiveEvent.equipmentReference as string) ?? null,\n isoEquipmentCode: (effectiveEvent.ISOEquipmentCode as string) ?? null,\n emptyIndicatorCode: (effectiveEvent.emptyIndicatorCode as 'EMPTY' | 'LADEN') ?? null,\n isTransshipmentMove: (effectiveEvent.isTransshipmentMove as boolean) ?? null,\n\n // \u2500\u2500\u2500 Location Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n locationName: (location?.locationName as string) ?? null,\n locationUnlocode: ((location?.UNLocationCode ?? location?.unLocationCode ?? \n transportCall?.UNLocationCode ?? transportCall?.unLocationCode) as string) ?? null,\n locationCountry: (address?.country as string) ?? null,\n \n // Facility code - transportCall has priority (where most carriers put it), then location\n facilityCode: ((transportCall?.facilityCode ?? location?.facilityCode) as string) ?? null,\n facilityCodeListProvider: ((transportCall?.facilityCodeListProvider ?? \n location?.facilityCodeListProvider) as 'SMDG' | 'BIC') ?? null,\n facilityTypeCode: ((transportCall?.facilityTypeCode ?? effectiveEvent.facilityTypeCode ?? \n location?.facilityTypeCode) as string) ?? null,\n \n // Address from otherFacility (full address string from DCSA)\n facilityAddress: (transportCall?.otherFacility as string) ?? null,\n \n // Coordinates - check location directly (as strings), then geoLocation nested\n latitude: parseCoordinate(location?.latitude) ?? parseCoordinate(geoLocation?.latitude),\n longitude: parseCoordinate(location?.longitude) ?? parseCoordinate(geoLocation?.longitude),\n\n // \u2500\u2500\u2500 Transport Call Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n transportCallReference: (transportCall?.transportCallReference as string) ?? null,\n modeOfTransport: (transportCall?.modeOfTransport as 'VESSEL' | 'RAIL' | 'TRUCK' | 'BARGE') ?? null,\n vesselName: ((vessel?.vesselName ?? vessel?.name) as string) ?? null,\n vesselImo: (vessel?.vesselIMONumber as string) ?? null,\n voyageNumber: (transportCall?.carrierExportVoyageNumber as string) ??\n (transportCall?.exportVoyageNumber as string) ??\n (transportCall?.importVoyageNumber as string) ??\n (transportCall?.voyageNumber as string) ??\n (vessel?.voyage as string) ?? null,\n carrierServiceCode: (transportCall?.carrierServiceCode as string) ?? null,\n carrierExportVoyageNumber: ((transportCall?.carrierExportVoyageNumber ?? transportCall?.exportVoyageNumber) as string) ?? null,\n carrierImportVoyageNumber: ((transportCall?.carrierImportVoyageNumber ?? transportCall?.importVoyageNumber) as string) ?? null,\n universalServiceReference: (transportCall?.universalServiceReference as string) ?? null,\n universalExportVoyageReference: (transportCall?.universalExportVoyageReference as string) ?? null,\n universalImportVoyageReference: (transportCall?.universalImportVoyageReference as string) ?? null,\n portVisitReference: (transportCall?.portVisitReference as string) ?? null,\n\n // \u2500\u2500\u2500 Document References \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n relatedDocumentReferences,\n\n // \u2500\u2500\u2500 Metadata Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n eventCreatedDateTime,\n retractedEventId: (metadata?.retractedEventID as string) ?? null,\n publisherName: (publisher?.partyName as string) ?? _carrierName,\n publisherRole: (metadata?.publisherRole as string) ??\n (event.publisherRole as string) ?? null,\n\n // \u2500\u2500\u2500 Additional Event Fields \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n delayReasonCode: (effectiveEvent.delayReasonCode as string) ?? null,\n changeRemark: (effectiveEvent.changeRemark as string) ?? null,\n seals,\n }\n })\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ function buildDcsaQueryParams(referenceValue, referenceType) {
2
+ switch (referenceType) {
3
+ case "container":
4
+ return `equipmentReference=${encodeURIComponent(referenceValue)}`;
5
+ case "booking":
6
+ return `carrierBookingReference=${encodeURIComponent(referenceValue)}`;
7
+ case "bol":
8
+ return `transportDocumentReference=${encodeURIComponent(referenceValue)}`;
9
+ default:
10
+ return `transportDocumentReference=${encodeURIComponent(referenceValue)}`;
11
+ }
12
+ }
13
+ export {
14
+ buildDcsaQueryParams
15
+ };
16
+ //# sourceMappingURL=dcsa-params.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/shipment_tracking/lib/dcsa-params.ts"],
4
+ "sourcesContent": ["import type { TrackingReferenceType } from '../data/entities'\n\nexport function buildDcsaQueryParams(referenceValue: string, referenceType: TrackingReferenceType): string {\n switch (referenceType) {\n case 'container':\n return `equipmentReference=${encodeURIComponent(referenceValue)}`\n case 'booking':\n return `carrierBookingReference=${encodeURIComponent(referenceValue)}`\n case 'bol':\n return `transportDocumentReference=${encodeURIComponent(referenceValue)}`\n default:\n return `transportDocumentReference=${encodeURIComponent(referenceValue)}`\n }\n}\n"],
5
+ "mappings": "AAEO,SAAS,qBAAqB,gBAAwB,eAA8C;AACzG,UAAQ,eAAe;AAAA,IACrB,KAAK;AACH,aAAO,sBAAsB,mBAAmB,cAAc,CAAC;AAAA,IACjE,KAAK;AACH,aAAO,2BAA2B,mBAAmB,cAAc,CAAC;AAAA,IACtE,KAAK;AACH,aAAO,8BAA8B,mBAAmB,cAAc,CAAC;AAAA,IACzE;AACE,aAAO,8BAA8B,mBAAmB,cAAc,CAAC;AAAA,EAC3E;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,48 @@
1
+ const STALE_AFTER_ARRIVAL_DAYS = 30;
2
+ const DAY_MS = 24 * 60 * 60 * 1e3;
3
+ function staleArrivalCutoff(now = /* @__PURE__ */ new Date()) {
4
+ return new Date(now.getTime() - STALE_AFTER_ARRIVAL_DAYS * DAY_MS);
5
+ }
6
+ function isEmptyGateIn(e) {
7
+ return e.eventType === "EQUIPMENT" && e.eventCode === "GTIN" && e.emptyIndicatorCode === "EMPTY" && e.eventClassifierCode === "ACT";
8
+ }
9
+ function isFinalDelivery(e) {
10
+ return e.eventType === "EQUIPMENT" && e.eventCode === "DLVR" && e.eventClassifierCode === "ACT";
11
+ }
12
+ function isContainerComplete(e) {
13
+ return isEmptyGateIn(e) || isFinalDelivery(e);
14
+ }
15
+ function allContainersComplete(events, containerNumbers) {
16
+ if (containerNumbers.size === 0) return false;
17
+ const complete = /* @__PURE__ */ new Set();
18
+ for (const e of events) {
19
+ if (e.equipmentReference && isContainerComplete(e)) complete.add(e.equipmentReference);
20
+ }
21
+ for (const c of containerNumbers) {
22
+ if (!complete.has(c)) return false;
23
+ }
24
+ return true;
25
+ }
26
+ function isDestinationArrival(e, destinationUnlocode) {
27
+ if (!destinationUnlocode) return false;
28
+ return (e.eventCode === "ARRI" || e.eventCode === "DISC") && e.eventClassifierCode === "ACT" && !!e.locationUnlocode && e.locationUnlocode.toUpperCase() === destinationUnlocode.toUpperCase();
29
+ }
30
+ function destinationArrivedBefore(events, destinationUnlocode, cutoff) {
31
+ for (const e of events) {
32
+ if (!isDestinationArrival(e, destinationUnlocode)) continue;
33
+ const t = e.eventDateTime ? new Date(e.eventDateTime).getTime() : NaN;
34
+ if (!Number.isNaN(t) && t <= cutoff.getTime()) return true;
35
+ }
36
+ return false;
37
+ }
38
+ export {
39
+ STALE_AFTER_ARRIVAL_DAYS,
40
+ allContainersComplete,
41
+ destinationArrivedBefore,
42
+ isContainerComplete,
43
+ isDestinationArrival,
44
+ isEmptyGateIn,
45
+ isFinalDelivery,
46
+ staleArrivalCutoff
47
+ };
48
+ //# sourceMappingURL=empty-return.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/modules/shipment_tracking/lib/empty-return.ts"],
4
+ "sourcesContent": ["/**\n * Container-journey completion detection (to stop polling a finished job).\n *\n * A container is done when the carrier reports either:\n *\n * - **Empty return** (DCSA carriers) \u2014 an actual (`ACT`) empty gate-in\n * (`GTIN` + `emptyIndicatorCode === 'EMPTY'`). Keying on the empty flag is\n * unambiguous: a *laden* `GTIN` is the export-origin gate-in (see\n * `route-inference.ts`), so this can never fire at origin.\n * - **Delivered to consignee** (COSCO) \u2014 an actual `DLVR` event. COSCO never\n * emits `GTIN`/`emptyIndicatorCode`, so it needs its own terminal signal.\n * `DLVR` is COSCO-exclusive (no other adapter or fixture emits it), so this\n * branch cannot prematurely stop a DCSA carrier. Note: we deliberately key on\n * the `DLVR` *event code*, not the `DELIVERED` *status* \u2014 DCSA carriers reach\n * `DELIVERED` via `GTOT`-at-destination (laden pickup) *before* the empty is\n * returned, so a status-based stop would defeat the empty-return intent.\n *\n * A `TrackingJob` may cover many containers (Bill of Lading / Booking Number),\n * so a job is only complete when **every** discovered container is complete \u2014\n * never on the first. Pure helpers: no DI, no persistence.\n *\n * Backup for missing events: empty gate-in (and COSCO `DLVR`) are sometimes\n * absent from carrier feeds, so `destinationArrivedBefore` stops a job once it\n * has arrived at its destination port and `STALE_AFTER_ARRIVAL_DAYS` have passed.\n */\n\n/** Minimal event shape both a fetched and a persisted `TrackingEvent` satisfy. */\nexport type EmptyReturnEvent = {\n eventType: string\n eventCode: string\n eventClassifierCode?: string | null\n emptyIndicatorCode?: string | null\n equipmentReference?: string | null\n locationUnlocode?: string | null\n eventDateTime?: Date | string | null\n}\n\n/** Buffer after destination arrival before we stop a job whose empty-return event never arrived. */\nexport const STALE_AFTER_ARRIVAL_DAYS = 30\nconst DAY_MS = 24 * 60 * 60 * 1000\n\n/** The `cutoff` for `destinationArrivedBefore`: arrivals at/before this are stale. */\nexport function staleArrivalCutoff(now: Date = new Date()): Date {\n return new Date(now.getTime() - STALE_AFTER_ARRIVAL_DAYS * DAY_MS)\n}\n\n/** An actual empty gate-in \u2014 the empty container returned to a depot (DCSA). */\nexport function isEmptyGateIn(e: EmptyReturnEvent): boolean {\n return (\n e.eventType === 'EQUIPMENT' &&\n e.eventCode === 'GTIN' &&\n e.emptyIndicatorCode === 'EMPTY' &&\n e.eventClassifierCode === 'ACT'\n )\n}\n\n/** An actual delivery to consignee \u2014 COSCO's terminal signal (CS210 \u2192 DLVR). */\nexport function isFinalDelivery(e: EmptyReturnEvent): boolean {\n return e.eventType === 'EQUIPMENT' && e.eventCode === 'DLVR' && e.eventClassifierCode === 'ACT'\n}\n\n/** A container is done when it is returned empty (DCSA) or delivered (COSCO). */\nexport function isContainerComplete(e: EmptyReturnEvent): boolean {\n return isEmptyGateIn(e) || isFinalDelivery(e)\n}\n\n/**\n * True when the job has \u22651 discovered container and every one has completed its\n * journey (empty return or delivery), i.e. polling can stop.\n */\nexport function allContainersComplete(\n events: readonly EmptyReturnEvent[],\n containerNumbers: ReadonlySet<string>,\n): boolean {\n if (containerNumbers.size === 0) return false\n const complete = new Set<string>()\n for (const e of events) {\n if (e.equipmentReference && isContainerComplete(e)) complete.add(e.equipmentReference)\n }\n for (const c of containerNumbers) {\n if (!complete.has(c)) return false\n }\n return true\n}\n\n/**\n * An actual arrival at the job's destination port \u2014 `ARRI` (transport) or `DISC`\n * (equipment), `ACT`, at the destination UNLOCODE. Destination-scoped by\n * construction: a null/unknown destination matches nothing, so the backup can\n * never fire for an in-transit shipment. Transshipment arrivals (different\n * UNLOCODE) are excluded.\n */\nexport function isDestinationArrival(\n e: EmptyReturnEvent,\n destinationUnlocode: string | null | undefined,\n): boolean {\n if (!destinationUnlocode) return false\n return (\n (e.eventCode === 'ARRI' || e.eventCode === 'DISC') &&\n e.eventClassifierCode === 'ACT' &&\n !!e.locationUnlocode &&\n e.locationUnlocode.toUpperCase() === destinationUnlocode.toUpperCase()\n )\n}\n\n/**\n * Time-based backup: true when the shipment arrived at its destination port\n * at/before `cutoff` (i.e. long enough ago to stop even though the empty-return\n * event never arrived). Job-level \u2014 `ARRI` carries no container reference.\n */\nexport function destinationArrivedBefore(\n events: readonly EmptyReturnEvent[],\n destinationUnlocode: string | null | undefined,\n cutoff: Date,\n): boolean {\n for (const e of events) {\n if (!isDestinationArrival(e, destinationUnlocode)) continue\n const t = e.eventDateTime ? new Date(e.eventDateTime).getTime() : NaN\n if (!Number.isNaN(t) && t <= cutoff.getTime()) return true\n }\n return false\n}\n"],
5
+ "mappings": "AAsCO,MAAM,2BAA2B;AACxC,MAAM,SAAS,KAAK,KAAK,KAAK;AAGvB,SAAS,mBAAmB,MAAY,oBAAI,KAAK,GAAS;AAC/D,SAAO,IAAI,KAAK,IAAI,QAAQ,IAAI,2BAA2B,MAAM;AACnE;AAGO,SAAS,cAAc,GAA8B;AAC1D,SACE,EAAE,cAAc,eAChB,EAAE,cAAc,UAChB,EAAE,uBAAuB,WACzB,EAAE,wBAAwB;AAE9B;AAGO,SAAS,gBAAgB,GAA8B;AAC5D,SAAO,EAAE,cAAc,eAAe,EAAE,cAAc,UAAU,EAAE,wBAAwB;AAC5F;AAGO,SAAS,oBAAoB,GAA8B;AAChE,SAAO,cAAc,CAAC,KAAK,gBAAgB,CAAC;AAC9C;AAMO,SAAS,sBACd,QACA,kBACS;AACT,MAAI,iBAAiB,SAAS,EAAG,QAAO;AACxC,QAAM,WAAW,oBAAI,IAAY;AACjC,aAAW,KAAK,QAAQ;AACtB,QAAI,EAAE,sBAAsB,oBAAoB,CAAC,EAAG,UAAS,IAAI,EAAE,kBAAkB;AAAA,EACvF;AACA,aAAW,KAAK,kBAAkB;AAChC,QAAI,CAAC,SAAS,IAAI,CAAC,EAAG,QAAO;AAAA,EAC/B;AACA,SAAO;AACT;AASO,SAAS,qBACd,GACA,qBACS;AACT,MAAI,CAAC,oBAAqB,QAAO;AACjC,UACG,EAAE,cAAc,UAAU,EAAE,cAAc,WAC3C,EAAE,wBAAwB,SAC1B,CAAC,CAAC,EAAE,oBACJ,EAAE,iBAAiB,YAAY,MAAM,oBAAoB,YAAY;AAEzE;AAOO,SAAS,yBACd,QACA,qBACA,QACS;AACT,aAAW,KAAK,QAAQ;AACtB,QAAI,CAAC,qBAAqB,GAAG,mBAAmB,EAAG;AACnD,UAAM,IAAI,EAAE,gBAAgB,IAAI,KAAK,EAAE,aAAa,EAAE,QAAQ,IAAI;AAClE,QAAI,CAAC,OAAO,MAAM,CAAC,KAAK,KAAK,OAAO,QAAQ,EAAG,QAAO;AAAA,EACxD;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }