@aeroswarm/core 0.2.9 → 0.2.11
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/dist/chunk-3T3CHHEM.js +145 -0
- package/dist/{chunk-ZBO7NUV3.js → chunk-J2UTSYKD.js} +2 -1
- package/dist/{chunk-TAFKYKUB.js → chunk-ZYX6U3ZK.js} +18 -1
- package/dist/flightplan/index.d.ts +21 -0
- package/dist/flightplan/index.js +16 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.js +24 -2
- package/dist/types/index.d.ts +101 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -1
- package/dist/validation/index.d.ts +105 -1
- package/dist/validation/index.js +3 -1
- package/package.json +63 -59
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// src/flightplan/index.ts
|
|
2
|
+
var FLIGHT_PLAN_MATCH_WINDOW_MS = 36 * 36e5;
|
|
3
|
+
function normalizeCallsign(cs) {
|
|
4
|
+
const v = cs?.trim().toUpperCase().replace(/\s+/g, "");
|
|
5
|
+
return v || void 0;
|
|
6
|
+
}
|
|
7
|
+
function dayKey(msg, receivedAt) {
|
|
8
|
+
if (msg.dof && /^\d{6}$/.test(msg.dof)) return `20${msg.dof}`;
|
|
9
|
+
const t = msg.eobtAt ?? msg.atdAt ?? msg.ataAt ?? receivedAt;
|
|
10
|
+
return new Date(t).toISOString().slice(0, 10).replace(/-/g, "");
|
|
11
|
+
}
|
|
12
|
+
function flightPlanId(msg, receivedAt) {
|
|
13
|
+
const callsign = normalizeCallsign(msg.callsign);
|
|
14
|
+
if (!callsign) return null;
|
|
15
|
+
return `${callsign}|${msg.adep ?? "-"}|${msg.ades ?? "-"}|${dayKey(msg, receivedAt)}`;
|
|
16
|
+
}
|
|
17
|
+
function pickMatchingPlan(candidates, msg, receivedAt) {
|
|
18
|
+
const ref = msg.eobtAt ?? msg.atdAt ?? msg.ataAt ?? receivedAt;
|
|
19
|
+
let best;
|
|
20
|
+
let bestDiff = Infinity;
|
|
21
|
+
for (const c of candidates) {
|
|
22
|
+
if (msg.adep && c.adep && msg.adep !== c.adep) continue;
|
|
23
|
+
if (msg.ades && c.ades && msg.ades !== c.ades) continue;
|
|
24
|
+
const planTime = c.atdAt ?? c.eobtAt ?? c.firstSeenAt;
|
|
25
|
+
const diff = Math.abs(planTime - ref);
|
|
26
|
+
if (diff <= FLIGHT_PLAN_MATCH_WINDOW_MS && diff < bestDiff) {
|
|
27
|
+
best = c;
|
|
28
|
+
bestDiff = diff;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return best;
|
|
32
|
+
}
|
|
33
|
+
function assignDefined(target, patch) {
|
|
34
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
35
|
+
if (v !== void 0 && v !== null && v !== "") target[k] = v;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function eetMs(eet) {
|
|
39
|
+
if (!eet || !/^\d{4}$/.test(eet)) return void 0;
|
|
40
|
+
return (Number(eet.slice(0, 2)) * 60 + Number(eet.slice(2, 4))) * 6e4;
|
|
41
|
+
}
|
|
42
|
+
function applyFlightPlanEvent(prev, ev) {
|
|
43
|
+
const m = ev.message;
|
|
44
|
+
const callsign = normalizeCallsign(m.callsign);
|
|
45
|
+
if (!callsign) return null;
|
|
46
|
+
const id = prev?.id ?? flightPlanId(m, ev.receivedAt);
|
|
47
|
+
if (!id) return null;
|
|
48
|
+
const next = {
|
|
49
|
+
status: "filed",
|
|
50
|
+
airportId: ev.airportId,
|
|
51
|
+
firstSeenAt: ev.receivedAt,
|
|
52
|
+
...prev,
|
|
53
|
+
id,
|
|
54
|
+
callsign,
|
|
55
|
+
other: { ...prev?.other ?? {} },
|
|
56
|
+
lastMessageType: m.type,
|
|
57
|
+
messageCount: (prev?.messageCount ?? 0) + 1,
|
|
58
|
+
updatedAt: ev.receivedAt
|
|
59
|
+
};
|
|
60
|
+
assignDefined(next, { icao24: m.icao24, registration: m.registration, dof: m.dof });
|
|
61
|
+
Object.assign(next.other, m.other);
|
|
62
|
+
if (!next.adep && m.adep) next.adep = m.adep;
|
|
63
|
+
if (!next.ades && m.ades) next.ades = m.ades;
|
|
64
|
+
switch (m.type) {
|
|
65
|
+
case "FPL":
|
|
66
|
+
assignDefined(next, {
|
|
67
|
+
aircraftType: m.aircraftType,
|
|
68
|
+
wake: m.wake,
|
|
69
|
+
flightRules: m.flightRules,
|
|
70
|
+
flightType: m.flightType,
|
|
71
|
+
adep: m.adep,
|
|
72
|
+
ades: m.ades,
|
|
73
|
+
alternates: m.alternates,
|
|
74
|
+
eobtAt: m.eobtAt,
|
|
75
|
+
eet: m.eet,
|
|
76
|
+
cruiseSpeed: m.cruiseSpeed,
|
|
77
|
+
cruiseLevel: m.cruiseLevel,
|
|
78
|
+
route: m.route,
|
|
79
|
+
equipment: m.equipment
|
|
80
|
+
});
|
|
81
|
+
if (prev?.status !== "departed" && prev?.status !== "arrived") next.status = "filed";
|
|
82
|
+
break;
|
|
83
|
+
case "CHG":
|
|
84
|
+
assignDefined(next, {
|
|
85
|
+
aircraftType: m.aircraftType,
|
|
86
|
+
wake: m.wake,
|
|
87
|
+
cruiseSpeed: m.cruiseSpeed,
|
|
88
|
+
cruiseLevel: m.cruiseLevel,
|
|
89
|
+
route: m.route
|
|
90
|
+
});
|
|
91
|
+
if (m.changes?.["13"]) assignDefined(next, { adep: m.adep, eobtAt: m.eobtAt });
|
|
92
|
+
if (m.changes?.["16"]) assignDefined(next, { ades: m.ades, eet: m.eet });
|
|
93
|
+
break;
|
|
94
|
+
case "DLA":
|
|
95
|
+
assignDefined(next, { eobtAt: m.eobtAt });
|
|
96
|
+
if (next.status === "filed" || next.status === "delayed") next.status = "delayed";
|
|
97
|
+
break;
|
|
98
|
+
case "DEP":
|
|
99
|
+
next.atdAt = m.atdAt ?? ev.receivedAt;
|
|
100
|
+
next.status = "departed";
|
|
101
|
+
break;
|
|
102
|
+
case "ARR":
|
|
103
|
+
next.ataAt = m.ataAt ?? ev.receivedAt;
|
|
104
|
+
next.status = "arrived";
|
|
105
|
+
break;
|
|
106
|
+
case "CNL":
|
|
107
|
+
next.status = "cancelled";
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
const departure = next.atdAt ?? next.eobtAt;
|
|
111
|
+
const flightTime = eetMs(next.eet);
|
|
112
|
+
next.etaAt = next.ataAt ?? (departure !== void 0 && flightTime !== void 0 ? departure + flightTime : void 0);
|
|
113
|
+
return next;
|
|
114
|
+
}
|
|
115
|
+
function flightPhase(plan, airportId) {
|
|
116
|
+
const icao = airportId?.trim().toUpperCase();
|
|
117
|
+
if (icao && plan.ades === icao) return "ARRIVAL";
|
|
118
|
+
if (icao && plan.adep === icao) return "DEPARTURE";
|
|
119
|
+
return plan.adep || plan.ades ? "OVERFLIGHT" : "UNKNOWN";
|
|
120
|
+
}
|
|
121
|
+
function summarizeFlightPlan(plan, airportId) {
|
|
122
|
+
const summary = { id: plan.id, status: plan.status, phase: flightPhase(plan, airportId) };
|
|
123
|
+
assignDefined(summary, {
|
|
124
|
+
adep: plan.adep,
|
|
125
|
+
ades: plan.ades,
|
|
126
|
+
aircraftType: plan.aircraftType,
|
|
127
|
+
registration: plan.registration,
|
|
128
|
+
eobtAt: plan.eobtAt,
|
|
129
|
+
atdAt: plan.atdAt,
|
|
130
|
+
ataAt: plan.ataAt,
|
|
131
|
+
etaAt: plan.etaAt,
|
|
132
|
+
cruiseLevel: plan.cruiseLevel,
|
|
133
|
+
route: plan.route
|
|
134
|
+
});
|
|
135
|
+
return summary;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export {
|
|
139
|
+
normalizeCallsign,
|
|
140
|
+
flightPlanId,
|
|
141
|
+
pickMatchingPlan,
|
|
142
|
+
applyFlightPlanEvent,
|
|
143
|
+
flightPhase,
|
|
144
|
+
summarizeFlightPlan
|
|
145
|
+
};
|
|
@@ -112,7 +112,8 @@ var TOPICS = {
|
|
|
112
112
|
HEALTH: "aero.source.health.v1",
|
|
113
113
|
LIFECYCLE: "aero.track.lifecycle.v1",
|
|
114
114
|
DEADLETTER: "aero.deadletter.v1",
|
|
115
|
-
MOVEMENT: "aero.movement.v1"
|
|
115
|
+
MOVEMENT: "aero.movement.v1",
|
|
116
|
+
FLIGHT_PLAN: "aero.flightplan.v1"
|
|
116
117
|
};
|
|
117
118
|
var STALE_AFTER_MS = 15e3;
|
|
118
119
|
var LOST_AFTER_MS = 9e4;
|
|
@@ -12,6 +12,21 @@ var velocitySchema = z.object({
|
|
|
12
12
|
heading: z.number().min(-1).max(361).optional(),
|
|
13
13
|
verticalRate: z.number().optional()
|
|
14
14
|
});
|
|
15
|
+
var flightPlanSummarySchema = z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
adep: z.string().optional(),
|
|
18
|
+
ades: z.string().optional(),
|
|
19
|
+
aircraftType: z.string().optional(),
|
|
20
|
+
registration: z.string().optional(),
|
|
21
|
+
eobtAt: z.number().optional(),
|
|
22
|
+
atdAt: z.number().optional(),
|
|
23
|
+
ataAt: z.number().optional(),
|
|
24
|
+
etaAt: z.number().optional(),
|
|
25
|
+
cruiseLevel: z.string().optional(),
|
|
26
|
+
route: z.string().optional(),
|
|
27
|
+
status: z.enum(["filed", "delayed", "departed", "arrived", "cancelled"]),
|
|
28
|
+
phase: z.enum(["ARRIVAL", "DEPARTURE", "OVERFLIGHT", "UNKNOWN"])
|
|
29
|
+
});
|
|
15
30
|
var currentTrackSchema = z.object({
|
|
16
31
|
trackId: z.string(),
|
|
17
32
|
source: z.enum(["ADSB", "ASTERIX_CAT010", "ASTERIX_CAT011", "ASTERIX_CAT020", "ASTERIX_CAT021", "ASTERIX_CAT048", "ASTERIX_CAT062", "FUSED"]),
|
|
@@ -29,7 +44,8 @@ var currentTrackSchema = z.object({
|
|
|
29
44
|
verticalRateFpm: z.number().nullable(),
|
|
30
45
|
confidence: z.number().min(0).max(1),
|
|
31
46
|
lastSeenAt: z.number(),
|
|
32
|
-
status: z.enum(["active", "stale", "lost"])
|
|
47
|
+
status: z.enum(["active", "stale", "lost"]),
|
|
48
|
+
flightPlan: flightPlanSummarySchema.optional()
|
|
33
49
|
});
|
|
34
50
|
var streamEnvelopeSchema = z.discriminatedUnion("type", [
|
|
35
51
|
z.object({
|
|
@@ -117,6 +133,7 @@ var apiResponseSchema = (dataSchema) => z.union([apiSuccessSchema(dataSchema), a
|
|
|
117
133
|
export {
|
|
118
134
|
positionSchema,
|
|
119
135
|
velocitySchema,
|
|
136
|
+
flightPlanSummarySchema,
|
|
120
137
|
currentTrackSchema,
|
|
121
138
|
streamEnvelopeSchema,
|
|
122
139
|
sourceHeartbeatSchema,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { FlightPlan, FlightPlanEvent, FlightPhase, AftnMessagePayload, FlightPlanSummary } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
declare function normalizeCallsign(cs?: string | null): string | undefined;
|
|
4
|
+
/** Stable identity of one flight: callsign + route + day of flight. */
|
|
5
|
+
declare function flightPlanId(msg: AftnMessagePayload, receivedAt: number): string | null;
|
|
6
|
+
/** Pick the existing plan (candidates share the callsign) that a CHG/DLA/DEP/ARR/CNL
|
|
7
|
+
* refers to: same departure/destination when given, closest in time, within the window. */
|
|
8
|
+
declare function pickMatchingPlan(candidates: Iterable<FlightPlan>, msg: AftnMessagePayload, receivedAt: number): FlightPlan | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Fold one AFTN message into the flight's current state. Returns `null` when
|
|
11
|
+
* the message carries no aircraft identification.
|
|
12
|
+
*
|
|
13
|
+
* FPL (re)files the plan; CHG amends the changed items; DLA moves the EOBT;
|
|
14
|
+
* DEP/ARR record actual times; CNL cancels. Other types only bump counters.
|
|
15
|
+
*/
|
|
16
|
+
declare function applyFlightPlanEvent(prev: FlightPlan | undefined, ev: FlightPlanEvent): FlightPlan | null;
|
|
17
|
+
/** Arrival/departure relative to an airport (ICAO). */
|
|
18
|
+
declare function flightPhase(plan: Pick<FlightPlan, "adep" | "ades">, airportId?: string): FlightPhase;
|
|
19
|
+
declare function summarizeFlightPlan(plan: FlightPlan, airportId?: string): FlightPlanSummary;
|
|
20
|
+
|
|
21
|
+
export { applyFlightPlanEvent, flightPhase, flightPlanId, normalizeCallsign, pickMatchingPlan, summarizeFlightPlan };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyFlightPlanEvent,
|
|
3
|
+
flightPhase,
|
|
4
|
+
flightPlanId,
|
|
5
|
+
normalizeCallsign,
|
|
6
|
+
pickMatchingPlan,
|
|
7
|
+
summarizeFlightPlan
|
|
8
|
+
} from "../chunk-3T3CHHEM.js";
|
|
9
|
+
export {
|
|
10
|
+
applyFlightPlanEvent,
|
|
11
|
+
flightPhase,
|
|
12
|
+
flightPlanId,
|
|
13
|
+
normalizeCallsign,
|
|
14
|
+
pickMatchingPlan,
|
|
15
|
+
summarizeFlightPlan
|
|
16
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { SourceHealthEvent, FusedTrackEvent } from './types/index.js';
|
|
2
|
-
export { AeroConnectionStatus, AeroRecoverableError, AssignedRoute, Bbox, ConfidenceBudget, CurrentTrack, Position, Protocol, RouteAssignment, SourceStatus, StreamEnvelope, TargetType, TrackSource, TrackStatus, Velocity } from './types/index.js';
|
|
2
|
+
export { AeroConnectionStatus, AeroRecoverableError, AftnMessagePayload, AssignedRoute, Bbox, ConfidenceBudget, CurrentTrack, FlightPhase, FlightPlan, FlightPlanEvent, FlightPlanStatus, FlightPlanSummary, Position, Protocol, RouteAssignment, SourceStatus, StreamEnvelope, TargetType, TrackSource, TrackStatus, Velocity } from './types/index.js';
|
|
3
3
|
import { TopicName } from './utils/index.js';
|
|
4
4
|
export { EMERGENCY_SQUAWKS, LOST_AFTER_MS, MACH1_KT, PolylineDistance, STALE_AFTER_MS, TOPICS, clamp, createEventId, createEventUid, createNanoid, createSessionId, createTrackId, distanceToPolylineM, haversineKm, isInsideBbox, isRenderableTrack, toCurrentTrack } from './utils/index.js';
|
|
5
|
-
export {
|
|
5
|
+
export { applyFlightPlanEvent, flightPhase, flightPlanId, normalizeCallsign, pickMatchingPlan, summarizeFlightPlan } from './flightplan/index.js';
|
|
6
|
+
export { CurrentTrackInput, StreamEnvelopeInput, WsSubscribeInput, apiErrorSchema, apiResponseSchema, apiSuccessSchema, currentTrackSchema, flightPlanSummarySchema, positionSchema, sourceHeartbeatSchema, streamEnvelopeSchema, velocitySchema, wsSubscribeSchema, wsUpdateFilterSchema } from './validation/index.js';
|
|
6
7
|
import pino, { Logger } from 'pino';
|
|
7
8
|
import { Registry, Counter, Gauge } from 'prom-client';
|
|
8
9
|
import { Redis } from 'ioredis';
|
|
@@ -241,6 +242,12 @@ declare const TOPIC_REGISTRY: {
|
|
|
241
242
|
readonly producer: "process-movement-detector";
|
|
242
243
|
readonly consumers: readonly ["connector-service"];
|
|
243
244
|
};
|
|
245
|
+
readonly "aero.flightplan.v1": {
|
|
246
|
+
readonly name: "aero.flightplan.v1";
|
|
247
|
+
readonly description: "Parsed AFTN/ATS messages (FPL, CHG, DLA, DEP, ARR, CNL) from AFTN feeds";
|
|
248
|
+
readonly producer: "simulator-service";
|
|
249
|
+
readonly consumers: readonly ["client-service"];
|
|
250
|
+
};
|
|
244
251
|
};
|
|
245
252
|
type TopicInfo = typeof TOPIC_REGISTRY[keyof typeof TOPIC_REGISTRY];
|
|
246
253
|
declare function getTopicInfo(topic: string): TopicInfo | undefined;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
applyFlightPlanEvent,
|
|
3
|
+
flightPhase,
|
|
4
|
+
flightPlanId,
|
|
5
|
+
normalizeCallsign,
|
|
6
|
+
pickMatchingPlan,
|
|
7
|
+
summarizeFlightPlan
|
|
8
|
+
} from "./chunk-3T3CHHEM.js";
|
|
1
9
|
import "./chunk-FXPGR372.js";
|
|
2
10
|
import {
|
|
3
11
|
EMERGENCY_SQUAWKS,
|
|
@@ -16,19 +24,20 @@ import {
|
|
|
16
24
|
isInsideBbox,
|
|
17
25
|
isRenderableTrack,
|
|
18
26
|
toCurrentTrack
|
|
19
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-J2UTSYKD.js";
|
|
20
28
|
import {
|
|
21
29
|
apiErrorSchema,
|
|
22
30
|
apiResponseSchema,
|
|
23
31
|
apiSuccessSchema,
|
|
24
32
|
currentTrackSchema,
|
|
33
|
+
flightPlanSummarySchema,
|
|
25
34
|
positionSchema,
|
|
26
35
|
sourceHeartbeatSchema,
|
|
27
36
|
streamEnvelopeSchema,
|
|
28
37
|
velocitySchema,
|
|
29
38
|
wsSubscribeSchema,
|
|
30
39
|
wsUpdateFilterSchema
|
|
31
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-ZYX6U3ZK.js";
|
|
32
41
|
|
|
33
42
|
// src/config/index.ts
|
|
34
43
|
import { config } from "dotenv";
|
|
@@ -332,6 +341,12 @@ var TOPIC_REGISTRY = {
|
|
|
332
341
|
description: "Takeoff/landing transitions detected from fused track altitude/speed",
|
|
333
342
|
producer: "process-movement-detector",
|
|
334
343
|
consumers: ["connector-service"]
|
|
344
|
+
},
|
|
345
|
+
[TOPICS.FLIGHT_PLAN]: {
|
|
346
|
+
name: TOPICS.FLIGHT_PLAN,
|
|
347
|
+
description: "Parsed AFTN/ATS messages (FPL, CHG, DLA, DEP, ARR, CNL) from AFTN feeds",
|
|
348
|
+
producer: "simulator-service",
|
|
349
|
+
consumers: ["client-service"]
|
|
335
350
|
}
|
|
336
351
|
};
|
|
337
352
|
function getTopicInfo(topic) {
|
|
@@ -522,6 +537,7 @@ export {
|
|
|
522
537
|
apiErrorSchema,
|
|
523
538
|
apiResponseSchema,
|
|
524
539
|
apiSuccessSchema,
|
|
540
|
+
applyFlightPlanEvent,
|
|
525
541
|
buildHealthResponse,
|
|
526
542
|
cacheSourceToken,
|
|
527
543
|
checkKafkaHealth,
|
|
@@ -540,6 +556,9 @@ export {
|
|
|
540
556
|
disconnectRedis,
|
|
541
557
|
distanceToPolylineM,
|
|
542
558
|
ensureTopics,
|
|
559
|
+
flightPhase,
|
|
560
|
+
flightPlanId,
|
|
561
|
+
flightPlanSummarySchema,
|
|
543
562
|
getConsumerGroupHealth,
|
|
544
563
|
getDbSchema,
|
|
545
564
|
getDbSearchPath,
|
|
@@ -560,7 +579,9 @@ export {
|
|
|
560
579
|
isRenderableTrack,
|
|
561
580
|
isValidTopic,
|
|
562
581
|
logger,
|
|
582
|
+
normalizeCallsign,
|
|
563
583
|
partitionKeys,
|
|
584
|
+
pickMatchingPlan,
|
|
564
585
|
positionSchema,
|
|
565
586
|
publishEvent,
|
|
566
587
|
registerWsClient,
|
|
@@ -573,6 +594,7 @@ export {
|
|
|
573
594
|
setTrack,
|
|
574
595
|
sourceHeartbeatSchema,
|
|
575
596
|
streamEnvelopeSchema,
|
|
597
|
+
summarizeFlightPlan,
|
|
576
598
|
toCurrentTrack,
|
|
577
599
|
trackUpdateRate,
|
|
578
600
|
unregisterWsClient,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -74,6 +74,104 @@ interface RouteAssignment {
|
|
|
74
74
|
}
|
|
75
75
|
type TrackStatus = "active" | "stale" | "lost";
|
|
76
76
|
type TrackSource = "ADSB" | "ASTERIX_CAT010" | "ASTERIX_CAT011" | "ASTERIX_CAT020" | "ASTERIX_CAT021" | "ASTERIX_CAT048" | "ASTERIX_CAT062" | "FUSED";
|
|
77
|
+
type FlightPlanStatus = "filed" | "delayed" | "departed" | "arrived" | "cancelled";
|
|
78
|
+
type FlightPhase = "ARRIVAL" | "DEPARTURE" | "OVERFLIGHT" | "UNKNOWN";
|
|
79
|
+
/** One parsed AFTN/ATS message — mirrors `AftnMessage` from @aeroswarm/codec
|
|
80
|
+
* (kept as a plain structural type so core stays free of a codec dependency). */
|
|
81
|
+
interface AftnMessagePayload {
|
|
82
|
+
type: string;
|
|
83
|
+
header: {
|
|
84
|
+
priority?: string;
|
|
85
|
+
addressees: string[];
|
|
86
|
+
originTime?: string;
|
|
87
|
+
originator?: string;
|
|
88
|
+
};
|
|
89
|
+
text: string;
|
|
90
|
+
callsign?: string;
|
|
91
|
+
flightRules?: string;
|
|
92
|
+
flightType?: string;
|
|
93
|
+
aircraftType?: string;
|
|
94
|
+
wake?: string;
|
|
95
|
+
equipment?: string;
|
|
96
|
+
adep?: string;
|
|
97
|
+
ades?: string;
|
|
98
|
+
eobt?: string;
|
|
99
|
+
atd?: string;
|
|
100
|
+
ata?: string;
|
|
101
|
+
eet?: string;
|
|
102
|
+
cruiseSpeed?: string;
|
|
103
|
+
cruiseLevel?: string;
|
|
104
|
+
route?: string;
|
|
105
|
+
alternates?: string[];
|
|
106
|
+
other: Record<string, string>;
|
|
107
|
+
registration?: string;
|
|
108
|
+
icao24?: string;
|
|
109
|
+
dof?: string;
|
|
110
|
+
changes?: Record<string, string>;
|
|
111
|
+
eobtAt?: number;
|
|
112
|
+
atdAt?: number;
|
|
113
|
+
ataAt?: number;
|
|
114
|
+
}
|
|
115
|
+
/** Published by an AFTN feed on TOPICS.FLIGHT_PLAN. */
|
|
116
|
+
interface FlightPlanEvent {
|
|
117
|
+
messageId: string;
|
|
118
|
+
sourceId: string;
|
|
119
|
+
feedId?: string;
|
|
120
|
+
/** Airport the feed is attached to (same convention as tracks) */
|
|
121
|
+
airportId?: string;
|
|
122
|
+
receivedAt: number;
|
|
123
|
+
message: AftnMessagePayload;
|
|
124
|
+
}
|
|
125
|
+
/** Current state of one flight, folded from FPL/CHG/DLA/DEP/ARR/CNL messages. */
|
|
126
|
+
interface FlightPlan {
|
|
127
|
+
id: string;
|
|
128
|
+
callsign: string;
|
|
129
|
+
icao24?: string;
|
|
130
|
+
registration?: string;
|
|
131
|
+
aircraftType?: string;
|
|
132
|
+
wake?: string;
|
|
133
|
+
flightRules?: string;
|
|
134
|
+
flightType?: string;
|
|
135
|
+
adep?: string;
|
|
136
|
+
ades?: string;
|
|
137
|
+
alternates?: string[];
|
|
138
|
+
eobtAt?: number;
|
|
139
|
+
atdAt?: number;
|
|
140
|
+
ataAt?: number;
|
|
141
|
+
/** Estimated elapsed time HHMM from item 16 */
|
|
142
|
+
eet?: string;
|
|
143
|
+
/** Estimated arrival: (actual or estimated departure) + EET */
|
|
144
|
+
etaAt?: number;
|
|
145
|
+
cruiseSpeed?: string;
|
|
146
|
+
cruiseLevel?: string;
|
|
147
|
+
route?: string;
|
|
148
|
+
equipment?: string;
|
|
149
|
+
dof?: string;
|
|
150
|
+
status: FlightPlanStatus;
|
|
151
|
+
airportId?: string;
|
|
152
|
+
other: Record<string, string>;
|
|
153
|
+
lastMessageType: string;
|
|
154
|
+
messageCount: number;
|
|
155
|
+
firstSeenAt: number;
|
|
156
|
+
updatedAt: number;
|
|
157
|
+
}
|
|
158
|
+
/** The subset attached to a live track for rendering. */
|
|
159
|
+
interface FlightPlanSummary {
|
|
160
|
+
id: string;
|
|
161
|
+
adep?: string;
|
|
162
|
+
ades?: string;
|
|
163
|
+
aircraftType?: string;
|
|
164
|
+
registration?: string;
|
|
165
|
+
eobtAt?: number;
|
|
166
|
+
atdAt?: number;
|
|
167
|
+
ataAt?: number;
|
|
168
|
+
etaAt?: number;
|
|
169
|
+
cruiseLevel?: string;
|
|
170
|
+
route?: string;
|
|
171
|
+
status: FlightPlanStatus;
|
|
172
|
+
/** Relative to the track's airport (ARRIVAL = ades matches, DEPARTURE = adep matches) */
|
|
173
|
+
phase: FlightPhase;
|
|
174
|
+
}
|
|
77
175
|
interface CurrentTrack {
|
|
78
176
|
trackId: string;
|
|
79
177
|
source: TrackSource;
|
|
@@ -95,6 +193,8 @@ interface CurrentTrack {
|
|
|
95
193
|
confidence: number;
|
|
96
194
|
lastSeenAt: number;
|
|
97
195
|
status: TrackStatus;
|
|
196
|
+
/** Flight-plan data correlated from AFTN (by Mode-S address, else callsign); absent when none matched */
|
|
197
|
+
flightPlan?: FlightPlanSummary;
|
|
98
198
|
}
|
|
99
199
|
type StreamEnvelope = {
|
|
100
200
|
type: "snapshot";
|
|
@@ -157,4 +257,4 @@ interface AeroRecoverableError {
|
|
|
157
257
|
}
|
|
158
258
|
type SourceStatus = SourceHealthEvent["status"];
|
|
159
259
|
|
|
160
|
-
export type { AeroConnectionStatus, AeroRecoverableError, AssignedRoute, Bbox, ConfidenceBudget, CurrentTrack, FusedTrackEvent, Position, Protocol, RouteAssignment, SourceHealthEvent, SourceStatus, StreamEnvelope, TargetType, TrackSource, TrackStatus, Velocity };
|
|
260
|
+
export type { AeroConnectionStatus, AeroRecoverableError, AftnMessagePayload, AssignedRoute, Bbox, ConfidenceBudget, CurrentTrack, FlightPhase, FlightPlan, FlightPlanEvent, FlightPlanStatus, FlightPlanSummary, FusedTrackEvent, Position, Protocol, RouteAssignment, SourceHealthEvent, SourceStatus, StreamEnvelope, TargetType, TrackSource, TrackStatus, Velocity };
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -36,6 +36,7 @@ declare const TOPICS: {
|
|
|
36
36
|
readonly LIFECYCLE: "aero.track.lifecycle.v1";
|
|
37
37
|
readonly DEADLETTER: "aero.deadletter.v1";
|
|
38
38
|
readonly MOVEMENT: "aero.movement.v1";
|
|
39
|
+
readonly FLIGHT_PLAN: "aero.flightplan.v1";
|
|
39
40
|
};
|
|
40
41
|
type TopicName = (typeof TOPICS)[keyof typeof TOPICS];
|
|
41
42
|
declare const STALE_AFTER_MS = 15000;
|
package/dist/utils/index.js
CHANGED
|
@@ -16,6 +16,32 @@ declare const velocitySchema: z.ZodObject<{
|
|
|
16
16
|
heading: z.ZodOptional<z.ZodNumber>;
|
|
17
17
|
verticalRate: z.ZodOptional<z.ZodNumber>;
|
|
18
18
|
}, z.core.$strip>;
|
|
19
|
+
declare const flightPlanSummarySchema: z.ZodObject<{
|
|
20
|
+
id: z.ZodString;
|
|
21
|
+
adep: z.ZodOptional<z.ZodString>;
|
|
22
|
+
ades: z.ZodOptional<z.ZodString>;
|
|
23
|
+
aircraftType: z.ZodOptional<z.ZodString>;
|
|
24
|
+
registration: z.ZodOptional<z.ZodString>;
|
|
25
|
+
eobtAt: z.ZodOptional<z.ZodNumber>;
|
|
26
|
+
atdAt: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
ataAt: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
etaAt: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
cruiseLevel: z.ZodOptional<z.ZodString>;
|
|
30
|
+
route: z.ZodOptional<z.ZodString>;
|
|
31
|
+
status: z.ZodEnum<{
|
|
32
|
+
filed: "filed";
|
|
33
|
+
delayed: "delayed";
|
|
34
|
+
departed: "departed";
|
|
35
|
+
arrived: "arrived";
|
|
36
|
+
cancelled: "cancelled";
|
|
37
|
+
}>;
|
|
38
|
+
phase: z.ZodEnum<{
|
|
39
|
+
ARRIVAL: "ARRIVAL";
|
|
40
|
+
DEPARTURE: "DEPARTURE";
|
|
41
|
+
OVERFLIGHT: "OVERFLIGHT";
|
|
42
|
+
UNKNOWN: "UNKNOWN";
|
|
43
|
+
}>;
|
|
44
|
+
}, z.core.$strip>;
|
|
19
45
|
declare const currentTrackSchema: z.ZodObject<{
|
|
20
46
|
trackId: z.ZodString;
|
|
21
47
|
source: z.ZodEnum<{
|
|
@@ -51,6 +77,32 @@ declare const currentTrackSchema: z.ZodObject<{
|
|
|
51
77
|
stale: "stale";
|
|
52
78
|
lost: "lost";
|
|
53
79
|
}>;
|
|
80
|
+
flightPlan: z.ZodOptional<z.ZodObject<{
|
|
81
|
+
id: z.ZodString;
|
|
82
|
+
adep: z.ZodOptional<z.ZodString>;
|
|
83
|
+
ades: z.ZodOptional<z.ZodString>;
|
|
84
|
+
aircraftType: z.ZodOptional<z.ZodString>;
|
|
85
|
+
registration: z.ZodOptional<z.ZodString>;
|
|
86
|
+
eobtAt: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
atdAt: z.ZodOptional<z.ZodNumber>;
|
|
88
|
+
ataAt: z.ZodOptional<z.ZodNumber>;
|
|
89
|
+
etaAt: z.ZodOptional<z.ZodNumber>;
|
|
90
|
+
cruiseLevel: z.ZodOptional<z.ZodString>;
|
|
91
|
+
route: z.ZodOptional<z.ZodString>;
|
|
92
|
+
status: z.ZodEnum<{
|
|
93
|
+
filed: "filed";
|
|
94
|
+
delayed: "delayed";
|
|
95
|
+
departed: "departed";
|
|
96
|
+
arrived: "arrived";
|
|
97
|
+
cancelled: "cancelled";
|
|
98
|
+
}>;
|
|
99
|
+
phase: z.ZodEnum<{
|
|
100
|
+
ARRIVAL: "ARRIVAL";
|
|
101
|
+
DEPARTURE: "DEPARTURE";
|
|
102
|
+
OVERFLIGHT: "OVERFLIGHT";
|
|
103
|
+
UNKNOWN: "UNKNOWN";
|
|
104
|
+
}>;
|
|
105
|
+
}, z.core.$strip>>;
|
|
54
106
|
}, z.core.$strip>;
|
|
55
107
|
declare const streamEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
56
108
|
type: z.ZodLiteral<"snapshot">;
|
|
@@ -92,6 +144,32 @@ declare const streamEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
92
144
|
stale: "stale";
|
|
93
145
|
lost: "lost";
|
|
94
146
|
}>;
|
|
147
|
+
flightPlan: z.ZodOptional<z.ZodObject<{
|
|
148
|
+
id: z.ZodString;
|
|
149
|
+
adep: z.ZodOptional<z.ZodString>;
|
|
150
|
+
ades: z.ZodOptional<z.ZodString>;
|
|
151
|
+
aircraftType: z.ZodOptional<z.ZodString>;
|
|
152
|
+
registration: z.ZodOptional<z.ZodString>;
|
|
153
|
+
eobtAt: z.ZodOptional<z.ZodNumber>;
|
|
154
|
+
atdAt: z.ZodOptional<z.ZodNumber>;
|
|
155
|
+
ataAt: z.ZodOptional<z.ZodNumber>;
|
|
156
|
+
etaAt: z.ZodOptional<z.ZodNumber>;
|
|
157
|
+
cruiseLevel: z.ZodOptional<z.ZodString>;
|
|
158
|
+
route: z.ZodOptional<z.ZodString>;
|
|
159
|
+
status: z.ZodEnum<{
|
|
160
|
+
filed: "filed";
|
|
161
|
+
delayed: "delayed";
|
|
162
|
+
departed: "departed";
|
|
163
|
+
arrived: "arrived";
|
|
164
|
+
cancelled: "cancelled";
|
|
165
|
+
}>;
|
|
166
|
+
phase: z.ZodEnum<{
|
|
167
|
+
ARRIVAL: "ARRIVAL";
|
|
168
|
+
DEPARTURE: "DEPARTURE";
|
|
169
|
+
OVERFLIGHT: "OVERFLIGHT";
|
|
170
|
+
UNKNOWN: "UNKNOWN";
|
|
171
|
+
}>;
|
|
172
|
+
}, z.core.$strip>>;
|
|
95
173
|
}, z.core.$strip>>;
|
|
96
174
|
}, z.core.$strip>;
|
|
97
175
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -134,6 +212,32 @@ declare const streamEnvelopeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
134
212
|
stale: "stale";
|
|
135
213
|
lost: "lost";
|
|
136
214
|
}>;
|
|
215
|
+
flightPlan: z.ZodOptional<z.ZodObject<{
|
|
216
|
+
id: z.ZodString;
|
|
217
|
+
adep: z.ZodOptional<z.ZodString>;
|
|
218
|
+
ades: z.ZodOptional<z.ZodString>;
|
|
219
|
+
aircraftType: z.ZodOptional<z.ZodString>;
|
|
220
|
+
registration: z.ZodOptional<z.ZodString>;
|
|
221
|
+
eobtAt: z.ZodOptional<z.ZodNumber>;
|
|
222
|
+
atdAt: z.ZodOptional<z.ZodNumber>;
|
|
223
|
+
ataAt: z.ZodOptional<z.ZodNumber>;
|
|
224
|
+
etaAt: z.ZodOptional<z.ZodNumber>;
|
|
225
|
+
cruiseLevel: z.ZodOptional<z.ZodString>;
|
|
226
|
+
route: z.ZodOptional<z.ZodString>;
|
|
227
|
+
status: z.ZodEnum<{
|
|
228
|
+
filed: "filed";
|
|
229
|
+
delayed: "delayed";
|
|
230
|
+
departed: "departed";
|
|
231
|
+
arrived: "arrived";
|
|
232
|
+
cancelled: "cancelled";
|
|
233
|
+
}>;
|
|
234
|
+
phase: z.ZodEnum<{
|
|
235
|
+
ARRIVAL: "ARRIVAL";
|
|
236
|
+
DEPARTURE: "DEPARTURE";
|
|
237
|
+
OVERFLIGHT: "OVERFLIGHT";
|
|
238
|
+
UNKNOWN: "UNKNOWN";
|
|
239
|
+
}>;
|
|
240
|
+
}, z.core.$strip>>;
|
|
137
241
|
}, z.core.$strip>;
|
|
138
242
|
}, z.core.$strip>;
|
|
139
243
|
}, z.core.$strip>, z.ZodObject<{
|
|
@@ -248,4 +352,4 @@ type CurrentTrackInput = z.infer<typeof currentTrackSchema>;
|
|
|
248
352
|
type WsSubscribeInput = z.infer<typeof wsSubscribeSchema>;
|
|
249
353
|
type StreamEnvelopeInput = z.infer<typeof streamEnvelopeSchema>;
|
|
250
354
|
|
|
251
|
-
export { type CurrentTrackInput, type StreamEnvelopeInput, type WsSubscribeInput, apiErrorSchema, apiResponseSchema, apiSuccessSchema, currentTrackSchema, positionSchema, sourceHeartbeatSchema, streamEnvelopeSchema, velocitySchema, wsSubscribeSchema, wsUpdateFilterSchema };
|
|
355
|
+
export { type CurrentTrackInput, type StreamEnvelopeInput, type WsSubscribeInput, apiErrorSchema, apiResponseSchema, apiSuccessSchema, currentTrackSchema, flightPlanSummarySchema, positionSchema, sourceHeartbeatSchema, streamEnvelopeSchema, velocitySchema, wsSubscribeSchema, wsUpdateFilterSchema };
|
package/dist/validation/index.js
CHANGED
|
@@ -3,18 +3,20 @@ import {
|
|
|
3
3
|
apiResponseSchema,
|
|
4
4
|
apiSuccessSchema,
|
|
5
5
|
currentTrackSchema,
|
|
6
|
+
flightPlanSummarySchema,
|
|
6
7
|
positionSchema,
|
|
7
8
|
sourceHeartbeatSchema,
|
|
8
9
|
streamEnvelopeSchema,
|
|
9
10
|
velocitySchema,
|
|
10
11
|
wsSubscribeSchema,
|
|
11
12
|
wsUpdateFilterSchema
|
|
12
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-ZYX6U3ZK.js";
|
|
13
14
|
export {
|
|
14
15
|
apiErrorSchema,
|
|
15
16
|
apiResponseSchema,
|
|
16
17
|
apiSuccessSchema,
|
|
17
18
|
currentTrackSchema,
|
|
19
|
+
flightPlanSummarySchema,
|
|
18
20
|
positionSchema,
|
|
19
21
|
sourceHeartbeatSchema,
|
|
20
22
|
streamEnvelopeSchema,
|
package/package.json
CHANGED
|
@@ -1,59 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@aeroswarm/core",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"type": "module",
|
|
5
|
-
"main": "./dist/index.js",
|
|
6
|
-
"types": "./dist/index.d.ts",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": {
|
|
9
|
-
"import": "./dist/index.js",
|
|
10
|
-
"types": "./dist/index.d.ts"
|
|
11
|
-
},
|
|
12
|
-
"./utils": {
|
|
13
|
-
"import": "./dist/utils/index.js",
|
|
14
|
-
"types": "./dist/utils/index.d.ts"
|
|
15
|
-
},
|
|
16
|
-
"./validation": {
|
|
17
|
-
"import": "./dist/validation/index.js",
|
|
18
|
-
"types": "./dist/validation/index.d.ts"
|
|
19
|
-
},
|
|
20
|
-
"./
|
|
21
|
-
"import": "./dist/
|
|
22
|
-
"types": "./dist/
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"release
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@aeroswarm/core",
|
|
3
|
+
"version": "0.2.11",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
},
|
|
12
|
+
"./utils": {
|
|
13
|
+
"import": "./dist/utils/index.js",
|
|
14
|
+
"types": "./dist/utils/index.d.ts"
|
|
15
|
+
},
|
|
16
|
+
"./validation": {
|
|
17
|
+
"import": "./dist/validation/index.js",
|
|
18
|
+
"types": "./dist/validation/index.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./flightplan": {
|
|
21
|
+
"import": "./dist/flightplan/index.js",
|
|
22
|
+
"types": "./dist/flightplan/index.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./types": {
|
|
25
|
+
"import": "./dist/types/index.js",
|
|
26
|
+
"types": "./dist/types/index.d.ts"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"registry": "https://registry.npmjs.org/"
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup src/index.ts src/utils/index.ts src/validation/index.ts src/types/index.ts src/flightplan/index.ts --format esm --clean --dts",
|
|
38
|
+
"dev": "tsup src/index.ts src/utils/index.ts src/validation/index.ts src/types/index.ts src/flightplan/index.ts --format esm --dts --watch",
|
|
39
|
+
"test": "vitest run --passWithNoTests",
|
|
40
|
+
"typecheck": "tsc --noEmit",
|
|
41
|
+
"clean": "rm -rf dist",
|
|
42
|
+
"prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build",
|
|
43
|
+
"release": "release-it",
|
|
44
|
+
"release:dry": "release-it --dry-run",
|
|
45
|
+
"release:patch": "release-it patch --no-git.requireCleanWorkingDir",
|
|
46
|
+
"release:minor": "release-it minor --no-git.requireCleanWorkingDir",
|
|
47
|
+
"release:major": "release-it major --no-git.requireCleanWorkingDir"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"dotenv": "^16.6.1",
|
|
51
|
+
"ioredis": "^5.6.1",
|
|
52
|
+
"kafkajs": "^2.2.4",
|
|
53
|
+
"pino": "^9.7.0",
|
|
54
|
+
"pino-pretty": "^13.0.0",
|
|
55
|
+
"prom-client": "^15.1.3",
|
|
56
|
+
"zod": "^4.4.3"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"release-it": "^18.1.2",
|
|
60
|
+
"tsup": "^8.5.1",
|
|
61
|
+
"vitest": "^4.1.6"
|
|
62
|
+
}
|
|
63
|
+
}
|