"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WindowCdpTransport = exports.WindowBidiTransport = void 0;
const log_js_1 = require("../utils/log.js");
const mapperTabPage_js_1 = require("./mapperTabPage.js");
class WindowBidiTransport {
static LOGGER_PREFIX_RECV = `${log_js_1.LogType.bidi}:RECV ◂`;
static LOGGER_PREFIX_SEND = `${log_js_1.LogType.bidi}:SEND ▸`;
#onMessage = null;
constructor() {
window.onBidiMessage = (message) => {
(0, mapperTabPage_js_1.log)(WindowBidiTransport.LOGGER_PREFIX_RECV, message);
try {
const command = WindowBidiTransport.#parseBidiMessage(message);
this.#onMessage?.call(null, command);
}
catch (e) {
const error = e instanceof Error ? e : new Error(e);
// Transport-level error does not provide channel.
this.#respondWithError(message, "invalid argument" /* ErrorCode.InvalidArgument */, error, null);
}
};
}
setOnMessage(onMessage) {
this.#onMessage = onMessage;
}
sendMessage(message) {
(0, mapperTabPage_js_1.log)(WindowBidiTransport.LOGGER_PREFIX_SEND, message);
const json = JSON.stringify(message);
window.sendBidiResponse(json);
}
close() {
this.#onMessage = null;
window.onBidiMessage = null;
}
#respondWithError(plainCommandData, errorCode, error, channel) {
const errorResponse = WindowBidiTransport.#getErrorResponse(plainCommandData, errorCode, error);
if (channel) {
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(message, errorCode, error) {
// 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 command = JSON.parse(message);
if (WindowBidiTransport.#getJsonType(command) === 'object' &&
'id' in command) {
messageId = command.id;
}
}
catch { }
return {
type: 'error',
id: messageId,
error: errorCode,
message: error.message,
};
}
static #parseBidiMessage(message) {
let command;
try {
command = JSON.parse(message);
}
catch {
throw new Error('Cannot parse data as JSON');
}
const type = WindowBidiTransport.#getJsonType(command);
if (type !== 'object') {
throw new Error(`Expected JSON object but got ${type}`);
}
// Extract and validate id, method and params.
const { id, method, params } = command;
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 = command.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 };
}
}
exports.WindowBidiTransport = WindowBidiTransport;
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;
}
}
exports.WindowCdpTransport = WindowCdpTransport;
//# sourceMappingURL=Transport.js.map |