@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,238 @@
1
+ import type { CarrierFetchedEvent } from './carrier-adapter'
2
+
3
+ export interface InferredRoute {
4
+ originUnlocode: string | null
5
+ destinationUnlocode: string | null
6
+ confidence: {
7
+ origin: 'high' | 'medium' | 'low' | null
8
+ destination: 'high' | 'medium' | 'low' | null
9
+ }
10
+ }
11
+
12
+ /**
13
+ * Checks if the facility type represents a port or intermodal terminal.
14
+ * Used to filter out client locations (CLOC) and depots (DEPO) when inferring ports.
15
+ *
16
+ * Valid facility types for port inference:
17
+ * - POTE: Port Terminal
18
+ * - INTE: Intermodal Terminal (rail/truck interchange)
19
+ */
20
+ function isPortOrTerminal(facilityTypeCode: string | null | undefined): boolean {
21
+ if (!facilityTypeCode) return false
22
+ return facilityTypeCode === 'POTE' || facilityTypeCode === 'INTE'
23
+ }
24
+
25
+ /**
26
+ * Checks if the facility type is a known non-port location (client site or depot).
27
+ * Used to filter out these locations when inferring destination ports.
28
+ */
29
+ function isNonPortLocation(facilityTypeCode: string | null | undefined): boolean {
30
+ if (!facilityTypeCode) return false
31
+ // CLOC = Client Location, DEPO = Depot - these are inland delivery points
32
+ return facilityTypeCode === 'CLOC' || facilityTypeCode === 'DEPO'
33
+ }
34
+
35
+ /**
36
+ * Infers origin and destination ports from DCSA tracking events.
37
+ *
38
+ * Strategy for DESTINATION:
39
+ * 1. Last EST/PLN ARRI event at a port terminal (POTE/INTE) → high confidence
40
+ * 2. Last ACT ARRI on VESSEL at a port terminal → high confidence
41
+ * 3. Last DISC event at a port terminal → medium confidence
42
+ * 4. Fallback: Last ARRI/DISC at any location (when no port data available)
43
+ *
44
+ * IMPORTANT: We filter by facilityTypeCode to exclude client locations (CLOC)
45
+ * and depots (DEPO) which are inland delivery points, not ports.
46
+ *
47
+ * Strategy for ORIGIN:
48
+ * 1. First ACT DEPA on VESSEL with exportVoyageNumber → high confidence (departure from load port)
49
+ * 2. First LOAD event on VESSEL → high confidence (where cargo was first loaded)
50
+ * 3. First GTIN (LADEN) event → medium confidence (gate-in at origin)
51
+ *
52
+ * Key insight:
53
+ * - exportVoyageNumber indicates outbound leg (origin side)
54
+ * - importVoyageNumber indicates inbound leg (destination side)
55
+ */
56
+ export function inferRouteFromEvents(events: CarrierFetchedEvent[]): InferredRoute {
57
+ const result: InferredRoute = {
58
+ originUnlocode: null,
59
+ destinationUnlocode: null,
60
+ confidence: {
61
+ origin: null,
62
+ destination: null,
63
+ },
64
+ }
65
+
66
+ if (!events || events.length === 0) {
67
+ return result
68
+ }
69
+
70
+ // Sort events by datetime for chronological processing
71
+ const sortedEvents = [...events].sort(
72
+ (a, b) => a.eventDateTime.getTime() - b.eventDateTime.getTime()
73
+ )
74
+
75
+ // ─── DESTINATION INFERENCE ─────────────────────────────────────────
76
+ // For transshipment voyages, there are multiple ARRI events (one per port).
77
+ // The LAST arrival event at a PORT TERMINAL is the final destination.
78
+ // We explicitly filter out client locations (CLOC) and depots (DEPO).
79
+
80
+ // Strategy 1: Look for LAST ARRI event (EST or PLN), excluding known non-port locations
81
+ // PLN (planned) and EST (estimated) both indicate scheduled arrivals.
82
+ // We take the LAST one as the final destination, filtering out client locations/depots.
83
+ // Note: We use "exclude non-port" rather than "include only port" to handle cases
84
+ // where facilityTypeCode is not provided (common in many carriers' responses).
85
+ const plannedArriEvents = sortedEvents.filter(
86
+ (e) =>
87
+ e.eventType === 'TRANSPORT' &&
88
+ e.eventCode === 'ARRI' &&
89
+ (e.eventClassifierCode === 'EST' || e.eventClassifierCode === 'PLN') &&
90
+ e.locationUnlocode &&
91
+ !isNonPortLocation(e.facilityTypeCode)
92
+ )
93
+
94
+ if (plannedArriEvents.length > 0) {
95
+ // Take the last planned arrival - this is the final port destination
96
+ const lastPlannedArri = plannedArriEvents[plannedArriEvents.length - 1]
97
+ result.destinationUnlocode = lastPlannedArri.locationUnlocode!
98
+ // High confidence if we have facility type info confirming it's a port, otherwise still high for PLN/EST
99
+ result.confidence.destination = 'high'
100
+ }
101
+
102
+ // Strategy 2: Look for last ACT ARRI on VESSEL, excluding known non-port locations
103
+ if (!result.destinationUnlocode) {
104
+ const actArriEvents = sortedEvents.filter(
105
+ (e) =>
106
+ e.eventType === 'TRANSPORT' &&
107
+ e.eventCode === 'ARRI' &&
108
+ e.eventClassifierCode === 'ACT' &&
109
+ e.modeOfTransport === 'VESSEL' &&
110
+ e.locationUnlocode &&
111
+ !isNonPortLocation(e.facilityTypeCode)
112
+ )
113
+
114
+ if (actArriEvents.length > 0) {
115
+ const lastArri = actArriEvents[actArriEvents.length - 1]
116
+ result.destinationUnlocode = lastArri.locationUnlocode!
117
+ result.confidence.destination = 'high'
118
+ }
119
+ }
120
+
121
+ // Strategy 3: Look for last DISC event, excluding known non-port locations
122
+ if (!result.destinationUnlocode) {
123
+ const discEvents = sortedEvents.filter(
124
+ (e) =>
125
+ e.eventType === 'EQUIPMENT' &&
126
+ e.eventCode === 'DISC' &&
127
+ e.locationUnlocode &&
128
+ !isNonPortLocation(e.facilityTypeCode)
129
+ )
130
+
131
+ if (discEvents.length > 0) {
132
+ const lastDisc = discEvents[discEvents.length - 1]
133
+ result.destinationUnlocode = lastDisc.locationUnlocode!
134
+ result.confidence.destination = 'medium'
135
+ }
136
+ }
137
+
138
+ // ─── ORIGIN INFERENCE ──────────────────────────────────────────────
139
+
140
+ // Strategy 1: First ACT DEPA on VESSEL with exportVoyageNumber
141
+ const firstVesselDepa = sortedEvents.find(
142
+ (e) =>
143
+ e.eventType === 'TRANSPORT' &&
144
+ e.eventCode === 'DEPA' &&
145
+ e.eventClassifierCode === 'ACT' &&
146
+ e.modeOfTransport === 'VESSEL' &&
147
+ e.carrierExportVoyageNumber &&
148
+ e.locationUnlocode
149
+ )
150
+
151
+ if (firstVesselDepa?.locationUnlocode) {
152
+ result.originUnlocode = firstVesselDepa.locationUnlocode
153
+ result.confidence.origin = 'high'
154
+ }
155
+
156
+ // Strategy 2: First LOAD event on VESSEL
157
+ if (!result.originUnlocode) {
158
+ const firstLoad = sortedEvents.find(
159
+ (e) =>
160
+ e.eventType === 'EQUIPMENT' &&
161
+ e.eventCode === 'LOAD' &&
162
+ e.eventClassifierCode === 'ACT' &&
163
+ e.modeOfTransport === 'VESSEL' &&
164
+ e.locationUnlocode
165
+ )
166
+
167
+ if (firstLoad?.locationUnlocode) {
168
+ result.originUnlocode = firstLoad.locationUnlocode
169
+ result.confidence.origin = 'high'
170
+ }
171
+ }
172
+
173
+ // Strategy 3: First GTIN (LADEN) event at a port terminal (fallback)
174
+ // Only consider events at port terminals (POTE), not inland depots (DEPO)
175
+ if (!result.originUnlocode) {
176
+ const firstGtinLaden = sortedEvents.find(
177
+ (e) =>
178
+ e.eventType === 'EQUIPMENT' &&
179
+ e.eventCode === 'GTIN' &&
180
+ e.emptyIndicatorCode === 'LADEN' &&
181
+ e.eventClassifierCode === 'ACT' &&
182
+ e.locationUnlocode &&
183
+ e.facilityTypeCode === 'POTE' // Port Terminal only
184
+ )
185
+
186
+ if (firstGtinLaden?.locationUnlocode) {
187
+ result.originUnlocode = firstGtinLaden.locationUnlocode
188
+ result.confidence.origin = 'medium'
189
+ }
190
+ }
191
+
192
+ // Strategy 4: First EST/PLN DEPA on VESSEL (for pre-departure tracking)
193
+ // When no actual events exist yet, use planned departure to infer origin
194
+ if (!result.originUnlocode) {
195
+ const firstPlannedDepa = sortedEvents.find(
196
+ (e) =>
197
+ e.eventType === 'TRANSPORT' &&
198
+ e.eventCode === 'DEPA' &&
199
+ (e.eventClassifierCode === 'EST' || e.eventClassifierCode === 'PLN') &&
200
+ e.modeOfTransport === 'VESSEL' &&
201
+ e.locationUnlocode
202
+ )
203
+
204
+ if (firstPlannedDepa?.locationUnlocode) {
205
+ result.originUnlocode = firstPlannedDepa.locationUnlocode
206
+ result.confidence.origin = 'medium' // Lower confidence for planned events
207
+ }
208
+ }
209
+
210
+ // Strategy 5: First PLN LOAD event on VESSEL (for pre-departure tracking)
211
+ if (!result.originUnlocode) {
212
+ const firstPlannedLoad = sortedEvents.find(
213
+ (e) =>
214
+ e.eventType === 'EQUIPMENT' &&
215
+ e.eventCode === 'LOAD' &&
216
+ (e.eventClassifierCode === 'EST' || e.eventClassifierCode === 'PLN') &&
217
+ e.modeOfTransport === 'VESSEL' &&
218
+ e.locationUnlocode
219
+ )
220
+
221
+ if (firstPlannedLoad?.locationUnlocode) {
222
+ result.originUnlocode = firstPlannedLoad.locationUnlocode
223
+ result.confidence.origin = 'medium'
224
+ }
225
+ }
226
+
227
+ return result
228
+ }
229
+
230
+ /**
231
+ * Validates a UN/LOCODE format.
232
+ * Format: 2 letters (country) + 3 alphanumeric (location)
233
+ * Example: CNYTN (China, Yantian), PLGDN (Poland, Gdansk)
234
+ */
235
+ export function isValidUnlocode(code: string | null | undefined): boolean {
236
+ if (!code) return false
237
+ return /^[A-Z]{2}[A-Z0-9]{3}$/.test(code.toUpperCase())
238
+ }
@@ -0,0 +1,92 @@
1
+ const DEFAULT_WINDOW_DAYS = 120 // 4 months
2
+ const JITTER_RANGE_HOURS = 4
3
+
4
+ function addDays(date: Date, days: number): Date {
5
+ const result = new Date(date)
6
+ result.setDate(result.getDate() + days)
7
+ return result
8
+ }
9
+
10
+ function addHours(date: Date, hours: number): Date {
11
+ const result = new Date(date)
12
+ result.setTime(result.getTime() + hours * 60 * 60 * 1000)
13
+ return result
14
+ }
15
+
16
+ function randomJitter(): number {
17
+ return Math.random() * JITTER_RANGE_HOURS - JITTER_RANGE_HOURS / 2
18
+ }
19
+
20
+ /**
21
+ * Generates a list of daily poll dates with random time jitter.
22
+ *
23
+ * - If ETD and ETA are provided, generates dates from ETD - 7 days to ETA + 14 days.
24
+ * - If only ETD is provided, generates from ETD - 7 days for the default window.
25
+ * - If nothing is provided, starts from now for the default window.
26
+ * - Jitter is +/- 2 hours to spread API load.
27
+ */
28
+ export function generatePollSchedule(input?: {
29
+ etd?: Date | null
30
+ eta?: Date | null
31
+ atd?: Date | null
32
+ ata?: Date | null
33
+ }): string[] {
34
+ const now = new Date()
35
+
36
+ // If already delivered (ATA present), no more polling needed
37
+ if (input?.ata) {
38
+ return []
39
+ }
40
+
41
+ let startDate: Date
42
+ let endDate: Date
43
+
44
+ if (input?.etd) {
45
+ startDate = addDays(input.etd, -7)
46
+ } else if (input?.atd) {
47
+ startDate = input.atd
48
+ } else {
49
+ startDate = now
50
+ }
51
+
52
+ if (input?.eta) {
53
+ endDate = addDays(input.eta, 14)
54
+ } else {
55
+ endDate = addDays(startDate, DEFAULT_WINDOW_DAYS)
56
+ }
57
+
58
+ // Ensure start is not in the past
59
+ if (startDate < now) {
60
+ startDate = now
61
+ }
62
+
63
+ const dates: string[] = []
64
+ let current = new Date(startDate)
65
+
66
+ while (current <= endDate) {
67
+ const withJitter = addHours(current, randomJitter())
68
+ // Only include future dates
69
+ if (withJitter > now) {
70
+ dates.push(withJitter.toISOString())
71
+ }
72
+ current = addDays(current, 1)
73
+ }
74
+
75
+ return dates
76
+ }
77
+
78
+ /**
79
+ * Given a schedule (array of ISO date strings), returns the next poll date after now.
80
+ */
81
+ export function getNextPollDate(schedule: string[]): Date | null {
82
+ const now = Date.now()
83
+
84
+ for (const dateStr of schedule) {
85
+ const date = new Date(dateStr)
86
+ if (date.getTime() > now) {
87
+ return date
88
+ }
89
+ }
90
+
91
+ return null
92
+ }
@@ -0,0 +1,350 @@
1
+ /**
2
+ * ShipsGo API v2 client (ocean + air).
3
+ *
4
+ * ShipsGo is a register-then-poll provider: you POST a shipment (spending a
5
+ * credit) and receive a ShipsGo shipment id, then GET that id for movements.
6
+ * Registration is idempotent on `reference` — a duplicate returns 409 with the
7
+ * existing shipment, so we treat 200 and 409 the same (both yield an id).
8
+ *
9
+ * Raw `fetch` is correct here (this is a server-side lib, not UI — `apiCall`
10
+ * is the frontend helper). Auth is the `X-Shipsgo-User-Token` header.
11
+ *
12
+ * Docs: https://api.shipsgo.com/v2
13
+ */
14
+
15
+ const TOKEN_HEADER = 'X-Shipsgo-User-Token'
16
+
17
+ /**
18
+ * Per-request timeout. ShipsGo polls run inside a sequential job loop, so a hung
19
+ * endpoint would otherwise stall the whole worker. Aborted requests surface as a
20
+ * normal fetch error → recorded as a transient job error.
21
+ */
22
+ const REQUEST_TIMEOUT_MS = 20_000
23
+
24
+ /**
25
+ * Standardizes an AWB to ShipsGo's `NNN-NNNNNNNN` shape (3 digits, hyphen, 8
26
+ * digits) so a value typed with spaces/other separators still validates against
27
+ * ShipsGo's `^[0-9]{3}(-)?[0-9]{8}$` pattern. Returns the trimmed input
28
+ * unchanged when it isn't 11 digits (let ShipsGo return the authoritative error).
29
+ */
30
+ export function normalizeAwbNumber(raw: string): string {
31
+ const digits = raw.replace(/\D/g, '')
32
+ if (digits.length === 11) return `${digits.slice(0, 3)}-${digits.slice(3)}`
33
+ return raw.trim()
34
+ }
35
+
36
+ export type ShipsGoClientConfig = {
37
+ apiToken: string
38
+ baseUrl: string
39
+ }
40
+
41
+ /** Thrown on HTTP 402 — the ShipsGo account has no remaining credits. */
42
+ export class ShipsGoCreditsExhaustedError extends Error {
43
+ constructor(message = 'ShipsGo credits exhausted (HTTP 402)') {
44
+ super(message)
45
+ this.name = 'ShipsGoCreditsExhaustedError'
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Thrown on HTTP 403 — the token is missing/invalid/expired. This is an
51
+ * account-level condition (like 402), not a per-job fault, so callers back the
52
+ * job off instead of burning its retry budget.
53
+ */
54
+ export class ShipsGoAuthError extends Error {
55
+ constructor(message = 'ShipsGo authentication failed (HTTP 403)') {
56
+ super(message)
57
+ this.name = 'ShipsGoAuthError'
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Thrown on HTTP 429 — the ShipsGo rate limit (100 req/min, collective across
63
+ * the account) was exceeded. `retryAfterSeconds` is derived from the
64
+ * `RateLimit-Reset` (UTC epoch) or `Retry-After` header when present. Transient,
65
+ * so callers back the job off without consuming its retry budget.
66
+ */
67
+ export class ShipsGoRateLimitedError extends Error {
68
+ constructor(
69
+ message = 'ShipsGo rate limit exceeded (HTTP 429)',
70
+ public readonly retryAfterSeconds?: number,
71
+ ) {
72
+ super(message)
73
+ this.name = 'ShipsGoRateLimitedError'
74
+ }
75
+ }
76
+
77
+ /** Thrown for any other non-2xx (and non-409) ShipsGo response. */
78
+ export class ShipsGoApiError extends Error {
79
+ constructor(
80
+ public readonly status: number,
81
+ message: string,
82
+ ) {
83
+ super(message)
84
+ this.name = 'ShipsGoApiError'
85
+ }
86
+ }
87
+
88
+ export type ShipsGoRegisterResult = {
89
+ /** ShipsGo shipment id (stringified integer). */
90
+ id: string
91
+ /** True when the shipment already existed (HTTP 409) — no credit spent. */
92
+ alreadyExisted: boolean
93
+ }
94
+
95
+ // ─── Response types (only the fields we consume) ─────────────────────────────
96
+
97
+ export type ShipsGoOceanLocation = {
98
+ code?: string | null
99
+ name?: string | null
100
+ timezone?: string | null
101
+ country?: { code?: string | null; name?: string | null } | null
102
+ }
103
+
104
+ export type ShipsGoOceanMovement = {
105
+ event: string // EMSH | GTIN | LOAD | DEPA | ARRV | DISC | GTOT | EMRT
106
+ status: 'EST' | 'ACT'
107
+ location?: ShipsGoOceanLocation | null
108
+ vessel?: { imo?: number | null; name?: string | null } | null
109
+ voyage?: string | null
110
+ timestamp: string
111
+ }
112
+
113
+ export type ShipsGoOceanContainer = {
114
+ number: string
115
+ status?: string | null
116
+ size?: number | null
117
+ type?: string | null
118
+ movements?: ShipsGoOceanMovement[] | null
119
+ }
120
+
121
+ /** ShipsGo route summary (shipment-level; POL/POD, transit, emissions). */
122
+ export type ShipsGoOceanRoutePort = {
123
+ location?: ShipsGoOceanLocation | null
124
+ date_of_loading?: string | null
125
+ date_of_discharge?: string | null
126
+ date_of_discharge_predicted?: string | null
127
+ }
128
+
129
+ export type ShipsGoOceanRoute = {
130
+ port_of_loading?: ShipsGoOceanRoutePort | null
131
+ port_of_discharge?: ShipsGoOceanRoutePort | null
132
+ transit_time?: number | null
133
+ transit_percentage?: number | null
134
+ co2_emission?: number | null
135
+ ts_count?: number | null
136
+ }
137
+
138
+ export type ShipsGoOceanShipment = {
139
+ id: number
140
+ reference?: string | null
141
+ booking_number?: string | null
142
+ container_number?: string | null
143
+ carrier?: { scac?: string | null; name?: string | null; status?: string | null } | null
144
+ status?: string | null
145
+ route?: ShipsGoOceanRoute | null
146
+ containers?: ShipsGoOceanContainer[] | null
147
+ }
148
+
149
+ // ─── Air response types (only the fields we consume) ─────────────────────────
150
+
151
+ export type ShipsGoAirLocation = {
152
+ name?: string | null
153
+ iata?: string | null
154
+ timezone?: string | null
155
+ country?: { code?: string | null; name?: string | null } | null
156
+ }
157
+
158
+ export type ShipsGoAirMovement = {
159
+ event: string // RCS | MAN | DEP | ARR | RCF | DLV
160
+ status: 'EST' | 'ACT'
161
+ location?: ShipsGoAirLocation | null
162
+ flight?: string | null
163
+ timestamp: string
164
+ }
165
+
166
+ /** ShipsGo air cargo summary (pieces / weight / volume). */
167
+ export type ShipsGoAirCargo = {
168
+ pieces?: number | null
169
+ weight?: number | null
170
+ weight_unit?: string | null
171
+ volume?: number | null
172
+ volume_unit?: string | null
173
+ }
174
+
175
+ /** ShipsGo air route summary (origin/destination airports + transit/emissions). */
176
+ export type ShipsGoAirRoutePort = {
177
+ location?: ShipsGoAirLocation | null
178
+ date_of_dep?: string | null
179
+ date_of_rcf?: string | null
180
+ }
181
+
182
+ export type ShipsGoAirRoute = {
183
+ origin?: ShipsGoAirRoutePort | null
184
+ destination?: ShipsGoAirRoutePort | null
185
+ transit_time?: number | null
186
+ transit_percentage?: number | null
187
+ co2_emission?: number | null
188
+ ts_count?: number | null
189
+ }
190
+
191
+ export type ShipsGoAirShipment = {
192
+ id: number
193
+ reference?: string | null
194
+ awb_number?: string | null
195
+ airline?: { iata?: string | null; name?: string | null } | null
196
+ status?: string | null // NEW | INPROGRESS | BOOKED | EN_ROUTE | LANDED | DELIVERED | UNTRACKED
197
+ status_extended?: unknown | null
198
+ cargo?: ShipsGoAirCargo | null
199
+ route?: ShipsGoAirRoute | null
200
+ movements?: ShipsGoAirMovement[] | null
201
+ }
202
+
203
+ type ShipmentEnvelope<T> = { message?: string; shipment?: T }
204
+
205
+ // ─── Internal fetch helper ───────────────────────────────────────────────────
206
+
207
+ async function shipsGoFetch(
208
+ config: ShipsGoClientConfig,
209
+ path: string,
210
+ init: RequestInit,
211
+ ): Promise<Response> {
212
+ const url = `${config.baseUrl.replace(/\/$/, '')}${path}`
213
+ return fetch(url, {
214
+ ...init,
215
+ signal: init.signal ?? AbortSignal.timeout(REQUEST_TIMEOUT_MS),
216
+ headers: {
217
+ [TOKEN_HEADER]: config.apiToken,
218
+ 'Content-Type': 'application/json',
219
+ Accept: 'application/json',
220
+ ...(init.headers ?? {}),
221
+ },
222
+ })
223
+ }
224
+
225
+ /**
226
+ * Maps account-level HTTP statuses (402/403/429) to their typed errors so every
227
+ * caller (register + GET) handles them uniformly. Returns without throwing for
228
+ * anything else; the caller then handles 409 / generic failures itself.
229
+ */
230
+ function throwForAccountLevelStatus(response: Response): void {
231
+ if (response.status === 402) throw new ShipsGoCreditsExhaustedError()
232
+ if (response.status === 403) throw new ShipsGoAuthError()
233
+ if (response.status === 429) throw new ShipsGoRateLimitedError(undefined, retryAfterSeconds(response))
234
+ }
235
+
236
+ /** Seconds until the rate-limit window resets, from `RateLimit-Reset` (UTC epoch) or `Retry-After`. */
237
+ function retryAfterSeconds(response: Response): number | undefined {
238
+ const reset = response.headers.get('RateLimit-Reset') ?? response.headers.get('X-RateLimit-Reset')
239
+ if (reset) {
240
+ const resetEpoch = Number(reset)
241
+ if (Number.isFinite(resetEpoch)) return Math.max(0, Math.ceil(resetEpoch - Date.now() / 1000))
242
+ }
243
+ const retryAfter = response.headers.get('Retry-After')
244
+ if (retryAfter) {
245
+ const secs = Number(retryAfter)
246
+ if (Number.isFinite(secs)) return Math.max(0, Math.ceil(secs))
247
+ }
248
+ return undefined
249
+ }
250
+
251
+ function toId(shipment: { id?: number } | undefined): string {
252
+ if (!shipment || shipment.id == null) {
253
+ throw new ShipsGoApiError(500, 'ShipsGo response missing shipment id')
254
+ }
255
+ return String(shipment.id)
256
+ }
257
+
258
+ async function handleRegister(response: Response): Promise<ShipsGoRegisterResult> {
259
+ throwForAccountLevelStatus(response)
260
+ if (response.status === 409) {
261
+ // Already exists — free; extract the existing shipment id.
262
+ const body = (await response.json().catch(() => ({}))) as ShipmentEnvelope<{ id: number }>
263
+ return { id: toId(body.shipment), alreadyExisted: true }
264
+ }
265
+ if (!response.ok) {
266
+ const text = await response.text().catch(() => 'unknown')
267
+ throw new ShipsGoApiError(response.status, `ShipsGo register failed (${response.status}): ${text}`)
268
+ }
269
+ const body = (await response.json()) as ShipmentEnvelope<{ id: number }>
270
+ return { id: toId(body.shipment), alreadyExisted: false }
271
+ }
272
+
273
+ // ─── Ocean ───────────────────────────────────────────────────────────────────
274
+
275
+ export async function registerOceanShipment(
276
+ config: ShipsGoClientConfig,
277
+ input: {
278
+ reference: string
279
+ bookingNumber?: string | null
280
+ containerNumber?: string | null
281
+ /** Optional SCAC hint — ShipsGo auto-detects the line when omitted. */
282
+ carrier?: string | null
283
+ },
284
+ ): Promise<ShipsGoRegisterResult> {
285
+ const payload: Record<string, unknown> = { reference: input.reference }
286
+ if (input.bookingNumber) payload.booking_number = input.bookingNumber
287
+ else if (input.containerNumber) payload.container_number = input.containerNumber
288
+ if (input.carrier) payload.carrier = input.carrier
289
+
290
+ const response = await shipsGoFetch(config, '/ocean/shipments', {
291
+ method: 'POST',
292
+ body: JSON.stringify(payload),
293
+ })
294
+ return handleRegister(response)
295
+ }
296
+
297
+ export async function getOceanShipment(
298
+ config: ShipsGoClientConfig,
299
+ id: string,
300
+ ): Promise<ShipsGoOceanShipment> {
301
+ const response = await shipsGoFetch(config, `/ocean/shipments/${encodeURIComponent(id)}`, {
302
+ method: 'GET',
303
+ })
304
+ throwForAccountLevelStatus(response)
305
+ if (!response.ok) {
306
+ const text = await response.text().catch(() => 'unknown')
307
+ throw new ShipsGoApiError(response.status, `ShipsGo get ocean shipment failed (${response.status}): ${text}`)
308
+ }
309
+ const body = (await response.json()) as ShipmentEnvelope<ShipsGoOceanShipment>
310
+ if (!body.shipment) {
311
+ throw new ShipsGoApiError(500, 'ShipsGo ocean response missing shipment')
312
+ }
313
+ return body.shipment
314
+ }
315
+
316
+ // ─── Air ───────────────────────────────────────────────────────────────────────
317
+
318
+ export async function registerAirShipment(
319
+ config: ShipsGoClientConfig,
320
+ input: {
321
+ reference: string
322
+ /** Air Waybill number — ShipsGo standardizes to `333-88888888`. */
323
+ awbNumber: string
324
+ },
325
+ ): Promise<ShipsGoRegisterResult> {
326
+ const response = await shipsGoFetch(config, '/air/shipments', {
327
+ method: 'POST',
328
+ body: JSON.stringify({ reference: input.reference, awb_number: normalizeAwbNumber(input.awbNumber) }),
329
+ })
330
+ return handleRegister(response)
331
+ }
332
+
333
+ export async function getAirShipment(
334
+ config: ShipsGoClientConfig,
335
+ id: string,
336
+ ): Promise<ShipsGoAirShipment> {
337
+ const response = await shipsGoFetch(config, `/air/shipments/${encodeURIComponent(id)}`, {
338
+ method: 'GET',
339
+ })
340
+ throwForAccountLevelStatus(response)
341
+ if (!response.ok) {
342
+ const text = await response.text().catch(() => 'unknown')
343
+ throw new ShipsGoApiError(response.status, `ShipsGo get air shipment failed (${response.status}): ${text}`)
344
+ }
345
+ const body = (await response.json()) as ShipmentEnvelope<ShipsGoAirShipment>
346
+ if (!body.shipment) {
347
+ throw new ShipsGoApiError(500, 'ShipsGo air response missing shipment')
348
+ }
349
+ return body.shipment
350
+ }