@10play/expo-air 0.6.0 → 0.7.0
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/build/ExpoAirModule.d.ts +1 -0
- package/build/ExpoAirModule.d.ts.map +1 -1
- package/build/ExpoAirModule.js.map +1 -1
- package/build/hmrReconnect.d.ts +13 -0
- package/build/hmrReconnect.d.ts.map +1 -0
- package/build/hmrReconnect.js +277 -0
- package/build/hmrReconnect.js.map +1 -0
- package/cli/dist/commands/dev.d.ts.map +1 -1
- package/cli/dist/commands/dev.js +32 -2
- package/cli/dist/commands/dev.js.map +1 -1
- package/cli/dist/server/promptServer.d.ts +11 -0
- package/cli/dist/server/promptServer.d.ts.map +1 -1
- package/cli/dist/server/promptServer.js +371 -10
- package/cli/dist/server/promptServer.js.map +1 -1
- package/cli/dist/types/messages.d.ts +39 -2
- package/cli/dist/types/messages.d.ts.map +1 -1
- package/ios/ExpoAir.podspec +4 -1
- package/ios/widget.jsbundle +3 -2
- package/package.json +1 -1
- package/plugin/build/index.js +37 -0
- package/widget/BubbleContent.tsx +81 -5
- package/widget/components/BranchSwitcher.tsx +257 -0
- package/widget/services/websocket.ts +61 -1
package/build/ExpoAirModule.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoAirModule.d.ts","sourceRoot":"","sources":["../src/ExpoAirModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,OAAO,aAAc,SAAQ,YAAY,CAAC,mBAAmB,CAAC;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,IAAI,MAAM;IACf,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IACvD,IAAI,IAAI,IAAI;IACZ,MAAM,IAAI,IAAI;IACd,QAAQ,IAAI,IAAI;
|
|
1
|
+
{"version":3,"file":"ExpoAirModule.d.ts","sourceRoot":"","sources":["../src/ExpoAirModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,OAAO,OAAO,aAAc,SAAQ,YAAY,CAAC,mBAAmB,CAAC;IACnE,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,IAAI,MAAM;IACf,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAC3C,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IACvD,IAAI,IAAI,IAAI;IACZ,MAAM,IAAI,IAAI;IACd,QAAQ,IAAI,IAAI;IAChB,YAAY,IAAI,MAAM;CACvB;;AAGD,wBAA6D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoAirModule.js","sourceRoot":"","sources":["../src/ExpoAirModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ExpoAirModule.js","sourceRoot":"","sources":["../src/ExpoAirModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAezD,yDAAyD;AACzD,eAAe,mBAAmB,CAAgB,SAAS,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\n\nimport { ExpoAirModuleEvents } from \"./ExpoAir.types\";\n\ndeclare class ExpoAirModule extends NativeModule<ExpoAirModuleEvents> {\n PI: number;\n hello(): string;\n setValueAsync(value: string): Promise<void>;\n show(options?: { size?: number; color?: string }): void;\n hide(): void;\n expand(): void;\n collapse(): void;\n getServerUrl(): string;\n}\n\n// This call loads the native module object from the JSI.\nexport default requireNativeModule<ExpoAirModule>(\"ExpoAir\");\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metro HMR WebSocket Auto-Reconnect
|
|
3
|
+
*
|
|
4
|
+
* Patches global.WebSocket to wrap Metro's HMR connections with automatic
|
|
5
|
+
* reconnection. When the HMR WebSocket disconnects (tunnel drops, WiFi issues,
|
|
6
|
+
* app backgrounding), this module auto-reconnects and tells the prompt server
|
|
7
|
+
* to re-touch uncommitted files so Metro re-pushes HMR updates.
|
|
8
|
+
*
|
|
9
|
+
* Must be imported early in the app lifecycle, before Metro's HMR client
|
|
10
|
+
* creates its WebSocket connection.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=hmrReconnect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmrReconnect.d.ts","sourceRoot":"","sources":["../src/hmrReconnect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metro HMR WebSocket Auto-Reconnect
|
|
3
|
+
*
|
|
4
|
+
* Patches global.WebSocket to wrap Metro's HMR connections with automatic
|
|
5
|
+
* reconnection. When the HMR WebSocket disconnects (tunnel drops, WiFi issues,
|
|
6
|
+
* app backgrounding), this module auto-reconnects and tells the prompt server
|
|
7
|
+
* to re-touch uncommitted files so Metro re-pushes HMR updates.
|
|
8
|
+
*
|
|
9
|
+
* Must be imported early in the app lifecycle, before Metro's HMR client
|
|
10
|
+
* creates its WebSocket connection.
|
|
11
|
+
*/
|
|
12
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
13
|
+
console.log("[expo-air:hmr] Initializing HMR auto-reconnect module");
|
|
14
|
+
const OriginalWebSocket = globalThis.WebSocket;
|
|
15
|
+
// Get the prompt server URL for retrigger requests
|
|
16
|
+
let serverHttpUrl = null;
|
|
17
|
+
try {
|
|
18
|
+
const ExpoAirModule = require("./ExpoAirModule").default ?? require("./ExpoAirModule");
|
|
19
|
+
const wsUrl = ExpoAirModule.getServerUrl?.();
|
|
20
|
+
console.log("[expo-air:hmr] Server URL from native module:", wsUrl);
|
|
21
|
+
if (wsUrl) {
|
|
22
|
+
serverHttpUrl = wsUrl
|
|
23
|
+
.replace(/^ws:/, "http:")
|
|
24
|
+
.replace(/^wss:/, "https:");
|
|
25
|
+
console.log("[expo-air:hmr] HTTP URL for retrigger:", serverHttpUrl);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.warn("[expo-air:hmr] getServerUrl() returned empty/null");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
console.warn("[expo-air:hmr] Failed to get server URL:", e);
|
|
33
|
+
}
|
|
34
|
+
const MAX_ATTEMPTS = 50;
|
|
35
|
+
const BASE_DELAY = 2000;
|
|
36
|
+
const MAX_DELAY = 30000;
|
|
37
|
+
function isMetroHMRUrl(url) {
|
|
38
|
+
return typeof url === "string" && url.includes("/hot");
|
|
39
|
+
}
|
|
40
|
+
function notifyServerOfReconnection() {
|
|
41
|
+
if (!serverHttpUrl) {
|
|
42
|
+
console.log("[expo-air:hmr] Cannot retrigger - no server URL available");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
console.log("[expo-air:hmr] Sending retrigger request to:", `${serverHttpUrl}/hmr-retrigger`);
|
|
46
|
+
globalThis
|
|
47
|
+
.fetch(`${serverHttpUrl}/hmr-retrigger`, { method: "POST" })
|
|
48
|
+
.then((res) => {
|
|
49
|
+
console.log("[expo-air:hmr] Retrigger response status:", res.status);
|
|
50
|
+
})
|
|
51
|
+
.catch((err) => {
|
|
52
|
+
console.warn("[expo-air:hmr] Retrigger request failed:", err);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
globalThis.WebSocket = function ReconnectingWebSocket(url, protocols) {
|
|
56
|
+
// Non-HMR connections pass through unchanged
|
|
57
|
+
if (!isMetroHMRUrl(url)) {
|
|
58
|
+
if (protocols !== undefined) {
|
|
59
|
+
return new OriginalWebSocket(url, protocols);
|
|
60
|
+
}
|
|
61
|
+
return new OriginalWebSocket(url);
|
|
62
|
+
}
|
|
63
|
+
console.log("[expo-air:hmr] Wrapping Metro HMR WebSocket:", url);
|
|
64
|
+
let inner = null;
|
|
65
|
+
const handlers = {
|
|
66
|
+
open: null,
|
|
67
|
+
close: null,
|
|
68
|
+
message: null,
|
|
69
|
+
error: null,
|
|
70
|
+
};
|
|
71
|
+
const eventListeners = {
|
|
72
|
+
open: new Set(),
|
|
73
|
+
close: new Set(),
|
|
74
|
+
message: new Set(),
|
|
75
|
+
error: new Set(),
|
|
76
|
+
};
|
|
77
|
+
let attempts = 0;
|
|
78
|
+
let intentionalClose = false;
|
|
79
|
+
let reconnectTimer = null;
|
|
80
|
+
// Capture HMR protocol messages for replay on reconnection.
|
|
81
|
+
// Metro's server tears down all client state (including file-change listeners)
|
|
82
|
+
// when the WebSocket disconnects. On reconnect, the client must re-send
|
|
83
|
+
// register-entrypoints so Metro knows which bundles to watch.
|
|
84
|
+
const registrationMessages = [];
|
|
85
|
+
// The wrapper object returned to the HMR client
|
|
86
|
+
const wrapper = Object.create(OriginalWebSocket.prototype);
|
|
87
|
+
function dispatch(type, event) {
|
|
88
|
+
const handler = handlers[type];
|
|
89
|
+
if (handler)
|
|
90
|
+
handler.call(wrapper, event);
|
|
91
|
+
const set = eventListeners[type];
|
|
92
|
+
if (set) {
|
|
93
|
+
for (const fn of set) {
|
|
94
|
+
fn.call(wrapper, event);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
function connect() {
|
|
99
|
+
let ws;
|
|
100
|
+
try {
|
|
101
|
+
console.log(`[expo-air:hmr] ${attempts > 0 ? "Re-c" : "C"}onnecting HMR WebSocket to:`, url);
|
|
102
|
+
ws = protocols
|
|
103
|
+
? new OriginalWebSocket(url, protocols)
|
|
104
|
+
: new OriginalWebSocket(url);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
console.warn("[expo-air:hmr] WebSocket creation failed:", e);
|
|
108
|
+
scheduleReconnect();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
inner = ws;
|
|
112
|
+
ws.onopen = (event) => {
|
|
113
|
+
const wasReconnect = attempts > 0;
|
|
114
|
+
attempts = 0;
|
|
115
|
+
console.log(`[expo-air:hmr] HMR WebSocket ${wasReconnect ? "RE" : ""}connected`);
|
|
116
|
+
if (wasReconnect && registrationMessages.length > 0) {
|
|
117
|
+
// Re-send captured registration messages BEFORE notifying HMR client.
|
|
118
|
+
// Metro's server resets all client state on disconnect, so we must
|
|
119
|
+
// re-register entrypoints for Metro to set up file-change listeners.
|
|
120
|
+
console.log(`[expo-air:hmr] Replaying ${registrationMessages.length} registration messages`);
|
|
121
|
+
for (const msg of registrationMessages) {
|
|
122
|
+
try {
|
|
123
|
+
ws.send(msg);
|
|
124
|
+
}
|
|
125
|
+
catch (e) {
|
|
126
|
+
console.warn("[expo-air:hmr] Failed to replay message:", e);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
dispatch("open", event);
|
|
131
|
+
if (wasReconnect) {
|
|
132
|
+
console.log("[expo-air:hmr] Reconnected, re-registered, requesting file retrigger");
|
|
133
|
+
// Delay retrigger to let Metro process registration and set up listeners
|
|
134
|
+
setTimeout(notifyServerOfReconnection, 2000);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
ws.onmessage = (event) => {
|
|
138
|
+
dispatch("message", event);
|
|
139
|
+
};
|
|
140
|
+
ws.onerror = (event) => {
|
|
141
|
+
console.warn("[expo-air:hmr] HMR WebSocket error");
|
|
142
|
+
dispatch("error", event);
|
|
143
|
+
};
|
|
144
|
+
ws.onclose = (event) => {
|
|
145
|
+
if (intentionalClose) {
|
|
146
|
+
dispatch("close", event);
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
console.log("[expo-air:hmr] HMR WebSocket disconnected (code:", event?.code, "), will auto-reconnect...");
|
|
150
|
+
scheduleReconnect();
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function scheduleReconnect() {
|
|
154
|
+
if (attempts >= MAX_ATTEMPTS) {
|
|
155
|
+
console.warn(`[expo-air:hmr] Gave up reconnecting after ${MAX_ATTEMPTS} attempts`);
|
|
156
|
+
dispatch("close", {
|
|
157
|
+
code: 1006,
|
|
158
|
+
reason: "Max reconnect attempts reached",
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
attempts++;
|
|
163
|
+
const delay = Math.min(BASE_DELAY * Math.pow(1.5, attempts - 1), MAX_DELAY);
|
|
164
|
+
const jitter = delay * (0.8 + Math.random() * 0.4);
|
|
165
|
+
console.log(`[expo-air:hmr] Reconnect attempt ${attempts}/${MAX_ATTEMPTS} in ${Math.round(jitter / 1000)}s`);
|
|
166
|
+
reconnectTimer = setTimeout(connect, jitter);
|
|
167
|
+
}
|
|
168
|
+
// on* handler properties
|
|
169
|
+
for (const type of ["open", "close", "message", "error"]) {
|
|
170
|
+
Object.defineProperty(wrapper, `on${type}`, {
|
|
171
|
+
get: () => handlers[type],
|
|
172
|
+
set: (fn) => {
|
|
173
|
+
handlers[type] = fn;
|
|
174
|
+
},
|
|
175
|
+
configurable: true,
|
|
176
|
+
enumerable: true,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
Object.defineProperties(wrapper, {
|
|
180
|
+
readyState: {
|
|
181
|
+
get: () => (inner ? inner.readyState : OriginalWebSocket.CLOSED),
|
|
182
|
+
configurable: true,
|
|
183
|
+
},
|
|
184
|
+
url: {
|
|
185
|
+
get: () => url,
|
|
186
|
+
configurable: true,
|
|
187
|
+
},
|
|
188
|
+
protocol: {
|
|
189
|
+
get: () => (inner ? inner.protocol : ""),
|
|
190
|
+
configurable: true,
|
|
191
|
+
},
|
|
192
|
+
extensions: {
|
|
193
|
+
get: () => (inner ? inner.extensions : ""),
|
|
194
|
+
configurable: true,
|
|
195
|
+
},
|
|
196
|
+
bufferedAmount: {
|
|
197
|
+
get: () => (inner ? inner.bufferedAmount : 0),
|
|
198
|
+
configurable: true,
|
|
199
|
+
},
|
|
200
|
+
binaryType: {
|
|
201
|
+
get: () => (inner ? inner.binaryType : "blob"),
|
|
202
|
+
set: (val) => {
|
|
203
|
+
if (inner)
|
|
204
|
+
inner.binaryType = val;
|
|
205
|
+
},
|
|
206
|
+
configurable: true,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
wrapper.send = (data) => {
|
|
210
|
+
// Capture HMR protocol messages needed for reconnection
|
|
211
|
+
if (typeof data === "string") {
|
|
212
|
+
try {
|
|
213
|
+
const parsed = JSON.parse(data);
|
|
214
|
+
if (parsed.type === "register-entrypoints" ||
|
|
215
|
+
parsed.type === "log-opt-in") {
|
|
216
|
+
// Update: keep latest version of each message type
|
|
217
|
+
const idx = registrationMessages.findIndex((m) => {
|
|
218
|
+
try {
|
|
219
|
+
return JSON.parse(m).type === parsed.type;
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
if (idx >= 0) {
|
|
226
|
+
registrationMessages[idx] = data;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
registrationMessages.push(data);
|
|
230
|
+
}
|
|
231
|
+
console.log(`[expo-air:hmr] Captured ${parsed.type} message for reconnection replay`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch {
|
|
235
|
+
// Not JSON, ignore
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (inner && inner.readyState === OriginalWebSocket.OPEN) {
|
|
239
|
+
inner.send(data);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
wrapper.close = (code, reason) => {
|
|
243
|
+
intentionalClose = true;
|
|
244
|
+
if (reconnectTimer) {
|
|
245
|
+
clearTimeout(reconnectTimer);
|
|
246
|
+
reconnectTimer = null;
|
|
247
|
+
}
|
|
248
|
+
if (inner)
|
|
249
|
+
inner.close(code, reason);
|
|
250
|
+
};
|
|
251
|
+
wrapper.addEventListener = (type, listener, _options) => {
|
|
252
|
+
const set = eventListeners[type];
|
|
253
|
+
if (set)
|
|
254
|
+
set.add(listener);
|
|
255
|
+
};
|
|
256
|
+
wrapper.removeEventListener = (type, listener) => {
|
|
257
|
+
const set = eventListeners[type];
|
|
258
|
+
if (set)
|
|
259
|
+
set.delete(listener);
|
|
260
|
+
};
|
|
261
|
+
wrapper.dispatchEvent = () => false;
|
|
262
|
+
connect();
|
|
263
|
+
return wrapper;
|
|
264
|
+
};
|
|
265
|
+
// Copy static constants
|
|
266
|
+
globalThis.WebSocket.CONNECTING = OriginalWebSocket.CONNECTING;
|
|
267
|
+
globalThis.WebSocket.OPEN = OriginalWebSocket.OPEN;
|
|
268
|
+
globalThis.WebSocket.CLOSING = OriginalWebSocket.CLOSING;
|
|
269
|
+
globalThis.WebSocket.CLOSED = OriginalWebSocket.CLOSED;
|
|
270
|
+
// Log final initialization state
|
|
271
|
+
console.log("[expo-air:hmr] Module initialized", {
|
|
272
|
+
serverHttpUrl: serverHttpUrl ? "set" : "NOT SET",
|
|
273
|
+
webSocketPatched: true,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
export {};
|
|
277
|
+
//# sourceMappingURL=hmrReconnect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hmrReconnect.js","sourceRoot":"","sources":["../src/hmrReconnect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Metro HMR WebSocket Auto-Reconnect\n *\n * Patches global.WebSocket to wrap Metro's HMR connections with automatic\n * reconnection. When the HMR WebSocket disconnects (tunnel drops, WiFi issues,\n * app backgrounding), this module auto-reconnects and tells the prompt server\n * to re-touch uncommitted files so Metro re-pushes HMR updates.\n *\n * Must be imported early in the app lifecycle, before Metro's HMR client\n * creates its WebSocket connection.\n */\n\n/* eslint-disable @typescript-eslint/no-var-requires */\n\ndeclare const __DEV__: boolean;\ndeclare const globalThis: {\n WebSocket: typeof WebSocket;\n fetch: typeof fetch;\n};\n\nif (typeof __DEV__ !== \"undefined\" && __DEV__) {\n console.log(\"[expo-air:hmr] Initializing HMR auto-reconnect module\");\n\n const OriginalWebSocket = globalThis.WebSocket;\n\n // Get the prompt server URL for retrigger requests\n let serverHttpUrl: string | null = null;\n try {\n const ExpoAirModule =\n require(\"./ExpoAirModule\").default ?? require(\"./ExpoAirModule\");\n const wsUrl: string = ExpoAirModule.getServerUrl?.();\n console.log(\"[expo-air:hmr] Server URL from native module:\", wsUrl);\n if (wsUrl) {\n serverHttpUrl = wsUrl\n .replace(/^ws:/, \"http:\")\n .replace(/^wss:/, \"https:\");\n console.log(\"[expo-air:hmr] HTTP URL for retrigger:\", serverHttpUrl);\n } else {\n console.warn(\"[expo-air:hmr] getServerUrl() returned empty/null\");\n }\n } catch (e) {\n console.warn(\"[expo-air:hmr] Failed to get server URL:\", e);\n }\n\n const MAX_ATTEMPTS = 50;\n const BASE_DELAY = 2000;\n const MAX_DELAY = 30000;\n\n function isMetroHMRUrl(url: string): boolean {\n return typeof url === \"string\" && url.includes(\"/hot\");\n }\n\n function notifyServerOfReconnection(): void {\n if (!serverHttpUrl) {\n console.log(\n \"[expo-air:hmr] Cannot retrigger - no server URL available\"\n );\n return;\n }\n console.log(\n \"[expo-air:hmr] Sending retrigger request to:\",\n `${serverHttpUrl}/hmr-retrigger`\n );\n globalThis\n .fetch(`${serverHttpUrl}/hmr-retrigger`, { method: \"POST\" })\n .then((res) => {\n console.log(\"[expo-air:hmr] Retrigger response status:\", res.status);\n })\n .catch((err) => {\n console.warn(\"[expo-air:hmr] Retrigger request failed:\", err);\n });\n }\n\n type Handler = ((...args: any[]) => void) | null;\n\n globalThis.WebSocket = function ReconnectingWebSocket(\n this: any,\n url: string,\n protocols?: string | string[]\n ) {\n // Non-HMR connections pass through unchanged\n if (!isMetroHMRUrl(url)) {\n if (protocols !== undefined) {\n return new OriginalWebSocket(url, protocols);\n }\n return new OriginalWebSocket(url);\n }\n\n console.log(\"[expo-air:hmr] Wrapping Metro HMR WebSocket:\", url);\n\n let inner: WebSocket | null = null;\n const handlers: Record<string, Handler> = {\n open: null,\n close: null,\n message: null,\n error: null,\n };\n const eventListeners: Record<string, Set<Function>> = {\n open: new Set(),\n close: new Set(),\n message: new Set(),\n error: new Set(),\n };\n\n let attempts = 0;\n let intentionalClose = false;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Capture HMR protocol messages for replay on reconnection.\n // Metro's server tears down all client state (including file-change listeners)\n // when the WebSocket disconnects. On reconnect, the client must re-send\n // register-entrypoints so Metro knows which bundles to watch.\n const registrationMessages: string[] = [];\n\n // The wrapper object returned to the HMR client\n const wrapper: any = Object.create(OriginalWebSocket.prototype);\n\n function dispatch(type: string, event: any): void {\n const handler = handlers[type];\n if (handler) handler.call(wrapper, event);\n const set = eventListeners[type];\n if (set) {\n for (const fn of set) {\n fn.call(wrapper, event);\n }\n }\n }\n\n function connect(): void {\n let ws: WebSocket;\n try {\n console.log(\n `[expo-air:hmr] ${attempts > 0 ? \"Re-c\" : \"C\"}onnecting HMR WebSocket to:`,\n url\n );\n ws = protocols\n ? new OriginalWebSocket(url, protocols)\n : new OriginalWebSocket(url);\n } catch (e) {\n console.warn(\"[expo-air:hmr] WebSocket creation failed:\", e);\n scheduleReconnect();\n return;\n }\n\n inner = ws;\n\n ws.onopen = (event: Event) => {\n const wasReconnect = attempts > 0;\n attempts = 0;\n\n console.log(\n `[expo-air:hmr] HMR WebSocket ${wasReconnect ? \"RE\" : \"\"}connected`\n );\n\n if (wasReconnect && registrationMessages.length > 0) {\n // Re-send captured registration messages BEFORE notifying HMR client.\n // Metro's server resets all client state on disconnect, so we must\n // re-register entrypoints for Metro to set up file-change listeners.\n console.log(\n `[expo-air:hmr] Replaying ${registrationMessages.length} registration messages`\n );\n for (const msg of registrationMessages) {\n try {\n ws.send(msg);\n } catch (e) {\n console.warn(\"[expo-air:hmr] Failed to replay message:\", e);\n }\n }\n }\n\n dispatch(\"open\", event);\n\n if (wasReconnect) {\n console.log(\n \"[expo-air:hmr] Reconnected, re-registered, requesting file retrigger\"\n );\n // Delay retrigger to let Metro process registration and set up listeners\n setTimeout(notifyServerOfReconnection, 2000);\n }\n };\n\n ws.onmessage = (event: MessageEvent) => {\n dispatch(\"message\", event);\n };\n\n ws.onerror = (event: Event) => {\n console.warn(\"[expo-air:hmr] HMR WebSocket error\");\n dispatch(\"error\", event);\n };\n\n ws.onclose = (event: CloseEvent) => {\n if (intentionalClose) {\n dispatch(\"close\", event);\n return;\n }\n\n console.log(\n \"[expo-air:hmr] HMR WebSocket disconnected (code:\",\n (event as any)?.code,\n \"), will auto-reconnect...\"\n );\n scheduleReconnect();\n };\n }\n\n function scheduleReconnect(): void {\n if (attempts >= MAX_ATTEMPTS) {\n console.warn(\n `[expo-air:hmr] Gave up reconnecting after ${MAX_ATTEMPTS} attempts`\n );\n\n dispatch(\"close\", {\n code: 1006,\n reason: \"Max reconnect attempts reached\",\n });\n return;\n }\n attempts++;\n const delay = Math.min(\n BASE_DELAY * Math.pow(1.5, attempts - 1),\n MAX_DELAY\n );\n const jitter = delay * (0.8 + Math.random() * 0.4);\n console.log(\n `[expo-air:hmr] Reconnect attempt ${attempts}/${MAX_ATTEMPTS} in ${Math.round(jitter / 1000)}s`\n );\n reconnectTimer = setTimeout(connect, jitter);\n }\n\n // on* handler properties\n for (const type of [\"open\", \"close\", \"message\", \"error\"] as const) {\n Object.defineProperty(wrapper, `on${type}`, {\n get: () => handlers[type],\n set: (fn: Handler) => {\n handlers[type] = fn;\n },\n configurable: true,\n enumerable: true,\n });\n }\n\n Object.defineProperties(wrapper, {\n readyState: {\n get: () => (inner ? inner.readyState : OriginalWebSocket.CLOSED),\n configurable: true,\n },\n url: {\n get: () => url,\n configurable: true,\n },\n protocol: {\n get: () => (inner ? inner.protocol : \"\"),\n configurable: true,\n },\n extensions: {\n get: () => (inner ? inner.extensions : \"\"),\n configurable: true,\n },\n bufferedAmount: {\n get: () => (inner ? inner.bufferedAmount : 0),\n configurable: true,\n },\n binaryType: {\n get: () => (inner ? inner.binaryType : \"blob\"),\n set: (val: BinaryType) => {\n if (inner) inner.binaryType = val;\n },\n configurable: true,\n },\n });\n\n wrapper.send = (data: any) => {\n // Capture HMR protocol messages needed for reconnection\n if (typeof data === \"string\") {\n try {\n const parsed = JSON.parse(data);\n if (\n parsed.type === \"register-entrypoints\" ||\n parsed.type === \"log-opt-in\"\n ) {\n // Update: keep latest version of each message type\n const idx = registrationMessages.findIndex((m) => {\n try {\n return JSON.parse(m).type === parsed.type;\n } catch {\n return false;\n }\n });\n if (idx >= 0) {\n registrationMessages[idx] = data;\n } else {\n registrationMessages.push(data);\n }\n console.log(\n `[expo-air:hmr] Captured ${parsed.type} message for reconnection replay`\n );\n }\n } catch {\n // Not JSON, ignore\n }\n }\n if (inner && inner.readyState === OriginalWebSocket.OPEN) {\n inner.send(data);\n }\n };\n\n wrapper.close = (code?: number, reason?: string) => {\n intentionalClose = true;\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n if (inner) inner.close(code, reason);\n };\n\n wrapper.addEventListener = (\n type: string,\n listener: Function,\n _options?: any\n ) => {\n const set = eventListeners[type];\n if (set) set.add(listener);\n };\n\n wrapper.removeEventListener = (type: string, listener: Function) => {\n const set = eventListeners[type];\n if (set) set.delete(listener);\n };\n\n wrapper.dispatchEvent = () => false;\n\n connect();\n return wrapper;\n } as any;\n\n // Copy static constants\n (globalThis.WebSocket as any).CONNECTING = OriginalWebSocket.CONNECTING;\n (globalThis.WebSocket as any).OPEN = OriginalWebSocket.OPEN;\n (globalThis.WebSocket as any).CLOSING = OriginalWebSocket.CLOSING;\n (globalThis.WebSocket as any).CLOSED = OriginalWebSocket.CLOSED;\n\n // Log final initialization state\n console.log(\"[expo-air:hmr] Module initialized\", {\n serverHttpUrl: serverHttpUrl ? \"set\" : \"NOT SET\",\n webSocketPatched: true,\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../commands/dev.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../commands/dev.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0HnE"}
|
package/cli/dist/commands/dev.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
-
import { spawn } from "child_process";
|
|
2
|
+
import { spawn, execSync } from "child_process";
|
|
3
|
+
import { existsSync, unlinkSync } from "fs";
|
|
4
|
+
import { join } from "path";
|
|
3
5
|
import { DevEnvironment } from "../runner/devEnvironment.js";
|
|
4
|
-
import { writeLocalConfig, updateInfoPlist } from "../utils/common.js";
|
|
6
|
+
import { writeLocalConfig, updateInfoPlist, getPackageRoot } from "../utils/common.js";
|
|
5
7
|
export async function devCommand(options) {
|
|
6
8
|
console.log(chalk.blue("\n 🛠 expo-air dev\n"));
|
|
7
9
|
console.log(chalk.gray(" Starting SDK development environment (simulator)...\n"));
|
|
@@ -20,6 +22,34 @@ export async function devCommand(options) {
|
|
|
20
22
|
await env.allocatePorts();
|
|
21
23
|
// Resolve project directory
|
|
22
24
|
env.resolveProject({ exitOnError: true });
|
|
25
|
+
// Remove prebuilt widget bundle so Metro is used for development
|
|
26
|
+
const packageRoot = getPackageRoot();
|
|
27
|
+
const prebuiltBundle = join(packageRoot, "ios", "widget.jsbundle");
|
|
28
|
+
if (existsSync(prebuiltBundle)) {
|
|
29
|
+
unlinkSync(prebuiltBundle);
|
|
30
|
+
console.log(chalk.green(" ✓ Removed prebuilt widget bundle (will use Metro)"));
|
|
31
|
+
}
|
|
32
|
+
// Check if Pods still reference the deleted bundle and need a refresh
|
|
33
|
+
const iosDir = join(env.getProjectRoot(), "ios");
|
|
34
|
+
const podsDir = join(iosDir, "Pods");
|
|
35
|
+
if (existsSync(podsDir)) {
|
|
36
|
+
try {
|
|
37
|
+
execSync("grep -rq 'widget\\.jsbundle' Pods/", {
|
|
38
|
+
cwd: iosDir,
|
|
39
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
40
|
+
});
|
|
41
|
+
// grep succeeded = stale reference exists, run pod install
|
|
42
|
+
console.log(chalk.blue(" ⟳ Refreshing pods (stale bundle reference)..."));
|
|
43
|
+
execSync("pod install", {
|
|
44
|
+
cwd: iosDir,
|
|
45
|
+
stdio: "inherit",
|
|
46
|
+
});
|
|
47
|
+
console.log(chalk.green(" ✓ Pods refreshed"));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// grep failed = no stale references, no pod install needed
|
|
51
|
+
}
|
|
52
|
+
}
|
|
23
53
|
// Start Metro servers (widget + app)
|
|
24
54
|
await env.startMetroServers();
|
|
25
55
|
// Start prompt server (with watch mode)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../commands/dev.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AASvF,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAmB;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC,CAAC;IAEnF,MAAM,GAAG,GAAG,IAAI,cAAc,CAAC;QAC7B,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAChC,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;QAC7E,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;QAC1E,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,IAAI;QACZ,cAAc,EAAE,IAAI;QACpB,YAAY,EAAE,KAAK;QACnB,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAEH,iBAAiB;IACjB,MAAM,GAAG,CAAC,aAAa,EAAE,CAAC;IAE1B,4BAA4B;IAC5B,GAAG,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,iEAAiE;IACjE,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;IACrC,MAAM,cAAc,GAAG,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;IACnE,IAAI,UAAU,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/B,UAAU,CAAC,cAAc,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qDAAqD,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,sEAAsE;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,QAAQ,CAAC,oCAAoC,EAAE;gBAC7C,GAAG,EAAE,MAAM;gBACX,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAChC,CAAC,CAAC;YACH,2DAA2D;YAC3D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;YAC3E,QAAQ,CAAC,aAAa,EAAE;gBACtB,GAAG,EAAE,MAAM;gBACX,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,2DAA2D;QAC7D,CAAC;IACH,CAAC;IAED,qCAAqC;IACrC,MAAM,GAAG,CAAC,iBAAiB,EAAE,CAAC;IAE9B,wCAAwC;IACxC,MAAM,GAAG,CAAC,iBAAiB,EAAE,CAAC;IAE9B,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B,MAAM,WAAW,GAAG,GAAG,CAAC,cAAc,EAAE,CAAC;IAEzC,oFAAoF;IACpF,MAAM,WAAW,GAA2B;QAC1C,SAAS,EAAE,kBAAkB,KAAK,CAAC,YAAY,EAAE;KAClD,CAAC;IACF,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACtB,WAAW,CAAC,cAAc,GAAG,oBAAoB,KAAK,CAAC,WAAW,EAAE,CAAC;IACvE,CAAC;IACD,WAAW,CAAC,WAAW,GAAG,oBAAoB,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC/D,gBAAgB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACjF,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,2CAA2C,CAAC,CAAC,CAAC;IACxE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC,CAAC;IACtF,CAAC;IAED,iCAAiC;IAEjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC,CAAC;IAC7E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC,CAAC;IAC9D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC,CAAC;IAE7E,MAAM,YAAY,GAAG,KAAK,CACxB,KAAK,EACL,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EACrD;QACE,GAAG,EAAE,WAAW;QAChB,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE;YACH,GAAI,OAAO,CAAC,GAA8B;YAC1C,WAAW,EAAE,GAAG;SACjB;KACF,CACF,CAAC;IAEF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YAChC,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACZ,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC,CAAC;YAChE,CAAC;QACH,CAAC,CAAC,CAAC;QACH,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,kBAAkB;IAClB,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IAE7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IACtC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,+BAA+B,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;IAC9E,IAAI,KAAK,CAAC,aAAa,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iCAAiC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iCAAiC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC5E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,+CAA+C,CAAC,CAAC,CAAC;IAE3E,2BAA2B;IAC3B,GAAG,CAAC,qBAAqB,CAAC,kCAAkC,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare class PromptServer {
|
|
2
2
|
private wss;
|
|
3
|
+
private httpServer;
|
|
3
4
|
private port;
|
|
4
5
|
private clients;
|
|
5
6
|
private currentQuery;
|
|
@@ -19,7 +20,14 @@ export declare class PromptServer {
|
|
|
19
20
|
private startGitWatcher;
|
|
20
21
|
private stopGitWatcher;
|
|
21
22
|
private getPRStatus;
|
|
23
|
+
private getRecentBranches;
|
|
24
|
+
private handleListBranches;
|
|
25
|
+
private isValidBranchName;
|
|
26
|
+
private handleSwitchBranch;
|
|
27
|
+
private handleCreateBranch;
|
|
22
28
|
private broadcastGitStatus;
|
|
29
|
+
private getGitRoot;
|
|
30
|
+
private retriggerHMR;
|
|
23
31
|
private getConfigPath;
|
|
24
32
|
private loadSession;
|
|
25
33
|
private saveSession;
|
|
@@ -36,6 +44,9 @@ export declare class PromptServer {
|
|
|
36
44
|
private isStopMessage;
|
|
37
45
|
private isDiscardChangesMessage;
|
|
38
46
|
private isRegisterPushTokenMessage;
|
|
47
|
+
private isListBranchesMessage;
|
|
48
|
+
private isSwitchBranchMessage;
|
|
49
|
+
private isCreateBranchMessage;
|
|
39
50
|
private executeWithSDK;
|
|
40
51
|
private sendToClient;
|
|
41
52
|
private sendToolUpdate;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptServer.d.ts","sourceRoot":"","sources":["../../server/promptServer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"promptServer.d.ts","sourceRoot":"","sources":["../../server/promptServer.ts"],"names":[],"mappings":"AAyBA,qBAAa,YAAY;IACvB,OAAO,CAAC,GAAG,CAAgC;IAC3C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,YAAY,CAAyC;IAC7D,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,mBAAmB,CAA8B;IACzD,OAAO,CAAC,gBAAgB,CAA+C;IACvE,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,uBAAuB,CAAc;IAC7C,OAAO,CAAC,aAAa,CAAsB;gBAE/B,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM;IAM9C,OAAO,CAAC,aAAa;IAYrB,OAAO,CAAC,aAAa;IAmCrB,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,iBAAiB;IA6DzB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,kBAAkB;IA0F1B,OAAO,CAAC,kBAAkB;IAgG1B,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,YAAY;IA4BpB,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,oBAAoB;IActB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+CtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAiC3B,OAAO,CAAC,gBAAgB;IA0DxB,OAAO,CAAC,aAAa;IAmErB,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,oBAAoB;IAkC5B,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,uBAAuB;IAS/B,OAAO,CAAC,0BAA0B;IAWlC,OAAO,CAAC,qBAAqB;IAS7B,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,qBAAqB;YAWf,cAAc;IAgP5B,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,cAAc;IAgCtB,OAAO,CAAC,iBAAiB;YAaX,oBAAoB;IA2BlC,OAAO,CAAC,GAAG;CAyBZ"}
|