@aeroswarm/client 0.1.13 → 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 +63 -17
- package/dist/index-ByNBpjNk.d.ts +75 -0
- package/dist/{index-BXiTmKdS.d.ts → index-CeayQnTp.d.ts} +153 -1
- package/dist/index.d.ts +21 -74
- package/dist/index.js +240 -6
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +24 -4
- package/dist/react/index.js +275 -27
- package/dist/react/index.js.map +1 -1
- package/dist/sdk/index.d.ts +1 -1
- package/dist/sdk/index.js +135 -7
- package/dist/sdk/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -65,6 +65,23 @@ client.disconnect();
|
|
|
65
65
|
| `tracks.stream(opts)` | Same live stream as an `AsyncIterable<LabeledTrack>` (`for await`) |
|
|
66
66
|
| `tracks.updateFilter(opts)` | Change bbox / minConfidence / maxUpdateHz / maxTracks without reconnecting |
|
|
67
67
|
| `tracks.reconnect()` | Force an immediate reconnect (skips backoff, re-subscribes with the last options, resumes after `disconnect()`); `false` if never subscribed. Also `AeroSwarm.reconnect()` and `useAeroTracks().reconnect` |
|
|
68
|
+
| `tracks.snapshot(input?)` | One-shot current state via tRPC (`airportId`, `bbox`, `source`, `minConfidence`, `limit`, `offset`) |
|
|
69
|
+
| `tracks.history(input)` | Persisted position history for one track (`trackId`, `airportId?`, `limit?`) — federated airports are served by their own backend |
|
|
70
|
+
| `airports.*` | Airport registry: `list/create/update/delete` + `surface`/`setSurface` (runway/taxiway/apron GeoJSON for the map) |
|
|
71
|
+
| `sources.*` | Register/list (optionally by `airportId`)/delete data sources (returns per-source auth tokens) |
|
|
72
|
+
| `alerts.*` | Alert history + live alert subscription |
|
|
73
|
+
| `rules.*` | Detection-rule CRUD — **global or per-airport** (see example below) |
|
|
74
|
+
| `routes.*` | Route conformance: pre-defined ground routes + live track clearances (deviation alerts) |
|
|
75
|
+
| `analytics.movements()` | Takeoffs/landings per hour + peak hour, per airport |
|
|
76
|
+
| `webhooks.*` | Webhook CRUD |
|
|
77
|
+
| `replay.days(input?)` | Data-availability calendar — which days have recorded tracks (see example below) |
|
|
78
|
+
| `replay.range/seek/window` | Historical replay metadata: range summary, point-in-time seek, time-bucketed window for scrubbing |
|
|
79
|
+
| `replay.stream(opts, cb)` | **Server-paced WS playback** — historical tracks streamed like live (see example below) |
|
|
80
|
+
| `system.*` | `stats`, `infraHealth`, `getConfig`/`setConfig`, `clearTable`, `ingestHistory` |
|
|
81
|
+
| `trpc` / `rest` / `graphql` | Direct typed API clients for anything not wrapped above — **untyped** (`createTRPCProxyClient<any>`), so prefer the wrappers above; fall back to `client.trpc.<router>.<procedure>.query/mutate(...)` only for endpoints not yet wrapped |
|
|
82
|
+
| `cache` | A `TrackCache` instance (see below) |
|
|
83
|
+
| `getStatus()` / `getLastUpdateAt()` / `getError()` / `getSourceStatus()` | Connection introspection |
|
|
84
|
+
| `disconnect()` | Tear down the WS connection |
|
|
68
85
|
|
|
69
86
|
### Label category / color
|
|
70
87
|
|
|
@@ -106,6 +123,7 @@ The server sends JSON envelopes `{ type, seq, serverTime, payload }`. The client
|
|
|
106
123
|
"targetType": "aircraft", // optional: aircraft | vehicle | unknown
|
|
107
124
|
"vehicleFleet": 3, // optional, only for vehicles
|
|
108
125
|
"airportId": "WARR", // optional ICAO scope
|
|
126
|
+
"dataSource": { "sac": 32, "sic": 136 }, // optional: the sensor behind the position shown (ASTERIX feeds)
|
|
109
127
|
"lat": -7.3797, "lon": 112.7868,// number | null
|
|
110
128
|
"altitudeFt": 0,
|
|
111
129
|
"groundSpeedKt": 12,
|
|
@@ -127,23 +145,8 @@ The server sends JSON envelopes `{ type, seq, serverTime, payload }`. The client
|
|
|
127
145
|
```
|
|
128
146
|
|
|
129
147
|
`status` and `labelColor` change only when the track's category or status actually changes — position-only deltas leave them untouched, so a label painted from `labelColor` does not flicker.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
| `airports.*` | Airport registry: `list/create/update/delete` + `surface`/`setSurface` (runway/taxiway/apron GeoJSON for the map) |
|
|
133
|
-
| `sources.*` | Register/list (optionally by `airportId`)/delete data sources (returns per-source auth tokens) |
|
|
134
|
-
| `alerts.*` | Alert history + live alert subscription |
|
|
135
|
-
| `rules.*` | Detection-rule CRUD — **global or per-airport** (see example below) |
|
|
136
|
-
| `routes.*` | Route conformance: pre-defined ground routes + live track clearances (deviation alerts) |
|
|
137
|
-
| `analytics.movements()` | Takeoffs/landings per hour + peak hour, per airport |
|
|
138
|
-
| `webhooks.*` | Webhook CRUD |
|
|
139
|
-
| `replay.days(input?)` | Data-availability calendar — which days have recorded tracks (see example below) |
|
|
140
|
-
| `replay.range/seek/window` | Historical replay metadata: range summary, point-in-time seek, time-bucketed window for scrubbing |
|
|
141
|
-
| `replay.stream(opts, cb)` | **Server-paced WS playback** — historical tracks streamed like live (see example below) |
|
|
142
|
-
| `system.*` | `stats`, `infraHealth`, `getConfig`/`setConfig`, `clearTable`, `ingestHistory` |
|
|
143
|
-
| `trpc` / `rest` / `graphql` | Direct typed API clients for anything not wrapped above — **untyped** (`createTRPCProxyClient<any>`), so prefer the wrappers above; fall back to `client.trpc.<router>.<procedure>.query/mutate(...)` only for endpoints not yet wrapped |
|
|
144
|
-
| `cache` | A `TrackCache` instance (see below) |
|
|
145
|
-
| `getStatus()` / `getLastUpdateAt()` / `getError()` / `getSourceStatus()` | Connection introspection |
|
|
146
|
-
| `disconnect()` | Tear down the WS connection |
|
|
148
|
+
|
|
149
|
+
`dataSource` is the ASTERIX System Area / System Identification Code (SAC/SIC) of the sensor that reported the position shown (for a merged track, the sensor that is currently preferred). `formatDataSource(track)` gives the display string `"ADSB 32/136"` (`sourceLabel(track.source)` gives just the kind: `ADSB`, `SURFACE` for CAT010/011, `MLAT`, `RADAR`, `SYSTEM`, `FUSED`); without a SAC/SIC it is the kind alone.
|
|
147
150
|
|
|
148
151
|
## Per-domain usage examples
|
|
149
152
|
|
|
@@ -449,6 +452,49 @@ Shared live-track state; feed it from your subscription callbacks and read it im
|
|
|
449
452
|
| `setStatus` / `setSourceStatus` / `setError` / `setDegraded` / `clear` | Connection metadata |
|
|
450
453
|
| Selectors | `selectAllTracks`, `selectRenderableTracks`, `selectTrack(id)`, `selectTrackCount`, `selectStatus`, `selectIsDegraded`, `selectLastUpdateAt`, `selectError` |
|
|
451
454
|
|
|
455
|
+
### REST errors: `AeroApiError`
|
|
456
|
+
|
|
457
|
+
Every failed REST call (`client.rest.*`, federated `tracks.history` and the like) throws an `AeroApiError` that keeps what the server said, instead of just `GET /x → 500`:
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
try { await client.tracks.history({ trackId, airportId: "WARR" }); }
|
|
461
|
+
catch (e) {
|
|
462
|
+
if (e instanceof AeroApiError) {
|
|
463
|
+
e.status; // 403
|
|
464
|
+
e.code; // "FORBIDDEN" — stable, for switch; a newer server may send a code you do not know
|
|
465
|
+
e.recoverable; // retrying later may help (rate limit, server busy)
|
|
466
|
+
e.message; // "Federated request /tracks/t1/history → 403: not your airport"
|
|
467
|
+
e.details; // whatever the server attached
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
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
|
+
|
|
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
|
+
|
|
452
498
|
### `useTrackMotion` / `createTrackMotion` — smooth live tracks
|
|
453
499
|
|
|
454
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:
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { CurrentTrack } from '@aeroswarm/core/types';
|
|
2
|
+
|
|
3
|
+
/** What the engine reads from a track. */
|
|
4
|
+
type MotionInput = Pick<CurrentTrack, "trackId" | "lat" | "lon" | "groundSpeedKt" | "headingDeg" | "altitudeFt" | "status" | "lastSeenAt"> & {
|
|
5
|
+
targetType?: CurrentTrack["targetType"];
|
|
6
|
+
};
|
|
7
|
+
interface MotionSample {
|
|
8
|
+
lat: number;
|
|
9
|
+
lon: number;
|
|
10
|
+
/** Degrees 0..360, eased; null until a valid heading has been seen. */
|
|
11
|
+
headingDeg: number | null;
|
|
12
|
+
altitudeFt: number | null;
|
|
13
|
+
/** Speed is above `minMovingKt`. */
|
|
14
|
+
moving: boolean;
|
|
15
|
+
/** Position currently comes from dead reckoning (not frozen, limit not reached). */
|
|
16
|
+
extrapolating: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface MotionFrame {
|
|
19
|
+
/** Server-aligned time of this frame (ms). */
|
|
20
|
+
at: number;
|
|
21
|
+
/** Only tracks whose picture changed since the previous frame. */
|
|
22
|
+
changed: ReadonlyMap<string, MotionSample>;
|
|
23
|
+
}
|
|
24
|
+
interface MotionScheduler {
|
|
25
|
+
request(callback: (timestamp: number) => void): unknown;
|
|
26
|
+
cancel(handle: unknown): void;
|
|
27
|
+
}
|
|
28
|
+
interface MotionOptions {
|
|
29
|
+
/** How long a correction takes to fade out. Default 1500 ms. */
|
|
30
|
+
blendMs?: number;
|
|
31
|
+
/** How long the icon takes to turn to a new heading. Default 800 ms. */
|
|
32
|
+
headingSmoothMs?: number;
|
|
33
|
+
/** Dead reckoning stops after this long without a new fix. Default 20 s in the air, 8 s on the surface. */
|
|
34
|
+
maxExtrapolateMs?: {
|
|
35
|
+
air: number;
|
|
36
|
+
surface: number;
|
|
37
|
+
};
|
|
38
|
+
/** Below this speed a track is treated as standing still. Default 5 kt. */
|
|
39
|
+
minMovingKt?: number;
|
|
40
|
+
/** A correction larger than this is a glitch or a sensor change far away: jump instead of easing. Default 5000 m. */
|
|
41
|
+
snapDistanceM?: number;
|
|
42
|
+
/** Frame rate limit for `start()`. Default 30. */
|
|
43
|
+
frameHz?: number;
|
|
44
|
+
/** Changes smaller than this are not reported. Default 0.5 m (and 0.5 degrees of heading). */
|
|
45
|
+
epsilonM?: number;
|
|
46
|
+
/** false = show raw positions (for comparing against another source). Default true. */
|
|
47
|
+
extrapolate?: boolean;
|
|
48
|
+
/** Decides what counts as "on the surface". Default: vehicles, or below 150 ft. */
|
|
49
|
+
isSurface?: (track: MotionInput) => boolean;
|
|
50
|
+
/** Browser clock. Default Date.now. Inject the replay clock to play back at another speed. */
|
|
51
|
+
clock?: () => number;
|
|
52
|
+
/** Frame timer. Default requestAnimationFrame, else setTimeout. Inject in tests. */
|
|
53
|
+
scheduler?: MotionScheduler;
|
|
54
|
+
}
|
|
55
|
+
interface TrackMotion {
|
|
56
|
+
/** `meta.serverTime` (from the WS envelope) keeps the server/browser clock offset current. */
|
|
57
|
+
update(track: MotionInput, meta?: {
|
|
58
|
+
serverTime?: number;
|
|
59
|
+
}): void;
|
|
60
|
+
remove(trackId: string): void;
|
|
61
|
+
clear(): void;
|
|
62
|
+
/** Where the track is shown at `at` (browser time; default now). Pure: does not touch frame state. */
|
|
63
|
+
sample(trackId: string, at?: number): MotionSample | undefined;
|
|
64
|
+
/** One frame: the tracks whose picture changed since the previous frame. `start()` calls this for you. */
|
|
65
|
+
tick(at?: number): ReadonlyMap<string, MotionSample>;
|
|
66
|
+
/** Runs frames until the returned function is called. Idles (no timer) while nothing moves. */
|
|
67
|
+
start(onFrame: (frame: MotionFrame) => void): () => void;
|
|
68
|
+
/** Tracks currently held. */
|
|
69
|
+
readonly size: number;
|
|
70
|
+
/** Current server minus browser clock, ms. */
|
|
71
|
+
offsetMs(): number;
|
|
72
|
+
}
|
|
73
|
+
declare function createTrackMotion(options?: MotionOptions): TrackMotion;
|
|
74
|
+
|
|
75
|
+
export { type MotionFrame as M, type TrackMotion as T, type MotionInput as a, type MotionOptions as b, type MotionSample as c, type MotionScheduler as d, createTrackMotion as e };
|
|
@@ -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;
|
|
@@ -332,6 +427,53 @@ declare class TrackCache extends TypedEmitter<{
|
|
|
332
427
|
})[];
|
|
333
428
|
}
|
|
334
429
|
|
|
430
|
+
/** Mirrors `API_ERROR_CODES` in @aeroswarm/core/api. A server may send codes this client does not know. */
|
|
431
|
+
type ApiErrorCode = "UNAUTHORIZED" | "FORBIDDEN" | "NOT_FOUND" | "BAD_REQUEST" | "CONFLICT" | "RATE_LIMITED" | "UNAVAILABLE" | "INTERNAL";
|
|
432
|
+
/** The code for an HTTP status when the server sent none. */
|
|
433
|
+
declare function codeForStatus(status: number): ApiErrorCode;
|
|
434
|
+
interface ApiErrorInit {
|
|
435
|
+
status: number;
|
|
436
|
+
code: string;
|
|
437
|
+
message: string;
|
|
438
|
+
recoverable: boolean;
|
|
439
|
+
details?: unknown;
|
|
440
|
+
}
|
|
441
|
+
/** A REST call failed. `code` is stable and meant for `switch`; `message` is for people. */
|
|
442
|
+
declare class AeroApiError extends Error {
|
|
443
|
+
readonly status: number;
|
|
444
|
+
readonly code: string;
|
|
445
|
+
/** Retrying later may succeed (rate limit, server busy or failing). */
|
|
446
|
+
readonly recoverable: boolean;
|
|
447
|
+
readonly details?: unknown;
|
|
448
|
+
constructor(init: ApiErrorInit);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* The parsed JSON of a response, untouched. Throws `AeroApiError` for a non-2xx status
|
|
452
|
+
* and for a 2xx that carries `{ ok: false }`. For endpoints whose callers read the
|
|
453
|
+
* envelope themselves (`r.data.x`).
|
|
454
|
+
*/
|
|
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
|
+
}>;
|
|
471
|
+
/**
|
|
472
|
+
* The data of a response: unwrapped from `{ ok, data }`, or the body as it is for servers
|
|
473
|
+
* that answer with bare data. Throws `AeroApiError` on failure.
|
|
474
|
+
*/
|
|
475
|
+
declare function parseApiResponse<T>(res: Response, label?: string): Promise<T>;
|
|
476
|
+
|
|
335
477
|
interface AeroSwarmOptions {
|
|
336
478
|
endpoint: string;
|
|
337
479
|
token: string;
|
|
@@ -391,6 +533,7 @@ declare class AeroSwarm {
|
|
|
391
533
|
* (a broken airports.list() call must never brick replay/history for
|
|
392
534
|
* everyone else). */
|
|
393
535
|
private resolveHistoryEndpoint;
|
|
536
|
+
private federatedRequest;
|
|
394
537
|
private federatedFetch;
|
|
395
538
|
constructor(opts: AeroSwarmOptions);
|
|
396
539
|
readonly tracks: {
|
|
@@ -419,6 +562,15 @@ declare class AeroSwarm {
|
|
|
419
562
|
limit?: number;
|
|
420
563
|
endpoint?: string;
|
|
421
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>;
|
|
422
574
|
};
|
|
423
575
|
/** Flight plans received from AFTN feeds. Live tracks that correlate with a
|
|
424
576
|
* plan (Mode-S address, else callsign) also carry `track.flightPlan`. */
|
|
@@ -698,4 +850,4 @@ declare class AeroSwarm {
|
|
|
698
850
|
reconnect(): boolean;
|
|
699
851
|
}
|
|
700
852
|
|
|
701
|
-
export {
|
|
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,79 +1,26 @@
|
|
|
1
|
-
export { A as
|
|
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
|
-
export { AeroConnectionStatus, AeroRecoverableError, Bbox, ConfidenceBudget, CurrentTrack, FlightPhase, FlightPlan, FlightPlanStatus, FlightPlanSummary, FusedTrackEvent, Position, Protocol, SourceHealthEvent, SourceStatus, StreamEnvelope, TrackSource, TrackStatus, Velocity } from '@aeroswarm/core/types';
|
|
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';
|
|
5
|
+
export { M as MotionFrame, a as MotionInput, b as MotionOptions, c as MotionSample, d as MotionScheduler, T as TrackMotion, e as createTrackMotion } from './index-ByNBpjNk.js';
|
|
5
6
|
import '@trpc/client';
|
|
6
7
|
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
at: number;
|
|
25
|
-
/** Only tracks whose picture changed since the previous frame. */
|
|
26
|
-
changed: ReadonlyMap<string, MotionSample>;
|
|
27
|
-
}
|
|
28
|
-
interface MotionScheduler {
|
|
29
|
-
request(callback: (timestamp: number) => void): unknown;
|
|
30
|
-
cancel(handle: unknown): void;
|
|
31
|
-
}
|
|
32
|
-
interface MotionOptions {
|
|
33
|
-
/** How long a correction takes to fade out. Default 1500 ms. */
|
|
34
|
-
blendMs?: number;
|
|
35
|
-
/** How long the icon takes to turn to a new heading. Default 800 ms. */
|
|
36
|
-
headingSmoothMs?: number;
|
|
37
|
-
/** Dead reckoning stops after this long without a new fix. Default 20 s in the air, 8 s on the surface. */
|
|
38
|
-
maxExtrapolateMs?: {
|
|
39
|
-
air: number;
|
|
40
|
-
surface: number;
|
|
41
|
-
};
|
|
42
|
-
/** Below this speed a track is treated as standing still. Default 5 kt. */
|
|
43
|
-
minMovingKt?: number;
|
|
44
|
-
/** A correction larger than this is a glitch or a sensor change far away: jump instead of easing. Default 5000 m. */
|
|
45
|
-
snapDistanceM?: number;
|
|
46
|
-
/** Frame rate limit for `start()`. Default 30. */
|
|
47
|
-
frameHz?: number;
|
|
48
|
-
/** Changes smaller than this are not reported. Default 0.5 m (and 0.5 degrees of heading). */
|
|
49
|
-
epsilonM?: number;
|
|
50
|
-
/** false = show raw positions (for comparing against another source). Default true. */
|
|
51
|
-
extrapolate?: boolean;
|
|
52
|
-
/** Decides what counts as "on the surface". Default: vehicles, or below 150 ft. */
|
|
53
|
-
isSurface?: (track: MotionInput) => boolean;
|
|
54
|
-
/** Browser clock. Default Date.now. Inject the replay clock to play back at another speed. */
|
|
55
|
-
clock?: () => number;
|
|
56
|
-
/** Frame timer. Default requestAnimationFrame, else setTimeout. Inject in tests. */
|
|
57
|
-
scheduler?: MotionScheduler;
|
|
58
|
-
}
|
|
59
|
-
interface TrackMotion {
|
|
60
|
-
/** `meta.serverTime` (from the WS envelope) keeps the server/browser clock offset current. */
|
|
61
|
-
update(track: MotionInput, meta?: {
|
|
62
|
-
serverTime?: number;
|
|
63
|
-
}): void;
|
|
64
|
-
remove(trackId: string): void;
|
|
65
|
-
clear(): void;
|
|
66
|
-
/** Where the track is shown at `at` (browser time; default now). Pure: does not touch frame state. */
|
|
67
|
-
sample(trackId: string, at?: number): MotionSample | undefined;
|
|
68
|
-
/** One frame: the tracks whose picture changed since the previous frame. `start()` calls this for you. */
|
|
69
|
-
tick(at?: number): ReadonlyMap<string, MotionSample>;
|
|
70
|
-
/** Runs frames until the returned function is called. Idles (no timer) while nothing moves. */
|
|
71
|
-
start(onFrame: (frame: MotionFrame) => void): () => void;
|
|
72
|
-
/** Tracks currently held. */
|
|
73
|
-
readonly size: number;
|
|
74
|
-
/** Current server minus browser clock, ms. */
|
|
75
|
-
offsetMs(): number;
|
|
76
|
-
}
|
|
77
|
-
declare function createTrackMotion(options?: MotionOptions): TrackMotion;
|
|
8
|
+
/**
|
|
9
|
+
* Short label for the kind of sensor behind a track.
|
|
10
|
+
*
|
|
11
|
+
* ADSB ADS-B (CAT021, or raw ADS-B)
|
|
12
|
+
* SURFACE surface movement data (CAT010 / CAT011): SMR, MLAT or an ADS-B station on the ground
|
|
13
|
+
* MLAT multilateration (CAT020)
|
|
14
|
+
* RADAR radar plots and tracks (CAT048)
|
|
15
|
+
* SYSTEM system track (CAT062)
|
|
16
|
+
* FUSED several sensors merged
|
|
17
|
+
*/
|
|
18
|
+
type SourceLabel = "ADSB" | "SURFACE" | "MLAT" | "RADAR" | "SYSTEM" | "FUSED";
|
|
19
|
+
declare function sourceLabel(source: CurrentTrack["source"]): SourceLabel;
|
|
20
|
+
/**
|
|
21
|
+
* The sensor behind a track as a display string: `"ADSB 32/136"` (kind, then SAC/SIC),
|
|
22
|
+
* or just `"ADSB"` when the feed gave no SAC/SIC.
|
|
23
|
+
*/
|
|
24
|
+
declare function formatDataSource(track: Pick<CurrentTrack, "source" | "dataSource">): string;
|
|
78
25
|
|
|
79
|
-
export { type
|
|
26
|
+
export { type SourceLabel, formatDataSource, sourceLabel };
|