bidiTab.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. "use strict";
  2. /**
  3. * Copyright 2021 Google LLC.
  4. * Copyright (c) Microsoft Corporation.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * @license
  19. */
  20. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  21. if (k2 === undefined) k2 = k;
  22. var desc = Object.getOwnPropertyDescriptor(m, k);
  23. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  24. desc = { enumerable: true, get: function() { return m[k]; } };
  25. }
  26. Object.defineProperty(o, k2, desc);
  27. }) : (function(o, m, k, k2) {
  28. if (k2 === undefined) k2 = k;
  29. o[k2] = m[k];
  30. }));
  31. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  32. Object.defineProperty(o, "default", { enumerable: true, value: v });
  33. }) : function(o, v) {
  34. o["default"] = v;
  35. });
  36. var __importStar = (this && this.__importStar) || function (mod) {
  37. if (mod && mod.__esModule) return mod;
  38. var result = {};
  39. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  40. __setModuleDefault(result, mod);
  41. return result;
  42. };
  43. Object.defineProperty(exports, "__esModule", { value: true });
  44. const Parser = __importStar(require("../protocol-parser/protocol-parser.js"));
  45. const protocol_1 = require("../protocol/protocol");
  46. const bidiMapper_js_1 = require("../bidiMapper/bidiMapper.js");
  47. const cdpConnection_js_1 = require("../cdp/cdpConnection.js");
  48. const log_js_1 = require("../utils/log.js");
  49. const mapperTabPage_js_1 = require("./mapperTabPage.js");
  50. // Initiate `setSelfTargetId` as soon as possible to prevent race condition.
  51. const waitSelfTargetIdPromise = waitSelfTargetId();
  52. void (async () => {
  53. (0, mapperTabPage_js_1.generatePage)();
  54. // Needed to filter out info related to BiDi target.
  55. const selfTargetId = await waitSelfTargetIdPromise;
  56. const bidiServer = await createBidiServer(selfTargetId);
  57. (0, mapperTabPage_js_1.log)(log_js_1.LogType.system, 'Launched');
  58. bidiServer.emitOutgoingMessage(bidiMapper_js_1.OutgoingBidiMessage.createResolved({ launched: true }, null));
  59. })();
  60. function createCdpConnection() {
  61. /**
  62. * A CdpTransport implementation that uses the window.cdp bindings
  63. * injected by Target.exposeDevToolsProtocol.
  64. */
  65. class WindowCdpTransport {
  66. #onMessage = null;
  67. constructor() {
  68. window.cdp.onmessage = (message) => {
  69. this.#onMessage?.call(null, message);
  70. };
  71. }
  72. setOnMessage(onMessage) {
  73. this.#onMessage = onMessage;
  74. }
  75. sendMessage(message) {
  76. window.cdp.send(message);
  77. }
  78. close() {
  79. this.#onMessage = null;
  80. window.cdp.onmessage = null;
  81. }
  82. }
  83. return new cdpConnection_js_1.CdpConnection(new WindowCdpTransport(), mapperTabPage_js_1.log);
  84. }
  85. function createBidiServer(selfTargetId) {
  86. class WindowBidiTransport {
  87. #onMessage = null;
  88. constructor() {
  89. window.onBidiMessage = (messageStr) => {
  90. (0, mapperTabPage_js_1.log)(`${log_js_1.LogType.bidi}:RECV ◂`, messageStr);
  91. let messageObject;
  92. try {
  93. messageObject = WindowBidiTransport.#parseBidiMessage(messageStr);
  94. }
  95. catch (e) {
  96. // Transport-level error does not provide channel.
  97. this.#respondWithError(messageStr, protocol_1.Message.ErrorCode.InvalidArgument, e.message, null);
  98. return;
  99. }
  100. this.#onMessage?.call(null, messageObject);
  101. };
  102. }
  103. setOnMessage(onMessage) {
  104. this.#onMessage = onMessage;
  105. }
  106. sendMessage(message) {
  107. const messageStr = JSON.stringify(message);
  108. window.sendBidiResponse(messageStr);
  109. (0, mapperTabPage_js_1.log)(`${log_js_1.LogType.bidi}:SEND ▸`, messageStr);
  110. }
  111. close() {
  112. this.#onMessage = null;
  113. window.onBidiMessage = null;
  114. }
  115. #respondWithError(plainCommandData, errorCode, errorMessage, channel) {
  116. const errorResponse = WindowBidiTransport.#getErrorResponse(plainCommandData, errorCode, errorMessage);
  117. if (channel) {
  118. // XXX: get rid of any, same code existed in BidiServer.
  119. this.sendMessage({
  120. ...errorResponse,
  121. channel,
  122. });
  123. }
  124. else {
  125. this.sendMessage(errorResponse);
  126. }
  127. }
  128. static #getJsonType(value) {
  129. if (value === null) {
  130. return 'null';
  131. }
  132. if (Array.isArray(value)) {
  133. return 'array';
  134. }
  135. return typeof value;
  136. }
  137. static #getErrorResponse(messageStr, errorCode, errorMessage) {
  138. // XXX: this is bizarre per spec. We reparse the payload and
  139. // extract the ID, regardless of what kind of value it was.
  140. let messageId;
  141. try {
  142. const messageObj = JSON.parse(messageStr);
  143. if (WindowBidiTransport.#getJsonType(messageObj) === 'object' &&
  144. 'id' in messageObj) {
  145. messageId = messageObj.id;
  146. }
  147. }
  148. catch { }
  149. return {
  150. id: messageId,
  151. error: errorCode,
  152. message: errorMessage,
  153. // XXX: optional stacktrace field.
  154. };
  155. }
  156. static #parseBidiMessage(messageStr) {
  157. let messageObject;
  158. try {
  159. messageObject = JSON.parse(messageStr);
  160. }
  161. catch {
  162. throw new Error('Cannot parse data as JSON');
  163. }
  164. const parsedType = WindowBidiTransport.#getJsonType(messageObject);
  165. if (parsedType !== 'object') {
  166. throw new Error(`Expected JSON object but got ${parsedType}`);
  167. }
  168. // Extract and validate id, method and params.
  169. const { id, method, params } = messageObject;
  170. const idType = WindowBidiTransport.#getJsonType(id);
  171. if (idType !== 'number' || !Number.isInteger(id) || id < 0) {
  172. // TODO: should uint64_t be the upper limit?
  173. // https://tools.ietf.org/html/rfc7049#section-2.1
  174. throw new Error(`Expected unsigned integer but got ${idType}`);
  175. }
  176. const methodType = WindowBidiTransport.#getJsonType(method);
  177. if (methodType !== 'string') {
  178. throw new Error(`Expected string method but got ${methodType}`);
  179. }
  180. const paramsType = WindowBidiTransport.#getJsonType(params);
  181. if (paramsType !== 'object') {
  182. throw new Error(`Expected object params but got ${paramsType}`);
  183. }
  184. let channel = messageObject.channel;
  185. if (channel !== undefined) {
  186. const channelType = WindowBidiTransport.#getJsonType(channel);
  187. if (channelType !== 'string') {
  188. throw new Error(`Expected string channel but got ${channelType}`);
  189. }
  190. // Empty string channel is considered as no channel provided.
  191. if (channel === '') {
  192. channel = undefined;
  193. }
  194. }
  195. return { id, method, params, channel };
  196. }
  197. }
  198. return bidiMapper_js_1.BidiServer.createAndStart(new WindowBidiTransport(), createCdpConnection(), selfTargetId, new BidiParserImpl(), mapperTabPage_js_1.log);
  199. }
  200. class BidiParserImpl {
  201. parseAddPreloadScriptParams(params) {
  202. return Parser.Script.parseAddPreloadScriptParams(params);
  203. }
  204. parseRemovePreloadScriptParams(params) {
  205. return Parser.Script.parseRemovePreloadScriptParams(params);
  206. }
  207. parseGetRealmsParams(params) {
  208. return Parser.Script.parseGetRealmsParams(params);
  209. }
  210. parseCallFunctionParams(params) {
  211. return Parser.Script.parseCallFunctionParams(params);
  212. }
  213. parseEvaluateParams(params) {
  214. return Parser.Script.parseEvaluateParams(params);
  215. }
  216. parseDisownParams(params) {
  217. return Parser.Script.parseDisownParams(params);
  218. }
  219. parseSendCommandParams(params) {
  220. return Parser.Cdp.parseSendCommandParams(params);
  221. }
  222. parseGetSessionParams(params) {
  223. return Parser.Cdp.parseGetSessionParams(params);
  224. }
  225. parseSubscribeParams(params) {
  226. return Parser.Session.parseSubscribeParams(params);
  227. }
  228. parseNavigateParams(params) {
  229. return Parser.BrowsingContext.parseNavigateParams(params);
  230. }
  231. parseReloadParams(params) {
  232. return Parser.BrowsingContext.parseReloadParams(params);
  233. }
  234. parseGetTreeParams(params) {
  235. return Parser.BrowsingContext.parseGetTreeParams(params);
  236. }
  237. parseCreateParams(params) {
  238. return Parser.BrowsingContext.parseCreateParams(params);
  239. }
  240. parseCloseParams(params) {
  241. return Parser.BrowsingContext.parseCloseParams(params);
  242. }
  243. parseCaptureScreenshotParams(params) {
  244. return Parser.BrowsingContext.parseCaptureScreenshotParams(params);
  245. }
  246. parsePrintParams(params) {
  247. return Parser.BrowsingContext.parsePrintParams(params);
  248. }
  249. parsePerformActionsParams(params) {
  250. return Parser.Input.parsePerformActionsParams(params);
  251. }
  252. parseReleaseActionsParams(params) {
  253. return Parser.Input.parseReleaseActionsParams(params);
  254. }
  255. parseSetViewportParams(params) {
  256. return Parser.BrowsingContext.parseSetViewportParams(params);
  257. }
  258. }
  259. // Needed to filter out info related to BiDi target.
  260. async function waitSelfTargetId() {
  261. return new Promise((resolve) => {
  262. window.setSelfTargetId = (targetId) => {
  263. (0, mapperTabPage_js_1.log)(log_js_1.LogType.system, 'Current target ID:', targetId);
  264. resolve(targetId);
  265. };
  266. });
  267. }
  268. //# sourceMappingURL=bidiTab.js.map