@aeroswarm/codec 0.1.10 → 0.1.12

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/index.js CHANGED
@@ -116,11 +116,15 @@ function parseBits(s) {
116
116
  }
117
117
  return out;
118
118
  }
119
+ function repetitionBytes(body, fallback) {
120
+ if (/<BDS[\s/>]/.test(body)) return 8;
121
+ const m = body.match(/<Fixed\s+length="(\d+)"/);
122
+ return m ? parseInt(m[1]) : fallback;
123
+ }
119
124
  function parseRepetitive(s) {
120
125
  const inner = firstContent(s, "Repetitive");
121
126
  const repAttr = inner.match(/<Repetitive\s+rep="(\d+)"/);
122
- const m = inner.match(/<Fixed\s+length="(\d+)"/);
123
- return { type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: m ? parseInt(m[1]) : 0 };
127
+ return { type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: repetitionBytes(inner, 0) };
124
128
  }
125
129
  function parseCompound(s) {
126
130
  const inner = firstContent(s, "Compound");
@@ -130,27 +134,47 @@ function parseCompound(s) {
130
134
  const varEnd = inner.indexOf("</Variable>");
131
135
  const afterVar = varEnd >= 0 ? inner.slice(varEnd + "</Variable>".length) : "";
132
136
  const subs = [];
133
- const subRe = /<(Fixed|Variable|Repetitive|Explicit)\s/g;
134
- let sm;
135
- while ((sm = subRe.exec(afterVar)) !== null) {
136
- const tag = sm[1];
137
- const rest = afterVar.slice(sm.index);
138
- if (tag === "Fixed") {
139
- const lm = rest.match(/<Fixed\s+length="(\d+)"/);
137
+ for (const child of topLevelChildren(afterVar)) {
138
+ const first = child.body.match(/<Fixed\s+length="(\d+)"/);
139
+ if (child.tag === "Fixed") {
140
+ const lm = child.open.match(/length="(\d+)"/);
140
141
  if (lm) subs.push({ type: "fixed", bytes: parseInt(lm[1]) });
141
- } else if (tag === "Variable") {
142
- const lm = rest.match(/<Fixed\s+length="(\d+)"/);
143
- subs.push({ type: "variable", chunkBytes: lm ? parseInt(lm[1]) : 1 });
144
- } else if (tag === "Repetitive") {
145
- const repAttr = rest.match(/<Repetitive\s+rep="(\d+)"/);
146
- const lm = rest.match(/<Fixed\s+length="(\d+)"/);
147
- subs.push({ type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: lm ? parseInt(lm[1]) : 1 });
142
+ } else if (child.tag === "Variable") {
143
+ subs.push({ type: "variable", chunkBytes: first ? parseInt(first[1]) : 1 });
144
+ } else if (child.tag === "Repetitive") {
145
+ const repAttr = child.open.match(/rep="(\d+)"/);
146
+ subs.push({ type: "repetitive", repBytes: repAttr ? parseInt(repAttr[1]) : 1, itemBytes: repetitionBytes(child.body, 1) });
148
147
  } else {
149
148
  subs.push({ type: "explicit" });
150
149
  }
151
150
  }
152
151
  return { type: "compound", indicatorChunk, subs };
153
152
  }
153
+ function topLevelChildren(s) {
154
+ const out = [];
155
+ const re = /<(\/?)(Fixed|Variable|Repetitive|Explicit|Compound)\b([^>]*?)(\/?)>/g;
156
+ let depth = 0;
157
+ let current = null;
158
+ let m;
159
+ while ((m = re.exec(s)) !== null) {
160
+ const closing = m[1] === "/";
161
+ const selfClosing = m[4] === "/";
162
+ if (!closing) {
163
+ if (depth === 0) {
164
+ if (selfClosing) out.push({ tag: m[2], open: m[0], body: "" });
165
+ else current = { tag: m[2], open: m[0], start: m.index + m[0].length };
166
+ }
167
+ if (!selfClosing) depth++;
168
+ } else {
169
+ depth--;
170
+ if (depth === 0 && current) {
171
+ out.push({ tag: current.tag, open: current.open, body: s.slice(current.start, m.index) });
172
+ current = null;
173
+ }
174
+ }
175
+ }
176
+ return out;
177
+ }
154
178
  function firstContent(s, tag) {
155
179
  return s.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`))?.[1] ?? "";
156
180
  }
@@ -168,23 +192,23 @@ function parseFspec(buf, start = 0) {
168
192
  return { bits, end: i };
169
193
  }
170
194
  function skipItem(buf, off, def) {
171
- if (off >= buf.length) return buf.length;
195
+ if (off >= buf.length) return buf.length + 1;
172
196
  switch (def.type) {
173
197
  case "fixed":
174
- return Math.min(off + def.bytes, buf.length);
198
+ return off + def.bytes;
175
199
  case "variable": {
176
200
  while (off + def.chunkBytes <= buf.length) {
177
201
  const last = buf[off + def.chunkBytes - 1];
178
202
  off += def.chunkBytes;
179
203
  if ((last & 1) === 0) break;
180
204
  }
181
- return Math.min(off, buf.length);
205
+ return off;
182
206
  }
183
207
  case "repetitive": {
184
- if (off + def.repBytes > buf.length) return buf.length;
208
+ if (off + def.repBytes > buf.length) return buf.length + 1;
185
209
  let rep = 0;
186
210
  for (let i = 0; i < def.repBytes; i++) rep = rep << 8 | buf[off + i];
187
- return Math.min(off + def.repBytes + rep * def.itemBytes, buf.length);
211
+ return off + def.repBytes + rep * def.itemBytes;
188
212
  }
189
213
  case "compound": {
190
214
  const presentIdxs = [];
@@ -202,13 +226,12 @@ function skipItem(buf, off, def) {
202
226
  if (idx >= def.subs.length) break;
203
227
  off = skipItem(buf, off, def.subs[idx]);
204
228
  }
205
- return Math.min(off, buf.length);
229
+ return off;
206
230
  }
207
231
  case "explicit": {
208
- if (off >= buf.length) return off;
232
+ if (off >= buf.length) return buf.length + 1;
209
233
  const len = buf[off];
210
- off++;
211
- return Math.min(off + len - 1, buf.length);
234
+ return off + Math.max(len, 1);
212
235
  }
213
236
  }
214
237
  }
@@ -218,16 +241,18 @@ function decodeBlock(block, def, onField) {
218
241
  const uapMap = new Map(def.uap.map((e) => [e.bit, e.id]));
219
242
  for (let i = 0; i < bits.length; i++) {
220
243
  if (!bits[i]) continue;
221
- if (off >= block.length) break;
244
+ if (off >= block.length) return { end: block.length, complete: true, overrun: true };
222
245
  const uapPos = i + Math.floor(i / 7);
223
246
  const id = uapMap.get(uapPos);
224
- if (id === void 0) break;
247
+ if (id === void 0) return { end: off, complete: false, overrun: false };
225
248
  const itemDef = def.items.get(id);
226
- if (!itemDef) break;
249
+ if (!itemDef) return { end: off, complete: false, overrun: false };
227
250
  const start = off;
228
251
  off = skipItem(block, off, itemDef);
229
- onField(id, block.slice(start, off), itemDef);
252
+ onField(id, block.slice(start, Math.min(off, block.length)), itemDef);
253
+ if (off > block.length) return { end: block.length, complete: true, overrun: true };
230
254
  }
255
+ return { end: off, complete: true, overrun: false };
231
256
  }
232
257
 
233
258
  // src/surveillance/asterix/fields.ts
@@ -616,6 +641,19 @@ function cat010(id, d, out, raw) {
616
641
  }
617
642
  }
618
643
  var MS_TO_KT = 1 / 0.514444;
644
+ function flightPlanCallsign(d) {
645
+ let indicators = 0;
646
+ while (indicators < d.length) {
647
+ indicators++;
648
+ if ((d[indicators - 1] & 1) === 0) break;
649
+ }
650
+ const first = d[0] ?? 0;
651
+ if ((first & 64) === 0) return void 0;
652
+ const at = indicators + ((first & 128) !== 0 ? 2 : 0);
653
+ if (d.length < at + 7) return void 0;
654
+ const text = d.subarray(at, at + 7).toString("latin1").trim();
655
+ return text.length > 0 && /^[A-Z0-9 ]+$/.test(text) ? text : void 0;
656
+ }
619
657
  function cat062(id, d, out, raw) {
620
658
  switch (id) {
621
659
  case "080":
@@ -667,14 +705,33 @@ function cat062(id, d, out, raw) {
667
705
  out.targetType = "vehicle";
668
706
  break;
669
707
  }
708
+ case "245": {
709
+ const cs = str(raw, "TId");
710
+ const text = cs !== void 0 ? cs : d.length >= 7 ? readCallsign(d.subarray(1)) : "";
711
+ if (text) out.callsign = text;
712
+ break;
713
+ }
714
+ case "390": {
715
+ if (out.callsign === void 0) {
716
+ const csn = flightPlanCallsign(d);
717
+ if (csn) out.callsign = csn;
718
+ }
719
+ break;
720
+ }
670
721
  case "380": {
671
722
  let fsLen = 0;
672
723
  while (fsLen < d.length) {
673
724
  fsLen++;
674
725
  if ((d[fsLen - 1] & 1) === 0) break;
675
726
  }
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");
727
+ let at = fsLen;
728
+ if (fsLen < d.length && (d[0] & 128) !== 0 && d.length >= at + 3) {
729
+ out.icao24 = d.readUIntBE(at, 3).toString(16).padStart(6, "0");
730
+ at += 3;
731
+ }
732
+ if (fsLen < d.length && (d[0] & 64) !== 0 && d.length >= at + 6 && out.callsign === void 0) {
733
+ const id2 = readCallsign(d.subarray(at, at + 6));
734
+ if (id2) out.callsign = id2;
678
735
  }
679
736
  break;
680
737
  }
@@ -863,6 +920,14 @@ var EDITIONS = {
863
920
  };
864
921
  function parseAsterix(buf, defaultEdition) {
865
922
  const records = [];
923
+ for (const block of parseAsterixBlocks(buf, defaultEdition)) {
924
+ if (block.edition === null) continue;
925
+ for (const fields of block.records) records.push({ category: block.category, edition: block.edition, fields });
926
+ }
927
+ return records;
928
+ }
929
+ function parseAsterixBlocks(buf, defaultEdition) {
930
+ const blocks = [];
866
931
  let offset = 0;
867
932
  while (offset + 3 <= buf.length) {
868
933
  const cat = buf[offset];
@@ -875,26 +940,56 @@ function parseAsterix(buf, defaultEdition) {
875
940
  for (const edition of toTry) {
876
941
  const def = loadDef(cat, edition);
877
942
  if (!def) continue;
878
- const fields = {};
879
- try {
880
- decodeBlock(block, def, (id, data, itemDef) => {
881
- const bits = itemDef.type === "fixed" || itemDef.type === "variable" ? itemDef.bits : void 0;
882
- const bitData = itemDef.type === "variable" ? data.subarray(0, itemDef.chunkBytes) : data;
883
- const raw = bits?.length ? extractBitFields(bitData, bits) : {};
884
- decodeKnownField(cat, id, data, fields, raw);
885
- });
886
- } catch {
887
- continue;
888
- }
889
- if (!isPlausible(fields)) continue;
890
- const score = plausibilityScore(fields);
891
- if (!best || score > best.score) {
892
- best = { edition, fields, score };
943
+ const { all, consumed, full } = decodeRecords(block, def, cat);
944
+ const first = all[0];
945
+ if (!first) continue;
946
+ const score = plausibilityScore(first);
947
+ if (!best || full && !best.full || full === best.full && score > best.score) {
948
+ best = { edition, all, consumed, score, full };
893
949
  }
894
950
  }
895
- if (best) records.push({ category: cat, edition: best.edition, fields: best.fields });
951
+ blocks.push({
952
+ category: cat,
953
+ edition: best?.edition ?? null,
954
+ length: block.length,
955
+ consumed: best?.consumed ?? 0,
956
+ clean: best?.full ?? false,
957
+ records: best?.all ?? []
958
+ });
896
959
  }
897
- return records;
960
+ return blocks;
961
+ }
962
+ function decodeRecords(block, def, cat) {
963
+ const records = [];
964
+ let pos = 0;
965
+ let clean = false;
966
+ while (pos < block.length) {
967
+ const fields = {};
968
+ let result;
969
+ try {
970
+ result = decodeBlock(block.subarray(pos), def, (id, data, itemDef) => {
971
+ const bits = itemDef.type === "fixed" || itemDef.type === "variable" ? itemDef.bits : void 0;
972
+ const bitData = itemDef.type === "variable" ? data.subarray(0, itemDef.chunkBytes) : data;
973
+ const raw = bits?.length ? extractBitFields(bitData, bits) : {};
974
+ decodeKnownField(cat, id, data, fields, raw);
975
+ });
976
+ } catch {
977
+ break;
978
+ }
979
+ if (!isPlausible(fields)) break;
980
+ if (result.overrun && records.length > 0) break;
981
+ records.push({ fields, end: pos + result.end });
982
+ if (!result.complete || result.end <= 0 || result.overrun) break;
983
+ pos += result.end;
984
+ clean = pos >= block.length;
985
+ }
986
+ if (clean) {
987
+ const kept = records.filter((r, i) => i === 0 || Object.keys(r.fields).length > 0).map((r) => r.fields);
988
+ return { all: kept, consumed: block.length, full: true };
989
+ }
990
+ const firstEmpty = records.findIndex((r, i) => i > 0 && Object.keys(r.fields).length === 0);
991
+ const usable = firstEmpty === -1 ? records : records.slice(0, firstEmpty);
992
+ return { all: usable.map((r) => r.fields), consumed: usable.length > 0 ? usable[usable.length - 1].end : 0, full: false };
898
993
  }
899
994
  function isPlausible(f) {
900
995
  if (f.lat !== void 0 && (f.lat < -90 || f.lat > 90)) return false;
@@ -1249,6 +1344,7 @@ export {
1249
1344
  decodeMlatFrame,
1250
1345
  parseAftn,
1251
1346
  parseAsterix,
1347
+ parseAsterixBlocks,
1252
1348
  resolveAsterixAltitudeFt,
1253
1349
  resolveAsterixPosition,
1254
1350
  splitAftnStream
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cat062.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cat062.test.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/cat062.test.ts"],"names":[],"mappings":""}
@@ -4,11 +4,21 @@ export declare function parseFspec(buf: Buffer, start?: number): {
4
4
  bits: boolean[];
5
5
  end: number;
6
6
  };
7
- /** Advance offset past one DataItem, returning new offset. */
7
+ /**
8
+ * Advance offset past one DataItem, returning new offset. The result is NOT clamped to the buffer: an offset past
9
+ * `buf.length` means the item needs more octets than there are (an overrun), which `decodeBlock` reports.
10
+ */
8
11
  export declare function skipItem(buf: Buffer, off: number, def: ItemDef): number;
9
12
  /**
10
- * Decode one ASTERIX data block (everything after the 3-byte header).
11
- * Calls `onField(id, bytes, itemDef)` for each present DataItem.
13
+ * Decode ONE record at the start of `block` (a data block can carry many records back to back, each with its own
14
+ * FSPEC). Calls `onField(id, bytes, itemDef)` for each present DataItem. Returns where the record ended, so the caller
15
+ * can go on with the next one, and whether that position can be trusted: `complete` is false when an item the
16
+ * definition does not know stopped the decode (the length of what follows is then unknown); `overrun` is true when an
17
+ * item needed more octets than the block has (the record is cut short or an item was sized wrongly).
12
18
  */
13
- export declare function decodeBlock(block: Buffer, def: AsterixDef, onField: (id: string, data: Buffer, itemDef: ItemDef) => void): void;
19
+ export declare function decodeBlock(block: Buffer, def: AsterixDef, onField: (id: string, data: Buffer, itemDef: ItemDef) => void): {
20
+ end: number;
21
+ complete: boolean;
22
+ overrun: boolean;
23
+ };
14
24
  //# sourceMappingURL=decoder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI3D,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAUnF;AAID,8DAA8D;AAC9D,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAiDvE;AAID;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAC5D,IAAI,CAyBN"}
1
+ {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI3D,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAUnF;AAID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAiDvE;AAID;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,IAAI,GAC5D;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CA2BtD"}
@@ -1,4 +1,5 @@
1
- export { parseAsterix } from './parser.js';
1
+ export { parseAsterix, parseAsterixBlocks } from './parser.js';
2
+ export type { AsterixBlockInfo } from './parser.js';
2
3
  export { resolveAsterixPosition, resolveAsterixAltitudeFt } from './resolvers.js';
3
4
  export type { RadarSite } from './resolvers.js';
4
5
  export type { AsterixRecord, AsterixFields } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC/D,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAClF,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { AsterixRecord } from './types.js';
1
+ import type { AsterixRecord, AsterixFields } from './types.js';
2
2
  /**
3
3
  * Parse raw ASTERIX UDP datagram into structured records.
4
4
  *
@@ -13,4 +13,21 @@ import type { AsterixRecord } from './types.js';
13
13
  * Use when you know the sender's edition for certainty.
14
14
  */
15
15
  export declare function parseAsterix(buf: Buffer, defaultEdition?: Record<number, string>): AsterixRecord[];
16
+ /** What became of one data block: the edition that fit (null = none, the block is dropped), its records, and how much of the block they used. */
17
+ export interface AsterixBlockInfo {
18
+ category: number;
19
+ edition: string | null;
20
+ /** Octets of the block after its 3-octet header. */
21
+ length: number;
22
+ /** Octets taken up by the decoded records. */
23
+ consumed: number;
24
+ /** The records tile the block exactly: no octets left over, none missing, no item that ran past the end. False points at an item sized wrongly or a tail that was not understood. */
25
+ clean: boolean;
26
+ records: AsterixFields[];
27
+ }
28
+ /**
29
+ * Same decoding as `parseAsterix`, block by block, with the facts needed to judge it (see `AsterixBlockInfo`). For tools
30
+ * that check a decoder against a capture; `parseAsterix` is built on it.
31
+ */
32
+ export declare function parseAsterixBlocks(buf: Buffer, defaultEdition?: Record<number, string>): AsterixBlockInfo[];
16
33
  //# sourceMappingURL=parser.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAiB,MAAM,YAAY,CAAC;AAsB/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,aAAa,EAAE,CA6CjB"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAsB/D;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,aAAa,EAAE,CAOjB;AAED,iJAAiJ;AACjJ,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,qLAAqL;IACrL,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,aAAa,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtC,gBAAgB,EAAE,CA2CpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=repetitive.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repetitive.test.d.ts","sourceRoot":"","sources":["../../../src/surveillance/asterix/repetitive.test.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeroswarm/codec",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",