@astur-mobile/core 0.5.0-beta.3 → 0.5.0-beta.5
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/flutter/network.d.ts +34 -0
- package/dist/flutter/network.d.ts.map +1 -0
- package/dist/flutter/network.js +121 -0
- package/dist/flutter/network.js.map +1 -0
- package/dist/flutter/vmService.d.ts +170 -0
- package/dist/flutter/vmService.d.ts.map +1 -0
- package/dist/flutter/vmService.js +630 -0
- package/dist/flutter/vmService.js.map +1 -0
- package/dist/image.d.ts +42 -0
- package/dist/image.d.ts.map +1 -0
- package/dist/image.js +87 -0
- package/dist/image.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/keyboard.d.ts +11 -0
- package/dist/keyboard.d.ts.map +1 -1
- package/dist/keyboard.js +13 -0
- package/dist/keyboard.js.map +1 -1
- package/dist/locator.d.ts +39 -0
- package/dist/locator.d.ts.map +1 -1
- package/dist/locator.js +77 -0
- package/dist/locator.js.map +1 -1
- package/dist/reactNative/network.d.ts +140 -0
- package/dist/reactNative/network.d.ts.map +1 -0
- package/dist/reactNative/network.js +382 -0
- package/dist/reactNative/network.js.map +1 -0
- package/dist/session.d.ts +41 -1
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +48 -3
- package/dist/session.js.map +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { NetworkCapabilities, NetworkRedactionOptions, NetworkRequestFilter, NetworkRequestRecord } from '@astur-mobile/protocol';
|
|
2
|
+
/**
|
|
3
|
+
* Network observation for Flutter Android, backed by the Dart VM service's
|
|
4
|
+
* `dart:io` HTTP profiler — the same source Flutter DevTools' Network view uses.
|
|
5
|
+
*
|
|
6
|
+
* Coverage is exactly `dart:io`'s HttpClient: that includes `package:http` and
|
|
7
|
+
* Dio's IO path, because both are built on it. It does NOT include a WebView's
|
|
8
|
+
* own requests, native SDKs, platform channels, or any client that opens its
|
|
9
|
+
* own sockets. Callers should read {@link capabilities} rather than assume.
|
|
10
|
+
*
|
|
11
|
+
* Read-only by design. Interception needs an in-app adapter that can hold a
|
|
12
|
+
* request open, which the profiler cannot do — it reports what already
|
|
13
|
+
* happened.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_REDACTED_HEADERS: string[];
|
|
16
|
+
/** 64 KiB. Enough for a JSON payload, small enough that a long run cannot blow up. */
|
|
17
|
+
export declare const DEFAULT_MAX_BODY_BYTES: number;
|
|
18
|
+
export declare const FLUTTER_NETWORK_CAPABILITIES: NetworkCapabilities;
|
|
19
|
+
/** Case-insensitive header redaction, applied before a record is ever returned. */
|
|
20
|
+
export declare function redactHeaders(headers: Record<string, unknown> | undefined, redact: string[]): Record<string, string>;
|
|
21
|
+
/** Keeps a body only when it is within budget, and says why when it is not. */
|
|
22
|
+
export declare function applyBodyLimit(body: string | undefined, maxBytes: number): Pick<NetworkRequestRecord, 'responseBody' | 'bodyOmittedReason'>;
|
|
23
|
+
/**
|
|
24
|
+
* Maps the VM profiler's payload onto {@link NetworkRequestRecord}.
|
|
25
|
+
*
|
|
26
|
+
* Every field is read defensively: the Dart SDK owns this shape and has moved
|
|
27
|
+
* fields between versions, so a missing key must degrade one record rather than
|
|
28
|
+
* throw and lose the whole batch.
|
|
29
|
+
*/
|
|
30
|
+
export declare function toNetworkRecords(profile: unknown, options: Required<NetworkRedactionOptions>): NetworkRequestRecord[];
|
|
31
|
+
/** Applies a {@link NetworkRequestFilter} to already-collected records. */
|
|
32
|
+
export declare function filterRecords(records: NetworkRequestRecord[], filter: NetworkRequestFilter | undefined): NetworkRequestRecord[];
|
|
33
|
+
export declare function resolveRedactionOptions(options: NetworkRedactionOptions | undefined): Required<NetworkRedactionOptions>;
|
|
34
|
+
//# sourceMappingURL=network.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../src/flutter/network.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,wBAAwB,CAAC;AAEhC;;;;;;;;;;;;GAYG;AAEH,eAAO,MAAM,wBAAwB,UAAyD,CAAC;AAE/F,sFAAsF;AACtF,eAAO,MAAM,sBAAsB,QAAY,CAAC;AAEhD,eAAO,MAAM,4BAA4B,EAAE,mBAO1C,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC5C,MAAM,EAAE,MAAM,EAAE,GACf,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,QAAQ,EAAE,MAAM,GACf,IAAI,CAAC,oBAAoB,EAAE,cAAc,GAAG,mBAAmB,CAAC,CAQlE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,QAAQ,CAAC,uBAAuB,CAAC,GACzC,oBAAoB,EAAE,CA4CxB;AAED,2EAA2E;AAC3E,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,EAAE,EAC/B,MAAM,EAAE,oBAAoB,GAAG,SAAS,GACvC,oBAAoB,EAAE,CAmBxB;AAED,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,uBAAuB,GAAG,SAAS,GAC3C,QAAQ,CAAC,uBAAuB,CAAC,CAKnC"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Network observation for Flutter Android, backed by the Dart VM service's
|
|
3
|
+
* `dart:io` HTTP profiler — the same source Flutter DevTools' Network view uses.
|
|
4
|
+
*
|
|
5
|
+
* Coverage is exactly `dart:io`'s HttpClient: that includes `package:http` and
|
|
6
|
+
* Dio's IO path, because both are built on it. It does NOT include a WebView's
|
|
7
|
+
* own requests, native SDKs, platform channels, or any client that opens its
|
|
8
|
+
* own sockets. Callers should read {@link capabilities} rather than assume.
|
|
9
|
+
*
|
|
10
|
+
* Read-only by design. Interception needs an in-app adapter that can hold a
|
|
11
|
+
* request open, which the profiler cannot do — it reports what already
|
|
12
|
+
* happened.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_REDACTED_HEADERS = ['authorization', 'cookie', 'set-cookie', 'x-api-key'];
|
|
15
|
+
/** 64 KiB. Enough for a JSON payload, small enough that a long run cannot blow up. */
|
|
16
|
+
export const DEFAULT_MAX_BODY_BYTES = 64 * 1024;
|
|
17
|
+
export const FLUTTER_NETWORK_CAPABILITIES = {
|
|
18
|
+
observe: true,
|
|
19
|
+
intercept: false,
|
|
20
|
+
transports: ['http'],
|
|
21
|
+
responseBodies: true,
|
|
22
|
+
coverage: "dart:io HttpClient traffic (package:http and Dio included); excludes WebView, native SDK, and platform-channel requests",
|
|
23
|
+
adapterRequired: true
|
|
24
|
+
};
|
|
25
|
+
/** Case-insensitive header redaction, applied before a record is ever returned. */
|
|
26
|
+
export function redactHeaders(headers, redact) {
|
|
27
|
+
const lowered = new Set(redact.map((name) => name.toLowerCase()));
|
|
28
|
+
const out = {};
|
|
29
|
+
for (const [key, value] of Object.entries(headers ?? {})) {
|
|
30
|
+
out[key] = lowered.has(key.toLowerCase())
|
|
31
|
+
? '<redacted>'
|
|
32
|
+
: Array.isArray(value) ? value.join(', ') : String(value);
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
/** Keeps a body only when it is within budget, and says why when it is not. */
|
|
37
|
+
export function applyBodyLimit(body, maxBytes) {
|
|
38
|
+
if (body === undefined) {
|
|
39
|
+
return { bodyOmittedReason: 'not-captured' };
|
|
40
|
+
}
|
|
41
|
+
if (Buffer.byteLength(body, 'utf8') > maxBytes) {
|
|
42
|
+
return { bodyOmittedReason: 'too-large' };
|
|
43
|
+
}
|
|
44
|
+
return { responseBody: body };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Maps the VM profiler's payload onto {@link NetworkRequestRecord}.
|
|
48
|
+
*
|
|
49
|
+
* Every field is read defensively: the Dart SDK owns this shape and has moved
|
|
50
|
+
* fields between versions, so a missing key must degrade one record rather than
|
|
51
|
+
* throw and lose the whole batch.
|
|
52
|
+
*/
|
|
53
|
+
export function toNetworkRecords(profile, options) {
|
|
54
|
+
const requests = profile?.requests;
|
|
55
|
+
if (!Array.isArray(requests)) {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
return requests.flatMap((entry) => {
|
|
59
|
+
// Guard the entry itself, not just its fields: a null/non-object row would
|
|
60
|
+
// otherwise throw and take every other record in the batch with it.
|
|
61
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
const row = entry;
|
|
65
|
+
const id = row.id === undefined ? undefined : String(row.id);
|
|
66
|
+
const uri = typeof row.uri === 'string' ? row.uri : undefined;
|
|
67
|
+
if (!id || !uri) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const request = (row.request ?? {});
|
|
71
|
+
const response = (row.response ?? {});
|
|
72
|
+
const startedMicros = Number(row.startTime ?? 0);
|
|
73
|
+
const endMicros = Number(row.endTime ?? 0);
|
|
74
|
+
const errorText = typeof request.error === 'string'
|
|
75
|
+
? request.error
|
|
76
|
+
: typeof row.error === 'string' ? row.error : undefined;
|
|
77
|
+
return [{
|
|
78
|
+
id,
|
|
79
|
+
transport: 'http',
|
|
80
|
+
method: typeof row.method === 'string' ? row.method.toUpperCase() : 'GET',
|
|
81
|
+
url: uri,
|
|
82
|
+
requestHeaders: redactHeaders(request.headers, options.redactHeaders),
|
|
83
|
+
...(response.headers
|
|
84
|
+
? { responseHeaders: redactHeaders(response.headers, options.redactHeaders) }
|
|
85
|
+
: {}),
|
|
86
|
+
...(response.statusCode === undefined ? {} : { status: Number(response.statusCode) }),
|
|
87
|
+
// The VM reports microseconds since epoch; the public contract is ms.
|
|
88
|
+
startedAt: Math.round(startedMicros / 1000),
|
|
89
|
+
...(endMicros > startedMicros ? { durationMs: Math.round((endMicros - startedMicros) / 1000) } : {}),
|
|
90
|
+
...(errorText ? { error: errorText } : {})
|
|
91
|
+
}];
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** Applies a {@link NetworkRequestFilter} to already-collected records. */
|
|
95
|
+
export function filterRecords(records, filter) {
|
|
96
|
+
if (!filter) {
|
|
97
|
+
return records;
|
|
98
|
+
}
|
|
99
|
+
return records.filter((record) => {
|
|
100
|
+
if (filter.method && record.method.toUpperCase() !== filter.method.toUpperCase()) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (filter.transport && record.transport !== filter.transport) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (filter.url instanceof RegExp) {
|
|
107
|
+
return filter.url.test(record.url);
|
|
108
|
+
}
|
|
109
|
+
if (typeof filter.url === 'string') {
|
|
110
|
+
return record.url.includes(filter.url);
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
export function resolveRedactionOptions(options) {
|
|
116
|
+
return {
|
|
117
|
+
redactHeaders: options?.redactHeaders ?? DEFAULT_REDACTED_HEADERS,
|
|
118
|
+
maxBodyBytes: options?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../src/flutter/network.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import type { MobileElementSnapshot } from '@astur-mobile/protocol';
|
|
2
|
+
interface RpcResult {
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
}
|
|
5
|
+
export interface FlutterVmServiceOptions {
|
|
6
|
+
/** WebSocket URL of the Dart VM service, e.g. ws://127.0.0.1:PORT/TOKEN/ws */
|
|
7
|
+
url: string;
|
|
8
|
+
requestTimeoutMs?: number;
|
|
9
|
+
/** How long to wait for the first completed frame before serving trees. */
|
|
10
|
+
readyTimeoutMs?: number;
|
|
11
|
+
/** Poll interval while waiting for the first completed frame. */
|
|
12
|
+
readyPollMs?: number;
|
|
13
|
+
/** How long the laid-out element set must stay unchanged before the UI is considered settled. */
|
|
14
|
+
readySettleMs?: number;
|
|
15
|
+
/**
|
|
16
|
+
* Total wall-clock budget for retrying an on-device tree walk that lands
|
|
17
|
+
* mid-build (transient build-lock errors).
|
|
18
|
+
*
|
|
19
|
+
* This is deliberately a time budget rather than an attempt count. Each
|
|
20
|
+
* attempt can itself block for up to `requestTimeoutMs`, so `N retries`
|
|
21
|
+
* bounds the worst case at `N * requestTimeoutMs` — with a handful of
|
|
22
|
+
* retries that is already minutes, which silently blows past the caller's
|
|
23
|
+
* own timeout (see `evaluateStringStable`).
|
|
24
|
+
*
|
|
25
|
+
* Defaults to `requestTimeoutMs + 10s`. Setting it below `requestTimeoutMs`
|
|
26
|
+
* caps the first attempt at less than a full request, turning a slow-but-fine
|
|
27
|
+
* tree walk into a timeout.
|
|
28
|
+
*/
|
|
29
|
+
evalBudgetMs?: number;
|
|
30
|
+
/** Delay between tree-walk retries. */
|
|
31
|
+
evalRetryDelayMs?: number;
|
|
32
|
+
}
|
|
33
|
+
export declare class FlutterVmService {
|
|
34
|
+
private ws?;
|
|
35
|
+
private nextId;
|
|
36
|
+
private readonly pending;
|
|
37
|
+
private isolateId?;
|
|
38
|
+
private rootLibId?;
|
|
39
|
+
private screen;
|
|
40
|
+
private readonly url;
|
|
41
|
+
private readonly timeoutMs;
|
|
42
|
+
private readonly readyTimeoutMs;
|
|
43
|
+
private readonly readyPollMs;
|
|
44
|
+
private readonly readySettleMs;
|
|
45
|
+
private readonly evalBudgetMs;
|
|
46
|
+
private readonly evalRetryDelayMs;
|
|
47
|
+
constructor(options: FlutterVmServiceOptions);
|
|
48
|
+
private openSocket;
|
|
49
|
+
/**
|
|
50
|
+
* Attaches for network observation only.
|
|
51
|
+
*
|
|
52
|
+
* Deliberately not {@link connect}: that one binds an isolate by evaluating a
|
|
53
|
+
* Dart expression, which needs the expression compiler that `flutter run`
|
|
54
|
+
* attaches. An app launched any other way — `simctl launch` on the iOS
|
|
55
|
+
* simulator, for instance — has a perfectly good VM service with a working
|
|
56
|
+
* HTTP profiler but no compiler, so requiring evaluation rejects a session
|
|
57
|
+
* that can observe traffic fine.
|
|
58
|
+
*
|
|
59
|
+
* Binds on the capability actually needed instead: an isolate that registered
|
|
60
|
+
* the `dart:io` profiler extensions.
|
|
61
|
+
*/
|
|
62
|
+
connectForNetwork(): Promise<boolean>;
|
|
63
|
+
connect(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Re-binds to the isolate created by a hot restart. `flutter run`'s `R` tears
|
|
66
|
+
* down the running isolate and starts a *new* one. The old isolate lingers in
|
|
67
|
+
* `getVM` for a moment — and is still readable but FROZEN at its last frame —
|
|
68
|
+
* so binding to it makes tree reads return stale UI (taps reach the live app
|
|
69
|
+
* but the tree never reflects them) or, once it dies, an empty tree. Excluding
|
|
70
|
+
* the pre-restart id is what makes resets land on the live isolate.
|
|
71
|
+
*/
|
|
72
|
+
reattach(): Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Re-checks readiness on the already-bound isolate without re-resolving it.
|
|
75
|
+
* Used by the reset path to re-wait after re-foregrounding a surfaceless engine
|
|
76
|
+
* (a hot restart can come back with a 0x0 view), so callers can retry cheaply
|
|
77
|
+
* instead of paying the isolate-resolution grace window again.
|
|
78
|
+
*/
|
|
79
|
+
ensureReady(): Promise<boolean>;
|
|
80
|
+
/**
|
|
81
|
+
* Binds {@link isolateId}/{@link rootLibId} to a live, evaluable isolate.
|
|
82
|
+
*
|
|
83
|
+
* When `previousIsolateId` is given (a hot-restart reattach), an isolate with a
|
|
84
|
+
* *different* id is strongly preferred — that's the replacement; the old one is
|
|
85
|
+
* the frozen/dying predecessor. We only fall back to the same id after a short
|
|
86
|
+
* grace window (covers the rare case where a restart reuses the id) so we don't
|
|
87
|
+
* grab the predecessor before its replacement has registered. Each candidate is
|
|
88
|
+
* validated with a trivial eval, since a dying isolate can still be listed yet
|
|
89
|
+
* reject evaluations.
|
|
90
|
+
*/
|
|
91
|
+
private resolveIsolate;
|
|
92
|
+
getTree(): Promise<MobileElementSnapshot>;
|
|
93
|
+
/**
|
|
94
|
+
* Runs the on-device tree walk and rebuilds the flat, parent-annotated output
|
|
95
|
+
* into a nested snapshot tree. Nesting matters because page logic reads a
|
|
96
|
+
* container's subtree (e.g. the counters under a tap-lab card) — a flat list
|
|
97
|
+
* would leave every container childless. Rows are emitted in pre-order, so a
|
|
98
|
+
* parent always precedes its children and the map is fully populated by the
|
|
99
|
+
* time we wire up links.
|
|
100
|
+
*/
|
|
101
|
+
private extractChildren;
|
|
102
|
+
/** Dismisses the soft keyboard by clearing the Flutter primary focus. */
|
|
103
|
+
unfocus(): Promise<void>;
|
|
104
|
+
dispose(): Promise<void>;
|
|
105
|
+
private parseRow;
|
|
106
|
+
/**
|
|
107
|
+
* Blocks until the app's UI has settled, so the first read returns fully
|
|
108
|
+
* laid-out bounds rather than zeros.
|
|
109
|
+
*
|
|
110
|
+
* Two phases:
|
|
111
|
+
* 1. Wait for a completed frame (scheduler idle) with a non-zero screen size —
|
|
112
|
+
* captures the real physical size, which is 0x0 until the view lays out.
|
|
113
|
+
* 2. Wait for the laid-out element set to stop changing across consecutive
|
|
114
|
+
* polls. This is necessary because parts of the tree (e.g. a bottom
|
|
115
|
+
* navigation bar) can lay out a frame or two after the first frame, so they
|
|
116
|
+
* report zero bounds immediately after step 1 — tapping such a node would
|
|
117
|
+
* hit the wrong coordinates. The fingerprint keys on which nodes are present
|
|
118
|
+
* and laid out, not their exact bounds, so a continuously-animating app
|
|
119
|
+
* still settles instead of polling until the timeout.
|
|
120
|
+
*/
|
|
121
|
+
private waitForReady;
|
|
122
|
+
/** Identity of the laid-out, labelled nodes — present-and-sized, ignoring exact position so animations still settle. Walks the (now nested) tree. */
|
|
123
|
+
private layoutFingerprint;
|
|
124
|
+
/**
|
|
125
|
+
* Evaluates the on-device tree walk, retrying transient build-lock failures.
|
|
126
|
+
*
|
|
127
|
+
* The walk uses `visitChildren`, which throws if it runs while Flutter is mid-build
|
|
128
|
+
* (app startup, route transitions, animations). Those settle within a frame or two,
|
|
129
|
+
* so a short bounded retry makes reads reliable without callers having to sleep.
|
|
130
|
+
*/
|
|
131
|
+
private evaluateStringStable;
|
|
132
|
+
private sleep;
|
|
133
|
+
/**
|
|
134
|
+
* Evaluates a Dart expression and returns its full String result (handles VM
|
|
135
|
+
* string truncation). `deadline` caps every RPC this makes, so paging a large
|
|
136
|
+
* tree cannot outlive the caller's retry budget.
|
|
137
|
+
*/
|
|
138
|
+
private evaluateString;
|
|
139
|
+
/**
|
|
140
|
+
* Turns on the Dart VM's HTTP profiler for this isolate.
|
|
141
|
+
*
|
|
142
|
+
* Off by default: with it on the VM retains every request (and its body) for
|
|
143
|
+
* the life of the isolate, so it is enabled only when a test asks to observe,
|
|
144
|
+
* and the buffer is cleared between tests.
|
|
145
|
+
*/
|
|
146
|
+
enableHttpProfiling(): Promise<void>;
|
|
147
|
+
/** Drops everything the profiler has buffered so far. */
|
|
148
|
+
clearHttpProfile(): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* Returns the profiler's buffered requests, newest state included.
|
|
151
|
+
*
|
|
152
|
+
* The response shape is owned by the Dart SDK and has changed between
|
|
153
|
+
* versions, so callers must treat every field as optional rather than
|
|
154
|
+
* trusting a schema — see `toNetworkRecords` in the Android driver.
|
|
155
|
+
*/
|
|
156
|
+
getHttpProfile(): Promise<RpcResult>;
|
|
157
|
+
/** Full detail (including the response body) for one profiled request. */
|
|
158
|
+
getHttpProfileRequest(id: string): Promise<RpcResult>;
|
|
159
|
+
/**
|
|
160
|
+
* Whether this isolate actually registered the dart:io HTTP profiler
|
|
161
|
+
* extensions. They are absent in some builds, so capability is detected at
|
|
162
|
+
* runtime rather than assumed from the platform.
|
|
163
|
+
*/
|
|
164
|
+
supportsHttpProfiling(): Promise<boolean>;
|
|
165
|
+
private call;
|
|
166
|
+
private onMessage;
|
|
167
|
+
private failAllPending;
|
|
168
|
+
}
|
|
169
|
+
export {};
|
|
170
|
+
//# sourceMappingURL=vmService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vmService.d.ts","sourceRoot":"","sources":["../../src/flutter/vmService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAyG5E,UAAU,SAAS;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AASD,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAC;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iGAAiG;IACjG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAAC,CAAY;IACvB,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6G;IACrI,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAS;IAC3B,OAAO,CAAC,MAAM,CAA+C;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,OAAO,EAAE,uBAAuB;YAc9B,UAAU;IAYxB;;;;;;;;;;;;OAYG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAKrC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B;;;;;;;OAOG;IACG,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAKlC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC;;;;;;;;;;OAUG;YACW,cAAc;IAmFtB,OAAO,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAiB/C;;;;;;;OAOG;YACW,eAAe;IAyB7B,yEAAyE;IACnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAIxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAU9B,OAAO,CAAC,QAAQ;IAgChB;;;;;;;;;;;;;;OAcG;YACW,YAAY;IA2D1B,qJAAqJ;IACrJ,OAAO,CAAC,iBAAiB;IAgBzB;;;;;;OAMG;YACW,oBAAoB;IA6ClC,OAAO,CAAC,KAAK;IAIb;;;;OAIG;YACW,cAAc;IAoC5B;;;;;;OAMG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAO1C,yDAAyD;IACnD,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIvC;;;;;;OAMG;IACG,cAAc,IAAI,OAAO,CAAC,SAAS,CAAC;IAI1C,0EAA0E;IACpE,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAI3D;;;;OAIG;IACG,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;IAM/C,OAAO,CAAC,IAAI;IAsBZ,OAAO,CAAC,SAAS;IAgCjB,OAAO,CAAC,cAAc;CAOvB"}
|