diff --git a/jsdoc/README.md b/jsdoc/README.md index 33639cfc9..5e616dc31 100644 --- a/jsdoc/README.md +++ b/jsdoc/README.md @@ -1,6 +1,10 @@ # Scripting + +The user journey + Welcome to the powerful world of scripting with sitespeed.io! This feature unlocks the potential to simulate real user journeys, measure performance, and gather detailed metrics by interacting with web pages through custom scripts. Whether you're looking to analyze simple page loads or complex user interactions, our scripting functionality offers the tools you need. + ## Key Features * **User Journey Simulation**: Script entire user flows, from navigation to clicks and form submissions, to capture a realistic user experience. diff --git a/jsdoc/jsdoc.json b/jsdoc/jsdoc.json index 045df29e9..ade5c4348 100644 --- a/jsdoc/jsdoc.json +++ b/jsdoc/jsdoc.json @@ -16,7 +16,7 @@ }, "opts": { "tutorials": "./jsdoc/tutorials/", - "destination": "../sitespeed.io/docs/documentation/sitespeed.io/scripting/tutorials", + "destination": "../sitespeed.io/docs/documentation/sitespeed.io/scripting/", "template": "node_modules/clean-jsdoc-theme", "theme_opts": { "homepageTitle": "Tutorials and documentation for scripting in Browsertime and sitespeed.io", @@ -33,7 +33,7 @@ "link": "." }, { - "title": "Documentation", + "title": "Back to documentation", "link": "https://www.sitespeed.io/documentation/sitespeed.io/" } ], diff --git a/jsdoc/tutorials/04-Interact-with-the-page.md b/jsdoc/tutorials/04-Interact-with-the-page.md index aa83d6563..6b2fdd86a 100644 --- a/jsdoc/tutorials/04-Interact-with-the-page.md +++ b/jsdoc/tutorials/04-Interact-with-the-page.md @@ -14,9 +14,46 @@ One of the key things in your script is to be able to find the right element to ### Using Chrome to find the CSS Selector to the element ![Using Chrome to find the selector](https://www.sitespeed.io/img/selector-chrome.png) +## Using Actions +Since Browsertime 21.0.0 we support easier access to the [Selenium Action API](https://www.selenium.dev/documentation/webdriver/actions_api/). That makes easier to interact with the page and you can also chain commands. You can checkout the [Selenium NodeJS Action API](https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html) to see more what you can do. + +Here's an example doing search on Wikipedia: +```javascript +/** + * @param {import('browsertime').BrowsertimeContext} context + * @param {import('browsertime').BrowsertimeCommands} commands + */ +export default async function (context, commands) { + await commands.measure.start('https://www.wikipedia.org'); + const searchBox = await commands.element.getById('searchInput'); + const submitButton = await commands.element.getByClassName( + 'pure-button pure-button-primary-progressive' + ); + + await commands.measure.start('Search'); + await commands.action + .getActions() + .move({ origin: searchBox }) + .pause(1000) + .press() + .sendKeys('Hepp') + .pause(200) + .click(submitButton) + .perform(); + + // If you would do more actions after calling .perform() + // you manually need to clear the action API + //await commands.action.clear(); + + await commands.wait.byPageToComplete(); + return commands.measure.stop(); +} +``` + + ## JavaScript -You can run your own JavaScript in the browser from your script. This is powerful becasue that makes it possible to do whatever you want :) +You can run your own JavaScript in the browser from your script. This is powerful because that makes it possible to do whatever you want :) ### Run Run JavaScript. Will throw an error if the JavaScript fails. diff --git a/jsdoc/tutorials/09-Examples.md b/jsdoc/tutorials/09-Examples.md index 5602732b1..739aba23d 100644 --- a/jsdoc/tutorials/09-Examples.md +++ b/jsdoc/tutorials/09-Examples.md @@ -34,6 +34,40 @@ export default async function (context, commands) { }; ``` +### Measuring Interaction to next paint - INP +One of the new metrics Google is pushing is [Interaction to next paint](https://web.dev/articles/inp). You can use it when you collect RUM and using sitespeed.io. To measure it you need to interact with a web page. The best way to do that is using the Action API. + + +```JavaScript +/** + * @param {import('browsertime').BrowsertimeContext} context + * @param {import('browsertime').BrowsertimeCommands} commands + */ +export default async function (context, commands) { + // Start to measure + await commands.measure.start(); + // Go to a page ... + await commands.navigate('https://en.m.wikipedia.org/wiki/Barack_Obama'); + + // When the page has finished loading you can find the navigation and click on it + const element = await commands.element.getByXpath( + '//*[@id="mw-mf-main-menu-button"]' + ); + await commands.action.getActions().click(element).perform(); + + // If you want to do multiple actions, remember to clear() the Action API manually + + // Add some wait for the menu to show up + await commands.wait.byTime(2000); + + // Measure everything, that means you will run the JavaScript that collects the interaction to next paint + return commands.measure.stop(); +} +``` + +You will see the metric in the page summary and in the metrics section. + + ### Measure a login step ```JavaScript @@ -328,47 +362,6 @@ export default async function (context, commands) { }; ``` - -### Measuring Interaction to next paint - INP -One of the new metrics Google is pushing is [First Input Delay](https://developers.google.com/web/updates/2018/05/first-input-delay). You can use it when you collect RUM but it can be hard to know what the user is doing. The recommended way is to use the Long Task API but the truth is that the attribution from the API is ... well can be better. When you have a long task, it is really hard to know why by looking at the attribution. - -How do we measure FID with sitespeed.io? You can measure clicks and button using the [Selenium Action API](https://selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html) and then sitespeed.io uses the `first-input` performance observer to get it. What's really cool is that you can really measure it, instead of doing guestimates. - -Here's an example on measuring open the navigation on Wikipedia on mobile. I run my tests on a Alacatel One phone. - -```JavaScript -/** - * @param {import('browsertime').BrowsertimeContext} context - * @param {import('browsertime').BrowsertimeCommands} commands - */ -export default async function (context, commands) { - // We have some Selenium context - const webdriver = context.selenium.webdriver; - const driver = context.selenium.driver; - - // Start to measure - await commands.measure.start(); - // Go to a page ... - await commands.navigate('https://en.m.wikipedia.org/wiki/Barack_Obama'); - - // When the page has finished loading you can find the navigation and click on it - const actions = driver.actions(); - const nav = await driver.findElement( - webdriver.By.xpath('//*[@id="mw-mf-main-menu-button"]') - ); - await actions.click(nav).perform(); - - // Measure everything, that means you will run the JavaScript that collects the first input delay - return commands.measure.stop(); -}; -``` - -You will see the metric in the page summary and in the metrics section. - -![First input delay](https://www.sitespeed.io/img/first-input-delay.png) - -You can do mouse click, key press but there's no good way to do swiping as we know using the [Selenium Action API](https://selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html). Your action will run after the page has loaded. If you wanna know what kind potential input delay you can have on load, you can use the *maxPotentialFid* metric that you will get by enabling `--cpu`. - ### Test multiple URLs If you want to test multiple URLs and need to do some specific things before each URL, you can do something like this (we pass on our [own options](#pass-your-own-options-to-your-script) to the script): diff --git a/package.json b/package.json index 62e021516..21e47bac2 100644 --- a/package.json +++ b/package.json @@ -39,12 +39,12 @@ "devDependencies": { "@types/selenium-webdriver": "4.1.21", "ava": "6.0.1", - "clean-jsdoc-theme": "^4.2.17", + "clean-jsdoc-theme": "4.2.17", "eslint": "8.55.0", "eslint-config-prettier": "9.1.0", "eslint-plugin-prettier": "5.0.1", "eslint-plugin-unicorn": "49.0.0", - "jsdoc": "^4.0.2", + "jsdoc": "4.0.2", "prettier": "3.1.1", "serve": "14.2.1", "serve-handler": "6.1.5", diff --git a/types/core/engine/command/action.d.ts b/types/core/engine/command/action.d.ts new file mode 100644 index 000000000..a1a52d277 --- /dev/null +++ b/types/core/engine/command/action.d.ts @@ -0,0 +1,73 @@ +/** + * This class provides an abstraction layer for Selenium's action sequence functionality. + * It allows for easy interaction with web elements using different locating strategies + * and simulating complex user gestures like mouse movements, key presses, etc. + * + * @class + * @hideconstructor + * @see https://www.selenium.dev/documentation/webdriver/actions_api/ + */ +export class Action { + constructor(browser: any); + /** + * @private + */ + private driver; + /** + * @private + */ + private actions; + clear(): Promise; + /** + * Retrieves the current action sequence builder. + * The actions builder can be used to chain multiple browser actions. + * @returns {SeleniumActions} The current Selenium Actions builder object for chaining browser actions. + * @example + * // Example of using the actions builder to perform a drag-and-drop operation: + * const elementToDrag = await commands.action.getElementByCss('.draggable'); + * const dropTarget = await commands.action.getElementByCss('.drop-target'); + * await commands.action.getAction() + * .dragAndDrop(elementToDrag, dropTarget) + * .perform(); + * + */ + getAction(): SeleniumActions; + /** + * Finds an element by its CSS selector. + * + * @param {string} name - The CSS selector of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getElementByCss(name: string): Promise; + /** + * Finds an element by its ID. + * + * @param {string} id - The ID of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getElementById(id: string): Promise; + /** + * Finds an element by its XPath. + * + * @param {string} xpath - The XPath query of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getElementByXpath(xpath: string): Promise; + /** + * Finds an element by its class name. + * + * @param {string} className - The class name of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getElementByClassName(className: string): Promise; + /** + * Finds an element by its name attribute. + * + * @param {string} name - The name attribute of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getElementByName(name: string): Promise; +} +import { Actions as SeleniumActions } from 'selenium-webdriver'; +import { WebElement } from 'selenium-webdriver'; +//# sourceMappingURL=action.d.ts.map \ No newline at end of file diff --git a/types/core/engine/command/action.d.ts.map b/types/core/engine/command/action.d.ts.map new file mode 100644 index 000000000..bf13494dd --- /dev/null +++ b/types/core/engine/command/action.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"action.d.ts","sourceRoot":"","sources":["../../../../lib/core/engine/command/action.js"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH;IACE,0BASC;IARC;;OAEG;IACH,eAAiC;IACjC;;OAEG;IACH,gBAAmD;IASrD,sBAEC;IAED;;;;;;;;;;;;OAYG;IACH,aAVa,eAAe,CAY3B;IAED;;;;;OAKG;IACH,sBAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,mBAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,yBAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,iCAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,uBAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;CACF;2CAnG0D,oBAAoB;2BAApB,oBAAoB"} \ No newline at end of file diff --git a/types/core/engine/command/actions.d.ts b/types/core/engine/command/actions.d.ts new file mode 100644 index 000000000..96be6ff17 --- /dev/null +++ b/types/core/engine/command/actions.d.ts @@ -0,0 +1,38 @@ +/** + * This class provides an abstraction layer for Selenium's action sequence functionality. + * It allows for easy interaction with web elements using different locating strategies + * and simulating complex user gestures like mouse movements, key presses, etc. + * + * @class + * @hideconstructor + * @see https://www.selenium.dev/documentation/webdriver/actions_api/ + * @see https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/lib/input_exports_Actions.html + */ +export class Actions { + constructor(browser: any); + /** + * @private + */ + private driver; + /** + * @private + */ + private actions; + clear(): Promise; + /** + * Retrieves the current action sequence builder. + * The actions builder can be used to chain multiple browser actions. + * @returns {SeleniumActions} The current Selenium Actions builder object for chaining browser actions. + * @example + * // Example of using the actions builder to perform a drag-and-drop operation: + * const elementToDrag = await commands.action.getElementByCss('.draggable'); + * const dropTarget = await commands.action.getElementByCss('.drop-target'); + * await commands.action.getAction() + * .dragAndDrop(elementToDrag, dropTarget) + * .perform(); + * + */ + getActions(): SeleniumActions; +} +import { Actions as SeleniumActions } from 'selenium-webdriver/lib/input.js'; +//# sourceMappingURL=actions.d.ts.map \ No newline at end of file diff --git a/types/core/engine/command/actions.d.ts.map b/types/core/engine/command/actions.d.ts.map new file mode 100644 index 000000000..63b856477 --- /dev/null +++ b/types/core/engine/command/actions.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../../lib/core/engine/command/actions.js"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH;IACE,0BASC;IARC;;OAEG;IACH,eAAiC;IACjC;;OAEG;IACH,gBAAmD;IASrD,sBAEC;IAED;;;;;;;;;;;;OAYG;IACH,cAVa,eAAe,CAY3B;CACF;2CAjD0C,iCAAiC"} \ No newline at end of file diff --git a/types/core/engine/command/element.d.ts b/types/core/engine/command/element.d.ts new file mode 100644 index 000000000..a1baed14a --- /dev/null +++ b/types/core/engine/command/element.d.ts @@ -0,0 +1,49 @@ +/** + * This class provides a way to get hokld of Seleniums WebElements. + * @class + * @hideconstructor + */ +export class Element { + constructor(browser: any); + /** + * @private + */ + private driver; + /** + * Finds an element by its CSS selector. + * + * @param {string} name - The CSS selector of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getByCss(name: string): Promise; + /** + * Finds an element by its ID. + * + * @param {string} id - The ID of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getById(id: string): Promise; + /** + * Finds an element by its XPath. + * + * @param {string} xpath - The XPath query of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getByXpath(xpath: string): Promise; + /** + * Finds an element by its class name. + * + * @param {string} className - The class name of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getByClassName(className: string): Promise; + /** + * Finds an element by its name attribute. + * + * @param {string} name - The name attribute of the element. + * @returns {Promise} A promise that resolves to the WebElement found. + */ + getByName(name: string): Promise; +} +import { WebElement } from 'selenium-webdriver'; +//# sourceMappingURL=element.d.ts.map \ No newline at end of file diff --git a/types/core/engine/command/element.d.ts.map b/types/core/engine/command/element.d.ts.map new file mode 100644 index 000000000..c51a065b9 --- /dev/null +++ b/types/core/engine/command/element.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../../../../lib/core/engine/command/element.js"],"names":[],"mappings":"AAGA;;;;GAIG;AACH;IACE,0BAKC;IAJC;;OAEG;IACH,eAAiC;IAGnC;;;;;OAKG;IACH,eAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,YAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,kBAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,0BAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;IAED;;;;;OAKG;IACH,gBAHW,MAAM,GACJ,QAAQ,UAAU,CAAC,CAI/B;CACF;2BA/D8B,oBAAoB"} \ No newline at end of file diff --git a/types/core/engine/command/measure.d.ts b/types/core/engine/command/measure.d.ts index af32ea3dd..347faba97 100644 --- a/types/core/engine/command/measure.d.ts +++ b/types/core/engine/command/measure.d.ts @@ -142,6 +142,13 @@ export class Measure { * If an alias is provided, or no URL is available, it sets up the environment for a user-driven navigation. * * @async + * @example + * await commands.measure.start('https://www.example.org'); + * // Or start the measurement and click on a link + * await commands.measure.start(); + * await commands.click.byLinkTextAndWait('Documentation'); + * // Remember to stop the measurements if you do not provide a URL + * await commands.measure.stop(); * @param {string} urlOrAlias - The URL to navigate to, or an alias representing the test. * @param {string} [optionalAlias] - An optional alias that can be used if the first parameter is a URL. * @throws {Error} Throws an error if navigation fails or if there are issues in the setup process. diff --git a/types/core/engine/command/measure.d.ts.map b/types/core/engine/command/measure.d.ts.map index dcd3320c7..368ab4136 100644 --- a/types/core/engine/command/measure.d.ts.map +++ b/types/core/engine/command/measure.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../../../lib/core/engine/command/measure.js"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH;IACE,sRA4GC;IA5FC;;OAEG;IACH,gBAAsB;IACtB;;OAEG;IACH,0BAA0C;IAC1C;;OAEG;IACH,cAAkB;IAClB;;OAEG;IACH,eAAoB;IACpB;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,gBAAsB;IACtB;;OAEG;IACH,0BAA0C;IAC1C;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,oBAAyD;IACzD;;OAEG;IACH,wBAAsC;IACtC;;OAEG;IACH,eAAoB;IACpB;;OAEG;IACH,0BAA0C;IAC1C;;OAEG;IACH,+BAAoD;IACpD;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,gBAAsB;IACtB;;OAEG;IACH,8BAA8B;IAC9B;;OAEG;IACH,6BAA6B;IAC7B;;OAEG;IACH,uBAA2B;IAC3B;;OAEG;IACH,mBAAoB;IACpB;;OAEG;IACH,gBAA6D;IAC7D;;OAEG;IACH,2BAAsE;IACtE;;OAEG;IACH,uBAA8D;IAC9D;;OAEG;IACH,2BAAqE;IAGvE;;;OAGG;IACH,oBAsBC;IArBC,aAAuE;IAuBzE;;;OAGG;IACH,mBAKC;IAED;;;OAGG;IACH,eAsBC;IAED;;;OAGG;IACH,iBAQC;IAED;;;;;;;;;;;;OAYG;IACH,kBAuBC;IAED;;;;;;;;;;;;OAYG;IACH,kBALW,MAAM,kBACN,MAAM,GAEJ,QAAQ,IAAI,CAAC,CAwFzB;IAED;;;;;;;;;OASG;IACH,qBAJW,MAAM,gBAkEhB;IAED;;;;;;;OAOG;IACH,UAJW,MAAM,oBAYhB;IAED;;;;;;;OAOG;IACH,6BAOC;IAED;;;OAGG;IACH,gBA+KC;CACF;sBA3oBqB,yBAAyB"} \ No newline at end of file +{"version":3,"file":"measure.d.ts","sourceRoot":"","sources":["../../../../lib/core/engine/command/measure.js"],"names":[],"mappings":"AA6BA;;;;;;GAMG;AACH;IACE,sRA4GC;IA5FC;;OAEG;IACH,gBAAsB;IACtB;;OAEG;IACH,0BAA0C;IAC1C;;OAEG;IACH,cAAkB;IAClB;;OAEG;IACH,eAAoB;IACpB;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,gBAAsB;IACtB;;OAEG;IACH,0BAA0C;IAC1C;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,oBAAyD;IACzD;;OAEG;IACH,wBAAsC;IACtC;;OAEG;IACH,eAAoB;IACpB;;OAEG;IACH,0BAA0C;IAC1C;;OAEG;IACH,+BAAoD;IACpD;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,gBAAsB;IACtB;;OAEG;IACH,8BAA8B;IAC9B;;OAEG;IACH,6BAA6B;IAC7B;;OAEG;IACH,uBAA2B;IAC3B;;OAEG;IACH,mBAAoB;IACpB;;OAEG;IACH,gBAA6D;IAC7D;;OAEG;IACH,2BAAsE;IACtE;;OAEG;IACH,uBAA8D;IAC9D;;OAEG;IACH,2BAAqE;IAGvE;;;OAGG;IACH,oBAsBC;IArBC,aAAuE;IAuBzE;;;OAGG;IACH,mBAKC;IAED;;;OAGG;IACH,eAsBC;IAED;;;OAGG;IACH,iBAQC;IAED;;;;;;;;;;;;OAYG;IACH,kBAuBC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,kBALW,MAAM,kBACN,MAAM,GAEJ,QAAQ,IAAI,CAAC,CAwFzB;IAED;;;;;;;;;OASG;IACH,qBAJW,MAAM,gBAkEhB;IAED;;;;;;;OAOG;IACH,UAJW,MAAM,oBAYhB;IAED;;;;;;;OAOG;IACH,6BAOC;IAED;;;OAGG;IACH,gBA+KC;CACF;sBAlpBqB,yBAAyB"} \ No newline at end of file diff --git a/types/core/engine/commands.d.ts b/types/core/engine/commands.d.ts index 8793b81c8..5273ef384 100644 --- a/types/core/engine/commands.d.ts +++ b/types/core/engine/commands.d.ts @@ -125,6 +125,17 @@ export class Commands { * @type {Select} */ select: Select; + /** + * Selenium's action sequence functionality. + * @type {Actions} + * @see https://www.selenium.dev/documentation/webdriver/actions_api/ + */ + action: Actions; + /** + * Get Selenium's WebElements. + * @type {Element} + */ + element: Element; } import { GeckoProfiler as GeckoProfilerCommand } from './command/geckoProfiler.js'; import { ChromeTrace } from './command/chromeTrace.js'; @@ -145,4 +156,6 @@ import { ChromeDevelopmentToolsProtocol } from './command/chromeDevToolsProtocol import { AndroidCommand } from './command/android.js'; import { Debug } from './command/debug.js'; import { Select } from './command/select.js'; +import { Actions } from './command/actions.js'; +import { Element } from './command/element.js'; //# sourceMappingURL=commands.d.ts.map \ No newline at end of file diff --git a/types/core/engine/commands.d.ts.map b/types/core/engine/commands.d.ts.map index 038df9070..c2aa20639 100644 --- a/types/core/engine/commands.d.ts.map +++ b/types/core/engine/commands.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../lib/core/engine/commands.js"],"names":[],"mappings":"AA2BA;;;GAGG;AACH;IACE,sRA0NC;IAvLC,+BAMC;IAMD;;;OAGG;IACH,OAFU,WAAW,CAE+C;IAEpE;;;OAGG;IACH,OAFU,KAAK,CAEmC;IAElD;;;OAGG;IACH,QAFU,MAAM,CAE0B;IAE1C;;;OAGG;IACH,SAFU,OAAO,CAEkB;IAEnC;;;OAGG;IACH,MAFU,IAAI,CAEkC;IAEhD;;;OAGG;IACH,SAFU,OAAO,CAEK;IAEtB;;;;;;;;OAQG;IACH,mBAA+C;IAE/C;;;OAGG;IACH,YAFU,UAAU,CAEwC;IAE5D;;;;;OAKG;IACH,gBAAyC;IAEzC;;;;;OAKG;IACH,wBAAmD;IAEnD;;;OAGG;IACH,IAFU,UAAU,CAEgC;IAEpD;;;OAGG;IACH,QAFU,MAAM,CAMf;IAED;;;OAGG;IACH,KAFU,GAAG,CAEc;IAE3B;;;OAGG;IACH,WAFU,SAAS,CAEoB;IAEvC;;;OAGG;IACH,OAFU,KAAK,CAEuD;IAEtE;;;OAGG;IACH,MAFU,IAAI,CAEQ;IAEtB;;;OAGG;IACH,YAFU,UAAU,CAE+C;IAEnE;;;OAGG;IACH,KAFU,8BAA8B,CAE1B;IAEd;;;OAGG;IACH,SAFU,cAAc,CAEkB;IAE1C;;;;OAIG;IACH,OAFW,KAAK,CAEwB;IAExC;;;OAGG;IACH,WA0BC;IAED;;;OAGG;IACH,QAFU,MAAM,CAEiB;CAEpC;sDAjOqD,4BAA4B;4BAXtD,0BAA0B;sBAdhC,oBAAoB;uBAsBnB,qBAAqB;wBAvBpB,sBAAsB;qBAEzB,mBAAmB;wBAChB,sBAAsB;2BAqBnB,yBAAyB;2BApBzB,yBAAyB;uBAC7B,qBAAqB;oBAExB,kBAAkB;mCAGH,wBAAwB;sBAFrC,oBAAoB;qBACrB,mBAAmB;2BAHb,yBAAyB;+CAQL,qCAAqC;+BADrD,sBAAsB;sBAD/B,oBAAoB;uBADnB,qBAAqB"} \ No newline at end of file +{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../lib/core/engine/commands.js"],"names":[],"mappings":"AA6BA;;;GAGG;AACH;IACE,sRAuOC;IApMC,+BAMC;IAMD;;;OAGG;IACH,OAFU,WAAW,CAE+C;IAEpE;;;OAGG;IACH,OAFU,KAAK,CAEmC;IAElD;;;OAGG;IACH,QAFU,MAAM,CAE0B;IAE1C;;;OAGG;IACH,SAFU,OAAO,CAEkB;IAEnC;;;OAGG;IACH,MAFU,IAAI,CAEkC;IAEhD;;;OAGG;IACH,SAFU,OAAO,CAEK;IAEtB;;;;;;;;OAQG;IACH,mBAA+C;IAE/C;;;OAGG;IACH,YAFU,UAAU,CAEwC;IAE5D;;;;;OAKG;IACH,gBAAyC;IAEzC;;;;;OAKG;IACH,wBAAmD;IAEnD;;;OAGG;IACH,IAFU,UAAU,CAEgC;IAEpD;;;OAGG;IACH,QAFU,MAAM,CAMf;IAED;;;OAGG;IACH,KAFU,GAAG,CAEc;IAE3B;;;OAGG;IACH,WAFU,SAAS,CAEoB;IAEvC;;;OAGG;IACH,OAFU,KAAK,CAEuD;IAEtE;;;OAGG;IACH,MAFU,IAAI,CAEQ;IAEtB;;;OAGG;IACH,YAFU,UAAU,CAE+C;IAEnE;;;OAGG;IACH,KAFU,8BAA8B,CAE1B;IAEd;;;OAGG;IACH,SAFU,cAAc,CAEkB;IAE1C;;;;OAIG;IACH,OAFW,KAAK,CAEwB;IAExC;;;OAGG;IACH,WA0BC;IAED;;;OAGG;IACH,QAFU,MAAM,CAEiB;IAEjC;;;;OAIG;IACH,QAHU,OAAO,CAGiB;IAElC;;;OAGG;IACH,SAFU,OAAO,CAEkB;CAEtC;sDA9OqD,4BAA4B;4BAXtD,0BAA0B;sBAfhC,oBAAoB;uBAuBnB,qBAAqB;wBAxBpB,sBAAsB;qBAGzB,mBAAmB;wBAChB,sBAAsB;2BAqBnB,yBAAyB;2BApBzB,yBAAyB;uBAC7B,qBAAqB;oBAExB,kBAAkB;mCAGH,wBAAwB;sBAFrC,oBAAoB;qBACrB,mBAAmB;2BAHb,yBAAyB;+CAQL,qCAAqC;+BADrD,sBAAsB;sBAD/B,oBAAoB;uBADnB,qBAAqB;wBAbpB,sBAAsB;wBAGtB,sBAAsB"} \ No newline at end of file