@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.
- package/LICENSE +21 -0
- package/NOTICE +25 -0
- package/dist/generated/entities/bic_config/index.js +21 -0
- package/dist/generated/entities/bic_config/index.js.map +7 -0
- package/dist/generated/entities/carrier_config/index.js +27 -0
- package/dist/generated/entities/carrier_config/index.js.map +7 -0
- package/dist/generated/entities/location_override/index.js +33 -0
- package/dist/generated/entities/location_override/index.js.map +7 -0
- package/dist/generated/entities/shipment/index.js +73 -0
- package/dist/generated/entities/shipment/index.js.map +7 -0
- package/dist/generated/entities/ships_go_config/index.js +31 -0
- package/dist/generated/entities/ships_go_config/index.js.map +7 -0
- package/dist/generated/entities/tracking_event/index.js +101 -0
- package/dist/generated/entities/tracking_event/index.js.map +7 -0
- package/dist/generated/entities/tracking_job/index.js +47 -0
- package/dist/generated/entities/tracking_job/index.js.map +7 -0
- package/dist/generated/entities/webhook/index.js +25 -0
- package/dist/generated/entities/webhook/index.js.map +7 -0
- package/dist/generated/entities/webhook_delivery/index.js +25 -0
- package/dist/generated/entities/webhook_delivery/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +21 -0
- package/dist/generated/entities.ids.generated.js.map +7 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +7 -0
- package/dist/modules/shipment_tracking/acl.js +22 -0
- package/dist/modules/shipment_tracking/acl.js.map +7 -0
- package/dist/modules/shipment_tracking/api/bic-configs/route.js +176 -0
- package/dist/modules/shipment_tracking/api/bic-configs/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/bic-configs/test/route.js +95 -0
- package/dist/modules/shipment_tracking/api/bic-configs/test/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/cargo-events/route.js +93 -0
- package/dist/modules/shipment_tracking/api/cargo-events/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/carrier-configs/route.js +139 -0
- package/dist/modules/shipment_tracking/api/carrier-configs/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/dashboard/ships-map/route.js +177 -0
- package/dist/modules/shipment_tracking/api/dashboard/ships-map/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/location-overrides/route.js +179 -0
- package/dist/modules/shipment_tracking/api/location-overrides/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/openapi.js +27 -0
- package/dist/modules/shipment_tracking/api/openapi.js.map +7 -0
- package/dist/modules/shipment_tracking/api/shipments/route.js +192 -0
- package/dist/modules/shipment_tracking/api/shipments/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/shipsgo-configs/route.js +185 -0
- package/dist/modules/shipment_tracking/api/shipsgo-configs/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/tracking-jobs/route.js +144 -0
- package/dist/modules/shipment_tracking/api/tracking-jobs/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/tracking-jobs/sync/route.js +107 -0
- package/dist/modules/shipment_tracking/api/tracking-jobs/sync/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/utils.js +12 -0
- package/dist/modules/shipment_tracking/api/utils.js.map +7 -0
- package/dist/modules/shipment_tracking/api/webhooks/deliveries/route.js +76 -0
- package/dist/modules/shipment_tracking/api/webhooks/deliveries/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/webhooks/route.js +135 -0
- package/dist/modules/shipment_tracking/api/webhooks/route.js.map +7 -0
- package/dist/modules/shipment_tracking/api/webhooks/test/route.js +71 -0
- package/dist/modules/shipment_tracking/api/webhooks/test/route.js.map +7 -0
- package/dist/modules/shipment_tracking/assets/carriers/cma_cgm.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/cosco.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/evergreen.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/hapag_lloyd.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/maersk.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/msc.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/one.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/oocl.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/yang_ming.png +0 -0
- package/dist/modules/shipment_tracking/assets/carriers/zim.png +0 -0
- package/dist/modules/shipment_tracking/assets/index.js +52 -0
- package/dist/modules/shipment_tracking/assets/index.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/carrier-configs/page.js +621 -0
- package/dist/modules/shipment_tracking/backend/carrier-configs/page.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/carrier-configs/page.meta.js +19 -0
- package/dist/modules/shipment_tracking/backend/carrier-configs/page.meta.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/location-overrides/page.js +198 -0
- package/dist/modules/shipment_tracking/backend/location-overrides/page.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/location-overrides/page.meta.js +19 -0
- package/dist/modules/shipment_tracking/backend/location-overrides/page.meta.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/shipment-tracking/page.js +279 -0
- package/dist/modules/shipment_tracking/backend/shipment-tracking/page.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/shipment-tracking/page.meta.js +19 -0
- package/dist/modules/shipment_tracking/backend/shipment-tracking/page.meta.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/tracking-jobs/page.js +10 -0
- package/dist/modules/shipment_tracking/backend/tracking-jobs/page.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/tracking-jobs/page.meta.js +19 -0
- package/dist/modules/shipment_tracking/backend/tracking-jobs/page.meta.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/webhooks/page.js +198 -0
- package/dist/modules/shipment_tracking/backend/webhooks/page.js.map +7 -0
- package/dist/modules/shipment_tracking/backend/webhooks/page.meta.js +19 -0
- package/dist/modules/shipment_tracking/backend/webhooks/page.meta.js.map +7 -0
- package/dist/modules/shipment_tracking/ce.js +52 -0
- package/dist/modules/shipment_tracking/ce.js.map +7 -0
- package/dist/modules/shipment_tracking/cli.js +229 -0
- package/dist/modules/shipment_tracking/cli.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/bic-configs.js +66 -0
- package/dist/modules/shipment_tracking/commands/bic-configs.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/carrier-configs.js +65 -0
- package/dist/modules/shipment_tracking/commands/carrier-configs.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/index.js +9 -0
- package/dist/modules/shipment_tracking/commands/index.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/location-overrides.js +93 -0
- package/dist/modules/shipment_tracking/commands/location-overrides.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/shipments.js +200 -0
- package/dist/modules/shipment_tracking/commands/shipments.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/shipsgo-configs.js +75 -0
- package/dist/modules/shipment_tracking/commands/shipsgo-configs.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/tracking-jobs.js +120 -0
- package/dist/modules/shipment_tracking/commands/tracking-jobs.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/tracking.js +140 -0
- package/dist/modules/shipment_tracking/commands/tracking.js.map +7 -0
- package/dist/modules/shipment_tracking/commands/webhooks.js +115 -0
- package/dist/modules/shipment_tracking/commands/webhooks.js.map +7 -0
- package/dist/modules/shipment_tracking/components/CombinedTimestampCell.js +168 -0
- package/dist/modules/shipment_tracking/components/CombinedTimestampCell.js.map +7 -0
- package/dist/modules/shipment_tracking/components/FacilityLocationInput.js +202 -0
- package/dist/modules/shipment_tracking/components/FacilityLocationInput.js.map +7 -0
- package/dist/modules/shipment_tracking/components/LocationOverrideDrawer.js +501 -0
- package/dist/modules/shipment_tracking/components/LocationOverrideDrawer.js.map +7 -0
- package/dist/modules/shipment_tracking/components/ShipmentDetailsDrawer.js +818 -0
- package/dist/modules/shipment_tracking/components/ShipmentDetailsDrawer.js.map +7 -0
- package/dist/modules/shipment_tracking/components/ShipmentDrawer.js +404 -0
- package/dist/modules/shipment_tracking/components/ShipmentDrawer.js.map +7 -0
- package/dist/modules/shipment_tracking/components/ShipsGoConfigSection.js +200 -0
- package/dist/modules/shipment_tracking/components/ShipsGoConfigSection.js.map +7 -0
- package/dist/modules/shipment_tracking/components/TimestampCell.js +108 -0
- package/dist/modules/shipment_tracking/components/TimestampCell.js.map +7 -0
- package/dist/modules/shipment_tracking/components/TrackingJobDrawer.js +343 -0
- package/dist/modules/shipment_tracking/components/TrackingJobDrawer.js.map +7 -0
- package/dist/modules/shipment_tracking/components/VesselTrackingMap.js +496 -0
- package/dist/modules/shipment_tracking/components/VesselTrackingMap.js.map +7 -0
- package/dist/modules/shipment_tracking/components/WebhookDrawer.js +332 -0
- package/dist/modules/shipment_tracking/components/WebhookDrawer.js.map +7 -0
- package/dist/modules/shipment_tracking/data/entities.js +686 -0
- package/dist/modules/shipment_tracking/data/entities.js.map +7 -0
- package/dist/modules/shipment_tracking/data/validators.js +434 -0
- package/dist/modules/shipment_tracking/data/validators.js.map +7 -0
- package/dist/modules/shipment_tracking/di.js +60 -0
- package/dist/modules/shipment_tracking/di.js.map +7 -0
- package/dist/modules/shipment_tracking/encryption.js +12 -0
- package/dist/modules/shipment_tracking/encryption.js.map +7 -0
- package/dist/modules/shipment_tracking/events.js +87 -0
- package/dist/modules/shipment_tracking/events.js.map +7 -0
- package/dist/modules/shipment_tracking/hooks/useVesselTracking.js +137 -0
- package/dist/modules/shipment_tracking/hooks/useVesselTracking.js.map +7 -0
- package/dist/modules/shipment_tracking/i18n/de.json +327 -0
- package/dist/modules/shipment_tracking/i18n/en.json +327 -0
- package/dist/modules/shipment_tracking/i18n/es.json +327 -0
- package/dist/modules/shipment_tracking/i18n/pl.json +327 -0
- package/dist/modules/shipment_tracking/index.js +15 -0
- package/dist/modules/shipment_tracking/index.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/cma-cgm.js +66 -0
- package/dist/modules/shipment_tracking/lib/adapters/cma-cgm.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/cosco-types.js +1 -0
- package/dist/modules/shipment_tracking/lib/adapters/cosco-types.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/cosco.js +236 -0
- package/dist/modules/shipment_tracking/lib/adapters/cosco.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/evergreen.js +87 -0
- package/dist/modules/shipment_tracking/lib/adapters/evergreen.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/hapag-lloyd.js +68 -0
- package/dist/modules/shipment_tracking/lib/adapters/hapag-lloyd.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/index.js +20 -0
- package/dist/modules/shipment_tracking/lib/adapters/index.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/maersk.js +84 -0
- package/dist/modules/shipment_tracking/lib/adapters/maersk.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/msc.js +170 -0
- package/dist/modules/shipment_tracking/lib/adapters/msc.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/adapters/zim.js +85 -0
- package/dist/modules/shipment_tracking/lib/adapters/zim.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/audit-helpers.js +20 -0
- package/dist/modules/shipment_tracking/lib/audit-helpers.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/auth/base64url.js +8 -0
- package/dist/modules/shipment_tracking/lib/auth/base64url.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/auth/oauth-client.js +38 -0
- package/dist/modules/shipment_tracking/lib/auth/oauth-client.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/background.js +15 -0
- package/dist/modules/shipment_tracking/lib/background.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/bic-api-client.js +106 -0
- package/dist/modules/shipment_tracking/lib/bic-api-client.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/carrier-adapter.js +17 -0
- package/dist/modules/shipment_tracking/lib/carrier-adapter.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/current-vessel.js +149 -0
- package/dist/modules/shipment_tracking/lib/current-vessel.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/dcsa-event-mapping.js +124 -0
- package/dist/modules/shipment_tracking/lib/dcsa-event-mapping.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/dcsa-event-parser.js +112 -0
- package/dist/modules/shipment_tracking/lib/dcsa-event-parser.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/dcsa-params.js +16 -0
- package/dist/modules/shipment_tracking/lib/dcsa-params.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/empty-return.js +48 -0
- package/dist/modules/shipment_tracking/lib/empty-return.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/location-overrides.js +85 -0
- package/dist/modules/shipment_tracking/lib/location-overrides.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/location-types.js +59 -0
- package/dist/modules/shipment_tracking/lib/location-types.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/logger.js +113 -0
- package/dist/modules/shipment_tracking/lib/logger.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/poi-event-processor.js +183 -0
- package/dist/modules/shipment_tracking/lib/poi-event-processor.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/poi-nats-config.js +52 -0
- package/dist/modules/shipment_tracking/lib/poi-nats-config.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/poi-types.js +43 -0
- package/dist/modules/shipment_tracking/lib/poi-types.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/rate-limiter.js +31 -0
- package/dist/modules/shipment_tracking/lib/rate-limiter.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/route-extraction.js +187 -0
- package/dist/modules/shipment_tracking/lib/route-extraction.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/route-inference.js +106 -0
- package/dist/modules/shipment_tracking/lib/route-inference.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/schedule-generator.js +63 -0
- package/dist/modules/shipment_tracking/lib/schedule-generator.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/shipsgo-client.js +143 -0
- package/dist/modules/shipment_tracking/lib/shipsgo-client.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/shipsgo-mapper.js +204 -0
- package/dist/modules/shipment_tracking/lib/shipsgo-mapper.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/status-machine.js +131 -0
- package/dist/modules/shipment_tracking/lib/status-machine.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/time-extraction.js +41 -0
- package/dist/modules/shipment_tracking/lib/time-extraction.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/timestamp-utils.js +100 -0
- package/dist/modules/shipment_tracking/lib/timestamp-utils.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/vessel-api.js +111 -0
- package/dist/modules/shipment_tracking/lib/vessel-api.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/vessel-cache.js +50 -0
- package/dist/modules/shipment_tracking/lib/vessel-cache.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/vessel-extraction.js +13 -0
- package/dist/modules/shipment_tracking/lib/vessel-extraction.js.map +7 -0
- package/dist/modules/shipment_tracking/lib/webhook-dispatcher.js +62 -0
- package/dist/modules/shipment_tracking/lib/webhook-dispatcher.js.map +7 -0
- package/dist/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.js +48 -0
- package/dist/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.js.map +7 -0
- package/dist/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.js +15 -0
- package/dist/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.js.map +7 -0
- package/dist/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.js +47 -0
- package/dist/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.js.map +7 -0
- package/dist/modules/shipment_tracking/notifications.js +145 -0
- package/dist/modules/shipment_tracking/notifications.js.map +7 -0
- package/dist/modules/shipment_tracking/services/carrierRegistry.js +24 -0
- package/dist/modules/shipment_tracking/services/carrierRegistry.js.map +7 -0
- package/dist/modules/shipment_tracking/services/poiNatsService.js +397 -0
- package/dist/modules/shipment_tracking/services/poiNatsService.js.map +7 -0
- package/dist/modules/shipment_tracking/services/shipsGoProvider.js +163 -0
- package/dist/modules/shipment_tracking/services/shipsGoProvider.js.map +7 -0
- package/dist/modules/shipment_tracking/services/trackingService.js +1283 -0
- package/dist/modules/shipment_tracking/services/trackingService.js.map +7 -0
- package/dist/modules/shipment_tracking/services/webhookService.js +263 -0
- package/dist/modules/shipment_tracking/services/webhookService.js.map +7 -0
- package/dist/modules/shipment_tracking/setup.js +72 -0
- package/dist/modules/shipment_tracking/setup.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/cargo-event-created.js +60 -0
- package/dist/modules/shipment_tracking/subscribers/cargo-event-created.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.js +58 -0
- package/dist/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/poi-event-notification.js +82 -0
- package/dist/modules/shipment_tracking/subscribers/poi-event-notification.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.js +53 -0
- package/dist/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/shipment-status-changed.js +28 -0
- package/dist/modules/shipment_tracking/subscribers/shipment-status-changed.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/terminal-event-ingest.js +67 -0
- package/dist/modules/shipment_tracking/subscribers/terminal-event-ingest.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/tracking-job-initial-poll.js +30 -0
- package/dist/modules/shipment_tracking/subscribers/tracking-job-initial-poll.js.map +7 -0
- package/dist/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.js +19 -0
- package/dist/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.js.map +7 -0
- package/dist/modules/shipment_tracking/tables/index.js +6 -0
- package/dist/modules/shipment_tracking/tables/index.js.map +7 -0
- package/dist/modules/shipment_tracking/tables/tracking_job/table.client.js +284 -0
- package/dist/modules/shipment_tracking/tables/tracking_job/table.client.js.map +7 -0
- package/dist/modules/shipment_tracking/tables/tracking_job/table.js +36 -0
- package/dist/modules/shipment_tracking/tables/tracking_job/table.js.map +7 -0
- package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/config.js +25 -0
- package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/config.js.map +7 -0
- package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.js +355 -0
- package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.js.map +7 -0
- package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.js +26 -0
- package/dist/modules/shipment_tracking/widgets/dashboard/ships-map/widget.js.map +7 -0
- package/dist/types/assets.d.js +1 -0
- package/dist/types/assets.d.js.map +7 -0
- package/generated/entities/bic_config/index.ts +20 -0
- package/generated/entities/carrier_config/index.ts +23 -0
- package/generated/entities/location_override/index.ts +26 -0
- package/generated/entities/shipment/index.ts +46 -0
- package/generated/entities/ships_go_config/index.ts +25 -0
- package/generated/entities/tracking_event/index.ts +60 -0
- package/generated/entities/tracking_job/index.ts +33 -0
- package/generated/entities/webhook/index.ts +22 -0
- package/generated/entities/webhook_delivery/index.ts +22 -0
- package/generated/entities.ids.generated.ts +47 -0
- package/package.json +81 -0
- package/src/index.ts +39 -0
- package/src/modules/shipment_tracking/__integration__/TC-TRACK-410-shipsgo-config-api.spec.ts +133 -0
- package/src/modules/shipment_tracking/__integration__/meta.ts +4 -0
- package/src/modules/shipment_tracking/__tests__/empty-return-stop.test.ts +231 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/hapag-lloyd-transship-container.json +702 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/index.ts +434 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/maersk-multi-transship-completed.json +1518 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/maersk-transship-intransit.json +558 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/msc-direct.json +222 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/msc-multi-transship-completed.json +974 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/msc-multi.json +4846 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/msc-transship.json +409 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/poi-events.json +240 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/synthetic/index.ts +138 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-eta-updates.json +288 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-route-inference.json +201 -0
- package/src/modules/shipment_tracking/__tests__/fixtures/synthetic-voyage-progression.json +410 -0
- package/src/modules/shipment_tracking/__tests__/shipsgo-air-mapper.test.ts +157 -0
- package/src/modules/shipment_tracking/__tests__/shipsgo-client.test.ts +155 -0
- package/src/modules/shipment_tracking/__tests__/shipsgo-mapper.test.ts +201 -0
- package/src/modules/shipment_tracking/__tests__/shipsgo-poll.test.ts +357 -0
- package/src/modules/shipment_tracking/__tests__/shipsgo-provider.test.ts +364 -0
- package/src/modules/shipment_tracking/__tests__/trackingService.integration.test.ts +2248 -0
- package/src/modules/shipment_tracking/__tests__/webhookPayload.test.ts +151 -0
- package/src/modules/shipment_tracking/acl.ts +18 -0
- package/src/modules/shipment_tracking/api/bic-configs/route.ts +206 -0
- package/src/modules/shipment_tracking/api/bic-configs/test/route.ts +108 -0
- package/src/modules/shipment_tracking/api/cargo-events/route.ts +101 -0
- package/src/modules/shipment_tracking/api/carrier-configs/route.ts +142 -0
- package/src/modules/shipment_tracking/api/dashboard/ships-map/route.ts +246 -0
- package/src/modules/shipment_tracking/api/location-overrides/route.ts +185 -0
- package/src/modules/shipment_tracking/api/openapi.ts +28 -0
- package/src/modules/shipment_tracking/api/shipments/route.ts +197 -0
- package/src/modules/shipment_tracking/api/shipsgo-configs/route.ts +215 -0
- package/src/modules/shipment_tracking/api/tracking-jobs/route.ts +149 -0
- package/src/modules/shipment_tracking/api/tracking-jobs/sync/route.ts +116 -0
- package/src/modules/shipment_tracking/api/utils.ts +10 -0
- package/src/modules/shipment_tracking/api/webhooks/deliveries/route.ts +82 -0
- package/src/modules/shipment_tracking/api/webhooks/route.ts +138 -0
- package/src/modules/shipment_tracking/api/webhooks/test/route.ts +84 -0
- package/src/modules/shipment_tracking/assets/carriers/cma_cgm.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/cosco.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/evergreen.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/hapag_lloyd.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/maersk.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/msc.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/one.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/oocl.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/yang_ming.png +0 -0
- package/src/modules/shipment_tracking/assets/carriers/zim.png +0 -0
- package/src/modules/shipment_tracking/assets/index.ts +66 -0
- package/src/modules/shipment_tracking/backend/carrier-configs/page.meta.ts +16 -0
- package/src/modules/shipment_tracking/backend/carrier-configs/page.tsx +782 -0
- package/src/modules/shipment_tracking/backend/location-overrides/page.meta.ts +16 -0
- package/src/modules/shipment_tracking/backend/location-overrides/page.tsx +241 -0
- package/src/modules/shipment_tracking/backend/shipment-tracking/page.meta.ts +16 -0
- package/src/modules/shipment_tracking/backend/shipment-tracking/page.tsx +340 -0
- package/src/modules/shipment_tracking/backend/tracking-jobs/page.meta.ts +16 -0
- package/src/modules/shipment_tracking/backend/tracking-jobs/page.tsx +16 -0
- package/src/modules/shipment_tracking/backend/webhooks/page.meta.ts +16 -0
- package/src/modules/shipment_tracking/backend/webhooks/page.tsx +228 -0
- package/src/modules/shipment_tracking/ce.ts +48 -0
- package/src/modules/shipment_tracking/cli.ts +321 -0
- package/src/modules/shipment_tracking/commands/bic-configs.ts +94 -0
- package/src/modules/shipment_tracking/commands/carrier-configs.ts +89 -0
- package/src/modules/shipment_tracking/commands/index.ts +8 -0
- package/src/modules/shipment_tracking/commands/location-overrides.ts +119 -0
- package/src/modules/shipment_tracking/commands/shipments.ts +247 -0
- package/src/modules/shipment_tracking/commands/shipsgo-configs.ts +101 -0
- package/src/modules/shipment_tracking/commands/tracking-jobs.ts +158 -0
- package/src/modules/shipment_tracking/commands/tracking.ts +230 -0
- package/src/modules/shipment_tracking/commands/webhooks.ts +159 -0
- package/src/modules/shipment_tracking/components/CombinedTimestampCell.tsx +236 -0
- package/src/modules/shipment_tracking/components/FacilityLocationInput.tsx +235 -0
- package/src/modules/shipment_tracking/components/LocationOverrideDrawer.tsx +586 -0
- package/src/modules/shipment_tracking/components/ShipmentDetailsDrawer.tsx +1364 -0
- package/src/modules/shipment_tracking/components/ShipmentDrawer.tsx +498 -0
- package/src/modules/shipment_tracking/components/ShipsGoConfigSection.tsx +266 -0
- package/src/modules/shipment_tracking/components/TimestampCell.tsx +146 -0
- package/src/modules/shipment_tracking/components/TrackingJobDrawer.tsx +467 -0
- package/src/modules/shipment_tracking/components/VesselTrackingMap.tsx +761 -0
- package/src/modules/shipment_tracking/components/WebhookDrawer.tsx +434 -0
- package/src/modules/shipment_tracking/data/entities.ts +748 -0
- package/src/modules/shipment_tracking/data/validators.ts +523 -0
- package/src/modules/shipment_tracking/di.ts +73 -0
- package/src/modules/shipment_tracking/encryption.ts +17 -0
- package/src/modules/shipment_tracking/events.ts +122 -0
- package/src/modules/shipment_tracking/hooks/useVesselTracking.ts +297 -0
- package/src/modules/shipment_tracking/i18n/de.json +327 -0
- package/src/modules/shipment_tracking/i18n/en.json +327 -0
- package/src/modules/shipment_tracking/i18n/es.json +327 -0
- package/src/modules/shipment_tracking/i18n/pl.json +327 -0
- package/src/modules/shipment_tracking/index.ts +13 -0
- package/src/modules/shipment_tracking/lib/__tests__/dcsa-event-mapping.test.ts +385 -0
- package/src/modules/shipment_tracking/lib/__tests__/dcsa-event-parser.test.ts +398 -0
- package/src/modules/shipment_tracking/lib/__tests__/empty-return.test.ts +174 -0
- package/src/modules/shipment_tracking/lib/__tests__/poi-event-processor.test.ts +699 -0
- package/src/modules/shipment_tracking/lib/__tests__/route-inference.test.ts +402 -0
- package/src/modules/shipment_tracking/lib/__tests__/status-machine.test.ts +447 -0
- package/src/modules/shipment_tracking/lib/__tests__/time-extraction.test.ts +331 -0
- package/src/modules/shipment_tracking/lib/__tests__/timestamp-utils.test.ts +260 -0
- package/src/modules/shipment_tracking/lib/__tests__/vessel-api.test.ts +125 -0
- package/src/modules/shipment_tracking/lib/__tests__/vessel-extraction.test.ts +108 -0
- package/src/modules/shipment_tracking/lib/adapters/cma-cgm.ts +84 -0
- package/src/modules/shipment_tracking/lib/adapters/cosco-types.ts +145 -0
- package/src/modules/shipment_tracking/lib/adapters/cosco.ts +314 -0
- package/src/modules/shipment_tracking/lib/adapters/evergreen.ts +107 -0
- package/src/modules/shipment_tracking/lib/adapters/hapag-lloyd.ts +88 -0
- package/src/modules/shipment_tracking/lib/adapters/index.ts +18 -0
- package/src/modules/shipment_tracking/lib/adapters/maersk.ts +104 -0
- package/src/modules/shipment_tracking/lib/adapters/msc.ts +223 -0
- package/src/modules/shipment_tracking/lib/adapters/zim.ts +106 -0
- package/src/modules/shipment_tracking/lib/audit-helpers.ts +29 -0
- package/src/modules/shipment_tracking/lib/auth/base64url.ts +4 -0
- package/src/modules/shipment_tracking/lib/auth/oauth-client.ts +53 -0
- package/src/modules/shipment_tracking/lib/background.ts +24 -0
- package/src/modules/shipment_tracking/lib/bic-api-client.ts +199 -0
- package/src/modules/shipment_tracking/lib/carrier-adapter.ts +136 -0
- package/src/modules/shipment_tracking/lib/current-vessel.ts +274 -0
- package/src/modules/shipment_tracking/lib/dcsa-event-mapping.ts +202 -0
- package/src/modules/shipment_tracking/lib/dcsa-event-parser.ts +163 -0
- package/src/modules/shipment_tracking/lib/dcsa-params.ts +14 -0
- package/src/modules/shipment_tracking/lib/empty-return.ts +122 -0
- package/src/modules/shipment_tracking/lib/location-overrides.ts +150 -0
- package/src/modules/shipment_tracking/lib/location-types.ts +154 -0
- package/src/modules/shipment_tracking/lib/logger.ts +195 -0
- package/src/modules/shipment_tracking/lib/poi-event-processor.ts +302 -0
- package/src/modules/shipment_tracking/lib/poi-nats-config.ts +134 -0
- package/src/modules/shipment_tracking/lib/poi-types.ts +198 -0
- package/src/modules/shipment_tracking/lib/rate-limiter.ts +58 -0
- package/src/modules/shipment_tracking/lib/route-extraction.ts +439 -0
- package/src/modules/shipment_tracking/lib/route-inference.ts +238 -0
- package/src/modules/shipment_tracking/lib/schedule-generator.ts +92 -0
- package/src/modules/shipment_tracking/lib/shipsgo-client.ts +350 -0
- package/src/modules/shipment_tracking/lib/shipsgo-mapper.ts +296 -0
- package/src/modules/shipment_tracking/lib/status-machine.ts +230 -0
- package/src/modules/shipment_tracking/lib/time-extraction.ts +85 -0
- package/src/modules/shipment_tracking/lib/timestamp-utils.ts +244 -0
- package/src/modules/shipment_tracking/lib/vessel-api.ts +299 -0
- package/src/modules/shipment_tracking/lib/vessel-cache.ts +102 -0
- package/src/modules/shipment_tracking/lib/vessel-extraction.ts +39 -0
- package/src/modules/shipment_tracking/lib/webhook-dispatcher.ts +93 -0
- package/src/modules/shipment_tracking/migrations/.snapshot-open-mercato.json +2914 -0
- package/src/modules/shipment_tracking/migrations/Migration20260422161208_shipment_tracking.ts +60 -0
- package/src/modules/shipment_tracking/migrations/Migration20260529120000_shipment_tracking_poi_region_names.ts +22 -0
- package/src/modules/shipment_tracking/migrations/Migration20260821120000_shipment_tracking_shipsgo.ts +65 -0
- package/src/modules/shipment_tracking/notifications.ts +151 -0
- package/src/modules/shipment_tracking/services/carrierRegistry.ts +29 -0
- package/src/modules/shipment_tracking/services/poiNatsService.ts +526 -0
- package/src/modules/shipment_tracking/services/shipsGoProvider.ts +231 -0
- package/src/modules/shipment_tracking/services/trackingService.ts +1777 -0
- package/src/modules/shipment_tracking/services/webhookService.ts +347 -0
- package/src/modules/shipment_tracking/setup.ts +99 -0
- package/src/modules/shipment_tracking/subscribers/__tests__/terminal-event-ingest.test.ts +141 -0
- package/src/modules/shipment_tracking/subscribers/cargo-event-created.ts +115 -0
- package/src/modules/shipment_tracking/subscribers/dcsa-event-webhook-dispatch.ts +115 -0
- package/src/modules/shipment_tracking/subscribers/poi-event-notification.ts +144 -0
- package/src/modules/shipment_tracking/subscribers/poi-event-webhook-dispatch.ts +94 -0
- package/src/modules/shipment_tracking/subscribers/shipment-status-changed.ts +41 -0
- package/src/modules/shipment_tracking/subscribers/terminal-event-ingest.ts +109 -0
- package/src/modules/shipment_tracking/subscribers/tracking-job-initial-poll.ts +53 -0
- package/src/modules/shipment_tracking/subscribers/tracking-job-webhook-dispatch.ts +50 -0
- package/src/modules/shipment_tracking/tables/index.ts +4 -0
- package/src/modules/shipment_tracking/tables/tracking_job/table.client.tsx +337 -0
- package/src/modules/shipment_tracking/tables/tracking_job/table.ts +34 -0
- package/src/modules/shipment_tracking/widgets/dashboard/ships-map/config.ts +32 -0
- package/src/modules/shipment_tracking/widgets/dashboard/ships-map/widget.client.tsx +448 -0
- package/src/modules/shipment_tracking/widgets/dashboard/ships-map/widget.ts +25 -0
- package/src/types/assets.d.ts +5 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import crypto from 'node:crypto'
|
|
2
|
+
import fs, { writeFileSync } from 'node:fs'
|
|
3
|
+
import os from 'node:os'
|
|
4
|
+
import path from 'node:path'
|
|
5
|
+
import { execFileSync } from 'node:child_process'
|
|
6
|
+
import type { CarrierAdapter, CarrierFetchResult, CarrierAdapterTestResult } from '../carrier-adapter'
|
|
7
|
+
import { extractDocumentReferences } from '../carrier-adapter'
|
|
8
|
+
import type { TrackingReferenceType } from '../../data/entities'
|
|
9
|
+
import { base64UrlEncode } from '../auth/base64url'
|
|
10
|
+
import { buildDcsaQueryParams } from '../dcsa-params'
|
|
11
|
+
import { parseDcsaEvents } from '../dcsa-event-parser'
|
|
12
|
+
import { withCarrierApiSpan } from '../logger'
|
|
13
|
+
|
|
14
|
+
// MSC's public track-and-trace events endpoint (DCSA). Overridable per carrier
|
|
15
|
+
// config via `apiEndpoint`.
|
|
16
|
+
const EVENTS_URL = 'https://api.tech.msc.com/msc/trackandtrace/v2.2/events'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* MSC OAuth account identity. These values are specific to the API account MSC
|
|
20
|
+
* issues to each integrator (Azure AD tenant, registered client_id and API
|
|
21
|
+
* scope) and are NOT shipped as defaults — supply them, together with the PFX
|
|
22
|
+
* certificate, through the carrier config's `authConfig`.
|
|
23
|
+
*/
|
|
24
|
+
type MscAuthConfig = {
|
|
25
|
+
certificate_base64: string
|
|
26
|
+
clientId: string
|
|
27
|
+
scope: string
|
|
28
|
+
tokenUrl: string
|
|
29
|
+
aud: string
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getAuth(authConfig: Record<string, unknown> | null | undefined): MscAuthConfig {
|
|
33
|
+
const certBase64 = authConfig?.certificate_base64 as string | undefined
|
|
34
|
+
const clientId = authConfig?.client_id as string | undefined
|
|
35
|
+
const scope = authConfig?.scope as string | undefined
|
|
36
|
+
const tokenUrl = authConfig?.token_url as string | undefined
|
|
37
|
+
const aud = (authConfig?.aud as string | undefined) || tokenUrl
|
|
38
|
+
const missing = [
|
|
39
|
+
!certBase64 && 'certificate_base64',
|
|
40
|
+
!clientId && 'client_id',
|
|
41
|
+
!scope && 'scope',
|
|
42
|
+
!tokenUrl && 'token_url',
|
|
43
|
+
].filter(Boolean)
|
|
44
|
+
if (missing.length) {
|
|
45
|
+
throw new Error(`MSC authConfig requires: ${missing.join(', ')}`)
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
certificate_base64: certBase64!,
|
|
49
|
+
clientId: clientId!,
|
|
50
|
+
scope: scope!,
|
|
51
|
+
tokenUrl: tokenUrl!,
|
|
52
|
+
aud: aud!,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function extractPfxComponents(pfxBuffer: Buffer): { privateKeyPem: string; certPem: string } {
|
|
57
|
+
const tempDir = os.tmpdir()
|
|
58
|
+
const uid = crypto.randomUUID()
|
|
59
|
+
const pfxPath = path.join(tempDir, `msc_${uid}.pfx`)
|
|
60
|
+
const certPath = path.join(tempDir, `msc_cert_${uid}.pem`)
|
|
61
|
+
const keyPath = path.join(tempDir, `msc_key_${uid}.pem`)
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
fs.writeFileSync(pfxPath, pfxBuffer)
|
|
65
|
+
|
|
66
|
+
execFileSync('openssl', ['pkcs12', '-in', pfxPath, '-nokeys', '-out', certPath, '-passin', 'pass:'])
|
|
67
|
+
execFileSync('openssl', ['pkcs12', '-in', pfxPath, '-nocerts', '-nodes', '-out', keyPath, '-passin', 'pass:'])
|
|
68
|
+
|
|
69
|
+
const certPem = fs.readFileSync(certPath, 'utf8')
|
|
70
|
+
const privateKeyPem = fs.readFileSync(keyPath, 'utf8')
|
|
71
|
+
|
|
72
|
+
return { privateKeyPem, certPem }
|
|
73
|
+
} finally {
|
|
74
|
+
for (const filePath of [pfxPath, certPath, keyPath]) {
|
|
75
|
+
try { fs.unlinkSync(filePath) } catch { /* ignore cleanup errors */ }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createMscJwt(auth: MscAuthConfig): string {
|
|
81
|
+
const pfxBuffer = Buffer.from(auth.certificate_base64, 'base64')
|
|
82
|
+
const { privateKeyPem, certPem } = extractPfxComponents(pfxBuffer)
|
|
83
|
+
|
|
84
|
+
// Extract the last certificate from the chain for x5t thumbprint
|
|
85
|
+
const certMatches = certPem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g)
|
|
86
|
+
if (!certMatches?.length) {
|
|
87
|
+
throw new Error('No certificates found in PFX')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const lastCert = certMatches[certMatches.length - 1]
|
|
91
|
+
const certDerBase64 = lastCert
|
|
92
|
+
.replace(/-----BEGIN CERTIFICATE-----/g, '')
|
|
93
|
+
.replace(/-----END CERTIFICATE-----/g, '')
|
|
94
|
+
.replace(/\r?\n/g, '')
|
|
95
|
+
.trim()
|
|
96
|
+
|
|
97
|
+
const certDer = Buffer.from(certDerBase64, 'base64')
|
|
98
|
+
const sha1Hash = crypto.createHash('sha1').update(certDer).digest()
|
|
99
|
+
const x5t = base64UrlEncode(sha1Hash)
|
|
100
|
+
|
|
101
|
+
const now = Math.floor(Date.now() / 1000)
|
|
102
|
+
|
|
103
|
+
const header = { alg: 'RS256', typ: 'JWT', x5t }
|
|
104
|
+
const payload = {
|
|
105
|
+
aud: auth.aud,
|
|
106
|
+
exp: now + 120,
|
|
107
|
+
iss: auth.clientId,
|
|
108
|
+
jti: crypto.randomUUID(),
|
|
109
|
+
nbf: now,
|
|
110
|
+
sub: auth.clientId,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const encodedHeader = base64UrlEncode(JSON.stringify(header))
|
|
114
|
+
const encodedPayload = base64UrlEncode(JSON.stringify(payload))
|
|
115
|
+
const unsignedToken = `${encodedHeader}.${encodedPayload}`
|
|
116
|
+
|
|
117
|
+
const sign = crypto.createSign('RSA-SHA256')
|
|
118
|
+
sign.update(unsignedToken)
|
|
119
|
+
const signature = sign.sign(privateKeyPem)
|
|
120
|
+
const encodedSignature = base64UrlEncode(signature)
|
|
121
|
+
|
|
122
|
+
return `${unsignedToken}.${encodedSignature}`
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
async function authenticate(auth: MscAuthConfig): Promise<string> {
|
|
126
|
+
return withCarrierApiSpan(
|
|
127
|
+
{ carrierCode: 'msc', operation: 'authenticate' },
|
|
128
|
+
async (span) => {
|
|
129
|
+
const jwt = createMscJwt(auth)
|
|
130
|
+
|
|
131
|
+
const body = new URLSearchParams({
|
|
132
|
+
client_id: auth.clientId,
|
|
133
|
+
client_assertion: jwt,
|
|
134
|
+
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
|
135
|
+
scope: auth.scope,
|
|
136
|
+
grant_type: 'client_credentials',
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const response = await fetch(auth.tokenUrl, {
|
|
140
|
+
method: 'POST',
|
|
141
|
+
headers: {
|
|
142
|
+
'Authorization': `Bearer ${jwt}`,
|
|
143
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
144
|
+
},
|
|
145
|
+
body: body.toString(),
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
span.setAttribute('http.status_code', response.status)
|
|
149
|
+
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const errorText = await response.text().catch(() => 'unknown')
|
|
152
|
+
throw new Error(`MSC token request failed (${response.status}): ${errorText}`)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const data = await response.json() as { access_token: string }
|
|
156
|
+
return data.access_token
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export class MscAdapter implements CarrierAdapter {
|
|
162
|
+
readonly carrierCode = 'msc'
|
|
163
|
+
readonly supportedReferenceTypes: TrackingReferenceType[] = ['container', 'booking', 'bol']
|
|
164
|
+
|
|
165
|
+
async fetchEvents(input: {
|
|
166
|
+
referenceType: TrackingReferenceType
|
|
167
|
+
referenceValue: string
|
|
168
|
+
apiEndpoint?: string | null
|
|
169
|
+
authConfig?: Record<string, unknown> | null
|
|
170
|
+
}): Promise<CarrierFetchResult> {
|
|
171
|
+
return withCarrierApiSpan(
|
|
172
|
+
{
|
|
173
|
+
carrierCode: this.carrierCode,
|
|
174
|
+
operation: 'fetchEvents',
|
|
175
|
+
referenceType: input.referenceType,
|
|
176
|
+
referenceValue: input.referenceValue,
|
|
177
|
+
},
|
|
178
|
+
async (span) => {
|
|
179
|
+
const auth = getAuth(input.authConfig)
|
|
180
|
+
const token = await authenticate(auth)
|
|
181
|
+
const params = buildDcsaQueryParams(input.referenceValue, input.referenceType)
|
|
182
|
+
const url = `${input.apiEndpoint || EVENTS_URL}?${params}`
|
|
183
|
+
|
|
184
|
+
const response = await fetch(url, {
|
|
185
|
+
headers: {
|
|
186
|
+
'Authorization': `Bearer ${token}`,
|
|
187
|
+
'Content-Type': 'application/json',
|
|
188
|
+
},
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
span.setAttribute('http.status_code', response.status)
|
|
192
|
+
|
|
193
|
+
if (!response.ok) {
|
|
194
|
+
const errorText = await response.text().catch(() => 'unknown')
|
|
195
|
+
throw new Error(`MSC API error (${response.status}): ${errorText}`)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const data = await response.json()
|
|
199
|
+
const events = parseDcsaEvents(data, 'MSC')
|
|
200
|
+
|
|
201
|
+
const { bookingNumber, bolNumber } = extractDocumentReferences(events)
|
|
202
|
+
|
|
203
|
+
span.setAttribute('events.count', events.length)
|
|
204
|
+
return { events, bookingNumber, bolNumber }
|
|
205
|
+
},
|
|
206
|
+
)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async testConnection(input: {
|
|
210
|
+
apiEndpoint?: string | null
|
|
211
|
+
authConfig?: Record<string, unknown> | null
|
|
212
|
+
}): Promise<CarrierAdapterTestResult> {
|
|
213
|
+
const start = Date.now()
|
|
214
|
+
try {
|
|
215
|
+
const auth = getAuth(input.authConfig)
|
|
216
|
+
await authenticate(auth)
|
|
217
|
+
return { success: true, message: 'MSC authentication successful', latencyMs: Date.now() - start }
|
|
218
|
+
} catch (error) {
|
|
219
|
+
const message = error instanceof Error ? error.message : 'Unknown error'
|
|
220
|
+
return { success: false, message: `MSC connection failed: ${message}`, latencyMs: Date.now() - start }
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { CarrierAdapter, CarrierFetchResult, CarrierAdapterTestResult } from '../carrier-adapter'
|
|
2
|
+
import { extractDocumentReferences } from '../carrier-adapter'
|
|
3
|
+
import type { TrackingReferenceType } from '../../data/entities'
|
|
4
|
+
import { fetchOAuthToken } from '../auth/oauth-client'
|
|
5
|
+
import { buildDcsaQueryParams } from '../dcsa-params'
|
|
6
|
+
import { parseDcsaEvents } from '../dcsa-event-parser'
|
|
7
|
+
import { withCarrierApiSpan } from '../logger'
|
|
8
|
+
|
|
9
|
+
const TOKEN_URL = 'https://apigw.zim.com/authorize/v1'
|
|
10
|
+
const EVENTS_URL = 'https://apigw.zim.com/trackAndTrace/v1'
|
|
11
|
+
|
|
12
|
+
type ZimAuthConfig = {
|
|
13
|
+
client_id: string
|
|
14
|
+
client_secret: string
|
|
15
|
+
subscription_key: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getAuth(authConfig: Record<string, unknown> | null | undefined): ZimAuthConfig {
|
|
19
|
+
const clientId = authConfig?.client_id as string | undefined
|
|
20
|
+
const clientSecret = authConfig?.client_secret as string | undefined
|
|
21
|
+
const subscriptionKey = authConfig?.subscription_key as string | undefined
|
|
22
|
+
if (!clientId || !clientSecret || !subscriptionKey) {
|
|
23
|
+
throw new Error('ZIM authConfig requires client_id, client_secret, and subscription_key')
|
|
24
|
+
}
|
|
25
|
+
return { client_id: clientId, client_secret: clientSecret, subscription_key: subscriptionKey }
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function authenticate(auth: ZimAuthConfig): Promise<string> {
|
|
29
|
+
return withCarrierApiSpan(
|
|
30
|
+
{ carrierCode: 'zim', operation: 'authenticate' },
|
|
31
|
+
async (span) => {
|
|
32
|
+
const token = await fetchOAuthToken({
|
|
33
|
+
tokenUrl: TOKEN_URL,
|
|
34
|
+
clientId: auth.client_id,
|
|
35
|
+
clientSecret: auth.client_secret,
|
|
36
|
+
authMethod: 'body',
|
|
37
|
+
extraBody: { scope: 'tracing' },
|
|
38
|
+
})
|
|
39
|
+
return token
|
|
40
|
+
},
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class ZimAdapter implements CarrierAdapter {
|
|
45
|
+
readonly carrierCode = 'zim'
|
|
46
|
+
readonly supportedReferenceTypes: TrackingReferenceType[] = ['container', 'booking', 'bol']
|
|
47
|
+
|
|
48
|
+
async fetchEvents(input: {
|
|
49
|
+
referenceType: TrackingReferenceType
|
|
50
|
+
referenceValue: string
|
|
51
|
+
apiEndpoint?: string | null
|
|
52
|
+
authConfig?: Record<string, unknown> | null
|
|
53
|
+
}): Promise<CarrierFetchResult> {
|
|
54
|
+
return withCarrierApiSpan(
|
|
55
|
+
{
|
|
56
|
+
carrierCode: this.carrierCode,
|
|
57
|
+
operation: 'fetchEvents',
|
|
58
|
+
referenceType: input.referenceType,
|
|
59
|
+
referenceValue: input.referenceValue,
|
|
60
|
+
},
|
|
61
|
+
async (span) => {
|
|
62
|
+
const auth = getAuth(input.authConfig)
|
|
63
|
+
const token = await authenticate(auth)
|
|
64
|
+
const params = buildDcsaQueryParams(input.referenceValue, input.referenceType)
|
|
65
|
+
const url = `${input.apiEndpoint || EVENTS_URL}?${params}`
|
|
66
|
+
|
|
67
|
+
const response = await fetch(url, {
|
|
68
|
+
headers: {
|
|
69
|
+
'Authorization': `Bearer ${token}`,
|
|
70
|
+
'Ocp-Apim-Subscription-Key': auth.subscription_key,
|
|
71
|
+
'Content-Type': 'application/json',
|
|
72
|
+
},
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
span.setAttribute('http.status_code', response.status)
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
const errorText = await response.text().catch(() => 'unknown')
|
|
79
|
+
throw new Error(`ZIM API error (${response.status}): ${errorText}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const data = await response.json()
|
|
83
|
+
const events = parseDcsaEvents(data, 'ZIM')
|
|
84
|
+
const { bookingNumber, bolNumber } = extractDocumentReferences(events)
|
|
85
|
+
|
|
86
|
+
span.setAttribute('events.count', events.length)
|
|
87
|
+
return { events, bookingNumber, bolNumber }
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async testConnection(input: {
|
|
93
|
+
apiEndpoint?: string | null
|
|
94
|
+
authConfig?: Record<string, unknown> | null
|
|
95
|
+
}): Promise<CarrierAdapterTestResult> {
|
|
96
|
+
const start = Date.now()
|
|
97
|
+
try {
|
|
98
|
+
const auth = getAuth(input.authConfig)
|
|
99
|
+
await authenticate(auth)
|
|
100
|
+
return { success: true, message: 'ZIM authentication successful', latencyMs: Date.now() - start }
|
|
101
|
+
} catch (error) {
|
|
102
|
+
const message = error instanceof Error ? error.message : 'Unknown error'
|
|
103
|
+
return { success: false, message: `ZIM connection failed: ${message}`, latencyMs: Date.now() - start }
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entities'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get the user ID of who created a tracking job by querying audit logs.
|
|
6
|
+
*
|
|
7
|
+
* This is used for notifications where we need to notify the user who created
|
|
8
|
+
* the tracking job, but the TrackingJob entity doesn't store createdByUserId.
|
|
9
|
+
*/
|
|
10
|
+
export async function getTrackingJobCreator(
|
|
11
|
+
em: EntityManager,
|
|
12
|
+
trackingJobId: string,
|
|
13
|
+
tenantId: string,
|
|
14
|
+
): Promise<string | null> {
|
|
15
|
+
const createLog = await em.findOne(
|
|
16
|
+
ActionLog,
|
|
17
|
+
{
|
|
18
|
+
tenantId,
|
|
19
|
+
resourceKind: 'shipment_tracking.tracking_job',
|
|
20
|
+
resourceId: trackingJobId,
|
|
21
|
+
commandId: 'shipment_tracking.tracking_job.create',
|
|
22
|
+
executionState: 'done',
|
|
23
|
+
deletedAt: null,
|
|
24
|
+
},
|
|
25
|
+
{ orderBy: { createdAt: 'asc' } },
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
return createLog?.actorUserId ?? null
|
|
29
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
type OAuthConfig = {
|
|
2
|
+
tokenUrl: string
|
|
3
|
+
clientId: string
|
|
4
|
+
clientSecret: string
|
|
5
|
+
scope?: string
|
|
6
|
+
extraHeaders?: Record<string, string>
|
|
7
|
+
extraBody?: Record<string, string>
|
|
8
|
+
authMethod?: 'body' | 'basic'
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function fetchOAuthToken(config: OAuthConfig): Promise<string> {
|
|
12
|
+
const { tokenUrl, clientId, clientSecret, scope, extraHeaders, extraBody, authMethod = 'body' } = config
|
|
13
|
+
|
|
14
|
+
const body = new URLSearchParams({ grant_type: 'client_credentials' })
|
|
15
|
+
|
|
16
|
+
if (authMethod === 'body') {
|
|
17
|
+
body.set('client_id', clientId)
|
|
18
|
+
body.set('client_secret', clientSecret)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (scope) {
|
|
22
|
+
body.set('scope', scope)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (extraBody) {
|
|
26
|
+
for (const [key, value] of Object.entries(extraBody)) {
|
|
27
|
+
body.set(key, value)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const headers: Record<string, string> = {
|
|
32
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
33
|
+
...extraHeaders,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (authMethod === 'basic') {
|
|
37
|
+
headers['Authorization'] = `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const response = await fetch(tokenUrl, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers,
|
|
43
|
+
body: body.toString(),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
const errorText = await response.text().catch(() => 'unknown')
|
|
48
|
+
throw new Error(`OAuth token request failed (${response.status}): ${errorText}`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const data = await response.json() as { access_token: string }
|
|
52
|
+
return data.access_token
|
|
53
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs a function in the background without blocking the caller.
|
|
3
|
+
* Errors are logged but not propagated.
|
|
4
|
+
*
|
|
5
|
+
* Uses setImmediate to defer execution to the next event loop iteration,
|
|
6
|
+
* allowing the caller to return immediately (non-blocking).
|
|
7
|
+
*
|
|
8
|
+
* @param fn - Async function to run in background
|
|
9
|
+
* @param label - Optional label for error logging
|
|
10
|
+
*/
|
|
11
|
+
export function runInBackground(fn: () => Promise<void>, label?: string): void {
|
|
12
|
+
setImmediate(() => {
|
|
13
|
+
fn().catch((err) => {
|
|
14
|
+
console.error(`[background${label ? `:${label}` : ''}] Error:`, err)
|
|
15
|
+
})
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sleep helper for retry delays
|
|
21
|
+
*/
|
|
22
|
+
export function sleep(ms: number): Promise<void> {
|
|
23
|
+
return new Promise((resolve) => setTimeout(resolve, ms))
|
|
24
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BIC Facility Code API v2 Client
|
|
3
|
+
*
|
|
4
|
+
* Provides facility enrichment data (coordinates, addresses, operator names)
|
|
5
|
+
* from the BIC Facility Code Database.
|
|
6
|
+
*
|
|
7
|
+
* API Documentation: https://app.swaggerhub.com/apis/BIC-ORG/Facility-Codes/2.0.1
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ─── Types ───────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
export interface BicTokenResponse {
|
|
13
|
+
accessToken: string
|
|
14
|
+
access_token: string // Also provided for compatibility
|
|
15
|
+
accessTokenExpiresAt: string // ISO datetime
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BicAddress {
|
|
19
|
+
street?: string
|
|
20
|
+
city?: string
|
|
21
|
+
postcode?: string
|
|
22
|
+
state?: string
|
|
23
|
+
country?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface BicCoordinates {
|
|
27
|
+
latitude: string // Note: strings in BIC API, need to parse
|
|
28
|
+
longitude: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface BicFacilityDetails {
|
|
32
|
+
name: string
|
|
33
|
+
address?: BicAddress
|
|
34
|
+
formattedAddress?: string
|
|
35
|
+
geographicalCoordinate?: BicCoordinates
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface BicOperator {
|
|
39
|
+
name: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface BicFacility {
|
|
43
|
+
code: string
|
|
44
|
+
codeProvider: 'BIC' | 'SMDG'
|
|
45
|
+
countryCode: string
|
|
46
|
+
unLocode: string
|
|
47
|
+
aliasCode?: string // If this code is deprecated
|
|
48
|
+
codeListProviderCode?: string // Short code for SMDG
|
|
49
|
+
operator?: BicOperator
|
|
50
|
+
facility?: BicFacilityDetails
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface BicClientConfig {
|
|
54
|
+
baseUrl: string
|
|
55
|
+
username: string
|
|
56
|
+
password: string
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ─── Client ──────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
export class BicApiClient {
|
|
62
|
+
private baseUrl: string
|
|
63
|
+
private username: string
|
|
64
|
+
private password: string
|
|
65
|
+
private accessToken: string | null = null
|
|
66
|
+
private tokenExpiresAt: Date | null = null
|
|
67
|
+
|
|
68
|
+
constructor(config: BicClientConfig) {
|
|
69
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, '') // Remove trailing slash
|
|
70
|
+
this.username = config.username
|
|
71
|
+
this.password = config.password
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Get OAuth2 token via Basic Auth
|
|
76
|
+
*/
|
|
77
|
+
private async getToken(): Promise<string> {
|
|
78
|
+
const now = new Date()
|
|
79
|
+
// Refresh if token expires in less than 60 seconds
|
|
80
|
+
if (this.accessToken && this.tokenExpiresAt && this.tokenExpiresAt > new Date(now.getTime() + 60_000)) {
|
|
81
|
+
return this.accessToken
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const credentials = Buffer.from(`${this.username}:${this.password}`).toString('base64')
|
|
85
|
+
|
|
86
|
+
const response = await fetch(`${this.baseUrl}/v2/oauth/token`, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: {
|
|
89
|
+
'Authorization': `Basic ${credentials}`,
|
|
90
|
+
'Content-Type': 'application/json',
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
const text = await response.text()
|
|
96
|
+
throw new Error(`BIC OAuth failed: ${response.status} - ${text}`)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const data: BicTokenResponse = await response.json()
|
|
100
|
+
this.accessToken = data.accessToken || data.access_token
|
|
101
|
+
this.tokenExpiresAt = new Date(data.accessTokenExpiresAt)
|
|
102
|
+
return this.accessToken
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Look up facility by code
|
|
107
|
+
*
|
|
108
|
+
* @param facilityCode - The facility code (BIC: 9 chars, SMDG: varies)
|
|
109
|
+
* @param codeProvider - 'BIC' or 'SMDG'
|
|
110
|
+
* @param unlocode - Required for SMDG codes to build the full lookup code
|
|
111
|
+
* @returns Facility data or null if not found
|
|
112
|
+
*/
|
|
113
|
+
async getFacility(
|
|
114
|
+
facilityCode: string,
|
|
115
|
+
codeProvider: 'BIC' | 'SMDG',
|
|
116
|
+
unlocode?: string
|
|
117
|
+
): Promise<BicFacility | null> {
|
|
118
|
+
const token = await this.getToken()
|
|
119
|
+
|
|
120
|
+
// Build lookup code:
|
|
121
|
+
// - BIC codes are already complete (9 chars)
|
|
122
|
+
// - SMDG codes need unlocode prefix (e.g., "PLGDY" + "DCT" = "PLGDYDCT")
|
|
123
|
+
const lookupCode = codeProvider === 'SMDG' && unlocode
|
|
124
|
+
? `${unlocode}${facilityCode}`
|
|
125
|
+
: facilityCode
|
|
126
|
+
|
|
127
|
+
const url = `${this.baseUrl}/v2/facilities/${lookupCode}?codeProvider=${codeProvider}`
|
|
128
|
+
|
|
129
|
+
const response = await fetch(url, {
|
|
130
|
+
headers: { 'Authorization': `Bearer ${token}` },
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
if (response.status === 404) {
|
|
134
|
+
return null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!response.ok) {
|
|
138
|
+
const text = await response.text()
|
|
139
|
+
throw new Error(`BIC API error: ${response.status} - ${text}`)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return response.json()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Test connection by fetching a token
|
|
147
|
+
* @returns true if authentication succeeds
|
|
148
|
+
*/
|
|
149
|
+
async testConnection(): Promise<boolean> {
|
|
150
|
+
await this.getToken()
|
|
151
|
+
return true
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ─── Static Helpers ──────────────────────────────────────────
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Parse coordinates from BIC response (strings to numbers)
|
|
158
|
+
*/
|
|
159
|
+
static parseCoordinates(facility: BicFacility): { latitude: number; longitude: number } | null {
|
|
160
|
+
const coords = facility.facility?.geographicalCoordinate
|
|
161
|
+
if (!coords?.latitude || !coords?.longitude) return null
|
|
162
|
+
|
|
163
|
+
const lat = parseFloat(coords.latitude)
|
|
164
|
+
const lng = parseFloat(coords.longitude)
|
|
165
|
+
|
|
166
|
+
if (isNaN(lat) || isNaN(lng)) return null
|
|
167
|
+
return { latitude: lat, longitude: lng }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Format address from BIC response
|
|
172
|
+
*/
|
|
173
|
+
static formatAddress(facility: BicFacility): string | null {
|
|
174
|
+
// Prefer formatted address if available
|
|
175
|
+
if (facility.facility?.formattedAddress) {
|
|
176
|
+
return facility.facility.formattedAddress
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const addr = facility.facility?.address
|
|
180
|
+
if (!addr) return null
|
|
181
|
+
|
|
182
|
+
const parts = [addr.street, addr.city, addr.state, addr.postcode, addr.country]
|
|
183
|
+
return parts.filter(Boolean).join(', ') || null
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Get facility name from BIC response
|
|
188
|
+
*/
|
|
189
|
+
static getFacilityName(facility: BicFacility): string | null {
|
|
190
|
+
return facility.facility?.name || null
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get operator name from BIC response
|
|
195
|
+
*/
|
|
196
|
+
static getOperatorName(facility: BicFacility): string | null {
|
|
197
|
+
return facility.operator?.name || null
|
|
198
|
+
}
|
|
199
|
+
}
|