@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,195 @@
1
+ import { AsyncLocalStorage } from 'node:async_hooks'
2
+ import { trace, SpanStatusCode, type Span } from '@opentelemetry/api'
3
+
4
+ const MODULE_NAME = 'shipment-tracking'
5
+
6
+ // ── Inlined structured logger + tracing ──────────────────────────────
7
+ // Previously provided by `@open-mercato/logger`, which is not published to the
8
+ // public npm registry. Reimplemented locally over `@opentelemetry/api` (already
9
+ // a dependency) and `node:async_hooks` so this package installs from public
10
+ // registries with no private dependency. Behaviour parity: JSON structured
11
+ // logs that carry any active async-local context, and an OTel active span
12
+ // wrapper that records exceptions and always ends the span.
13
+
14
+ type LogContext = Record<string, unknown>
15
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error'
16
+
17
+ const logContext = new AsyncLocalStorage<LogContext>()
18
+
19
+ function emit(level: LogLevel, message: string, fields?: LogContext): void {
20
+ const record: LogContext = {
21
+ level,
22
+ time: new Date().toISOString(),
23
+ message,
24
+ ...logContext.getStore(),
25
+ ...fields,
26
+ }
27
+ const line = JSON.stringify(record)
28
+ if (level === 'error') console.error(line)
29
+ else if (level === 'warn') console.warn(line)
30
+ else console.log(line)
31
+ }
32
+
33
+ const logger = {
34
+ debug: (message: string, fields?: LogContext) => emit('debug', message, fields),
35
+ info: (message: string, fields?: LogContext) => emit('info', message, fields),
36
+ warn: (message: string, fields?: LogContext) => emit('warn', message, fields),
37
+ error: (message: string, fields?: LogContext) => emit('error', message, fields),
38
+ }
39
+
40
+ function runWithLogContext<T>(ctx: LogContext, fn: () => T | Promise<T>): T | Promise<T> {
41
+ return logContext.run({ ...logContext.getStore(), ...ctx }, fn)
42
+ }
43
+
44
+ const tracer = trace.getTracer(MODULE_NAME)
45
+
46
+ function withSpan<T>(
47
+ opts: { name: string; attributes?: Record<string, string | number | boolean | undefined> },
48
+ fn: (span: Span) => Promise<T>,
49
+ ): Promise<T> {
50
+ const attributes = Object.fromEntries(
51
+ Object.entries(opts.attributes ?? {}).filter(([, v]) => v !== undefined),
52
+ ) as Record<string, string | number | boolean>
53
+ return tracer.startActiveSpan(opts.name, { attributes }, async (span) => {
54
+ try {
55
+ return await fn(span)
56
+ } catch (error) {
57
+ span.recordException(error as Error)
58
+ span.setStatus({ code: SpanStatusCode.ERROR })
59
+ throw error
60
+ } finally {
61
+ span.end()
62
+ }
63
+ })
64
+ }
65
+
66
+ // ──────────────────────────────────────────────────────────────────────
67
+
68
+ export type CarrierOperation = 'authenticate' | 'fetchEvents'
69
+
70
+ export interface CarrierApiContext {
71
+ carrierCode: string
72
+ operation: CarrierOperation
73
+ referenceType?: string
74
+ referenceValue?: string
75
+ }
76
+
77
+ export interface CarrierLogContext {
78
+ carrierCode: string
79
+ shipmentId?: string
80
+ trackingJobId?: string
81
+ }
82
+
83
+ /**
84
+ * Run a function with carrier context in logs.
85
+ * All logs within the function will include the carrier context fields.
86
+ */
87
+ export function withCarrierContext<T>(
88
+ ctx: CarrierLogContext,
89
+ fn: () => T | Promise<T>,
90
+ ): T | Promise<T> {
91
+ return runWithLogContext({ module: MODULE_NAME, ...ctx }, fn)
92
+ }
93
+
94
+ /**
95
+ * Run a carrier API call with OpenTelemetry span and structured logging.
96
+ *
97
+ * Creates a span named `carrier.{carrierCode}.{operation}` with relevant attributes.
98
+ * Logs debug on start, info on success, error on failure.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const events = await withCarrierApiSpan(
103
+ * { carrierCode: 'maersk', operation: 'fetchEvents', referenceType: 'container' },
104
+ * async (span) => {
105
+ * const response = await fetch(url, options)
106
+ * span.setAttribute('http.status_code', response.status)
107
+ * return response.json()
108
+ * }
109
+ * )
110
+ * ```
111
+ */
112
+ export async function withCarrierApiSpan<T>(
113
+ ctx: CarrierApiContext,
114
+ fn: (span: Span) => Promise<T>,
115
+ ): Promise<T> {
116
+ const spanName = `carrier.${ctx.carrierCode}.${ctx.operation}`
117
+
118
+ logger.debug(`Starting ${ctx.operation}`, {
119
+ module: MODULE_NAME,
120
+ carrierCode: ctx.carrierCode,
121
+ operation: ctx.operation,
122
+ referenceType: ctx.referenceType,
123
+ })
124
+
125
+ const startMs = Date.now()
126
+
127
+ return withSpan(
128
+ {
129
+ name: spanName,
130
+ attributes: {
131
+ 'carrier.code': ctx.carrierCode,
132
+ 'carrier.operation': ctx.operation,
133
+ module: MODULE_NAME,
134
+ ...(ctx.referenceType && { 'tracking.reference_type': ctx.referenceType }),
135
+ },
136
+ },
137
+ async (span) => {
138
+ try {
139
+ const result = await fn(span)
140
+ const durationMs = Date.now() - startMs
141
+
142
+ logger.info(`Completed ${ctx.operation}`, {
143
+ module: MODULE_NAME,
144
+ carrierCode: ctx.carrierCode,
145
+ operation: ctx.operation,
146
+ durationMs,
147
+ success: true,
148
+ })
149
+
150
+ span.setAttribute('duration_ms', durationMs)
151
+ return result
152
+ } catch (error) {
153
+ const durationMs = Date.now() - startMs
154
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
155
+
156
+ logger.error(`Failed ${ctx.operation}`, {
157
+ module: MODULE_NAME,
158
+ carrierCode: ctx.carrierCode,
159
+ operation: ctx.operation,
160
+ durationMs,
161
+ success: false,
162
+ error: errorMessage,
163
+ })
164
+
165
+ span.setAttribute('duration_ms', durationMs)
166
+ throw error
167
+ }
168
+ },
169
+ )
170
+ }
171
+
172
+ /**
173
+ * Log rate limit events with structured fields.
174
+ */
175
+ export function logRateLimit(ctx: {
176
+ carrierCode: string
177
+ tenantId: string
178
+ allowed: boolean
179
+ retryAfterSeconds?: number
180
+ }): void {
181
+ const level = ctx.allowed ? 'debug' : 'info'
182
+ logger[level]('Rate limit check', {
183
+ module: MODULE_NAME,
184
+ carrierCode: ctx.carrierCode,
185
+ tenantId: ctx.tenantId,
186
+ allowed: ctx.allowed,
187
+ retryAfterSeconds: ctx.retryAfterSeconds,
188
+ })
189
+ }
190
+
191
+ /**
192
+ * The shipment tracking logger instance.
193
+ * Use this for general logging within the shipment-tracking module.
194
+ */
195
+ export const trackingLogger = logger
@@ -0,0 +1,302 @@
1
+ /**
2
+ * POI Event Processor
3
+ *
4
+ * Processes POI proximity events from AIS system and matches them
5
+ * to tracked shipments for notification and event creation.
6
+ */
7
+
8
+ import type { EntityManager } from '@mikro-orm/postgresql'
9
+ import { Shipment, TrackingEvent, TrackingJob } from '../data/entities'
10
+ import type { PoiProximityEvent, ProcessedPoiEvent, ProximityEventType } from './poi-types'
11
+ import { PROXIMITY_EVENT_CODES } from './poi-types'
12
+ import { trackingLogger } from './logger'
13
+
14
+ const LOG_COMPONENT = 'poi-processor'
15
+
16
+ // ─── Shipment Matching ───────────────────────────────────────
17
+
18
+ /**
19
+ * Find active shipments that match the given vessel IMO.
20
+ *
21
+ * A shipment matches if:
22
+ * - It has the same vesselImo
23
+ * - It's active (not deleted, not delivered)
24
+ * - It has an associated tracking job (tracking is enabled)
25
+ */
26
+ export async function findShipmentsByVesselImo(
27
+ em: EntityManager,
28
+ vesselImo: string
29
+ ): Promise<Shipment[]> {
30
+ return em.find(Shipment, {
31
+ vesselImo,
32
+ isActive: true,
33
+ deletedAt: null,
34
+ status: { $nin: ['DELIVERED'] },
35
+ trackingJob: { $ne: null },
36
+ })
37
+ }
38
+
39
+ // ─── Event Processing ────────────────────────────────────────
40
+
41
+ /**
42
+ * Generate a deterministic source event ID for deduplication.
43
+ *
44
+ * Must be stable across redeliveries (nak / max_deliver retries / consumer replay),
45
+ * so it derives only from payload fields — never the wall clock. Arrival/departure
46
+ * events anchor on ata/atd; timeless events (e.g. WAYPOINT_REACHED) anchor on the POI code.
47
+ *
48
+ * Caveat: two distinct position-update batches that emit the same type + sequenceOrder
49
+ * for the same vessel with no ata/atd and no POI code collapse to one event. Acceptable
50
+ * for waypoints; revisit with a producer-supplied event id or JetStream msg.seq if real
51
+ * duplicates surface.
52
+ */
53
+ export function generateSourceEventId(event: PoiProximityEvent): string {
54
+ const anchor = event.ata || event.atd || getPoiCode(event) || 'unknown'
55
+ return `poi-${event.mmsi}-${event.type}-${anchor}-${event.sequenceOrder}`
56
+ }
57
+
58
+ /**
59
+ * Extract event datetime from POI event.
60
+ */
61
+ export function extractEventDateTime(event: PoiProximityEvent): Date {
62
+ if (event.ata) {
63
+ return new Date(event.ata)
64
+ }
65
+ if (event.atd) {
66
+ return new Date(event.atd)
67
+ }
68
+ return new Date()
69
+ }
70
+
71
+ /**
72
+ * Get POI code from event (arrival or departure).
73
+ */
74
+ export function getPoiCode(event: PoiProximityEvent): string | null {
75
+ return event.arrivedPoiCode || event.departedPoiCode || null
76
+ }
77
+
78
+ /**
79
+ * Resolve the human-friendly location name for a POI event, following the producer's
80
+ * per-type identity fallback:
81
+ * - terminal events → terminalName → portName → city
82
+ * - port events → city → portName
83
+ * - waypoint events → null (no port/terminal/city; the localized region name is used instead,
84
+ * stored separately in regionNamePl/regionNameEn and chosen at render time)
85
+ *
86
+ * Returns null when nothing usable is present, so callers fall back to the raw POI code.
87
+ */
88
+ export function resolvePoiLocationName(event: PoiProximityEvent): string | null {
89
+ if (event.type.startsWith('TERMINAL')) {
90
+ return event.terminalName || event.portName || event.city || null
91
+ }
92
+ if (event.type.startsWith('PORT')) {
93
+ return event.city || event.portName || null
94
+ }
95
+ return null
96
+ }
97
+
98
+ /**
99
+ * Map POI event type to Open Mercato event ID.
100
+ */
101
+ export function mapToOpenMercatoEventId(type: ProximityEventType): string {
102
+ const eventMap: Record<ProximityEventType, string> = {
103
+ PORT_ARRIVAL: 'shipment_tracking.poi.port_arrival',
104
+ PORT_PROXIMITY_ARRIVAL: 'shipment_tracking.poi.port_proximity_arrival',
105
+ PORT_PROXIMITY_DEPARTURE: 'shipment_tracking.poi.port_departure',
106
+ TERMINAL_ARRIVAL: 'shipment_tracking.poi.terminal_arrival',
107
+ TERMINAL_PROXIMITY_ARRIVAL: 'shipment_tracking.poi.terminal_proximity_arrival',
108
+ TERMINAL_PROXIMITY_DEPARTURE: 'shipment_tracking.poi.terminal_departure',
109
+ WAYPOINT_REACHED: 'shipment_tracking.poi.waypoint_reached',
110
+ }
111
+ return eventMap[type]
112
+ }
113
+
114
+ /**
115
+ * Process a POI event and match it to shipments.
116
+ *
117
+ * @param em - Entity manager
118
+ * @param event - Raw POI proximity event from NATS
119
+ * @returns Processed event with matched shipments, or null if no matches
120
+ */
121
+ export async function processPoiEvent(
122
+ em: EntityManager,
123
+ event: PoiProximityEvent
124
+ ): Promise<ProcessedPoiEvent | null> {
125
+ // The AIS detector sets `shipId` from `ship.id`, which is the vessel IMO.
126
+ // Match directly against the IMO we already store on the shipment — no lookup needed.
127
+ const vesselImo = String(event.shipId)
128
+ const shipments = await findShipmentsByVesselImo(em, vesselImo)
129
+
130
+ if (shipments.length === 0) {
131
+ trackingLogger.debug('No active shipments found for vessel IMO', {
132
+ component: LOG_COMPONENT,
133
+ mmsi: event.mmsi,
134
+ vesselImo,
135
+ eventType: event.type,
136
+ })
137
+ return null
138
+ }
139
+
140
+ return {
141
+ poiEvent: event,
142
+ vesselImo,
143
+ shipmentIds: shipments.map((s) => s.id),
144
+ eventDateTime: extractEventDateTime(event),
145
+ poiCode: getPoiCode(event),
146
+ eventCode: PROXIMITY_EVENT_CODES[event.type],
147
+ sourceEventId: generateSourceEventId(event),
148
+ }
149
+ }
150
+
151
+ // ─── TrackingEvent Creation ──────────────────────────────────
152
+
153
+ /**
154
+ * Check if a POI event has already been processed (deduplication).
155
+ */
156
+ export async function isEventAlreadyProcessed(
157
+ em: EntityManager,
158
+ trackingJobId: string,
159
+ sourceEventId: string
160
+ ): Promise<boolean> {
161
+ const existing = await em.findOne(TrackingEvent, {
162
+ trackingJob: trackingJobId,
163
+ source: 'ais',
164
+ sourceEventId,
165
+ })
166
+ return existing !== null
167
+ }
168
+
169
+ /**
170
+ * Create a TrackingEvent record from a processed POI event.
171
+ */
172
+ export function createTrackingEventFromPoi(
173
+ processedEvent: ProcessedPoiEvent,
174
+ trackingJob: TrackingJob
175
+ ): TrackingEvent {
176
+ const { poiEvent, eventDateTime, eventCode, sourceEventId, poiCode, vesselImo } = processedEvent
177
+
178
+ const event = new TrackingEvent()
179
+ event.organizationId = trackingJob.organizationId
180
+ event.tenantId = trackingJob.tenantId
181
+ event.trackingJob = trackingJob
182
+ event.source = 'ais'
183
+ event.sourceEventId = sourceEventId
184
+ event.eventType = 'TRANSPORT'
185
+ event.eventCode = eventCode
186
+ event.eventClassifierCode = 'ACT' // Actual event
187
+ event.eventDateTime = eventDateTime
188
+ event.description = null // Labels resolved via i18n: event_codes.<CODE>
189
+ event.latitude = poiEvent.lat
190
+ event.longitude = poiEvent.lng
191
+ event.vesselName = poiEvent.shipName
192
+ // The POI producer sets shipId to the vessel IMO (that's how we matched the shipment),
193
+ // so persist it — route legs/maps need the IMO, not just the name.
194
+ event.vesselImo = vesselImo
195
+ event.locationUnlocode = poiCode // raw POI code (grid/LOCODE), kept as the dedup reference
196
+ // Friendly port/terminal name (null for waypoints, which use the localized region name below).
197
+ // Populating locationName also gives route extraction a real name instead of the grid code.
198
+ event.locationName = resolvePoiLocationName(poiEvent)
199
+ event.regionNamePl = poiEvent.regionNamePl ?? null
200
+ event.regionNameEn = poiEvent.regionNameEn ?? null
201
+
202
+ // Store raw event data for debugging
203
+ event.rawData = {
204
+ poiEventType: poiEvent.type,
205
+ mmsi: poiEvent.mmsi,
206
+ shipId: poiEvent.shipId,
207
+ arrivedPoiCode: poiEvent.arrivedPoiCode,
208
+ departedPoiCode: poiEvent.departedPoiCode,
209
+ distanceToPoiMeters: poiEvent.distanceToPoiMeters,
210
+ sequenceOrder: poiEvent.sequenceOrder,
211
+ // POI identity fields without dedicated columns — kept here for debugging. The resolved
212
+ // name lands in locationName; region names have their own columns.
213
+ portName: poiEvent.portName,
214
+ terminalName: poiEvent.terminalName,
215
+ city: poiEvent.city,
216
+ }
217
+
218
+ return event
219
+ }
220
+
221
+ // ─── Batch Processing ────────────────────────────────────────
222
+
223
+ export type PoiProcessingResult = {
224
+ processed: number
225
+ matched: number
226
+ eventsCreated: number
227
+ errors: number
228
+ }
229
+
230
+ /**
231
+ * Process a batch of POI events.
232
+ */
233
+ export async function processPoiEventBatch(
234
+ em: EntityManager,
235
+ events: PoiProximityEvent[]
236
+ ): Promise<PoiProcessingResult> {
237
+ const result: PoiProcessingResult = {
238
+ processed: 0,
239
+ matched: 0,
240
+ eventsCreated: 0,
241
+ errors: 0,
242
+ }
243
+
244
+ for (const event of events) {
245
+ result.processed++
246
+
247
+ try {
248
+ const processed = await processPoiEvent(em, event)
249
+
250
+ if (!processed) {
251
+ continue
252
+ }
253
+
254
+ result.matched++
255
+
256
+ // For each matched shipment, check if we need to create events
257
+ for (const shipmentId of processed.shipmentIds) {
258
+ const shipment = await em.findOne(Shipment, { id: shipmentId }, { populate: ['trackingJob'] })
259
+
260
+ if (!shipment?.trackingJob) {
261
+ continue
262
+ }
263
+
264
+ // Check for duplicates
265
+ const alreadyProcessed = await isEventAlreadyProcessed(
266
+ em,
267
+ shipment.trackingJob.id,
268
+ processed.sourceEventId
269
+ )
270
+
271
+ if (alreadyProcessed) {
272
+ trackingLogger.debug('Event already processed', {
273
+ component: LOG_COMPONENT,
274
+ sourceEventId: processed.sourceEventId,
275
+ trackingJobId: shipment.trackingJob.id,
276
+ })
277
+ continue
278
+ }
279
+
280
+ // Create TrackingEvent
281
+ const trackingEvent = createTrackingEventFromPoi(processed, shipment.trackingJob)
282
+ em.persist(trackingEvent)
283
+ result.eventsCreated++
284
+ }
285
+ } catch (error) {
286
+ trackingLogger.error('Error processing POI event', {
287
+ component: LOG_COMPONENT,
288
+ mmsi: event.mmsi,
289
+ eventType: event.type,
290
+ error: error instanceof Error ? error.message : String(error),
291
+ stack: error instanceof Error ? error.stack : undefined,
292
+ })
293
+ result.errors++
294
+ }
295
+ }
296
+
297
+ if (result.eventsCreated > 0) {
298
+ await em.flush()
299
+ }
300
+
301
+ return result
302
+ }
@@ -0,0 +1,134 @@
1
+ /**
2
+ * NATS Configuration for POI Proximity Events
3
+ *
4
+ * Configuration for connecting to NATS server and subscribing to
5
+ * POI proximity events from the AIS system.
6
+ */
7
+
8
+ import { createHash, randomUUID } from 'crypto'
9
+
10
+ // ─── Configuration Interface ─────────────────────────────────
11
+
12
+ export interface PoiNatsConfig {
13
+ /** NATS server URL (e.g., nats://localhost:4222) */
14
+ serverUrl: string
15
+
16
+ /** JetStream stream name containing POI events */
17
+ streamName: string
18
+
19
+ /** NATS subject for POI proximity events (filter within stream) */
20
+ subject: string
21
+
22
+ /** Unique instance identifier (derived from JWT_SECRET or explicit) */
23
+ instanceId: string
24
+
25
+ /** Durable consumer name for reliable message delivery (includes instanceId) */
26
+ consumerName: string
27
+
28
+ /** Connection name for debugging */
29
+ connectionName: string
30
+
31
+ /** Reconnect settings */
32
+ reconnect: {
33
+ /** Maximum reconnect attempts (-1 for infinite) */
34
+ maxAttempts: number
35
+ /** Initial delay between reconnects in ms */
36
+ initialDelayMs: number
37
+ /** Maximum delay between reconnects in ms */
38
+ maxDelayMs: number
39
+ }
40
+ }
41
+
42
+ // ─── Instance ID Generation ──────────────────────────────────
43
+
44
+ /**
45
+ * Generate a unique instance ID for this deployment.
46
+ *
47
+ * Priority:
48
+ * 1. POI_NATS_INSTANCE_ID env var (explicit override)
49
+ * 2. Hash of JWT_SECRET (stable, unique per installation)
50
+ * 3. Random UUID prefix (fallback for dev/testing)
51
+ */
52
+ function generateInstanceId(): string {
53
+ // 1. Explicit override
54
+ if (process.env.POI_NATS_INSTANCE_ID) {
55
+ return process.env.POI_NATS_INSTANCE_ID
56
+ }
57
+
58
+ // 2. Derive from JWT_SECRET (stable across restarts)
59
+ const jwtSecret = process.env.JWT_SECRET
60
+ if (jwtSecret) {
61
+ const hash = createHash('sha256').update(jwtSecret).digest('hex')
62
+ return hash.substring(0, 8)
63
+ }
64
+
65
+ // 3. Fallback to random (dev/testing only)
66
+ console.warn('[poi-nats] JWT_SECRET not set, using random instance ID (not stable across restarts)')
67
+ return randomUUID().split('-')[0]
68
+ }
69
+
70
+ // ─── Default Configuration ───────────────────────────────────
71
+
72
+ const DEFAULT_RECONNECT = {
73
+ maxAttempts: -1, // Infinite reconnect
74
+ initialDelayMs: 250,
75
+ maxDelayMs: 5000,
76
+ }
77
+
78
+ // ─── Configuration Loader ────────────────────────────────────
79
+
80
+ /**
81
+ * Load POI NATS configuration from environment variables.
82
+ *
83
+ * Environment variables:
84
+ * - POI_NATS_URL: NATS server URL (required to enable)
85
+ * - POI_NATS_STREAM: JetStream stream name (default: AIS_STREAM)
86
+ * - POI_NATS_SUBJECT: Subject filter for POI events (default: ais.ship.proximity.events)
87
+ * - POI_NATS_INSTANCE_ID: Unique instance identifier (default: derived from JWT_SECRET)
88
+ *
89
+ * The consumer name is auto-generated as: shipment-tracking-poi-{instanceId}
90
+ * This allows multiple self-hosted instances to each receive all messages independently.
91
+ */
92
+ export function loadPoiNatsConfig(): PoiNatsConfig {
93
+ const instanceId = generateInstanceId()
94
+ const consumerName = `shipment-tracking-poi-${instanceId}`
95
+
96
+ return {
97
+ serverUrl: process.env.POI_NATS_URL || 'nats://localhost:4222',
98
+ streamName: process.env.POI_NATS_STREAM || 'AIS_STREAM',
99
+ subject: process.env.POI_NATS_SUBJECT || 'ais.ship.proximity.events',
100
+ instanceId,
101
+ consumerName,
102
+ connectionName: `shipment-tracking-poi-${instanceId}`,
103
+ reconnect: DEFAULT_RECONNECT,
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Check if POI NATS integration is configured.
109
+ *
110
+ * Returns true only if POI_NATS_URL is explicitly set.
111
+ * When not configured, the POI subscriber will be skipped.
112
+ */
113
+ export function isPoiNatsConfigured(): boolean {
114
+ return !!process.env.POI_NATS_URL
115
+ }
116
+
117
+ /**
118
+ * Validate POI NATS configuration.
119
+ *
120
+ * @throws Error if configuration is invalid
121
+ */
122
+ export function validatePoiNatsConfig(config: PoiNatsConfig): void {
123
+ if (!config.serverUrl) {
124
+ throw new Error('POI_NATS_URL is required')
125
+ }
126
+
127
+ if (!config.serverUrl.startsWith('nats://') && !config.serverUrl.startsWith('nats+tls://')) {
128
+ throw new Error('POI_NATS_URL must start with nats:// or nats+tls://')
129
+ }
130
+
131
+ if (!config.subject) {
132
+ throw new Error('POI_NATS_SUBJECT is required')
133
+ }
134
+ }