Path: blob/main/client/lib/FrozenFrameEnvironment.ts
1028 views
import inspectInstanceProperties from 'awaited-dom/base/inspectInstanceProperties';1import * as Util from 'util';2import StateMachine from 'awaited-dom/base/StateMachine';3import AwaitedPath from 'awaited-dom/base/AwaitedPath';4import { IRequestInit } from 'awaited-dom/base/interfaces/official';5import SuperDocument from 'awaited-dom/impl/super-klasses/SuperDocument';6import Storage from 'awaited-dom/impl/official-klasses/Storage';7import CSSStyleDeclaration from 'awaited-dom/impl/official-klasses/CSSStyleDeclaration';8import {9createCSSStyleDeclaration,10createResponse,11createStorage,12createSuperDocument,13} from 'awaited-dom/impl/create';14import Request from 'awaited-dom/impl/official-klasses/Request';15import Response from 'awaited-dom/impl/official-klasses/Response';16import { IElementIsolate, INodeIsolate } from 'awaited-dom/base/interfaces/isolate';17import { INodeVisibility } from '@secret-agent/interfaces/INodeVisibility';18import {19getComputedStyleFnName,20getComputedVisibilityFnName,21} from '@secret-agent/interfaces/jsPathFnNames';22import IJsPathResult from '@secret-agent/interfaces/IJsPathResult';23import IAwaitedOptions from '../interfaces/IAwaitedOptions';24import RequestGenerator, { getRequestIdOrUrl } from './Request';25import CookieStorage, { createCookieStorage } from './CookieStorage';26import Agent from './Agent';27import CoreFrameEnvironment from './CoreFrameEnvironment';28import FrozenTab from './FrozenTab';29import * as AwaitedHandler from './SetupAwaitedHandler';3031const { getState, setState } = StateMachine<FrozenFrameEnvironment, IState>();32const awaitedPathState = StateMachine<33any,34{ awaitedPath: AwaitedPath; awaitedOptions: IAwaitedOptions }35>();3637export interface IState {38secretAgent: Agent;39tab: FrozenTab;40coreFrame: Promise<CoreFrameEnvironment>;41prefetchedJsPaths: Promise<Map<string, IJsPathResult>>;42}4344const propertyKeys: (keyof FrozenFrameEnvironment)[] = [45'frameId',46'url',47'name',48'parentFrameId',49'cookieStorage',50'localStorage',51'sessionStorage',52'document',53'Request',54];5556export default class FrozenFrameEnvironment {57constructor(58secretAgent: Agent,59tab: FrozenTab,60coreFrame: Promise<CoreFrameEnvironment>,61prefetchedJsPaths: Promise<IJsPathResult[]>,62) {63setState(this, {64secretAgent,65tab,66coreFrame,67prefetchedJsPaths: prefetchedJsPaths.then(x => {68const resultMap = new Map<string, IJsPathResult>();69for (let i = 0; i < x.length; i += 1) {70const result = x[i];71result.index = i;72resultMap.set(JSON.stringify(result.jsPath), result);73}74return resultMap;75}),76});77}7879public get isMainFrame(): Promise<boolean> {80return this.parentFrameId.then(x => !x);81}8283public get frameId(): Promise<number> {84return getCoreFrameEnvironment(this).then(x => x.frameId);85}8687public get url(): Promise<string> {88return getCoreFrameEnvironment(this).then(x => x.getUrl());89}9091public get name(): Promise<string> {92return getCoreFrameEnvironment(this)93.then(x => x.getFrameMeta())94.then(x => x.name);95}9697public get parentFrameId(): Promise<number | null> {98return getCoreFrameEnvironment(this)99.then(x => x.getFrameMeta())100.then(x => x.parentFrameId);101}102103public get cookieStorage(): CookieStorage {104return createCookieStorage(getCoreFrameEnvironment(this));105}106107public get document(): SuperDocument {108const awaitedPath = new AwaitedPath(null, 'document');109const awaitedOptions = { ...getState(this) };110return createSuperDocument<IAwaitedOptions>(awaitedPath, awaitedOptions) as SuperDocument;111}112113public get localStorage(): Storage {114const awaitedPath = new AwaitedPath(null, 'localStorage');115const awaitedOptions = { ...getState(this) };116return createStorage<IAwaitedOptions>(awaitedPath, awaitedOptions) as Storage;117}118119public get sessionStorage(): Storage {120const awaitedPath = new AwaitedPath(null, 'sessionStorage');121const awaitedOptions = { ...getState(this) };122return createStorage<IAwaitedOptions>(awaitedPath, awaitedOptions) as Storage;123}124125public get Request(): typeof Request {126return RequestGenerator(getCoreFrameEnvironment(this));127}128129// METHODS130131public async fetch(request: Request | string, init?: IRequestInit): Promise<Response> {132const requestInput = await getRequestIdOrUrl(request);133const coreFrame = await getCoreFrameEnvironment(this);134const nodePointer = await coreFrame.fetch(requestInput, init);135136const awaitedPath = new AwaitedPath(null).withNodeId(null, nodePointer.id);137return createResponse(awaitedPath, { ...getState(this) });138}139140public async getComputedStyle(141element: IElementIsolate,142pseudoElement?: string,143): Promise<CSSStyleDeclaration & { [style: string]: string }> {144const { awaitedPath, coreFrame, awaitedOptions } = await AwaitedHandler.getAwaitedState(145awaitedPathState,146element,147);148const newPath = awaitedPath.addMethod(element, getComputedStyleFnName, pseudoElement);149const result = await AwaitedHandler.execJsPath<Record<string, string>>(150coreFrame,151awaitedOptions,152newPath.toJSON(),153);154const declaration = createCSSStyleDeclaration<IAwaitedOptions>(newPath, awaitedOptions);155const attributes = AwaitedHandler.cleanResult(156awaitedPathState,157declaration,158result,159new Error().stack,160);161Object.assign(declaration, attributes);162return declaration;163}164165public async getComputedVisibility(node: INodeIsolate): Promise<INodeVisibility> {166if (!node) return { isVisible: false, nodeExists: false };167return await AwaitedHandler.delegate.runMethod<INodeVisibility, INodeIsolate>(168awaitedPathState,169node,170getComputedVisibilityFnName,171[],172);173}174175// @deprecated 2021-04-30: Replaced with getComputedVisibility176public async isElementVisible(element: IElementIsolate): Promise<boolean> {177return await this.getComputedVisibility(element as any).then(x => x.isVisible);178}179180public async getJsValue<T>(path: string): Promise<T> {181const coreFrame = await getCoreFrameEnvironment(this);182return coreFrame.getJsValue<T>(path);183}184185public toJSON(): any {186// return empty so we can avoid infinite "stringifying" in jest187return {188type: this.constructor.name,189};190}191192public [Util.inspect.custom](): any {193return inspectInstanceProperties(this, propertyKeys as any);194}195}196197export function getFrameState(object: any): IState {198return getState(object);199}200201export function getCoreFrameEnvironment(202frameEnvironment: FrozenFrameEnvironment,203): Promise<CoreFrameEnvironment> {204return getState(frameEnvironment).coreFrame;205}206207208