@unbound-app/debugger-protocol 2.0.1 → 2.1.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/dist/controller.d.mts +8 -2
- package/dist/controller.mjs +12 -2
- package/dist/index-CxErH5OQ.d.mts +768 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +1 -1
- package/dist/pending-requests.d.mts +2 -2
- package/dist/pending-requests.mjs +2 -2
- package/dist/registry.d.mts +22 -3
- package/dist/registry.mjs +27 -1
- package/dist/src-D7-HmLkb.mjs +492 -0
- package/package.json +1 -1
- package/dist/index-DwVwBIbm.d.mts +0 -234
- package/dist/src-D0Oi4NXs.mjs +0 -139
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { A as ReactDevtoolsStatus, C as
|
|
2
|
-
export { BRIDGE_REPLY_GRACE_MS, BridgeMessage, CONTROLLER_ENDPOINT_MARKER, DEFAULT_BRIDGE_PORT, DEFAULT_EVAL_TIMEOUT_MS, DeviceHello, DeviceInfo, DeviceStatus, EvalRequest, EvalResult, LogMessage, MAX_EVAL_TIMEOUT_MS, PUSH_TIMEOUT_MS, PushRequest, PushResult, PushedAddonKind, REACT_DEVTOOLS_SHUTDOWN_EVENT, REACT_DEVTOOLS_STATUS_EVENT, type ReactDevtoolsFrame, type ReactDevtoolsStatus, RequestFailureCode, type ViewFrame, type ViewHighlight, type ViewNode, type ViewsRequest, type ViewsResult, _default as default, parseMessage, resolveEvalTimeout, serializeMessage };
|
|
1
|
+
import { $ as MetroFilesResult, A as ReactDevtoolsStatus, At as ExplorerImage, B as ViewSection, Bt as ExplorerTarget, C as _default, Ct as EXPLORER_RESULT_TYPES, D as REACT_DEVTOOLS_SHUTDOWN_EVENT, Dt as ExplorerClassesResult, E as serializeMessage, Et as ExplorerClassesRequest, F as ViewFrame, Ft as ExplorerObject, G as METRO_RESULT_TYPES, Gt as failExplorerRequest, H as ViewsResult, Ht as ExplorerValueKind, I as ViewHighlight, It as ExplorerObjectRequest, J as MetroChildrenResult, K as METRO_SEARCH_PAGE_SIZE, Kt as isExplorerRequest, L as ViewNode, Lt as ExplorerObjectResult, M as ViewDetails, Mt as ExplorerMemberKind, N as ViewDetailsRequest, Nt as ExplorerMembersRequest, O as REACT_DEVTOOLS_STATUS_EVENT, Ot as ExplorerError, P as ViewDetailsResult, Pt as ExplorerMembersResult, Q as MetroFilesRequest, R as ViewProperty, Rt as ExplorerRequest, S as SERVE_BRIDGE_COMMAND, St as EXPLORER_MEMBERS_PAGE_SIZE, T as resolveEvalTimeout, Tt as ExplorerClass, U as METRO_CHILDREN_PAGE_SIZE, Ut as ExplorerValuesRequest, V as ViewsRequest, Vt as ExplorerValue, W as METRO_MODULES_PAGE_SIZE, Wt as ExplorerValuesResult, X as MetroErrorCode, Y as MetroError, Z as MetroFile, _ as PUSH_TIMEOUT_MS, _t as MetroValueKind, a as BridgeInfo, at as MetroModule, b as PushedAddonKind, bt as isMetroResult, c as DEFAULT_BRIDGE_PORT, ct as MetroModulesResult, d as DeviceInfo, dt as MetroRequest, et as MetroLoadAllRequest, f as DeviceStatus, ft as MetroResult, g as MAX_EVAL_TIMEOUT_MS, gt as MetroValue, h as LogMessage, ht as MetroTarget, i as BridgeAdvertisement, it as MetroMatch, j as VIEWS_PAGE_SIZE, jt as ExplorerMember, k as ReactDevtoolsFrame, kt as ExplorerErrorCode, l as DEFAULT_EVAL_TIMEOUT_MS, lt as MetroReadRequest, m as EvalResult, mt as MetroSearchResult, n as BRIDGE_SERVICE_PROTOCOL, nt as MetroLoadRequest, o as BridgeMessage, ot as MetroModuleStatus, p as EvalRequest, pt as MetroSearchRequest, q as MetroChildrenRequest, qt as isExplorerResult, r as BRIDGE_SERVICE_TYPE, rt as MetroLoadResult, s as CONTROLLER_ENDPOINT_MARKER, st as MetroModulesRequest, t as BRIDGE_REPLY_GRACE_MS, tt as MetroLoadAllResult, u as DeviceHello, ut as MetroReadResult, v as PushRequest, vt as failMetroRequest, w as parseMessage, wt as EXPLORER_VALUES_LIMIT, x as RequestFailureCode, xt as EXPLORER_CLASSES_PAGE_SIZE, y as PushResult, yt as isMetroRequest, z as ViewPropertyValue, zt as ExplorerResult } from "./index-CxErH5OQ.mjs";
|
|
2
|
+
export { BRIDGE_REPLY_GRACE_MS, BRIDGE_SERVICE_PROTOCOL, BRIDGE_SERVICE_TYPE, BridgeAdvertisement, BridgeInfo, BridgeMessage, CONTROLLER_ENDPOINT_MARKER, DEFAULT_BRIDGE_PORT, DEFAULT_EVAL_TIMEOUT_MS, DeviceHello, DeviceInfo, DeviceStatus, EXPLORER_CLASSES_PAGE_SIZE, EXPLORER_MEMBERS_PAGE_SIZE, EXPLORER_RESULT_TYPES, EXPLORER_VALUES_LIMIT, EvalRequest, EvalResult, type ExplorerClass, type ExplorerClassesRequest, type ExplorerClassesResult, type ExplorerError, type ExplorerErrorCode, type ExplorerImage, type ExplorerMember, type ExplorerMemberKind, type ExplorerMembersRequest, type ExplorerMembersResult, type ExplorerObject, type ExplorerObjectRequest, type ExplorerObjectResult, type ExplorerRequest, type ExplorerResult, type ExplorerTarget, type ExplorerValue, type ExplorerValueKind, type ExplorerValuesRequest, type ExplorerValuesResult, LogMessage, MAX_EVAL_TIMEOUT_MS, METRO_CHILDREN_PAGE_SIZE, METRO_MODULES_PAGE_SIZE, METRO_RESULT_TYPES, METRO_SEARCH_PAGE_SIZE, type MetroChildrenRequest, type MetroChildrenResult, type MetroError, type MetroErrorCode, type MetroFile, type MetroFilesRequest, type MetroFilesResult, type MetroLoadAllRequest, type MetroLoadAllResult, type MetroLoadRequest, type MetroLoadResult, type MetroMatch, type MetroModule, type MetroModuleStatus, type MetroModulesRequest, type MetroModulesResult, type MetroReadRequest, type MetroReadResult, type MetroRequest, type MetroResult, type MetroSearchRequest, type MetroSearchResult, type MetroTarget, type MetroValue, type MetroValueKind, PUSH_TIMEOUT_MS, PushRequest, PushResult, PushedAddonKind, REACT_DEVTOOLS_SHUTDOWN_EVENT, REACT_DEVTOOLS_STATUS_EVENT, type ReactDevtoolsFrame, type ReactDevtoolsStatus, RequestFailureCode, SERVE_BRIDGE_COMMAND, VIEWS_PAGE_SIZE, type ViewDetails, type ViewDetailsRequest, type ViewDetailsResult, type ViewFrame, type ViewHighlight, type ViewNode, type ViewProperty, type ViewPropertyValue, type ViewSection, type ViewsRequest, type ViewsResult, _default as default, failExplorerRequest, failMetroRequest, isExplorerRequest, isExplorerResult, isMetroRequest, isMetroResult, parseMessage, resolveEvalTimeout, serializeMessage };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as BRIDGE_REPLY_GRACE_MS, n as
|
|
1
|
+
export { t as BRIDGE_REPLY_GRACE_MS, n as BRIDGE_SERVICE_PROTOCOL, r as BRIDGE_SERVICE_TYPE, i as CONTROLLER_ENDPOINT_MARKER, a as DEFAULT_BRIDGE_PORT, o as DEFAULT_EVAL_TIMEOUT_MS, w as EXPLORER_CLASSES_PAGE_SIZE, T as EXPLORER_MEMBERS_PAGE_SIZE, E as EXPLORER_RESULT_TYPES, D as EXPLORER_VALUES_LIMIT, s as MAX_EVAL_TIMEOUT_MS, _ as METRO_CHILDREN_PAGE_SIZE, v as METRO_MODULES_PAGE_SIZE, y as METRO_RESULT_TYPES, b as METRO_SEARCH_PAGE_SIZE, c as PUSH_TIMEOUT_MS, m as REACT_DEVTOOLS_SHUTDOWN_EVENT, h as REACT_DEVTOOLS_STATUS_EVENT, l as SERVE_BRIDGE_COMMAND, g as VIEWS_PAGE_SIZE, p as default, O as failExplorerRequest, x as failMetroRequest, k as isExplorerRequest, A as isExplorerResult, S as isMetroRequest, C as isMetroResult, u as parseMessage, d as resolveEvalTimeout, f as serializeMessage } from "./src-D7-HmLkb.mjs";
|
|
@@ -28,9 +28,9 @@ export declare class PendingRequests<R, M = undefined> {
|
|
|
28
28
|
resolve(id: string, result: R): boolean;
|
|
29
29
|
/**
|
|
30
30
|
* @description Settles every pending request with a failure, so no caller waits forever.
|
|
31
|
-
* @param fail Builds each request's failure result from its id.
|
|
31
|
+
* @param fail Builds each request's failure result from its id and meta.
|
|
32
32
|
*/
|
|
33
|
-
failAll(fail: (id: string) => R): void;
|
|
33
|
+
failAll(fail: (id: string, meta: M) => R): void;
|
|
34
34
|
/**
|
|
35
35
|
* @description Drops matching requests without settling them, for when nobody is left to answer.
|
|
36
36
|
* @param matches Picks the requests to drop by their meta.
|
|
@@ -30,10 +30,10 @@ var PendingRequests = class {
|
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* @description Settles every pending request with a failure, so no caller waits forever.
|
|
33
|
-
* @param fail Builds each request's failure result from its id.
|
|
33
|
+
* @param fail Builds each request's failure result from its id and meta.
|
|
34
34
|
*/
|
|
35
35
|
failAll(fail) {
|
|
36
|
-
for (const id of this.entries
|
|
36
|
+
for (const [id, { meta }] of this.entries) this.resolve(id, fail(id, meta));
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* @description Drops matching requests without settling them, for when nobody is left to answer.
|
package/dist/registry.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControllerClient } from "./controller.mjs";
|
|
2
|
-
import { StaticDecode, TObject } from "typebox";
|
|
2
|
+
import { Static, StaticDecode, TObject, Type } from "typebox";
|
|
3
3
|
/**
|
|
4
4
|
* One command definition feeds both surfaces: the CLI builds flags and positionals from its schema,
|
|
5
5
|
* and the MCP server uses the schema as the tool's input schema.
|
|
@@ -8,11 +8,30 @@ import { StaticDecode, TObject } from "typebox";
|
|
|
8
8
|
export type CommandContext = {
|
|
9
9
|
client: ControllerClient;
|
|
10
10
|
};
|
|
11
|
-
/**
|
|
11
|
+
/** Why a command failed, so a front end branches on `code` instead of the text. */
|
|
12
|
+
export declare const CommandErrorCodeSchema: Type.TUnion<[Type.TLiteral<"invalid-input">, Type.TLiteral<"no-device">, Type.TLiteral<"device-disconnected">, Type.TLiteral<"timeout">, Type.TLiteral<"bridge-unreachable">, Type.TLiteral<"shut-down">, Type.TLiteral<"device-error">, Type.TLiteral<"not-found">, Type.TLiteral<"tool-failed">, Type.TLiteral<"unsupported">, Type.TLiteral<"command-failed">]>;
|
|
13
|
+
export type CommandErrorCode = Static<typeof CommandErrorCodeSchema>;
|
|
14
|
+
/** A failed command's reason, as `--json` prints it and the MCP tool result carries it. */
|
|
15
|
+
export declare const CommandErrorSchema: TObject<{
|
|
16
|
+
code: Type.TUnion<[Type.TLiteral<"invalid-input">, Type.TLiteral<"no-device">, Type.TLiteral<"device-disconnected">, Type.TLiteral<"timeout">, Type.TLiteral<"bridge-unreachable">, Type.TLiteral<"shut-down">, Type.TLiteral<"device-error">, Type.TLiteral<"not-found">, Type.TLiteral<"tool-failed">, Type.TLiteral<"unsupported">, Type.TLiteral<"command-failed">]>;
|
|
17
|
+
message: Type.TString;
|
|
18
|
+
/** What to do about it. */
|
|
19
|
+
hint: Type.TOptional<Type.TString>;
|
|
20
|
+
/** The schema property the failure is about, for a form to highlight. */
|
|
21
|
+
field: Type.TOptional<Type.TString>;
|
|
22
|
+
stack: Type.TOptional<Type.TString>;
|
|
23
|
+
}>;
|
|
24
|
+
export type CommandError = Static<typeof CommandErrorSchema>;
|
|
25
|
+
/** What a command handler returns: a success flag, human-readable text, optional structured data, and why it failed. */
|
|
12
26
|
export type CommandOutput = {
|
|
13
|
-
ok:
|
|
27
|
+
ok: true;
|
|
14
28
|
text: string;
|
|
15
29
|
data?: unknown;
|
|
30
|
+
} | {
|
|
31
|
+
ok: false;
|
|
32
|
+
text: string;
|
|
33
|
+
data?: unknown;
|
|
34
|
+
error?: CommandError;
|
|
16
35
|
};
|
|
17
36
|
/** A command usable from both the CLI and (when opted in) the MCP server. */
|
|
18
37
|
export type CommandDefinition<S extends TObject = TObject> = {
|
package/dist/registry.mjs
CHANGED
|
@@ -1 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
// src/registry.ts
|
|
3
|
+
/** Why a command failed, so a front end branches on `code` instead of the text. */
|
|
4
|
+
const CommandErrorCodeSchema = Type.Union([
|
|
5
|
+
Type.Literal("invalid-input"),
|
|
6
|
+
Type.Literal("no-device"),
|
|
7
|
+
Type.Literal("device-disconnected"),
|
|
8
|
+
Type.Literal("timeout"),
|
|
9
|
+
Type.Literal("bridge-unreachable"),
|
|
10
|
+
Type.Literal("shut-down"),
|
|
11
|
+
Type.Literal("device-error"),
|
|
12
|
+
Type.Literal("not-found"),
|
|
13
|
+
Type.Literal("tool-failed"),
|
|
14
|
+
Type.Literal("unsupported"),
|
|
15
|
+
Type.Literal("command-failed")
|
|
16
|
+
]);
|
|
17
|
+
/** A failed command's reason, as `--json` prints it and the MCP tool result carries it. */
|
|
18
|
+
const CommandErrorSchema = Type.Object({
|
|
19
|
+
code: CommandErrorCodeSchema,
|
|
20
|
+
message: Type.String(),
|
|
21
|
+
/** What to do about it. */
|
|
22
|
+
hint: Type.Optional(Type.String()),
|
|
23
|
+
/** The schema property the failure is about, for a form to highlight. */
|
|
24
|
+
field: Type.Optional(Type.String()),
|
|
25
|
+
stack: Type.Optional(Type.String())
|
|
26
|
+
});
|
|
27
|
+
export { CommandErrorCodeSchema, CommandErrorSchema };
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
// src/explorer.ts
|
|
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
|
+
const EXPLORER_MEMBERS_PAGE_SIZE = 100;
|
|
8
|
+
/** The most images or class names a device returns for one {@link ExplorerClassesRequest}. */
|
|
9
|
+
const EXPLORER_CLASSES_PAGE_SIZE = 200;
|
|
10
|
+
/** The most member values one {@link ExplorerValuesRequest} may name. */
|
|
11
|
+
const EXPLORER_VALUES_LIMIT = 50;
|
|
12
|
+
/** The result frame type answering each request frame type. */
|
|
13
|
+
const EXPLORER_RESULT_TYPES = {
|
|
14
|
+
"explorer-object-request": "explorer-object-result",
|
|
15
|
+
"explorer-members-request": "explorer-members-result",
|
|
16
|
+
"explorer-values-request": "explorer-values-result",
|
|
17
|
+
"explorer-classes-request": "explorer-classes-result"
|
|
18
|
+
};
|
|
19
|
+
const MEMBER_KINDS = /* @__PURE__ */ new Set([
|
|
20
|
+
"properties",
|
|
21
|
+
"ivars",
|
|
22
|
+
"methods",
|
|
23
|
+
"classMethods",
|
|
24
|
+
"protocols",
|
|
25
|
+
"fields",
|
|
26
|
+
"constructors",
|
|
27
|
+
"interfaces"
|
|
28
|
+
]);
|
|
29
|
+
const VALUE_KINDS$1 = /* @__PURE__ */ new Set([
|
|
30
|
+
"nil",
|
|
31
|
+
"number",
|
|
32
|
+
"bool",
|
|
33
|
+
"string",
|
|
34
|
+
"object",
|
|
35
|
+
"class",
|
|
36
|
+
"struct",
|
|
37
|
+
"pointer",
|
|
38
|
+
"selector",
|
|
39
|
+
"other",
|
|
40
|
+
"skipped",
|
|
41
|
+
"error"
|
|
42
|
+
]);
|
|
43
|
+
const ERROR_CODES$1 = /* @__PURE__ */ new Set([
|
|
44
|
+
"stale",
|
|
45
|
+
"disabled",
|
|
46
|
+
"unavailable",
|
|
47
|
+
"unsupported",
|
|
48
|
+
"unknown-class",
|
|
49
|
+
"failed"
|
|
50
|
+
]);
|
|
51
|
+
const READS = /* @__PURE__ */ new Set([
|
|
52
|
+
"auto",
|
|
53
|
+
"manual",
|
|
54
|
+
"never"
|
|
55
|
+
]);
|
|
56
|
+
/**
|
|
57
|
+
* @description Builds the failed answer to an explorer request.
|
|
58
|
+
* @param request The request, or its type and id.
|
|
59
|
+
* @param error What failed.
|
|
60
|
+
* @param code Why it failed.
|
|
61
|
+
* @returns The result frame.
|
|
62
|
+
*/
|
|
63
|
+
function failExplorerRequest(request, error, code) {
|
|
64
|
+
return {
|
|
65
|
+
type: EXPLORER_RESULT_TYPES[request.type],
|
|
66
|
+
id: request.id,
|
|
67
|
+
ok: false,
|
|
68
|
+
error,
|
|
69
|
+
code
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* @description Checks whether a frame is an explorer request, by its type alone.
|
|
74
|
+
* @param frame A parsed frame.
|
|
75
|
+
* @returns Whether it is one.
|
|
76
|
+
*/
|
|
77
|
+
function isExplorerRequest(frame) {
|
|
78
|
+
return Object.hasOwn(EXPLORER_RESULT_TYPES, frame.type);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @description Checks whether a frame is an explorer result, by its type alone.
|
|
82
|
+
* @param frame A parsed frame.
|
|
83
|
+
* @returns Whether it is one.
|
|
84
|
+
*/
|
|
85
|
+
function isExplorerResult(frame) {
|
|
86
|
+
return Object.values(EXPLORER_RESULT_TYPES).includes(frame.type);
|
|
87
|
+
}
|
|
88
|
+
function isObject$2(value) {
|
|
89
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
90
|
+
}
|
|
91
|
+
function isCount$1(value) {
|
|
92
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
93
|
+
}
|
|
94
|
+
function isStrings(value) {
|
|
95
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "string");
|
|
96
|
+
}
|
|
97
|
+
function isNullableString$1(value) {
|
|
98
|
+
return value === null || typeof value === "string";
|
|
99
|
+
}
|
|
100
|
+
/** Checks an optional field: absent, `undefined`, or passing `check`. */
|
|
101
|
+
function optional$1(record, key, check) {
|
|
102
|
+
return record[key] === void 0 || check(record[key]);
|
|
103
|
+
}
|
|
104
|
+
const isString$1 = (value) => typeof value === "string";
|
|
105
|
+
const isNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
106
|
+
function isTarget$1(value) {
|
|
107
|
+
if (!isObject$2(value)) return false;
|
|
108
|
+
const keys = [
|
|
109
|
+
"node",
|
|
110
|
+
"object",
|
|
111
|
+
"className"
|
|
112
|
+
].filter((key) => value[key] !== void 0);
|
|
113
|
+
return keys.length === 1 && typeof value[keys[0] ?? ""] === "string";
|
|
114
|
+
}
|
|
115
|
+
function isExplorerClass(value) {
|
|
116
|
+
return isObject$2(value) && typeof value.name === "string" && isNullableString$1(value.image) && (value.instanceSize === null || isCount$1(value.instanceSize)) && isObject$2(value.counts) && Object.entries(value.counts).every(([kind, count]) => MEMBER_KINDS.has(kind) && isCount$1(count));
|
|
117
|
+
}
|
|
118
|
+
function isExplorerMember(value) {
|
|
119
|
+
return isObject$2(value) && typeof value.name === "string" && MEMBER_KINDS.has(value.kind) && isNullableString$1(value.type) && isNullableString$1(value.signature) && READS.has(value.read) && optional$1(value, "returnType", isString$1) && optional$1(value, "parameters", isStrings) && optional$1(value, "attributes", isStrings) && optional$1(value, "static", (flag) => typeof flag === "boolean") && optional$1(value, "offset", isNumber) && optional$1(value, "size", isNumber) && optional$1(value, "image", isNullableString$1);
|
|
120
|
+
}
|
|
121
|
+
function isExplorerValue(value) {
|
|
122
|
+
return isObject$2(value) && typeof value.name === "string" && VALUE_KINDS$1.has(value.kind) && typeof value.text === "string" && optional$1(value, "object", isString$1) && optional$1(value, "className", isString$1);
|
|
123
|
+
}
|
|
124
|
+
function isExplorerObject(value) {
|
|
125
|
+
return isObject$2(value) && isNullableString$1(value.ref) && typeof value.className === "string" && isNullableString$1(value.description) && (value.platform === "ios" || value.platform === "android") && Array.isArray(value.chain) && value.chain.every(isExplorerClass);
|
|
126
|
+
}
|
|
127
|
+
function isExplorerImage(value) {
|
|
128
|
+
return isObject$2(value) && typeof value.path === "string" && typeof value.name === "string" && isCount$1(value.classCount);
|
|
129
|
+
}
|
|
130
|
+
function isPage(frame) {
|
|
131
|
+
return optional$1(frame, "offset", isCount$1) && optional$1(frame, "limit", isCount$1) && optional$1(frame, "filter", isString$1);
|
|
132
|
+
}
|
|
133
|
+
/** Checks a result's id and outcome; `isOk` checks the payload of a successful one. */
|
|
134
|
+
function isResult$1(frame, isOk) {
|
|
135
|
+
if (typeof frame.id !== "string") return false;
|
|
136
|
+
if (frame.ok === true) return isOk();
|
|
137
|
+
return frame.ok === false && typeof frame.error === "string" && ERROR_CODES$1.has(frame.code);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* @description Checks the fields of an explorer frame whose `type` is already known.
|
|
141
|
+
* @param frame The parsed frame.
|
|
142
|
+
* @returns Whether the frame is a valid explorer request or result.
|
|
143
|
+
*/
|
|
144
|
+
function isExplorerFrame(frame) {
|
|
145
|
+
if (!isObject$2(frame)) return false;
|
|
146
|
+
switch (frame.type) {
|
|
147
|
+
case "explorer-object-request": return typeof frame.id === "string" && isTarget$1(frame.target);
|
|
148
|
+
case "explorer-object-result": return isResult$1(frame, () => isExplorerObject(frame.object));
|
|
149
|
+
case "explorer-members-request": return typeof frame.id === "string" && typeof frame.className === "string" && MEMBER_KINDS.has(frame.kind) && isPage(frame);
|
|
150
|
+
case "explorer-members-result": return isResult$1(frame, () => isCount$1(frame.total) && Array.isArray(frame.members) && frame.members.every(isExplorerMember));
|
|
151
|
+
case "explorer-values-request": return typeof frame.id === "string" && typeof frame.object === "string" && typeof frame.className === "string" && MEMBER_KINDS.has(frame.kind) && isStrings(frame.names) && optional$1(frame, "invokeGetters", (flag) => typeof flag === "boolean");
|
|
152
|
+
case "explorer-values-result": return isResult$1(frame, () => Array.isArray(frame.values) && frame.values.every(isExplorerValue));
|
|
153
|
+
case "explorer-classes-request": return typeof frame.id === "string" && optional$1(frame, "image", isString$1) && isPage(frame);
|
|
154
|
+
case "explorer-classes-result": return isResult$1(frame, () => isCount$1(frame.total) && optional$1(frame, "images", (images) => Array.isArray(images) && images.every(isExplorerImage)) && optional$1(frame, "classes", isStrings));
|
|
155
|
+
default: return false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// src/metro.ts
|
|
159
|
+
/**
|
|
160
|
+
* The Metro explorer's frames: list, load and search modules, and walk a loaded module's exports as a tree. Long
|
|
161
|
+
* work runs in short device-side batches the controller repeats; getters run only when asked.
|
|
162
|
+
*/
|
|
163
|
+
/** The most modules a device returns for one {@link MetroModulesRequest}. */
|
|
164
|
+
const METRO_MODULES_PAGE_SIZE = 200;
|
|
165
|
+
/** The most properties a device returns for one {@link MetroChildrenRequest}. */
|
|
166
|
+
const METRO_CHILDREN_PAGE_SIZE = 100;
|
|
167
|
+
/** The most matches a device collects for one {@link MetroSearchRequest} before it stops at a module's end. */
|
|
168
|
+
const METRO_SEARCH_PAGE_SIZE = 50;
|
|
169
|
+
/** The result frame type answering each request frame type. */
|
|
170
|
+
const METRO_RESULT_TYPES = {
|
|
171
|
+
"metro-modules-request": "metro-modules-result",
|
|
172
|
+
"metro-load-request": "metro-load-result",
|
|
173
|
+
"metro-load-all-request": "metro-load-all-result",
|
|
174
|
+
"metro-search-request": "metro-search-result",
|
|
175
|
+
"metro-files-request": "metro-files-result",
|
|
176
|
+
"metro-children-request": "metro-children-result",
|
|
177
|
+
"metro-read-request": "metro-read-result"
|
|
178
|
+
};
|
|
179
|
+
const STATUSES = /* @__PURE__ */ new Set([
|
|
180
|
+
"loaded",
|
|
181
|
+
"unloaded",
|
|
182
|
+
"failed"
|
|
183
|
+
]);
|
|
184
|
+
const VALUE_KINDS = /* @__PURE__ */ new Set([
|
|
185
|
+
"string",
|
|
186
|
+
"number",
|
|
187
|
+
"boolean",
|
|
188
|
+
"nullish",
|
|
189
|
+
"symbol",
|
|
190
|
+
"function",
|
|
191
|
+
"class",
|
|
192
|
+
"array",
|
|
193
|
+
"object",
|
|
194
|
+
"error",
|
|
195
|
+
"getter"
|
|
196
|
+
]);
|
|
197
|
+
const ERROR_CODES = /* @__PURE__ */ new Set([
|
|
198
|
+
"stale",
|
|
199
|
+
"unknown-module",
|
|
200
|
+
"unloaded",
|
|
201
|
+
"failed"
|
|
202
|
+
]);
|
|
203
|
+
/**
|
|
204
|
+
* @description Builds the failed answer to a Metro request.
|
|
205
|
+
* @param request The request, or its type and id.
|
|
206
|
+
* @param error What failed.
|
|
207
|
+
* @param code Why it failed.
|
|
208
|
+
* @returns The result frame.
|
|
209
|
+
*/
|
|
210
|
+
function failMetroRequest(request, error, code) {
|
|
211
|
+
return {
|
|
212
|
+
type: METRO_RESULT_TYPES[request.type],
|
|
213
|
+
id: request.id,
|
|
214
|
+
ok: false,
|
|
215
|
+
error,
|
|
216
|
+
code
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* @description Checks whether a frame is a Metro request, by its type alone.
|
|
221
|
+
* @param frame A parsed frame.
|
|
222
|
+
* @returns Whether it is one.
|
|
223
|
+
*/
|
|
224
|
+
function isMetroRequest(frame) {
|
|
225
|
+
return Object.hasOwn(METRO_RESULT_TYPES, frame.type);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* @description Checks whether a frame is a Metro result, by its type alone.
|
|
229
|
+
* @param frame A parsed frame.
|
|
230
|
+
* @returns Whether it is one.
|
|
231
|
+
*/
|
|
232
|
+
function isMetroResult(frame) {
|
|
233
|
+
return Object.values(METRO_RESULT_TYPES).includes(frame.type);
|
|
234
|
+
}
|
|
235
|
+
function isObject$1(value) {
|
|
236
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
237
|
+
}
|
|
238
|
+
function isCount(value) {
|
|
239
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
240
|
+
}
|
|
241
|
+
/** Checks an optional field: absent, `undefined`, or passing `check`. */
|
|
242
|
+
function optional(record, key, check) {
|
|
243
|
+
return record[key] === void 0 || check(record[key]);
|
|
244
|
+
}
|
|
245
|
+
const isString = (value) => typeof value === "string";
|
|
246
|
+
function isTarget(value) {
|
|
247
|
+
if (!isObject$1(value)) return false;
|
|
248
|
+
const keys = ["module", "ref"].filter((key) => value[key] !== void 0);
|
|
249
|
+
return keys.length === 1 && (keys[0] === "module" ? isCount(value.module) : isString(value.ref));
|
|
250
|
+
}
|
|
251
|
+
function isMetroModule(value) {
|
|
252
|
+
return isObject$1(value) && isCount(value.id) && STATUSES.has(value.status) && (value.label === null || typeof value.label === "string");
|
|
253
|
+
}
|
|
254
|
+
function isMetroValue(value) {
|
|
255
|
+
return isObject$1(value) && typeof value.key === "string" && VALUE_KINDS.has(value.kind) && typeof value.text === "string" && optional(value, "ref", isString) && optional(value, "internal", (flag) => typeof flag === "boolean");
|
|
256
|
+
}
|
|
257
|
+
const isMetroValues = (value) => Array.isArray(value) && value.every(isMetroValue);
|
|
258
|
+
function isMetroFile(value) {
|
|
259
|
+
return isObject$1(value) && isCount(value.id) && isString(value.path);
|
|
260
|
+
}
|
|
261
|
+
function isMetroMatch(value) {
|
|
262
|
+
return isObject$1(value) && isMetroModule(value.module) && Array.isArray(value.path) && value.path.every(isString) && isMetroValue(value.value);
|
|
263
|
+
}
|
|
264
|
+
/** Checks a result's id and outcome; `isOk` checks the payload of a successful one. */
|
|
265
|
+
function isResult(frame, isOk) {
|
|
266
|
+
if (typeof frame.id !== "string") return false;
|
|
267
|
+
if (frame.ok === true) return isOk();
|
|
268
|
+
return frame.ok === false && typeof frame.error === "string" && ERROR_CODES.has(frame.code);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* @description Checks the fields of a Metro frame whose `type` is already known.
|
|
272
|
+
* @param frame The parsed frame.
|
|
273
|
+
* @returns Whether the frame is a valid Metro request or result.
|
|
274
|
+
*/
|
|
275
|
+
function isMetroFrame(frame) {
|
|
276
|
+
if (!isObject$1(frame)) return false;
|
|
277
|
+
switch (frame.type) {
|
|
278
|
+
case "metro-modules-request": return typeof frame.id === "string" && optional(frame, "filter", isString) && optional(frame, "status", (status) => STATUSES.has(status)) && optional(frame, "offset", isCount) && optional(frame, "limit", isCount);
|
|
279
|
+
case "metro-modules-result": return isResult(frame, () => isCount(frame.total) && isCount(frame.loaded) && isCount(frame.count) && Array.isArray(frame.modules) && frame.modules.every(isMetroModule));
|
|
280
|
+
case "metro-load-request": return typeof frame.id === "string" && isCount(frame.module);
|
|
281
|
+
case "metro-load-result": return isResult(frame, () => isMetroModule(frame.module) && isCount(frame.loaded));
|
|
282
|
+
case "metro-load-all-request": return typeof frame.id === "string";
|
|
283
|
+
case "metro-load-all-result": return isResult(frame, () => [
|
|
284
|
+
frame.attempted,
|
|
285
|
+
frame.failed,
|
|
286
|
+
frame.remaining,
|
|
287
|
+
frame.loaded,
|
|
288
|
+
frame.count
|
|
289
|
+
].every(isCount));
|
|
290
|
+
case "metro-search-request": return typeof frame.id === "string" && isString(frame.query) && optional(frame, "cursor", isCount) && optional(frame, "limit", isCount);
|
|
291
|
+
case "metro-search-result": return isResult(frame, () => Array.isArray(frame.matches) && frame.matches.every(isMetroMatch) && (frame.cursor === null || isCount(frame.cursor)) && isCount(frame.searched) && isCount(frame.total));
|
|
292
|
+
case "metro-files-request": return typeof frame.id === "string";
|
|
293
|
+
case "metro-files-result": return isResult(frame, () => Array.isArray(frame.files) && frame.files.every(isMetroFile) && isCount(frame.unloaded) && isCount(frame.count));
|
|
294
|
+
case "metro-children-request": return typeof frame.id === "string" && isTarget(frame.target) && optional(frame, "offset", isCount) && optional(frame, "limit", isCount);
|
|
295
|
+
case "metro-children-result": return isResult(frame, () => isMetroValue(frame.value) && isCount(frame.total) && isMetroValues(frame.children) && isMetroValues(frame.internal));
|
|
296
|
+
case "metro-read-request": return typeof frame.id === "string" && typeof frame.ref === "string";
|
|
297
|
+
case "metro-read-result": return isResult(frame, () => isMetroValue(frame.value));
|
|
298
|
+
default: return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// src/views.ts
|
|
302
|
+
/**
|
|
303
|
+
* The view finder's frames: a controller asks the device for one page of one level of its native view
|
|
304
|
+
* tree at a time, for one view's properties when it selects it, and names the view to outline on screen.
|
|
305
|
+
*/
|
|
306
|
+
/** The most views a device returns for one {@link ViewsRequest}; a longer level is read in pages. */
|
|
307
|
+
const VIEWS_PAGE_SIZE = 100;
|
|
308
|
+
const VISIBILITIES = /* @__PURE__ */ new Set([
|
|
309
|
+
"visible",
|
|
310
|
+
"invisible",
|
|
311
|
+
"gone"
|
|
312
|
+
]);
|
|
313
|
+
function isObject(value) {
|
|
314
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
315
|
+
}
|
|
316
|
+
function isNullableString(value) {
|
|
317
|
+
return value === null || typeof value === "string";
|
|
318
|
+
}
|
|
319
|
+
function isViewFrame(value) {
|
|
320
|
+
return isObject(value) && "x" in value && typeof value.x === "number" && "y" in value && typeof value.y === "number" && "width" in value && typeof value.width === "number" && "height" in value && typeof value.height === "number";
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* @description Checks that a value has every field a {@link ViewNode} needs.
|
|
324
|
+
* @param value The parsed value.
|
|
325
|
+
* @returns Whether it is a view node.
|
|
326
|
+
*/
|
|
327
|
+
function isViewNode(value) {
|
|
328
|
+
return isObject(value) && "id" in value && typeof value.id === "string" && "className" in value && typeof value.className === "string" && "resourceName" in value && isNullableString(value.resourceName) && "frame" in value && isViewFrame(value.frame) && "visibility" in value && VISIBILITIES.has(value.visibility) && "alpha" in value && (value.alpha === null || typeof value.alpha === "number") && "text" in value && isNullableString(value.text) && "childCount" in value && typeof value.childCount === "number";
|
|
329
|
+
}
|
|
330
|
+
function isOptionalCount(value) {
|
|
331
|
+
return value === void 0 || typeof value === "number" && Number.isInteger(value) && value >= 0;
|
|
332
|
+
}
|
|
333
|
+
function isViewProperty(value) {
|
|
334
|
+
return isObject(value) && "key" in value && typeof value.key === "string" && "value" in value && (isNullableString(value.value) || typeof value.value === "number" || typeof value.value === "boolean") && (!("kind" in value) || value.kind === void 0 || value.kind === "color") && (!("unit" in value) || value.unit === void 0 || typeof value.unit === "string");
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* @description Checks that a value has every field {@link ViewDetails} needs.
|
|
338
|
+
* @param value The parsed value.
|
|
339
|
+
* @returns Whether it is a view's details.
|
|
340
|
+
*/
|
|
341
|
+
function isViewDetails(value) {
|
|
342
|
+
return isObject(value) && "classChain" in value && Array.isArray(value.classChain) && value.classChain.every((name) => typeof name === "string") && "sections" in value && Array.isArray(value.sections) && value.sections.every((section) => isObject(section) && "title" in section && typeof section.title === "string" && "properties" in section && Array.isArray(section.properties) && section.properties.every(isViewProperty));
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* @description Checks the fields of a view finder frame whose `type` is already known.
|
|
346
|
+
* @param frame The parsed frame.
|
|
347
|
+
* @returns Whether the frame is a valid view request, result, details frame or highlight.
|
|
348
|
+
*/
|
|
349
|
+
function isViewFrameMessage(frame) {
|
|
350
|
+
if (!isObject(frame) || !("type" in frame)) return false;
|
|
351
|
+
switch (frame.type) {
|
|
352
|
+
case "views-request": return "id" in frame && typeof frame.id === "string" && (!("parent" in frame) || frame.parent === void 0 || typeof frame.parent === "string") && isOptionalCount("offset" in frame ? frame.offset : void 0) && isOptionalCount("limit" in frame ? frame.limit : void 0);
|
|
353
|
+
case "views-result": return "id" in frame && typeof frame.id === "string" && "ok" in frame && (frame.ok === true ? "nodes" in frame && Array.isArray(frame.nodes) && frame.nodes.every(isViewNode) && isOptionalCount("total" in frame ? frame.total : void 0) : frame.ok === false && "error" in frame && typeof frame.error === "string");
|
|
354
|
+
case "view-details-request": return "id" in frame && typeof frame.id === "string" && "node" in frame && typeof frame.node === "string";
|
|
355
|
+
case "view-details-result": return "id" in frame && typeof frame.id === "string" && "ok" in frame && (frame.ok === true ? "details" in frame && isViewDetails(frame.details) : frame.ok === false && "error" in frame && typeof frame.error === "string");
|
|
356
|
+
case "view-highlight": return "node" in frame && isNullableString(frame.node);
|
|
357
|
+
default: return false;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// src/react-devtools.ts
|
|
361
|
+
/**
|
|
362
|
+
* The event the device sends the frontend, with a {@link ReactDevtoolsStatus}, when its backend
|
|
363
|
+
* starts a session, cannot start one, or ends one.
|
|
364
|
+
*/
|
|
365
|
+
const REACT_DEVTOOLS_STATUS_EVENT = "unbound:backend-status";
|
|
366
|
+
/** React DevTools' own event that ends a backend session; the bridge sends it when the frontend leaves. */
|
|
367
|
+
const REACT_DEVTOOLS_SHUTDOWN_EVENT = "shutdown";
|
|
368
|
+
/**
|
|
369
|
+
* @description Checks the fields of a React DevTools frame whose `type` is already known.
|
|
370
|
+
* @param frame The parsed frame.
|
|
371
|
+
* @returns Whether the frame names an event.
|
|
372
|
+
*/
|
|
373
|
+
function isReactDevtoolsFrame(frame) {
|
|
374
|
+
return typeof frame === "object" && frame !== null && "event" in frame && typeof frame.event === "string";
|
|
375
|
+
}
|
|
376
|
+
// src/index.ts
|
|
377
|
+
/** The default port the bridge listens on and controllers dial. */
|
|
378
|
+
const DEFAULT_BRIDGE_PORT = 9090;
|
|
379
|
+
const DEFAULT_EVAL_TIMEOUT_MS = 1e4;
|
|
380
|
+
const MAX_EVAL_TIMEOUT_MS = 864e5;
|
|
381
|
+
/** How long the bridge waits for the device to reload a pushed addon. */
|
|
382
|
+
const PUSH_TIMEOUT_MS = 6e4;
|
|
383
|
+
/**
|
|
384
|
+
* How much longer a controller waits than the bridge, so the bridge's own timeout reply always
|
|
385
|
+
* arrives before the controller gives up on its own.
|
|
386
|
+
*/
|
|
387
|
+
const BRIDGE_REPLY_GRACE_MS = 5e3;
|
|
388
|
+
/**
|
|
389
|
+
* @description Picks how long an eval may run: the requested timeout when it is a positive number of
|
|
390
|
+
* milliseconds, capped at {@link MAX_EVAL_TIMEOUT_MS}, otherwise {@link DEFAULT_EVAL_TIMEOUT_MS}.
|
|
391
|
+
* @param requested The timeout the controller asked for, if any.
|
|
392
|
+
* @returns The timeout to apply, in milliseconds.
|
|
393
|
+
*/
|
|
394
|
+
function resolveEvalTimeout(requested) {
|
|
395
|
+
return typeof requested === "number" && requested > 0 ? Math.min(requested, MAX_EVAL_TIMEOUT_MS) : DEFAULT_EVAL_TIMEOUT_MS;
|
|
396
|
+
}
|
|
397
|
+
/** The query marker a controller appends to its URL so the bridge routes it as a controller, not a device. */
|
|
398
|
+
const CONTROLLER_ENDPOINT_MARKER = "mcp";
|
|
399
|
+
/** The unlisted `ubd` command that runs the bridge in the foreground; tools that start one run it. */
|
|
400
|
+
const SERVE_BRIDGE_COMMAND = "serve-bridge";
|
|
401
|
+
/** The Bonjour service type a bridge advertises, so a device on the same network can find it. */
|
|
402
|
+
const BRIDGE_SERVICE_TYPE = "_unbound-bridge._tcp";
|
|
403
|
+
/** The `proto` TXT value of an advertised bridge; a device skips bridges that speak another one. */
|
|
404
|
+
const BRIDGE_SERVICE_PROTOCOL = "1";
|
|
405
|
+
/**
|
|
406
|
+
* @description Safely parses a raw wire frame into a {@link BridgeMessage}, guarding against invalid
|
|
407
|
+
* JSON and unknown shapes so both ends can trust what they route.
|
|
408
|
+
* @param raw The JSON string received off the socket.
|
|
409
|
+
* @returns The parsed message, or `undefined` if it isn't a recognised frame.
|
|
410
|
+
*/
|
|
411
|
+
function parseMessage(raw) {
|
|
412
|
+
let value;
|
|
413
|
+
try {
|
|
414
|
+
value = JSON.parse(raw);
|
|
415
|
+
} catch {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
return hasRequiredFields(value) ? value : void 0;
|
|
419
|
+
}
|
|
420
|
+
function hasRequiredFields(frame) {
|
|
421
|
+
if (typeof frame !== "object" || frame === null || !("type" in frame)) return false;
|
|
422
|
+
switch (frame.type) {
|
|
423
|
+
case "log": return "message" in frame && typeof frame.message === "string" && "level" in frame && (frame.level === 1 || frame.level === 2 || frame.level === 3);
|
|
424
|
+
case "eval": return "id" in frame && typeof frame.id === "string" && "code" in frame && typeof frame.code === "string";
|
|
425
|
+
case "eval-result": return "id" in frame && typeof frame.id === "string" && "ok" in frame && (frame.ok === true ? "value" in frame && typeof frame.value === "string" : frame.ok === false && hasError(frame));
|
|
426
|
+
case "plugin-push-result": return "id" in frame && typeof frame.id === "string" && "ok" in frame && (frame.ok === true || frame.ok === false && hasError(frame));
|
|
427
|
+
case "plugin-push": return "id" in frame && typeof frame.id === "string" && "addonId" in frame && typeof frame.addonId === "string" && (!("kind" in frame) || frame.kind === void 0 || frame.kind === "plugin" || frame.kind === "theme") && "bundle" in frame && typeof frame.bundle === "string" && "manifest" in frame && typeof frame.manifest === "object" && frame.manifest !== null && (!("bytecode" in frame) || frame.bytecode === void 0 || isStringRecord(frame.bytecode)) && (!("files" in frame) || frame.files === void 0 || isStringRecord(frame.files));
|
|
428
|
+
case "hello": return "device" in frame && isDeviceInfo(frame.device);
|
|
429
|
+
case "device-status": return "connected" in frame && (frame.connected === false || frame.connected === true && (!("device" in frame) || frame.device === void 0 || isDeviceInfo(frame.device)));
|
|
430
|
+
case "bridge-info": return "code" in frame && typeof frame.code === "string" && "advertising" in frame && typeof frame.advertising === "boolean" && (!("address" in frame) || typeof frame.address === "string") && (!("error" in frame) || typeof frame.error === "string");
|
|
431
|
+
case "views-request":
|
|
432
|
+
case "views-result":
|
|
433
|
+
case "view-details-request":
|
|
434
|
+
case "view-details-result":
|
|
435
|
+
case "view-highlight": return isViewFrameMessage(frame);
|
|
436
|
+
case "explorer-object-request":
|
|
437
|
+
case "explorer-object-result":
|
|
438
|
+
case "explorer-members-request":
|
|
439
|
+
case "explorer-members-result":
|
|
440
|
+
case "explorer-values-request":
|
|
441
|
+
case "explorer-values-result":
|
|
442
|
+
case "explorer-classes-request":
|
|
443
|
+
case "explorer-classes-result": return isExplorerFrame(frame);
|
|
444
|
+
case "metro-modules-request":
|
|
445
|
+
case "metro-modules-result":
|
|
446
|
+
case "metro-load-request":
|
|
447
|
+
case "metro-load-result":
|
|
448
|
+
case "metro-load-all-request":
|
|
449
|
+
case "metro-load-all-result":
|
|
450
|
+
case "metro-search-request":
|
|
451
|
+
case "metro-search-result":
|
|
452
|
+
case "metro-files-request":
|
|
453
|
+
case "metro-files-result":
|
|
454
|
+
case "metro-children-request":
|
|
455
|
+
case "metro-children-result":
|
|
456
|
+
case "metro-read-request":
|
|
457
|
+
case "metro-read-result": return isMetroFrame(frame);
|
|
458
|
+
case "react-devtools": return isReactDevtoolsFrame(frame);
|
|
459
|
+
default: return false;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
function hasError(frame) {
|
|
463
|
+
return typeof frame === "object" && frame !== null && "error" in frame && typeof frame.error === "string";
|
|
464
|
+
}
|
|
465
|
+
function isDeviceInfo(value) {
|
|
466
|
+
return typeof value === "object" && value !== null && "platform" in value && typeof value.platform === "string" && "discordVersion" in value && typeof value.discordVersion === "string" && "loaderVersion" in value && typeof value.loaderVersion === "string" && "clientVersion" in value && typeof value.clientVersion === "string";
|
|
467
|
+
}
|
|
468
|
+
function isStringRecord(value) {
|
|
469
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === "string");
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* @description Serialises a {@link BridgeMessage} into its wire form. Inverse of {@link parseMessage}.
|
|
473
|
+
* @param message The message to frame.
|
|
474
|
+
* @returns The JSON string to send over the socket.
|
|
475
|
+
*/
|
|
476
|
+
function serializeMessage(message) {
|
|
477
|
+
return JSON.stringify(message);
|
|
478
|
+
}
|
|
479
|
+
var src_default = {
|
|
480
|
+
DEFAULT_BRIDGE_PORT,
|
|
481
|
+
DEFAULT_EVAL_TIMEOUT_MS,
|
|
482
|
+
MAX_EVAL_TIMEOUT_MS,
|
|
483
|
+
PUSH_TIMEOUT_MS,
|
|
484
|
+
BRIDGE_REPLY_GRACE_MS,
|
|
485
|
+
CONTROLLER_ENDPOINT_MARKER: "mcp",
|
|
486
|
+
REACT_DEVTOOLS_SHUTDOWN_EVENT,
|
|
487
|
+
REACT_DEVTOOLS_STATUS_EVENT,
|
|
488
|
+
resolveEvalTimeout,
|
|
489
|
+
parseMessage,
|
|
490
|
+
serializeMessage
|
|
491
|
+
};
|
|
492
|
+
export { isExplorerResult as A, isMetroResult as C, EXPLORER_VALUES_LIMIT as D, EXPLORER_RESULT_TYPES as E, failExplorerRequest as O, isMetroRequest as S, EXPLORER_MEMBERS_PAGE_SIZE as T, METRO_CHILDREN_PAGE_SIZE as _, DEFAULT_BRIDGE_PORT as a, METRO_SEARCH_PAGE_SIZE as b, PUSH_TIMEOUT_MS as c, resolveEvalTimeout as d, serializeMessage as f, VIEWS_PAGE_SIZE as g, REACT_DEVTOOLS_STATUS_EVENT as h, CONTROLLER_ENDPOINT_MARKER as i, isExplorerRequest as k, SERVE_BRIDGE_COMMAND as l, REACT_DEVTOOLS_SHUTDOWN_EVENT as m, BRIDGE_SERVICE_PROTOCOL as n, DEFAULT_EVAL_TIMEOUT_MS as o, src_default as p, BRIDGE_SERVICE_TYPE as r, MAX_EVAL_TIMEOUT_MS as s, BRIDGE_REPLY_GRACE_MS as t, parseMessage as u, METRO_MODULES_PAGE_SIZE as v, EXPLORER_CLASSES_PAGE_SIZE as w, failMetroRequest as x, METRO_RESULT_TYPES as y };
|
package/package.json
CHANGED