@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,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/shipment_tracking/services/poiNatsService.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * POI NATS Subscriber Service\n *\n * Subscribes to POI proximity events from the AIS system via NATS JetStream\n * and processes them to create tracking events and notifications.\n */\n\nimport type { NatsConnection, JetStreamClient, JetStreamManager, Consumer, ConsumerMessages } from 'nats'\nimport { connect, JSONCodec, AckPolicy, DeliverPolicy, ReplayPolicy } from 'nats'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport type { EventBus } from '@open-mercato/events'\nimport { loadPoiNatsConfig, validatePoiNatsConfig, isPoiNatsConfigured, type PoiNatsConfig } from '../lib/poi-nats-config'\nimport type { PoiProximityEvent } from '../lib/poi-types'\nimport { getJobPoiEventId } from '../lib/poi-types'\nimport { mapToOpenMercatoEventId } from '../lib/poi-event-processor'\nimport {\n processPoiEvent,\n isEventAlreadyProcessed,\n createTrackingEventFromPoi,\n} from '../lib/poi-event-processor'\nimport { Shipment } from '../data/entities'\nimport { trackingLogger } from '../lib/logger'\nimport type { TrackingService } from './trackingService'\n\nconst LOG_COMPONENT = 'poi-nats'\n\n// \u2500\u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ntype PoiNatsServiceDeps = {\n em: () => EntityManager\n eventBus: EventBus\n trackingService: TrackingService\n}\n\ntype ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'draining' | 'closed'\n\nexport type PoiNatsServiceStats = {\n status: ConnectionStatus\n messagesReceived: number\n messagesProcessed: number\n eventsCreated: number\n errors: number\n lastMessageAt: Date | null\n connectedAt: Date | null\n}\n\n// \u2500\u2500\u2500 Service \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class PoiNatsService {\n private deps: PoiNatsServiceDeps\n private config: PoiNatsConfig\n private connection: NatsConnection | null = null\n private jetstream: JetStreamClient | null = null\n private consumer: Consumer | null = null\n private consumerMessages: ConsumerMessages | null = null\n private status: ConnectionStatus = 'disconnected'\n private stats: PoiNatsServiceStats = {\n status: 'disconnected',\n messagesReceived: 0,\n messagesProcessed: 0,\n eventsCreated: 0,\n errors: 0,\n lastMessageAt: null,\n connectedAt: null,\n }\n\n /**\n * Track per-job events already emitted in this batch to avoid duplicates.\n * Key format: `${trackingJobId}:${eventType}:${sourceEventId}`\n */\n private emittedJobEvents: Set<string> = new Set()\n\n constructor(deps: PoiNatsServiceDeps) {\n this.deps = deps\n this.config = loadPoiNatsConfig()\n }\n\n /**\n * Get current service statistics.\n */\n getStats(): PoiNatsServiceStats {\n return { ...this.stats, status: this.status }\n }\n\n /**\n * Check if the service is connected.\n */\n isConnected(): boolean {\n return this.status === 'connected'\n }\n\n /**\n * Check if POI NATS integration is configured.\n */\n isConfigured(): boolean {\n return isPoiNatsConfigured()\n }\n\n /**\n * Start the NATS subscriber.\n */\n async start(): Promise<void> {\n if (!isPoiNatsConfigured()) {\n trackingLogger.info('POI_NATS_URL not configured, skipping POI event subscription', {\n component: LOG_COMPONENT,\n })\n return\n }\n\n if (this.status === 'connected' || this.status === 'connecting') {\n trackingLogger.warn('Service is already started or connecting', {\n component: LOG_COMPONENT,\n status: this.status,\n })\n return\n }\n\n try {\n validatePoiNatsConfig(this.config)\n this.status = 'connecting'\n\n trackingLogger.info('Connecting to NATS server', {\n component: LOG_COMPONENT,\n serverUrl: this.config.serverUrl,\n })\n\n this.connection = await connect({\n servers: this.config.serverUrl,\n name: this.config.connectionName,\n reconnect: true,\n maxReconnectAttempts: this.config.reconnect.maxAttempts,\n reconnectTimeWait: this.config.reconnect.initialDelayMs,\n reconnectJitter: this.config.reconnect.maxDelayMs - this.config.reconnect.initialDelayMs,\n })\n\n this.status = 'connected'\n this.stats.connectedAt = new Date()\n\n trackingLogger.info('Connected to NATS server', { component: LOG_COMPONENT })\n\n // Set up connection event handlers\n this.setupConnectionHandlers()\n\n // Subscribe to POI events\n await this.subscribe()\n\n trackingLogger.info('Subscribed to POI subject', {\n component: LOG_COMPONENT,\n subject: this.config.subject,\n })\n } catch (error) {\n this.status = 'disconnected'\n trackingLogger.error('Failed to connect to NATS', {\n component: LOG_COMPONENT,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n throw error\n }\n }\n\n /**\n * Stop the NATS subscriber gracefully.\n */\n async stop(): Promise<void> {\n if (!this.connection) {\n return\n }\n\n this.status = 'draining'\n trackingLogger.info('Draining NATS connection', { component: LOG_COMPONENT })\n\n try {\n // Stop consuming messages first\n if (this.consumerMessages) {\n this.consumerMessages.stop()\n this.consumerMessages = null\n }\n\n this.consumer = null\n this.jetstream = null\n\n // Drain and close connection\n await this.connection.drain()\n this.connection = null\n this.status = 'closed'\n\n trackingLogger.info('NATS connection closed', { component: LOG_COMPONENT })\n } catch (error) {\n trackingLogger.error('Error during NATS shutdown', {\n component: LOG_COMPONENT,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n this.status = 'disconnected'\n throw error\n }\n }\n\n /**\n * Subscribe to POI proximity events via JetStream.\n *\n * Auto-creates the durable consumer if it doesn't exist.\n * Each instance gets a unique consumer name (based on JWT_SECRET hash)\n * so multiple self-hosted installations can each receive all messages.\n */\n private async subscribe(): Promise<void> {\n if (!this.connection) {\n throw new Error('Not connected to NATS')\n }\n\n // Get JetStream manager for consumer management\n const jsm = await this.connection.jetstreamManager()\n\n // Ensure consumer exists (create if not)\n await this.ensureConsumer(jsm)\n\n // Get JetStream client for consuming\n this.jetstream = this.connection.jetstream()\n\n trackingLogger.debug('Binding to JetStream consumer', {\n component: LOG_COMPONENT,\n consumerName: this.config.consumerName,\n streamName: this.config.streamName,\n })\n\n // Bind to the durable consumer\n this.consumer = await this.jetstream.consumers.get(\n this.config.streamName,\n this.config.consumerName\n )\n\n trackingLogger.debug('Consumer bound, starting to consume messages', {\n component: LOG_COMPONENT,\n consumerName: this.config.consumerName,\n })\n\n // Start consuming messages\n this.consumerMessages = await this.consumer.consume()\n\n // Process messages asynchronously\n this.processMessages()\n }\n\n /**\n * Ensure the durable consumer exists on the stream.\n * Creates it if it doesn't exist with the appropriate configuration.\n */\n private async ensureConsumer(jsm: JetStreamManager): Promise<void> {\n const consumerConfig = {\n durable_name: this.config.consumerName,\n ack_policy: AckPolicy.Explicit,\n deliver_policy: DeliverPolicy.All, // Replay all messages from stream start\n replay_policy: ReplayPolicy.Instant, // Don't throttle replay\n filter_subject: this.config.subject,\n max_deliver: 5, // Prevent infinite redelivery of poison messages\n }\n\n try {\n // Check if consumer exists\n await jsm.consumers.info(this.config.streamName, this.config.consumerName)\n trackingLogger.debug('Consumer exists', {\n component: LOG_COMPONENT,\n consumerName: this.config.consumerName,\n })\n } catch (error: unknown) {\n // Consumer doesn't exist, create it\n const errorCode = (error as { code?: string })?.code\n if (errorCode === '404' || (error as { api_error?: { err_code?: number } })?.api_error?.err_code === 10014) {\n trackingLogger.info('Creating JetStream consumer', {\n component: LOG_COMPONENT,\n consumerName: this.config.consumerName,\n streamName: this.config.streamName,\n })\n await jsm.consumers.add(this.config.streamName, consumerConfig)\n trackingLogger.info('JetStream consumer created', {\n component: LOG_COMPONENT,\n consumerName: this.config.consumerName,\n })\n } else {\n // Some other error, rethrow\n throw error\n }\n }\n }\n\n /**\n * Process incoming messages from the JetStream consumer.\n */\n private async processMessages(): Promise<void> {\n if (!this.consumerMessages) {\n return\n }\n\n const jsonCodec = JSONCodec<PoiProximityEvent>()\n\n for await (const msg of this.consumerMessages) {\n this.stats.messagesReceived++\n this.stats.lastMessageAt = new Date()\n\n try {\n const event = jsonCodec.decode(msg.data)\n \n // Validate required fields - skip malformed/test messages\n if (!event || !event.type || !event.mmsi) {\n trackingLogger.debug('Skipping invalid message (missing type or mmsi)', {\n component: LOG_COMPONENT,\n })\n msg.ack() // Ack to prevent redelivery of bad messages\n continue\n }\n\n await this.handlePoiEvent(event)\n\n // Acknowledge successful processing\n msg.ack()\n this.stats.messagesProcessed++\n } catch (error) {\n this.stats.errors++\n trackingLogger.error('Error processing NATS message', {\n component: LOG_COMPONENT,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n\n // Negative acknowledge - message will be redelivered\n msg.nak()\n }\n }\n }\n\n /**\n * Handle a single POI proximity event.\n */\n private async handlePoiEvent(event: PoiProximityEvent): Promise<void> {\n // Clear job event deduplication set at start of each message\n // This ensures a clean slate and prevents silent event drops on retry\n this.emittedJobEvents.clear()\n\n trackingLogger.debug('Received POI event', {\n component: LOG_COMPONENT,\n eventType: event.type,\n vesselName: event.shipName,\n mmsi: event.mmsi,\n })\n\n // Fork a fresh, cleared EM per message: this worker resolves the container once\n // and loops forever, so reusing the container EM would leak its identity map.\n const em = this.deps.em().fork({ clear: true })\n\n try {\n // Process the event and find matching shipments\n const processed = await processPoiEvent(em, event)\n\n if (!processed) {\n // No matching shipments found\n return\n }\n\n trackingLogger.info('Matched shipments for POI event', {\n component: LOG_COMPONENT,\n mmsi: event.mmsi,\n eventType: event.type,\n matchedShipmentCount: processed.shipmentIds.length,\n })\n\n // Track which tracking jobs got a new event, so we can re-derive their shipments'\n // denormalized state (Journey Timeline / status / ETA) afterwards. POI events are\n // TRANSPORT (vessel) events that apply to every container on the job, and dedup means\n // only the first container actually creates the TrackingEvent \u2014 so we refresh the\n // WHOLE job, not just the container where the row was created.\n const affectedJobIds = new Set<string>()\n\n // Process each matched shipment\n for (const shipmentId of processed.shipmentIds) {\n const shipment = await em.findOne(\n Shipment,\n { id: shipmentId },\n { populate: ['trackingJob'] }\n )\n\n if (!shipment?.trackingJob) {\n continue\n }\n\n // Check for duplicates\n const alreadyProcessed = await isEventAlreadyProcessed(\n em,\n shipment.trackingJob.id,\n processed.sourceEventId\n )\n\n if (alreadyProcessed) {\n trackingLogger.debug('Event already processed', {\n component: LOG_COMPONENT,\n sourceEventId: processed.sourceEventId,\n trackingJobId: shipment.trackingJob.id,\n })\n continue\n }\n\n // Create TrackingEvent record\n const trackingEvent = createTrackingEventFromPoi(processed, shipment.trackingJob)\n em.persist(trackingEvent)\n this.stats.eventsCreated++\n\n affectedJobIds.add(shipment.trackingJob.id)\n\n // Emit per-shipment event (for webhooks/external integrations)\n const shipmentEventId = mapToOpenMercatoEventId(event.type)\n await this.deps.eventBus.emit(shipmentEventId, {\n shipmentId: shipment.id,\n trackingEventId: trackingEvent.id,\n organizationId: shipment.organizationId,\n tenantId: shipment.tenantId,\n vesselName: event.shipName,\n vesselMmsi: event.mmsi,\n vesselImo: processed.vesselImo,\n eventType: event.type,\n poiCode: processed.poiCode,\n latitude: event.lat,\n longitude: event.lng,\n eventDateTime: processed.eventDateTime.toISOString(),\n distanceToPoiMeters: event.distanceToPoiMeters,\n })\n\n // Emit per-job event (for in-app notifications) - only once per tracking job\n // This avoids duplicate notifications for multi-container bookings\n const trackingJobId = shipment.trackingJob.id\n const jobEventKey = `${trackingJobId}:${event.type}:${processed.sourceEventId}`\n if (!this.emittedJobEvents.has(jobEventKey)) {\n this.emittedJobEvents.add(jobEventKey)\n\n const jobEventId = getJobPoiEventId(event.type)\n await this.deps.eventBus.emit(jobEventId, {\n trackingJobId,\n shipmentId: shipment.id,\n trackingEventId: trackingEvent.id,\n organizationId: shipment.organizationId,\n tenantId: shipment.tenantId,\n vesselName: event.shipName,\n vesselMmsi: event.mmsi,\n vesselImo: processed.vesselImo,\n eventType: event.type,\n poiCode: processed.poiCode,\n latitude: event.lat,\n longitude: event.lng,\n eventDateTime: processed.eventDateTime.toISOString(),\n distanceToPoiMeters: event.distanceToPoiMeters,\n // Include shipment reference info for notification body\n containerNumber: shipment.containerNumber,\n bookingNumber: shipment.bookingNumber,\n bolNumber: shipment.bolNumber,\n })\n\n trackingLogger.debug('Emitted per-job POI event', {\n component: LOG_COMPONENT,\n trackingJobId,\n eventType: event.type,\n })\n }\n\n trackingLogger.info('Created tracking event from POI', {\n component: LOG_COMPONENT,\n shipmentId,\n eventType: event.type,\n trackingEventId: trackingEvent.id,\n })\n }\n\n await em.flush()\n\n // Re-derive denormalized state so AIS arrivals appear in the Journey Timeline and\n // update status/ETA in real time, instead of waiting for the next carrier poll.\n for (const trackingJobId of affectedJobIds) {\n await this.deps.trackingService.refreshShipmentsFromEvents(em, trackingJobId)\n }\n } catch (error) {\n trackingLogger.error('Error handling POI event', {\n component: LOG_COMPONENT,\n eventType: event.type,\n mmsi: event.mmsi,\n error: error instanceof Error ? error.message : String(error),\n stack: error instanceof Error ? error.stack : undefined,\n })\n throw error\n }\n }\n\n /**\n * Set up connection event handlers.\n */\n private setupConnectionHandlers(): void {\n if (!this.connection) {\n return\n }\n\n // Handle connection status changes\n ;(async () => {\n if (!this.connection) return\n\n for await (const status of this.connection.status()) {\n switch (status.type) {\n case 'disconnect':\n trackingLogger.warn('Disconnected from NATS server', { component: LOG_COMPONENT })\n this.status = 'disconnected'\n break\n case 'reconnect':\n trackingLogger.info('Reconnected to NATS server', { component: LOG_COMPONENT })\n this.status = 'connected'\n break\n case 'reconnecting':\n trackingLogger.info('Reconnecting to NATS server', { component: LOG_COMPONENT })\n this.status = 'connecting'\n break\n case 'error':\n trackingLogger.error('NATS connection error', {\n component: LOG_COMPONENT,\n data: status.data,\n })\n break\n }\n }\n })()\n }\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,SAAS,WAAW,WAAW,eAAe,oBAAoB;AAG3E,SAAS,mBAAmB,uBAAuB,2BAA+C;AAElG,SAAS,wBAAwB;AACjC,SAAS,+BAA+B;AACxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAG/B,MAAM,gBAAgB;AAwBf,MAAM,eAAe;AAAA,EAwB1B,YAAY,MAA0B;AArBtC,SAAQ,aAAoC;AAC5C,SAAQ,YAAoC;AAC5C,SAAQ,WAA4B;AACpC,SAAQ,mBAA4C;AACpD,SAAQ,SAA2B;AACnC,SAAQ,QAA6B;AAAA,MACnC,QAAQ;AAAA,MACR,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,MACnB,eAAe;AAAA,MACf,QAAQ;AAAA,MACR,eAAe;AAAA,MACf,aAAa;AAAA,IACf;AAMA;AAAA;AAAA;AAAA;AAAA,SAAQ,mBAAgC,oBAAI,IAAI;AAG9C,SAAK,OAAO;AACZ,SAAK,SAAS,kBAAkB;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,WAAgC;AAC9B,WAAO,EAAE,GAAG,KAAK,OAAO,QAAQ,KAAK,OAAO;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,eAAwB;AACtB,WAAO,oBAAoB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,QAAI,CAAC,oBAAoB,GAAG;AAC1B,qBAAe,KAAK,gEAAgE;AAAA,QAClF,WAAW;AAAA,MACb,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,eAAe,KAAK,WAAW,cAAc;AAC/D,qBAAe,KAAK,4CAA4C;AAAA,QAC9D,WAAW;AAAA,QACX,QAAQ,KAAK;AAAA,MACf,CAAC;AACD;AAAA,IACF;AAEA,QAAI;AACF,4BAAsB,KAAK,MAAM;AACjC,WAAK,SAAS;AAEd,qBAAe,KAAK,6BAA6B;AAAA,QAC/C,WAAW;AAAA,QACX,WAAW,KAAK,OAAO;AAAA,MACzB,CAAC;AAED,WAAK,aAAa,MAAM,QAAQ;AAAA,QAC9B,SAAS,KAAK,OAAO;AAAA,QACrB,MAAM,KAAK,OAAO;AAAA,QAClB,WAAW;AAAA,QACX,sBAAsB,KAAK,OAAO,UAAU;AAAA,QAC5C,mBAAmB,KAAK,OAAO,UAAU;AAAA,QACzC,iBAAiB,KAAK,OAAO,UAAU,aAAa,KAAK,OAAO,UAAU;AAAA,MAC5E,CAAC;AAED,WAAK,SAAS;AACd,WAAK,MAAM,cAAc,oBAAI,KAAK;AAElC,qBAAe,KAAK,4BAA4B,EAAE,WAAW,cAAc,CAAC;AAG5E,WAAK,wBAAwB;AAG7B,YAAM,KAAK,UAAU;AAErB,qBAAe,KAAK,6BAA6B;AAAA,QAC/C,WAAW;AAAA,QACX,SAAS,KAAK,OAAO;AAAA,MACvB,CAAC;AAAA,IACH,SAAS,OAAO;AACd,WAAK,SAAS;AACd,qBAAe,MAAM,6BAA6B;AAAA,QAChD,WAAW;AAAA,QACX,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC5D,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MAChD,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAsB;AAC1B,QAAI,CAAC,KAAK,YAAY;AACpB;AAAA,IACF;AAEA,SAAK,SAAS;AACd,mBAAe,KAAK,4BAA4B,EAAE,WAAW,cAAc,CAAC;AAE5E,QAAI;AAEF,UAAI,KAAK,kBAAkB;AACzB,aAAK,iBAAiB,KAAK;AAC3B,aAAK,mBAAmB;AAAA,MAC1B;AAEA,WAAK,WAAW;AAChB,WAAK,YAAY;AAGjB,YAAM,KAAK,WAAW,MAAM;AAC5B,WAAK,aAAa;AAClB,WAAK,SAAS;AAEd,qBAAe,KAAK,0BAA0B,EAAE,WAAW,cAAc,CAAC;AAAA,IAC5E,SAAS,OAAO;AACd,qBAAe,MAAM,8BAA8B;AAAA,QACjD,WAAW;AAAA,QACX,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC5D,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MAChD,CAAC;AACD,WAAK,SAAS;AACd,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,YAA2B;AACvC,QAAI,CAAC,KAAK,YAAY;AACpB,YAAM,IAAI,MAAM,uBAAuB;AAAA,IACzC;AAGA,UAAM,MAAM,MAAM,KAAK,WAAW,iBAAiB;AAGnD,UAAM,KAAK,eAAe,GAAG;AAG7B,SAAK,YAAY,KAAK,WAAW,UAAU;AAE3C,mBAAe,MAAM,iCAAiC;AAAA,MACpD,WAAW;AAAA,MACX,cAAc,KAAK,OAAO;AAAA,MAC1B,YAAY,KAAK,OAAO;AAAA,IAC1B,CAAC;AAGD,SAAK,WAAW,MAAM,KAAK,UAAU,UAAU;AAAA,MAC7C,KAAK,OAAO;AAAA,MACZ,KAAK,OAAO;AAAA,IACd;AAEA,mBAAe,MAAM,gDAAgD;AAAA,MACnE,WAAW;AAAA,MACX,cAAc,KAAK,OAAO;AAAA,IAC5B,CAAC;AAGD,SAAK,mBAAmB,MAAM,KAAK,SAAS,QAAQ;AAGpD,SAAK,gBAAgB;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,eAAe,KAAsC;AACjE,UAAM,iBAAiB;AAAA,MACrB,cAAc,KAAK,OAAO;AAAA,MAC1B,YAAY,UAAU;AAAA,MACtB,gBAAgB,cAAc;AAAA;AAAA,MAC9B,eAAe,aAAa;AAAA;AAAA,MAC5B,gBAAgB,KAAK,OAAO;AAAA,MAC5B,aAAa;AAAA;AAAA,IACf;AAEA,QAAI;AAEF,YAAM,IAAI,UAAU,KAAK,KAAK,OAAO,YAAY,KAAK,OAAO,YAAY;AACzE,qBAAe,MAAM,mBAAmB;AAAA,QACtC,WAAW;AAAA,QACX,cAAc,KAAK,OAAO;AAAA,MAC5B,CAAC;AAAA,IACH,SAAS,OAAgB;AAEvB,YAAM,YAAa,OAA6B;AAChD,UAAI,cAAc,SAAU,OAAiD,WAAW,aAAa,OAAO;AAC1G,uBAAe,KAAK,+BAA+B;AAAA,UACjD,WAAW;AAAA,UACX,cAAc,KAAK,OAAO;AAAA,UAC1B,YAAY,KAAK,OAAO;AAAA,QAC1B,CAAC;AACD,cAAM,IAAI,UAAU,IAAI,KAAK,OAAO,YAAY,cAAc;AAC9D,uBAAe,KAAK,8BAA8B;AAAA,UAChD,WAAW;AAAA,UACX,cAAc,KAAK,OAAO;AAAA,QAC5B,CAAC;AAAA,MACH,OAAO;AAEL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,kBAAiC;AAC7C,QAAI,CAAC,KAAK,kBAAkB;AAC1B;AAAA,IACF;AAEA,UAAM,YAAY,UAA6B;AAE/C,qBAAiB,OAAO,KAAK,kBAAkB;AAC7C,WAAK,MAAM;AACX,WAAK,MAAM,gBAAgB,oBAAI,KAAK;AAEpC,UAAI;AACF,cAAM,QAAQ,UAAU,OAAO,IAAI,IAAI;AAGvC,YAAI,CAAC,SAAS,CAAC,MAAM,QAAQ,CAAC,MAAM,MAAM;AACxC,yBAAe,MAAM,mDAAmD;AAAA,YACtE,WAAW;AAAA,UACb,CAAC;AACD,cAAI,IAAI;AACR;AAAA,QACF;AAEA,cAAM,KAAK,eAAe,KAAK;AAG/B,YAAI,IAAI;AACR,aAAK,MAAM;AAAA,MACb,SAAS,OAAO;AACd,aAAK,MAAM;AACX,uBAAe,MAAM,iCAAiC;AAAA,UACpD,WAAW;AAAA,UACX,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,UAC5D,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,QAChD,CAAC;AAGD,YAAI,IAAI;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAe,OAAyC;AAGpE,SAAK,iBAAiB,MAAM;AAE5B,mBAAe,MAAM,sBAAsB;AAAA,MACzC,WAAW;AAAA,MACX,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,MAAM,MAAM;AAAA,IACd,CAAC;AAID,UAAM,KAAK,KAAK,KAAK,GAAG,EAAE,KAAK,EAAE,OAAO,KAAK,CAAC;AAE9C,QAAI;AAEF,YAAM,YAAY,MAAM,gBAAgB,IAAI,KAAK;AAEjD,UAAI,CAAC,WAAW;AAEd;AAAA,MACF;AAEA,qBAAe,KAAK,mCAAmC;AAAA,QACrD,WAAW;AAAA,QACX,MAAM,MAAM;AAAA,QACZ,WAAW,MAAM;AAAA,QACjB,sBAAsB,UAAU,YAAY;AAAA,MAC9C,CAAC;AAOD,YAAM,iBAAiB,oBAAI,IAAY;AAGvC,iBAAW,cAAc,UAAU,aAAa;AAC9C,cAAM,WAAW,MAAM,GAAG;AAAA,UACxB;AAAA,UACA,EAAE,IAAI,WAAW;AAAA,UACjB,EAAE,UAAU,CAAC,aAAa,EAAE;AAAA,QAC9B;AAEA,YAAI,CAAC,UAAU,aAAa;AAC1B;AAAA,QACF;AAGA,cAAM,mBAAmB,MAAM;AAAA,UAC7B;AAAA,UACA,SAAS,YAAY;AAAA,UACrB,UAAU;AAAA,QACZ;AAEA,YAAI,kBAAkB;AACpB,yBAAe,MAAM,2BAA2B;AAAA,YAC9C,WAAW;AAAA,YACX,eAAe,UAAU;AAAA,YACzB,eAAe,SAAS,YAAY;AAAA,UACtC,CAAC;AACD;AAAA,QACF;AAGA,cAAM,gBAAgB,2BAA2B,WAAW,SAAS,WAAW;AAChF,WAAG,QAAQ,aAAa;AACxB,aAAK,MAAM;AAEX,uBAAe,IAAI,SAAS,YAAY,EAAE;AAG1C,cAAM,kBAAkB,wBAAwB,MAAM,IAAI;AAC1D,cAAM,KAAK,KAAK,SAAS,KAAK,iBAAiB;AAAA,UAC7C,YAAY,SAAS;AAAA,UACrB,iBAAiB,cAAc;AAAA,UAC/B,gBAAgB,SAAS;AAAA,UACzB,UAAU,SAAS;AAAA,UACnB,YAAY,MAAM;AAAA,UAClB,YAAY,MAAM;AAAA,UAClB,WAAW,UAAU;AAAA,UACrB,WAAW,MAAM;AAAA,UACjB,SAAS,UAAU;AAAA,UACnB,UAAU,MAAM;AAAA,UAChB,WAAW,MAAM;AAAA,UACjB,eAAe,UAAU,cAAc,YAAY;AAAA,UACnD,qBAAqB,MAAM;AAAA,QAC7B,CAAC;AAID,cAAM,gBAAgB,SAAS,YAAY;AAC3C,cAAM,cAAc,GAAG,aAAa,IAAI,MAAM,IAAI,IAAI,UAAU,aAAa;AAC7E,YAAI,CAAC,KAAK,iBAAiB,IAAI,WAAW,GAAG;AAC3C,eAAK,iBAAiB,IAAI,WAAW;AAErC,gBAAM,aAAa,iBAAiB,MAAM,IAAI;AAC9C,gBAAM,KAAK,KAAK,SAAS,KAAK,YAAY;AAAA,YACxC;AAAA,YACA,YAAY,SAAS;AAAA,YACrB,iBAAiB,cAAc;AAAA,YAC/B,gBAAgB,SAAS;AAAA,YACzB,UAAU,SAAS;AAAA,YACnB,YAAY,MAAM;AAAA,YAClB,YAAY,MAAM;AAAA,YAClB,WAAW,UAAU;AAAA,YACrB,WAAW,MAAM;AAAA,YACjB,SAAS,UAAU;AAAA,YACnB,UAAU,MAAM;AAAA,YAChB,WAAW,MAAM;AAAA,YACjB,eAAe,UAAU,cAAc,YAAY;AAAA,YACnD,qBAAqB,MAAM;AAAA;AAAA,YAE3B,iBAAiB,SAAS;AAAA,YAC1B,eAAe,SAAS;AAAA,YACxB,WAAW,SAAS;AAAA,UACtB,CAAC;AAED,yBAAe,MAAM,6BAA6B;AAAA,YAChD,WAAW;AAAA,YACX;AAAA,YACA,WAAW,MAAM;AAAA,UACnB,CAAC;AAAA,QACH;AAEA,uBAAe,KAAK,mCAAmC;AAAA,UACrD,WAAW;AAAA,UACX;AAAA,UACA,WAAW,MAAM;AAAA,UACjB,iBAAiB,cAAc;AAAA,QACjC,CAAC;AAAA,MACH;AAEA,YAAM,GAAG,MAAM;AAIf,iBAAW,iBAAiB,gBAAgB;AAC1C,cAAM,KAAK,KAAK,gBAAgB,2BAA2B,IAAI,aAAa;AAAA,MAC9E;AAAA,IACF,SAAS,OAAO;AACd,qBAAe,MAAM,4BAA4B;AAAA,QAC/C,WAAW;AAAA,QACX,WAAW,MAAM;AAAA,QACjB,MAAM,MAAM;AAAA,QACZ,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC5D,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MAChD,CAAC;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAAgC;AACtC,QAAI,CAAC,KAAK,YAAY;AACpB;AAAA,IACF;AAGA;AAAC,KAAC,YAAY;AACZ,UAAI,CAAC,KAAK,WAAY;AAEtB,uBAAiB,UAAU,KAAK,WAAW,OAAO,GAAG;AACnD,gBAAQ,OAAO,MAAM;AAAA,UACnB,KAAK;AACH,2BAAe,KAAK,iCAAiC,EAAE,WAAW,cAAc,CAAC;AACjF,iBAAK,SAAS;AACd;AAAA,UACF,KAAK;AACH,2BAAe,KAAK,8BAA8B,EAAE,WAAW,cAAc,CAAC;AAC9E,iBAAK,SAAS;AACd;AAAA,UACF,KAAK;AACH,2BAAe,KAAK,+BAA+B,EAAE,WAAW,cAAc,CAAC;AAC/E,iBAAK,SAAS;AACd;AAAA,UACF,KAAK;AACH,2BAAe,MAAM,yBAAyB;AAAA,cAC5C,WAAW;AAAA,cACX,MAAM,OAAO;AAAA,YACf,CAAC;AACD;AAAA,QACJ;AAAA,MACF;AAAA,IACF,GAAG;AAAA,EACL;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
2
|
+
import { ShipsGoConfig } from "../data/entities.js";
|
|
3
|
+
import {
|
|
4
|
+
registerOceanShipment,
|
|
5
|
+
getOceanShipment,
|
|
6
|
+
registerAirShipment,
|
|
7
|
+
getAirShipment
|
|
8
|
+
} from "../lib/shipsgo-client.js";
|
|
9
|
+
import { mapOceanShipmentToEvents, mapAirShipmentToEvents } from "../lib/shipsgo-mapper.js";
|
|
10
|
+
import { trackingLogger } from "../lib/logger.js";
|
|
11
|
+
const DEFAULT_BASE_URL = "https://api.shipsgo.com/v2";
|
|
12
|
+
const DEFAULT_RATE_LIMIT = { requests: 60, windowSeconds: 60 };
|
|
13
|
+
const PLATFORM_RATE_LIMIT_IDENTITY = "shipsgo:platform-shared";
|
|
14
|
+
class ShipsGoProvider {
|
|
15
|
+
constructor(deps) {
|
|
16
|
+
this.deps = deps;
|
|
17
|
+
}
|
|
18
|
+
/** Loads the tenant's (non-deleted) ShipsGoConfig row, decrypting the token. */
|
|
19
|
+
async loadRow(scope) {
|
|
20
|
+
const em = this.deps.em();
|
|
21
|
+
return findOneWithDecryption(
|
|
22
|
+
em,
|
|
23
|
+
ShipsGoConfig,
|
|
24
|
+
{
|
|
25
|
+
organizationId: scope.organizationId,
|
|
26
|
+
tenantId: scope.tenantId,
|
|
27
|
+
deletedAt: null
|
|
28
|
+
},
|
|
29
|
+
void 0,
|
|
30
|
+
{ tenantId: scope.tenantId, organizationId: scope.organizationId }
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the ShipsGo client config for a tenant scope.
|
|
35
|
+
*
|
|
36
|
+
* A tenant's own ShipsGoConfig row is **authoritative**: if it exists but is
|
|
37
|
+
* disabled (isEnabled/isActive false), has the requested mode off, or has no
|
|
38
|
+
* token, this returns null and does NOT fall back to the shared platform
|
|
39
|
+
* account — otherwise a tenant who turned ShipsGo off would still spend
|
|
40
|
+
* platform credits. The env fallback (SHIPSGO_API_TOKEN / SHIPSGO_BASE_URL)
|
|
41
|
+
* applies only when the tenant has NO config row at all.
|
|
42
|
+
*/
|
|
43
|
+
/** Pure row → client config (with env fallback when no row). See resolveConfig. */
|
|
44
|
+
configFromRow(row, mode) {
|
|
45
|
+
if (row) {
|
|
46
|
+
if (!row.isEnabled || !row.isActive) return null;
|
|
47
|
+
if (mode === "ocean" && !row.oceanEnabled) return null;
|
|
48
|
+
if (mode === "air" && !row.airEnabled) return null;
|
|
49
|
+
if (!row.apiToken) return null;
|
|
50
|
+
return { apiToken: row.apiToken, baseUrl: row.baseUrl || DEFAULT_BASE_URL };
|
|
51
|
+
}
|
|
52
|
+
const envToken = process.env.SHIPSGO_API_TOKEN;
|
|
53
|
+
if (envToken) {
|
|
54
|
+
return { apiToken: envToken, baseUrl: process.env.SHIPSGO_BASE_URL || DEFAULT_BASE_URL };
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/** Pure row → rate limit (row's values, else the platform default). */
|
|
59
|
+
rateLimitFromRow(row) {
|
|
60
|
+
if (row && row.rateLimitRequests > 0 && row.rateLimitWindowSeconds > 0) {
|
|
61
|
+
return { requests: row.rateLimitRequests, windowSeconds: row.rateLimitWindowSeconds };
|
|
62
|
+
}
|
|
63
|
+
return { ...DEFAULT_RATE_LIMIT };
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Resolves the ShipsGo client config for a tenant scope.
|
|
67
|
+
*
|
|
68
|
+
* A tenant's own ShipsGoConfig row is **authoritative**: if it exists but is
|
|
69
|
+
* disabled (isEnabled/isActive false), has the requested mode off, or has no
|
|
70
|
+
* token, this returns null and does NOT fall back to the shared platform
|
|
71
|
+
* account — otherwise a tenant who turned ShipsGo off would still spend
|
|
72
|
+
* platform credits. The env fallback (SHIPSGO_API_TOKEN / SHIPSGO_BASE_URL)
|
|
73
|
+
* applies only when the tenant has NO config row at all.
|
|
74
|
+
*/
|
|
75
|
+
async resolveConfig(scope, mode) {
|
|
76
|
+
return this.configFromRow(await this.loadRow(scope), mode);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Per-tenant rate limit for ShipsGo polling. Honors the tenant row's
|
|
80
|
+
* rate_limit_* when present, else the platform default (kept under ShipsGo's
|
|
81
|
+
* 100 req/min account-wide ceiling).
|
|
82
|
+
*/
|
|
83
|
+
async resolveRateLimit(scope) {
|
|
84
|
+
return this.rateLimitFromRow(await this.loadRow(scope));
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Everything a poll needs from a SINGLE config read: the client config, the
|
|
88
|
+
* rate limit, and the rate-limit identity (per-tenant for a BYO token; the
|
|
89
|
+
* shared platform identity when falling back to the env token, so all such
|
|
90
|
+
* tenants share one budget against the one ShipsGo account).
|
|
91
|
+
*/
|
|
92
|
+
async resolvePollContext(scope, mode) {
|
|
93
|
+
const row = await this.loadRow(scope);
|
|
94
|
+
return {
|
|
95
|
+
config: this.configFromRow(row, mode),
|
|
96
|
+
rateLimit: this.rateLimitFromRow(row),
|
|
97
|
+
rateLimitIdentity: row ? scope.tenantId : PLATFORM_RATE_LIMIT_IDENTITY
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Fetches events for a ShipsGo-provider tracking job, registering it first if
|
|
102
|
+
* it has no ShipsGo shipment id yet. Persists the id on the job immediately
|
|
103
|
+
* after registration so a crash mid-poll never re-registers (ShipsGo's 409
|
|
104
|
+
* dedup is a second guard). Branches ocean vs air on `job.mode`.
|
|
105
|
+
*
|
|
106
|
+
* `config` may be passed pre-resolved (the poll resolves it once alongside the
|
|
107
|
+
* rate limit); omit it and the provider resolves it itself.
|
|
108
|
+
*/
|
|
109
|
+
async fetchOrRegister(job, config) {
|
|
110
|
+
const resolved = config === void 0 ? await this.resolveConfig({ organizationId: job.organizationId, tenantId: job.tenantId }, job.mode) : config;
|
|
111
|
+
if (!resolved) {
|
|
112
|
+
throw new Error(`ShipsGo not configured for tenant (mode=${job.mode})`);
|
|
113
|
+
}
|
|
114
|
+
return job.mode === "air" ? this.fetchOrRegisterAir(job, resolved) : this.fetchOrRegisterOcean(job, resolved);
|
|
115
|
+
}
|
|
116
|
+
async fetchOrRegisterOcean(job, config) {
|
|
117
|
+
const em = this.deps.em();
|
|
118
|
+
if (!job.providerShipmentId) {
|
|
119
|
+
const bookingNumber = job.referenceType === "booking" || job.referenceType === "bol" ? job.referenceValue : null;
|
|
120
|
+
const containerNumber = job.referenceType === "container" ? job.referenceValue : null;
|
|
121
|
+
const result = await registerOceanShipment(config, {
|
|
122
|
+
reference: job.id,
|
|
123
|
+
bookingNumber,
|
|
124
|
+
containerNumber
|
|
125
|
+
});
|
|
126
|
+
job.providerShipmentId = result.id;
|
|
127
|
+
await em.flush();
|
|
128
|
+
trackingLogger.info("ShipsGo shipment registered", {
|
|
129
|
+
trackingJobId: job.id,
|
|
130
|
+
providerShipmentId: result.id,
|
|
131
|
+
alreadyExisted: result.alreadyExisted,
|
|
132
|
+
referenceType: job.referenceType,
|
|
133
|
+
mode: "ocean"
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const shipment = await getOceanShipment(config, job.providerShipmentId);
|
|
137
|
+
return mapOceanShipmentToEvents(shipment);
|
|
138
|
+
}
|
|
139
|
+
async fetchOrRegisterAir(job, config) {
|
|
140
|
+
const em = this.deps.em();
|
|
141
|
+
if (!job.providerShipmentId) {
|
|
142
|
+
const result = await registerAirShipment(config, {
|
|
143
|
+
reference: job.id,
|
|
144
|
+
awbNumber: job.referenceValue
|
|
145
|
+
});
|
|
146
|
+
job.providerShipmentId = result.id;
|
|
147
|
+
await em.flush();
|
|
148
|
+
trackingLogger.info("ShipsGo shipment registered", {
|
|
149
|
+
trackingJobId: job.id,
|
|
150
|
+
providerShipmentId: result.id,
|
|
151
|
+
alreadyExisted: result.alreadyExisted,
|
|
152
|
+
referenceType: job.referenceType,
|
|
153
|
+
mode: "air"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const shipment = await getAirShipment(config, job.providerShipmentId);
|
|
157
|
+
return mapAirShipmentToEvents(shipment);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
export {
|
|
161
|
+
ShipsGoProvider
|
|
162
|
+
};
|
|
163
|
+
//# sourceMappingURL=shipsGoProvider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/shipment_tracking/services/shipsGoProvider.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { ShipsGoConfig, TrackingJob } from '../data/entities'\nimport type { CarrierFetchResult } from '../lib/carrier-adapter'\nimport {\n registerOceanShipment,\n getOceanShipment,\n registerAirShipment,\n getAirShipment,\n type ShipsGoClientConfig,\n} from '../lib/shipsgo-client'\nimport { mapOceanShipmentToEvents, mapAirShipmentToEvents } from '../lib/shipsgo-mapper'\nimport { trackingLogger } from '../lib/logger'\n\nconst DEFAULT_BASE_URL = 'https://api.shipsgo.com/v2'\n\n// Platform-fallback rate limit when no per-tenant row governs the account.\n// Kept under ShipsGo's documented 100 req/min account-wide ceiling.\nconst DEFAULT_RATE_LIMIT = { requests: 60, windowSeconds: 60 } as const\n\n/**\n * Rate-limit identity for the shared platform (env-token) account. All tenants\n * that fall back to SHIPSGO_API_TOKEN hit the SAME ShipsGo account, so they must\n * share ONE rate-limit budget (keyed on this) rather than each getting their own\n * \u2014 otherwise N tenants \u00D7 the per-tenant limit would blow the 100 req/min cap.\n * Tenants with their own ShipsGoConfig row (BYO token) key on their tenant id.\n */\nconst PLATFORM_RATE_LIMIT_IDENTITY = 'shipsgo:platform-shared'\n\nexport type ShipsGoRateLimit = { requests: number; windowSeconds: number }\n\n/** Everything a single poll needs, resolved from ONE config read. */\nexport type ShipsGoPollContext = {\n config: ShipsGoClientConfig | null\n rateLimit: ShipsGoRateLimit\n /** checkRateLimit identity \u2014 per-tenant for BYO tokens, shared for the platform account. */\n rateLimitIdentity: string\n}\n\ntype ShipsGoProviderDeps = {\n em: () => EntityManager\n}\n\n/**\n * ShipsGo aggregator provider \u2014 the register-then-poll counterpart to the\n * direct DCSA carrier adapters. Resolves the per-tenant ShipsGo config (or a\n * platform env fallback), registers the shipment on first poll (idempotently,\n * using the tracking-job id as ShipsGo `reference`), then fetches + maps.\n */\nexport class ShipsGoProvider {\n constructor(private deps: ShipsGoProviderDeps) {}\n\n /** Loads the tenant's (non-deleted) ShipsGoConfig row, decrypting the token. */\n private async loadRow(scope: { organizationId: string; tenantId: string }): Promise<ShipsGoConfig | null> {\n const em = this.deps.em()\n return findOneWithDecryption(\n em,\n ShipsGoConfig,\n {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n { tenantId: scope.tenantId, organizationId: scope.organizationId },\n )\n }\n\n /**\n * Resolves the ShipsGo client config for a tenant scope.\n *\n * A tenant's own ShipsGoConfig row is **authoritative**: if it exists but is\n * disabled (isEnabled/isActive false), has the requested mode off, or has no\n * token, this returns null and does NOT fall back to the shared platform\n * account \u2014 otherwise a tenant who turned ShipsGo off would still spend\n * platform credits. The env fallback (SHIPSGO_API_TOKEN / SHIPSGO_BASE_URL)\n * applies only when the tenant has NO config row at all.\n */\n /** Pure row \u2192 client config (with env fallback when no row). See resolveConfig. */\n private configFromRow(row: ShipsGoConfig | null, mode: 'ocean' | 'air'): ShipsGoClientConfig | null {\n if (row) {\n if (!row.isEnabled || !row.isActive) return null\n if (mode === 'ocean' && !row.oceanEnabled) return null\n if (mode === 'air' && !row.airEnabled) return null\n if (!row.apiToken) return null\n return { apiToken: row.apiToken, baseUrl: row.baseUrl || DEFAULT_BASE_URL }\n }\n // No per-tenant row \u2192 platform env fallback (shared account).\n const envToken = process.env.SHIPSGO_API_TOKEN\n if (envToken) {\n return { apiToken: envToken, baseUrl: process.env.SHIPSGO_BASE_URL || DEFAULT_BASE_URL }\n }\n return null\n }\n\n /** Pure row \u2192 rate limit (row's values, else the platform default). */\n private rateLimitFromRow(row: ShipsGoConfig | null): ShipsGoRateLimit {\n if (row && row.rateLimitRequests > 0 && row.rateLimitWindowSeconds > 0) {\n return { requests: row.rateLimitRequests, windowSeconds: row.rateLimitWindowSeconds }\n }\n return { ...DEFAULT_RATE_LIMIT }\n }\n\n /**\n * Resolves the ShipsGo client config for a tenant scope.\n *\n * A tenant's own ShipsGoConfig row is **authoritative**: if it exists but is\n * disabled (isEnabled/isActive false), has the requested mode off, or has no\n * token, this returns null and does NOT fall back to the shared platform\n * account \u2014 otherwise a tenant who turned ShipsGo off would still spend\n * platform credits. The env fallback (SHIPSGO_API_TOKEN / SHIPSGO_BASE_URL)\n * applies only when the tenant has NO config row at all.\n */\n async resolveConfig(\n scope: { organizationId: string; tenantId: string },\n mode: 'ocean' | 'air',\n ): Promise<ShipsGoClientConfig | null> {\n return this.configFromRow(await this.loadRow(scope), mode)\n }\n\n /**\n * Per-tenant rate limit for ShipsGo polling. Honors the tenant row's\n * rate_limit_* when present, else the platform default (kept under ShipsGo's\n * 100 req/min account-wide ceiling).\n */\n async resolveRateLimit(scope: { organizationId: string; tenantId: string }): Promise<ShipsGoRateLimit> {\n return this.rateLimitFromRow(await this.loadRow(scope))\n }\n\n /**\n * Everything a poll needs from a SINGLE config read: the client config, the\n * rate limit, and the rate-limit identity (per-tenant for a BYO token; the\n * shared platform identity when falling back to the env token, so all such\n * tenants share one budget against the one ShipsGo account).\n */\n async resolvePollContext(\n scope: { organizationId: string; tenantId: string },\n mode: 'ocean' | 'air',\n ): Promise<ShipsGoPollContext> {\n const row = await this.loadRow(scope)\n return {\n config: this.configFromRow(row, mode),\n rateLimit: this.rateLimitFromRow(row),\n rateLimitIdentity: row ? scope.tenantId : PLATFORM_RATE_LIMIT_IDENTITY,\n }\n }\n\n /**\n * Fetches events for a ShipsGo-provider tracking job, registering it first if\n * it has no ShipsGo shipment id yet. Persists the id on the job immediately\n * after registration so a crash mid-poll never re-registers (ShipsGo's 409\n * dedup is a second guard). Branches ocean vs air on `job.mode`.\n *\n * `config` may be passed pre-resolved (the poll resolves it once alongside the\n * rate limit); omit it and the provider resolves it itself.\n */\n async fetchOrRegister(job: TrackingJob, config?: ShipsGoClientConfig | null): Promise<CarrierFetchResult> {\n const resolved = config === undefined\n ? await this.resolveConfig({ organizationId: job.organizationId, tenantId: job.tenantId }, job.mode)\n : config\n if (!resolved) {\n throw new Error(`ShipsGo not configured for tenant (mode=${job.mode})`)\n }\n\n return job.mode === 'air'\n ? this.fetchOrRegisterAir(job, resolved)\n : this.fetchOrRegisterOcean(job, resolved)\n }\n\n private async fetchOrRegisterOcean(\n job: TrackingJob,\n config: ShipsGoClientConfig,\n ): Promise<CarrierFetchResult> {\n const em = this.deps.em()\n\n if (!job.providerShipmentId) {\n const bookingNumber =\n job.referenceType === 'booking' || job.referenceType === 'bol' ? job.referenceValue : null\n const containerNumber = job.referenceType === 'container' ? job.referenceValue : null\n\n const result = await registerOceanShipment(config, {\n reference: job.id,\n bookingNumber,\n containerNumber,\n })\n\n job.providerShipmentId = result.id\n await em.flush()\n\n trackingLogger.info('ShipsGo shipment registered', {\n trackingJobId: job.id,\n providerShipmentId: result.id,\n alreadyExisted: result.alreadyExisted,\n referenceType: job.referenceType,\n mode: 'ocean',\n })\n }\n\n const shipment = await getOceanShipment(config, job.providerShipmentId)\n return mapOceanShipmentToEvents(shipment)\n }\n\n private async fetchOrRegisterAir(\n job: TrackingJob,\n config: ShipsGoClientConfig,\n ): Promise<CarrierFetchResult> {\n const em = this.deps.em()\n\n if (!job.providerShipmentId) {\n // Air jobs reference the AWB (referenceType='awb').\n const result = await registerAirShipment(config, {\n reference: job.id,\n awbNumber: job.referenceValue,\n })\n\n job.providerShipmentId = result.id\n await em.flush()\n\n trackingLogger.info('ShipsGo shipment registered', {\n trackingJobId: job.id,\n providerShipmentId: result.id,\n alreadyExisted: result.alreadyExisted,\n referenceType: job.referenceType,\n mode: 'air',\n })\n }\n\n const shipment = await getAirShipment(config, job.providerShipmentId)\n return mapAirShipmentToEvents(shipment)\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|