@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,347 @@
1
+ import type { EntityManager } from '@mikro-orm/postgresql'
2
+ import type { EventBus } from '@open-mercato/events'
3
+ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
4
+ import { Shipment, TrackingEvent, TrackingJob, Webhook, WebhookDelivery } from '../data/entities'
5
+ import { dispatchWebhook } from '../lib/webhook-dispatcher'
6
+ import { sleep } from '../lib/background'
7
+
8
+ type WebhookServiceDeps = {
9
+ em: () => EntityManager
10
+ eventBus: EventBus
11
+ }
12
+
13
+ const RETRY_DELAYS_MS = [5_000, 30_000, 120_000] // 5s, 30s, 2min
14
+ const MAX_RETRIES = 3
15
+
16
+ /**
17
+ * Builds a full shipment payload including tracking events for webhook dispatch.
18
+ * Includes all DCSA T&T v3.0 fields.
19
+ * Timestamps are provided as multi-source arrays; consumers compute primary via "latest updatedAt wins".
20
+ */
21
+ function buildShipmentPayload(shipment: Shipment, trackingEvents: TrackingEvent[]): Record<string, unknown> {
22
+ // Get current location from latest tracking event (derived at query time)
23
+ const latestEvent = trackingEvents.length > 0 ? trackingEvents[trackingEvents.length - 1] : null
24
+
25
+ return {
26
+ id: shipment.id,
27
+ status: shipment.status,
28
+ carrierCode: shipment.carrierCode,
29
+ containerNumber: shipment.containerNumber,
30
+ isoEquipmentCode: shipment.isoEquipmentCode,
31
+ bookingNumber: shipment.bookingNumber,
32
+ bolNumber: shipment.bolNumber,
33
+ // Multi-source timestamp arrays (consumers compute primary via "latest updatedAt wins")
34
+ etdTimestamps: shipment.etdTimestamps,
35
+ etaTimestamps: shipment.etaTimestamps,
36
+ atdTimestamps: shipment.atdTimestamps,
37
+ ataTimestamps: shipment.ataTimestamps,
38
+ // Origin/destination (rich JSONB location data)
39
+ originLocation: shipment.originLocation,
40
+ destinationLocation: shipment.destinationLocation,
41
+ // Current location derived from latest event
42
+ currentLocationName: latestEvent?.locationName ?? null,
43
+ currentLocationUnlocode: latestEvent?.locationUnlocode ?? null,
44
+ // Vessel info
45
+ vesselName: shipment.vesselName,
46
+ vesselImo: shipment.vesselImo,
47
+ voyageNumber: shipment.voyageNumber,
48
+ eventCount: shipment.eventCount,
49
+ lastEventAt: shipment.lastEventAt?.toISOString() ?? null,
50
+ extra: shipment.extra,
51
+ createdAt: shipment.createdAt?.toISOString() ?? null,
52
+ updatedAt: shipment.updatedAt?.toISOString() ?? null,
53
+ trackingEvents: trackingEvents.map((event) => ({
54
+ // Event source
55
+ id: event.id,
56
+ source: event.source,
57
+ sourceEventId: event.sourceEventId,
58
+
59
+ // Core event fields
60
+ eventType: event.eventType,
61
+ eventCode: event.eventCode,
62
+ eventClassifierCode: event.eventClassifierCode,
63
+ eventDateTime: event.eventDateTime?.toISOString() ?? null,
64
+ eventDateTimeOffset: event.eventDateTimeOffset,
65
+ description: event.description,
66
+
67
+ // Equipment fields (DCSA EQUIPMENT events)
68
+ equipmentReference: event.equipmentReference,
69
+ isoEquipmentCode: event.isoEquipmentCode,
70
+ emptyIndicatorCode: event.emptyIndicatorCode,
71
+ isTransshipmentMove: event.isTransshipmentMove,
72
+
73
+ // Location fields
74
+ locationName: event.locationName,
75
+ locationUnlocode: event.locationUnlocode,
76
+ locationCountry: event.locationCountry,
77
+ facilityCode: event.facilityCode,
78
+ facilityCodeListProvider: event.facilityCodeListProvider,
79
+ facilityTypeCode: event.facilityTypeCode,
80
+ latitude: event.latitude,
81
+ longitude: event.longitude,
82
+
83
+ // Transport call fields
84
+ transportCallReference: event.transportCallReference,
85
+ modeOfTransport: event.modeOfTransport,
86
+ vesselName: event.vesselName,
87
+ vesselImo: event.vesselImo,
88
+ voyageNumber: event.voyageNumber,
89
+ carrierServiceCode: event.carrierServiceCode,
90
+ carrierExportVoyageNumber: event.carrierExportVoyageNumber,
91
+ carrierImportVoyageNumber: event.carrierImportVoyageNumber,
92
+ universalServiceReference: event.universalServiceReference,
93
+ universalExportVoyageReference: event.universalExportVoyageReference,
94
+ universalImportVoyageReference: event.universalImportVoyageReference,
95
+ portVisitReference: event.portVisitReference,
96
+
97
+ // Document references
98
+ relatedDocumentReferences: event.relatedDocumentReferences,
99
+
100
+ // Metadata fields
101
+ eventCreatedDateTime: event.eventCreatedDateTime?.toISOString() ?? null,
102
+ retractedEventId: event.retractedEventId,
103
+ publisherName: event.publisherName,
104
+ publisherRole: event.publisherRole,
105
+
106
+ // Additional fields
107
+ delayReasonCode: event.delayReasonCode,
108
+ changeRemark: event.changeRemark,
109
+ seals: event.seals,
110
+
111
+ // Timestamps
112
+ createdAt: event.createdAt?.toISOString() ?? null,
113
+ })),
114
+ }
115
+ }
116
+
117
+ /**
118
+ * WebhookService handles finding matching webhooks and dispatching them
119
+ * with full shipment data and retry logic.
120
+ */
121
+ export class WebhookService {
122
+ private deps: WebhookServiceDeps
123
+
124
+ constructor(deps: WebhookServiceDeps) {
125
+ this.deps = deps
126
+ }
127
+
128
+ /**
129
+ * Builds the full shipment payload including tracking events.
130
+ * Events are fetched from the TrackingJob associated with the shipment.
131
+ */
132
+ async buildFullShipmentPayload(shipmentId: string): Promise<Record<string, unknown> | null> {
133
+ const em = this.deps.em()
134
+
135
+ const shipment = await em.findOne(Shipment, { id: shipmentId, deletedAt: null }, { populate: ['trackingJob'] })
136
+ if (!shipment) {
137
+ return null
138
+ }
139
+
140
+ // If shipment has a tracking job, get events filtered for this container
141
+ let trackingEvents: TrackingEvent[] = []
142
+ if (shipment.trackingJob) {
143
+ const allEvents = await em.find(
144
+ TrackingEvent,
145
+ { trackingJob: shipment.trackingJob },
146
+ { orderBy: { eventDateTime: 'asc' } },
147
+ )
148
+ // Filter events for this specific container
149
+ // Include TRANSPORT events (no equipmentReference) and EQUIPMENT events matching this container
150
+ trackingEvents = allEvents.filter((event) => {
151
+ if (event.eventType === 'TRANSPORT') return true
152
+ if (event.eventType === 'EQUIPMENT') {
153
+ return event.equipmentReference === shipment.containerNumber
154
+ }
155
+ return false
156
+ })
157
+ }
158
+
159
+ return buildShipmentPayload(shipment, trackingEvents)
160
+ }
161
+
162
+ /**
163
+ * Dispatches webhooks for a shipment event with full data and retry logic.
164
+ *
165
+ * @param input.eventType - The event type (e.g., 'shipment.created', 'shipment.tracking_update')
166
+ * @param input.shipmentPayload - Full shipment data including cargo events
167
+ * @param input.tenantId - Tenant ID for finding matching webhooks
168
+ * @param input.organizationId - Organization ID for finding matching webhooks
169
+ * @returns Number of webhooks successfully dispatched
170
+ */
171
+ async dispatchWithRetry(input: {
172
+ eventType: string
173
+ shipmentPayload: Record<string, unknown>
174
+ tenantId: string
175
+ organizationId: string
176
+ }): Promise<{ success: boolean; dispatched: number; failed: number }> {
177
+ const em = this.deps.em()
178
+
179
+ // Find matching webhooks
180
+ const webhooks = await findWithDecryption(
181
+ em,
182
+ Webhook,
183
+ {
184
+ tenantId: input.tenantId,
185
+ organizationId: input.organizationId,
186
+ isActive: true,
187
+ },
188
+ undefined,
189
+ { tenantId: input.tenantId, organizationId: input.organizationId },
190
+ )
191
+
192
+ // Filter to webhooks subscribed to this event type
193
+ const matching = webhooks.filter((webhook) => {
194
+ return webhook.eventsSubscribed.some((pattern) => {
195
+ // Exact match
196
+ if (pattern === input.eventType) return true
197
+ // Global wildcard
198
+ if (pattern === '*') return true
199
+ // Module wildcard (e.g., 'shipment_tracking.*' matches 'shipment_tracking.shipment.created')
200
+ if (pattern.endsWith('.*')) {
201
+ const prefix = pattern.slice(0, -2)
202
+ if (input.eventType.startsWith(prefix + '.')) return true
203
+ }
204
+ // Entity wildcard (e.g., 'shipment_tracking.shipment.*' matches 'shipment_tracking.shipment.created')
205
+ if (pattern.endsWith('.*')) {
206
+ const prefix = pattern.slice(0, -1)
207
+ if (input.eventType.startsWith(prefix)) return true
208
+ }
209
+ return false
210
+ })
211
+ })
212
+
213
+ if (matching.length === 0) {
214
+ console.debug('[shipment-tracking:webhook] No matching webhooks found for event:', input.eventType, {
215
+ totalWebhooks: webhooks.length,
216
+ webhookPatterns: webhooks.map((w) => w.eventsSubscribed),
217
+ })
218
+ return { success: true, dispatched: 0, failed: 0 }
219
+ }
220
+
221
+ console.log('[shipment-tracking:webhook] Dispatching to', matching.length, 'webhooks for event:', input.eventType)
222
+
223
+ let dispatched = 0
224
+ let failed = 0
225
+
226
+ const fullPayload = {
227
+ type: input.eventType,
228
+ timestamp: new Date().toISOString(),
229
+ ...input.shipmentPayload,
230
+ }
231
+
232
+ for (const webhook of matching) {
233
+ const result = await this.dispatchSingleWebhook(em, webhook, fullPayload, input.eventType)
234
+ if (result.success) {
235
+ dispatched++
236
+ } else {
237
+ failed++
238
+ }
239
+ }
240
+
241
+ return {
242
+ success: failed === 0,
243
+ dispatched,
244
+ failed,
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Dispatches a single webhook with retry logic.
250
+ * Records delivery attempts in the WebhookDelivery table for audit.
251
+ */
252
+ private async dispatchSingleWebhook(
253
+ em: EntityManager,
254
+ webhook: Webhook,
255
+ payload: Record<string, unknown>,
256
+ eventType: string,
257
+ ): Promise<{ success: boolean }> {
258
+ // Create delivery record for audit
259
+ // Use getReference to create a managed reference since webhook may be detached after decryption
260
+ const delivery = em.create(WebhookDelivery, {
261
+ webhook: em.getReference(Webhook, webhook.id),
262
+ eventType,
263
+ status: 'pending',
264
+ payload,
265
+ retryCount: 0,
266
+ })
267
+ em.persist(delivery)
268
+ await em.flush()
269
+
270
+ let lastResult: Awaited<ReturnType<typeof dispatchWebhook>> | null = null
271
+
272
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
273
+ lastResult = await dispatchWebhook({
274
+ url: webhook.url,
275
+ payload,
276
+ hmacSecret: webhook.hmacSecret,
277
+ })
278
+
279
+ if (lastResult.success) {
280
+ // Success - update delivery record
281
+ delivery.status = 'success'
282
+ delivery.responseStatus = lastResult.responseStatus ?? null
283
+ delivery.responseBody = lastResult.responseBody ?? null
284
+ delivery.retryCount = attempt
285
+ await em.flush()
286
+
287
+ // Emit success event for monitoring
288
+ await this.deps.eventBus.emit('shipment_tracking.webhook.delivery_success', {
289
+ deliveryId: delivery.id,
290
+ webhookId: webhook.id,
291
+ eventType,
292
+ responseStatus: lastResult.responseStatus,
293
+ })
294
+
295
+ return { success: true }
296
+ }
297
+
298
+ // Failed - update delivery record with error
299
+ delivery.responseStatus = lastResult.responseStatus ?? null
300
+ delivery.responseBody = lastResult.responseBody ?? null
301
+ delivery.errorMessage = lastResult.errorMessage ?? null
302
+ delivery.retryCount = attempt + 1
303
+
304
+ if (attempt < MAX_RETRIES) {
305
+ // Wait before retry
306
+ const delayMs = RETRY_DELAYS_MS[attempt] ?? RETRY_DELAYS_MS[RETRY_DELAYS_MS.length - 1]
307
+ await sleep(delayMs)
308
+ }
309
+ }
310
+
311
+ // All retries exhausted
312
+ delivery.status = 'failed'
313
+ await em.flush()
314
+
315
+ // Emit failure event for monitoring
316
+ await this.deps.eventBus.emit('shipment_tracking.webhook.delivery_failed', {
317
+ deliveryId: delivery.id,
318
+ webhookId: webhook.id,
319
+ eventType,
320
+ retryCount: delivery.retryCount,
321
+ lastError: lastResult?.errorMessage ?? 'Unknown error',
322
+ })
323
+
324
+ return { success: false }
325
+ }
326
+
327
+ /**
328
+ * Legacy method for backwards compatibility with existing subscribers.
329
+ * Finds matching webhooks and dispatches them (used by kept subscribers).
330
+ *
331
+ * @deprecated Use dispatchWithRetry() for new code
332
+ */
333
+ async dispatchEvent(input: {
334
+ eventType: string
335
+ payload: Record<string, unknown>
336
+ tenantId: string
337
+ organizationId: string
338
+ }): Promise<number> {
339
+ const result = await this.dispatchWithRetry({
340
+ eventType: input.eventType,
341
+ shipmentPayload: input.payload,
342
+ tenantId: input.tenantId,
343
+ organizationId: input.organizationId,
344
+ })
345
+ return result.dispatched
346
+ }
347
+ }
@@ -0,0 +1,99 @@
1
+ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
2
+
3
+ type SchedulerServiceType = {
4
+ register: (registration: {
5
+ name: string
6
+ description?: string
7
+ scopeType: 'system' | 'organization' | 'tenant'
8
+ organizationId?: string
9
+ tenantId?: string
10
+ scheduleType: 'cron' | 'interval'
11
+ scheduleValue: string
12
+ timezone?: string
13
+ targetType: 'queue' | 'command'
14
+ targetQueue?: string
15
+ targetCommand?: string
16
+ targetPayload?: unknown
17
+ sourceType?: 'user' | 'module'
18
+ sourceModule?: string
19
+ isEnabled?: boolean
20
+ }) => Promise<void>
21
+ }
22
+
23
+ export const setup: ModuleSetupConfig = {
24
+ defaultRoleFeatures: {
25
+ admin: ['shipment_tracking.*'],
26
+ employee: [
27
+ 'shipment_tracking.shipments.view',
28
+ 'shipment_tracking.tracking_jobs.view',
29
+ 'shipment_tracking.carrier_configs.view',
30
+ 'shipment_tracking.shipsgo_config.view',
31
+ 'shipment_tracking.webhooks.view',
32
+ 'shipment_tracking.location_overrides.view',
33
+ ],
34
+ },
35
+
36
+ seedDefaults: async (ctx) => {
37
+ // Register scheduled jobs for this organization
38
+ // The scheduler service may not be available in all installations
39
+ try {
40
+ const schedulerService = ctx.container.resolve<SchedulerServiceType>('schedulerService')
41
+
42
+ // Register daily poll schedule
43
+ await schedulerService.register({
44
+ name: 'Daily Shipment Tracking Poll',
45
+ description:
46
+ 'Polls all active tracking jobs for carrier updates every day at 6:00 AM UTC. You can change the schedule time in the scheduler settings.',
47
+ scopeType: 'organization',
48
+ tenantId: ctx.tenantId,
49
+ organizationId: ctx.organizationId,
50
+ scheduleType: 'cron',
51
+ scheduleValue: '0 6 * * *', // 6:00 AM UTC daily
52
+ timezone: 'UTC',
53
+ targetType: 'command',
54
+ targetCommand: 'shipment_tracking.tracking.poll_all',
55
+ targetPayload: {
56
+ tenantId: ctx.tenantId,
57
+ organizationId: ctx.organizationId,
58
+ },
59
+ sourceType: 'module',
60
+ sourceModule: 'shipment_tracking',
61
+ isEnabled: true,
62
+ })
63
+ console.log(
64
+ `[shipment-tracking] Registered daily poll schedule for org ${ctx.organizationId}`,
65
+ )
66
+
67
+ // Register PRE_ARRIVAL evaluation schedule
68
+ // Runs every 6 hours to check IN_TRANSIT shipments approaching destination
69
+ await schedulerService.register({
70
+ name: 'Pre-Arrival Status Evaluation',
71
+ description:
72
+ 'Checks IN_TRANSIT shipments every 6 hours and upgrades them to PRE_ARRIVAL when ETA is within 7 days.',
73
+ scopeType: 'organization',
74
+ tenantId: ctx.tenantId,
75
+ organizationId: ctx.organizationId,
76
+ scheduleType: 'cron',
77
+ scheduleValue: '0 */6 * * *', // Every 6 hours
78
+ timezone: 'UTC',
79
+ targetType: 'command',
80
+ targetCommand: 'shipment_tracking.tracking.evaluate_pre_arrival',
81
+ targetPayload: {
82
+ tenantId: ctx.tenantId,
83
+ organizationId: ctx.organizationId,
84
+ },
85
+ sourceType: 'module',
86
+ sourceModule: 'shipment_tracking',
87
+ isEnabled: true,
88
+ })
89
+ console.log(
90
+ `[shipment-tracking] Registered pre-arrival evaluation schedule for org ${ctx.organizationId}`,
91
+ )
92
+ } catch (error) {
93
+ // Scheduler module may not be installed - this is fine
94
+ console.debug('[shipment-tracking] Scheduler service not available, skipping schedule registration')
95
+ }
96
+ },
97
+ }
98
+
99
+ export default setup
@@ -0,0 +1,141 @@
1
+ import { describe, it, expect, vi } from 'vitest'
2
+ import handle, { metadata } from '../terminal-event-ingest'
3
+
4
+ const PAYLOAD = {
5
+ sourceEventId: 'bct:11341499051:DEPA',
6
+ eventType: 'TRANSPORT' as const,
7
+ eventCode: 'DEPA',
8
+ eventClassifierCode: 'ACT' as const,
9
+ eventDateTime: '2026-06-03T01:58:00.000Z',
10
+ containerNumber: 'GCXU5598460',
11
+ tenantId: 'ten-1',
12
+ organizationId: 'org-1',
13
+ unlocode: 'PLGDN',
14
+ facilityCode: 'GDNBCT',
15
+ facilityCodeListProvider: 'SMDG' as const,
16
+ vesselName: null,
17
+ voyageNumber: null,
18
+ modeOfTransport: 'VESSEL' as const,
19
+ seals: [{ number: 'CN7842852' }],
20
+ rawData: { 'Unit Nbr': 'GCXU5598460', Category: 'Import' },
21
+ }
22
+
23
+ const shipment = (id: string, jobId: string | null) => ({
24
+ id,
25
+ organizationId: 'org-1',
26
+ tenantId: 'ten-1',
27
+ trackingJob: jobId ? { id: jobId } : null,
28
+ })
29
+
30
+ function setup(opts: { shipments: unknown[]; existing?: unknown }) {
31
+ const fork = {
32
+ find: vi.fn(async () => opts.shipments),
33
+ findOne: vi.fn(async () => opts.existing ?? null),
34
+ persist: vi.fn(),
35
+ flush: vi.fn(async () => {}),
36
+ }
37
+ const em = { fork: () => fork }
38
+ const service = { refreshShipmentsFromEvents: vi.fn(async () => {}) }
39
+ const resolve = vi.fn((name: string) => (name === 'em' ? em : service))
40
+ return { fork, service, resolve, ctx: { resolve } as never }
41
+ }
42
+
43
+ describe('terminal-event-ingest bridge subscriber', () => {
44
+ it('reacts to the terminal_tracking event id (string coupling only)', () => {
45
+ expect(metadata.event).toBe('terminal_tracking.terminal_event.created')
46
+ expect(metadata.id).toBe('shipment_tracking:terminal-event-ingest')
47
+ })
48
+
49
+ it("ingests a source:'port' TrackingEvent onto a matching shipment and refreshes it", async () => {
50
+ const { fork, service, ctx } = setup({ shipments: [shipment('ship-1', 'job-1')] })
51
+
52
+ await handle(PAYLOAD, ctx)
53
+
54
+ expect(fork.persist).toHaveBeenCalledTimes(1)
55
+ const ev = fork.persist.mock.calls[0][0] as Record<string, unknown>
56
+ expect(ev.source).toBe('port')
57
+ expect(ev.sourceEventId).toBe('bct:11341499051:DEPA')
58
+ expect(ev.eventCode).toBe('DEPA')
59
+ expect(ev.eventType).toBe('TRANSPORT')
60
+ expect(ev.eventClassifierCode).toBe('ACT')
61
+ expect(ev.equipmentReference).toBe('GCXU5598460')
62
+ expect(ev.facilityCode).toBe('GDNBCT')
63
+ expect(ev.locationUnlocode).toBe('PLGDN')
64
+
65
+ expect(fork.flush).toHaveBeenCalledTimes(1)
66
+ expect(service.refreshShipmentsFromEvents).toHaveBeenCalledTimes(1)
67
+ const [, jobId, shipmentIds] = service.refreshShipmentsFromEvents.mock.calls[0]
68
+ expect(jobId).toBe('job-1')
69
+ expect(shipmentIds).toEqual(['ship-1'])
70
+ })
71
+
72
+ it('dedupes: skips when a port event with the same sourceEventId already exists', async () => {
73
+ const { fork, service, ctx } = setup({
74
+ shipments: [shipment('ship-1', 'job-1')],
75
+ existing: { id: 'already-there' },
76
+ })
77
+
78
+ await handle(PAYLOAD, ctx)
79
+
80
+ expect(fork.persist).not.toHaveBeenCalled()
81
+ expect(fork.flush).not.toHaveBeenCalled()
82
+ expect(service.refreshShipmentsFromEvents).not.toHaveBeenCalled()
83
+ })
84
+
85
+ it('no-ops when the matching shipment has no tracking job', async () => {
86
+ const { fork, service, ctx } = setup({ shipments: [shipment('ship-1', null)] })
87
+
88
+ await handle(PAYLOAD, ctx)
89
+
90
+ expect(fork.findOne).not.toHaveBeenCalled()
91
+ expect(fork.persist).not.toHaveBeenCalled()
92
+ expect(service.refreshShipmentsFromEvents).not.toHaveBeenCalled()
93
+ })
94
+
95
+ it('no-ops (and does no work) when no shipment matches the container', async () => {
96
+ const { fork, service, ctx } = setup({ shipments: [] })
97
+
98
+ await handle(PAYLOAD, ctx)
99
+
100
+ expect(fork.persist).not.toHaveBeenCalled()
101
+ expect(fork.flush).not.toHaveBeenCalled()
102
+ expect(service.refreshShipmentsFromEvents).not.toHaveBeenCalled()
103
+ })
104
+
105
+ it('refreshes a job once for multiple shipments sharing it', async () => {
106
+ const { fork, service, ctx } = setup({
107
+ shipments: [shipment('ship-1', 'job-1'), shipment('ship-2', 'job-1')],
108
+ })
109
+
110
+ await handle(PAYLOAD, ctx)
111
+
112
+ expect(fork.persist).toHaveBeenCalledTimes(2)
113
+ expect(service.refreshShipmentsFromEvents).toHaveBeenCalledTimes(1)
114
+ const [, jobId, shipmentIds] = service.refreshShipmentsFromEvents.mock.calls[0]
115
+ expect(jobId).toBe('job-1')
116
+ expect(shipmentIds).toEqual(['ship-1', 'ship-2'])
117
+ })
118
+
119
+ it('scopes the shipment match to active, non-delivered shipments (no historic override)', async () => {
120
+ // A returned container reuses its number across journeys; the bridge must
121
+ // not refresh a closed/delivered shipment from a prior journey.
122
+ const { fork, ctx } = setup({ shipments: [] })
123
+
124
+ await handle(PAYLOAD, ctx)
125
+
126
+ const where = fork.find.mock.calls[0][1] as Record<string, unknown>
127
+ expect(where.containerNumber).toBe('GCXU5598460')
128
+ expect(where.deletedAt).toBeNull()
129
+ expect(where.isActive).toBe(true)
130
+ expect(where.status).toEqual({ $nin: ['DELIVERED'] })
131
+ })
132
+
133
+ it('guards against a malformed payload (missing containerNumber/sourceEventId)', async () => {
134
+ const { resolve, ctx } = setup({ shipments: [] })
135
+
136
+ await handle({ ...PAYLOAD, containerNumber: '' }, ctx)
137
+ await handle({ ...PAYLOAD, sourceEventId: '' }, ctx)
138
+
139
+ expect(resolve).not.toHaveBeenCalled()
140
+ })
141
+ })
@@ -0,0 +1,115 @@
1
+ import type { DocumentReference } from '../data/entities'
2
+
3
+ export const metadata = {
4
+ event: 'shipment_tracking.tracking_event.created',
5
+ persistent: true,
6
+ id: 'shipment_tracking:tracking-event-created',
7
+ }
8
+
9
+ type TrackingEventCreatedPayload = {
10
+ id: string
11
+ trackingJobId: string
12
+ tenantId: string
13
+ organizationId: string
14
+
15
+ // Event source
16
+ source: string
17
+ sourceEventId?: string | null
18
+
19
+ // Core event fields
20
+ eventType: string
21
+ eventCode: string
22
+ eventClassifierCode?: string | null
23
+ eventDateTime?: string | null
24
+ description?: string | null
25
+
26
+ // Equipment fields (critical for multi-container bookings)
27
+ equipmentReference?: string | null
28
+ isoEquipmentCode?: string | null
29
+ emptyIndicatorCode?: string | null
30
+ isTransshipmentMove?: boolean | null
31
+
32
+ // Location fields
33
+ locationName?: string | null
34
+ locationUnlocode?: string | null
35
+ locationCountry?: string | null
36
+ facilityCode?: string | null
37
+ facilityTypeCode?: string | null
38
+
39
+ // Transport call fields
40
+ vesselName?: string | null
41
+ vesselImo?: string | null
42
+ voyageNumber?: string | null
43
+ carrierServiceCode?: string | null
44
+ modeOfTransport?: string | null
45
+
46
+ // Document references
47
+ relatedDocumentReferences?: DocumentReference[] | null
48
+
49
+ // Metadata
50
+ publisherName?: string | null
51
+ publisherRole?: string | null
52
+ }
53
+
54
+ type ResolverContext = {
55
+ resolve: <T = unknown>(name: string) => T
56
+ }
57
+
58
+ export default async function handle(payload: TrackingEventCreatedPayload, ctx: ResolverContext) {
59
+ try {
60
+ const webhookService = ctx.resolve<any>('shipmentTrackingWebhookService')
61
+
62
+ await webhookService.dispatchEvent({
63
+ eventType: 'shipment_tracking.tracking_event.created',
64
+ payload: {
65
+ event: {
66
+ // IDs
67
+ id: payload.id,
68
+ trackingJobId: payload.trackingJobId,
69
+
70
+ // Event source
71
+ source: payload.source,
72
+ sourceEventId: payload.sourceEventId,
73
+
74
+ // Core event fields
75
+ eventType: payload.eventType,
76
+ eventCode: payload.eventCode,
77
+ eventClassifierCode: payload.eventClassifierCode,
78
+ eventDateTime: payload.eventDateTime,
79
+ description: payload.description,
80
+
81
+ // Equipment fields (critical for multi-container bookings)
82
+ equipmentReference: payload.equipmentReference,
83
+ isoEquipmentCode: payload.isoEquipmentCode,
84
+ emptyIndicatorCode: payload.emptyIndicatorCode,
85
+ isTransshipmentMove: payload.isTransshipmentMove,
86
+
87
+ // Location fields
88
+ locationName: payload.locationName,
89
+ locationUnlocode: payload.locationUnlocode,
90
+ locationCountry: payload.locationCountry,
91
+ facilityCode: payload.facilityCode,
92
+ facilityTypeCode: payload.facilityTypeCode,
93
+
94
+ // Transport call fields
95
+ vesselName: payload.vesselName,
96
+ vesselImo: payload.vesselImo,
97
+ voyageNumber: payload.voyageNumber,
98
+ carrierServiceCode: payload.carrierServiceCode,
99
+ modeOfTransport: payload.modeOfTransport,
100
+
101
+ // Document references
102
+ relatedDocumentReferences: payload.relatedDocumentReferences,
103
+
104
+ // Metadata
105
+ publisherName: payload.publisherName,
106
+ publisherRole: payload.publisherRole,
107
+ },
108
+ },
109
+ tenantId: payload.tenantId,
110
+ organizationId: payload.organizationId,
111
+ })
112
+ } catch (error) {
113
+ console.error('[shipment-tracking:subscriber] Failed to dispatch tracking_event.created webhook:', error)
114
+ }
115
+ }