"use strict";
/**
 * Copyright 2021 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.
 *
 * @license
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const Parser = __importStar(require("../protocol-parser/protocol-parser.js"));
const protocol_1 = require("../protocol/protocol");
const bidiMapper_js_1 = require("../bidiMapper/bidiMapper.js");
const cdpConnection_js_1 = require("../cdp/cdpConnection.js");
const log_js_1 = require("../utils/log.js");
const mapperTabPage_js_1 = require("./mapperTabPage.js");
// Initiate `setSelfTargetId` as soon as possible to prevent race condition.
const waitSelfTargetIdPromise = waitSelfTargetId();
void (async () => {
    (0, mapperTabPage_js_1.generatePage)();
    // Needed to filter out info related to BiDi target.
    const selfTargetId = await waitSelfTargetIdPromise;
    const bidiServer = await createBidiServer(selfTargetId);
    (0, mapperTabPage_js_1.log)(log_js_1.LogType.system, 'Launched');
    bidiServer.emitOutgoingMessage(bidiMapper_js_1.OutgoingBidiMessage.createResolved({ launched: true }, null));
})();
function createCdpConnection() {
    /**
     * A CdpTransport implementation that uses the window.cdp bindings
     * injected by Target.exposeDevToolsProtocol.
     */
    class WindowCdpTransport {
        #onMessage = null;
        constructor() {
            window.cdp.onmessage = (message) => {
                this.#onMessage?.call(null, message);
            };
        }
        setOnMessage(onMessage) {
            this.#onMessage = onMessage;
        }
        sendMessage(message) {
            window.cdp.send(message);
        }
        close() {
            this.#onMessage = null;
            window.cdp.onmessage = null;
        }
    }
    return new cdpConnection_js_1.CdpConnection(new WindowCdpTransport(), mapperTabPage_js_1.log);
}
function createBidiServer(selfTargetId) {
    class WindowBidiTransport {
        #onMessage = null;
        constructor() {
            window.onBidiMessage = (messageStr) => {
                (0, mapperTabPage_js_1.log)(`${log_js_1.LogType.bidi}:RECV ◂`, messageStr);
                let messageObject;
                try {
                    messageObject = WindowBidiTransport.#parseBidiMessage(messageStr);
                }
                catch (e) {
                    // Transport-level error does not provide channel.
                    this.#respondWithError(messageStr, protocol_1.Message.ErrorCode.InvalidArgument, e.message, null);
                    return;
                }
                this.#onMessage?.call(null, messageObject);
            };
        }
        setOnMessage(onMessage) {
            this.#onMessage = onMessage;
        }
        sendMessage(message) {
            const messageStr = JSON.stringify(message);
            window.sendBidiResponse(messageStr);
            (0, mapperTabPage_js_1.log)(`${log_js_1.LogType.bidi}:SEND ▸`, messageStr);
        }
        close() {
            this.#onMessage = null;
            window.onBidiMessage = null;
        }
        #respondWithError(plainCommandData, errorCode, errorMessage, channel) {
            const errorResponse = WindowBidiTransport.#getErrorResponse(plainCommandData, errorCode, errorMessage);
            if (channel) {
                // XXX: get rid of any, same code existed in BidiServer.
                this.sendMessage({
                    ...errorResponse,
                    channel,
                });
            }
            else {
                this.sendMessage(errorResponse);
            }
        }
        static #getJsonType(value) {
            if (value === null) {
                return 'null';
            }
            if (Array.isArray(value)) {
                return 'array';
            }
            return typeof value;
        }
        static #getErrorResponse(messageStr, errorCode, errorMessage) {
            // XXX: this is bizarre per spec. We reparse the payload and
            // extract the ID, regardless of what kind of value it was.
            let messageId;
            try {
                const messageObj = JSON.parse(messageStr);
                if (WindowBidiTransport.#getJsonType(messageObj) === 'object' &&
                    'id' in messageObj) {
                    messageId = messageObj.id;
                }
            }
            catch { }
            return {
                id: messageId,
                error: errorCode,
                message: errorMessage,
                // XXX: optional stacktrace field.
            };
        }
        static #parseBidiMessage(messageStr) {
            let messageObject;
            try {
                messageObject = JSON.parse(messageStr);
            }
            catch {
                throw new Error('Cannot parse data as JSON');
            }
            const parsedType = WindowBidiTransport.#getJsonType(messageObject);
            if (parsedType !== 'object') {
                throw new Error(`Expected JSON object but got ${parsedType}`);
            }
            // Extract and validate id, method and params.
            const { id, method, params } = messageObject;
            const idType = WindowBidiTransport.#getJsonType(id);
            if (idType !== 'number' || !Number.isInteger(id) || id < 0) {
                // TODO: should uint64_t be the upper limit?
                // https://tools.ietf.org/html/rfc7049#section-2.1
                throw new Error(`Expected unsigned integer but got ${idType}`);
            }
            const methodType = WindowBidiTransport.#getJsonType(method);
            if (methodType !== 'string') {
                throw new Error(`Expected string method but got ${methodType}`);
            }
            const paramsType = WindowBidiTransport.#getJsonType(params);
            if (paramsType !== 'object') {
                throw new Error(`Expected object params but got ${paramsType}`);
            }
            let channel = messageObject.channel;
            if (channel !== undefined) {
                const channelType = WindowBidiTransport.#getJsonType(channel);
                if (channelType !== 'string') {
                    throw new Error(`Expected string channel but got ${channelType}`);
                }
                // Empty string channel is considered as no channel provided.
                if (channel === '') {
                    channel = undefined;
                }
            }
            return { id, method, params, channel };
        }
    }
    return bidiMapper_js_1.BidiServer.createAndStart(new WindowBidiTransport(), createCdpConnection(), selfTargetId, new BidiParserImpl(), mapperTabPage_js_1.log);
}
class BidiParserImpl {
    parseAddPreloadScriptParams(params) {
        return Parser.Script.parseAddPreloadScriptParams(params);
    }
    parseRemovePreloadScriptParams(params) {
        return Parser.Script.parseRemovePreloadScriptParams(params);
    }
    parseGetRealmsParams(params) {
        return Parser.Script.parseGetRealmsParams(params);
    }
    parseCallFunctionParams(params) {
        return Parser.Script.parseCallFunctionParams(params);
    }
    parseEvaluateParams(params) {
        return Parser.Script.parseEvaluateParams(params);
    }
    parseDisownParams(params) {
        return Parser.Script.parseDisownParams(params);
    }
    parseSendCommandParams(params) {
        return Parser.Cdp.parseSendCommandParams(params);
    }
    parseGetSessionParams(params) {
        return Parser.Cdp.parseGetSessionParams(params);
    }
    parseSubscribeParams(params) {
        return Parser.Session.parseSubscribeParams(params);
    }
    parseNavigateParams(params) {
        return Parser.BrowsingContext.parseNavigateParams(params);
    }
    parseReloadParams(params) {
        return Parser.BrowsingContext.parseReloadParams(params);
    }
    parseGetTreeParams(params) {
        return Parser.BrowsingContext.parseGetTreeParams(params);
    }
    parseCreateParams(params) {
        return Parser.BrowsingContext.parseCreateParams(params);
    }
    parseCloseParams(params) {
        return Parser.BrowsingContext.parseCloseParams(params);
    }
    parseCaptureScreenshotParams(params) {
        return Parser.BrowsingContext.parseCaptureScreenshotParams(params);
    }
    parsePrintParams(params) {
        return Parser.BrowsingContext.parsePrintParams(params);
    }
    parsePerformActionsParams(params) {
        return Parser.Input.parsePerformActionsParams(params);
    }
    parseReleaseActionsParams(params) {
        return Parser.Input.parseReleaseActionsParams(params);
    }
    parseSetViewportParams(params) {
        return Parser.BrowsingContext.parseSetViewportParams(params);
    }
}
// Needed to filter out info related to BiDi target.
async function waitSelfTargetId() {
    return new Promise((resolve) => {
        window.setSelfTargetId = (targetId) => {
            (0, mapperTabPage_js_1.log)(log_js_1.LogType.system, 'Current target ID:', targetId);
            resolve(targetId);
        };
    });
}
//# sourceMappingURL=bidiTab.js.map