@aeroswarm/client 0.1.14 → 0.1.15
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 +25 -0
- package/dist/{index-CyxVoJXL.d.ts → index-CeayQnTp.d.ts} +121 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +124 -4
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +23 -2
- package/dist/react/index.js +194 -25
- package/dist/react/index.js.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +49 -4
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -470,6 +470,31 @@ catch (e) {
|
|
|
470
470
|
```
|
|
471
471
|
Servers answer either in the standard format (`{ ok, data, meta }` / `{ ok: false, error: { code, message, recoverable } }`, see `@aeroswarm/core/api`) or in the older shape (bare data, `{ ok: false, error: "text" }`); both are read. Federated calls send `x-aero-envelope: 1` to get the standard format. `parseApiResponse(res)` and `readApiBody(res)` are exported for your own `fetch` calls.
|
|
472
472
|
|
|
473
|
+
### `tracks.trail` / `createTrailPoller` / `useTrackTrail` — the path an aircraft has flown
|
|
474
|
+
|
|
475
|
+
The airport's backend builds the trail (memory first, stored history as a fallback), so the client computes nothing: it gets a GeoJSON `FeatureCollection` with one `LineString` (`[lon, lat, altitude m]`) and a `Point` per time mark, each with `properties.label` already written in the time zone you ask for.
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
const { trail } = await client.tracks.trail({
|
|
479
|
+
trackId,
|
|
480
|
+
endpoint: "https://asmgcs.example/aero", // the airport backend (or an airportId with a historyEndpoint)
|
|
481
|
+
tz: "Asia/Jakarta", // labels such as "01-11-26 11:16"; default UTC
|
|
482
|
+
});
|
|
483
|
+
// whole flight by default. fromMs/toMs: a period. stepM: coarser line. limit: at most n points. labelEveryMs: marks (default 2 min)
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
Keep it current while an aircraft is selected: the first request is the whole trail, after that only what is new is fetched (`sinceMs`), so polling every few seconds costs a few hundred bytes.
|
|
487
|
+
|
|
488
|
+
```ts
|
|
489
|
+
const poller = createTrailPoller(
|
|
490
|
+
(sinceMs) => client.tracks.trail({ trackId, endpoint, tz: "Asia/Jakarta", sinceMs }),
|
|
491
|
+
{ pollMs: 5000, onUpdate: (trail) => draw(trail) }, // draw the line, and each mark's properties.label
|
|
492
|
+
);
|
|
493
|
+
poller.stop(); // when it is deselected
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
React: `const { trail, loading, error } = useTrackTrail(selectedTrackId, { endpoint, tz: "Asia/Jakarta" })` (pass `null` while nothing is selected). A fixed period (`toMs`) is fetched once. A trail already shown stays when a request fails; polling stops for good when the server says the track is unknown (`NOT_FOUND`). `mergeTrail(prev, delta)` and `trailEnd(trail)` are exported if you manage the polling yourself. To end the line at the icon, draw one more segment from the trail's last point to `createTrackMotion().sample(trackId)`.
|
|
497
|
+
|
|
473
498
|
### `useTrackMotion` / `createTrackMotion` — smooth live tracks
|
|
474
499
|
|
|
475
500
|
Feeds update a track once a second (MLAT, ADS-B) or once per antenna sweep (radar, ~7.5 s). Drawn as they arrive, icons jump. `createTrackMotion` (no React needed) shows where the aircraft *probably is right now* and eases corrections in, like a flight tracker:
|
|
@@ -264,6 +264,101 @@ declare class AeroReplayClient {
|
|
|
264
264
|
declare function createAeroTrpcClient(endpoint: string, token: string): _trpc_client.TRPCClient<any>;
|
|
265
265
|
type AeroTrpcClient = ReturnType<typeof createAeroTrpcClient>;
|
|
266
266
|
|
|
267
|
+
interface TrailLine {
|
|
268
|
+
type: "Feature";
|
|
269
|
+
properties: {
|
|
270
|
+
kind: "trail";
|
|
271
|
+
trackId: string;
|
|
272
|
+
/** epoch ms of the first and the last point */
|
|
273
|
+
from: number;
|
|
274
|
+
to: number;
|
|
275
|
+
/** spacing of the points, metres */
|
|
276
|
+
stepM: number;
|
|
277
|
+
/** the line starts at the beginning of the flight (nothing older exists) */
|
|
278
|
+
fromStart: boolean;
|
|
279
|
+
};
|
|
280
|
+
/** [lon, lat, altitude in metres] */
|
|
281
|
+
geometry: {
|
|
282
|
+
type: "LineString";
|
|
283
|
+
coordinates: Array<[number, number, number]>;
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
interface TrailMark {
|
|
287
|
+
type: "Feature";
|
|
288
|
+
/** `label` is ready to display, e.g. "01-11-26 11:16" */
|
|
289
|
+
properties: {
|
|
290
|
+
kind: "mark";
|
|
291
|
+
t: number;
|
|
292
|
+
label: string;
|
|
293
|
+
};
|
|
294
|
+
geometry: {
|
|
295
|
+
type: "Point";
|
|
296
|
+
coordinates: [number, number];
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
interface TrailFeatureCollection {
|
|
300
|
+
type: "FeatureCollection";
|
|
301
|
+
features: Array<TrailLine | TrailMark>;
|
|
302
|
+
}
|
|
303
|
+
interface TrailMeta {
|
|
304
|
+
serverTime?: number;
|
|
305
|
+
count?: number;
|
|
306
|
+
/** the server dropped points to honour `limit` */
|
|
307
|
+
truncated?: boolean;
|
|
308
|
+
}
|
|
309
|
+
interface TrailResult {
|
|
310
|
+
trail: TrailFeatureCollection;
|
|
311
|
+
meta?: TrailMeta;
|
|
312
|
+
}
|
|
313
|
+
interface TrailRequest {
|
|
314
|
+
trackId: string;
|
|
315
|
+
/** The airport backend's base URL (its `/aero` mount). Without it `airportId` must have a registered historyEndpoint. */
|
|
316
|
+
endpoint?: string;
|
|
317
|
+
airportId?: string;
|
|
318
|
+
/** A period instead of the whole flight (epoch ms). */
|
|
319
|
+
fromMs?: number;
|
|
320
|
+
toMs?: number;
|
|
321
|
+
/** Only what is newer than this: for keeping a trail current. */
|
|
322
|
+
sinceMs?: number;
|
|
323
|
+
/** Coarser spacing than the server stores, metres. */
|
|
324
|
+
stepM?: number;
|
|
325
|
+
/** At most this many points. */
|
|
326
|
+
limit?: number;
|
|
327
|
+
/** A time mark every this many ms (default 120 000), aligned to the clock. 0 = none. */
|
|
328
|
+
labelEveryMs?: number;
|
|
329
|
+
/** Time zone of the labels, e.g. "Asia/Jakarta" (default UTC). */
|
|
330
|
+
tz?: string;
|
|
331
|
+
labelFormat?: "datetime" | "time";
|
|
332
|
+
}
|
|
333
|
+
/** Time of the last point of a trail; undefined when it has none. What to pass as `sinceMs`. */
|
|
334
|
+
declare function trailEnd(trail: TrailFeatureCollection): number | undefined;
|
|
335
|
+
/**
|
|
336
|
+
* Appends a delta (a request with `sinceMs`) to the trail you already have. Returns `prev`
|
|
337
|
+
* itself when the delta adds nothing, so a caller can tell nothing changed.
|
|
338
|
+
*/
|
|
339
|
+
declare function mergeTrail(prev: TrailFeatureCollection | undefined, delta: TrailFeatureCollection): TrailFeatureCollection;
|
|
340
|
+
interface TrailPollerOptions {
|
|
341
|
+
/** How often to ask for what is new. Default 5000. 0 or less: fetch once and stop. */
|
|
342
|
+
pollMs?: number;
|
|
343
|
+
/** Called with the whole trail, first when it arrives, then each time it grows. */
|
|
344
|
+
onUpdate: (trail: TrailFeatureCollection) => void;
|
|
345
|
+
onError?: (err: unknown) => void;
|
|
346
|
+
/** Stop for good when the server says the track is unknown (it left and its retention ended). Default true. */
|
|
347
|
+
stopWhenGone?: boolean;
|
|
348
|
+
}
|
|
349
|
+
interface TrailPoller {
|
|
350
|
+
stop(): void;
|
|
351
|
+
/** Ask now instead of waiting for the next tick. */
|
|
352
|
+
refresh(): Promise<void>;
|
|
353
|
+
/** The trail as it stands. */
|
|
354
|
+
current(): TrailFeatureCollection | undefined;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Fetches a trail once and then keeps it current by asking only for what is new.
|
|
358
|
+
* Framework-free: `useTrackTrail` is a thin wrapper around it.
|
|
359
|
+
*/
|
|
360
|
+
declare function createTrailPoller(fetchTrail: (sinceMs?: number) => Promise<TrailResult>, options: TrailPollerOptions): TrailPoller;
|
|
361
|
+
|
|
267
362
|
declare class AeroGraphQLClient {
|
|
268
363
|
private readonly endpoint;
|
|
269
364
|
private readonly token;
|
|
@@ -358,6 +453,21 @@ declare class AeroApiError extends Error {
|
|
|
358
453
|
* envelope themselves (`r.data.x`).
|
|
359
454
|
*/
|
|
360
455
|
declare function readApiBody(res: Response, label?: string): Promise<unknown>;
|
|
456
|
+
/** What a standard response says about itself (see `meta` in @aeroswarm/core/api). Absent for servers that answer with bare data. */
|
|
457
|
+
interface ApiMetaLike {
|
|
458
|
+
serverTime?: number;
|
|
459
|
+
count?: number;
|
|
460
|
+
nextCursor?: string;
|
|
461
|
+
truncated?: boolean;
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* The data of a response together with its `meta`: unwrapped from `{ ok, data, meta }`, or the body
|
|
465
|
+
* as it is (and no meta) for servers that answer with bare data. Throws `AeroApiError` on failure.
|
|
466
|
+
*/
|
|
467
|
+
declare function parseApiEnvelope<T>(res: Response, label?: string): Promise<{
|
|
468
|
+
data: T;
|
|
469
|
+
meta?: ApiMetaLike;
|
|
470
|
+
}>;
|
|
361
471
|
/**
|
|
362
472
|
* The data of a response: unwrapped from `{ ok, data }`, or the body as it is for servers
|
|
363
473
|
* that answer with bare data. Throws `AeroApiError` on failure.
|
|
@@ -423,6 +533,7 @@ declare class AeroSwarm {
|
|
|
423
533
|
* (a broken airports.list() call must never brick replay/history for
|
|
424
534
|
* everyone else). */
|
|
425
535
|
private resolveHistoryEndpoint;
|
|
536
|
+
private federatedRequest;
|
|
426
537
|
private federatedFetch;
|
|
427
538
|
constructor(opts: AeroSwarmOptions);
|
|
428
539
|
readonly tracks: {
|
|
@@ -451,6 +562,15 @@ declare class AeroSwarm {
|
|
|
451
562
|
limit?: number;
|
|
452
563
|
endpoint?: string;
|
|
453
564
|
}) => Promise<TrackHistoryPoint[]>;
|
|
565
|
+
/**
|
|
566
|
+
* The path an aircraft has flown, ready to draw: a GeoJSON line plus a point for every time
|
|
567
|
+
* mark, with the label already written in `tz`. By default the whole flight so far; `fromMs`
|
|
568
|
+
* and `toMs` choose a period, `sinceMs` fetches only what is new (see `createTrailPoller`),
|
|
569
|
+
* `stepM` asks for a coarser line. The airport's backend builds it (memory first, history
|
|
570
|
+
* as a fallback), so nothing is computed here. There is no AeroSwarm-side equivalent:
|
|
571
|
+
* pass `endpoint` or an `airportId` with a registered `historyEndpoint`.
|
|
572
|
+
*/
|
|
573
|
+
trail: (input: TrailRequest) => Promise<TrailResult>;
|
|
454
574
|
};
|
|
455
575
|
/** Flight plans received from AFTN feeds. Live tracks that correlate with a
|
|
456
576
|
* plan (Mode-S address, else callsign) also carry `track.flightPlan`. */
|
|
@@ -730,4 +850,4 @@ declare class AeroSwarm {
|
|
|
730
850
|
reconnect(): boolean;
|
|
731
851
|
}
|
|
732
852
|
|
|
733
|
-
export { AeroApiError as A, type DayAvailability as D, type FlightPlanRow as F, LABEL_COLORS as L, type ReplayCallbacks as R, type SourceRow as S, TrackCache as T, type UseAeroTracksResult as U, AeroReplayClient as a, AeroSwarm as b, type AeroSwarmOptions as c, AeroWsClient as d, type AftnMessageRow as e, type ApiErrorCode as f, type ApiErrorInit as g, type
|
|
853
|
+
export { AeroApiError as A, codeForStatus as B, createTrailPoller as C, type DayAvailability as D, getLabelCategory as E, type FlightPlanRow as F, mergeTrail as G, parseApiEnvelope as H, parseApiResponse as I, readApiBody as J, trailEnd as K, LABEL_COLORS as L, withLabel as M, type ReplayCallbacks as R, type SourceRow as S, TrackCache as T, type UseAeroTracksResult as U, AeroReplayClient as a, AeroSwarm as b, type AeroSwarmOptions as c, AeroWsClient as d, type AftnMessageRow as e, type ApiErrorCode as f, type ApiErrorInit as g, type ApiMetaLike as h, type LabelCategory as i, type LabeledTrack as j, type LiveTrackCallbacks as k, type ReplayHandle as l, type ReplayProgress as m, type ReplayStreamOptions as n, type StreamMeta as o, type SubscribeOptions as p, type TrackCallbacks as q, type TrackHistoryPoint as r, type TrailFeatureCollection as s, type TrailLine as t, type TrailMark as u, type TrailMeta as v, type TrailPoller as w, type TrailPollerOptions as x, type TrailRequest as y, type TrailResult as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AeroApiError, a as AeroReplayClient, b as AeroSwarm, c as AeroSwarmOptions, d as AeroWsClient, e as AftnMessageRow, f as ApiErrorCode, g as ApiErrorInit, D as DayAvailability, F as FlightPlanRow, L as LABEL_COLORS,
|
|
1
|
+
export { A as AeroApiError, a as AeroReplayClient, b as AeroSwarm, c as AeroSwarmOptions, d as AeroWsClient, e as AftnMessageRow, f as ApiErrorCode, g as ApiErrorInit, h as ApiMetaLike, D as DayAvailability, F as FlightPlanRow, L as LABEL_COLORS, i as LabelCategory, j as LabeledTrack, k as LiveTrackCallbacks, R as ReplayCallbacks, l as ReplayHandle, m as ReplayProgress, n as ReplayStreamOptions, S as SourceRow, o as StreamMeta, p as SubscribeOptions, T as TrackCache, q as TrackCallbacks, r as TrackHistoryPoint, s as TrailFeatureCollection, t as TrailLine, u as TrailMark, v as TrailMeta, w as TrailPoller, x as TrailPollerOptions, y as TrailRequest, z as TrailResult, U as UseAeroTracksResult, B as codeForStatus, C as createTrailPoller, E as getLabelCategory, G as mergeTrail, H as parseApiEnvelope, I as parseApiResponse, J as readApiBody, K as trailEnd, M as withLabel } from './index-CeayQnTp.js';
|
|
2
2
|
import { CurrentTrack } from '@aeroswarm/core/types';
|
|
3
3
|
export { AeroConnectionStatus, AeroRecoverableError, Bbox, ConfidenceBudget, CurrentTrack, DataSource, FlightPhase, FlightPlan, FlightPlanStatus, FlightPlanSummary, FusedTrackEvent, Position, Protocol, SourceHealthEvent, SourceStatus, StreamEnvelope, TrackSource, TrackStatus, Velocity } from '@aeroswarm/core/types';
|
|
4
4
|
export { clamp, haversineKm, isInsideBbox, isRenderableTrack, toCurrentTrack } from '@aeroswarm/core/utils';
|
package/dist/index.js
CHANGED
|
@@ -388,9 +388,14 @@ async function readApiBody(res, label) {
|
|
|
388
388
|
if (!res.ok || isFailure(body)) throw errorFrom(res, body, text, label);
|
|
389
389
|
return body;
|
|
390
390
|
}
|
|
391
|
-
async function
|
|
391
|
+
async function parseApiEnvelope(res, label) {
|
|
392
392
|
const body = await readApiBody(res, label);
|
|
393
|
-
|
|
393
|
+
if (!isEnvelope(body)) return { data: body };
|
|
394
|
+
const meta = body.meta;
|
|
395
|
+
return { data: body.data, ...isObject(meta) && { meta } };
|
|
396
|
+
}
|
|
397
|
+
async function parseApiResponse(res, label) {
|
|
398
|
+
return (await parseApiEnvelope(res, label)).data;
|
|
394
399
|
}
|
|
395
400
|
|
|
396
401
|
// src/sdk/api/rest.ts
|
|
@@ -629,13 +634,16 @@ var AeroSwarm = class _AeroSwarm {
|
|
|
629
634
|
return null;
|
|
630
635
|
}
|
|
631
636
|
}
|
|
632
|
-
async
|
|
637
|
+
async federatedRequest(base, path, query) {
|
|
633
638
|
const url = new URL(`${base}${path}`);
|
|
634
639
|
for (const [k, v] of Object.entries(query ?? {})) if (v !== void 0) url.searchParams.set(k, v);
|
|
635
640
|
const res = await fetch(url, {
|
|
636
641
|
headers: { Authorization: `Bearer ${this.opts.token}`, [ENVELOPE_HEADER]: "1" }
|
|
637
642
|
});
|
|
638
|
-
return
|
|
643
|
+
return parseApiEnvelope(res, `Federated request ${url.pathname}`);
|
|
644
|
+
}
|
|
645
|
+
async federatedFetch(base, path, query) {
|
|
646
|
+
return (await this.federatedRequest(base, path, query)).data;
|
|
639
647
|
}
|
|
640
648
|
tracks = {
|
|
641
649
|
subscribe: (opts, callbacks) => {
|
|
@@ -726,6 +734,42 @@ var AeroSwarm = class _AeroSwarm {
|
|
|
726
734
|
});
|
|
727
735
|
}
|
|
728
736
|
return this.trpc.tracks.history.query(input);
|
|
737
|
+
},
|
|
738
|
+
/**
|
|
739
|
+
* The path an aircraft has flown, ready to draw: a GeoJSON line plus a point for every time
|
|
740
|
+
* mark, with the label already written in `tz`. By default the whole flight so far; `fromMs`
|
|
741
|
+
* and `toMs` choose a period, `sinceMs` fetches only what is new (see `createTrailPoller`),
|
|
742
|
+
* `stepM` asks for a coarser line. The airport's backend builds it (memory first, history
|
|
743
|
+
* as a fallback), so nothing is computed here. There is no AeroSwarm-side equivalent:
|
|
744
|
+
* pass `endpoint` or an `airportId` with a registered `historyEndpoint`.
|
|
745
|
+
*/
|
|
746
|
+
trail: async (input) => {
|
|
747
|
+
const base = await this.resolveHistoryEndpoint(input.airportId, input.endpoint);
|
|
748
|
+
if (!base) {
|
|
749
|
+
throw new AeroApiError({
|
|
750
|
+
status: 400,
|
|
751
|
+
code: "BAD_REQUEST",
|
|
752
|
+
recoverable: false,
|
|
753
|
+
message: "tracks.trail needs the airport's backend: pass `endpoint`, or an `airportId` that has a historyEndpoint"
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
const num = (v) => v === void 0 ? void 0 : String(v);
|
|
757
|
+
const { data, meta } = await this.federatedRequest(
|
|
758
|
+
base,
|
|
759
|
+
`/tracks/${encodeURIComponent(input.trackId)}/trail`,
|
|
760
|
+
{
|
|
761
|
+
fromMs: num(input.fromMs),
|
|
762
|
+
toMs: num(input.toMs),
|
|
763
|
+
sinceMs: num(input.sinceMs),
|
|
764
|
+
stepM: num(input.stepM),
|
|
765
|
+
limit: num(input.limit),
|
|
766
|
+
labelEveryMs: num(input.labelEveryMs),
|
|
767
|
+
tz: input.tz,
|
|
768
|
+
labelFormat: input.labelFormat,
|
|
769
|
+
format: "geojson"
|
|
770
|
+
}
|
|
771
|
+
);
|
|
772
|
+
return { trail: data, ...meta && { meta } };
|
|
729
773
|
}
|
|
730
774
|
};
|
|
731
775
|
/** Flight plans received from AFTN feeds. Live tracks that correlate with a
|
|
@@ -1199,6 +1243,78 @@ function formatDataSource(track) {
|
|
|
1199
1243
|
const ds = track.dataSource;
|
|
1200
1244
|
return ds ? `${kind} ${ds.sac}/${ds.sic}` : kind;
|
|
1201
1245
|
}
|
|
1246
|
+
|
|
1247
|
+
// src/shared/trail/index.ts
|
|
1248
|
+
var lineOf = (fc) => fc.features.find((f) => f.properties.kind === "trail");
|
|
1249
|
+
var marksOf = (fc) => fc.features.filter((f) => f.properties.kind === "mark");
|
|
1250
|
+
function trailEnd(trail) {
|
|
1251
|
+
const line = lineOf(trail);
|
|
1252
|
+
return line && line.geometry.coordinates.length > 0 ? line.properties.to : void 0;
|
|
1253
|
+
}
|
|
1254
|
+
function mergeTrail(prev, delta) {
|
|
1255
|
+
if (!prev) return delta;
|
|
1256
|
+
const before = lineOf(prev);
|
|
1257
|
+
const added = lineOf(delta);
|
|
1258
|
+
if (!before || !added) return prev;
|
|
1259
|
+
if (added.geometry.coordinates.length === 0) return prev;
|
|
1260
|
+
const seen = new Set(marksOf(prev).map((m) => m.properties.t));
|
|
1261
|
+
const newMarks = marksOf(delta).filter((m) => !seen.has(m.properties.t));
|
|
1262
|
+
const line = {
|
|
1263
|
+
...before,
|
|
1264
|
+
properties: { ...before.properties, to: added.properties.to, stepM: Math.max(before.properties.stepM, added.properties.stepM) },
|
|
1265
|
+
geometry: { type: "LineString", coordinates: [...before.geometry.coordinates, ...added.geometry.coordinates] }
|
|
1266
|
+
};
|
|
1267
|
+
return { type: "FeatureCollection", features: [line, ...marksOf(prev), ...newMarks] };
|
|
1268
|
+
}
|
|
1269
|
+
var isGone = (err) => typeof err === "object" && err !== null && err.code === "NOT_FOUND";
|
|
1270
|
+
function createTrailPoller(fetchTrail, options) {
|
|
1271
|
+
const pollMs = options.pollMs ?? 5e3;
|
|
1272
|
+
const stopWhenGone = options.stopWhenGone ?? true;
|
|
1273
|
+
let current;
|
|
1274
|
+
let stopped = false;
|
|
1275
|
+
let timer;
|
|
1276
|
+
let running;
|
|
1277
|
+
const schedule = () => {
|
|
1278
|
+
if (stopped || pollMs <= 0) return;
|
|
1279
|
+
timer = setTimeout(() => void tick(), pollMs);
|
|
1280
|
+
};
|
|
1281
|
+
async function once() {
|
|
1282
|
+
try {
|
|
1283
|
+
const since = current ? trailEnd(current) : void 0;
|
|
1284
|
+
const { trail } = await fetchTrail(since);
|
|
1285
|
+
if (stopped) return;
|
|
1286
|
+
const next = mergeTrail(current, trail);
|
|
1287
|
+
if (next !== current) {
|
|
1288
|
+
current = next;
|
|
1289
|
+
options.onUpdate(next);
|
|
1290
|
+
}
|
|
1291
|
+
} catch (err) {
|
|
1292
|
+
if (stopped) return;
|
|
1293
|
+
options.onError?.(err);
|
|
1294
|
+
if (stopWhenGone && isGone(err)) stopped = true;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
function tick() {
|
|
1298
|
+
if (stopped) return Promise.resolve();
|
|
1299
|
+
running ??= once().finally(() => {
|
|
1300
|
+
running = void 0;
|
|
1301
|
+
schedule();
|
|
1302
|
+
});
|
|
1303
|
+
return running;
|
|
1304
|
+
}
|
|
1305
|
+
void tick();
|
|
1306
|
+
return {
|
|
1307
|
+
stop() {
|
|
1308
|
+
stopped = true;
|
|
1309
|
+
if (timer) clearTimeout(timer);
|
|
1310
|
+
},
|
|
1311
|
+
async refresh() {
|
|
1312
|
+
if (timer) clearTimeout(timer);
|
|
1313
|
+
await (running ?? tick());
|
|
1314
|
+
},
|
|
1315
|
+
current: () => current
|
|
1316
|
+
};
|
|
1317
|
+
}
|
|
1202
1318
|
export {
|
|
1203
1319
|
AeroApiError,
|
|
1204
1320
|
AeroReplayClient,
|
|
@@ -1209,15 +1325,19 @@ export {
|
|
|
1209
1325
|
clamp,
|
|
1210
1326
|
codeForStatus,
|
|
1211
1327
|
createTrackMotion,
|
|
1328
|
+
createTrailPoller,
|
|
1212
1329
|
formatDataSource,
|
|
1213
1330
|
getLabelCategory,
|
|
1214
1331
|
haversineKm,
|
|
1215
1332
|
isInsideBbox,
|
|
1216
1333
|
isRenderableTrack2 as isRenderableTrack,
|
|
1334
|
+
mergeTrail,
|
|
1335
|
+
parseApiEnvelope,
|
|
1217
1336
|
parseApiResponse,
|
|
1218
1337
|
readApiBody,
|
|
1219
1338
|
sourceLabel,
|
|
1220
1339
|
toCurrentTrack,
|
|
1340
|
+
trailEnd,
|
|
1221
1341
|
withLabel
|
|
1222
1342
|
};
|
|
1223
1343
|
//# sourceMappingURL=index.js.map
|