140 lines
6.6 KiB
JavaScript
140 lines
6.6 KiB
JavaScript
"use strict";
|
|
/**
|
|
* Copyright 2024 Google LLC.
|
|
* Copyright (c) Microsoft Corporation.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.WindowRealm = void 0;
|
|
const protocol_js_1 = require("../../../protocol/protocol.js");
|
|
const Realm_js_1 = require("./Realm.js");
|
|
const SharedId_js_1 = require("./SharedId.js");
|
|
class WindowRealm extends Realm_js_1.Realm {
|
|
#browsingContextId;
|
|
#browsingContextStorage;
|
|
sandbox;
|
|
constructor(browsingContextId, browsingContextStorage, cdpClient, eventManager, executionContextId, logger, origin, realmId, realmStorage, sandbox) {
|
|
super(cdpClient, eventManager, executionContextId, logger, origin, realmId, realmStorage);
|
|
this.#browsingContextId = browsingContextId;
|
|
this.#browsingContextStorage = browsingContextStorage;
|
|
this.sandbox = sandbox;
|
|
this.initialize();
|
|
}
|
|
#getBrowsingContextId(navigableId) {
|
|
const maybeBrowsingContext = this.#browsingContextStorage
|
|
.getAllContexts()
|
|
.find((context) => context.navigableId === navigableId);
|
|
return maybeBrowsingContext?.id ?? 'UNKNOWN';
|
|
}
|
|
get browsingContext() {
|
|
return this.#browsingContextStorage.getContext(this.#browsingContextId);
|
|
}
|
|
get associatedBrowsingContexts() {
|
|
return [this.browsingContext];
|
|
}
|
|
get realmType() {
|
|
return 'window';
|
|
}
|
|
get realmInfo() {
|
|
return {
|
|
...this.baseInfo,
|
|
type: this.realmType,
|
|
context: this.#browsingContextId,
|
|
sandbox: this.sandbox,
|
|
};
|
|
}
|
|
get source() {
|
|
return {
|
|
realm: this.realmId,
|
|
context: this.browsingContext.id,
|
|
};
|
|
}
|
|
serializeForBiDi(deepSerializedValue, internalIdMap) {
|
|
const bidiValue = deepSerializedValue.value;
|
|
if (deepSerializedValue.type === 'node' && bidiValue !== undefined) {
|
|
if (Object.hasOwn(bidiValue, 'backendNodeId')) {
|
|
let navigableId = this.browsingContext.navigableId ?? 'UNKNOWN';
|
|
if (Object.hasOwn(bidiValue, 'loaderId')) {
|
|
// `loaderId` should be always there after ~2024-03-05, when
|
|
// https://crrev.com/c/5116240 reaches stable.
|
|
// TODO: remove the check after the date.
|
|
navigableId = bidiValue.loaderId;
|
|
delete bidiValue['loaderId'];
|
|
}
|
|
deepSerializedValue.sharedId =
|
|
(0, SharedId_js_1.getSharedId)(this.#getBrowsingContextId(navigableId), navigableId, bidiValue.backendNodeId);
|
|
delete bidiValue['backendNodeId'];
|
|
}
|
|
if (Object.hasOwn(bidiValue, 'children')) {
|
|
for (const i in bidiValue.children) {
|
|
bidiValue.children[i] = this.serializeForBiDi(bidiValue.children[i], internalIdMap);
|
|
}
|
|
}
|
|
if (Object.hasOwn(bidiValue, 'shadowRoot') &&
|
|
bidiValue.shadowRoot !== null) {
|
|
bidiValue.shadowRoot = this.serializeForBiDi(bidiValue.shadowRoot, internalIdMap);
|
|
}
|
|
// `namespaceURI` can be is either `null` or non-empty string.
|
|
if (bidiValue.namespaceURI === '') {
|
|
bidiValue.namespaceURI = null;
|
|
}
|
|
}
|
|
return super.serializeForBiDi(deepSerializedValue, internalIdMap);
|
|
}
|
|
async deserializeForCdp(localValue) {
|
|
if ('sharedId' in localValue && localValue.sharedId) {
|
|
const parsedSharedId = (0, SharedId_js_1.parseSharedId)(localValue.sharedId);
|
|
if (parsedSharedId === null) {
|
|
throw new protocol_js_1.NoSuchNodeException(`SharedId "${localValue.sharedId}" was not found.`);
|
|
}
|
|
const { documentId, backendNodeId } = parsedSharedId;
|
|
// TODO: add proper validation if the element is accessible from the current realm.
|
|
if (this.browsingContext.navigableId !== documentId) {
|
|
throw new protocol_js_1.NoSuchNodeException(`SharedId "${localValue.sharedId}" belongs to different document. Current document is ${this.browsingContext.navigableId}.`);
|
|
}
|
|
try {
|
|
const { object } = await this.cdpClient.sendCommand('DOM.resolveNode', {
|
|
backendNodeId,
|
|
executionContextId: this.executionContextId,
|
|
});
|
|
// TODO(#375): Release `obj.object.objectId` after using.
|
|
return { objectId: object.objectId };
|
|
}
|
|
catch (error) {
|
|
// Heuristic to detect "no such node" exception. Based on the specific
|
|
// CDP implementation.
|
|
if (error.code === -32000 /* CdpErrorConstants.GENERIC_ERROR */ &&
|
|
error.message === 'No node with given id found') {
|
|
throw new protocol_js_1.NoSuchNodeException(`SharedId "${localValue.sharedId}" was not found.`);
|
|
}
|
|
throw new protocol_js_1.UnknownErrorException(error.message, error.stack);
|
|
}
|
|
}
|
|
return await super.deserializeForCdp(localValue);
|
|
}
|
|
async evaluate(expression, awaitPromise, resultOwnership, serializationOptions, userActivation, includeCommandLineApi) {
|
|
await this.#browsingContextStorage
|
|
.getContext(this.#browsingContextId)
|
|
.targetUnblockedOrThrow();
|
|
return await super.evaluate(expression, awaitPromise, resultOwnership, serializationOptions, userActivation, includeCommandLineApi);
|
|
}
|
|
async callFunction(functionDeclaration, awaitPromise, thisLocalValue, argumentsLocalValues, resultOwnership, serializationOptions, userActivation) {
|
|
await this.#browsingContextStorage
|
|
.getContext(this.#browsingContextId)
|
|
.targetUnblockedOrThrow();
|
|
return await super.callFunction(functionDeclaration, awaitPromise, thisLocalValue, argumentsLocalValues, resultOwnership, serializationOptions, userActivation);
|
|
}
|
|
}
|
|
exports.WindowRealm = WindowRealm;
|
|
//# sourceMappingURL=WindowRealm.js.map
|