@skyvexsoftware/stratos-sdk 0.1.1

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.
Files changed (101) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +201 -0
  3. package/dist/helpers/createPlugin.d.ts +22 -0
  4. package/dist/helpers/createPlugin.js +32 -0
  5. package/dist/helpers/index.d.ts +4 -0
  6. package/dist/helpers/index.js +3 -0
  7. package/dist/helpers/units.d.ts +36 -0
  8. package/dist/helpers/units.js +101 -0
  9. package/dist/hooks/context.d.ts +12 -0
  10. package/dist/hooks/context.js +18 -0
  11. package/dist/hooks/index.d.ts +16 -0
  12. package/dist/hooks/index.js +16 -0
  13. package/dist/hooks/useFlightEvents.d.ts +37 -0
  14. package/dist/hooks/useFlightEvents.js +152 -0
  15. package/dist/hooks/useFlightManager.d.ts +20 -0
  16. package/dist/hooks/useFlightManager.js +90 -0
  17. package/dist/hooks/useFlightPhase.d.ts +31 -0
  18. package/dist/hooks/useFlightPhase.js +67 -0
  19. package/dist/hooks/useLandingAnalysis.d.ts +37 -0
  20. package/dist/hooks/useLandingAnalysis.js +87 -0
  21. package/dist/hooks/usePluginLogger.d.ts +13 -0
  22. package/dist/hooks/usePluginLogger.js +16 -0
  23. package/dist/hooks/useShellAuth.d.ts +14 -0
  24. package/dist/hooks/useShellAuth.js +13 -0
  25. package/dist/hooks/useShellConfig.d.ts +14 -0
  26. package/dist/hooks/useShellConfig.js +14 -0
  27. package/dist/hooks/useShellNavigation.d.ts +12 -0
  28. package/dist/hooks/useShellNavigation.js +15 -0
  29. package/dist/hooks/useShellToast.d.ts +12 -0
  30. package/dist/hooks/useShellToast.js +15 -0
  31. package/dist/hooks/useSimData.d.ts +70 -0
  32. package/dist/hooks/useSimData.js +135 -0
  33. package/dist/hooks/useSimulatorData.d.ts +57 -0
  34. package/dist/hooks/useSimulatorData.js +258 -0
  35. package/dist/hooks/useTrackingSession.d.ts +40 -0
  36. package/dist/hooks/useTrackingSession.js +152 -0
  37. package/dist/icons.d.ts +13 -0
  38. package/dist/icons.js +13 -0
  39. package/dist/index.d.ts +30 -0
  40. package/dist/index.js +28 -0
  41. package/dist/shared-types/flight-manager.d.ts +112 -0
  42. package/dist/shared-types/flight-manager.js +2 -0
  43. package/dist/shared-types/index.d.ts +7 -0
  44. package/dist/shared-types/index.js +4 -0
  45. package/dist/shared-types/simulator.d.ts +386 -0
  46. package/dist/shared-types/simulator.js +48 -0
  47. package/dist/shared-types/socket-events.d.ts +171 -0
  48. package/dist/shared-types/socket-events.js +79 -0
  49. package/dist/shared-types/theme.d.ts +3 -0
  50. package/dist/shared-types/theme.js +2 -0
  51. package/dist/types/context.d.ts +206 -0
  52. package/dist/types/context.js +8 -0
  53. package/dist/types/index.d.ts +4 -0
  54. package/dist/types/index.js +2 -0
  55. package/dist/types/manifest.d.ts +42 -0
  56. package/dist/types/manifest.js +12 -0
  57. package/dist/types/module.d.ts +31 -0
  58. package/dist/types/module.js +7 -0
  59. package/dist/ui/alert-dialog.d.ts +21 -0
  60. package/dist/ui/alert-dialog.js +27 -0
  61. package/dist/ui/badge.d.ts +9 -0
  62. package/dist/ui/badge.js +21 -0
  63. package/dist/ui/button.d.ts +17 -0
  64. package/dist/ui/button.js +39 -0
  65. package/dist/ui/card.d.ts +10 -0
  66. package/dist/ui/card.js +25 -0
  67. package/dist/ui/dialog.d.ts +14 -0
  68. package/dist/ui/dialog.js +25 -0
  69. package/dist/ui/index.d.ts +18 -0
  70. package/dist/ui/index.js +16 -0
  71. package/dist/ui/input.d.ts +4 -0
  72. package/dist/ui/input.js +7 -0
  73. package/dist/ui/label.d.ts +5 -0
  74. package/dist/ui/label.js +8 -0
  75. package/dist/ui/radio-group.d.ts +6 -0
  76. package/dist/ui/radio-group.js +11 -0
  77. package/dist/ui/select.d.ts +14 -0
  78. package/dist/ui/select.js +27 -0
  79. package/dist/ui/separator.d.ts +5 -0
  80. package/dist/ui/separator.js +8 -0
  81. package/dist/ui/slider.d.ts +5 -0
  82. package/dist/ui/slider.js +8 -0
  83. package/dist/ui/switch.d.ts +13 -0
  84. package/dist/ui/switch.js +9 -0
  85. package/dist/ui/tabs.d.ts +8 -0
  86. package/dist/ui/tabs.js +13 -0
  87. package/dist/ui/textarea.d.ts +4 -0
  88. package/dist/ui/textarea.js +7 -0
  89. package/dist/ui/tooltip.d.ts +8 -0
  90. package/dist/ui/tooltip.js +11 -0
  91. package/dist/utils/cn.d.ts +3 -0
  92. package/dist/utils/cn.js +6 -0
  93. package/dist/vite/externals.d.ts +9 -0
  94. package/dist/vite/externals.js +19 -0
  95. package/dist/vite/plugin-config.d.ts +49 -0
  96. package/dist/vite/plugin-config.js +236 -0
  97. package/dist/vite/serve-externals.d.ts +9 -0
  98. package/dist/vite/serve-externals.js +78 -0
  99. package/dist/vite/stratos-dev-server.d.ts +21 -0
  100. package/dist/vite/stratos-dev-server.js +188 -0
  101. package/package.json +96 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * useSimData — TanStack Query + Socket.io hook for real-time simulator data.
3
+ *
4
+ * Hydrates from GET /api/simulator/snapshot on mount, then subscribes to
5
+ * simulator:data and simulator:status Socket.io events to keep the cache
6
+ * up-to-date. Multiple consumers share a single query cache entry.
7
+ *
8
+ * ## Performance
9
+ *
10
+ * Simulator data arrives at ~10–20 Hz via Socket.io. To prevent unnecessary
11
+ * React renders, incoming data is buffered and flushed to the TanStack Query
12
+ * cache using `requestAnimationFrame`. This aligns cache updates with the
13
+ * browser's paint cycle (~60 fps / ~16ms per frame), coalescing multiple
14
+ * Socket.io events that arrive within a single frame into one cache write.
15
+ *
16
+ * Additional optimizations:
17
+ * - **Structural sharing** (TanStack Query default): prevents re-renders when
18
+ * `setQueryData` is called with structurally identical data.
19
+ * - **`select` parameter**: components can subscribe to a subset of fields
20
+ * (e.g. `useSimData({ select: s => s?.data?.altitude })`) and only re-render
21
+ * when those specific values change.
22
+ * - **No polling**: `staleTime: Infinity` with disabled refetch options ensures
23
+ * Socket.io pushes are the sole update mechanism after initial REST hydration.
24
+ *
25
+ * Target: <16ms per frame for the tracking page render cycle.
26
+ */
27
+ import type { SimDataSnapshot } from "../shared-types/simulator";
28
+ export declare const simDataKeys: {
29
+ snapshot: readonly ["simulator", "snapshot"];
30
+ };
31
+ type UseSimDataOptions<TSelected = SimDataSnapshot> = {
32
+ select?: (snapshot: SimDataSnapshot) => TSelected;
33
+ };
34
+ type UseSimDataReturn<TSelected = SimDataSnapshot> = {
35
+ data: TSelected;
36
+ isLoading: boolean;
37
+ };
38
+ /**
39
+ * Hook for real-time simulator data using TanStack Query + Socket.io.
40
+ *
41
+ * On mount, fetches the current simulator snapshot via REST.
42
+ * Then subscribes to Socket.io events and updates the query cache directly,
43
+ * so multiple components share a single cache entry with TanStack Query deduplication.
44
+ *
45
+ * Supports an optional `select` parameter to subscribe to specific fields
46
+ * and only re-render when those fields change (via TanStack Query structural sharing).
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * // Full data (re-renders on any field change)
51
+ * const { data } = useSimData();
52
+ *
53
+ * // Position only (re-renders only when lat/lon/heading change)
54
+ * const { data: pos } = useSimData({
55
+ * select: (s) => ({
56
+ * lat: s?.data?.latitude ?? 0,
57
+ * lon: s?.data?.longitude ?? 0,
58
+ * hdg: s?.data?.heading ?? 0,
59
+ * }),
60
+ * });
61
+ *
62
+ * // Single scalar (re-renders only when altitude changes)
63
+ * const { data: alt } = useSimData({
64
+ * select: (s) => s?.data?.altitude ?? 0,
65
+ * });
66
+ * ```
67
+ */
68
+ export declare function useSimData<TSelected = SimDataSnapshot>(options?: UseSimDataOptions<TSelected>): UseSimDataReturn<TSelected>;
69
+ export {};
70
+ //# sourceMappingURL=useSimData.d.ts.map
@@ -0,0 +1,135 @@
1
+ /**
2
+ * useSimData — TanStack Query + Socket.io hook for real-time simulator data.
3
+ *
4
+ * Hydrates from GET /api/simulator/snapshot on mount, then subscribes to
5
+ * simulator:data and simulator:status Socket.io events to keep the cache
6
+ * up-to-date. Multiple consumers share a single query cache entry.
7
+ *
8
+ * ## Performance
9
+ *
10
+ * Simulator data arrives at ~10–20 Hz via Socket.io. To prevent unnecessary
11
+ * React renders, incoming data is buffered and flushed to the TanStack Query
12
+ * cache using `requestAnimationFrame`. This aligns cache updates with the
13
+ * browser's paint cycle (~60 fps / ~16ms per frame), coalescing multiple
14
+ * Socket.io events that arrive within a single frame into one cache write.
15
+ *
16
+ * Additional optimizations:
17
+ * - **Structural sharing** (TanStack Query default): prevents re-renders when
18
+ * `setQueryData` is called with structurally identical data.
19
+ * - **`select` parameter**: components can subscribe to a subset of fields
20
+ * (e.g. `useSimData({ select: s => s?.data?.altitude })`) and only re-render
21
+ * when those specific values change.
22
+ * - **No polling**: `staleTime: Infinity` with disabled refetch options ensures
23
+ * Socket.io pushes are the sole update mechanism after initial REST hydration.
24
+ *
25
+ * Target: <16ms per frame for the tracking page render cycle.
26
+ */
27
+ import { useEffect, useRef } from "react";
28
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
29
+ import { useSocket } from "./useSimulatorData";
30
+ import { SOCKET_EVENTS } from "../shared-types/socket-events";
31
+ const SERVER_PORT = 2066;
32
+ const API_BASE = `http://127.0.0.1:${SERVER_PORT}`;
33
+ export const simDataKeys = {
34
+ snapshot: ["simulator", "snapshot"],
35
+ };
36
+ async function fetchSnapshot() {
37
+ const response = await fetch(`${API_BASE}/api/simulator/snapshot`, {
38
+ headers: { Accept: "application/json" },
39
+ });
40
+ const json = (await response.json());
41
+ return json.data;
42
+ }
43
+ /**
44
+ * Hook for real-time simulator data using TanStack Query + Socket.io.
45
+ *
46
+ * On mount, fetches the current simulator snapshot via REST.
47
+ * Then subscribes to Socket.io events and updates the query cache directly,
48
+ * so multiple components share a single cache entry with TanStack Query deduplication.
49
+ *
50
+ * Supports an optional `select` parameter to subscribe to specific fields
51
+ * and only re-render when those fields change (via TanStack Query structural sharing).
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * // Full data (re-renders on any field change)
56
+ * const { data } = useSimData();
57
+ *
58
+ * // Position only (re-renders only when lat/lon/heading change)
59
+ * const { data: pos } = useSimData({
60
+ * select: (s) => ({
61
+ * lat: s?.data?.latitude ?? 0,
62
+ * lon: s?.data?.longitude ?? 0,
63
+ * hdg: s?.data?.heading ?? 0,
64
+ * }),
65
+ * });
66
+ *
67
+ * // Single scalar (re-renders only when altitude changes)
68
+ * const { data: alt } = useSimData({
69
+ * select: (s) => s?.data?.altitude ?? 0,
70
+ * });
71
+ * ```
72
+ */
73
+ export function useSimData(options) {
74
+ const queryClient = useQueryClient();
75
+ const { socket } = useSocket();
76
+ const socketRef = useRef(socket);
77
+ socketRef.current = socket;
78
+ const { data, isLoading } = useQuery({
79
+ queryKey: simDataKeys.snapshot,
80
+ queryFn: fetchSnapshot,
81
+ select: options?.select,
82
+ staleTime: Infinity,
83
+ refetchOnWindowFocus: false,
84
+ refetchOnReconnect: false,
85
+ });
86
+ // Subscribe to Socket.io events and push updates into the query cache.
87
+ // Uses requestAnimationFrame to batch high-frequency simulator:data updates
88
+ // (~10–20 Hz) to the browser's paint cycle, preventing unnecessary renders.
89
+ useEffect(() => {
90
+ if (!socket)
91
+ return;
92
+ // --- RAF-throttled simulator data updates ---
93
+ let pendingData = null;
94
+ let rafId = 0;
95
+ const flushData = () => {
96
+ rafId = 0;
97
+ const payload = pendingData;
98
+ if (!payload)
99
+ return;
100
+ pendingData = null;
101
+ queryClient.setQueryData(simDataKeys.snapshot, (prev) => ({
102
+ data: payload.data,
103
+ isConnected: prev?.isConnected ?? true,
104
+ simulatorType: payload.simulatorType,
105
+ }));
106
+ };
107
+ const handleData = (payload) => {
108
+ pendingData = payload;
109
+ if (!rafId) {
110
+ rafId = requestAnimationFrame(flushData);
111
+ }
112
+ };
113
+ // Status updates are infrequent — apply immediately (no throttle)
114
+ const handleStatus = (payload) => {
115
+ queryClient.setQueryData(simDataKeys.snapshot, (prev) => ({
116
+ data: prev?.data ?? null,
117
+ isConnected: payload.status === "connected",
118
+ simulatorType: payload.simulatorType,
119
+ }));
120
+ };
121
+ socket.on(SOCKET_EVENTS.SIMULATOR_DATA, handleData);
122
+ socket.on(SOCKET_EVENTS.SIMULATOR_STATUS, handleStatus);
123
+ return () => {
124
+ if (rafId)
125
+ cancelAnimationFrame(rafId);
126
+ socket.off(SOCKET_EVENTS.SIMULATOR_DATA, handleData);
127
+ socket.off(SOCKET_EVENTS.SIMULATOR_STATUS, handleStatus);
128
+ };
129
+ }, [socket, queryClient]);
130
+ return {
131
+ data: data,
132
+ isLoading,
133
+ };
134
+ }
135
+ //# sourceMappingURL=useSimData.js.map
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Socket.io React Hooks for Stratos
3
+ *
4
+ * Provides real-time communication with the shell's Express server for:
5
+ * - Simulator data streaming
6
+ * - Flight state updates
7
+ * - Protocol URL events
8
+ * - Notifications
9
+ * - System metrics
10
+ */
11
+ import { Socket } from "socket.io-client";
12
+ import { SOCKET_EVENTS } from "../shared-types/socket-events";
13
+ import type { ConnectionState, NotificationPayload, ProtocolUrlPayload, SimulatorDataPayload, SimulatorStatusPayload, SystemMetricsPayload } from "../shared-types/socket-events";
14
+ export { SOCKET_EVENTS, type ConnectionState, type NotificationPayload, type ProtocolUrlPayload, type SimulatorDataPayload, type SimulatorStatusPayload, type SystemMetricsPayload, };
15
+ type UseSocketReturn = {
16
+ socket: Socket | null;
17
+ isConnected: boolean;
18
+ connectionState: ConnectionState;
19
+ clientId: string | null;
20
+ connect: () => void;
21
+ disconnect: () => void;
22
+ subscribe: (eventType: string) => void;
23
+ unsubscribe: (eventType: string) => void;
24
+ };
25
+ /**
26
+ * Core Socket.io hook for managing connection.
27
+ * Uses a singleton socket manager to share connection across all hooks.
28
+ */
29
+ export declare function useSocket(): UseSocketReturn;
30
+ /**
31
+ * Hook for simulator data streaming.
32
+ * Subscribes to real-time flight data and simulator status events.
33
+ */
34
+ export declare function useSimulatorData(onData?: (payload: SimulatorDataPayload) => void, onStatus?: (payload: SimulatorStatusPayload) => void): {
35
+ isConnected: boolean;
36
+ latestData: SimulatorDataPayload | null;
37
+ simulatorStatus: SimulatorStatusPayload | null;
38
+ };
39
+ /**
40
+ * Hook for protocol URL events (deep links).
41
+ */
42
+ export declare function useProtocolUrl(onProtocolUrl?: (payload: ProtocolUrlPayload) => void): ProtocolUrlPayload | null;
43
+ /**
44
+ * Hook for notifications.
45
+ */
46
+ export declare function useNotifications(onNotification?: (payload: NotificationPayload) => void): {
47
+ notifications: NotificationPayload[];
48
+ clearNotifications: () => void;
49
+ };
50
+ /**
51
+ * Hook for system metrics streaming.
52
+ */
53
+ export declare function useSystemMetrics(onMetrics?: (payload: SystemMetricsPayload) => void): {
54
+ isConnected: boolean;
55
+ metrics: SystemMetricsPayload | null;
56
+ };
57
+ //# sourceMappingURL=useSimulatorData.d.ts.map
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Socket.io React Hooks for Stratos
3
+ *
4
+ * Provides real-time communication with the shell's Express server for:
5
+ * - Simulator data streaming
6
+ * - Flight state updates
7
+ * - Protocol URL events
8
+ * - Notifications
9
+ * - System metrics
10
+ */
11
+ import { useEffect, useState, useCallback, useSyncExternalStore } from "react";
12
+ import { io } from "socket.io-client";
13
+ import { SOCKET_EVENTS } from "../shared-types/socket-events";
14
+ // Re-export canonical types so existing consumers that import from
15
+ // "./useSimulatorData" continue to work without changes.
16
+ export { SOCKET_EVENTS, };
17
+ // Server configuration - matches shell main process
18
+ const SERVER_PORT = 2066;
19
+ const SERVER_URL = `http://127.0.0.1:${SERVER_PORT}`;
20
+ class SocketManager {
21
+ constructor() {
22
+ this.socket = null;
23
+ this.connectionState = "disconnected";
24
+ this.clientId = null;
25
+ this.listeners = new Set();
26
+ this.refCount = 0;
27
+ this.snapshot = this.createSnapshot();
28
+ }
29
+ static getInstance() {
30
+ if (!SocketManager.instance) {
31
+ SocketManager.instance = new SocketManager();
32
+ }
33
+ return SocketManager.instance;
34
+ }
35
+ createSnapshot() {
36
+ return {
37
+ socket: this.socket,
38
+ connectionState: this.connectionState,
39
+ clientId: this.clientId,
40
+ isConnected: this.connectionState === "connected",
41
+ };
42
+ }
43
+ subscribe(listener) {
44
+ this.listeners.add(listener);
45
+ this.refCount++;
46
+ if (this.refCount === 1) {
47
+ this.connect();
48
+ }
49
+ return () => {
50
+ this.listeners.delete(listener);
51
+ this.refCount--;
52
+ if (this.refCount === 0) {
53
+ setTimeout(() => {
54
+ if (this.refCount === 0) {
55
+ this.disconnect();
56
+ }
57
+ }, 1000);
58
+ }
59
+ };
60
+ }
61
+ notify() {
62
+ this.snapshot = this.createSnapshot();
63
+ this.listeners.forEach((listener) => listener());
64
+ }
65
+ connect() {
66
+ if (this.socket)
67
+ return;
68
+ this.connectionState = "connecting";
69
+ this.notify();
70
+ this.socket = io(SERVER_URL, {
71
+ transports: ["websocket", "polling"],
72
+ reconnection: true,
73
+ reconnectionAttempts: 5,
74
+ reconnectionDelay: 1000,
75
+ autoConnect: true,
76
+ });
77
+ this.socket.on("connect", () => {
78
+ this.connectionState = "connected";
79
+ this.notify();
80
+ });
81
+ this.socket.on("connected", (data) => {
82
+ this.clientId = data.clientId;
83
+ this.notify();
84
+ });
85
+ this.socket.on("disconnect", () => {
86
+ this.connectionState = "disconnected";
87
+ this.clientId = null;
88
+ this.notify();
89
+ });
90
+ this.socket.on("connect_error", () => {
91
+ this.connectionState = "error";
92
+ this.notify();
93
+ });
94
+ }
95
+ disconnect() {
96
+ if (this.socket) {
97
+ this.socket.close();
98
+ this.socket = null;
99
+ this.connectionState = "disconnected";
100
+ this.clientId = null;
101
+ this.snapshot = this.createSnapshot();
102
+ }
103
+ }
104
+ getSnapshot() {
105
+ return this.snapshot;
106
+ }
107
+ manualConnect() {
108
+ if (this.socket && !this.socket.connected) {
109
+ this.connectionState = "connecting";
110
+ this.notify();
111
+ this.socket.connect();
112
+ }
113
+ }
114
+ manualDisconnect() {
115
+ if (this.socket && this.socket.connected) {
116
+ this.socket.disconnect();
117
+ }
118
+ }
119
+ }
120
+ const socketManager = SocketManager.getInstance();
121
+ // ── Hooks ───────────────────────────────────────────────────────────────
122
+ /**
123
+ * Core Socket.io hook for managing connection.
124
+ * Uses a singleton socket manager to share connection across all hooks.
125
+ */
126
+ export function useSocket() {
127
+ const state = useSyncExternalStore((listener) => socketManager.subscribe(listener), () => socketManager.getSnapshot(), () => socketManager.getSnapshot());
128
+ const connect = useCallback(() => {
129
+ socketManager.manualConnect();
130
+ }, []);
131
+ const disconnect = useCallback(() => {
132
+ socketManager.manualDisconnect();
133
+ }, []);
134
+ const subscribe = useCallback((eventType) => {
135
+ const socket = socketManager.getSnapshot().socket;
136
+ if (socket && socket.connected) {
137
+ socket.emit("subscribe", eventType);
138
+ }
139
+ }, []);
140
+ const unsubscribe = useCallback((eventType) => {
141
+ const socket = socketManager.getSnapshot().socket;
142
+ if (socket && socket.connected) {
143
+ socket.emit("unsubscribe", eventType);
144
+ }
145
+ }, []);
146
+ return {
147
+ socket: state.socket,
148
+ isConnected: state.isConnected,
149
+ connectionState: state.connectionState,
150
+ clientId: state.clientId,
151
+ connect,
152
+ disconnect,
153
+ subscribe,
154
+ unsubscribe,
155
+ };
156
+ }
157
+ /**
158
+ * Hook for simulator data streaming.
159
+ * Subscribes to real-time flight data and simulator status events.
160
+ */
161
+ export function useSimulatorData(onData, onStatus) {
162
+ const { socket, isConnected } = useSocket();
163
+ const [latestData, setLatestData] = useState(null);
164
+ const [simulatorStatus, setSimulatorStatus] = useState(null);
165
+ useEffect(() => {
166
+ if (!socket)
167
+ return;
168
+ const handleData = (payload) => {
169
+ setLatestData(payload);
170
+ onData?.(payload);
171
+ };
172
+ const handleStatus = (payload) => {
173
+ setSimulatorStatus(payload);
174
+ onStatus?.(payload);
175
+ };
176
+ socket.on(SOCKET_EVENTS.SIMULATOR_DATA, handleData);
177
+ socket.on(SOCKET_EVENTS.SIMULATOR_STATUS, handleStatus);
178
+ return () => {
179
+ socket.off(SOCKET_EVENTS.SIMULATOR_DATA, handleData);
180
+ socket.off(SOCKET_EVENTS.SIMULATOR_STATUS, handleStatus);
181
+ };
182
+ }, [socket, onData, onStatus]);
183
+ return {
184
+ isConnected,
185
+ latestData,
186
+ simulatorStatus,
187
+ };
188
+ }
189
+ /**
190
+ * Hook for protocol URL events (deep links).
191
+ */
192
+ export function useProtocolUrl(onProtocolUrl) {
193
+ const { socket } = useSocket();
194
+ const [latestUrl, setLatestUrl] = useState(null);
195
+ useEffect(() => {
196
+ if (!socket)
197
+ return;
198
+ const handleProtocolUrl = (payload) => {
199
+ setLatestUrl(payload);
200
+ onProtocolUrl?.(payload);
201
+ };
202
+ socket.on(SOCKET_EVENTS.PROTOCOL_URL, handleProtocolUrl);
203
+ return () => {
204
+ socket.off(SOCKET_EVENTS.PROTOCOL_URL, handleProtocolUrl);
205
+ };
206
+ }, [socket, onProtocolUrl]);
207
+ return latestUrl;
208
+ }
209
+ /**
210
+ * Hook for notifications.
211
+ */
212
+ export function useNotifications(onNotification) {
213
+ const { socket } = useSocket();
214
+ const [notifications, setNotifications] = useState([]);
215
+ useEffect(() => {
216
+ if (!socket)
217
+ return;
218
+ const handleNotification = (payload) => {
219
+ setNotifications((prev) => [...prev, payload]);
220
+ onNotification?.(payload);
221
+ };
222
+ socket.on(SOCKET_EVENTS.NOTIFICATION, handleNotification);
223
+ return () => {
224
+ socket.off(SOCKET_EVENTS.NOTIFICATION, handleNotification);
225
+ };
226
+ }, [socket, onNotification]);
227
+ const clearNotifications = useCallback(() => {
228
+ setNotifications([]);
229
+ }, []);
230
+ return {
231
+ notifications,
232
+ clearNotifications,
233
+ };
234
+ }
235
+ /**
236
+ * Hook for system metrics streaming.
237
+ */
238
+ export function useSystemMetrics(onMetrics) {
239
+ const { socket, isConnected } = useSocket();
240
+ const [metrics, setMetrics] = useState(null);
241
+ useEffect(() => {
242
+ if (!socket)
243
+ return;
244
+ const handleMetrics = (payload) => {
245
+ setMetrics(payload);
246
+ onMetrics?.(payload);
247
+ };
248
+ socket.on(SOCKET_EVENTS.SYSTEM_METRICS, handleMetrics);
249
+ return () => {
250
+ socket.off(SOCKET_EVENTS.SYSTEM_METRICS, handleMetrics);
251
+ };
252
+ }, [socket, onMetrics]);
253
+ return {
254
+ isConnected,
255
+ metrics,
256
+ };
257
+ }
258
+ //# sourceMappingURL=useSimulatorData.js.map
@@ -0,0 +1,40 @@
1
+ /**
2
+ * useTrackingSession — Convenience hook that combines flight manager state
3
+ * with derived tracking metadata (isTracking, isPaused, elapsedTime, phase).
4
+ *
5
+ * Hydrates from GET /api/flight-manager/state on mount, then subscribes to
6
+ * flight:manager Socket.io events for real-time updates.
7
+ *
8
+ * Acts as a higher-level wrapper — plugins can still use useFlightManager()
9
+ * or lower-level hooks (useSimData, useFlightPhase, etc.) for more control.
10
+ */
11
+ import type { CurrentFlight, FlightPlan, StartFlightResult, RecoverableFlight } from "../shared-types/flight-manager";
12
+ import { FlightPhase } from "../shared-types/simulator";
13
+ export declare const trackingSessionKeys: {
14
+ state: readonly ["tracking-session", "state"];
15
+ pendingRecovery: readonly ["tracking-session", "pending-recovery"];
16
+ };
17
+ type UseTrackingSessionReturn = {
18
+ isTracking: boolean;
19
+ isPaused: boolean;
20
+ currentFlight: CurrentFlight | null;
21
+ pendingRecovery: RecoverableFlight | null;
22
+ elapsedTime: number;
23
+ phase: FlightPhase;
24
+ startFlight: (plan: FlightPlan, options?: {
25
+ skipPreflightWarnings?: boolean;
26
+ forceStart?: boolean;
27
+ }) => Promise<StartFlightResult>;
28
+ pauseFlight: () => Promise<boolean>;
29
+ resumeFlight: () => Promise<boolean>;
30
+ endFlight: (status?: "completed" | "diverted" | "crashed" | "cancelled") => Promise<{
31
+ success: boolean;
32
+ error?: string;
33
+ }>;
34
+ recoverFlight: () => Promise<boolean>;
35
+ dismissRecovery: () => Promise<boolean>;
36
+ isLoading: boolean;
37
+ };
38
+ export declare function useTrackingSession(): UseTrackingSessionReturn;
39
+ export {};
40
+ //# sourceMappingURL=useTrackingSession.d.ts.map