@aeroswarm/codec 0.1.8 → 0.1.10
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/README.md +26 -1
- package/dist/index.js +332 -1
- package/dist/surveillance/aftn/index.d.ts +3 -0
- package/dist/surveillance/aftn/index.d.ts.map +1 -0
- package/dist/surveillance/aftn/parser.d.ts +16 -0
- package/dist/surveillance/aftn/parser.d.ts.map +1 -0
- package/dist/surveillance/aftn/parser.test.d.ts +2 -0
- package/dist/surveillance/aftn/parser.test.d.ts.map +1 -0
- package/dist/surveillance/aftn/types.d.ts +75 -0
- package/dist/surveillance/aftn/types.d.ts.map +1 -0
- package/dist/surveillance/asterix/fields.d.ts.map +1 -1
- package/dist/surveillance/asterix/types.d.ts +6 -0
- package/dist/surveillance/asterix/types.d.ts.map +1 -1
- package/dist/surveillance/index.d.ts +1 -0
- package/dist/surveillance/index.d.ts.map +1 -1
- package/package.json +40 -40
package/README.md
CHANGED
|
@@ -52,11 +52,35 @@ In the services this is wired to the `ASTERIX_EDITIONS` env var (format `"21:0.2
|
|
|
52
52
|
| CAT023 | CNS/ATM ground station & service status | 1.2 |
|
|
53
53
|
| CAT034 | Radar service messages (north marker, sector crossing) — sensor id only | 1.27, 1.26 |
|
|
54
54
|
| CAT048 | Monoradar (PSR/SSR) target reports | 1.21, 1.14 |
|
|
55
|
-
| CAT062 | System/fused tracks from ATC (keyed by system track number;
|
|
55
|
+
| CAT062 | System/fused tracks from ATC (keyed by system track number; item 380 is compound — only the target address `ADR` is unpacked into `icao24`) | 1.18, 1.16, 1.9, 1.7, 0.17 |
|
|
56
56
|
| CAT063 | Sensor status — sensor id only | 1.3 |
|
|
57
57
|
|
|
58
|
+
CAT021 (edition 1.4+) and CAT048 also expose `trackNumber` (I021/161, I048/161), so reports without a Mode-S address can still be tracked per sensor.
|
|
59
|
+
|
|
58
60
|
Definitions are standard `asterix` XML files in [`src/config/`](src/config/). More category XMLs are already present there (CAT001, 002, 004, …) but not yet registered — see "Adding a category" below.
|
|
59
61
|
|
|
62
|
+
## AFTN / ATS messages
|
|
63
|
+
|
|
64
|
+
Flight-plan data, not positions: `parseAftn` turns one raw AFTN message (FPL, CHG, DLA, DEP, ARR, CNL) into plain JSON.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { parseAftn, splitAftnStream } from "@aeroswarm/codec";
|
|
68
|
+
|
|
69
|
+
// UDP: one message per datagram
|
|
70
|
+
const msg = parseAftn(datagram); // AftnMessage | null
|
|
71
|
+
// msg.callsign "BTK7630" · msg.adep "WARR" · msg.ades "WIII" · msg.aircraftType "A320"
|
|
72
|
+
// msg.cruiseSpeed "N0450" · msg.cruiseLevel "F350" · msg.route "DCT ABMAL L897 BIKMA DCT"
|
|
73
|
+
// msg.icao24 "8a0123" (item 18 CODE/) · msg.eobtAt / atdAt / ataAt (epoch ms, UTC)
|
|
74
|
+
|
|
75
|
+
// TCP: a message ends at NNNN or ETX
|
|
76
|
+
const { messages, rest } = splitAftnStream(buffered + chunk);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- Tolerates gateway framing: SOH/STX/ETX, a `ZCZC` start line, `NNNN`, unknown header lines. Returns `null` when no `( … )` body is present — never throws.
|
|
80
|
+
- Month and year are resolved from `DOF/` or, failing that, the origin `DDHHMM` group nearest to `options.now`.
|
|
81
|
+
- `icao24` comes from `CODE/` and is the precise key for correlating a plan with a surveillance track; callsign is the fallback.
|
|
82
|
+
- Route stays a string (airways, fixes, `DCT`, coordinates) — turning fixes into coordinates needs an AIRAC database this package does not carry.
|
|
83
|
+
|
|
60
84
|
## Exposed API
|
|
61
85
|
|
|
62
86
|
### `parseAsterix(buf, defaultEdition?)`
|
|
@@ -90,6 +114,7 @@ interface AsterixFields {
|
|
|
90
114
|
lat?: number; lon?: number; // WGS-84 degrees
|
|
91
115
|
altitudeFt?: number;
|
|
92
116
|
timeOfDay?: number; // seconds since UTC midnight
|
|
117
|
+
trackNumber?: number; // per-sensor track number (CAT010/011/020/021/048/062)
|
|
93
118
|
velocity?: { groundSpeedKt?: number; headingDeg?: number };
|
|
94
119
|
positionCartesian?: { xNm?: number; yNm?: number };
|
|
95
120
|
measuredPosition?: { rangeNm?: number; azimuthDeg?: number };
|
package/dist/index.js
CHANGED
|
@@ -268,6 +268,11 @@ function str(raw, ...names) {
|
|
|
268
268
|
function validLatLon(lat, lon) {
|
|
269
269
|
return lat >= -90 && lat <= 90 && lon >= -180 && lon <= 180;
|
|
270
270
|
}
|
|
271
|
+
function trdFlags(raw, out) {
|
|
272
|
+
if (num(raw, "TST") === 1) out.testTarget = true;
|
|
273
|
+
if (num(raw, "RAB") === 1) out.fixedTransponder = true;
|
|
274
|
+
if (num(raw, "SIM") === 1) out.simulated = true;
|
|
275
|
+
}
|
|
271
276
|
function decodeKnownField(cat, id, data, out, raw = {}) {
|
|
272
277
|
try {
|
|
273
278
|
if (cat === 21) cat021(id, data, out, raw);
|
|
@@ -299,6 +304,10 @@ function catSystemStatus(id, d, out, raw) {
|
|
|
299
304
|
}
|
|
300
305
|
function cat021(id, d, out, raw) {
|
|
301
306
|
switch (id) {
|
|
307
|
+
case "040":
|
|
308
|
+
trdFlags(raw, out);
|
|
309
|
+
break;
|
|
310
|
+
// I021/040 TRD
|
|
302
311
|
case "010": {
|
|
303
312
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
304
313
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -387,6 +396,12 @@ function cat021(id, d, out, raw) {
|
|
|
387
396
|
else if (d.length >= 2) out.squawk = (d.readUIntBE(0, 2) & 4095).toString(8).padStart(4, "0");
|
|
388
397
|
break;
|
|
389
398
|
}
|
|
399
|
+
case "161": {
|
|
400
|
+
const tn = num(raw, "TrackN", "Tn");
|
|
401
|
+
if (tn !== void 0) out.trackNumber = tn;
|
|
402
|
+
else if (d.length >= 2) out.trackNumber = d.readUIntBE(0, 2) & 4095;
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
390
405
|
case "030": {
|
|
391
406
|
const t = num(raw, "ToD");
|
|
392
407
|
if (t !== void 0) out.timeOfDay = t;
|
|
@@ -397,6 +412,10 @@ function cat021(id, d, out, raw) {
|
|
|
397
412
|
}
|
|
398
413
|
function cat048(id, d, out, raw) {
|
|
399
414
|
switch (id) {
|
|
415
|
+
case "020":
|
|
416
|
+
trdFlags(raw, out);
|
|
417
|
+
break;
|
|
418
|
+
// I048/020 TRD
|
|
400
419
|
case "010": {
|
|
401
420
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
402
421
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -416,6 +435,12 @@ function cat048(id, d, out, raw) {
|
|
|
416
435
|
} else if (d.length >= 6) out.callsign = readCallsign(d);
|
|
417
436
|
break;
|
|
418
437
|
}
|
|
438
|
+
case "161": {
|
|
439
|
+
const tn = num(raw, "Tn");
|
|
440
|
+
if (tn !== void 0) out.trackNumber = tn;
|
|
441
|
+
else if (d.length >= 2) out.trackNumber = d.readUIntBE(0, 2) & 4095;
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
419
444
|
case "042": {
|
|
420
445
|
const x = num(raw, "X"), y = num(raw, "Y");
|
|
421
446
|
if (x !== void 0 && y !== void 0) out.positionCartesian = { xNm: x, yNm: y };
|
|
@@ -520,6 +545,10 @@ function cat023(id, d, out, raw) {
|
|
|
520
545
|
}
|
|
521
546
|
function cat010(id, d, out, raw) {
|
|
522
547
|
switch (id) {
|
|
548
|
+
case "020":
|
|
549
|
+
trdFlags(raw, out);
|
|
550
|
+
break;
|
|
551
|
+
// I010/020 TRD
|
|
523
552
|
case "010": {
|
|
524
553
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
525
554
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -589,6 +618,10 @@ function cat010(id, d, out, raw) {
|
|
|
589
618
|
var MS_TO_KT = 1 / 0.514444;
|
|
590
619
|
function cat062(id, d, out, raw) {
|
|
591
620
|
switch (id) {
|
|
621
|
+
case "080":
|
|
622
|
+
trdFlags(raw, out);
|
|
623
|
+
break;
|
|
624
|
+
// I062/080 TRD
|
|
592
625
|
case "010": {
|
|
593
626
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
594
627
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -628,6 +661,23 @@ function cat062(id, d, out, raw) {
|
|
|
628
661
|
else if (d.length >= 2) out.trackNumber = d.readUIntBE(0, 2);
|
|
629
662
|
break;
|
|
630
663
|
}
|
|
664
|
+
case "300": {
|
|
665
|
+
const vfi = num(raw, "VFI");
|
|
666
|
+
out.vehicleFleet = vfi ?? (d.length >= 1 ? d[0] : void 0);
|
|
667
|
+
out.targetType = "vehicle";
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
case "380": {
|
|
671
|
+
let fsLen = 0;
|
|
672
|
+
while (fsLen < d.length) {
|
|
673
|
+
fsLen++;
|
|
674
|
+
if ((d[fsLen - 1] & 1) === 0) break;
|
|
675
|
+
}
|
|
676
|
+
if (fsLen < d.length && (d[0] & 128) !== 0 && d.length >= fsLen + 3) {
|
|
677
|
+
out.icao24 = d.readUIntBE(fsLen, 3).toString(16).padStart(6, "0");
|
|
678
|
+
}
|
|
679
|
+
break;
|
|
680
|
+
}
|
|
631
681
|
case "070": {
|
|
632
682
|
const t = num(raw, "ToD", "TOTI");
|
|
633
683
|
if (t !== void 0) out.timeOfDay = t;
|
|
@@ -647,6 +697,10 @@ function catServiceMsg(id, d, out, raw) {
|
|
|
647
697
|
}
|
|
648
698
|
function cat020(id, d, out, raw) {
|
|
649
699
|
switch (id) {
|
|
700
|
+
case "020":
|
|
701
|
+
trdFlags(raw, out);
|
|
702
|
+
break;
|
|
703
|
+
// I020/020 TRD
|
|
650
704
|
case "010": {
|
|
651
705
|
const sac = num(raw, "SAC"), sic = num(raw, "SIC");
|
|
652
706
|
if (sac !== void 0 && sic !== void 0) out.dataSource = { sac, sic };
|
|
@@ -913,12 +967,289 @@ function decodeMlatFrame(_frame) {
|
|
|
913
967
|
function decodeAsmgcsFrame(_frame) {
|
|
914
968
|
return null;
|
|
915
969
|
}
|
|
970
|
+
|
|
971
|
+
// src/surveillance/aftn/parser.ts
|
|
972
|
+
var PRIORITY_LINE = /^(SS|DD|FF|GG|KK)\s+(.+)$/;
|
|
973
|
+
var ORIGIN_LINE = /^(\d{6})\s+([A-Z]{8})\b/;
|
|
974
|
+
var ADDRESSEES_ONLY = /^(?:[A-Z]{8}\s*)+$/;
|
|
975
|
+
var AERODROME_TIME = /^([A-Z]{4})(\d{4})?/;
|
|
976
|
+
var ITEM18_ENTRY = /([A-Z]{2,5})\/(.*?)(?=\s+[A-Z]{2,5}\/|\s*$)/gs;
|
|
977
|
+
function normalise(input) {
|
|
978
|
+
const text = typeof input === "string" ? input : input.toString("latin1");
|
|
979
|
+
return text.replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "").replace(/\r\n?/g, "\n").replace(/^\s*ZCZC[^\n]*\n/m, "").replace(/\s*NNNN\s*$/, "");
|
|
980
|
+
}
|
|
981
|
+
function parseHeader(headerText) {
|
|
982
|
+
const header = { addressees: [] };
|
|
983
|
+
const lines = headerText.split("\n").map((l) => l.trim()).filter(Boolean);
|
|
984
|
+
let inAddressees = false;
|
|
985
|
+
for (const line of lines) {
|
|
986
|
+
const origin = ORIGIN_LINE.exec(line);
|
|
987
|
+
if (origin) {
|
|
988
|
+
header.originTime = origin[1];
|
|
989
|
+
header.originator = origin[2];
|
|
990
|
+
inAddressees = false;
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
const prio = PRIORITY_LINE.exec(line);
|
|
994
|
+
if (prio && !header.priority) {
|
|
995
|
+
header.priority = prio[1];
|
|
996
|
+
header.addressees.push(...prio[2].match(/[A-Z]{8}/g) ?? []);
|
|
997
|
+
inAddressees = true;
|
|
998
|
+
continue;
|
|
999
|
+
}
|
|
1000
|
+
if (inAddressees && ADDRESSEES_ONLY.test(line)) {
|
|
1001
|
+
header.addressees.push(...line.match(/[A-Z]{8}/g) ?? []);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
return header;
|
|
1005
|
+
}
|
|
1006
|
+
function parseItem18(raw) {
|
|
1007
|
+
const out = {};
|
|
1008
|
+
const text = raw.trim();
|
|
1009
|
+
if (!text || text === "0") return out;
|
|
1010
|
+
for (const m of text.matchAll(ITEM18_ENTRY)) {
|
|
1011
|
+
const key = m[1];
|
|
1012
|
+
const value = m[2].trim();
|
|
1013
|
+
if (value && out[key] === void 0) out[key] = value;
|
|
1014
|
+
}
|
|
1015
|
+
return out;
|
|
1016
|
+
}
|
|
1017
|
+
function splitCallsign(token) {
|
|
1018
|
+
const cs = token?.split("/")[0]?.trim().toUpperCase();
|
|
1019
|
+
return cs || void 0;
|
|
1020
|
+
}
|
|
1021
|
+
function applyAerodromeTime(token, onAerodrome, onTime) {
|
|
1022
|
+
const m = token ? AERODROME_TIME.exec(token.trim().toUpperCase()) : null;
|
|
1023
|
+
if (!m) return;
|
|
1024
|
+
onAerodrome(m[1]);
|
|
1025
|
+
if (m[2] && onTime) onTime(m[2]);
|
|
1026
|
+
}
|
|
1027
|
+
function applyItem18(msg, entries) {
|
|
1028
|
+
Object.assign(msg.other, entries);
|
|
1029
|
+
if (entries["REG"]) msg.registration = entries["REG"].replace(/[^A-Z0-9-]/gi, "").toUpperCase() || void 0;
|
|
1030
|
+
if (entries["DOF"] && /^\d{6}$/.test(entries["DOF"])) msg.dof = entries["DOF"];
|
|
1031
|
+
const code = entries["CODE"]?.trim();
|
|
1032
|
+
if (code && /^[0-9A-Fa-f]{6}$/.test(code)) msg.icao24 = code.toLowerCase();
|
|
1033
|
+
}
|
|
1034
|
+
var SPEED_LEVEL_ROUTE = /^([NMK]\d{3,4})(F\d{3}|A\d{3}|S\d{4}|M\d{4}|VFR)?\s*(.*)$/;
|
|
1035
|
+
var TYPE_WAKE = /^\d{0,2}([A-Z0-9]{2,4})\/([LMHJ])$/;
|
|
1036
|
+
function applyRoute(msg, text) {
|
|
1037
|
+
const route = text?.trim().toUpperCase();
|
|
1038
|
+
if (!route) return;
|
|
1039
|
+
const m = SPEED_LEVEL_ROUTE.exec(route);
|
|
1040
|
+
if (!m) {
|
|
1041
|
+
msg.route = route;
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
msg.cruiseSpeed = m[1];
|
|
1045
|
+
if (m[2]) msg.cruiseLevel = m[2];
|
|
1046
|
+
if (m[3]) msg.route = m[3].trim();
|
|
1047
|
+
}
|
|
1048
|
+
function applyAircraft(msg, text) {
|
|
1049
|
+
const aircraft = text?.trim().toUpperCase();
|
|
1050
|
+
if (!aircraft) return;
|
|
1051
|
+
const m = TYPE_WAKE.exec(aircraft);
|
|
1052
|
+
if (m) {
|
|
1053
|
+
msg.aircraftType = m[1];
|
|
1054
|
+
msg.wake = m[2];
|
|
1055
|
+
} else msg.aircraftType = aircraft;
|
|
1056
|
+
}
|
|
1057
|
+
function parseFpl(parts, msg) {
|
|
1058
|
+
msg.callsign = splitCallsign(parts[1]);
|
|
1059
|
+
const rulesType = parts[2]?.trim().toUpperCase();
|
|
1060
|
+
if (rulesType) {
|
|
1061
|
+
msg.flightRules = rulesType[0];
|
|
1062
|
+
if (rulesType[1]) msg.flightType = rulesType[1];
|
|
1063
|
+
}
|
|
1064
|
+
applyAircraft(msg, parts[3]);
|
|
1065
|
+
if (parts[4]) msg.equipment = parts[4].trim();
|
|
1066
|
+
applyAerodromeTime(parts[5], (a) => {
|
|
1067
|
+
msg.adep = a;
|
|
1068
|
+
}, (t) => {
|
|
1069
|
+
msg.eobt = t;
|
|
1070
|
+
});
|
|
1071
|
+
applyRoute(msg, parts[6]);
|
|
1072
|
+
const dest = parts[7]?.trim().toUpperCase();
|
|
1073
|
+
if (dest) {
|
|
1074
|
+
const m = /^([A-Z]{4})(\d{4})?(?:\s+([A-Z]{4}))?(?:\s+([A-Z]{4}))?/.exec(dest);
|
|
1075
|
+
if (m) {
|
|
1076
|
+
msg.ades = m[1];
|
|
1077
|
+
if (m[2]) msg.eet = m[2];
|
|
1078
|
+
const alts = [m[3], m[4]].filter((x) => !!x);
|
|
1079
|
+
if (alts.length) msg.alternates = alts;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
applyItem18(msg, parseItem18(parts.slice(8).join("-")));
|
|
1083
|
+
}
|
|
1084
|
+
function parseChg(parts, msg) {
|
|
1085
|
+
msg.callsign = splitCallsign(parts[1]);
|
|
1086
|
+
applyAerodromeTime(parts[2], (a) => {
|
|
1087
|
+
msg.adep = a;
|
|
1088
|
+
}, (t) => {
|
|
1089
|
+
msg.eobt = t;
|
|
1090
|
+
});
|
|
1091
|
+
applyAerodromeTime(parts[3], (a) => {
|
|
1092
|
+
msg.ades = a;
|
|
1093
|
+
});
|
|
1094
|
+
const changes = {};
|
|
1095
|
+
const item18Chunks = [];
|
|
1096
|
+
for (const part of parts.slice(4)) {
|
|
1097
|
+
const numbered = /^(\d{1,2})\/(.*)$/.exec(part.trim());
|
|
1098
|
+
if (numbered) changes[numbered[1]] = numbered[2].trim();
|
|
1099
|
+
else item18Chunks.push(part);
|
|
1100
|
+
}
|
|
1101
|
+
if (Object.keys(changes).length) {
|
|
1102
|
+
msg.changes = changes;
|
|
1103
|
+
const f13 = changes["13"];
|
|
1104
|
+
if (f13) applyAerodromeTime(f13, (a) => {
|
|
1105
|
+
msg.adep = a;
|
|
1106
|
+
}, (t) => {
|
|
1107
|
+
msg.eobt = t;
|
|
1108
|
+
});
|
|
1109
|
+
applyRoute(msg, changes["15"]);
|
|
1110
|
+
const f16 = changes["16"]?.toUpperCase();
|
|
1111
|
+
if (f16) applyAerodromeTime(f16, (a) => {
|
|
1112
|
+
msg.ades = a;
|
|
1113
|
+
}, (t) => {
|
|
1114
|
+
msg.eet = t;
|
|
1115
|
+
});
|
|
1116
|
+
applyAircraft(msg, changes["9"]);
|
|
1117
|
+
const f18 = changes["18"];
|
|
1118
|
+
if (f18) applyItem18(msg, parseItem18(f18));
|
|
1119
|
+
}
|
|
1120
|
+
if (item18Chunks.length) applyItem18(msg, parseItem18(item18Chunks.join(" ")));
|
|
1121
|
+
}
|
|
1122
|
+
function parseMovement(parts, msg) {
|
|
1123
|
+
msg.callsign = splitCallsign(parts[1]);
|
|
1124
|
+
const type = msg.type;
|
|
1125
|
+
if (type === "DEP") {
|
|
1126
|
+
applyAerodromeTime(parts[2], (a) => {
|
|
1127
|
+
msg.adep = a;
|
|
1128
|
+
}, (t) => {
|
|
1129
|
+
msg.atd = t;
|
|
1130
|
+
});
|
|
1131
|
+
applyAerodromeTime(parts[3], (a) => {
|
|
1132
|
+
msg.ades = a;
|
|
1133
|
+
});
|
|
1134
|
+
} else if (type === "ARR") {
|
|
1135
|
+
applyAerodromeTime(parts[2], (a) => {
|
|
1136
|
+
msg.adep = a;
|
|
1137
|
+
});
|
|
1138
|
+
applyAerodromeTime(parts[3], (a) => {
|
|
1139
|
+
msg.ades = a;
|
|
1140
|
+
}, (t) => {
|
|
1141
|
+
msg.ata = t;
|
|
1142
|
+
});
|
|
1143
|
+
} else if (type === "DLA") {
|
|
1144
|
+
applyAerodromeTime(parts[2], (a) => {
|
|
1145
|
+
msg.adep = a;
|
|
1146
|
+
}, (t) => {
|
|
1147
|
+
msg.eobt = t;
|
|
1148
|
+
});
|
|
1149
|
+
applyAerodromeTime(parts[3], (a) => {
|
|
1150
|
+
msg.ades = a;
|
|
1151
|
+
});
|
|
1152
|
+
} else {
|
|
1153
|
+
applyAerodromeTime(parts[2], (a) => {
|
|
1154
|
+
msg.adep = a;
|
|
1155
|
+
});
|
|
1156
|
+
applyAerodromeTime(parts[3], (a) => {
|
|
1157
|
+
msg.ades = a;
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
applyItem18(msg, parseItem18(parts.slice(4).join(" ")));
|
|
1161
|
+
}
|
|
1162
|
+
function resolveBaseDay(msg, now) {
|
|
1163
|
+
if (msg.dof) {
|
|
1164
|
+
const yy = Number(msg.dof.slice(0, 2));
|
|
1165
|
+
return { y: 2e3 + yy, m: Number(msg.dof.slice(2, 4)) - 1, d: Number(msg.dof.slice(4, 6)) };
|
|
1166
|
+
}
|
|
1167
|
+
const origin = msg.header.originTime;
|
|
1168
|
+
if (!origin) return null;
|
|
1169
|
+
const day = Number(origin.slice(0, 2));
|
|
1170
|
+
const ref = new Date(now);
|
|
1171
|
+
let best = null;
|
|
1172
|
+
let bestDiff = Infinity;
|
|
1173
|
+
for (const offset of [-1, 0, 1]) {
|
|
1174
|
+
const probe = new Date(Date.UTC(ref.getUTCFullYear(), ref.getUTCMonth() + offset, day));
|
|
1175
|
+
if (probe.getUTCDate() !== day) continue;
|
|
1176
|
+
const diff = Math.abs(probe.getTime() - now);
|
|
1177
|
+
if (diff < bestDiff) {
|
|
1178
|
+
bestDiff = diff;
|
|
1179
|
+
best = { y: probe.getUTCFullYear(), m: probe.getUTCMonth(), d: day };
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
return best;
|
|
1183
|
+
}
|
|
1184
|
+
function toEpoch(base, hhmm) {
|
|
1185
|
+
if (!hhmm || !/^\d{4}$/.test(hhmm)) return void 0;
|
|
1186
|
+
const hh = Number(hhmm.slice(0, 2));
|
|
1187
|
+
const mm = Number(hhmm.slice(2, 4));
|
|
1188
|
+
if (hh > 23 || mm > 59) return void 0;
|
|
1189
|
+
return Date.UTC(base.y, base.m, base.d, hh, mm);
|
|
1190
|
+
}
|
|
1191
|
+
function parseAftn(input, options = {}) {
|
|
1192
|
+
const s = normalise(input);
|
|
1193
|
+
const open = s.indexOf("(");
|
|
1194
|
+
const close = s.lastIndexOf(")");
|
|
1195
|
+
if (open < 0 || close <= open) return null;
|
|
1196
|
+
const text = s.slice(open, close + 1).replace(/\s*\n\s*/g, " ").trim();
|
|
1197
|
+
const inner = text.slice(1, -1);
|
|
1198
|
+
const parts = inner.split("-").map((p) => p.trim());
|
|
1199
|
+
const type = parts[0];
|
|
1200
|
+
if (!type || !/^[A-Z]{3}$/.test(type)) return null;
|
|
1201
|
+
const msg = {
|
|
1202
|
+
type,
|
|
1203
|
+
header: parseHeader(s.slice(0, open)),
|
|
1204
|
+
text,
|
|
1205
|
+
other: {}
|
|
1206
|
+
};
|
|
1207
|
+
switch (type) {
|
|
1208
|
+
case "FPL":
|
|
1209
|
+
parseFpl(parts, msg);
|
|
1210
|
+
break;
|
|
1211
|
+
case "CHG":
|
|
1212
|
+
parseChg(parts, msg);
|
|
1213
|
+
break;
|
|
1214
|
+
case "DEP":
|
|
1215
|
+
case "ARR":
|
|
1216
|
+
case "DLA":
|
|
1217
|
+
case "CNL":
|
|
1218
|
+
parseMovement(parts, msg);
|
|
1219
|
+
break;
|
|
1220
|
+
default:
|
|
1221
|
+
msg.callsign = splitCallsign(parts[1]);
|
|
1222
|
+
}
|
|
1223
|
+
const base = resolveBaseDay(msg, options.now ?? Date.now());
|
|
1224
|
+
if (base) {
|
|
1225
|
+
msg.eobtAt = toEpoch(base, msg.eobt);
|
|
1226
|
+
msg.atdAt = toEpoch(base, msg.atd);
|
|
1227
|
+
msg.ataAt = toEpoch(base, msg.ata);
|
|
1228
|
+
}
|
|
1229
|
+
return msg;
|
|
1230
|
+
}
|
|
1231
|
+
function splitAftnStream(buffer) {
|
|
1232
|
+
const messages = [];
|
|
1233
|
+
let rest = buffer;
|
|
1234
|
+
const terminator = /NNNN|\x03/;
|
|
1235
|
+
for (; ; ) {
|
|
1236
|
+
const m = terminator.exec(rest);
|
|
1237
|
+
if (!m) break;
|
|
1238
|
+
const end = m.index + m[0].length;
|
|
1239
|
+
const chunk = rest.slice(0, end);
|
|
1240
|
+
if (chunk.includes("(")) messages.push(chunk);
|
|
1241
|
+
rest = rest.slice(end);
|
|
1242
|
+
}
|
|
1243
|
+
return { messages, rest };
|
|
1244
|
+
}
|
|
916
1245
|
export {
|
|
917
1246
|
decodeAdsbFrame,
|
|
918
1247
|
decodeAis,
|
|
919
1248
|
decodeAsmgcsFrame,
|
|
920
1249
|
decodeMlatFrame,
|
|
1250
|
+
parseAftn,
|
|
921
1251
|
parseAsterix,
|
|
922
1252
|
resolveAsterixAltitudeFt,
|
|
923
|
-
resolveAsterixPosition
|
|
1253
|
+
resolveAsterixPosition,
|
|
1254
|
+
splitAftnStream
|
|
924
1255
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/surveillance/aftn/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACzD,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AftnMessage, ParseAftnOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse one AFTN message (raw datagram / TCP-delimited text).
|
|
4
|
+
*
|
|
5
|
+
* Tolerant of gateway framing: control characters (SOH/STX/ETX), a
|
|
6
|
+
* classic `ZCZC` start line, `NNNN` terminator and unknown header lines are
|
|
7
|
+
* ignored. Returns `null` when no `( … )` ATS message body is present.
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseAftn(input: string | Buffer, options?: ParseAftnOptions): AftnMessage | null;
|
|
10
|
+
/** Split a TCP byte stream into complete messages: a message ends at `NNNN`
|
|
11
|
+
* or ETX (0x03). Returns the complete messages and the unconsumed tail. */
|
|
12
|
+
export declare function splitAftnStream(buffer: string): {
|
|
13
|
+
messages: string[];
|
|
14
|
+
rest: string;
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/surveillance/aftn/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAsN5E;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,WAAW,GAAG,IAAI,CAsCpG;AAED;4EAC4E;AAC5E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAapF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parser.test.d.ts","sourceRoot":"","sources":["../../../src/surveillance/aftn/parser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/** Parsed AFTN message header (priority / addressees / origin group). */
|
|
2
|
+
export interface AftnHeader {
|
|
3
|
+
/** Priority indicator: SS, DD, FF, GG or KK */
|
|
4
|
+
priority?: string;
|
|
5
|
+
/** 8-letter addressee indicators */
|
|
6
|
+
addressees: string[];
|
|
7
|
+
/** Origin time group, DDHHMM (UTC) */
|
|
8
|
+
originTime?: string;
|
|
9
|
+
/** 8-letter originator indicator */
|
|
10
|
+
originator?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* One parsed ATS message (ICAO Doc 4444 App. 3 formats: FPL, CHG, DLA, DEP,
|
|
14
|
+
* ARR, CNL; any other 3-letter type is returned with identity fields only).
|
|
15
|
+
*
|
|
16
|
+
* Plain JSON — safe to publish on Kafka as-is.
|
|
17
|
+
*/
|
|
18
|
+
export interface AftnMessage {
|
|
19
|
+
/** FPL | CHG | DLA | DEP | ARR | CNL | … */
|
|
20
|
+
type: string;
|
|
21
|
+
header: AftnHeader;
|
|
22
|
+
/** Message text from "(" to ")" with line breaks normalised to spaces */
|
|
23
|
+
text: string;
|
|
24
|
+
/** Aircraft identification (item 7), upper-case */
|
|
25
|
+
callsign?: string;
|
|
26
|
+
/** I (IFR) · V (VFR) · Y (IFR→VFR) · Z (VFR→IFR) */
|
|
27
|
+
flightRules?: string;
|
|
28
|
+
/** S scheduled · N non-scheduled · G general · M military · X other */
|
|
29
|
+
flightType?: string;
|
|
30
|
+
/** ICAO aircraft type designator, e.g. A320 */
|
|
31
|
+
aircraftType?: string;
|
|
32
|
+
/** L / M / H / J */
|
|
33
|
+
wake?: string;
|
|
34
|
+
/** Item 10 as sent (communication/navigation/surveillance equipment) */
|
|
35
|
+
equipment?: string;
|
|
36
|
+
/** Departure aerodrome (ICAO) */
|
|
37
|
+
adep?: string;
|
|
38
|
+
/** Destination aerodrome (ICAO) */
|
|
39
|
+
ades?: string;
|
|
40
|
+
/** Estimated off-block time HHMM (FPL), or the new EOBT (DLA) */
|
|
41
|
+
eobt?: string;
|
|
42
|
+
/** Actual time of departure HHMM (DEP) */
|
|
43
|
+
atd?: string;
|
|
44
|
+
/** Actual time of arrival HHMM (ARR) */
|
|
45
|
+
ata?: string;
|
|
46
|
+
/** Estimated elapsed time HHMM (FPL item 16) */
|
|
47
|
+
eet?: string;
|
|
48
|
+
/** Cruising speed group, e.g. N0450 / M078 / K0830 */
|
|
49
|
+
cruiseSpeed?: string;
|
|
50
|
+
/** Cruising level group, e.g. F350 / A045 / S1010 / VFR */
|
|
51
|
+
cruiseLevel?: string;
|
|
52
|
+
/** Route string (airways, fixes, DCT, coordinates) after speed/level */
|
|
53
|
+
route?: string;
|
|
54
|
+
/** Alternate aerodromes */
|
|
55
|
+
alternates?: string[];
|
|
56
|
+
/** Item 18 keyed entries: REG, DOF, EET, CODE, PBN, NAV, OPR, RMK, … */
|
|
57
|
+
other: Record<string, string>;
|
|
58
|
+
/** Aircraft registration (REG/) */
|
|
59
|
+
registration?: string;
|
|
60
|
+
/** 24-bit Mode-S address, lower-case hex (CODE/) — correlates with a track's icao24 */
|
|
61
|
+
icao24?: string;
|
|
62
|
+
/** Date of flight YYMMDD (DOF/) */
|
|
63
|
+
dof?: string;
|
|
64
|
+
/** CHG only: ICAO item number → new data */
|
|
65
|
+
changes?: Record<string, string>;
|
|
66
|
+
/** Epoch ms (UTC) resolved from DOF/origin day + the HHMM groups above */
|
|
67
|
+
eobtAt?: number;
|
|
68
|
+
atdAt?: number;
|
|
69
|
+
ataAt?: number;
|
|
70
|
+
}
|
|
71
|
+
export interface ParseAftnOptions {
|
|
72
|
+
/** Reference time used to resolve month/year when DOF/ is absent. Default: now. */
|
|
73
|
+
now?: number;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/surveillance/aftn/types.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,sCAAsC;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IAEb,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2BAA2B;IAC3B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/fields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAoE7C,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,GAAE,SAAc,GAAG,IAAI,CAWrH"}
|
|
@@ -41,6 +41,12 @@ export interface AsterixFields {
|
|
|
41
41
|
vehicleFleet?: number;
|
|
42
42
|
/** Sensor-assigned local track number */
|
|
43
43
|
trackNumber?: number;
|
|
44
|
+
/** TST bit — test target */
|
|
45
|
+
testTarget?: boolean;
|
|
46
|
+
/** RAB bit — report from a fixed field-monitor transponder (MLAT RPU etc.) */
|
|
47
|
+
fixedTransponder?: boolean;
|
|
48
|
+
/** SIM bit — simulated target */
|
|
49
|
+
simulated?: boolean;
|
|
44
50
|
}
|
|
45
51
|
export interface AsterixRecord {
|
|
46
52
|
category: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,iBAAiB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,gBAAgB,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1C,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACnG,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/types.ts"],"names":[],"mappings":"AACA,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3D,iBAAiB,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACnD,gBAAgB,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,UAAU,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAE1C,sFAAsF;IACtF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACnG,4CAA4C;IAC5C,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;IAChD,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8EAA8E;IAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,iCAAiC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,aAAa,CAAC;CACvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/surveillance/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/surveillance/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@aeroswarm/codec",
|
|
3
|
-
"version": "0.1.
|
|
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
|
-
"main": "./dist/index.js"
|
|
12
|
-
}
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"src/config"
|
|
17
|
-
],
|
|
18
|
-
"publishConfig": {
|
|
19
|
-
"access": "public",
|
|
20
|
-
"registry": "https://registry.npmjs.org/"
|
|
21
|
-
},
|
|
22
|
-
"scripts": {
|
|
23
|
-
"build": "tsup src/index.ts --format esm --clean && tsc --emitDeclarationOnly",
|
|
24
|
-
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
25
|
-
"test": "vitest run --passWithNoTests",
|
|
26
|
-
"typecheck": "tsc --noEmit",
|
|
27
|
-
"clean": "rm -rf dist",
|
|
28
|
-
"prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build",
|
|
29
|
-
"release": "release-it",
|
|
30
|
-
"release:dry": "release-it --dry-run",
|
|
31
|
-
"release:patch": "release-it patch --no-git.requireCleanWorkingDir",
|
|
32
|
-
"release:minor": "release-it minor --no-git.requireCleanWorkingDir",
|
|
33
|
-
"release:major": "release-it major --no-git.requireCleanWorkingDir"
|
|
34
|
-
},
|
|
35
|
-
"devDependencies": {
|
|
36
|
-
"release-it": "^18.1.2",
|
|
37
|
-
"tsup": "^8.5.1",
|
|
38
|
-
"vitest": "^4.1.6"
|
|
39
|
-
}
|
|
40
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@aeroswarm/codec",
|
|
3
|
+
"version": "0.1.10",
|
|
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
|
+
"main": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"src/config"
|
|
17
|
+
],
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public",
|
|
20
|
+
"registry": "https://registry.npmjs.org/"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup src/index.ts --format esm --clean && tsc --emitDeclarationOnly",
|
|
24
|
+
"dev": "tsup src/index.ts --format esm --dts --watch",
|
|
25
|
+
"test": "vitest run --passWithNoTests",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"clean": "rm -rf dist",
|
|
28
|
+
"prepublishOnly": "pnpm run typecheck && pnpm run test && pnpm run build",
|
|
29
|
+
"release": "release-it",
|
|
30
|
+
"release:dry": "release-it --dry-run",
|
|
31
|
+
"release:patch": "release-it patch --no-git.requireCleanWorkingDir",
|
|
32
|
+
"release:minor": "release-it minor --no-git.requireCleanWorkingDir",
|
|
33
|
+
"release:major": "release-it major --no-git.requireCleanWorkingDir"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"release-it": "^18.1.2",
|
|
37
|
+
"tsup": "^8.5.1",
|
|
38
|
+
"vitest": "^4.1.6"
|
|
39
|
+
}
|
|
40
|
+
}
|