@unbound-app/debugger-protocol 2.0.1 → 2.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.
@@ -0,0 +1,768 @@
1
+ import { PushedManifest } from "@unbound-app/types";
2
+ /**
3
+ * The object explorer's frames: a controller asks the device for a native object's class chain, one page of one kind
4
+ * of a class's members, the values of the members on screen, and (iOS) the loaded images and their classes.
5
+ */
6
+ /** The most members a device returns for one {@link ExplorerMembersRequest}. */
7
+ declare const EXPLORER_MEMBERS_PAGE_SIZE = 100;
8
+ /** The most images or class names a device returns for one {@link ExplorerClassesRequest}. */
9
+ declare const EXPLORER_CLASSES_PAGE_SIZE = 200;
10
+ /** The most member values one {@link ExplorerValuesRequest} may name. */
11
+ declare const EXPLORER_VALUES_LIMIT = 50;
12
+ /** A kind of class member: the first five are Objective-C's, `fields` to `interfaces` Java's, `methods` both. */
13
+ type ExplorerMemberKind = 'properties' | 'ivars' | 'methods' | 'classMethods' | 'protocols' | 'fields' | 'constructors' | 'interfaces';
14
+ /** What to explore: a listed view, an object the explorer handed out a ref for, or a class by name. */
15
+ type ExplorerTarget = {
16
+ node: string;
17
+ } | {
18
+ object: string;
19
+ } | {
20
+ className: string;
21
+ };
22
+ /** One class of an object's chain, with how many members of each kind it declares itself. */
23
+ type ExplorerClass = {
24
+ name: string;
25
+ /** The binary image that defines the class, or `null` when unknown, as on Android. */
26
+ image: string | null;
27
+ /** The size of an instance in bytes, or `null` when unknown. */
28
+ instanceSize: number | null;
29
+ counts: Partial<Record<ExplorerMemberKind, number>>;
30
+ };
31
+ /** One member a class declares. */
32
+ type ExplorerMember = {
33
+ name: string;
34
+ kind: ExplorerMemberKind;
35
+ /** The decoded type of a property, ivar or field, or a method's return type. */
36
+ type: string | null;
37
+ /** A declaration to show, such as `- (void)setFoo:(id)foo`. */
38
+ signature: string | null;
39
+ returnType?: string;
40
+ parameters?: string[];
41
+ /** Property attributes such as `nonatomic`, `strong` or `readonly`. */
42
+ attributes?: string[];
43
+ static?: boolean;
44
+ offset?: number;
45
+ size?: number;
46
+ image?: string | null;
47
+ /** Whether a value read is automatic and safe, runs code so needs a click, or is never made. */
48
+ read: 'auto' | 'manual' | 'never';
49
+ };
50
+ /** How a member's value reads: a value kind, `skipped` when unsafe to read, or `error`. */
51
+ type ExplorerValueKind = 'nil' | 'number' | 'bool' | 'string' | 'object' | 'class' | 'struct' | 'pointer' | 'selector' | 'other' | 'skipped' | 'error';
52
+ /** One member's value, read on the device. */
53
+ type ExplorerValue = {
54
+ name: string;
55
+ kind: ExplorerValueKind;
56
+ text: string;
57
+ /** The ref to open an object value with, as an `{ object }` target. */
58
+ object?: string;
59
+ className?: string;
60
+ };
61
+ /** A native object, or a class alone when `ref` is `null`. */
62
+ type ExplorerObject = {
63
+ /** The device's ref for the object, `<epoch>:<n>`, valid until the debugger reconnects or JavaScript reloads. */
64
+ ref: string | null;
65
+ className: string;
66
+ description: string | null;
67
+ platform: 'ios' | 'android';
68
+ /** The class, then each superclass up to the root. */
69
+ chain: ExplorerClass[];
70
+ };
71
+ /** Why an explorer request failed, so the controller can fall back or explain. */
72
+ type ExplorerErrorCode =
73
+ /** The ref or node is gone, such as after a JavaScript reload. */
74
+ 'stale' |
75
+ /** Developer mode and the debugger are both off. */
76
+ 'disabled' |
77
+ /** The inspector failed to load. */
78
+ 'unavailable' |
79
+ /** The loader or platform cannot answer this request. */
80
+ 'unsupported' | 'unknown-class' | 'failed';
81
+ /** A failed explorer answer. */
82
+ type ExplorerError = {
83
+ ok: false;
84
+ error: string;
85
+ code: ExplorerErrorCode;
86
+ };
87
+ /** A loaded binary image that defines Objective-C classes. */
88
+ type ExplorerImage = {
89
+ path: string;
90
+ name: string;
91
+ classCount: number;
92
+ };
93
+ /** Controller → bridge → device: read an object's class chain. */
94
+ type ExplorerObjectRequest = {
95
+ type: 'explorer-object-request';
96
+ /** Correlation id echoed back on the matching {@link ExplorerObjectResult}. */
97
+ id: string;
98
+ target: ExplorerTarget;
99
+ };
100
+ /** The answer to an {@link ExplorerObjectRequest}. */
101
+ type ExplorerObjectResult = {
102
+ type: 'explorer-object-result';
103
+ id: string;
104
+ } & ({
105
+ ok: true;
106
+ object: ExplorerObject;
107
+ } | ExplorerError);
108
+ /** Controller → bridge → device: list one page of one kind of the members a class declares. */
109
+ type ExplorerMembersRequest = {
110
+ type: 'explorer-members-request';
111
+ id: string;
112
+ className: string;
113
+ kind: ExplorerMemberKind;
114
+ offset?: number;
115
+ /** At most {@link EXPLORER_MEMBERS_PAGE_SIZE}, which is also the default. */
116
+ limit?: number;
117
+ /** A case-insensitive substring of the member names to keep. */
118
+ filter?: string;
119
+ };
120
+ /** The answer to an {@link ExplorerMembersRequest}. */
121
+ type ExplorerMembersResult = {
122
+ type: 'explorer-members-result';
123
+ id: string;
124
+ } & ({
125
+ ok: true;
126
+ members: ExplorerMember[];
127
+ total: number;
128
+ } | ExplorerError);
129
+ /** Controller → bridge → device: read the named members of `className` on an object. */
130
+ type ExplorerValuesRequest = {
131
+ type: 'explorer-values-request';
132
+ id: string;
133
+ /** The object's ref. */
134
+ object: string;
135
+ className: string;
136
+ kind: ExplorerMemberKind;
137
+ /** At most {@link EXPLORER_VALUES_LIMIT} names. */
138
+ names: string[];
139
+ /** Runs the getters of computed properties too. */
140
+ invokeGetters?: boolean;
141
+ };
142
+ /** The answer to an {@link ExplorerValuesRequest}. */
143
+ type ExplorerValuesResult = {
144
+ type: 'explorer-values-result';
145
+ id: string;
146
+ } & ({
147
+ ok: true;
148
+ values: ExplorerValue[];
149
+ } | ExplorerError);
150
+ /** Controller → bridge → device: list a page of the loaded images, or of one image's class names. */
151
+ type ExplorerClassesRequest = {
152
+ type: 'explorer-classes-request';
153
+ id: string;
154
+ /** The image path whose classes to list; the images themselves when omitted. */
155
+ image?: string;
156
+ filter?: string;
157
+ offset?: number;
158
+ /** At most {@link EXPLORER_CLASSES_PAGE_SIZE}, which is also the default. */
159
+ limit?: number;
160
+ };
161
+ /** The answer to an {@link ExplorerClassesRequest}: `images` without an image, `classes` with one. */
162
+ type ExplorerClassesResult = {
163
+ type: 'explorer-classes-result';
164
+ id: string;
165
+ } & ({
166
+ ok: true;
167
+ total: number;
168
+ images?: ExplorerImage[];
169
+ classes?: string[];
170
+ } | ExplorerError);
171
+ type ExplorerRequest = ExplorerObjectRequest | ExplorerMembersRequest | ExplorerValuesRequest | ExplorerClassesRequest;
172
+ type ExplorerResult = ExplorerObjectResult | ExplorerMembersResult | ExplorerValuesResult | ExplorerClassesResult;
173
+ /** The result frame type answering each request frame type. */
174
+ declare const EXPLORER_RESULT_TYPES: {
175
+ readonly 'explorer-object-request': 'explorer-object-result';
176
+ readonly 'explorer-members-request': 'explorer-members-result';
177
+ readonly 'explorer-values-request': 'explorer-values-result';
178
+ readonly 'explorer-classes-request': 'explorer-classes-result';
179
+ };
180
+ /** A frame narrowed to its type, before its other fields are checked. */
181
+ type TypedFrame$1 = {
182
+ type: string;
183
+ };
184
+ /**
185
+ * @description Builds the failed answer to an explorer request.
186
+ * @param request The request, or its type and id.
187
+ * @param error What failed.
188
+ * @param code Why it failed.
189
+ * @returns The result frame.
190
+ */
191
+ declare function failExplorerRequest(request: Pick<ExplorerRequest, 'type' | 'id'>, error: string, code: ExplorerErrorCode): ExplorerResult;
192
+ /**
193
+ * @description Checks whether a frame is an explorer request, by its type alone.
194
+ * @param frame A parsed frame.
195
+ * @returns Whether it is one.
196
+ */
197
+ declare function isExplorerRequest(frame: TypedFrame$1): frame is ExplorerRequest;
198
+ /**
199
+ * @description Checks whether a frame is an explorer result, by its type alone.
200
+ * @param frame A parsed frame.
201
+ * @returns Whether it is one.
202
+ */
203
+ declare function isExplorerResult(frame: TypedFrame$1): frame is ExplorerResult;
204
+ /**
205
+ * The Metro explorer's frames: list, load and search modules, and walk a loaded module's exports as a tree. Long
206
+ * work runs in short device-side batches the controller repeats; getters run only when asked.
207
+ */
208
+ /** The most modules a device returns for one {@link MetroModulesRequest}. */
209
+ declare const METRO_MODULES_PAGE_SIZE = 200;
210
+ /** The most properties a device returns for one {@link MetroChildrenRequest}. */
211
+ declare const METRO_CHILDREN_PAGE_SIZE = 100;
212
+ /** The most matches a device collects for one {@link MetroSearchRequest} before it stops at a module's end. */
213
+ declare const METRO_SEARCH_PAGE_SIZE = 50;
214
+ /** Whether a module's factory has run: `failed` when it threw, or searches skip it before it ran. */
215
+ type MetroModuleStatus = 'loaded' | 'unloaded' | 'failed';
216
+ /** One Metro module. */
217
+ type MetroModule = {
218
+ id: number;
219
+ status: MetroModuleStatus;
220
+ /** A loaded module's file path, else its first export names; `null` before it loads or when it exports none. */
221
+ label: string | null;
222
+ };
223
+ /** What a value is, which picks its colour; `getter` is an accessor that has not run. */
224
+ type MetroValueKind = 'string' | 'number' | 'boolean' | 'nullish' | 'symbol' | 'function' | 'class' | 'array' | 'object' | 'error' | 'getter';
225
+ /** One value in the tree: a module's exports, a property, or a slot such as `[[Prototype]]`. */
226
+ type MetroValue = {
227
+ key: string;
228
+ kind: MetroValueKind;
229
+ text: string;
230
+ /**
231
+ * The ref that lists the value's children, or that runs a getter. The same object always has the same ref, so a
232
+ * controller can tell a value that is already open above itself.
233
+ */
234
+ ref?: string;
235
+ /** An engine slot such as `[[Prototype]]` or `[[Entries]]` rather than a property. */
236
+ internal?: boolean;
237
+ };
238
+ /** What to list the children of: a loaded module's exports, or a value the device handed out a ref for. */
239
+ type MetroTarget = {
240
+ module: number;
241
+ } | {
242
+ ref: string;
243
+ };
244
+ /** Why a Metro request failed. */
245
+ type MetroErrorCode =
246
+ /** The ref is gone, such as after a JavaScript reload. */
247
+ 'stale' | 'unknown-module' |
248
+ /** The module has not loaded, so it has no exports to list. */
249
+ 'unloaded' | 'failed';
250
+ /** A failed Metro answer. */
251
+ type MetroError = {
252
+ ok: false;
253
+ error: string;
254
+ code: MetroErrorCode;
255
+ };
256
+ /** Controller → bridge → device: list a page of the modules matching a filter and a status. */
257
+ type MetroModulesRequest = {
258
+ type: 'metro-modules-request';
259
+ /** Correlation id echoed back on the matching {@link MetroModulesResult}. */
260
+ id: string;
261
+ /** A case-insensitive id prefix or substring of a module's label. */
262
+ filter?: string;
263
+ /** The status to keep; every module when omitted. */
264
+ status?: MetroModuleStatus;
265
+ offset?: number;
266
+ /** At most {@link METRO_MODULES_PAGE_SIZE}, which is also the default. */
267
+ limit?: number;
268
+ };
269
+ /** The answer to a {@link MetroModulesRequest}. */
270
+ type MetroModulesResult = {
271
+ type: 'metro-modules-result';
272
+ id: string;
273
+ } & ({
274
+ ok: true;
275
+ modules: MetroModule[];
276
+ /** How many modules match. */
277
+ total: number;
278
+ /** How many modules have loaded, of `count`. */
279
+ loaded: number;
280
+ /** How many modules the registry holds. */
281
+ count: number;
282
+ } | MetroError);
283
+ /** Controller → bridge → device: run a module's factory, and those of the modules it requires. */
284
+ type MetroLoadRequest = {
285
+ type: 'metro-load-request';
286
+ id: string;
287
+ module: number;
288
+ };
289
+ /** The answer to a {@link MetroLoadRequest}: the module afterwards, `failed` when its factory threw. */
290
+ type MetroLoadResult = {
291
+ type: 'metro-load-result';
292
+ id: string;
293
+ } & ({
294
+ ok: true;
295
+ module: MetroModule;
296
+ loaded: number;
297
+ } | MetroError);
298
+ /**
299
+ * Controller → bridge → device: load the next batch of modules that have not loaded, skipping the blacklist of
300
+ * modules that threw or export something invalid. The controller repeats it until `remaining` is 0.
301
+ */
302
+ type MetroLoadAllRequest = {
303
+ type: 'metro-load-all-request';
304
+ id: string;
305
+ };
306
+ /** The answer to a {@link MetroLoadAllRequest}: what the batch did and what is left. */
307
+ type MetroLoadAllResult = {
308
+ type: 'metro-load-all-result';
309
+ id: string;
310
+ } & ({
311
+ ok: true;
312
+ /** How many modules this batch ran. */
313
+ attempted: number;
314
+ /** How many of those threw, and joined the blacklist. */
315
+ failed: number;
316
+ /** How many modules are still to run; 0 when Load All is done. */
317
+ remaining: number;
318
+ loaded: number;
319
+ count: number;
320
+ } | MetroError);
321
+ /** One key a search matched: the module, the keys from its exports down to it, and its value. */
322
+ type MetroMatch = {
323
+ module: MetroModule;
324
+ /** Property keys, or `[[Prototype]]`, from the exports; empty when the exports themselves match. */
325
+ path: string[];
326
+ value: MetroValue;
327
+ };
328
+ /**
329
+ * Controller → bridge → device: find keys containing `query` under the loaded modules' exports and prototypes,
330
+ * without running getters, for one batch; the answer's `cursor` continues it.
331
+ */
332
+ type MetroSearchRequest = {
333
+ type: 'metro-search-request';
334
+ id: string;
335
+ /** Case-insensitive text a key or function name contains. */
336
+ query: string;
337
+ /** The loaded module to start from, as an index; the previous answer's `cursor`. */
338
+ cursor?: number;
339
+ /** At most {@link METRO_SEARCH_PAGE_SIZE}, which is also the default. */
340
+ limit?: number;
341
+ };
342
+ /** The answer to a {@link MetroSearchRequest}. */
343
+ type MetroSearchResult = {
344
+ type: 'metro-search-result';
345
+ id: string;
346
+ } & ({
347
+ ok: true;
348
+ matches: MetroMatch[];
349
+ /** Where the next request continues, or `null` once every loaded module is searched. */
350
+ cursor: number | null;
351
+ /** How many loaded modules are searched so far, of `total`. */
352
+ searched: number;
353
+ total: number;
354
+ } | MetroError);
355
+ /** A loaded module that reported the source file it was built from. */
356
+ type MetroFile = {
357
+ id: number;
358
+ /** The path Discord's import tracker reported, such as `modules/user_profile/native/UserProfileStore.tsx`. */
359
+ path: string;
360
+ };
361
+ /**
362
+ * Controller → bridge → device: list every loaded module's file path, for a file tree. A module reports its path
363
+ * only as it loads, so the tree is complete once every module has loaded.
364
+ */
365
+ type MetroFilesRequest = {
366
+ type: 'metro-files-request';
367
+ id: string;
368
+ };
369
+ /** The answer to a {@link MetroFilesRequest}, sorted by path. */
370
+ type MetroFilesResult = {
371
+ type: 'metro-files-result';
372
+ id: string;
373
+ } & ({
374
+ ok: true;
375
+ files: MetroFile[];
376
+ /** How many modules have not loaded, whose paths are not known yet. */
377
+ unloaded: number;
378
+ count: number;
379
+ } | MetroError);
380
+ /** Controller → bridge → device: describe a value and list a page of its children. */
381
+ type MetroChildrenRequest = {
382
+ type: 'metro-children-request';
383
+ id: string;
384
+ target: MetroTarget;
385
+ offset?: number;
386
+ /** At most {@link METRO_CHILDREN_PAGE_SIZE}, which is also the default. */
387
+ limit?: number;
388
+ };
389
+ /** The answer to a {@link MetroChildrenRequest}. */
390
+ type MetroChildrenResult = {
391
+ type: 'metro-children-result';
392
+ id: string;
393
+ } & ({
394
+ ok: true;
395
+ /** The target itself. */
396
+ value: MetroValue;
397
+ /** A page of its own properties. */
398
+ children: MetroValue[];
399
+ /** How many own properties it has. */
400
+ total: number;
401
+ /** Its slots, listed after the properties: `[[Entries]]`, `[[Prototype]]`. */
402
+ internal: MetroValue[];
403
+ } | MetroError);
404
+ /** Controller → bridge → device: run the getter a `getter` value's ref stands for. */
405
+ type MetroReadRequest = {
406
+ type: 'metro-read-request';
407
+ id: string;
408
+ ref: string;
409
+ };
410
+ /** The answer to a {@link MetroReadRequest}: the getter's result, or an `error` value for what it threw. */
411
+ type MetroReadResult = {
412
+ type: 'metro-read-result';
413
+ id: string;
414
+ } & ({
415
+ ok: true;
416
+ value: MetroValue;
417
+ } | MetroError);
418
+ type MetroRequest = MetroModulesRequest | MetroLoadRequest | MetroLoadAllRequest | MetroSearchRequest | MetroFilesRequest | MetroChildrenRequest | MetroReadRequest;
419
+ type MetroResult = MetroModulesResult | MetroLoadResult | MetroLoadAllResult | MetroSearchResult | MetroFilesResult | MetroChildrenResult | MetroReadResult;
420
+ /** The result frame type answering each request frame type. */
421
+ declare const METRO_RESULT_TYPES: {
422
+ readonly 'metro-modules-request': 'metro-modules-result';
423
+ readonly 'metro-load-request': 'metro-load-result';
424
+ readonly 'metro-load-all-request': 'metro-load-all-result';
425
+ readonly 'metro-search-request': 'metro-search-result';
426
+ readonly 'metro-files-request': 'metro-files-result';
427
+ readonly 'metro-children-request': 'metro-children-result';
428
+ readonly 'metro-read-request': 'metro-read-result';
429
+ };
430
+ /** A frame narrowed to its type, before its other fields are checked. */
431
+ type TypedFrame = {
432
+ type: string;
433
+ };
434
+ /**
435
+ * @description Builds the failed answer to a Metro request.
436
+ * @param request The request, or its type and id.
437
+ * @param error What failed.
438
+ * @param code Why it failed.
439
+ * @returns The result frame.
440
+ */
441
+ declare function failMetroRequest(request: Pick<MetroRequest, 'type' | 'id'>, error: string, code: MetroErrorCode): MetroResult;
442
+ /**
443
+ * @description Checks whether a frame is a Metro request, by its type alone.
444
+ * @param frame A parsed frame.
445
+ * @returns Whether it is one.
446
+ */
447
+ declare function isMetroRequest(frame: TypedFrame): frame is MetroRequest;
448
+ /**
449
+ * @description Checks whether a frame is a Metro result, by its type alone.
450
+ * @param frame A parsed frame.
451
+ * @returns Whether it is one.
452
+ */
453
+ declare function isMetroResult(frame: TypedFrame): frame is MetroResult;
454
+ /**
455
+ * The view finder's frames: a controller asks the device for one page of one level of its native view
456
+ * tree at a time, for one view's properties when it selects it, and names the view to outline on screen.
457
+ */
458
+ /** The most views a device returns for one {@link ViewsRequest}; a longer level is read in pages. */
459
+ declare const VIEWS_PAGE_SIZE = 100;
460
+ /** A rectangle in screen coordinates, in dp on Android and points on iOS. */
461
+ type ViewFrame = {
462
+ x: number;
463
+ y: number;
464
+ width: number;
465
+ height: number;
466
+ };
467
+ /** One native view, with only its top-level properties. */
468
+ type ViewNode = {
469
+ /** The device's id for the view, valid until the next request for the roots. */
470
+ id: string;
471
+ /** The fully qualified Java class name, or the Objective-C class name. */
472
+ className: string;
473
+ /** The Android resource entry name of the view's id, or the iOS accessibility identifier. */
474
+ resourceName: string | null;
475
+ frame: ViewFrame;
476
+ visibility: 'visible' | 'invisible' | 'gone';
477
+ /** The view's opacity from 0 to 1, or `null` when the platform did not report it. */
478
+ alpha: number | null;
479
+ /** The text a text view shows, cut to a few hundred characters. */
480
+ text: string | null;
481
+ /** How many direct children the view has. */
482
+ childCount: number;
483
+ };
484
+ /**
485
+ * Controller → bridge → device: list a page of the children of `parent`, or the root views when it is
486
+ * omitted. Listing the roots renews every id.
487
+ */
488
+ type ViewsRequest = {
489
+ type: 'views-request';
490
+ /** Correlation id echoed back on the matching {@link ViewsResult}. */
491
+ id: string;
492
+ parent?: string;
493
+ /** The index of the first child to list. Defaults to 0. */
494
+ offset?: number;
495
+ /** How many children to list, at most {@link VIEWS_PAGE_SIZE}, which is also the default. */
496
+ limit?: number;
497
+ };
498
+ /** The answer to a {@link ViewsRequest}, sent device → bridge → the controller that asked. */
499
+ type ViewsResult = {
500
+ type: 'views-result';
501
+ /** The `id` of the {@link ViewsRequest} this answers. */
502
+ id: string;
503
+ } & ({
504
+ ok: true;
505
+ nodes: ViewNode[];
506
+ /** How many children the parent has in all; more pages follow while it exceeds `offset + nodes.length`. */
507
+ total?: number;
508
+ } | {
509
+ ok: false;
510
+ error: string;
511
+ });
512
+ /** A property value: text, a number, a flag or nothing. A `color` is `#RRGGBBAA`. */
513
+ type ViewPropertyValue = string | number | boolean | null;
514
+ /** One property of a native view, read when the controller selects it. */
515
+ type ViewProperty = {
516
+ key: string;
517
+ value: ViewPropertyValue;
518
+ /** Draws the value as a colour swatch when `color`. */
519
+ kind?: 'color';
520
+ /** The unit a number is in, such as `dp`, `pt` or `px`. */
521
+ unit?: string;
522
+ };
523
+ /** A titled group of properties, such as Layout or Accessibility. */
524
+ type ViewSection = {
525
+ title: string;
526
+ properties: ViewProperty[];
527
+ };
528
+ /** What a device reads about one view beyond its {@link ViewNode}, for patching it with the native bridge. */
529
+ type ViewDetails = {
530
+ /** The view's class, then each superclass up to the platform's root view class. */
531
+ classChain: string[];
532
+ sections: ViewSection[];
533
+ };
534
+ /** Controller → bridge → device: read the properties of the listed view `node`. */
535
+ type ViewDetailsRequest = {
536
+ type: 'view-details-request';
537
+ /** Correlation id echoed back on the matching {@link ViewDetailsResult}. */
538
+ id: string;
539
+ node: string;
540
+ };
541
+ /** The answer to a {@link ViewDetailsRequest}, sent device → bridge → the controller that asked. */
542
+ type ViewDetailsResult = {
543
+ type: 'view-details-result';
544
+ /** The `id` of the {@link ViewDetailsRequest} this answers. */
545
+ id: string;
546
+ } & ({
547
+ ok: true;
548
+ details: ViewDetails;
549
+ } | {
550
+ ok: false;
551
+ error: string;
552
+ });
553
+ /** Controller → bridge → device: outline the view with this id on screen, or clear the outline when `null`. */
554
+ type ViewHighlight = {
555
+ type: 'view-highlight';
556
+ node: string | null;
557
+ };
558
+ /**
559
+ * React DevTools over the debugger socket: the device's backend and the frontend (the DevTools app's
560
+ * controller) swap React DevTools' own `{ event, payload }` messages, each wrapped in one frame.
561
+ */
562
+ /** Device ↔ bridge ↔ the frontend controller: one React DevTools message. */
563
+ type ReactDevtoolsFrame = {
564
+ type: 'react-devtools';
565
+ event: string;
566
+ payload?: unknown;
567
+ };
568
+ /** The payload of {@link REACT_DEVTOOLS_STATUS_EVENT}. */
569
+ type ReactDevtoolsStatus = {
570
+ connected: boolean;
571
+ /** Why the backend is unavailable, such as the loader not having run it. */
572
+ error?: string;
573
+ };
574
+ /**
575
+ * The event the device sends the frontend, with a {@link ReactDevtoolsStatus}, when its backend
576
+ * starts a session, cannot start one, or ends one.
577
+ */
578
+ declare const REACT_DEVTOOLS_STATUS_EVENT = "unbound:backend-status";
579
+ /** React DevTools' own event that ends a backend session; the bridge sends it when the frontend leaves. */
580
+ declare const REACT_DEVTOOLS_SHUTDOWN_EVENT = "shutdown";
581
+ /**
582
+ * The wire protocol shared by the bridge, the device and controllers: every frame is a JSON-encoded
583
+ * {@link BridgeMessage}. Dependency-free at runtime so the React Native client can bundle it.
584
+ */
585
+ /** A request to evaluate code on the device, sent controller → bridge → device. */
586
+ type EvalRequest = {
587
+ type: 'eval';
588
+ /** Correlation id echoed back on the matching {@link EvalResult}. */
589
+ id: string;
590
+ code: string;
591
+ timeout?: number;
592
+ };
593
+ /**
594
+ * Why a request failed before the device answered it, so callers branch on a code instead of the error text.
595
+ */
596
+ type RequestFailureCode =
597
+ /** The bridge has no device. */
598
+ 'no-device' |
599
+ /** The device dropped mid-request. */
600
+ 'device-disconnected' | 'timeout' |
601
+ /** The controller has no socket to the bridge. */
602
+ 'bridge-unreachable' |
603
+ /** The controller closed. */
604
+ 'shut-down';
605
+ /** The outcome of an {@link EvalRequest}, sent device → bridge → the one waiting controller. */
606
+ type EvalResult = {
607
+ type: 'eval-result';
608
+ /** The `id` of the {@link EvalRequest} this answers. */
609
+ id: string;
610
+ /**
611
+ * Console output captured during this eval, so callers see its side effects too. Populated by
612
+ * the controller that owns the request, not sent by the device.
613
+ */
614
+ logs?: LogMessage[];
615
+ } & ({
616
+ ok: true;
617
+ /** The inspected return value. */
618
+ value: string;
619
+ } | {
620
+ ok: false;
621
+ /** The inspected error. */
622
+ error: string;
623
+ /** Set when the bridge or controller failed the eval; absent when the code itself threw on the device. */
624
+ code?: RequestFailureCode;
625
+ });
626
+ /** The addon managers a push can reload into. */
627
+ type PushedAddonKind = 'plugin' | 'theme';
628
+ /**
629
+ * A request to hot-reload a plugin or theme on the device, sent controller → bridge → device. Carries
630
+ * the freshly built bundle and manifest so the device swaps them in without a re-fetch.
631
+ */
632
+ type PushRequest = {
633
+ type: 'plugin-push';
634
+ /** Correlation id echoed back on the matching {@link PushResult}. */
635
+ id: string;
636
+ addonId: string;
637
+ /** Which manager reloads the addon; a plugin when omitted, as pushes from older CLIs are. */
638
+ kind?: PushedAddonKind;
639
+ bundle: string;
640
+ /** The manifest as authored; the device validates it before swapping anything in. */
641
+ manifest: PushedManifest;
642
+ /** The bundle compiled to Hermes bytecode, base64-encoded, by bytecode version; its digests are in `manifest.bytecode`. */
643
+ bytecode?: Record<string, string>;
644
+ /** Each extra file the manifest lists beside the bundle, such as an image, base64-encoded, by path. */
645
+ files?: Record<string, string>;
646
+ };
647
+ /** The outcome of a {@link PushRequest}, sent device → bridge → the one waiting controller. */
648
+ type PushResult = {
649
+ type: 'plugin-push-result';
650
+ /** The `id` of the {@link PushRequest} this answers. */
651
+ id: string;
652
+ } & ({
653
+ ok: true;
654
+ } | {
655
+ ok: false;
656
+ /** The reload failure, inspected. */
657
+ error: string;
658
+ /** Set when the bridge or controller failed the push; absent when the device's reload failed. */
659
+ code?: RequestFailureCode;
660
+ });
661
+ /** A `console.*` / `nativeLoggingHook` line, streamed device → bridge → all controllers. */
662
+ type LogMessage = {
663
+ type: 'log';
664
+ /** 1 = log/gray, 2 = warn/yellow, 3 = error/red. */
665
+ level: 1 | 2 | 3;
666
+ message: string;
667
+ };
668
+ /** What a device reports about itself when it connects. */
669
+ type DeviceInfo = {
670
+ platform: string;
671
+ discordVersion: string;
672
+ loaderVersion: string;
673
+ clientVersion: string;
674
+ };
675
+ /** Device → bridge, once its socket opens, so the bridge can say which device is attached. */
676
+ type DeviceHello = {
677
+ type: 'hello';
678
+ device: DeviceInfo;
679
+ };
680
+ /** Bridge → controller, once on attach and whenever the device connects, drops or says hello. */
681
+ type DeviceStatus = {
682
+ type: 'device-status';
683
+ } & ({
684
+ connected: false;
685
+ } | {
686
+ connected: true;
687
+ /** Present once the connected device has said hello. */
688
+ device?: DeviceInfo;
689
+ });
690
+ /**
691
+ * Bridge → controller, once on attach, from a bridge that advertises itself over Bonjour: the
692
+ * pairing code its TXT record carries, and how to reach it by hand when discovery fails.
693
+ */
694
+ type BridgeInfo = {
695
+ type: 'bridge-info';
696
+ /** The four-digit pairing code, also the advertisement's `code`. */
697
+ code: string;
698
+ /** `ip:port` on the advertised network, for the Debugger Address setting. */
699
+ address?: string;
700
+ /** Whether devices on the network can find the bridge. */
701
+ advertising: boolean;
702
+ /** Why it isn't advertising. */
703
+ error?: string;
704
+ };
705
+ /** Every framed message on the wire. */
706
+ type BridgeMessage = EvalRequest | EvalResult | PushRequest | PushResult | LogMessage | DeviceHello | DeviceStatus | BridgeInfo | ViewsRequest | ViewsResult | ViewDetailsRequest | ViewDetailsResult | ViewHighlight | ExplorerRequest | ExplorerResult | MetroRequest | MetroResult | ReactDevtoolsFrame;
707
+ /** The default port the bridge listens on and controllers dial. */
708
+ declare const DEFAULT_BRIDGE_PORT = 9090;
709
+ declare const DEFAULT_EVAL_TIMEOUT_MS = 10000;
710
+ declare const MAX_EVAL_TIMEOUT_MS = 86400000;
711
+ /** How long the bridge waits for the device to reload a pushed addon. */
712
+ declare const PUSH_TIMEOUT_MS = 60000;
713
+ /**
714
+ * How much longer a controller waits than the bridge, so the bridge's own timeout reply always
715
+ * arrives before the controller gives up on its own.
716
+ */
717
+ declare const BRIDGE_REPLY_GRACE_MS = 5000;
718
+ /**
719
+ * @description Picks how long an eval may run: the requested timeout when it is a positive number of
720
+ * milliseconds, capped at {@link MAX_EVAL_TIMEOUT_MS}, otherwise {@link DEFAULT_EVAL_TIMEOUT_MS}.
721
+ * @param requested The timeout the controller asked for, if any.
722
+ * @returns The timeout to apply, in milliseconds.
723
+ */
724
+ declare function resolveEvalTimeout(requested: number | undefined): number;
725
+ /** The query marker a controller appends to its URL so the bridge routes it as a controller, not a device. */
726
+ declare const CONTROLLER_ENDPOINT_MARKER = "mcp";
727
+ /** The unlisted `ubd` command that runs the bridge in the foreground; tools that start one run it. */
728
+ declare const SERVE_BRIDGE_COMMAND = "serve-bridge";
729
+ /** The Bonjour service type a bridge advertises, so a device on the same network can find it. */
730
+ declare const BRIDGE_SERVICE_TYPE = "_unbound-bridge._tcp";
731
+ /** The `proto` TXT value of an advertised bridge; a device skips bridges that speak another one. */
732
+ declare const BRIDGE_SERVICE_PROTOCOL = "1";
733
+ /** What an advertised bridge's TXT record holds, beside its instance name, which names the computer. */
734
+ type BridgeAdvertisement = {
735
+ /** The protocol version, {@link BRIDGE_SERVICE_PROTOCOL}. */
736
+ proto: string;
737
+ /** The tool that started the bridge. */
738
+ by: 'devtools' | 'cli';
739
+ /** The four-digit pairing code the tool also shows, so the user can tell it is their computer. */
740
+ code: string;
741
+ };
742
+ /**
743
+ * @description Safely parses a raw wire frame into a {@link BridgeMessage}, guarding against invalid
744
+ * JSON and unknown shapes so both ends can trust what they route.
745
+ * @param raw The JSON string received off the socket.
746
+ * @returns The parsed message, or `undefined` if it isn't a recognised frame.
747
+ */
748
+ declare function parseMessage(raw: string): BridgeMessage | undefined;
749
+ /**
750
+ * @description Serialises a {@link BridgeMessage} into its wire form. Inverse of {@link parseMessage}.
751
+ * @param message The message to frame.
752
+ * @returns The JSON string to send over the socket.
753
+ */
754
+ declare function serializeMessage(message: BridgeMessage): string;
755
+ declare const _default: {
756
+ DEFAULT_BRIDGE_PORT: number;
757
+ DEFAULT_EVAL_TIMEOUT_MS: number;
758
+ MAX_EVAL_TIMEOUT_MS: number;
759
+ PUSH_TIMEOUT_MS: number;
760
+ BRIDGE_REPLY_GRACE_MS: number;
761
+ CONTROLLER_ENDPOINT_MARKER: string;
762
+ REACT_DEVTOOLS_SHUTDOWN_EVENT: string;
763
+ REACT_DEVTOOLS_STATUS_EVENT: string;
764
+ resolveEvalTimeout: typeof resolveEvalTimeout;
765
+ parseMessage: typeof parseMessage;
766
+ serializeMessage: typeof serializeMessage;
767
+ };
768
+ export { MetroFilesResult as $, ReactDevtoolsStatus as A, ExplorerImage as At, ViewSection as B, ExplorerTarget as Bt, _default as C, EXPLORER_RESULT_TYPES as Ct, REACT_DEVTOOLS_SHUTDOWN_EVENT as D, ExplorerClassesResult as Dt, serializeMessage as E, ExplorerClassesRequest as Et, ViewFrame as F, ExplorerObject as Ft, METRO_RESULT_TYPES as G, failExplorerRequest as Gt, ViewsResult as H, ExplorerValueKind as Ht, ViewHighlight as I, ExplorerObjectRequest as It, MetroChildrenResult as J, METRO_SEARCH_PAGE_SIZE as K, isExplorerRequest as Kt, ViewNode as L, ExplorerObjectResult as Lt, ViewDetails as M, ExplorerMemberKind as Mt, ViewDetailsRequest as N, ExplorerMembersRequest as Nt, REACT_DEVTOOLS_STATUS_EVENT as O, ExplorerError as Ot, ViewDetailsResult as P, ExplorerMembersResult as Pt, MetroFilesRequest as Q, ViewProperty as R, ExplorerRequest as Rt, SERVE_BRIDGE_COMMAND as S, EXPLORER_MEMBERS_PAGE_SIZE as St, resolveEvalTimeout as T, ExplorerClass as Tt, METRO_CHILDREN_PAGE_SIZE as U, ExplorerValuesRequest as Ut, ViewsRequest as V, ExplorerValue as Vt, METRO_MODULES_PAGE_SIZE as W, ExplorerValuesResult as Wt, MetroErrorCode as X, MetroError as Y, MetroFile as Z, PUSH_TIMEOUT_MS as _, MetroValueKind as _t, BridgeInfo as a, MetroModule as at, PushedAddonKind as b, isMetroResult as bt, DEFAULT_BRIDGE_PORT as c, MetroModulesResult as ct, DeviceInfo as d, MetroRequest as dt, MetroLoadAllRequest as et, DeviceStatus as f, MetroResult as ft, MAX_EVAL_TIMEOUT_MS as g, MetroValue as gt, LogMessage as h, MetroTarget as ht, BridgeAdvertisement as i, MetroMatch as it, VIEWS_PAGE_SIZE as j, ExplorerMember as jt, ReactDevtoolsFrame as k, ExplorerErrorCode as kt, DEFAULT_EVAL_TIMEOUT_MS as l, MetroReadRequest as lt, EvalResult as m, MetroSearchResult as mt, BRIDGE_SERVICE_PROTOCOL as n, MetroLoadRequest as nt, BridgeMessage as o, MetroModuleStatus as ot, EvalRequest as p, MetroSearchRequest as pt, MetroChildrenRequest as q, isExplorerResult as qt, BRIDGE_SERVICE_TYPE as r, MetroLoadResult as rt, CONTROLLER_ENDPOINT_MARKER as s, MetroModulesRequest as st, BRIDGE_REPLY_GRACE_MS as t, MetroLoadAllResult as tt, DeviceHello as u, MetroReadResult as ut, PushRequest as v, failMetroRequest as vt, parseMessage as w, EXPLORER_VALUES_LIMIT as wt, RequestFailureCode as x, EXPLORER_CLASSES_PAGE_SIZE as xt, PushResult as y, isMetroRequest as yt, ViewPropertyValue as z, ExplorerResult as zt };