@aeroswarm/client 0.1.12 → 0.1.13
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 +35 -1
- package/dist/index-BXiTmKdS.d.ts +701 -0
- package/dist/index.d.ts +71 -688
- package/dist/index.js +317 -11
- package/dist/index.js.map +1 -1
- package/dist/react/index.d.ts +24 -2
- package/dist/react/index.js +355 -30
- package/dist/react/index.js.map +1 -1
- package/dist/sdk/index.d.ts +1 -2
- package/dist/sdk/index.js +7 -6
- package/dist/sdk/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,696 +1,79 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
export { A as AeroReplayClient, a as AeroSwarm, b as AeroSwarmOptions, c as AeroWsClient, d as AftnMessageRow, D as DayAvailability, F as FlightPlanRow, L as LABEL_COLORS, e as LabelCategory, f as LabeledTrack, g as LiveTrackCallbacks, R as ReplayCallbacks, h as ReplayHandle, i as ReplayProgress, j as ReplayStreamOptions, S as SourceRow, k as StreamMeta, l as SubscribeOptions, T as TrackCache, m as TrackCallbacks, n as TrackHistoryPoint, U as UseAeroTracksResult, o as getLabelCategory, w as withLabel } from './index-BXiTmKdS.js';
|
|
2
|
+
import { CurrentTrack } from '@aeroswarm/core/types';
|
|
3
3
|
export { AeroConnectionStatus, AeroRecoverableError, Bbox, ConfidenceBudget, CurrentTrack, FlightPhase, FlightPlan, FlightPlanStatus, FlightPlanSummary, FusedTrackEvent, Position, Protocol, SourceHealthEvent, SourceStatus, StreamEnvelope, TrackSource, TrackStatus, Velocity } from '@aeroswarm/core/types';
|
|
4
|
-
import * as _trpc_client from '@trpc/client';
|
|
5
4
|
export { clamp, haversineKm, isInsideBbox, isRenderableTrack, toCurrentTrack } from '@aeroswarm/core/utils';
|
|
5
|
+
import '@trpc/client';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type: string;
|
|
11
|
-
sourceToken: string;
|
|
12
|
-
createdAt: string;
|
|
13
|
-
/** Airport this source's data belongs to. When set, anything that
|
|
14
|
-
* authenticates with this source's token (WS live/replay, tRPC calls)
|
|
15
|
-
* is scoped to this airport automatically. */
|
|
16
|
-
airportId?: string | null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** A flight plan plus the live track it currently correlates with (null = not on radar). */
|
|
20
|
-
type FlightPlanRow = FlightPlan & {
|
|
21
|
-
trackId: string | null;
|
|
22
|
-
};
|
|
23
|
-
/** One raw AFTN message from the live log (newest first, capped by the service). */
|
|
24
|
-
interface AftnMessageRow {
|
|
25
|
-
id: string;
|
|
26
|
-
receivedAt: number;
|
|
27
|
-
airportId: string | null;
|
|
28
|
-
feedId: string | null;
|
|
29
|
-
callsign: string | null;
|
|
30
|
-
type: string;
|
|
31
|
-
adep?: string;
|
|
32
|
-
ades?: string;
|
|
33
|
-
raw: string;
|
|
34
|
-
}
|
|
35
|
-
declare class AeroRestClient {
|
|
36
|
-
private readonly endpoint;
|
|
37
|
-
private readonly token;
|
|
38
|
-
constructor(endpoint: string, token: string);
|
|
39
|
-
private req;
|
|
40
|
-
createSource(body: Record<string, unknown>): Promise<{
|
|
41
|
-
ok: boolean;
|
|
42
|
-
data: {
|
|
43
|
-
sourceId: string;
|
|
44
|
-
sourceToken: string;
|
|
45
|
-
airportId?: string | null;
|
|
46
|
-
};
|
|
47
|
-
}>;
|
|
48
|
-
listSources(): Promise<{
|
|
49
|
-
ok: boolean;
|
|
50
|
-
data: {
|
|
51
|
-
sources: SourceRow[];
|
|
52
|
-
};
|
|
53
|
-
}>;
|
|
54
|
-
deleteSource(id: string): Promise<{
|
|
55
|
-
ok: boolean;
|
|
56
|
-
}>;
|
|
57
|
-
createWebhook(body: {
|
|
58
|
-
url: string;
|
|
59
|
-
events: string[];
|
|
60
|
-
secret?: string;
|
|
61
|
-
}): Promise<{
|
|
62
|
-
webhookId: string;
|
|
63
|
-
}>;
|
|
64
|
-
getTracksCurrent(params?: {
|
|
65
|
-
bbox?: [number, number, number, number];
|
|
66
|
-
minConfidence?: number;
|
|
67
|
-
}): Promise<{
|
|
68
|
-
tracks: unknown[];
|
|
69
|
-
count: number;
|
|
70
|
-
}>;
|
|
71
|
-
/** Flight plans received from AFTN feeds (FPL/CHG/DLA/DEP/ARR/CNL folded per flight). */
|
|
72
|
-
listFlightPlans(params?: {
|
|
73
|
-
airportId?: string;
|
|
74
|
-
status?: string;
|
|
75
|
-
callsign?: string;
|
|
76
|
-
limit?: number;
|
|
77
|
-
}): Promise<{
|
|
78
|
-
ok: boolean;
|
|
79
|
-
data: {
|
|
80
|
-
flightPlans: FlightPlanRow[];
|
|
81
|
-
count: number;
|
|
82
|
-
};
|
|
83
|
-
}>;
|
|
84
|
-
getFlightPlan(id: string): Promise<{
|
|
85
|
-
ok: boolean;
|
|
86
|
-
data: {
|
|
87
|
-
flightPlan: FlightPlan;
|
|
88
|
-
};
|
|
89
|
-
}>;
|
|
90
|
-
/** Raw AFTN messages (every parsed ATS message, newest first — the input
|
|
91
|
-
* side of the flight-plan pipeline). */
|
|
92
|
-
listAftnMessages(params?: {
|
|
93
|
-
airportId?: string;
|
|
94
|
-
limit?: number;
|
|
95
|
-
}): Promise<{
|
|
96
|
-
ok: boolean;
|
|
97
|
-
data: {
|
|
98
|
-
messages: AftnMessageRow[];
|
|
99
|
-
count: number;
|
|
100
|
-
};
|
|
101
|
-
}>;
|
|
102
|
-
health(): Promise<{
|
|
103
|
-
status: string;
|
|
104
|
-
}>;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
type WsEncoding = "json" | "msgpack";
|
|
108
|
-
interface SubscribeOptions {
|
|
109
|
-
bbox?: [number, number, number, number];
|
|
110
|
-
/** Scope the stream to tracks stamped with this ICAO airport code, e.g. "WARR" */
|
|
111
|
-
airportId?: string;
|
|
112
|
-
source?: "fused" | "normalized";
|
|
113
|
-
minConfidence?: number;
|
|
114
|
-
maxTracks?: number;
|
|
115
|
-
mode?: "delta" | "full";
|
|
116
|
-
maxUpdateHz?: number;
|
|
117
|
-
encoding?: WsEncoding;
|
|
118
|
-
staleAfterMs?: number;
|
|
119
|
-
removeAfterMs?: number;
|
|
120
|
-
}
|
|
121
|
-
interface TrackCallbacks {
|
|
122
|
-
onTrackUpdate?: (track: CurrentTrack) => void;
|
|
123
|
-
onTrackRemoved?: (event: {
|
|
124
|
-
trackId: string;
|
|
125
|
-
reason: string;
|
|
126
|
-
}) => void;
|
|
127
|
-
onSnapshot?: (tracks: CurrentTrack[]) => void;
|
|
128
|
-
onSourceStatus?: (event: {
|
|
129
|
-
sourceId: string;
|
|
130
|
-
status: SourceStatus;
|
|
131
|
-
}) => void;
|
|
132
|
-
onStatusChange?: (status: AeroConnectionStatus) => void;
|
|
133
|
-
onError?: (err: AeroRecoverableError) => void;
|
|
134
|
-
onDegraded?: (reason: string) => void;
|
|
135
|
-
}
|
|
136
|
-
declare class AeroWsClient {
|
|
137
|
-
private readonly url;
|
|
138
|
-
private readonly token;
|
|
139
|
-
private readonly maxReconnectDelay;
|
|
140
|
-
private readonly heartbeatTimeoutMs;
|
|
141
|
-
private ws;
|
|
142
|
-
private attempt;
|
|
143
|
-
private stopped;
|
|
144
|
-
private lastSubscribe;
|
|
145
|
-
private callbacks;
|
|
146
|
-
private lastSeq;
|
|
147
|
-
private lastHeartbeat;
|
|
148
|
-
private heartbeatTimer;
|
|
149
|
-
private reconnectTimer;
|
|
150
|
-
private status;
|
|
151
|
-
constructor(url: string, token: string, maxReconnectDelay?: number, heartbeatTimeoutMs?: number);
|
|
152
|
-
connect(opts: SubscribeOptions, callbacks: TrackCallbacks): void;
|
|
153
|
-
updateFilter(opts: Partial<Pick<SubscribeOptions, 'bbox' | 'minConfidence' | 'maxUpdateHz' | 'maxTracks'>>): void;
|
|
154
|
-
disconnect(): void;
|
|
155
|
-
/**
|
|
156
|
-
* Force a fresh connection now, skipping any backoff wait. Re-subscribes with
|
|
157
|
-
* the last `connect()` options (the server then sends a new snapshot).
|
|
158
|
-
* Also resumes after `disconnect()`. No-op if `connect()` was never called.
|
|
159
|
-
* Returns false in that no-op case.
|
|
160
|
-
*/
|
|
161
|
-
reconnect(): boolean;
|
|
162
|
-
getStatus(): AeroConnectionStatus;
|
|
163
|
-
private _setStatus;
|
|
164
|
-
/** Close the current socket without letting its onclose schedule a reconnect. */
|
|
165
|
-
private _dropSocket;
|
|
166
|
-
private _connect;
|
|
167
|
-
private _handleRaw;
|
|
168
|
-
private _requestSnapshot;
|
|
169
|
-
private _resetHeartbeatTimer;
|
|
170
|
-
private _clearHeartbeatTimer;
|
|
171
|
-
private _scheduleReconnect;
|
|
172
|
-
private _clearReconnectTimer;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Server-paced WS replay client for `/ws/tracks/replay`.
|
|
177
|
-
*
|
|
178
|
-
* The server streams historical `fused_tracks` events at `speed`× real
|
|
179
|
-
* time (paced server-side against a wall-clock anchor), so the client
|
|
180
|
-
* receives replay frames exactly like live traffic: a `snapshot`
|
|
181
|
-
* envelope with the state at `from`, then `track.updated` /
|
|
182
|
-
* `track.removed` envelopes, plus `replay.progress` heartbeats and a
|
|
183
|
-
* final `replay.done`.
|
|
184
|
-
*
|
|
185
|
-
* The wire protocol is plain JSON, so consumers that don't use this SDK
|
|
186
|
-
* can speak it manually:
|
|
187
|
-
*
|
|
188
|
-
* → connect wss://host/ws/tracks/replay?token=TOKEN[&airportId=WARR][&sessionId=ID]
|
|
189
|
-
* → send { "type": "replay.start", "from": ISO, "to": ISO, "speed": 2 }
|
|
190
|
-
* → send { "type": "replay.pause" } · { "type": "replay.resume" }
|
|
191
|
-
* → send { "type": "replay.seek", "at": ISO }
|
|
192
|
-
* → send { "type": "replay.stop" }
|
|
193
|
-
* ← recv { "type": "snapshot", "payload": { "tracks": [...], "sessionId": ID } }
|
|
194
|
-
* ← recv { "type": "track.updated", "payload": { "track": {...} } }
|
|
195
|
-
* ← recv { "type": "track.removed", "payload": { "trackId": ID, "reason": "dropped" } }
|
|
196
|
-
* ← recv { "type": "replay.progress", "payload": { "at": ISO, "pct": 0-100, "sessionId": ID } }
|
|
197
|
-
* ← recv { "type": "replay.done", "payload": { "sessionId": ID } }
|
|
198
|
-
*
|
|
199
|
-
* Reconnecting with the same `sessionId` (within 1 h) resumes a replay
|
|
200
|
-
* from its last saved position.
|
|
201
|
-
*/
|
|
202
|
-
interface ReplayStreamOptions {
|
|
203
|
-
from: Date | string;
|
|
204
|
-
to: Date | string;
|
|
205
|
-
/** Playback speed multiplier (1 = realtime). Default 1. */
|
|
206
|
-
speed?: number;
|
|
207
|
-
/** Which airport to replay. Federated airports (with a historyEndpoint)
|
|
208
|
-
* are resolved by AeroSwarm.replay.stream to their own backend; against
|
|
209
|
-
* AeroSwarm's own endpoint this is a row filter on the local DB. */
|
|
210
|
-
airportId?: string;
|
|
211
|
-
/** Resume a previous session instead of starting fresh. */
|
|
212
|
-
sessionId?: string;
|
|
213
|
-
}
|
|
214
|
-
interface ReplayProgress {
|
|
215
|
-
/** Replay-time position (ISO timestamp) */
|
|
216
|
-
at: string;
|
|
217
|
-
/** 0–100 within the requested range */
|
|
218
|
-
pct: number;
|
|
219
|
-
sessionId: string;
|
|
220
|
-
}
|
|
221
|
-
interface ReplayCallbacks {
|
|
222
|
-
/** State at `from` — arrives once per start/seek. */
|
|
223
|
-
onSnapshot?: (tracks: CurrentTrack[], sessionId: string) => void;
|
|
224
|
-
onTrackUpdate?: (track: CurrentTrack) => void;
|
|
225
|
-
onTrackRemoved?: (event: {
|
|
226
|
-
trackId: string;
|
|
227
|
-
reason: string;
|
|
228
|
-
}) => void;
|
|
229
|
-
onProgress?: (progress: ReplayProgress) => void;
|
|
230
|
-
onDone?: (sessionId: string) => void;
|
|
231
|
-
onError?: (error: Error) => void;
|
|
232
|
-
}
|
|
233
|
-
interface ReplayHandle {
|
|
234
|
-
readonly sessionId: string | null;
|
|
235
|
-
pause(): void;
|
|
236
|
-
resume(): void;
|
|
237
|
-
/** Jump to a replay-time position; the server restarts the paced stream there. */
|
|
238
|
-
seek(at: Date | string): void;
|
|
239
|
-
/** End the replay and close the socket. */
|
|
240
|
-
stop(): void;
|
|
241
|
-
}
|
|
242
|
-
declare class AeroReplayClient {
|
|
243
|
-
private readonly wsBase;
|
|
244
|
-
private readonly token;
|
|
245
|
-
/** Default "/ws/tracks/replay" (AeroSwarm's own endpoint). A federated
|
|
246
|
-
* airport backend running @aeroswarm/replay-server's default mount
|
|
247
|
-
* uses "/replay" instead — see AeroSwarm.replay.stream's endpoint
|
|
248
|
-
* resolution. */
|
|
249
|
-
private readonly wsPath;
|
|
250
|
-
constructor(wsBase: string, token: string,
|
|
251
|
-
/** Default "/ws/tracks/replay" (AeroSwarm's own endpoint). A federated
|
|
252
|
-
* airport backend running @aeroswarm/replay-server's default mount
|
|
253
|
-
* uses "/replay" instead — see AeroSwarm.replay.stream's endpoint
|
|
254
|
-
* resolution. */
|
|
255
|
-
wsPath?: string);
|
|
256
|
-
/** Open a replay stream. Returns a handle for transport control. */
|
|
257
|
-
stream(opts: ReplayStreamOptions, callbacks: ReplayCallbacks): ReplayHandle;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
declare function createAeroTrpcClient(endpoint: string, token: string): _trpc_client.TRPCClient<any>;
|
|
261
|
-
type AeroTrpcClient = ReturnType<typeof createAeroTrpcClient>;
|
|
262
|
-
|
|
263
|
-
declare class AeroGraphQLClient {
|
|
264
|
-
private readonly endpoint;
|
|
265
|
-
private readonly token;
|
|
266
|
-
constructor(endpoint: string, token: string);
|
|
267
|
-
query<T = unknown>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Callsign-label category of a track, in priority order:
|
|
272
|
-
* LOST (track status "lost") > GROUND_VEHICLE > ARRIVAL / DEPARTURE > UNKNOWN.
|
|
273
|
-
* ARRIVAL/DEPARTURE come from the correlated flight plan, relative to the
|
|
274
|
-
* track's airport (`track.flightPlan.phase`).
|
|
275
|
-
*/
|
|
276
|
-
type LabelCategory = "ARRIVAL" | "DEPARTURE" | "GROUND_VEHICLE" | "LOST" | "UNKNOWN";
|
|
277
|
-
declare const LABEL_COLORS: Readonly<Record<LabelCategory, string>>;
|
|
278
|
-
/** A track as the client exposes it: the server's track plus derived label fields. */
|
|
279
|
-
type LabeledTrack = CurrentTrack & {
|
|
280
|
-
labelCategory: LabelCategory;
|
|
281
|
-
labelColor: string;
|
|
7
|
+
/** What the engine reads from a track. */
|
|
8
|
+
type MotionInput = Pick<CurrentTrack, "trackId" | "lat" | "lon" | "groundSpeedKt" | "headingDeg" | "altitudeFt" | "status" | "lastSeenAt"> & {
|
|
9
|
+
targetType?: CurrentTrack["targetType"];
|
|
282
10
|
};
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
11
|
+
interface MotionSample {
|
|
12
|
+
lat: number;
|
|
13
|
+
lon: number;
|
|
14
|
+
/** Degrees 0..360, eased; null until a valid heading has been seen. */
|
|
15
|
+
headingDeg: number | null;
|
|
16
|
+
altitudeFt: number | null;
|
|
17
|
+
/** Speed is above `minMovingKt`. */
|
|
18
|
+
moving: boolean;
|
|
19
|
+
/** Position currently comes from dead reckoning (not frozen, limit not reached). */
|
|
20
|
+
extrapolating: boolean;
|
|
21
|
+
}
|
|
22
|
+
interface MotionFrame {
|
|
23
|
+
/** Server-aligned time of this frame (ms). */
|
|
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;
|
|
311
41
|
};
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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;
|
|
319
63
|
}): void;
|
|
320
|
-
|
|
321
|
-
getAll(): LabeledTrack[];
|
|
322
|
-
get(id: string): LabeledTrack | undefined;
|
|
323
|
-
get size(): number;
|
|
64
|
+
remove(trackId: string): void;
|
|
324
65
|
clear(): void;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
encoding?: "json" | "msgpack";
|
|
338
|
-
staleAfterMs?: number;
|
|
339
|
-
removeAfterMs?: number;
|
|
340
|
-
onTokenExpired?: () => Promise<string>;
|
|
341
|
-
}
|
|
342
|
-
/** Live callbacks: tracks arrive merged with previous state and carry
|
|
343
|
-
* `status`, `labelCategory` and `labelColor`. */
|
|
344
|
-
interface LiveTrackCallbacks extends Omit<TrackCallbacks, "onTrackUpdate" | "onSnapshot"> {
|
|
345
|
-
onTrackUpdate?: (track: LabeledTrack) => void;
|
|
346
|
-
onSnapshot?: (tracks: LabeledTrack[]) => void;
|
|
347
|
-
}
|
|
348
|
-
interface UseAeroTracksResult {
|
|
349
|
-
tracks: CurrentTrack[];
|
|
350
|
-
status: AeroConnectionStatus;
|
|
351
|
-
sourceStatus: Record<string, string>;
|
|
352
|
-
lastUpdateAt: number | null;
|
|
353
|
-
error: AeroRecoverableError | null;
|
|
354
|
-
}
|
|
355
|
-
interface TrackHistoryPoint {
|
|
356
|
-
t: number;
|
|
357
|
-
lat: number | null;
|
|
358
|
-
lon: number | null;
|
|
359
|
-
altFt: number | null;
|
|
360
|
-
speedKt: number | null;
|
|
361
|
-
headingDeg: number | null;
|
|
362
|
-
}
|
|
363
|
-
interface DayAvailability {
|
|
364
|
-
day: string;
|
|
365
|
-
eventCount: number;
|
|
366
|
-
trackCount: number;
|
|
367
|
-
firstAt: string | null;
|
|
368
|
-
lastAt: string | null;
|
|
369
|
-
}
|
|
370
|
-
declare class AeroSwarm {
|
|
371
|
-
private readonly opts;
|
|
372
|
-
readonly trpc: AeroTrpcClient;
|
|
373
|
-
readonly rest: AeroRestClient;
|
|
374
|
-
readonly graphql: AeroGraphQLClient;
|
|
375
|
-
readonly cache: TrackCache;
|
|
376
|
-
private readonly wsClient;
|
|
377
|
-
private _status;
|
|
378
|
-
private _lastUpdateAt;
|
|
379
|
-
private _error;
|
|
380
|
-
private _sourceStatus;
|
|
381
|
-
private airportsCache;
|
|
382
|
-
private static readonly AIRPORTS_CACHE_TTL_MS;
|
|
383
|
-
/** Resolves which base URL (if any) should serve a federated call.
|
|
384
|
-
* Returns null to mean "use AeroSwarm's own endpoint" — the normal,
|
|
385
|
-
* unfederated path, which is also what a lookup failure falls back to
|
|
386
|
-
* (a broken airports.list() call must never brick replay/history for
|
|
387
|
-
* everyone else). */
|
|
388
|
-
private resolveHistoryEndpoint;
|
|
389
|
-
private federatedFetch;
|
|
390
|
-
constructor(opts: AeroSwarmOptions);
|
|
391
|
-
readonly tracks: {
|
|
392
|
-
subscribe: (opts: SubscribeOptions, callbacks: LiveTrackCallbacks) => (() => void);
|
|
393
|
-
updateFilter: (opts: Partial<SubscribeOptions>) => void;
|
|
394
|
-
/** Drop the live socket and reconnect immediately (no backoff wait),
|
|
395
|
-
* re-subscribing with the last options. Returns false if nothing has
|
|
396
|
-
* been subscribed yet. */
|
|
397
|
-
reconnect: () => boolean;
|
|
398
|
-
stream: (opts: SubscribeOptions) => AsyncIterable<LabeledTrack>;
|
|
399
|
-
snapshot: (input?: {
|
|
400
|
-
airportId?: string;
|
|
401
|
-
bbox?: Bbox;
|
|
402
|
-
source?: "fused" | "normalized";
|
|
403
|
-
minConfidence?: number;
|
|
404
|
-
limit?: number;
|
|
405
|
-
offset?: number;
|
|
406
|
-
}) => any;
|
|
407
|
-
/** Persisted position history for one track. If the airport has a
|
|
408
|
-
* `historyEndpoint` (or `endpoint` is passed explicitly), this calls
|
|
409
|
-
* that backend's `@aeroswarm/replay-server` instead of AeroSwarm's
|
|
410
|
-
* own local database — see docs/development/federation/003-*.md. */
|
|
411
|
-
history: (input: {
|
|
412
|
-
trackId: string;
|
|
413
|
-
airportId?: string;
|
|
414
|
-
limit?: number;
|
|
415
|
-
endpoint?: string;
|
|
416
|
-
}) => Promise<TrackHistoryPoint[]>;
|
|
417
|
-
};
|
|
418
|
-
/** Flight plans received from AFTN feeds. Live tracks that correlate with a
|
|
419
|
-
* plan (Mode-S address, else callsign) also carry `track.flightPlan`. */
|
|
420
|
-
readonly flightPlans: {
|
|
421
|
-
list: (input?: {
|
|
422
|
-
airportId?: string;
|
|
423
|
-
status?: string;
|
|
424
|
-
callsign?: string;
|
|
425
|
-
limit?: number;
|
|
426
|
-
}) => Promise<FlightPlanRow[]>;
|
|
427
|
-
get: (id: string) => Promise<_aeroswarm_core_types.FlightPlan>;
|
|
428
|
-
};
|
|
429
|
-
/** Raw AFTN/ATS messages received by AFTN feeds — the input side of the
|
|
430
|
-
* flight-plan pipeline (newest first, capped by the service). */
|
|
431
|
-
readonly aftn: {
|
|
432
|
-
messages: (input?: {
|
|
433
|
-
airportId?: string;
|
|
434
|
-
limit?: number;
|
|
435
|
-
}) => Promise<AftnMessageRow[]>;
|
|
436
|
-
};
|
|
437
|
-
readonly sources: {
|
|
438
|
-
/** Registers a source and returns its token, tied to `airportId` — a
|
|
439
|
-
* source is a sensor physically at one airport, so this is required.
|
|
440
|
-
* Anything that later authenticates with the returned token (WS
|
|
441
|
-
* live/replay, tRPC calls) is scoped to that airport automatically,
|
|
442
|
-
* with no need to keep passing `airportId` on every subsequent call.
|
|
443
|
-
* For access spanning multiple airports, use the viewer/dashboard
|
|
444
|
-
* token instead — it's never auto-scoped. */
|
|
445
|
-
create: (body: {
|
|
446
|
-
name: string;
|
|
447
|
-
airportId: string;
|
|
448
|
-
sourceType?: string;
|
|
449
|
-
location?: {
|
|
450
|
-
lat: number;
|
|
451
|
-
lon: number;
|
|
452
|
-
};
|
|
453
|
-
config?: Record<string, unknown>;
|
|
454
|
-
}) => Promise<{
|
|
455
|
-
ok: boolean;
|
|
456
|
-
data: {
|
|
457
|
-
sourceId: string;
|
|
458
|
-
sourceToken: string;
|
|
459
|
-
airportId?: string | null;
|
|
460
|
-
};
|
|
461
|
-
}>;
|
|
462
|
-
health: (sourceId: string) => any;
|
|
463
|
-
list: (input?: {
|
|
464
|
-
airportId?: string;
|
|
465
|
-
}) => any;
|
|
466
|
-
/** Reassigning `airportId` (including to `null` to clear it) re-caches
|
|
467
|
-
* the source's token immediately, so the new scoping takes effect
|
|
468
|
-
* without waiting out the token cache's TTL. */
|
|
469
|
-
update: (input: {
|
|
470
|
-
id: string;
|
|
471
|
-
name?: string;
|
|
472
|
-
airportId?: string | null;
|
|
473
|
-
location?: {
|
|
474
|
-
lat: number;
|
|
475
|
-
lon: number;
|
|
476
|
-
};
|
|
477
|
-
config?: Record<string, unknown>;
|
|
478
|
-
}) => any;
|
|
479
|
-
delete: (id: string) => any;
|
|
480
|
-
};
|
|
481
|
-
/** Airport registry (multi-airport tenancy). */
|
|
482
|
-
readonly airports: {
|
|
483
|
-
list: () => Promise<{
|
|
484
|
-
airports: {
|
|
485
|
-
id: string;
|
|
486
|
-
name: string;
|
|
487
|
-
city: string | null;
|
|
488
|
-
lat: number;
|
|
489
|
-
lon: number;
|
|
490
|
-
bbox: [number, number, number, number];
|
|
491
|
-
timezone: string;
|
|
492
|
-
/** Set = this airport serves its own replay/history (federated —
|
|
493
|
-
* see docs/development/federation/003-*.md); `replay.*`/
|
|
494
|
-
* `tracks.history` calls for it connect there directly instead of
|
|
495
|
-
* AeroSwarm's own endpoint. null = AeroSwarm serves it (default). */
|
|
496
|
-
historyEndpoint: string | null;
|
|
497
|
-
}[];
|
|
498
|
-
}>;
|
|
499
|
-
create: (input: {
|
|
500
|
-
id: string;
|
|
501
|
-
name: string;
|
|
502
|
-
city?: string;
|
|
503
|
-
lat: number;
|
|
504
|
-
lon: number;
|
|
505
|
-
bbox: [number, number, number, number];
|
|
506
|
-
timezone?: string;
|
|
507
|
-
historyEndpoint?: string;
|
|
508
|
-
}) => Promise<{
|
|
509
|
-
ok: boolean;
|
|
510
|
-
id: string;
|
|
511
|
-
}>;
|
|
512
|
-
update: (input: {
|
|
513
|
-
id: string;
|
|
514
|
-
name?: string;
|
|
515
|
-
city?: string;
|
|
516
|
-
lat?: number;
|
|
517
|
-
lon?: number;
|
|
518
|
-
bbox?: [number, number, number, number];
|
|
519
|
-
timezone?: string;
|
|
520
|
-
/** null clears it (reverts to AeroSwarm's own replay); omit to leave unchanged. */
|
|
521
|
-
historyEndpoint?: string | null;
|
|
522
|
-
}) => Promise<{
|
|
523
|
-
ok: boolean;
|
|
524
|
-
}>;
|
|
525
|
-
delete: (input: {
|
|
526
|
-
id: string;
|
|
527
|
-
}) => Promise<{
|
|
528
|
-
ok: boolean;
|
|
529
|
-
}>;
|
|
530
|
-
/** Surface geometry (runway/taxiway/apron GeoJSON) for the map. */
|
|
531
|
-
surface: (input: {
|
|
532
|
-
id: string;
|
|
533
|
-
}) => Promise<{
|
|
534
|
-
surface: unknown | null;
|
|
535
|
-
}>;
|
|
536
|
-
setSurface: (input: {
|
|
537
|
-
id: string;
|
|
538
|
-
surface: Record<string, unknown>;
|
|
539
|
-
}) => Promise<{
|
|
540
|
-
ok: boolean;
|
|
541
|
-
}>;
|
|
542
|
-
};
|
|
543
|
-
readonly replay: {
|
|
544
|
-
/** Data-availability calendar: which days have recorded tracks.
|
|
545
|
-
* Use this to populate/validate replay date pickers — days not in
|
|
546
|
-
* the list have no data. Federates to the airport's own backend when
|
|
547
|
-
* it has a `historyEndpoint` (or `endpoint` is passed explicitly) —
|
|
548
|
-
* see docs/development/federation/003-*.md. */
|
|
549
|
-
days: (input?: {
|
|
550
|
-
airportId?: string;
|
|
551
|
-
lookbackDays?: number;
|
|
552
|
-
endpoint?: string;
|
|
553
|
-
}) => Promise<{
|
|
554
|
-
days: DayAvailability[];
|
|
555
|
-
}>;
|
|
556
|
-
range: (input: {
|
|
557
|
-
from: string;
|
|
558
|
-
to: string;
|
|
559
|
-
airportId?: string;
|
|
560
|
-
endpoint?: string;
|
|
561
|
-
}) => Promise<{
|
|
562
|
-
earliest: string | null;
|
|
563
|
-
latest: string | null;
|
|
564
|
-
eventCount: number;
|
|
565
|
-
trackCount: number;
|
|
566
|
-
from: string;
|
|
567
|
-
to: string;
|
|
568
|
-
}>;
|
|
569
|
-
/** Server-paced WS playback: streams historical tracks at `speed`× in
|
|
570
|
-
* the same envelope format as the live stream. Returns a transport
|
|
571
|
-
* handle (pause/resume/seek/stop) — a Promise, since resolving which
|
|
572
|
-
* backend serves this airport (see docs/development/federation/003-*.md)
|
|
573
|
-
* is async. See `AeroReplayClient` for the raw wire protocol if you
|
|
574
|
-
* want to speak WS manually instead. */
|
|
575
|
-
stream: (opts: ReplayStreamOptions & {
|
|
576
|
-
endpoint?: string;
|
|
577
|
-
}, callbacks: ReplayCallbacks) => Promise<ReplayHandle>;
|
|
578
|
-
};
|
|
579
|
-
/** Movement analytics: takeoffs/landings per hour + peak hour, recorded
|
|
580
|
-
* by the pipeline's movement detector. */
|
|
581
|
-
readonly analytics: {
|
|
582
|
-
movements: (input?: {
|
|
583
|
-
airportId?: string;
|
|
584
|
-
day?: string;
|
|
585
|
-
}) => Promise<{
|
|
586
|
-
day: string;
|
|
587
|
-
hours: {
|
|
588
|
-
hour: string;
|
|
589
|
-
takeoffs: number;
|
|
590
|
-
landings: number;
|
|
591
|
-
}[];
|
|
592
|
-
totals: {
|
|
593
|
-
takeoffs: number;
|
|
594
|
-
landings: number;
|
|
595
|
-
};
|
|
596
|
-
peak: {
|
|
597
|
-
hour: string;
|
|
598
|
-
count: number;
|
|
599
|
-
} | null;
|
|
600
|
-
}>;
|
|
601
|
-
};
|
|
602
|
-
/** Route conformance: pre-defined ground routes + live track clearances.
|
|
603
|
-
* Assign a route to a track and the safety engine can detect when it
|
|
604
|
-
* strays beyond the route's corridor. */
|
|
605
|
-
readonly routes: {
|
|
606
|
-
list: (input?: {
|
|
607
|
-
airportId?: string;
|
|
608
|
-
}) => Promise<{
|
|
609
|
-
routes: {
|
|
610
|
-
routeId: string;
|
|
611
|
-
airportId: string;
|
|
612
|
-
name: string;
|
|
613
|
-
kind: string;
|
|
614
|
-
points: [number, number][];
|
|
615
|
-
maxDeviationM: number;
|
|
616
|
-
enabled: boolean;
|
|
617
|
-
}[];
|
|
618
|
-
}>;
|
|
619
|
-
create: (input: {
|
|
620
|
-
airportId: string;
|
|
621
|
-
name: string;
|
|
622
|
-
kind?: "taxi" | "departure" | "arrival";
|
|
623
|
-
points: [number, number][];
|
|
624
|
-
maxDeviationM?: number;
|
|
625
|
-
}) => Promise<{
|
|
626
|
-
id: string;
|
|
627
|
-
}>;
|
|
628
|
-
delete: (input: {
|
|
629
|
-
id: string;
|
|
630
|
-
}) => Promise<{
|
|
631
|
-
ok: boolean;
|
|
632
|
-
}>;
|
|
633
|
-
assign: (input: {
|
|
634
|
-
trackId: string;
|
|
635
|
-
routeId: string;
|
|
636
|
-
}) => Promise<{
|
|
637
|
-
ok: boolean;
|
|
638
|
-
}>;
|
|
639
|
-
unassign: (input: {
|
|
640
|
-
trackId: string;
|
|
641
|
-
}) => Promise<{
|
|
642
|
-
ok: boolean;
|
|
643
|
-
}>;
|
|
644
|
-
assignments: () => Promise<{
|
|
645
|
-
assignments: {
|
|
646
|
-
trackId: string;
|
|
647
|
-
routeId: string;
|
|
648
|
-
assignedAt: number;
|
|
649
|
-
}[];
|
|
650
|
-
}>;
|
|
651
|
-
};
|
|
652
|
-
readonly webhooks: {
|
|
653
|
-
list: () => any;
|
|
654
|
-
create: (body: {
|
|
655
|
-
url: string;
|
|
656
|
-
events: string[];
|
|
657
|
-
secret?: string;
|
|
658
|
-
}) => Promise<{
|
|
659
|
-
ok: boolean;
|
|
660
|
-
webhookId: string;
|
|
661
|
-
}>;
|
|
662
|
-
delete: (input: {
|
|
663
|
-
id: string;
|
|
664
|
-
}) => any;
|
|
665
|
-
};
|
|
666
|
-
readonly system: {
|
|
667
|
-
stats: () => any;
|
|
668
|
-
infraHealth: () => any;
|
|
669
|
-
ingestHistory: () => any;
|
|
670
|
-
getConfig: () => Promise<{
|
|
671
|
-
key: string;
|
|
672
|
-
value: string;
|
|
673
|
-
updatedAt: string;
|
|
674
|
-
}[]>;
|
|
675
|
-
setConfig: (input: {
|
|
676
|
-
key: string;
|
|
677
|
-
value: string;
|
|
678
|
-
}) => Promise<{
|
|
679
|
-
ok: boolean;
|
|
680
|
-
}>;
|
|
681
|
-
clearTable: (input: {
|
|
682
|
-
table: "fused_tracks" | "source_health";
|
|
683
|
-
mode: "all" | "range";
|
|
684
|
-
from?: string;
|
|
685
|
-
to?: string;
|
|
686
|
-
}) => any;
|
|
687
|
-
};
|
|
688
|
-
getStatus(): AeroConnectionStatus;
|
|
689
|
-
getLastUpdateAt(): number | null;
|
|
690
|
-
getError(): AeroRecoverableError | null;
|
|
691
|
-
getSourceStatus(): Record<string, string>;
|
|
692
|
-
disconnect(): void;
|
|
693
|
-
reconnect(): boolean;
|
|
694
|
-
}
|
|
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;
|
|
695
78
|
|
|
696
|
-
export {
|
|
79
|
+
export { type MotionFrame, type MotionInput, type MotionOptions, type MotionSample, type MotionScheduler, type TrackMotion, createTrackMotion };
|