@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,198 @@
1
+ /**
2
+ * POI Proximity Event Types
3
+ *
4
+ * Type definitions for AIS POI proximity events received from the
5
+ * poi-proximity-detector service via NATS.
6
+ */
7
+
8
+ // ─── Enums ───────────────────────────────────────────────────
9
+
10
+ /**
11
+ * Types of proximity events emitted by the POI detector.
12
+ */
13
+ export type ProximityEventType =
14
+ | 'PORT_ARRIVAL'
15
+ | 'PORT_PROXIMITY_ARRIVAL'
16
+ | 'PORT_PROXIMITY_DEPARTURE'
17
+ | 'TERMINAL_ARRIVAL'
18
+ | 'TERMINAL_PROXIMITY_ARRIVAL'
19
+ | 'TERMINAL_PROXIMITY_DEPARTURE'
20
+ | 'WAYPOINT_REACHED'
21
+
22
+ /**
23
+ * Map POI event types to distinct event codes for TrackingEvent records.
24
+ * These codes are AIS-specific and don't conflict with standard DCSA codes.
25
+ * Labels are resolved via i18n: shipment_tracking.event_codes.<CODE>
26
+ */
27
+ export const PROXIMITY_EVENT_CODES: Record<ProximityEventType, string> = {
28
+ PORT_ARRIVAL: 'PARR',
29
+ PORT_PROXIMITY_ARRIVAL: 'PPRA',
30
+ PORT_PROXIMITY_DEPARTURE: 'PPRD',
31
+ TERMINAL_ARRIVAL: 'TARR',
32
+ TERMINAL_PROXIMITY_ARRIVAL: 'TPRA',
33
+ TERMINAL_PROXIMITY_DEPARTURE: 'TPRD',
34
+ WAYPOINT_REACHED: 'WAYR',
35
+ }
36
+
37
+ /**
38
+ * Categorize events as arrival, departure, or proximity.
39
+ */
40
+ export type ProximityEventCategory = 'arrival' | 'departure' | 'proximity' | 'waypoint'
41
+
42
+ export const PROXIMITY_EVENT_CATEGORY: Record<ProximityEventType, ProximityEventCategory> = {
43
+ PORT_ARRIVAL: 'arrival',
44
+ PORT_PROXIMITY_ARRIVAL: 'proximity',
45
+ PORT_PROXIMITY_DEPARTURE: 'departure',
46
+ TERMINAL_ARRIVAL: 'arrival',
47
+ TERMINAL_PROXIMITY_ARRIVAL: 'proximity',
48
+ TERMINAL_PROXIMITY_DEPARTURE: 'departure',
49
+ WAYPOINT_REACHED: 'waypoint',
50
+ }
51
+
52
+ // ─── Event Payload ───────────────────────────────────────────
53
+
54
+ /**
55
+ * POI proximity event payload received from the AIS POI detector.
56
+ *
57
+ * This matches the ShipPoiProximityData interface from the poi-proximity-detector service.
58
+ */
59
+ export interface PoiProximityEvent {
60
+ /**
61
+ * Vessel IMO number. In the AIS system `ships.id` IS the IMO, and the detector
62
+ * sets this field from `ship.id` — so this is the real IMO, not an internal id.
63
+ * Used to match shipments directly by `vesselImo` (no MMSI→IMO lookup).
64
+ */
65
+ shipId: number
66
+
67
+ /** Ship name */
68
+ shipName: string
69
+
70
+ /** Maritime Mobile Service Identity (9 digits) */
71
+ mmsi: number
72
+
73
+ /** Latitude of ship position */
74
+ lat: number
75
+
76
+ /** Longitude of ship position */
77
+ lng: number
78
+
79
+ /** Actual Time of Arrival (ISO 8601) - present for arrival events */
80
+ ata?: string
81
+
82
+ /** Actual Time of Departure (ISO 8601) - present for departure events */
83
+ atd?: string
84
+
85
+ /** Type of proximity event */
86
+ type: ProximityEventType
87
+
88
+ /** POI code for arrival events (e.g., port/terminal LOCODE or custom code) */
89
+ arrivedPoiCode?: string
90
+
91
+ /** POI code for departure events */
92
+ departedPoiCode?: string
93
+
94
+ /** Distance to POI in meters (null if not applicable) */
95
+ distanceToPoiMeters: number | null
96
+
97
+ /** Sequence order for multiple events in same message batch */
98
+ sequenceOrder: number
99
+
100
+ /**
101
+ * Human-friendly POI identity for arrival/proximity events at a matched port or terminal.
102
+ * All nullable — which fields are populated depends on the event type and how rich the
103
+ * matched POI is (e.g. a PORT_ARRIVAL from a port's geometric center may only have `city`).
104
+ * Resolved for display via {@link resolvePoiLocationName}.
105
+ */
106
+ portName?: string | null
107
+ terminalName?: string | null
108
+ city?: string | null
109
+
110
+ /**
111
+ * Human-friendly region name in Polish (e.g. "Morze Północne"), set for open-water
112
+ * WAYPOINT_REACHED events that have no port/terminal/city. Null for port/terminal events.
113
+ */
114
+ regionNamePl?: string | null
115
+
116
+ /** Human-friendly region name in English (e.g. "North Sea"). Null for port/terminal events — see {@link regionNamePl}. */
117
+ regionNameEn?: string | null
118
+ }
119
+
120
+ // ─── Processed Event ─────────────────────────────────────────
121
+
122
+ /**
123
+ * Processed POI event enriched with shipment context.
124
+ */
125
+ export interface ProcessedPoiEvent {
126
+ /** Original POI event */
127
+ poiEvent: PoiProximityEvent
128
+
129
+ /** IMO number (resolved from MMSI if needed) */
130
+ vesselImo: string | null
131
+
132
+ /** Matched shipment IDs */
133
+ shipmentIds: string[]
134
+
135
+ /** Event timestamp (from ata/atd or current time) */
136
+ eventDateTime: Date
137
+
138
+ /** POI code (arrived or departed) */
139
+ poiCode: string | null
140
+
141
+ /** Mapped event code for TrackingEvent */
142
+ eventCode: string
143
+
144
+ /** Source event ID for deduplication */
145
+ sourceEventId: string
146
+ }
147
+
148
+ // ─── Event ID Mapping ────────────────────────────────────────
149
+
150
+ /**
151
+ * POI event type string used in event IDs.
152
+ * Maps ProximityEventType to the underscore-separated format used in event declarations.
153
+ */
154
+ export type PoiEventTypeString =
155
+ | 'port_arrival'
156
+ | 'port_proximity_arrival'
157
+ | 'port_departure'
158
+ | 'terminal_arrival'
159
+ | 'terminal_proximity_arrival'
160
+ | 'terminal_departure'
161
+ | 'waypoint_reached'
162
+
163
+ /**
164
+ * Map ProximityEventType to the event type string used in event IDs.
165
+ */
166
+ export const PROXIMITY_EVENT_TO_STRING: Record<ProximityEventType, PoiEventTypeString> = {
167
+ PORT_ARRIVAL: 'port_arrival',
168
+ PORT_PROXIMITY_ARRIVAL: 'port_proximity_arrival',
169
+ PORT_PROXIMITY_DEPARTURE: 'port_departure',
170
+ TERMINAL_ARRIVAL: 'terminal_arrival',
171
+ TERMINAL_PROXIMITY_ARRIVAL: 'terminal_proximity_arrival',
172
+ TERMINAL_PROXIMITY_DEPARTURE: 'terminal_departure',
173
+ WAYPOINT_REACHED: 'waypoint_reached',
174
+ }
175
+
176
+ /**
177
+ * Get the per-tracking-job event ID for a POI event type.
178
+ * Used for notifications to avoid duplicates for multi-container bookings.
179
+ *
180
+ * @example
181
+ * getJobPoiEventId('PORT_ARRIVAL') // 'shipment_tracking.tracking_job.poi.port_arrival'
182
+ */
183
+ export function getJobPoiEventId(eventType: ProximityEventType): string {
184
+ const typeString = PROXIMITY_EVENT_TO_STRING[eventType]
185
+ return `shipment_tracking.tracking_job.poi.${typeString}`
186
+ }
187
+
188
+ /**
189
+ * Get the per-shipment event ID for a POI event type.
190
+ * Used for webhooks and external integrations.
191
+ *
192
+ * @example
193
+ * getShipmentPoiEventId('PORT_ARRIVAL') // 'shipment_tracking.poi.port_arrival'
194
+ */
195
+ export function getShipmentPoiEventId(eventType: ProximityEventType): string {
196
+ const typeString = PROXIMITY_EVENT_TO_STRING[eventType]
197
+ return `shipment_tracking.poi.${typeString}`
198
+ }
@@ -0,0 +1,58 @@
1
+ import { logRateLimit } from './logger'
2
+
3
+ export type RateLimitResult = {
4
+ allowed: boolean
5
+ retryAfterSeconds?: number
6
+ }
7
+
8
+ export type CacheService = {
9
+ get(key: string): Promise<string | null>
10
+ set(key: string, value: string, ttlSeconds?: number): Promise<void>
11
+ }
12
+
13
+ /**
14
+ * Token bucket rate limiter using a cache backend.
15
+ *
16
+ * Key: `st:ratelimit:{tenantId}:{carrier}`
17
+ *
18
+ * Stores the current token count and last refill timestamp in the cache.
19
+ * Refills tokens proportionally based on elapsed time.
20
+ */
21
+ export async function checkRateLimit(
22
+ cache: CacheService,
23
+ tenantId: string,
24
+ carrierCode: string,
25
+ maxRequests: number,
26
+ windowSeconds: number,
27
+ ): Promise<RateLimitResult> {
28
+ const key = `st:ratelimit:${tenantId}:${carrierCode}`
29
+ const now = Date.now()
30
+
31
+ const raw = await cache.get(key)
32
+ let tokens = maxRequests
33
+ let lastRefill = now
34
+
35
+ if (raw) {
36
+ try {
37
+ const state = JSON.parse(raw) as { tokens: number; lastRefill: number }
38
+ const elapsed = (now - state.lastRefill) / 1000
39
+ const refilled = Math.floor((elapsed / windowSeconds) * maxRequests)
40
+ tokens = Math.min(maxRequests, state.tokens + refilled)
41
+ lastRefill = refilled > 0 ? now : state.lastRefill
42
+ } catch {
43
+ // Corrupted cache entry, reset
44
+ }
45
+ }
46
+
47
+ if (tokens <= 0) {
48
+ const retryAfterSeconds = Math.ceil(windowSeconds / maxRequests)
49
+ logRateLimit({ carrierCode, tenantId, allowed: false, retryAfterSeconds })
50
+ return { allowed: false, retryAfterSeconds }
51
+ }
52
+
53
+ tokens -= 1
54
+ await cache.set(key, JSON.stringify({ tokens, lastRefill }), windowSeconds * 2)
55
+
56
+ logRateLimit({ carrierCode, tenantId, allowed: true })
57
+ return { allowed: true }
58
+ }
@@ -0,0 +1,439 @@
1
+ /**
2
+ * Route extraction utilities for shipment tracking.
3
+ *
4
+ * Extracts route stops from tracking events for display in the shipment details drawer.
5
+ * This logic is shared between:
6
+ * - TrackingService (when populating denormalized data on shipment)
7
+ * - ShipmentDetailsDrawer (as types reference)
8
+ */
9
+
10
+ // ─── Types ───────────────────────────────────────────────────
11
+
12
+ /**
13
+ * Seal information for a container.
14
+ */
15
+ export interface SealInfo {
16
+ number: string
17
+ source?: string | null // CAR (carrier), SHI (shipper), TER (terminal), CUS (customs)
18
+ type?: string | null
19
+ }
20
+
21
+ /**
22
+ * A stop along the shipment's route (origin, transshipment, or destination).
23
+ * Stored as JSONB on the Shipment entity.
24
+ *
25
+ * Includes facility/terminal details from DCSA events for rich location display.
26
+ */
27
+ export interface RouteStopEntry {
28
+ // Core fields
29
+ location: string // Terminal or port name
30
+ unlocode?: string | null // UN/LOCODE (e.g., "PLGDN")
31
+ // 'transshipment' = cargo changes vessels here; 'port_call' = same vessel calls en route
32
+ type: 'origin' | 'transshipment' | 'port_call' | 'destination'
33
+ vesselName?: string | null // Vessel name for this leg
34
+ vesselImo?: string | null // Vessel IMO number for vessel tracking
35
+
36
+ // Timestamps
37
+ ata?: string | null // Actual arrival - ISO datetime string
38
+ atd?: string | null // Actual departure - ISO datetime string
39
+ eta?: string | null // Estimated arrival - ISO datetime string (for delay calculation)
40
+ etd?: string | null // Estimated departure - ISO datetime string (for delay calculation)
41
+
42
+ // Facility/terminal details (from DCSA events)
43
+ countryCode?: string | null // ISO 3166-1 alpha-2 (e.g., "PL")
44
+ facilityCode?: string | null // SMDG/BIC code (e.g., "DCT")
45
+ facilityCodeListProvider?: 'BIC' | 'SMDG' | null
46
+ facilityTypeCode?: string | null // POTE (port terminal), DEPO (depot), etc.
47
+ facilityAddress?: string | null // Full address string from DCSA otherFacility
48
+ coords?: {
49
+ latitude: number
50
+ longitude: number
51
+ } | null
52
+
53
+ // From BIC enrichment (optional)
54
+ operatorName?: string | null
55
+ }
56
+
57
+ /**
58
+ * A cargo/tracking event entry for a specific container.
59
+ * Stored as JSONB on the Shipment entity.
60
+ *
61
+ * Includes facility details from DCSA events for route extraction.
62
+ */
63
+ export interface CargoEventEntry {
64
+ // Core fields
65
+ id: string
66
+ eventType: string
67
+ eventCode: string
68
+ eventClassifierCode?: 'ACT' | 'PLN' | 'EST' | null
69
+ eventDateTime: string // ISO datetime string
70
+ description?: string | null
71
+
72
+ // Location fields
73
+ locationName?: string | null
74
+ locationUnlocode?: string | null
75
+
76
+ // Human-friendly region names for AIS POI events (localized at render). Null for carrier events.
77
+ regionNamePl?: string | null
78
+ regionNameEn?: string | null
79
+
80
+ // Vessel/voyage fields
81
+ vesselName?: string | null
82
+ vesselImo?: string | null
83
+ voyageNumber?: string | null
84
+ isTransshipmentMove?: boolean | null
85
+
86
+ emptyIndicatorCode?: 'EMPTY' | 'LADEN' | null
87
+
88
+ // Facility/terminal details (from DCSA events)
89
+ facilityCode?: string | null // SMDG/BIC code (e.g., "DCT")
90
+ facilityCodeListProvider?: 'BIC' | 'SMDG' | null
91
+ facilityTypeCode?: string | null // POTE, DEPO, etc.
92
+ facilityAddress?: string | null // Full address string
93
+ latitude?: number | null
94
+ longitude?: number | null
95
+
96
+ // Seal information (from DCSA events)
97
+ seals?: SealInfo[] | null
98
+ }
99
+
100
+ /**
101
+ * Context for route extraction - provides origin/destination hints.
102
+ */
103
+ export interface RouteExtractionContext {
104
+ originUnlocode?: string | null
105
+ destinationUnlocode?: string | null
106
+ }
107
+
108
+ // ─── Route Extraction ────────────────────────────────────────
109
+
110
+ /**
111
+ * AIS POI event codes that are too fine-grained for Route Details and are
112
+ * skipped during route extraction:
113
+ * - WAYR (waypoint reached) — open-water grid codes (e.g. "N051E001-00773"), no real place
114
+ * - TARR / TPRA / TPRD (terminal arrival / proximity arrival / proximity departure)
115
+ *
116
+ * Port-level AIS events (PARR/PPRA/PPRD) and all carrier/DCSA milestones
117
+ * (ARRI/DEPA/GTIN/GTOT/LOAD/DISC, …) are kept — they define the route.
118
+ * Excluded events remain in the Journey Timeline (cargoEvents).
119
+ */
120
+ const ROUTE_DETAIL_EXCLUDED_EVENT_CODES = new Set(['WAYR', 'TARR', 'TPRA', 'TPRD'])
121
+
122
+ // ISO datetime strings are UTC (toISOString), so lexicographic compare == chronological.
123
+ function earliestIso(a?: string | null, b?: string | null): string | null {
124
+ if (!a) return b ?? null
125
+ if (!b) return a
126
+ return a < b ? a : b
127
+ }
128
+ function latestIso(a?: string | null, b?: string | null): string | null {
129
+ if (!a) return b ?? null
130
+ if (!b) return a
131
+ return a > b ? a : b
132
+ }
133
+
134
+ /**
135
+ * Extracts route stops from a list of cargo events.
136
+ *
137
+ * The algorithm:
138
+ * 1. Sorts events chronologically
139
+ * 2. Groups events by location (unlocode or name)
140
+ * 3. Tracks vessels, arrival/departure times, and transshipment indicators
141
+ * 4. Assigns type (origin/transshipment/destination) based on position and context
142
+ *
143
+ * @param events - Array of cargo events (already filtered for specific container)
144
+ * @param context - Optional context with origin/destination hints
145
+ * @returns Array of route stops in chronological order
146
+ */
147
+ export function extractRouteFromEvents(
148
+ events: CargoEventEntry[],
149
+ context?: RouteExtractionContext
150
+ ): RouteStopEntry[] {
151
+ if (!events || events.length === 0) {
152
+ return []
153
+ }
154
+
155
+ // Sort events by datetime
156
+ const sortedEvents = [...events].sort(
157
+ (a, b) => new Date(a.eventDateTime).getTime() - new Date(b.eventDateTime).getTime()
158
+ )
159
+
160
+ // Build location map with timestamps and facility data
161
+ // vessels is a Map of vesselName -> vesselImo (to track IMO alongside name)
162
+ const locationMap = new Map<string, {
163
+ name: string
164
+ unlocode?: string | null
165
+ countryCode?: string | null
166
+ vessels: Map<string, string | null> // vesselName -> vesselImo
167
+ ata?: string
168
+ atd?: string
169
+ eta?: string
170
+ etd?: string
171
+ isTransshipment: boolean
172
+ // Facility data from events
173
+ facilityCode?: string | null
174
+ facilityCodeListProvider?: 'BIC' | 'SMDG' | null
175
+ facilityTypeCode?: string | null
176
+ facilityAddress?: string | null
177
+ coords?: { latitude: number; longitude: number } | null
178
+ }>()
179
+
180
+ for (const event of sortedEvents) {
181
+ // Skip fine-grained AIS POI events (waypoints + terminals) — Route Details
182
+ // shows port-level stops only. See ROUTE_DETAIL_EXCLUDED_EVENT_CODES.
183
+ if (ROUTE_DETAIL_EXCLUDED_EVENT_CODES.has(event.eventCode)) continue
184
+
185
+ const loc = event.locationUnlocode || event.locationName
186
+ if (!loc) continue
187
+
188
+ if (!locationMap.has(loc)) {
189
+ // Extract country code from UN/LOCODE (first 2 chars)
190
+ const countryCode = event.locationUnlocode?.length === 5
191
+ ? event.locationUnlocode.slice(0, 2)
192
+ : null
193
+
194
+ locationMap.set(loc, {
195
+ name: event.locationName || loc,
196
+ unlocode: event.locationUnlocode || null,
197
+ countryCode,
198
+ vessels: new Map<string, string | null>(),
199
+ isTransshipment: false,
200
+ // Initialize facility fields
201
+ facilityCode: null,
202
+ facilityCodeListProvider: null,
203
+ facilityTypeCode: null,
204
+ facilityAddress: null,
205
+ coords: null,
206
+ })
207
+ }
208
+
209
+ const entry = locationMap.get(loc)!
210
+
211
+ // Update facility data if this event has more complete info
212
+ // Prefer events with facility codes over those without
213
+ if (event.facilityCode && !entry.facilityCode) {
214
+ entry.facilityCode = event.facilityCode
215
+ entry.facilityCodeListProvider = event.facilityCodeListProvider || null
216
+ }
217
+ if (event.facilityTypeCode && !entry.facilityTypeCode) {
218
+ entry.facilityTypeCode = event.facilityTypeCode
219
+ }
220
+ if (event.facilityAddress && !entry.facilityAddress) {
221
+ entry.facilityAddress = event.facilityAddress
222
+ }
223
+ if (event.latitude != null && event.longitude != null && !entry.coords) {
224
+ entry.coords = { latitude: event.latitude, longitude: event.longitude }
225
+ }
226
+
227
+ if (event.vesselName) {
228
+ // Store vessel name with its IMO (may be null)
229
+ // If we already have this vessel, only update if the new event has an IMO
230
+ const existingImo = entry.vessels.get(event.vesselName)
231
+ if (!existingImo && event.vesselImo) {
232
+ entry.vessels.set(event.vesselName, event.vesselImo)
233
+ } else if (!entry.vessels.has(event.vesselName)) {
234
+ entry.vessels.set(event.vesselName, event.vesselImo || null)
235
+ }
236
+ }
237
+
238
+ // Track actual arrivals/departures
239
+ // ARRI = vessel arrival at port
240
+ // GTIN = gate-in (container enters terminal via truck/rail - indicates arrival for inland segments)
241
+ // For the first segment (depot to port), GTIN at the port indicates the container arrived there
242
+ if (event.eventCode === 'ARRI' && event.eventClassifierCode === 'ACT') {
243
+ entry.ata = event.eventDateTime
244
+ }
245
+ // Use GTIN as arrival indicator for port terminals when no ARRI event exists
246
+ // This handles the depot-to-port segment where container arrives by truck
247
+ if (event.eventCode === 'GTIN' && event.eventClassifierCode === 'ACT' && !entry.ata) {
248
+ // Only use GTIN as arrival if it's at a port terminal (POTE) or intermodal (INTE)
249
+ if (event.facilityTypeCode === 'POTE' || event.facilityTypeCode === 'INTE') {
250
+ entry.ata = event.eventDateTime
251
+ }
252
+ }
253
+ if (event.eventCode === 'DEPA' && event.eventClassifierCode === 'ACT') {
254
+ entry.atd = event.eventDateTime
255
+ }
256
+ // Use GTOT (gate-out) as departure indicator for depots/terminals
257
+ // This handles the first segment where container departs depot by truck
258
+ if (event.eventCode === 'GTOT' && event.eventClassifierCode === 'ACT' && !entry.atd) {
259
+ entry.atd = event.eventDateTime
260
+ }
261
+
262
+ // AIS port proximity events. Only ports survive into Route Details (waypoints +
263
+ // terminals are filtered out above), so these are the arrival/departure signals for
264
+ // AIS-tracked port calls — without them an AIS-only stop (e.g. a transshipment port
265
+ // not in the DCSA feed) has no ATA/ATD and its segment bars never turn green.
266
+ // Applied only when no carrier (DCSA) timestamp exists, so DCSA ATA/ATD always win.
267
+ // PARR = port arrival, PPRA = port proximity arrival, PPRD = port proximity departure.
268
+ if (
269
+ (event.eventCode === 'PARR' || event.eventCode === 'PPRA') &&
270
+ event.eventClassifierCode === 'ACT' &&
271
+ !entry.ata
272
+ ) {
273
+ entry.ata = event.eventDateTime
274
+ }
275
+ if (event.eventCode === 'PPRD' && event.eventClassifierCode === 'ACT' && !entry.atd) {
276
+ entry.atd = event.eventDateTime
277
+ }
278
+
279
+ // Track estimated/planned arrivals/departures (for delay calculation)
280
+ // Only store the first estimate (original plan) to compare against actual
281
+ if (event.eventCode === 'ARRI' && (event.eventClassifierCode === 'PLN' || event.eventClassifierCode === 'EST')) {
282
+ if (!entry.eta) entry.eta = event.eventDateTime
283
+ }
284
+ if (event.eventCode === 'DEPA' && (event.eventClassifierCode === 'PLN' || event.eventClassifierCode === 'EST')) {
285
+ if (!entry.etd) entry.etd = event.eventDateTime
286
+ }
287
+
288
+ // Mark transshipment if container was discharged and loaded
289
+ if (event.isTransshipmentMove ||
290
+ (event.eventCode === 'DISC' || event.eventCode === 'LOAD')) {
291
+ entry.isTransshipment = true
292
+ }
293
+ }
294
+
295
+ // Convert to route stops
296
+ const stops: RouteStopEntry[] = []
297
+ const locations = Array.from(locationMap.entries())
298
+
299
+ for (let i = 0; i < locations.length; i++) {
300
+ const [key, data] = locations[i]
301
+ const isFirst = i === 0
302
+ const isLast = i === locations.length - 1
303
+
304
+ // Determine type based on position and context.
305
+ // An intermediate stop is a real 'transshipment' only when the cargo actually
306
+ // changed vessels here (isTransshipmentMove / DISC+LOAD); otherwise it's a plain
307
+ // 'port_call' — the same vessel calling en route (e.g. AIS port proximity events).
308
+ let type: 'origin' | 'transshipment' | 'port_call' | 'destination' =
309
+ data.isTransshipment ? 'transshipment' : 'port_call'
310
+
311
+ if (isFirst || key === context?.originUnlocode) {
312
+ type = 'origin'
313
+ } else if (isLast || key === context?.destinationUnlocode) {
314
+ type = 'destination'
315
+ }
316
+
317
+ // Get the last vessel entry (most recent vessel at this stop)
318
+ const vesselEntries = Array.from(data.vessels.entries())
319
+ const lastVessel = vesselEntries.length > 0 ? vesselEntries[vesselEntries.length - 1] : null
320
+ const vesselName = lastVessel ? lastVessel[0] : null
321
+ const vesselImo = lastVessel ? lastVessel[1] : null
322
+
323
+ stops.push({
324
+ location: data.name,
325
+ unlocode: data.unlocode,
326
+ type,
327
+ vesselName,
328
+ vesselImo,
329
+ ata: data.ata || null,
330
+ atd: data.atd || null,
331
+ eta: data.eta || null,
332
+ etd: data.etd || null,
333
+ // Facility details
334
+ countryCode: data.countryCode || null,
335
+ facilityCode: data.facilityCode || null,
336
+ facilityCodeListProvider: data.facilityCodeListProvider || null,
337
+ facilityTypeCode: data.facilityTypeCode || null,
338
+ facilityAddress: data.facilityAddress || null,
339
+ coords: data.coords || null,
340
+ operatorName: null, // Will be populated by BIC enrichment if needed
341
+ })
342
+ }
343
+
344
+ // Collapse consecutive stops at the same place into one port call. AIS port events for a
345
+ // single city can arrive under several POI codes (proximity vs actual arrival, different
346
+ // berths), which would otherwise render as duplicate rows (e.g. two "Le Havre") with split
347
+ // timestamps — breaking segment colors. Merge by location name, keeping the earliest
348
+ // arrival and latest departure so segment status is computed correctly.
349
+ const merged: RouteStopEntry[] = []
350
+ for (const stop of stops) {
351
+ const prev = merged[merged.length - 1]
352
+ if (prev && prev.location === stop.location) {
353
+ prev.ata = earliestIso(prev.ata, stop.ata)
354
+ prev.atd = latestIso(prev.atd, stop.atd)
355
+ prev.eta = earliestIso(prev.eta, stop.eta)
356
+ prev.etd = latestIso(prev.etd, stop.etd)
357
+ prev.vesselName = prev.vesselName ?? stop.vesselName
358
+ prev.vesselImo = prev.vesselImo ?? stop.vesselImo
359
+ // Prefer a real UN/LOCODE over a raw AIS POI grid code
360
+ if (prev.unlocode?.length !== 5 && stop.unlocode?.length === 5) prev.unlocode = stop.unlocode
361
+ prev.countryCode = prev.countryCode ?? stop.countryCode
362
+ prev.facilityCode = prev.facilityCode ?? stop.facilityCode
363
+ prev.facilityCodeListProvider = prev.facilityCodeListProvider ?? stop.facilityCodeListProvider
364
+ prev.facilityTypeCode = prev.facilityTypeCode ?? stop.facilityTypeCode
365
+ prev.facilityAddress = prev.facilityAddress ?? stop.facilityAddress
366
+ prev.coords = prev.coords ?? stop.coords
367
+ // Promote type if a merged member is an endpoint (origin/destination beats transshipment)
368
+ if (stop.type === 'origin') prev.type = 'origin'
369
+ else if (stop.type === 'destination' && prev.type !== 'origin') prev.type = 'destination'
370
+ else if (stop.type === 'transshipment' && prev.type === 'port_call') prev.type = 'transshipment'
371
+ continue
372
+ }
373
+ merged.push({ ...stop })
374
+ }
375
+
376
+ return merged
377
+ }
378
+
379
+ // ─── Event Mapping ───────────────────────────────────────────
380
+
381
+ /**
382
+ * Maps a TrackingEvent entity to a CargoEventEntry for storage.
383
+ *
384
+ * @param event - The tracking event entity
385
+ * @returns A simplified event entry suitable for JSONB storage
386
+ */
387
+ export function mapTrackingEventToEntry(event: {
388
+ id: string
389
+ eventType: string
390
+ eventCode: string
391
+ eventClassifierCode?: string | null
392
+ eventDateTime: Date
393
+ description?: string | null
394
+ locationName?: string | null
395
+ locationUnlocode?: string | null
396
+ regionNamePl?: string | null
397
+ regionNameEn?: string | null
398
+ vesselName?: string | null
399
+ vesselImo?: string | null
400
+ voyageNumber?: string | null
401
+ isTransshipmentMove?: boolean | null
402
+ emptyIndicatorCode?: 'EMPTY' | 'LADEN' | null
403
+ // Facility fields
404
+ facilityCode?: string | null
405
+ facilityCodeListProvider?: 'BIC' | 'SMDG' | null
406
+ facilityTypeCode?: string | null
407
+ facilityAddress?: string | null
408
+ latitude?: number | null
409
+ longitude?: number | null
410
+ // Seal fields
411
+ seals?: SealInfo[] | null
412
+ }): CargoEventEntry {
413
+ return {
414
+ id: event.id,
415
+ eventType: event.eventType,
416
+ eventCode: event.eventCode,
417
+ eventClassifierCode: event.eventClassifierCode as 'ACT' | 'PLN' | 'EST' | null,
418
+ eventDateTime: event.eventDateTime.toISOString(),
419
+ description: event.description || null,
420
+ locationName: event.locationName || null,
421
+ locationUnlocode: event.locationUnlocode || null,
422
+ regionNamePl: event.regionNamePl || null,
423
+ regionNameEn: event.regionNameEn || null,
424
+ vesselName: event.vesselName || null,
425
+ vesselImo: event.vesselImo || null,
426
+ voyageNumber: event.voyageNumber || null,
427
+ isTransshipmentMove: event.isTransshipmentMove ?? null,
428
+ emptyIndicatorCode: event.emptyIndicatorCode ?? null,
429
+ // Facility fields
430
+ facilityCode: event.facilityCode || null,
431
+ facilityCodeListProvider: event.facilityCodeListProvider || null,
432
+ facilityTypeCode: event.facilityTypeCode || null,
433
+ facilityAddress: event.facilityAddress || null,
434
+ latitude: event.latitude ?? null,
435
+ longitude: event.longitude ?? null,
436
+ // Seal fields
437
+ seals: event.seals ?? null,
438
+ }
439
+ }