122 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * Copyright 2023 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.
 | |
|  *
 | |
|  */
 | |
| import { uuidv4 } from '../../../utils/uuid.js';
 | |
| import { ChannelProxy } from './ChannelProxy.js';
 | |
| /**
 | |
|  * BiDi IDs are generated by the server and are unique within contexts.
 | |
|  *
 | |
|  * CDP preload script IDs are generated by the client and are unique
 | |
|  * within sessions.
 | |
|  *
 | |
|  * The mapping between BiDi and CDP preload script IDs is 1:many.
 | |
|  * BiDi IDs are needed by the mapper to keep track of potential multiple CDP IDs
 | |
|  * in the client.
 | |
|  */
 | |
| export class PreloadScript {
 | |
|     /** BiDi ID, an automatically generated UUID. */
 | |
|     #id = uuidv4();
 | |
|     /** CDP preload scripts. */
 | |
|     #cdpPreloadScripts = [];
 | |
|     /** The script itself, in a format expected by the spec i.e. a function. */
 | |
|     #functionDeclaration;
 | |
|     /** Targets, in which the preload script is initialized. */
 | |
|     #targetIds = new Set();
 | |
|     /** Channels to be added as arguments to functionDeclaration. */
 | |
|     #channels;
 | |
|     /** The script sandbox / world name. */
 | |
|     #sandbox;
 | |
|     /** The browsing contexts to execute the preload scripts in, if any. */
 | |
|     #contexts;
 | |
|     get id() {
 | |
|         return this.#id;
 | |
|     }
 | |
|     get targetIds() {
 | |
|         return this.#targetIds;
 | |
|     }
 | |
|     constructor(params, logger) {
 | |
|         this.#channels =
 | |
|             params.arguments?.map((a) => new ChannelProxy(a.value, logger)) ?? [];
 | |
|         this.#functionDeclaration = params.functionDeclaration;
 | |
|         this.#sandbox = params.sandbox;
 | |
|         this.#contexts = params.contexts;
 | |
|     }
 | |
|     /** Channels of the preload script. */
 | |
|     get channels() {
 | |
|         return this.#channels;
 | |
|     }
 | |
|     /** Contexts of the preload script, if any */
 | |
|     get contexts() {
 | |
|         return this.#contexts;
 | |
|     }
 | |
|     /**
 | |
|      * String to be evaluated. Wraps user-provided function so that the following
 | |
|      * steps are run:
 | |
|      * 1. Create channels.
 | |
|      * 2. Store the created channels in window.
 | |
|      * 3. Call the user-provided function with channels as arguments.
 | |
|      */
 | |
|     #getEvaluateString() {
 | |
|         const channelsArgStr = `[${this.channels
 | |
|             .map((c) => c.getEvalInWindowStr())
 | |
|             .join(', ')}]`;
 | |
|         return `(()=>{(${this.#functionDeclaration})(...${channelsArgStr})})()`;
 | |
|     }
 | |
|     /**
 | |
|      * Adds the script to the given CDP targets by calling the
 | |
|      * `Page.addScriptToEvaluateOnNewDocument` command.
 | |
|      */
 | |
|     async initInTargets(cdpTargets, runImmediately) {
 | |
|         await Promise.all(Array.from(cdpTargets).map((cdpTarget) => this.initInTarget(cdpTarget, runImmediately)));
 | |
|     }
 | |
|     /**
 | |
|      * Adds the script to the given CDP target by calling the
 | |
|      * `Page.addScriptToEvaluateOnNewDocument` command.
 | |
|      */
 | |
|     async initInTarget(cdpTarget, runImmediately) {
 | |
|         const addCdpPreloadScriptResult = await cdpTarget.cdpClient.sendCommand('Page.addScriptToEvaluateOnNewDocument', {
 | |
|             source: this.#getEvaluateString(),
 | |
|             worldName: this.#sandbox,
 | |
|             runImmediately,
 | |
|         });
 | |
|         this.#cdpPreloadScripts.push({
 | |
|             target: cdpTarget,
 | |
|             preloadScriptId: addCdpPreloadScriptResult.identifier,
 | |
|         });
 | |
|         this.#targetIds.add(cdpTarget.id);
 | |
|     }
 | |
|     /**
 | |
|      * Removes this script from all CDP targets.
 | |
|      */
 | |
|     async remove() {
 | |
|         await Promise.all([
 | |
|             this.#cdpPreloadScripts.map(async (cdpPreloadScript) => {
 | |
|                 const cdpTarget = cdpPreloadScript.target;
 | |
|                 const cdpPreloadScriptId = cdpPreloadScript.preloadScriptId;
 | |
|                 return await cdpTarget.cdpClient.sendCommand('Page.removeScriptToEvaluateOnNewDocument', {
 | |
|                     identifier: cdpPreloadScriptId,
 | |
|                 });
 | |
|             }),
 | |
|         ]);
 | |
|     }
 | |
|     /** Removes the provided cdp target from the list of cdp preload scripts. */
 | |
|     dispose(cdpTargetId) {
 | |
|         this.#cdpPreloadScripts = this.#cdpPreloadScripts.filter((cdpPreloadScript) => cdpPreloadScript.target?.id !== cdpTargetId);
 | |
|         this.#targetIds.delete(cdpTargetId);
 | |
|     }
 | |
| }
 | |
| //# sourceMappingURL=PreloadScript.js.map
 | 
