browser-debugger-cli 0.8.0 → 0.9.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/README.md +4 -1
- package/dist/cdp/schema.d.ts +4 -1
- package/dist/cdp/schema.js +48 -7
- package/dist/commands/cdp.js +3 -2
- package/dist/commands/cleanup.d.ts +11 -0
- package/dist/commands/cleanup.js +161 -57
- package/dist/commands/console.d.ts +20 -1
- package/dist/commands/console.js +57 -17
- package/dist/commands/details.js +3 -2
- package/dist/commands/dom/DomElementResolver.d.ts +10 -3
- package/dist/commands/dom/DomElementResolver.js +35 -17
- package/dist/commands/dom/a11y.d.ts +10 -0
- package/dist/commands/dom/a11y.js +27 -5
- package/dist/commands/dom/eval.d.ts +3 -1
- package/dist/commands/dom/eval.js +29 -4
- package/dist/commands/dom/form.js +16 -62
- package/dist/commands/dom/formInteraction.js +152 -113
- package/dist/commands/dom/formSummary.d.ts +49 -0
- package/dist/commands/dom/formSummary.js +180 -0
- package/dist/commands/dom/frames.d.ts +2 -1
- package/dist/commands/dom/frames.js +17 -2
- package/dist/commands/dom/get.d.ts +6 -5
- package/dist/commands/dom/get.js +92 -82
- package/dist/commands/dom/helpers/index.d.ts +1 -1
- package/dist/commands/dom/helpers/index.js +1 -1
- package/dist/commands/dom/helpers/query.d.ts +44 -17
- package/dist/commands/dom/helpers/query.js +244 -97
- package/dist/commands/dom/helpers/runElementCommand.d.ts +10 -2
- package/dist/commands/dom/helpers/runElementCommand.js +97 -30
- package/dist/commands/dom/helpers/screenshot.d.ts +4 -1
- package/dist/commands/dom/helpers/screenshot.js +164 -49
- package/dist/commands/dom/index.d.ts +3 -1
- package/dist/commands/dom/index.js +16 -6
- package/dist/commands/dom/layout.d.ts +14 -0
- package/dist/commands/dom/layout.js +54 -0
- package/dist/commands/dom/listeners.d.ts +5 -1
- package/dist/commands/dom/listeners.js +13 -3
- package/dist/commands/dom/query.js +2 -3
- package/dist/commands/dom/screenshot.d.ts +12 -2
- package/dist/commands/dom/screenshot.js +27 -3
- package/dist/commands/dom/semanticUtils.d.ts +6 -13
- package/dist/commands/dom/semanticUtils.js +15 -19
- package/dist/commands/dom/wait.d.ts +13 -0
- package/dist/commands/dom/wait.js +83 -0
- package/dist/commands/helpJson.js +2 -2
- package/dist/commands/network/list.js +4 -11
- package/dist/commands/optionBehaviors.js +112 -21
- package/dist/commands/page.d.ts +2 -1
- package/dist/commands/page.js +41 -5
- package/dist/commands/peek.js +4 -11
- package/dist/commands/sessions.d.ts +8 -0
- package/dist/commands/sessions.js +19 -0
- package/dist/commands/shared/CommandRunner.js +4 -4
- package/dist/commands/shared/dataFetcher.js +2 -2
- package/dist/commands/shared/followMode.d.ts +21 -1
- package/dist/commands/shared/followMode.js +29 -2
- package/dist/commands/shared/handleValidationError.d.ts +2 -2
- package/dist/commands/shared/handleValidationError.js +12 -3
- package/dist/commands/shared/optionTypes.d.ts +40 -5
- package/dist/commands/shared/startHelpers.js +12 -3
- package/dist/commands/shared/validation.d.ts +3 -2
- package/dist/commands/shared/validation.js +4 -3
- package/dist/commands/start.d.ts +63 -0
- package/dist/commands/start.js +115 -15
- package/dist/commands/status.js +29 -7
- package/dist/commands/stop.js +7 -6
- package/dist/commands/tail.js +4 -11
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands.js +2 -0
- package/dist/connection/chromeIdentity.d.ts +65 -0
- package/dist/connection/chromeIdentity.js +143 -0
- package/dist/connection/launcher/profilePreferences.d.ts +47 -0
- package/dist/connection/launcher/profilePreferences.js +151 -0
- package/dist/connection/launcher.d.ts +21 -2
- package/dist/connection/launcher.js +42 -16
- package/dist/connection/portReservation.d.ts +14 -4
- package/dist/connection/portReservation.js +21 -6
- package/dist/connection/startupExit.d.ts +8 -0
- package/dist/connection/startupExit.js +15 -6
- package/dist/constants.d.ts +6 -2
- package/dist/constants.js +9 -2
- package/dist/daemon/SessionController.js +23 -7
- package/dist/daemon/errors.d.ts +1 -1
- package/dist/daemon/errors.js +1 -1
- package/dist/daemon/launcher.d.ts +2 -1
- package/dist/daemon/launcher.js +5 -6
- package/dist/daemon/server/SocketServer.js +1 -2
- package/dist/daemon/session/Session.d.ts +13 -0
- package/dist/daemon/session/Session.js +57 -8
- package/dist/daemon/session/chromeConnection.d.ts +9 -0
- package/dist/daemon/session/chromeConnection.js +45 -8
- package/dist/daemon/session/commandRegistry.js +52 -62
- package/dist/daemon/session/interactions.d.ts +35 -9
- package/dist/daemon/session/interactions.js +36 -9
- package/dist/daemon/session/triggeredRequests.d.ts +67 -0
- package/dist/daemon/session/triggeredRequests.js +157 -0
- package/dist/daemon/session/types.d.ts +5 -1
- package/dist/daemon.js +5393 -1600
- package/dist/errors/messages.d.ts +387 -24
- package/dist/errors/messages.js +761 -67
- package/dist/index.js +3976 -1558
- package/dist/ipc/client.d.ts +12 -1
- package/dist/ipc/client.js +22 -3
- package/dist/ipc/protocol/commands.d.ts +89 -4
- package/dist/ipc/protocol/commands.js +2 -0
- package/dist/ipc/protocol/domTypes.d.ts +258 -7
- package/dist/ipc/session/lifecycle.d.ts +8 -1
- package/dist/ipc/session/queries.d.ts +5 -1
- package/dist/ipc/session/types.d.ts +5 -0
- package/dist/ipc/transport/index.d.ts +2 -1
- package/dist/ipc/transport/index.js +2 -2
- package/dist/runtime/dom/actionEffects.d.ts +106 -0
- package/dist/runtime/dom/actionEffects.js +256 -0
- package/dist/runtime/dom/actionEffectsScripts.d.ts +52 -0
- package/dist/runtime/dom/actionEffectsScripts.js +234 -0
- package/dist/runtime/dom/elementGeometry.d.ts +170 -0
- package/dist/runtime/dom/elementGeometry.js +553 -0
- package/dist/runtime/dom/elementInfo.d.ts +77 -0
- package/dist/runtime/dom/elementInfo.js +191 -0
- package/dist/runtime/dom/evalHelpers.d.ts +51 -6
- package/dist/runtime/dom/evalHelpers.js +136 -26
- package/dist/runtime/dom/eventListeners.d.ts +2 -1
- package/dist/runtime/dom/eventListeners.js +174 -47
- package/dist/runtime/dom/formDiscovery.d.ts +1 -1
- package/dist/runtime/dom/formDiscovery.js +116 -16
- package/dist/runtime/dom/formFillHelpers/fill.d.ts +10 -0
- package/dist/runtime/dom/formFillHelpers/fill.js +125 -10
- package/dist/runtime/dom/formFillHelpers/index.d.ts +2 -2
- package/dist/runtime/dom/formFillHelpers/index.js +2 -2
- package/dist/runtime/dom/formFillHelpers/pressKey.js +14 -3
- package/dist/runtime/dom/formFillHelpers/scroll.d.ts +3 -0
- package/dist/runtime/dom/formFillHelpers/scroll.js +60 -18
- package/dist/runtime/dom/formFillHelpers/shared.d.ts +17 -0
- package/dist/runtime/dom/formFillHelpers/shared.js +25 -1
- package/dist/runtime/dom/formFillHelpers/stability.d.ts +20 -6
- package/dist/runtime/dom/formFillHelpers/stability.js +50 -19
- package/dist/runtime/dom/formSubmitHelpers.d.ts +3 -0
- package/dist/runtime/dom/formSubmitHelpers.js +89 -15
- package/dist/runtime/dom/frameLayout.d.ts +60 -0
- package/dist/runtime/dom/frameLayout.js +140 -0
- package/dist/runtime/dom/frameOrigin.d.ts +50 -0
- package/dist/runtime/dom/frameOrigin.js +62 -0
- package/dist/runtime/dom/frameScopedConnection.d.ts +92 -0
- package/dist/runtime/dom/frameScopedConnection.js +252 -0
- package/dist/runtime/dom/frameSelection.d.ts +1 -1
- package/dist/runtime/dom/frameSelection.js +2 -2
- package/dist/runtime/dom/frames.d.ts +25 -2
- package/dist/runtime/dom/frames.js +202 -63
- package/dist/runtime/dom/layout.d.ts +67 -0
- package/dist/runtime/dom/layout.js +333 -0
- package/dist/runtime/dom/listenerPageScripts.d.ts +66 -0
- package/dist/runtime/dom/listenerPageScripts.js +279 -0
- package/dist/runtime/dom/listenerSummary.d.ts +132 -11
- package/dist/runtime/dom/listenerSummary.js +344 -22
- package/dist/runtime/dom/pageActivity.d.ts +41 -0
- package/dist/runtime/dom/pageActivity.js +123 -0
- package/dist/runtime/dom/reactEventHelpers.d.ts +58 -2
- package/dist/runtime/dom/reactEventHelpers.js +212 -41
- package/dist/runtime/dom/targetNode.d.ts +80 -27
- package/dist/runtime/dom/targetNode.js +249 -33
- package/dist/runtime/dom/wait.d.ts +25 -0
- package/dist/runtime/dom/wait.js +199 -0
- package/dist/runtime/dom/waitCondition.d.ts +71 -0
- package/dist/runtime/dom/waitCondition.js +75 -0
- package/dist/runtime/page/emulation.d.ts +51 -0
- package/dist/runtime/page/emulation.js +80 -0
- package/dist/runtime/page/loadingState.d.ts +36 -0
- package/dist/runtime/page/loadingState.js +86 -0
- package/dist/runtime/page/navigation.d.ts +46 -2
- package/dist/runtime/page/navigation.js +69 -33
- package/dist/session/QueryCacheManager.d.ts +11 -1
- package/dist/session/QueryCacheManager.js +25 -3
- package/dist/session/chromeOwners.d.ts +34 -0
- package/dist/session/chromeOwners.js +51 -0
- package/dist/session/cleanup/staleSession.d.ts +11 -1
- package/dist/session/cleanup/staleSession.js +17 -6
- package/dist/session/cleanup/userCommands.js +2 -4
- package/dist/session/metadata.d.ts +5 -1
- package/dist/session/metadata.js +2 -1
- package/dist/session/paths.d.ts +77 -3
- package/dist/session/paths.js +111 -5
- package/dist/session/port.d.ts +31 -7
- package/dist/session/port.js +50 -43
- package/dist/session/portClaims.d.ts +66 -0
- package/dist/session/portClaims.js +284 -0
- package/dist/session/sessionList.d.ts +58 -0
- package/dist/session/sessionList.js +199 -0
- package/dist/session/sessionName.d.ts +46 -0
- package/dist/session/sessionName.js +97 -0
- package/dist/telemetry/a11y.d.ts +8 -3
- package/dist/telemetry/a11y.js +92 -28
- package/dist/telemetry/requestKinds.d.ts +32 -0
- package/dist/telemetry/requestKinds.js +61 -0
- package/dist/telemetry/requestState.d.ts +31 -0
- package/dist/telemetry/requestState.js +38 -0
- package/dist/types.d.ts +80 -3
- package/dist/ui/formatters/a11y.js +3 -0
- package/dist/ui/formatters/console/chronological.d.ts +8 -0
- package/dist/ui/formatters/console/chronological.js +17 -4
- package/dist/ui/formatters/console/json.js +3 -4
- package/dist/ui/formatters/console/shared.d.ts +12 -0
- package/dist/ui/formatters/console.d.ts +2 -2
- package/dist/ui/formatters/console.js +1 -1
- package/dist/ui/formatters/details.js +2 -1
- package/dist/ui/formatters/dom.d.ts +26 -14
- package/dist/ui/formatters/dom.js +65 -52
- package/dist/ui/formatters/form.js +29 -18
- package/dist/ui/formatters/layout.d.ts +31 -0
- package/dist/ui/formatters/layout.js +53 -0
- package/dist/ui/formatters/listeners.d.ts +3 -2
- package/dist/ui/formatters/listeners.js +73 -9
- package/dist/ui/formatters/networkHeaders.js +13 -0
- package/dist/ui/formatters/preview.js +2 -1
- package/dist/ui/formatters/requestStatus.d.ts +1 -17
- package/dist/ui/formatters/requestStatus.js +2 -30
- package/dist/ui/formatters/sessions.d.ts +12 -0
- package/dist/ui/formatters/sessions.js +40 -0
- package/dist/ui/formatters/status.d.ts +21 -2
- package/dist/ui/formatters/status.js +47 -10
- package/dist/ui/formatters/triggeredRequests.d.ts +36 -0
- package/dist/ui/formatters/triggeredRequests.js +65 -0
- package/dist/ui/formatting.d.ts +10 -0
- package/dist/ui/formatting.js +28 -36
- package/dist/ui/messages/chrome.d.ts +9 -0
- package/dist/ui/messages/chrome.js +17 -5
- package/dist/ui/messages/commands.d.ts +388 -14
- package/dist/ui/messages/commands.js +664 -21
- package/dist/ui/messages/consoleMessages.d.ts +10 -0
- package/dist/ui/messages/consoleMessages.js +17 -0
- package/dist/ui/messages/hints.js +2 -1
- package/dist/ui/messages/preview.js +5 -4
- package/dist/ui/messages/session.d.ts +16 -21
- package/dist/ui/messages/session.js +28 -26
- package/dist/ui/messages/sessionCommand.d.ts +43 -0
- package/dist/ui/messages/sessionCommand.js +52 -0
- package/dist/utils/async.d.ts +8 -0
- package/dist/utils/async.js +19 -0
- package/dist/utils/http.d.ts +22 -1
- package/dist/utils/http.js +28 -9
- package/dist/utils/selectorFilters.d.ts +36 -8
- package/dist/utils/selectorFilters.js +267 -53
- package/dist/utils/shellDetection.d.ts +8 -2
- package/dist/utils/shellDetection.js +120 -33
- package/dist/utils/suggestions.d.ts +26 -0
- package/dist/utils/suggestions.js +73 -0
- package/dist/utils/taskMappings.js +10 -0
- package/dist/utils/url.d.ts +12 -2
- package/dist/utils/url.js +69 -7
- package/package.json +1 -1
- package/dist/ui/formatters/sessionFormatters.d.ts +0 -58
- package/dist/ui/formatters/sessionFormatters.js +0 -121
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
* all, not even to `Runtime.terminateExecution`.
|
|
15
15
|
*/
|
|
16
16
|
import { CDPConnection } from '../../connection/cdp.js';
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
17
|
+
import { CDPProtocolError } from '../../connection/errors.js';
|
|
18
|
+
import { frameLostDuringEvalError, frameNavigatedDuringEvalError, frameNotReadyError, frameRemovedDuringEvalError, pageClosedDuringEvalError, } from '../../errors/messages.js';
|
|
19
|
+
import { evaluateScript, isContextLostError, pageStillOpen, settledWithin, withBusyPageRecovery, } from './evalHelpers.js';
|
|
20
|
+
import { effectiveFrameOrigin, isCrossOrigin } from './frameOrigin.js';
|
|
19
21
|
import { frameError, selectFrame } from './frameSelection.js';
|
|
20
22
|
import { attachedSessionOf } from '../../telemetry/attachedTargets.js';
|
|
21
23
|
import { senderFor } from '../../telemetry/objectExpander.js';
|
|
@@ -70,18 +72,45 @@ function recoverySender(fc, sessionId) {
|
|
|
70
72
|
*/
|
|
71
73
|
async function sendToSession(fc, method, params, sessionId) {
|
|
72
74
|
const command = fc.conn.send(method, params, sessionId);
|
|
73
|
-
|
|
75
|
+
const scope = sessionId === undefined ? 'page' : 'frame';
|
|
76
|
+
return (await withBusyPageRecovery(recoverySender(fc, sessionId), command, { scope }));
|
|
74
77
|
}
|
|
75
78
|
/**
|
|
76
|
-
*
|
|
79
|
+
* Default execution contexts of a session's frames, reported when Runtime is
|
|
80
|
+
* enabled.
|
|
81
|
+
*
|
|
82
|
+
* @param fc - Frame connection
|
|
83
|
+
* @param sessionId - Session, undefined for the page
|
|
84
|
+
* @returns Context of each frame, by frame id
|
|
85
|
+
*/
|
|
86
|
+
async function defaultContexts(fc, sessionId) {
|
|
87
|
+
const contexts = new Map();
|
|
88
|
+
const stop = fc.conn.on('Runtime.executionContextCreated', ({ context }, eventSession) => {
|
|
89
|
+
const auxData = (context.auxData ?? {});
|
|
90
|
+
const frameId = auxData['frameId'];
|
|
91
|
+
if (eventSession !== sessionId || !auxData['isDefault'] || typeof frameId !== 'string')
|
|
92
|
+
return;
|
|
93
|
+
contexts.set(frameId, { uniqueId: context.uniqueId, origin: context.origin });
|
|
94
|
+
});
|
|
95
|
+
try {
|
|
96
|
+
await sendToSession(fc, 'Runtime.enable', {}, sessionId);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
stop();
|
|
100
|
+
}
|
|
101
|
+
return contexts;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Frame tree of a session and the default contexts of its frames.
|
|
77
105
|
*
|
|
78
106
|
* @param fc - Frame connection
|
|
79
107
|
* @param sessionId - Session, undefined for the page
|
|
80
108
|
* @returns The tree
|
|
81
109
|
*/
|
|
82
|
-
async function
|
|
110
|
+
async function readSession(fc, sessionId) {
|
|
111
|
+
const contexts = await defaultContexts(fc, sessionId);
|
|
83
112
|
const { frameTree: tree } = await sendToSession(fc, 'Page.getFrameTree', {}, sessionId);
|
|
84
|
-
return { tree, ...(sessionId && { sessionId }) };
|
|
113
|
+
return { tree, contexts, ...(sessionId && { sessionId }) };
|
|
85
114
|
}
|
|
86
115
|
/**
|
|
87
116
|
* Attach to the out-of-process iframes directly below a session. Chrome
|
|
@@ -116,25 +145,46 @@ async function attachChildFrames(fc, parentSession) {
|
|
|
116
145
|
*/
|
|
117
146
|
async function outOfProcessTrees(fc, parentSession) {
|
|
118
147
|
const sessions = await attachChildFrames(fc, parentSession);
|
|
119
|
-
const nested = await Promise.all(sessions.map(
|
|
120
|
-
await frameTree(fc, sessionId),
|
|
121
|
-
...(await outOfProcessTrees(fc, sessionId)),
|
|
122
|
-
]));
|
|
148
|
+
const nested = await Promise.all(sessions.map((sessionId) => childSessionTrees(fc, sessionId)));
|
|
123
149
|
return nested.flat();
|
|
124
150
|
}
|
|
125
151
|
/**
|
|
126
|
-
*
|
|
152
|
+
* Trees of an out-of-process iframe and the ones nested in it. A frame
|
|
153
|
+
* removed while the page is being listed (its session is gone) is skipped.
|
|
154
|
+
*
|
|
155
|
+
* @param fc - Frame connection
|
|
156
|
+
* @param sessionId - The iframe's session
|
|
157
|
+
* @returns Its tree and the nested ones, or none when it went away
|
|
158
|
+
*/
|
|
159
|
+
async function childSessionTrees(fc, sessionId) {
|
|
160
|
+
try {
|
|
161
|
+
return [await readSession(fc, sessionId), ...(await outOfProcessTrees(fc, sessionId))];
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (!(error instanceof CDPProtocolError))
|
|
165
|
+
throw error;
|
|
166
|
+
log.debug(`Frame session ${sessionId} went away while listing: ${error.message}`);
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* All frames of the trees, each with its session and default context.
|
|
127
172
|
*
|
|
128
173
|
* @param trees - Frame trees
|
|
129
174
|
* @returns Frames in tree order
|
|
130
175
|
*/
|
|
131
176
|
function flattenTrees(trees) {
|
|
132
177
|
const nodes = [];
|
|
133
|
-
const walk = (tree,
|
|
134
|
-
|
|
135
|
-
|
|
178
|
+
const walk = (tree, owner) => {
|
|
179
|
+
const context = owner.contexts.get(tree.frame.id);
|
|
180
|
+
nodes.push({
|
|
181
|
+
frame: tree.frame,
|
|
182
|
+
...(owner.sessionId && { sessionId: owner.sessionId }),
|
|
183
|
+
...(context && { context }),
|
|
184
|
+
});
|
|
185
|
+
tree.childFrames?.forEach((child) => walk(child, owner));
|
|
136
186
|
};
|
|
137
|
-
trees.forEach((
|
|
187
|
+
trees.forEach((owner) => walk(owner.tree, owner));
|
|
138
188
|
return nodes;
|
|
139
189
|
}
|
|
140
190
|
/**
|
|
@@ -175,7 +225,7 @@ function attributeValue(attributes = [], key) {
|
|
|
175
225
|
* @param fc - Frame connection
|
|
176
226
|
* @param frameId - Frame
|
|
177
227
|
* @param ownerSession - Session of the parent frame
|
|
178
|
-
* @returns `name` and `
|
|
228
|
+
* @returns `name`, `id` and `sandbox` attributes when set
|
|
179
229
|
*/
|
|
180
230
|
async function ownerAttributes(fc, frameId, ownerSession) {
|
|
181
231
|
try {
|
|
@@ -183,78 +233,104 @@ async function ownerAttributes(fc, frameId, ownerSession) {
|
|
|
183
233
|
const { node } = await sendToSession(fc, 'DOM.describeNode', { backendNodeId }, ownerSession);
|
|
184
234
|
const name = attributeValue(node.attributes, 'name');
|
|
185
235
|
const id = attributeValue(node.attributes, 'id');
|
|
186
|
-
|
|
236
|
+
const sandbox = attributeValue(node.attributes, 'sandbox');
|
|
237
|
+
return { ...(name && { name }), ...(id && { id }), ...(sandbox !== undefined && { sandbox }) };
|
|
187
238
|
}
|
|
188
239
|
catch (error) {
|
|
189
240
|
log.debug(`No iframe element for frame ${frameId}: ${getErrorMessage(error)}`);
|
|
190
241
|
return {};
|
|
191
242
|
}
|
|
192
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Where a frame sits in the listing: its origin, and the index of its parent.
|
|
246
|
+
* Parents are placed before their children, so a child can inherit its
|
|
247
|
+
* parent's origin.
|
|
248
|
+
*
|
|
249
|
+
* @param node - The frame
|
|
250
|
+
* @param index - Its position
|
|
251
|
+
* @param owner - Attributes of its iframe element
|
|
252
|
+
* @param state - Frames placed so far (updated)
|
|
253
|
+
* @returns Origin and parent index
|
|
254
|
+
*/
|
|
255
|
+
function placeFrame(node, index, owner, state) {
|
|
256
|
+
const { frame, context } = node;
|
|
257
|
+
const parentId = frame.parentId ?? '';
|
|
258
|
+
const origin = effectiveFrameOrigin({
|
|
259
|
+
url: frame.url,
|
|
260
|
+
securityOrigin: frame.securityOrigin,
|
|
261
|
+
contextOrigin: context?.origin,
|
|
262
|
+
parentOrigin: state.originOf.get(parentId),
|
|
263
|
+
sandbox: owner.sandbox,
|
|
264
|
+
});
|
|
265
|
+
const parentIndex = state.indexOf.get(parentId);
|
|
266
|
+
state.originOf.set(frame.id, origin);
|
|
267
|
+
state.indexOf.set(frame.id, index);
|
|
268
|
+
return { origin, ...(parentIndex !== undefined && { parentIndex }) };
|
|
269
|
+
}
|
|
193
270
|
/**
|
|
194
271
|
* Describe an iframe for listing. Chrome names a frame after its element's
|
|
195
272
|
* `id` when it has no `name`, so such a name is not repeated.
|
|
196
273
|
*
|
|
197
|
-
* @param fc - Frame connection
|
|
198
274
|
* @param node - The frame
|
|
199
275
|
* @param index - Its position
|
|
200
|
-
* @param
|
|
276
|
+
* @param owner - Attributes of its iframe element
|
|
277
|
+
* @param state - Frames described so far (updated)
|
|
201
278
|
* @returns The located frame
|
|
202
279
|
*/
|
|
203
|
-
|
|
204
|
-
const { frame, sessionId } = node;
|
|
205
|
-
const owner = await ownerAttributes(fc, frame.id, context.sessionOf.get(frame.parentId ?? ''));
|
|
280
|
+
function describeFrame(node, index, owner, state) {
|
|
281
|
+
const { frame, sessionId, context } = node;
|
|
206
282
|
const name = owner.name ?? (frame.name === owner.id ? undefined : frame.name);
|
|
283
|
+
const { origin, parentIndex } = placeFrame(node, index, owner, state);
|
|
207
284
|
const info = {
|
|
208
285
|
index,
|
|
209
286
|
url: frame.url + (frame.urlFragment ?? ''),
|
|
210
287
|
...(name && { name }),
|
|
211
288
|
...(owner.id && { id: owner.id }),
|
|
212
|
-
origin
|
|
213
|
-
crossOrigin:
|
|
289
|
+
origin,
|
|
290
|
+
crossOrigin: isCrossOrigin(origin, state.topOrigin),
|
|
214
291
|
outOfProcess: sessionId !== undefined,
|
|
292
|
+
...(parentIndex !== undefined && { parentIndex }),
|
|
293
|
+
};
|
|
294
|
+
const ownerSession = state.sessionOf.get(frame.parentId ?? '');
|
|
295
|
+
return {
|
|
296
|
+
info,
|
|
297
|
+
frameId: frame.id,
|
|
298
|
+
...(sessionId && { sessionId }),
|
|
299
|
+
...(ownerSession && { ownerSession }),
|
|
300
|
+
...(context && { context }),
|
|
215
301
|
};
|
|
216
|
-
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* The listing state before the first iframe: the page's own origin.
|
|
305
|
+
*
|
|
306
|
+
* @param page - The page's session tree
|
|
307
|
+
* @param sessionOf - Session of each frame
|
|
308
|
+
* @returns Initial state
|
|
309
|
+
*/
|
|
310
|
+
function initialListingState(page, sessionOf) {
|
|
311
|
+
const top = page.tree.frame;
|
|
312
|
+
const topOrigin = effectiveFrameOrigin({
|
|
313
|
+
url: top.url,
|
|
314
|
+
securityOrigin: top.securityOrigin,
|
|
315
|
+
contextOrigin: page.contexts.get(top.id)?.origin,
|
|
316
|
+
});
|
|
317
|
+
return { topOrigin, originOf: new Map([[top.id, topOrigin]]), indexOf: new Map(), sessionOf };
|
|
217
318
|
}
|
|
218
319
|
/**
|
|
219
320
|
* Find every iframe of the page, nested and out-of-process ones included.
|
|
321
|
+
* Frames that go away while they are being listed are skipped.
|
|
220
322
|
*
|
|
221
323
|
* @param fc - Frame connection
|
|
222
324
|
* @returns Iframes in listing order
|
|
223
325
|
*/
|
|
224
326
|
async function discoverFrames(fc) {
|
|
225
|
-
const [page, outOfProcess] = await Promise.all([
|
|
327
|
+
const [page, outOfProcess] = await Promise.all([readSession(fc), outOfProcessTrees(fc)]);
|
|
226
328
|
const nodes = flattenTrees([page, ...outOfProcess]);
|
|
227
329
|
const sessionOf = new Map(nodes.map((node) => [node.frame.id, node.sessionId]));
|
|
228
|
-
const context = { topOrigin: page.tree.frame.securityOrigin, sessionOf };
|
|
229
330
|
const iframes = iframesInOrder(nodes, page.tree.frame.id);
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
* The default (main-world) execution context of a frame, so the script sees
|
|
234
|
-
* the frame's own globals.
|
|
235
|
-
*
|
|
236
|
-
* @param fc - Frame connection
|
|
237
|
-
* @param frame - The frame
|
|
238
|
-
* @returns The context's unique id
|
|
239
|
-
* @throws CommandError (83) when the frame has no context yet
|
|
240
|
-
*/
|
|
241
|
-
async function defaultContext(fc, frame) {
|
|
242
|
-
const contexts = [];
|
|
243
|
-
const stop = fc.conn.on('Runtime.executionContextCreated', ({ context }, sessionId) => {
|
|
244
|
-
if (sessionId === frame.sessionId)
|
|
245
|
-
contexts.push(context);
|
|
246
|
-
});
|
|
247
|
-
try {
|
|
248
|
-
await sendToSession(fc, 'Runtime.enable', {}, frame.sessionId);
|
|
249
|
-
}
|
|
250
|
-
finally {
|
|
251
|
-
stop();
|
|
252
|
-
}
|
|
253
|
-
const auxData = (c) => (c.auxData ?? {});
|
|
254
|
-
const context = contexts.find((c) => auxData(c)['frameId'] === frame.frameId && auxData(c)['isDefault']);
|
|
255
|
-
if (!context)
|
|
256
|
-
throw frameError(frameNotReadyError(frame.info.url), EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
257
|
-
return context.uniqueId;
|
|
331
|
+
const owners = await Promise.all(iframes.map((node) => ownerAttributes(fc, node.frame.id, sessionOf.get(node.frame.parentId ?? ''))));
|
|
332
|
+
const state = initialListingState(page, sessionOf);
|
|
333
|
+
return iframes.map((node, index) => describeFrame(node, index, owners[index] ?? {}, state));
|
|
258
334
|
}
|
|
259
335
|
/**
|
|
260
336
|
* List the page's iframes.
|
|
@@ -279,7 +355,57 @@ async function resolveFrame(fc, query) {
|
|
|
279
355
|
const frames = await discoverFrames(fc);
|
|
280
356
|
const selected = selectFrame(frames.map((frame) => frame.info), query);
|
|
281
357
|
const frame = frames[selected.index];
|
|
282
|
-
|
|
358
|
+
if (!frame.context) {
|
|
359
|
+
throw frameError(frameNotReadyError(frame.info.url), EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
360
|
+
}
|
|
361
|
+
return { frame, uniqueContextId: frame.context.uniqueId };
|
|
362
|
+
}
|
|
363
|
+
/** Chrome's messages when a frame (or the session of its parent) no longer exists */
|
|
364
|
+
const FRAME_GONE_PATTERN = /not found|no frame|no node/i;
|
|
365
|
+
/** How long the frame's parent gets to say whether the frame is still there */
|
|
366
|
+
const OWNER_CHECK_MS = 2_000;
|
|
367
|
+
/**
|
|
368
|
+
* Whether the frame's iframe element is still in its parent.
|
|
369
|
+
*
|
|
370
|
+
* @param conn - Connection the frame was found on
|
|
371
|
+
* @param frame - The frame
|
|
372
|
+
* @returns `attached`, `removed`, or `unknown` when the parent did not answer in time
|
|
373
|
+
* @throws Errors other than Chrome saying the frame is gone (e.g. a lost connection)
|
|
374
|
+
*/
|
|
375
|
+
async function frameOwnerState(conn, frame) {
|
|
376
|
+
try {
|
|
377
|
+
const owner = conn.send('DOM.getFrameOwner', { frameId: frame.frameId }, frame.ownerSession);
|
|
378
|
+
return (await settledWithin(owner, OWNER_CHECK_MS)).settled ? 'attached' : 'unknown';
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
if (!(error instanceof CDPProtocolError) || !FRAME_GONE_PATTERN.test(error.message))
|
|
382
|
+
throw error;
|
|
383
|
+
log.debug(`Frame ${frame.frameId} is gone: ${error.message}`);
|
|
384
|
+
return 'removed';
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* The error for a script whose frame context went away: the page was
|
|
389
|
+
* closed, the frame navigated (its iframe element is still there) or was
|
|
390
|
+
* removed.
|
|
391
|
+
*
|
|
392
|
+
* @param conn - Connection the frame was found on
|
|
393
|
+
* @param page - The session's connection to the page
|
|
394
|
+
* @param frame - The frame
|
|
395
|
+
* @returns Command error (83)
|
|
396
|
+
* @throws Errors of the checks other than Chrome saying the frame is gone
|
|
397
|
+
*/
|
|
398
|
+
export async function frameContextLostError(conn, page, frame) {
|
|
399
|
+
if (!(await pageStillOpen(page))) {
|
|
400
|
+
return frameError(pageClosedDuringEvalError(), EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
401
|
+
}
|
|
402
|
+
const messages = {
|
|
403
|
+
attached: frameNavigatedDuringEvalError,
|
|
404
|
+
removed: frameRemovedDuringEvalError,
|
|
405
|
+
unknown: frameLostDuringEvalError,
|
|
406
|
+
};
|
|
407
|
+
const err = messages[await frameOwnerState(conn, frame)](frame.url);
|
|
408
|
+
return frameError(err, EXIT_CODES.RESOURCE_NOT_FOUND);
|
|
283
409
|
}
|
|
284
410
|
/**
|
|
285
411
|
* Evaluate a `bdg dom eval` script in one iframe, like {@link evaluateScript}
|
|
@@ -288,18 +414,31 @@ async function resolveFrame(fc, query) {
|
|
|
288
414
|
* @param page - The session's connection
|
|
289
415
|
* @param wsUrl - WebSocket URL of the page target
|
|
290
416
|
* @param script - JavaScript expression
|
|
291
|
-
* @param query - Requested frame (index, name/id attribute, or part of the URL)
|
|
417
|
+
* @param query - Requested frame (index, name/id attribute, or part of the name, id or URL)
|
|
292
418
|
* @returns Value, type and the frame's URL
|
|
293
|
-
* @throws CommandError (81/83) when the frame is ambiguous or missing,
|
|
419
|
+
* @throws CommandError (81/83) when the frame is ambiguous or missing, (83)
|
|
420
|
+
* when it navigated or was removed while the script ran, else as evaluateScript
|
|
294
421
|
*/
|
|
295
422
|
export async function evaluateInFrame(page, wsUrl, script, query) {
|
|
296
423
|
return withFrameConnection(page, wsUrl, async (fc) => {
|
|
297
424
|
const { frame, uniqueContextId } = await resolveFrame(fc, query);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
425
|
+
try {
|
|
426
|
+
const result = await evaluateScript(fc.conn, script, {
|
|
427
|
+
...(frame.sessionId && { sessionId: frame.sessionId }),
|
|
428
|
+
uniqueContextId,
|
|
429
|
+
recovery: recoverySender(fc, frame.sessionId),
|
|
430
|
+
});
|
|
431
|
+
return { ...result, frame: frame.info.url };
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
if (!isContextLostError(error))
|
|
435
|
+
throw error;
|
|
436
|
+
throw await frameContextLostError(fc.conn, fc.page, {
|
|
437
|
+
frameId: frame.frameId,
|
|
438
|
+
url: frame.info.url,
|
|
439
|
+
...(frame.ownerSession && { ownerSession: frame.ownerSession }),
|
|
440
|
+
});
|
|
441
|
+
}
|
|
303
442
|
});
|
|
304
443
|
}
|
|
305
444
|
//# sourceMappingURL=frames.js.map
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Positions, sizes and visibility of elements (`bdg dom layout`).
|
|
3
|
+
*
|
|
4
|
+
* One page-side pass per command measures every match: its box in page and
|
|
5
|
+
* viewport coordinates (iframe offsets included), what clips it, whether it
|
|
6
|
+
* is rendered, what covers its center and the styles that decide how it
|
|
7
|
+
* shows. The measurements are classified outside the page
|
|
8
|
+
* ({@link classifyViewportPosition}).
|
|
9
|
+
*/
|
|
10
|
+
import type { CDPConnection } from '../../connection/cdp.js';
|
|
11
|
+
import type { DomLayoutCommand } from '../../ipc/protocol/commands.js';
|
|
12
|
+
import type { LayoutComputedStyle, LayoutResult, PageLayout } from '../../ipc/protocol/domTypes.js';
|
|
13
|
+
import { type ElementGeometry } from './elementGeometry.js';
|
|
14
|
+
/** Matches measured per command (the rest are counted as omitted) */
|
|
15
|
+
export declare const LAYOUT_ELEMENT_LIMIT = 100;
|
|
16
|
+
/**
|
|
17
|
+
* Page-side end of a visible span kept clear of an overlay scrollbar along
|
|
18
|
+
* an edge (16 CSS px wide): overlay scrollbars (macOS, mobile) show for about a
|
|
19
|
+
* second after a scroll and catch hit tests, which then return the scroller.
|
|
20
|
+
* The span ends before the strip when it reaches into it and also shows
|
|
21
|
+
* outside it; without overlay scrollbars along the edge it is unchanged.
|
|
22
|
+
* Arguments: span start and end, the edge, whether overlay scrollbars show there.
|
|
23
|
+
*/
|
|
24
|
+
export declare const CLEAR_OF_SCROLLBAR_JS = "(start, end, edge, overlay) =>\n overlay && end > edge - 16 && edge - 16 > start ? edge - 16 : end";
|
|
25
|
+
/** One element as {@link LAYOUT_JS} measures it. */
|
|
26
|
+
export interface RawElementLayout {
|
|
27
|
+
index: number;
|
|
28
|
+
tag: string;
|
|
29
|
+
element: string;
|
|
30
|
+
text: string;
|
|
31
|
+
context: string;
|
|
32
|
+
geometry: ElementGeometry;
|
|
33
|
+
coveredBy: string | null;
|
|
34
|
+
computed: LayoutComputedStyle;
|
|
35
|
+
}
|
|
36
|
+
/** What {@link LAYOUT_JS} returns. */
|
|
37
|
+
export interface RawLayout {
|
|
38
|
+
/** Elements the selector matched */
|
|
39
|
+
count: number;
|
|
40
|
+
/** Set when at least one element was measured */
|
|
41
|
+
page?: PageLayout;
|
|
42
|
+
elements: RawElementLayout[];
|
|
43
|
+
/** Measured inside a cross-origin iframe: `page` and the coordinates are that frame's */
|
|
44
|
+
crossOriginFrame?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Measure the elements a selector (or cached index) refers to.
|
|
48
|
+
*
|
|
49
|
+
* @param cdp - CDP connection
|
|
50
|
+
* @param params - Selector (and index) or backend node id
|
|
51
|
+
* @returns Layout report
|
|
52
|
+
* @throws CommandError (83) no match, (81) index out of range or invalid
|
|
53
|
+
* selector, (87) the cached element left the page
|
|
54
|
+
*/
|
|
55
|
+
export declare function inspectLayout(cdp: CDPConnection, params: DomLayoutCommand): Promise<LayoutResult>;
|
|
56
|
+
/**
|
|
57
|
+
* Turn page-side measurements into the layout report: rounded page and
|
|
58
|
+
* viewport coordinates, viewport position and text preview per element.
|
|
59
|
+
*
|
|
60
|
+
* @param raw - Measurements with at least one element
|
|
61
|
+
* @param params - Request (selector and index)
|
|
62
|
+
* @returns Layout report
|
|
63
|
+
*/
|
|
64
|
+
export declare function buildLayoutResult(raw: RawLayout & {
|
|
65
|
+
page: PageLayout;
|
|
66
|
+
}, params: Pick<DomLayoutCommand, 'selector' | 'index'>): LayoutResult;
|
|
67
|
+
//# sourceMappingURL=layout.d.ts.map
|