@midscene/shared 1.6.1-beta-20260331083547.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,7 +72,7 @@ function findNearestPackageJson(dir) {
72
72
  return findNearestPackageJson(parentDir);
73
73
  }
74
74
  function getElementInfosScriptContent() {
75
- const htmlElementScript = "(()=>{\n var __webpack_modules__ = {\n \"../../node_modules/.pnpm/js-sha256@0.11.0/node_modules/js-sha256/src/sha256.js\" (module, __unused_rspack_exports, __webpack_require__) {\n module = __webpack_require__.nmd(module);\n /**\n * [js-sha256]{@link https://github.com/emn178/js-sha256}\n *\n * @version 0.11.0\n * @author Chen, Yi-Cyuan [emn178@gmail.com]\n * @copyright Chen, Yi-Cyuan 2014-2024\n * @license MIT\n */ (function() {\n 'use strict';\n var ERROR = 'input is invalid type';\n var WINDOW = 'object' == typeof window;\n var root = WINDOW ? window : {};\n if (root.JS_SHA256_NO_WINDOW) WINDOW = false;\n var WEB_WORKER = !WINDOW && 'object' == typeof self;\n var NODE_JS = !root.JS_SHA256_NO_NODE_JS && 'object' == typeof process && process.versions && process.versions.node;\n if (NODE_JS) root = __webpack_require__.g;\n else if (WEB_WORKER) root = self;\n var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && 'object' == typeof module && module.exports;\n var AMD = 'function' == typeof define && define.amd;\n var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && 'undefined' != typeof ArrayBuffer;\n var HEX_CHARS = '0123456789abcdef'.split('');\n var EXTRA = [\n -2147483648,\n 8388608,\n 32768,\n 128\n ];\n var SHIFT = [\n 24,\n 16,\n 8,\n 0\n ];\n var K = [\n 0x428a2f98,\n 0x71374491,\n 0xb5c0fbcf,\n 0xe9b5dba5,\n 0x3956c25b,\n 0x59f111f1,\n 0x923f82a4,\n 0xab1c5ed5,\n 0xd807aa98,\n 0x12835b01,\n 0x243185be,\n 0x550c7dc3,\n 0x72be5d74,\n 0x80deb1fe,\n 0x9bdc06a7,\n 0xc19bf174,\n 0xe49b69c1,\n 0xefbe4786,\n 0x0fc19dc6,\n 0x240ca1cc,\n 0x2de92c6f,\n 0x4a7484aa,\n 0x5cb0a9dc,\n 0x76f988da,\n 0x983e5152,\n 0xa831c66d,\n 0xb00327c8,\n 0xbf597fc7,\n 0xc6e00bf3,\n 0xd5a79147,\n 0x06ca6351,\n 0x14292967,\n 0x27b70a85,\n 0x2e1b2138,\n 0x4d2c6dfc,\n 0x53380d13,\n 0x650a7354,\n 0x766a0abb,\n 0x81c2c92e,\n 0x92722c85,\n 0xa2bfe8a1,\n 0xa81a664b,\n 0xc24b8b70,\n 0xc76c51a3,\n 0xd192e819,\n 0xd6990624,\n 0xf40e3585,\n 0x106aa070,\n 0x19a4c116,\n 0x1e376c08,\n 0x2748774c,\n 0x34b0bcb5,\n 0x391c0cb3,\n 0x4ed8aa4a,\n 0x5b9cca4f,\n 0x682e6ff3,\n 0x748f82ee,\n 0x78a5636f,\n 0x84c87814,\n 0x8cc70208,\n 0x90befffa,\n 0xa4506ceb,\n 0xbef9a3f7,\n 0xc67178f2\n ];\n var OUTPUT_TYPES = [\n 'hex',\n 'array',\n 'digest',\n 'arrayBuffer'\n ];\n var blocks = [];\n if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) Array.isArray = function(obj) {\n return '[object Array]' === Object.prototype.toString.call(obj);\n };\n if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) ArrayBuffer.isView = function(obj) {\n return 'object' == typeof obj && obj.buffer && obj.buffer.constructor === ArrayBuffer;\n };\n var createOutputMethod = function(outputType, is224) {\n return function(message) {\n return new Sha256(is224, true).update(message)[outputType]();\n };\n };\n var createMethod = function(is224) {\n var method = createOutputMethod('hex', is224);\n if (NODE_JS) method = nodeWrap(method, is224);\n method.create = function() {\n return new Sha256(is224);\n };\n method.update = function(message) {\n return method.create().update(message);\n };\n for(var i = 0; i < OUTPUT_TYPES.length; ++i){\n var type = OUTPUT_TYPES[i];\n method[type] = createOutputMethod(type, is224);\n }\n return method;\n };\n var nodeWrap = function(method, is224) {\n var crypto = __webpack_require__(\"?c118\");\n var Buffer = __webpack_require__(\"?4999\").Buffer;\n var algorithm = is224 ? 'sha224' : 'sha256';\n var bufferFrom;\n bufferFrom = Buffer.from && !root.JS_SHA256_NO_BUFFER_FROM ? Buffer.from : function(message) {\n return new Buffer(message);\n };\n var nodeMethod = function(message) {\n if ('string' == typeof message) return crypto.createHash(algorithm).update(message, 'utf8').digest('hex');\n if (null == message) throw new Error(ERROR);\n if (message.constructor === ArrayBuffer) message = new Uint8Array(message);\n if (Array.isArray(message) || ArrayBuffer.isView(message) || message.constructor === Buffer) return crypto.createHash(algorithm).update(bufferFrom(message)).digest('hex');\n return method(message);\n };\n return nodeMethod;\n };\n var createHmacOutputMethod = function(outputType, is224) {\n return function(key, message) {\n return new HmacSha256(key, is224, true).update(message)[outputType]();\n };\n };\n var createHmacMethod = function(is224) {\n var method = createHmacOutputMethod('hex', is224);\n method.create = function(key) {\n return new HmacSha256(key, is224);\n };\n method.update = function(key, message) {\n return method.create(key).update(message);\n };\n for(var i = 0; i < OUTPUT_TYPES.length; ++i){\n var type = OUTPUT_TYPES[i];\n method[type] = createHmacOutputMethod(type, is224);\n }\n return method;\n };\n function Sha256(is224, sharedMemory) {\n if (sharedMemory) {\n blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n this.blocks = blocks;\n } else this.blocks = [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ];\n if (is224) {\n this.h0 = 0xc1059ed8;\n this.h1 = 0x367cd507;\n this.h2 = 0x3070dd17;\n this.h3 = 0xf70e5939;\n this.h4 = 0xffc00b31;\n this.h5 = 0x68581511;\n this.h6 = 0x64f98fa7;\n this.h7 = 0xbefa4fa4;\n } else {\n this.h0 = 0x6a09e667;\n this.h1 = 0xbb67ae85;\n this.h2 = 0x3c6ef372;\n this.h3 = 0xa54ff53a;\n this.h4 = 0x510e527f;\n this.h5 = 0x9b05688c;\n this.h6 = 0x1f83d9ab;\n this.h7 = 0x5be0cd19;\n }\n this.block = this.start = this.bytes = this.hBytes = 0;\n this.finalized = this.hashed = false;\n this.first = true;\n this.is224 = is224;\n }\n Sha256.prototype.update = function(message) {\n if (this.finalized) return;\n var notString, type = typeof message;\n if ('string' !== type) {\n if ('object' === type) {\n if (null === message) throw new Error(ERROR);\n else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) message = new Uint8Array(message);\n else if (!Array.isArray(message)) {\n if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) throw new Error(ERROR);\n }\n } else throw new Error(ERROR);\n notString = true;\n }\n var code, index = 0, i, length = message.length, blocks = this.blocks;\n while(index < length){\n if (this.hashed) {\n this.hashed = false;\n blocks[0] = this.block;\n this.block = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n }\n if (notString) for(i = this.start; index < length && i < 64; ++index)blocks[i >>> 2] |= message[index] << SHIFT[3 & i++];\n else for(i = this.start; index < length && i < 64; ++index){\n code = message.charCodeAt(index);\n if (code < 0x80) blocks[i >>> 2] |= code << SHIFT[3 & i++];\n else if (code < 0x800) {\n blocks[i >>> 2] |= (0xc0 | code >>> 6) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | 0x3f & code) << SHIFT[3 & i++];\n } else if (code < 0xd800 || code >= 0xe000) {\n blocks[i >>> 2] |= (0xe0 | code >>> 12) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | code >>> 6 & 0x3f) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | 0x3f & code) << SHIFT[3 & i++];\n } else {\n code = 0x10000 + ((0x3ff & code) << 10 | 0x3ff & message.charCodeAt(++index));\n blocks[i >>> 2] |= (0xf0 | code >>> 18) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | code >>> 12 & 0x3f) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | code >>> 6 & 0x3f) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | 0x3f & code) << SHIFT[3 & i++];\n }\n }\n this.lastByteIndex = i;\n this.bytes += i - this.start;\n if (i >= 64) {\n this.block = blocks[16];\n this.start = i - 64;\n this.hash();\n this.hashed = true;\n } else this.start = i;\n }\n if (this.bytes > 4294967295) {\n this.hBytes += this.bytes / 4294967296 | 0;\n this.bytes = this.bytes % 4294967296;\n }\n return this;\n };\n Sha256.prototype.finalize = function() {\n if (this.finalized) return;\n this.finalized = true;\n var blocks = this.blocks, i = this.lastByteIndex;\n blocks[16] = this.block;\n blocks[i >>> 2] |= EXTRA[3 & i];\n this.block = blocks[16];\n if (i >= 56) {\n if (!this.hashed) this.hash();\n blocks[0] = this.block;\n blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n }\n blocks[14] = this.hBytes << 3 | this.bytes >>> 29;\n blocks[15] = this.bytes << 3;\n this.hash();\n };\n Sha256.prototype.hash = function() {\n var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6, h = this.h7, blocks = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;\n for(j = 16; j < 64; ++j){\n t1 = blocks[j - 15];\n s0 = (t1 >>> 7 | t1 << 25) ^ (t1 >>> 18 | t1 << 14) ^ t1 >>> 3;\n t1 = blocks[j - 2];\n s1 = (t1 >>> 17 | t1 << 15) ^ (t1 >>> 19 | t1 << 13) ^ t1 >>> 10;\n blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 | 0;\n }\n bc = b & c;\n for(j = 0; j < 64; j += 4){\n if (this.first) {\n if (this.is224) {\n ab = 300032;\n t1 = blocks[0] - 1413257819;\n h = t1 - 150054599 | 0;\n d = t1 + 24177077 | 0;\n } else {\n ab = 704751109;\n t1 = blocks[0] - 210244248;\n h = t1 - 1521486534 | 0;\n d = t1 + 143694565 | 0;\n }\n this.first = false;\n } else {\n s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);\n s1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);\n ab = a & b;\n maj = ab ^ a & c ^ bc;\n ch = e & f ^ ~e & g;\n t1 = h + s1 + ch + K[j] + blocks[j];\n t2 = s0 + maj;\n h = d + t1 | 0;\n d = t1 + t2 | 0;\n }\n s0 = (d >>> 2 | d << 30) ^ (d >>> 13 | d << 19) ^ (d >>> 22 | d << 10);\n s1 = (h >>> 6 | h << 26) ^ (h >>> 11 | h << 21) ^ (h >>> 25 | h << 7);\n da = d & a;\n maj = da ^ d & b ^ ab;\n ch = h & e ^ ~h & f;\n t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];\n t2 = s0 + maj;\n g = c + t1 | 0;\n c = t1 + t2 | 0;\n s0 = (c >>> 2 | c << 30) ^ (c >>> 13 | c << 19) ^ (c >>> 22 | c << 10);\n s1 = (g >>> 6 | g << 26) ^ (g >>> 11 | g << 21) ^ (g >>> 25 | g << 7);\n cd = c & d;\n maj = cd ^ c & a ^ da;\n ch = g & h ^ ~g & e;\n t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];\n t2 = s0 + maj;\n f = b + t1 | 0;\n b = t1 + t2 | 0;\n s0 = (b >>> 2 | b << 30) ^ (b >>> 13 | b << 19) ^ (b >>> 22 | b << 10);\n s1 = (f >>> 6 | f << 26) ^ (f >>> 11 | f << 21) ^ (f >>> 25 | f << 7);\n bc = b & c;\n maj = bc ^ b & d ^ cd;\n ch = f & g ^ ~f & h;\n t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];\n t2 = s0 + maj;\n e = a + t1 | 0;\n a = t1 + t2 | 0;\n this.chromeBugWorkAround = true;\n }\n this.h0 = this.h0 + a | 0;\n this.h1 = this.h1 + b | 0;\n this.h2 = this.h2 + c | 0;\n this.h3 = this.h3 + d | 0;\n this.h4 = this.h4 + e | 0;\n this.h5 = this.h5 + f | 0;\n this.h6 = this.h6 + g | 0;\n this.h7 = this.h7 + h | 0;\n };\n Sha256.prototype.hex = function() {\n this.finalize();\n var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7;\n var hex = HEX_CHARS[h0 >>> 28 & 0x0F] + HEX_CHARS[h0 >>> 24 & 0x0F] + HEX_CHARS[h0 >>> 20 & 0x0F] + HEX_CHARS[h0 >>> 16 & 0x0F] + HEX_CHARS[h0 >>> 12 & 0x0F] + HEX_CHARS[h0 >>> 8 & 0x0F] + HEX_CHARS[h0 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h0] + HEX_CHARS[h1 >>> 28 & 0x0F] + HEX_CHARS[h1 >>> 24 & 0x0F] + HEX_CHARS[h1 >>> 20 & 0x0F] + HEX_CHARS[h1 >>> 16 & 0x0F] + HEX_CHARS[h1 >>> 12 & 0x0F] + HEX_CHARS[h1 >>> 8 & 0x0F] + HEX_CHARS[h1 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h1] + HEX_CHARS[h2 >>> 28 & 0x0F] + HEX_CHARS[h2 >>> 24 & 0x0F] + HEX_CHARS[h2 >>> 20 & 0x0F] + HEX_CHARS[h2 >>> 16 & 0x0F] + HEX_CHARS[h2 >>> 12 & 0x0F] + HEX_CHARS[h2 >>> 8 & 0x0F] + HEX_CHARS[h2 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h2] + HEX_CHARS[h3 >>> 28 & 0x0F] + HEX_CHARS[h3 >>> 24 & 0x0F] + HEX_CHARS[h3 >>> 20 & 0x0F] + HEX_CHARS[h3 >>> 16 & 0x0F] + HEX_CHARS[h3 >>> 12 & 0x0F] + HEX_CHARS[h3 >>> 8 & 0x0F] + HEX_CHARS[h3 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h3] + HEX_CHARS[h4 >>> 28 & 0x0F] + HEX_CHARS[h4 >>> 24 & 0x0F] + HEX_CHARS[h4 >>> 20 & 0x0F] + HEX_CHARS[h4 >>> 16 & 0x0F] + HEX_CHARS[h4 >>> 12 & 0x0F] + HEX_CHARS[h4 >>> 8 & 0x0F] + HEX_CHARS[h4 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h4] + HEX_CHARS[h5 >>> 28 & 0x0F] + HEX_CHARS[h5 >>> 24 & 0x0F] + HEX_CHARS[h5 >>> 20 & 0x0F] + HEX_CHARS[h5 >>> 16 & 0x0F] + HEX_CHARS[h5 >>> 12 & 0x0F] + HEX_CHARS[h5 >>> 8 & 0x0F] + HEX_CHARS[h5 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h5] + HEX_CHARS[h6 >>> 28 & 0x0F] + HEX_CHARS[h6 >>> 24 & 0x0F] + HEX_CHARS[h6 >>> 20 & 0x0F] + HEX_CHARS[h6 >>> 16 & 0x0F] + HEX_CHARS[h6 >>> 12 & 0x0F] + HEX_CHARS[h6 >>> 8 & 0x0F] + HEX_CHARS[h6 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h6];\n if (!this.is224) hex += HEX_CHARS[h7 >>> 28 & 0x0F] + HEX_CHARS[h7 >>> 24 & 0x0F] + HEX_CHARS[h7 >>> 20 & 0x0F] + HEX_CHARS[h7 >>> 16 & 0x0F] + HEX_CHARS[h7 >>> 12 & 0x0F] + HEX_CHARS[h7 >>> 8 & 0x0F] + HEX_CHARS[h7 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h7];\n return hex;\n };\n Sha256.prototype.toString = Sha256.prototype.hex;\n Sha256.prototype.digest = function() {\n this.finalize();\n var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7;\n var arr = [\n h0 >>> 24 & 0xFF,\n h0 >>> 16 & 0xFF,\n h0 >>> 8 & 0xFF,\n 0xFF & h0,\n h1 >>> 24 & 0xFF,\n h1 >>> 16 & 0xFF,\n h1 >>> 8 & 0xFF,\n 0xFF & h1,\n h2 >>> 24 & 0xFF,\n h2 >>> 16 & 0xFF,\n h2 >>> 8 & 0xFF,\n 0xFF & h2,\n h3 >>> 24 & 0xFF,\n h3 >>> 16 & 0xFF,\n h3 >>> 8 & 0xFF,\n 0xFF & h3,\n h4 >>> 24 & 0xFF,\n h4 >>> 16 & 0xFF,\n h4 >>> 8 & 0xFF,\n 0xFF & h4,\n h5 >>> 24 & 0xFF,\n h5 >>> 16 & 0xFF,\n h5 >>> 8 & 0xFF,\n 0xFF & h5,\n h6 >>> 24 & 0xFF,\n h6 >>> 16 & 0xFF,\n h6 >>> 8 & 0xFF,\n 0xFF & h6\n ];\n if (!this.is224) arr.push(h7 >>> 24 & 0xFF, h7 >>> 16 & 0xFF, h7 >>> 8 & 0xFF, 0xFF & h7);\n return arr;\n };\n Sha256.prototype.array = Sha256.prototype.digest;\n Sha256.prototype.arrayBuffer = function() {\n this.finalize();\n var buffer = new ArrayBuffer(this.is224 ? 28 : 32);\n var dataView = new DataView(buffer);\n dataView.setUint32(0, this.h0);\n dataView.setUint32(4, this.h1);\n dataView.setUint32(8, this.h2);\n dataView.setUint32(12, this.h3);\n dataView.setUint32(16, this.h4);\n dataView.setUint32(20, this.h5);\n dataView.setUint32(24, this.h6);\n if (!this.is224) dataView.setUint32(28, this.h7);\n return buffer;\n };\n function HmacSha256(key, is224, sharedMemory) {\n var i, type = typeof key;\n if ('string' === type) {\n var bytes = [], length = key.length, index = 0, code;\n for(i = 0; i < length; ++i){\n code = key.charCodeAt(i);\n if (code < 0x80) bytes[index++] = code;\n else if (code < 0x800) {\n bytes[index++] = 0xc0 | code >>> 6;\n bytes[index++] = 0x80 | 0x3f & code;\n } else if (code < 0xd800 || code >= 0xe000) {\n bytes[index++] = 0xe0 | code >>> 12;\n bytes[index++] = 0x80 | code >>> 6 & 0x3f;\n bytes[index++] = 0x80 | 0x3f & code;\n } else {\n code = 0x10000 + ((0x3ff & code) << 10 | 0x3ff & key.charCodeAt(++i));\n bytes[index++] = 0xf0 | code >>> 18;\n bytes[index++] = 0x80 | code >>> 12 & 0x3f;\n bytes[index++] = 0x80 | code >>> 6 & 0x3f;\n bytes[index++] = 0x80 | 0x3f & code;\n }\n }\n key = bytes;\n } else if ('object' === type) {\n if (null === key) throw new Error(ERROR);\n else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) key = new Uint8Array(key);\n else if (!Array.isArray(key)) {\n if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) throw new Error(ERROR);\n }\n } else throw new Error(ERROR);\n if (key.length > 64) key = new Sha256(is224, true).update(key).array();\n var oKeyPad = [], iKeyPad = [];\n for(i = 0; i < 64; ++i){\n var b = key[i] || 0;\n oKeyPad[i] = 0x5c ^ b;\n iKeyPad[i] = 0x36 ^ b;\n }\n Sha256.call(this, is224, sharedMemory);\n this.update(iKeyPad);\n this.oKeyPad = oKeyPad;\n this.inner = true;\n this.sharedMemory = sharedMemory;\n }\n HmacSha256.prototype = new Sha256();\n HmacSha256.prototype.finalize = function() {\n Sha256.prototype.finalize.call(this);\n if (this.inner) {\n this.inner = false;\n var innerHash = this.array();\n Sha256.call(this, this.is224, this.sharedMemory);\n this.update(this.oKeyPad);\n this.update(innerHash);\n Sha256.prototype.finalize.call(this);\n }\n };\n var exports = createMethod();\n exports.sha256 = exports;\n exports.sha224 = createMethod(true);\n exports.sha256.hmac = createHmacMethod();\n exports.sha224.hmac = createHmacMethod(true);\n if (COMMON_JS) module.exports = exports;\n else {\n root.sha256 = exports.sha256;\n root.sha224 = exports.sha224;\n if (AMD) define(function() {\n return exports;\n });\n }\n })();\n },\n \"?4999\" () {},\n \"?c118\" () {}\n };\n var __webpack_module_cache__ = {};\n function __webpack_require__(moduleId) {\n var cachedModule = __webpack_module_cache__[moduleId];\n if (void 0 !== cachedModule) return cachedModule.exports;\n var module = __webpack_module_cache__[moduleId] = {\n id: moduleId,\n loaded: false,\n exports: {}\n };\n __webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n module.loaded = true;\n return module.exports;\n }\n (()=>{\n __webpack_require__.d = (exports, definition)=>{\n for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {\n enumerable: true,\n get: definition[key]\n });\n };\n })();\n (()=>{\n __webpack_require__.g = (()=>{\n if ('object' == typeof globalThis) return globalThis;\n try {\n return this || new Function('return this')();\n } catch (e) {\n if ('object' == typeof window) return window;\n }\n })();\n })();\n (()=>{\n __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);\n })();\n (()=>{\n __webpack_require__.r = (exports)=>{\n if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n };\n })();\n (()=>{\n __webpack_require__.nmd = (module)=>{\n module.paths = [];\n if (!module.children) module.children = [];\n return module;\n };\n })();\n var __webpack_exports__ = {};\n (()=>{\n \"use strict\";\n __webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, {\n getNodeInfoByXpath: ()=>getNodeInfoByXpath,\n getXpathsById: ()=>getXpathsById,\n trimAttributes: ()=>trimAttributes,\n webExtractNodeTreeAsString: ()=>extractTreeNodeAsString,\n getElementXpath: ()=>getElementXpath,\n webExtractNodeTree: ()=>extractTreeNode,\n generateElementByRect: ()=>generateElementByRect,\n descriptionOfTree: ()=>descriptionOfTree,\n getXpathsByPoint: ()=>getXpathsByPoint,\n webExtractTextWithPosition: ()=>web_extractor_extractTextWithPosition,\n treeToList: ()=>treeToList,\n traverseTree: ()=>traverseTree,\n isNotContainerElement: ()=>isNotContainerElement,\n truncateText: ()=>truncateText,\n getElementInfoByXpath: ()=>getElementInfoByXpath\n });\n function truncateText(text, maxLength = 150) {\n if (void 0 === text) return '';\n if ('object' == typeof text) text = JSON.stringify(text);\n if ('number' == typeof text) return text.toString();\n if ('string' == typeof text && text.length > maxLength) return `${text.slice(0, maxLength)}...`;\n if ('string' == typeof text) return text.trim();\n return '';\n }\n function trimAttributes(attributes, truncateTextLength) {\n const tailorAttributes = Object.keys(attributes).reduce((res, currentKey)=>{\n const attributeVal = attributes[currentKey];\n if ('style' === currentKey || 'htmlTagName' === currentKey || 'nodeType' === currentKey) return res;\n res[currentKey] = truncateText(attributeVal, truncateTextLength);\n return res;\n }, {});\n return tailorAttributes;\n }\n const nodeSizeThreshold = 4;\n function descriptionOfTree(tree, truncateTextLength, filterNonTextContent = false, visibleOnly = true) {\n const attributesString = (kv)=>Object.entries(kv).map(([key, value])=>`${key}=\"${truncateText(value, truncateTextLength)}\"`).join(' ');\n function buildContentTree(node, indent = 0, visibleOnly = true) {\n let before = '';\n let contentWithIndent = '';\n let after = '';\n let emptyNode = true;\n const indentStr = ' '.repeat(indent);\n let children = '';\n for(let i = 0; i < (node.children || []).length; i++){\n const childContent = buildContentTree(node.children[i], indent + 1, visibleOnly);\n if (childContent) children += `\\n${childContent}`;\n }\n if (node.node && node.node.rect.width > nodeSizeThreshold && node.node.rect.height > nodeSizeThreshold && (!filterNonTextContent || filterNonTextContent && node.node.content) && (!visibleOnly || visibleOnly && node.node.isVisible)) {\n emptyNode = false;\n let nodeTypeString;\n nodeTypeString = node.node.attributes?.htmlTagName ? node.node.attributes.htmlTagName.replace(/[<>]/g, '') : node.node.attributes.nodeType.replace(/\\sNode$/, '').toLowerCase();\n const rectAttribute = node.node.rect ? {\n left: node.node.rect.left,\n top: node.node.rect.top,\n width: node.node.rect.width,\n height: node.node.rect.height\n } : {};\n before = `<${nodeTypeString} id=\"${node.node.id}\" ${attributesString(trimAttributes(node.node.attributes || {}, truncateTextLength))} ${attributesString(rectAttribute)}>`;\n const content = truncateText(node.node.content, truncateTextLength);\n contentWithIndent = content ? `\\n${indentStr} ${content}` : '';\n after = `</${nodeTypeString}>`;\n } else if (!filterNonTextContent) {\n if (!children.trim().startsWith('<>')) {\n before = '<>';\n contentWithIndent = '';\n after = '</>';\n }\n }\n if (emptyNode && !children.trim()) return '';\n const result = `${indentStr}${before}${contentWithIndent}${children}\\n${indentStr}${after}`;\n if (result.trim()) return result;\n return '';\n }\n const result = buildContentTree(tree, 0, visibleOnly);\n return result.replace(/^\\s*\\n/gm, '');\n }\n function treeToList(tree) {\n const result = [];\n function dfs(node) {\n if (node.node) result.push(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return result;\n }\n function traverseTree(tree, onNode) {\n function dfs(node) {\n if (node.node) node.node = onNode(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return tree;\n }\n const CONTAINER_MINI_HEIGHT = 3;\n const CONTAINER_MINI_WIDTH = 3;\n function isFormElement(node) {\n return node instanceof HTMLElement && ('input' === node.tagName.toLowerCase() || 'textarea' === node.tagName.toLowerCase() || 'select' === node.tagName.toLowerCase() || 'option' === node.tagName.toLowerCase());\n }\n function isButtonElement(node) {\n return node instanceof HTMLElement && 'button' === node.tagName.toLowerCase();\n }\n function isAElement(node) {\n return node instanceof HTMLElement && 'a' === node.tagName.toLowerCase();\n }\n function isSvgElement(node) {\n return node instanceof SVGElement;\n }\n function isImgElement(node) {\n if (!includeBaseElement(node) && node instanceof Element) {\n const computedStyle = window.getComputedStyle(node);\n const backgroundImage = computedStyle.getPropertyValue('background-image');\n if ('none' !== backgroundImage) return true;\n }\n if (isIconfont(node)) return true;\n return node instanceof HTMLElement && 'img' === node.tagName.toLowerCase() || node instanceof SVGElement && 'svg' === node.tagName.toLowerCase();\n }\n function isIconfont(node) {\n if (node instanceof Element) {\n const computedStyle = window.getComputedStyle(node);\n const fontFamilyValue = computedStyle.fontFamily || '';\n return fontFamilyValue.toLowerCase().indexOf('iconfont') >= 0;\n }\n return false;\n }\n function isNotContainerElement(node) {\n return isTextElement(node) || isIconfont(node) || isImgElement(node) || isButtonElement(node) || isAElement(node) || isFormElement(node);\n }\n function isTextElement(node) {\n if (node instanceof Element) {\n if (node?.childNodes?.length === 1 && node?.childNodes[0] instanceof Text) return true;\n }\n return node.nodeName?.toLowerCase?.() === '#text' && !isIconfont(node);\n }\n function isContainerElement(node) {\n if (!(node instanceof HTMLElement)) return false;\n if (includeBaseElement(node)) return false;\n const computedStyle = window.getComputedStyle(node);\n const backgroundColor = computedStyle.getPropertyValue('background-color');\n if (backgroundColor) return true;\n return false;\n }\n function includeBaseElement(node) {\n if (!(node instanceof HTMLElement)) return false;\n if (node.innerText) return true;\n const includeList = [\n 'svg',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'option',\n 'img',\n 'a'\n ];\n for (const tagName of includeList){\n const element = node.querySelectorAll(tagName);\n if (element.length > 0) return true;\n }\n return false;\n }\n function generateElementByPoint(center, description, edgeSize = 8) {\n const [centerX, centerY] = center;\n const offset = Math.ceil(edgeSize / 2) - 1;\n const expandedRect = {\n left: Math.max(centerX - offset, 0),\n top: Math.max(centerY - offset, 0),\n width: edgeSize,\n height: edgeSize\n };\n return {\n rect: expandedRect,\n center: [\n centerX,\n centerY\n ],\n description: description || ''\n };\n }\n function generateElementByRect(sourceRect, description, edgeSize = 8) {\n const centerX = sourceRect.left + Math.floor((sourceRect.width - 1) / 2);\n const centerY = sourceRect.top + Math.floor((sourceRect.height - 1) / 2);\n return generateElementByPoint([\n centerX,\n centerY\n ], description, edgeSize);\n }\n var sha256 = __webpack_require__(\"../../node_modules/.pnpm/js-sha256@0.11.0/node_modules/js-sha256/src/sha256.js\");\n 'undefined' != typeof process && process.versions?.node;\n const hashMap = {};\n function generateHashId(rect, content = '') {\n const combined = JSON.stringify({\n content,\n rect\n });\n let sliceLength = 5;\n let slicedHash = '';\n const hashHex = sha256.sha256.create().update(combined).hex();\n const toLetters = (hex)=>hex.split('').map((char)=>{\n const code = Number.parseInt(char, 16);\n return String.fromCharCode(97 + code % 26);\n }).join('');\n const hashLetters = toLetters(hashHex);\n while(sliceLength < hashLetters.length - 1){\n slicedHash = hashLetters.slice(0, sliceLength);\n if (hashMap[slicedHash] && hashMap[slicedHash] !== combined) {\n sliceLength++;\n continue;\n }\n hashMap[slicedHash] = combined;\n break;\n }\n return slicedHash;\n }\n const MAX_VALUE_LENGTH = 300;\n let util_debugMode = false;\n function setDebugMode(mode) {\n util_debugMode = mode;\n }\n function logger(..._msg) {\n if (!util_debugMode) return;\n console.log(..._msg);\n }\n function isElementPartiallyInViewport(rect, currentWindow, currentDocument, visibleAreaRatio = 2 / 3) {\n const elementHeight = rect.height;\n const elementWidth = rect.width;\n const viewportRect = {\n left: 0,\n top: 0,\n width: currentWindow.innerWidth || currentDocument.documentElement.clientWidth,\n height: currentWindow.innerHeight || currentDocument.documentElement.clientHeight,\n right: currentWindow.innerWidth || currentDocument.documentElement.clientWidth,\n bottom: currentWindow.innerHeight || currentDocument.documentElement.clientHeight,\n x: 0,\n y: 0,\n zoom: 1\n };\n const overlapRect = overlappedRect(rect, viewportRect);\n if (!overlapRect) return false;\n const visibleArea = overlapRect.width * overlapRect.height;\n const totalArea = elementHeight * elementWidth;\n return visibleArea / totalArea >= visibleAreaRatio;\n }\n function getPseudoElementContent(element, currentWindow) {\n if (!(element instanceof currentWindow.HTMLElement)) return {\n before: '',\n after: ''\n };\n const beforeContent = currentWindow.getComputedStyle(element, '::before').getPropertyValue('content');\n const afterContent = currentWindow.getComputedStyle(element, '::after').getPropertyValue('content');\n return {\n before: 'none' === beforeContent ? '' : beforeContent.replace(/\"/g, ''),\n after: 'none' === afterContent ? '' : afterContent.replace(/\"/g, '')\n };\n }\n function overlappedRect(rect1, rect2) {\n const left = Math.max(rect1.left, rect2.left);\n const top = Math.max(rect1.top, rect2.top);\n const right = Math.min(rect1.right, rect2.right);\n const bottom = Math.min(rect1.bottom, rect2.bottom);\n if (left < right && top < bottom) return {\n left,\n top,\n right,\n bottom,\n width: right - left,\n height: bottom - top,\n x: left,\n y: top,\n zoom: 1\n };\n return null;\n }\n function getRect(el, baseZoom, currentWindow) {\n let originalRect;\n let newZoom = 1;\n const hasGetBoundingClientRect = el instanceof Element;\n if (hasGetBoundingClientRect) {\n originalRect = el.getBoundingClientRect();\n if (el instanceof currentWindow.HTMLElement && !('currentCSSZoom' in el)) newZoom = Number.parseFloat(currentWindow.getComputedStyle(el).zoom) || 1;\n } else {\n const range = currentWindow.document.createRange();\n range.selectNodeContents(el);\n originalRect = range.getBoundingClientRect();\n }\n const zoom = newZoom * baseZoom;\n return {\n width: originalRect.width * zoom,\n height: originalRect.height * zoom,\n left: originalRect.left * zoom,\n top: originalRect.top * zoom,\n right: originalRect.right * zoom,\n bottom: originalRect.bottom * zoom,\n x: originalRect.x * zoom,\n y: originalRect.y * zoom,\n zoom\n };\n }\n const isElementCovered = (el, rect, currentWindow)=>{\n const x = rect.left + rect.width / 2;\n const y = rect.top + rect.height / 2;\n const topElement = currentWindow.document.elementFromPoint(x, y);\n if (!topElement) return false;\n if (topElement === el) return false;\n if (el?.contains(topElement)) return false;\n if (topElement?.contains(el)) return false;\n const rectOfTopElement = getRect(topElement, 1, currentWindow);\n const overlapRect = overlappedRect(rect, rectOfTopElement);\n if (!overlapRect) return false;\n logger(el, 'Element is covered by another element', {\n topElement,\n el,\n rect,\n x,\n y\n });\n return true;\n };\n function elementRect(el, currentWindow, currentDocument, baseZoom = 1) {\n if (!el) {\n logger(el, 'Element is not in the DOM hierarchy');\n return false;\n }\n if (!(el instanceof currentWindow.HTMLElement) && el.nodeType !== Node.TEXT_NODE && 'svg' !== el.nodeName.toLowerCase()) {\n logger(el, 'Element is not in the DOM hierarchy');\n return false;\n }\n if (el instanceof currentWindow.HTMLElement) {\n const style = currentWindow.getComputedStyle(el);\n if ('none' === style.display || 'hidden' === style.visibility || '0' === style.opacity && 'INPUT' !== el.tagName) {\n logger(el, 'Element is hidden');\n return false;\n }\n }\n const rect = getRect(el, baseZoom, currentWindow);\n if (0 === rect.width && 0 === rect.height) {\n logger(el, 'Element has no size');\n return false;\n }\n if (1 === baseZoom && isElementCovered(el, rect, currentWindow)) return false;\n const isVisible = isElementPartiallyInViewport(rect, currentWindow, currentDocument);\n let parent = el;\n const parentUntilNonStatic = (currentNode)=>{\n let parent = currentNode?.parentElement;\n while(parent){\n const style = currentWindow.getComputedStyle(parent);\n if ('static' !== style.position) return parent;\n parent = parent.parentElement;\n }\n return null;\n };\n while(parent && parent !== currentDocument.body){\n if (!(parent instanceof currentWindow.HTMLElement)) {\n parent = parent.parentElement;\n continue;\n }\n const parentStyle = currentWindow.getComputedStyle(parent);\n if ('hidden' === parentStyle.overflow) {\n const parentRect = getRect(parent, 1, currentWindow);\n const tolerance = 10;\n if (rect.right < parentRect.left - tolerance || rect.left > parentRect.right + tolerance || rect.bottom < parentRect.top - tolerance || rect.top > parentRect.bottom + tolerance) {\n logger(el, 'element is partially or totally hidden by an ancestor', {\n rect,\n parentRect\n });\n return false;\n }\n }\n if ('fixed' === parentStyle.position || 'sticky' === parentStyle.position) break;\n parent = 'absolute' === parentStyle.position ? parentUntilNonStatic(parent) : parent.parentElement;\n }\n return {\n left: Math.round(rect.left),\n top: Math.round(rect.top),\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n zoom: rect.zoom,\n isVisible\n };\n }\n function getNodeAttributes(node, currentWindow) {\n if (!node || !(node instanceof currentWindow.HTMLElement) || !node.attributes) return {};\n const attributesList = Array.from(node.attributes).map((attr)=>{\n if ('class' === attr.name) return [\n attr.name,\n `.${attr.value.split(' ').join('.')}`\n ];\n let value = attr.value;\n if (value.startsWith('data:image')) value = 'image';\n if (value.length > MAX_VALUE_LENGTH) value = `${value.slice(0, MAX_VALUE_LENGTH)}...`;\n return [\n attr.name,\n value\n ];\n });\n return Object.fromEntries(attributesList);\n }\n const NODE_CACHE_MAX_SIZE = 2000;\n function setNodeHashCacheListOnWindow() {\n if ('undefined' != typeof window) window.midsceneNodeHashCache = new Map();\n }\n function getNodeCacheMap() {\n if ('undefined' == typeof window) return;\n return window.midsceneNodeHashCache;\n }\n function setNodeToCacheList(node, id) {\n const cache = getNodeCacheMap();\n if (!cache) return;\n if (cache.has(id)) return;\n if (cache.size >= NODE_CACHE_MAX_SIZE) {\n const firstKey = cache.keys().next().value;\n if (void 0 !== firstKey) cache.delete(firstKey);\n }\n cache.set(id, node);\n }\n function getNodeFromCacheList(id) {\n return getNodeCacheMap()?.get(id);\n }\n function midsceneGenerateHash(node, content, rect) {\n const slicedHash = generateHashId(rect, content);\n if (node) {\n if ('undefined' != typeof window && !getNodeCacheMap()) setNodeHashCacheListOnWindow();\n setNodeToCacheList(node, slicedHash);\n }\n return slicedHash;\n }\n function getTopDocument() {\n const container = document.body || document;\n return container;\n }\n let indexId = 0;\n function tagNameOfNode(node) {\n let tagName = '';\n if (node instanceof HTMLElement) tagName = node.tagName?.toLowerCase();\n else {\n const parentElement = node.parentElement;\n if (parentElement && parentElement instanceof HTMLElement) tagName = parentElement.tagName?.toLowerCase();\n }\n return tagName ? `<${tagName}>` : '';\n }\n function collectElementInfo(node, currentWindow, currentDocument, baseZoom = 1, basePoint = {\n left: 0,\n top: 0\n }, isContainer = false) {\n const rect = elementRect(node, currentWindow, currentDocument, baseZoom);\n if (!rect) return null;\n if (rect.width < CONTAINER_MINI_WIDTH || rect.height < CONTAINER_MINI_HEIGHT) return null;\n if (0 !== basePoint.left || 0 !== basePoint.top) {\n rect.left += basePoint.left;\n rect.top += basePoint.top;\n }\n if (rect.height >= window.innerHeight && rect.width >= window.innerWidth) return null;\n if (isFormElement(node)) {\n const attributes = getNodeAttributes(node, currentWindow);\n let valueContent = attributes.value || attributes.placeholder || node.textContent || '';\n const nodeHashId = midsceneGenerateHash(node, valueContent, rect);\n const tagName = node.tagName.toLowerCase();\n if ('select' === node.tagName.toLowerCase()) {\n const selectedOption = node.options[node.selectedIndex];\n valueContent = selectedOption?.textContent || '';\n }\n if (('input' === node.tagName.toLowerCase() || 'textarea' === node.tagName.toLowerCase()) && node.value) valueContent = node.value;\n const elementInfo = {\n id: nodeHashId,\n nodeHashId,\n nodeType: \"FORM_ITEM Node\",\n indexId: indexId++,\n attributes: {\n ...attributes,\n htmlTagName: `<${tagName}>`,\n nodeType: \"FORM_ITEM Node\"\n },\n content: valueContent.trim(),\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isButtonElement(node)) {\n const rect = mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom);\n if (!rect) return null;\n const attributes = getNodeAttributes(node, currentWindow);\n const pseudo = getPseudoElementContent(node, currentWindow);\n const content = node.innerText || pseudo.before || pseudo.after || '';\n const nodeHashId = midsceneGenerateHash(node, content, rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n nodeType: \"BUTTON Node\",\n attributes: {\n ...attributes,\n htmlTagName: tagNameOfNode(node),\n nodeType: \"BUTTON Node\"\n },\n content,\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isImgElement(node)) {\n const attributes = getNodeAttributes(node, currentWindow);\n const nodeHashId = midsceneGenerateHash(node, '', rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n attributes: {\n ...attributes,\n ...node.nodeName?.toLowerCase() === 'svg' ? {\n svgContent: 'true'\n } : {},\n nodeType: \"IMG Node\",\n htmlTagName: tagNameOfNode(node)\n },\n nodeType: \"IMG Node\",\n content: '',\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isTextElement(node)) {\n const text = node.textContent?.trim().replace(/\\n+/g, ' ');\n if (!text) return null;\n const attributes = getNodeAttributes(node, currentWindow);\n const attributeKeys = Object.keys(attributes);\n if (!text.trim() && 0 === attributeKeys.length) return null;\n const nodeHashId = midsceneGenerateHash(node, text, rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n nodeType: \"TEXT Node\",\n attributes: {\n ...attributes,\n nodeType: \"TEXT Node\",\n htmlTagName: tagNameOfNode(node)\n },\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n content: text,\n rect,\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isAElement(node)) {\n const attributes = getNodeAttributes(node, currentWindow);\n const pseudo = getPseudoElementContent(node, currentWindow);\n const content = node.innerText || pseudo.before || pseudo.after || '';\n const nodeHashId = midsceneGenerateHash(node, content, rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n nodeType: \"Anchor Node\",\n attributes: {\n ...attributes,\n htmlTagName: tagNameOfNode(node),\n nodeType: \"Anchor Node\"\n },\n content,\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isContainerElement(node) || isContainer) {\n const attributes = getNodeAttributes(node, currentWindow);\n const nodeHashId = midsceneGenerateHash(node, '', rect);\n const elementInfo = {\n id: nodeHashId,\n nodeHashId,\n indexId: indexId++,\n nodeType: \"CONTAINER Node\",\n attributes: {\n ...attributes,\n nodeType: \"CONTAINER Node\",\n htmlTagName: tagNameOfNode(node)\n },\n content: '',\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n return null;\n }\n function web_extractor_extractTextWithPosition(initNode, debugMode = false) {\n const elementNode = extractTreeNode(initNode, debugMode);\n const elementInfoArray = [];\n function dfsTopChildren(node) {\n if (node.node) elementInfoArray.push(node.node);\n for(let i = 0; i < node.children.length; i++)dfsTopChildren(node.children[i]);\n }\n dfsTopChildren({\n children: elementNode.children,\n node: elementNode.node\n });\n return elementInfoArray;\n }\n function extractTreeNodeAsString(initNode, visibleOnly = false, debugMode = false) {\n const elementNode = extractTreeNode(initNode, debugMode);\n return descriptionOfTree(elementNode, void 0, false, visibleOnly);\n }\n function extractTreeNode(initNode, debugMode = false) {\n setDebugMode(debugMode);\n indexId = 0;\n const topDocument = getTopDocument();\n const startNode = initNode || topDocument;\n const topChildren = [];\n function dfs(node, currentWindow, currentDocument, baseZoom = 1, basePoint = {\n left: 0,\n top: 0\n }) {\n if (!node) return null;\n if (node.nodeType && 10 === node.nodeType) return null;\n const elementInfo = collectElementInfo(node, currentWindow, currentDocument, baseZoom, basePoint);\n if (node instanceof currentWindow.HTMLIFrameElement) {\n if (node.contentWindow && node.contentWindow) return null;\n }\n const nodeInfo = {\n node: elementInfo,\n children: []\n };\n if (elementInfo?.nodeType === \"BUTTON Node\" || elementInfo?.nodeType === \"IMG Node\" || elementInfo?.nodeType === \"TEXT Node\" || elementInfo?.nodeType === \"FORM_ITEM Node\" || elementInfo?.nodeType === \"CONTAINER Node\") return nodeInfo;\n const rect = getRect(node, baseZoom, currentWindow);\n for(let i = 0; i < node.childNodes.length; i++){\n logger('will dfs', node.childNodes[i]);\n const childNodeInfo = dfs(node.childNodes[i], currentWindow, currentDocument, rect.zoom, basePoint);\n if (Array.isArray(childNodeInfo)) nodeInfo.children.push(...childNodeInfo);\n else if (childNodeInfo) nodeInfo.children.push(childNodeInfo);\n }\n if (null === nodeInfo.node) {\n if (0 === nodeInfo.children.length) return null;\n return nodeInfo.children;\n }\n return nodeInfo;\n }\n const rootNodeInfo = dfs(startNode, window, document, 1, {\n left: 0,\n top: 0\n });\n if (Array.isArray(rootNodeInfo)) topChildren.push(...rootNodeInfo);\n else if (rootNodeInfo) topChildren.push(rootNodeInfo);\n if (startNode === topDocument) {\n const iframes = document.querySelectorAll('iframe');\n for(let i = 0; i < iframes.length; i++){\n const iframe = iframes[i];\n if (iframe.contentDocument && iframe.contentWindow) {\n const iframeInfo = collectElementInfo(iframe, window, document, 1);\n if (iframeInfo) {\n const iframeChildren = dfs(iframe.contentDocument.body, iframe.contentWindow, iframe.contentDocument, 1, {\n left: iframeInfo.rect.left,\n top: iframeInfo.rect.top\n });\n if (Array.isArray(iframeChildren)) topChildren.push(...iframeChildren);\n else if (iframeChildren) topChildren.push(iframeChildren);\n }\n }\n }\n }\n return {\n node: null,\n children: topChildren\n };\n }\n function mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom = 1) {\n const selfRect = elementRect(node, currentWindow, currentDocument, baseZoom);\n if (!selfRect) return null;\n let minLeft = selfRect.left;\n let minTop = selfRect.top;\n let maxRight = selfRect.left + selfRect.width;\n let maxBottom = selfRect.top + selfRect.height;\n function traverse(child) {\n for(let i = 0; i < child.childNodes.length; i++){\n const sub = child.childNodes[i];\n if (1 === sub.nodeType) {\n const rect = elementRect(sub, currentWindow, currentDocument, baseZoom);\n if (rect) {\n minLeft = Math.min(minLeft, rect.left);\n minTop = Math.min(minTop, rect.top);\n maxRight = Math.max(maxRight, rect.left + rect.width);\n maxBottom = Math.max(maxBottom, rect.top + rect.height);\n }\n traverse(sub);\n }\n }\n }\n traverse(node);\n return {\n ...selfRect,\n left: minLeft,\n top: minTop,\n width: maxRight - minLeft,\n height: maxBottom - minTop\n };\n }\n const SUB_XPATH_SEPARATOR = '|>>|';\n function parseCSSZoom(style) {\n return Number.parseFloat(style.zoom ?? '1') || 1;\n }\n function calculateIframeOffset(nodeOwnerDoc, rootDoc) {\n let leftOffset = 0;\n let topOffset = 0;\n let iterDoc = nodeOwnerDoc;\n while(iterDoc && iterDoc !== rootDoc)try {\n const frameElement = iterDoc.defaultView?.frameElement;\n if (!frameElement) break;\n const rect = frameElement.getBoundingClientRect();\n const parentWin = iterDoc.defaultView?.parent;\n let borderLeft = 0;\n let borderTop = 0;\n let zoom = 1;\n try {\n if (parentWin) {\n const style = parentWin.getComputedStyle(frameElement);\n borderLeft = Number.parseFloat(style.borderLeftWidth) || 0;\n borderTop = Number.parseFloat(style.borderTopWidth) || 0;\n zoom = parseCSSZoom(style);\n }\n } catch {}\n leftOffset = leftOffset / zoom + rect.left + borderLeft;\n topOffset = topOffset / zoom + rect.top + borderTop;\n iterDoc = frameElement.ownerDocument;\n } catch {\n break;\n }\n return {\n left: leftOffset,\n top: topOffset\n };\n }\n function translatePointToIframeCoordinates(point, iframeElement, parentWindow) {\n const rect = iframeElement.getBoundingClientRect();\n const style = parentWindow.getComputedStyle(iframeElement);\n const clientLeft = iframeElement.clientLeft;\n const clientTop = iframeElement.clientTop;\n const paddingLeft = Number.parseFloat(style.paddingLeft) || 0;\n const paddingTop = Number.parseFloat(style.paddingTop) || 0;\n const zoom = parseCSSZoom(style);\n return {\n left: (point.left - rect.left - clientLeft - paddingLeft) / zoom,\n top: (point.top - rect.top - clientTop - paddingTop) / zoom\n };\n }\n const getElementXpathIndex = (element)=>{\n let index = 1;\n let prev = element.previousElementSibling;\n while(prev){\n if (prev.nodeName.toLowerCase() === element.nodeName.toLowerCase()) index++;\n prev = prev.previousElementSibling;\n }\n return index;\n };\n const normalizeXpathText = (text)=>{\n if ('string' != typeof text) return '';\n return text.replace(/\\s+/g, ' ').trim();\n };\n const buildCurrentElementXpath = (element, isOrderSensitive, isLeafElement, limitToCurrentDocument = false)=>{\n const parentPath = element.parentNode ? getElementXpath(element.parentNode, isOrderSensitive, false, limitToCurrentDocument) : '';\n const prefix = parentPath ? `${parentPath}/` : '/';\n const tagName = element.nodeName.toLowerCase();\n const textContent = element.textContent?.trim();\n const isSVGNamespace = 'http://www.w3.org/2000/svg' === element.namespaceURI;\n const tagSelector = isSVGNamespace ? `*[name()=\"${tagName}\"]` : tagName;\n if (isOrderSensitive) {\n const index = getElementXpathIndex(element);\n return `${prefix}${tagSelector}[${index}]`;\n }\n if (isLeafElement && textContent) return `${prefix}${tagSelector}[normalize-space()=\"${normalizeXpathText(textContent)}\"]`;\n const index = getElementXpathIndex(element);\n return `${prefix}${tagSelector}[${index}]`;\n };\n const getElementXpath = (element, isOrderSensitive = false, isLeafElement = false, limitToCurrentDocument = false)=>{\n if (element.nodeType === Node.TEXT_NODE) {\n const parentNode = element.parentNode;\n if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {\n const parentXPath = getElementXpath(parentNode, isOrderSensitive, true, limitToCurrentDocument);\n const textContent = element.textContent?.trim();\n if (textContent) return `${parentXPath}/text()[normalize-space()=\"${normalizeXpathText(textContent)}\"]`;\n return `${parentXPath}/text()`;\n }\n return '';\n }\n if (element.nodeType !== Node.ELEMENT_NODE) return '';\n const el = element;\n try {\n const nodeName = el.nodeName.toLowerCase();\n if (el === el.ownerDocument?.documentElement || 'html' === nodeName) {\n if (!limitToCurrentDocument) {\n const frameElement = el.ownerDocument?.defaultView?.frameElement;\n if (frameElement) {\n const framePath = getElementXpath(frameElement, isOrderSensitive, false, limitToCurrentDocument);\n return `${framePath}${SUB_XPATH_SEPARATOR}/html`;\n }\n }\n return '/html';\n }\n if (el === el.ownerDocument?.body || 'body' === nodeName) {\n if (!limitToCurrentDocument) {\n const frameElement = el.ownerDocument?.defaultView?.frameElement;\n if (frameElement) {\n const framePath = getElementXpath(frameElement, isOrderSensitive, false, limitToCurrentDocument);\n return `${framePath}${SUB_XPATH_SEPARATOR}/html/body`;\n }\n }\n return '/html/body';\n }\n } catch (error) {\n logger('[midscene:locator] ownerDocument access failed:', error);\n if ('html' === el.nodeName.toLowerCase()) return '/html';\n if ('body' === el.nodeName.toLowerCase()) return '/html/body';\n }\n if (isSvgElement(el)) {\n const tagName = el.nodeName.toLowerCase();\n if ('svg' === tagName) return buildCurrentElementXpath(el, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n let parent = el.parentNode;\n while(parent && parent.nodeType === Node.ELEMENT_NODE){\n const parentEl = parent;\n if (!isSvgElement(parentEl)) return getElementXpath(parentEl, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n const parentTag = parentEl.nodeName.toLowerCase();\n if ('svg' === parentTag) return getElementXpath(parentEl, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n parent = parent.parentNode;\n }\n const fallbackParent = el.parentNode;\n if (fallbackParent && fallbackParent.nodeType === Node.ELEMENT_NODE) return getElementXpath(fallbackParent, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n return '';\n }\n return buildCurrentElementXpath(el, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n };\n function getXpathsById(id) {\n const node = getNodeFromCacheList(id);\n if (!node) return null;\n const fullXPath = getElementXpath(node, false, true, true);\n return [\n fullXPath\n ];\n }\n function getXpathsByPoint(point, isOrderSensitive) {\n let currentWindow = 'undefined' != typeof window ? window : void 0;\n let currentDocument = 'undefined' != typeof document ? document : void 0;\n let { left, top } = point;\n let depth = 0;\n const MAX_DEPTH = 10;\n let xpathPrefix = '';\n let lastFoundElement = null;\n while(depth < MAX_DEPTH){\n depth++;\n const element = currentDocument.elementFromPoint(left, top);\n if (!element) {\n if (lastFoundElement) {\n const fullXPath = getElementXpath(lastFoundElement, isOrderSensitive, true, true);\n return [\n xpathPrefix + fullXPath\n ];\n }\n return null;\n }\n lastFoundElement = element;\n const tag = element.tagName.toLowerCase();\n if ('iframe' === tag || 'frame' === tag) try {\n const contentWindow = element.contentWindow;\n const contentDocument = element.contentDocument;\n if (contentWindow && contentDocument) {\n const localPoint = translatePointToIframeCoordinates({\n left,\n top\n }, element, currentWindow);\n const currentIframeXpath = getElementXpath(element, isOrderSensitive, false, true);\n xpathPrefix += currentIframeXpath + SUB_XPATH_SEPARATOR;\n currentWindow = contentWindow;\n currentDocument = contentDocument;\n left = localPoint.left;\n top = localPoint.top;\n continue;\n }\n } catch (error) {\n logger('[midscene:locator] iframe penetration failed (cross-origin?):', error);\n }\n const fullXPath = getElementXpath(element, isOrderSensitive, true, true);\n return [\n xpathPrefix + fullXPath\n ];\n }\n if (lastFoundElement) {\n const fullXPath = getElementXpath(lastFoundElement, isOrderSensitive, true, true);\n return [\n xpathPrefix + fullXPath\n ];\n }\n return null;\n }\n function getNodeInfoByXpath(xpath) {\n const parts = xpath.split(SUB_XPATH_SEPARATOR).map((p)=>p.trim()).filter(Boolean);\n if (0 === parts.length) return null;\n let currentDocument = 'undefined' != typeof document ? document : void 0;\n let node = null;\n for(let i = 0; i < parts.length; i++){\n const currentXpath = parts[i];\n const xpathResult = currentDocument.evaluate(currentXpath, currentDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n if (1 !== xpathResult.snapshotLength) {\n logger(`[midscene:locator] XPath \"${currentXpath}\" matched ${xpathResult.snapshotLength} elements (expected 1), discarding.`);\n return null;\n }\n node = xpathResult.snapshotItem(0);\n if (i < parts.length - 1) if (!node || node.nodeType !== Node.ELEMENT_NODE || 'iframe' !== node.tagName.toLowerCase()) return null;\n else try {\n const contentDocument = node.contentDocument;\n if (contentDocument) currentDocument = contentDocument;\n else {\n logger('[midscene:locator] iframe contentDocument is null (cross-origin?)');\n return null;\n }\n } catch (error) {\n logger('[midscene:locator] iframe contentDocument access failed:', error);\n return null;\n }\n }\n return node;\n }\n function getElementInfoByXpath(xpath) {\n const node = getNodeInfoByXpath(xpath);\n if (!node) return null;\n let targetWindow = 'undefined' != typeof window ? window : void 0;\n let targetDocument = 'undefined' != typeof document ? document : void 0;\n if (node.ownerDocument?.defaultView) {\n targetWindow = node.ownerDocument.defaultView;\n targetDocument = node.ownerDocument;\n }\n const rootDoc = 'undefined' != typeof document ? document : null;\n const iframeOffset = calculateIframeOffset(node.ownerDocument ?? null, rootDoc);\n const targetWin = targetWindow;\n const targetDoc = targetDocument;\n if (node instanceof targetWin.HTMLElement) {\n const rect = getRect(node, 1, targetWin);\n const isVisible = isElementPartiallyInViewport(rect, targetWin, targetDoc, 1);\n if (!isVisible) node.scrollIntoView({\n behavior: 'instant',\n block: 'center'\n });\n }\n return collectElementInfo(node, targetWin, targetDoc, 1, iframeOffset, true);\n }\n })();\n window.midscene_element_inspector = __webpack_exports__;\n})();\n";
75
+ const htmlElementScript = "(()=>{\n var __webpack_modules__ = {\n \"../../node_modules/.pnpm/js-sha256@0.11.0/node_modules/js-sha256/src/sha256.js\" (module, __unused_rspack_exports, __webpack_require__) {\n module = __webpack_require__.nmd(module);\n /**\n * [js-sha256]{@link https://github.com/emn178/js-sha256}\n *\n * @version 0.11.0\n * @author Chen, Yi-Cyuan [emn178@gmail.com]\n * @copyright Chen, Yi-Cyuan 2014-2024\n * @license MIT\n */ (function() {\n 'use strict';\n var ERROR = 'input is invalid type';\n var WINDOW = 'object' == typeof window;\n var root = WINDOW ? window : {};\n if (root.JS_SHA256_NO_WINDOW) WINDOW = false;\n var WEB_WORKER = !WINDOW && 'object' == typeof self;\n var NODE_JS = !root.JS_SHA256_NO_NODE_JS && 'object' == typeof process && process.versions && process.versions.node;\n if (NODE_JS) root = __webpack_require__.g;\n else if (WEB_WORKER) root = self;\n var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && 'object' == typeof module && module.exports;\n var AMD = 'function' == typeof define && define.amd;\n var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && 'undefined' != typeof ArrayBuffer;\n var HEX_CHARS = '0123456789abcdef'.split('');\n var EXTRA = [\n -2147483648,\n 8388608,\n 32768,\n 128\n ];\n var SHIFT = [\n 24,\n 16,\n 8,\n 0\n ];\n var K = [\n 0x428a2f98,\n 0x71374491,\n 0xb5c0fbcf,\n 0xe9b5dba5,\n 0x3956c25b,\n 0x59f111f1,\n 0x923f82a4,\n 0xab1c5ed5,\n 0xd807aa98,\n 0x12835b01,\n 0x243185be,\n 0x550c7dc3,\n 0x72be5d74,\n 0x80deb1fe,\n 0x9bdc06a7,\n 0xc19bf174,\n 0xe49b69c1,\n 0xefbe4786,\n 0x0fc19dc6,\n 0x240ca1cc,\n 0x2de92c6f,\n 0x4a7484aa,\n 0x5cb0a9dc,\n 0x76f988da,\n 0x983e5152,\n 0xa831c66d,\n 0xb00327c8,\n 0xbf597fc7,\n 0xc6e00bf3,\n 0xd5a79147,\n 0x06ca6351,\n 0x14292967,\n 0x27b70a85,\n 0x2e1b2138,\n 0x4d2c6dfc,\n 0x53380d13,\n 0x650a7354,\n 0x766a0abb,\n 0x81c2c92e,\n 0x92722c85,\n 0xa2bfe8a1,\n 0xa81a664b,\n 0xc24b8b70,\n 0xc76c51a3,\n 0xd192e819,\n 0xd6990624,\n 0xf40e3585,\n 0x106aa070,\n 0x19a4c116,\n 0x1e376c08,\n 0x2748774c,\n 0x34b0bcb5,\n 0x391c0cb3,\n 0x4ed8aa4a,\n 0x5b9cca4f,\n 0x682e6ff3,\n 0x748f82ee,\n 0x78a5636f,\n 0x84c87814,\n 0x8cc70208,\n 0x90befffa,\n 0xa4506ceb,\n 0xbef9a3f7,\n 0xc67178f2\n ];\n var OUTPUT_TYPES = [\n 'hex',\n 'array',\n 'digest',\n 'arrayBuffer'\n ];\n var blocks = [];\n if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) Array.isArray = function(obj) {\n return '[object Array]' === Object.prototype.toString.call(obj);\n };\n if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) ArrayBuffer.isView = function(obj) {\n return 'object' == typeof obj && obj.buffer && obj.buffer.constructor === ArrayBuffer;\n };\n var createOutputMethod = function(outputType, is224) {\n return function(message) {\n return new Sha256(is224, true).update(message)[outputType]();\n };\n };\n var createMethod = function(is224) {\n var method = createOutputMethod('hex', is224);\n if (NODE_JS) method = nodeWrap(method, is224);\n method.create = function() {\n return new Sha256(is224);\n };\n method.update = function(message) {\n return method.create().update(message);\n };\n for(var i = 0; i < OUTPUT_TYPES.length; ++i){\n var type = OUTPUT_TYPES[i];\n method[type] = createOutputMethod(type, is224);\n }\n return method;\n };\n var nodeWrap = function(method, is224) {\n var crypto = __webpack_require__(\"?c118\");\n var Buffer = __webpack_require__(\"?4999\").Buffer;\n var algorithm = is224 ? 'sha224' : 'sha256';\n var bufferFrom;\n bufferFrom = Buffer.from && !root.JS_SHA256_NO_BUFFER_FROM ? Buffer.from : function(message) {\n return new Buffer(message);\n };\n var nodeMethod = function(message) {\n if ('string' == typeof message) return crypto.createHash(algorithm).update(message, 'utf8').digest('hex');\n if (null == message) throw new Error(ERROR);\n if (message.constructor === ArrayBuffer) message = new Uint8Array(message);\n if (Array.isArray(message) || ArrayBuffer.isView(message) || message.constructor === Buffer) return crypto.createHash(algorithm).update(bufferFrom(message)).digest('hex');\n return method(message);\n };\n return nodeMethod;\n };\n var createHmacOutputMethod = function(outputType, is224) {\n return function(key, message) {\n return new HmacSha256(key, is224, true).update(message)[outputType]();\n };\n };\n var createHmacMethod = function(is224) {\n var method = createHmacOutputMethod('hex', is224);\n method.create = function(key) {\n return new HmacSha256(key, is224);\n };\n method.update = function(key, message) {\n return method.create(key).update(message);\n };\n for(var i = 0; i < OUTPUT_TYPES.length; ++i){\n var type = OUTPUT_TYPES[i];\n method[type] = createHmacOutputMethod(type, is224);\n }\n return method;\n };\n function Sha256(is224, sharedMemory) {\n if (sharedMemory) {\n blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n this.blocks = blocks;\n } else this.blocks = [\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0,\n 0\n ];\n if (is224) {\n this.h0 = 0xc1059ed8;\n this.h1 = 0x367cd507;\n this.h2 = 0x3070dd17;\n this.h3 = 0xf70e5939;\n this.h4 = 0xffc00b31;\n this.h5 = 0x68581511;\n this.h6 = 0x64f98fa7;\n this.h7 = 0xbefa4fa4;\n } else {\n this.h0 = 0x6a09e667;\n this.h1 = 0xbb67ae85;\n this.h2 = 0x3c6ef372;\n this.h3 = 0xa54ff53a;\n this.h4 = 0x510e527f;\n this.h5 = 0x9b05688c;\n this.h6 = 0x1f83d9ab;\n this.h7 = 0x5be0cd19;\n }\n this.block = this.start = this.bytes = this.hBytes = 0;\n this.finalized = this.hashed = false;\n this.first = true;\n this.is224 = is224;\n }\n Sha256.prototype.update = function(message) {\n if (this.finalized) return;\n var notString, type = typeof message;\n if ('string' !== type) {\n if ('object' === type) {\n if (null === message) throw new Error(ERROR);\n else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) message = new Uint8Array(message);\n else if (!Array.isArray(message)) {\n if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) throw new Error(ERROR);\n }\n } else throw new Error(ERROR);\n notString = true;\n }\n var code, index = 0, i, length = message.length, blocks = this.blocks;\n while(index < length){\n if (this.hashed) {\n this.hashed = false;\n blocks[0] = this.block;\n this.block = blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n }\n if (notString) for(i = this.start; index < length && i < 64; ++index)blocks[i >>> 2] |= message[index] << SHIFT[3 & i++];\n else for(i = this.start; index < length && i < 64; ++index){\n code = message.charCodeAt(index);\n if (code < 0x80) blocks[i >>> 2] |= code << SHIFT[3 & i++];\n else if (code < 0x800) {\n blocks[i >>> 2] |= (0xc0 | code >>> 6) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | 0x3f & code) << SHIFT[3 & i++];\n } else if (code < 0xd800 || code >= 0xe000) {\n blocks[i >>> 2] |= (0xe0 | code >>> 12) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | code >>> 6 & 0x3f) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | 0x3f & code) << SHIFT[3 & i++];\n } else {\n code = 0x10000 + ((0x3ff & code) << 10 | 0x3ff & message.charCodeAt(++index));\n blocks[i >>> 2] |= (0xf0 | code >>> 18) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | code >>> 12 & 0x3f) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | code >>> 6 & 0x3f) << SHIFT[3 & i++];\n blocks[i >>> 2] |= (0x80 | 0x3f & code) << SHIFT[3 & i++];\n }\n }\n this.lastByteIndex = i;\n this.bytes += i - this.start;\n if (i >= 64) {\n this.block = blocks[16];\n this.start = i - 64;\n this.hash();\n this.hashed = true;\n } else this.start = i;\n }\n if (this.bytes > 4294967295) {\n this.hBytes += this.bytes / 4294967296 | 0;\n this.bytes = this.bytes % 4294967296;\n }\n return this;\n };\n Sha256.prototype.finalize = function() {\n if (this.finalized) return;\n this.finalized = true;\n var blocks = this.blocks, i = this.lastByteIndex;\n blocks[16] = this.block;\n blocks[i >>> 2] |= EXTRA[3 & i];\n this.block = blocks[16];\n if (i >= 56) {\n if (!this.hashed) this.hash();\n blocks[0] = this.block;\n blocks[16] = blocks[1] = blocks[2] = blocks[3] = blocks[4] = blocks[5] = blocks[6] = blocks[7] = blocks[8] = blocks[9] = blocks[10] = blocks[11] = blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;\n }\n blocks[14] = this.hBytes << 3 | this.bytes >>> 29;\n blocks[15] = this.bytes << 3;\n this.hash();\n };\n Sha256.prototype.hash = function() {\n var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6, h = this.h7, blocks = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;\n for(j = 16; j < 64; ++j){\n t1 = blocks[j - 15];\n s0 = (t1 >>> 7 | t1 << 25) ^ (t1 >>> 18 | t1 << 14) ^ t1 >>> 3;\n t1 = blocks[j - 2];\n s1 = (t1 >>> 17 | t1 << 15) ^ (t1 >>> 19 | t1 << 13) ^ t1 >>> 10;\n blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 | 0;\n }\n bc = b & c;\n for(j = 0; j < 64; j += 4){\n if (this.first) {\n if (this.is224) {\n ab = 300032;\n t1 = blocks[0] - 1413257819;\n h = t1 - 150054599 | 0;\n d = t1 + 24177077 | 0;\n } else {\n ab = 704751109;\n t1 = blocks[0] - 210244248;\n h = t1 - 1521486534 | 0;\n d = t1 + 143694565 | 0;\n }\n this.first = false;\n } else {\n s0 = (a >>> 2 | a << 30) ^ (a >>> 13 | a << 19) ^ (a >>> 22 | a << 10);\n s1 = (e >>> 6 | e << 26) ^ (e >>> 11 | e << 21) ^ (e >>> 25 | e << 7);\n ab = a & b;\n maj = ab ^ a & c ^ bc;\n ch = e & f ^ ~e & g;\n t1 = h + s1 + ch + K[j] + blocks[j];\n t2 = s0 + maj;\n h = d + t1 | 0;\n d = t1 + t2 | 0;\n }\n s0 = (d >>> 2 | d << 30) ^ (d >>> 13 | d << 19) ^ (d >>> 22 | d << 10);\n s1 = (h >>> 6 | h << 26) ^ (h >>> 11 | h << 21) ^ (h >>> 25 | h << 7);\n da = d & a;\n maj = da ^ d & b ^ ab;\n ch = h & e ^ ~h & f;\n t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];\n t2 = s0 + maj;\n g = c + t1 | 0;\n c = t1 + t2 | 0;\n s0 = (c >>> 2 | c << 30) ^ (c >>> 13 | c << 19) ^ (c >>> 22 | c << 10);\n s1 = (g >>> 6 | g << 26) ^ (g >>> 11 | g << 21) ^ (g >>> 25 | g << 7);\n cd = c & d;\n maj = cd ^ c & a ^ da;\n ch = g & h ^ ~g & e;\n t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];\n t2 = s0 + maj;\n f = b + t1 | 0;\n b = t1 + t2 | 0;\n s0 = (b >>> 2 | b << 30) ^ (b >>> 13 | b << 19) ^ (b >>> 22 | b << 10);\n s1 = (f >>> 6 | f << 26) ^ (f >>> 11 | f << 21) ^ (f >>> 25 | f << 7);\n bc = b & c;\n maj = bc ^ b & d ^ cd;\n ch = f & g ^ ~f & h;\n t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];\n t2 = s0 + maj;\n e = a + t1 | 0;\n a = t1 + t2 | 0;\n this.chromeBugWorkAround = true;\n }\n this.h0 = this.h0 + a | 0;\n this.h1 = this.h1 + b | 0;\n this.h2 = this.h2 + c | 0;\n this.h3 = this.h3 + d | 0;\n this.h4 = this.h4 + e | 0;\n this.h5 = this.h5 + f | 0;\n this.h6 = this.h6 + g | 0;\n this.h7 = this.h7 + h | 0;\n };\n Sha256.prototype.hex = function() {\n this.finalize();\n var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7;\n var hex = HEX_CHARS[h0 >>> 28 & 0x0F] + HEX_CHARS[h0 >>> 24 & 0x0F] + HEX_CHARS[h0 >>> 20 & 0x0F] + HEX_CHARS[h0 >>> 16 & 0x0F] + HEX_CHARS[h0 >>> 12 & 0x0F] + HEX_CHARS[h0 >>> 8 & 0x0F] + HEX_CHARS[h0 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h0] + HEX_CHARS[h1 >>> 28 & 0x0F] + HEX_CHARS[h1 >>> 24 & 0x0F] + HEX_CHARS[h1 >>> 20 & 0x0F] + HEX_CHARS[h1 >>> 16 & 0x0F] + HEX_CHARS[h1 >>> 12 & 0x0F] + HEX_CHARS[h1 >>> 8 & 0x0F] + HEX_CHARS[h1 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h1] + HEX_CHARS[h2 >>> 28 & 0x0F] + HEX_CHARS[h2 >>> 24 & 0x0F] + HEX_CHARS[h2 >>> 20 & 0x0F] + HEX_CHARS[h2 >>> 16 & 0x0F] + HEX_CHARS[h2 >>> 12 & 0x0F] + HEX_CHARS[h2 >>> 8 & 0x0F] + HEX_CHARS[h2 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h2] + HEX_CHARS[h3 >>> 28 & 0x0F] + HEX_CHARS[h3 >>> 24 & 0x0F] + HEX_CHARS[h3 >>> 20 & 0x0F] + HEX_CHARS[h3 >>> 16 & 0x0F] + HEX_CHARS[h3 >>> 12 & 0x0F] + HEX_CHARS[h3 >>> 8 & 0x0F] + HEX_CHARS[h3 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h3] + HEX_CHARS[h4 >>> 28 & 0x0F] + HEX_CHARS[h4 >>> 24 & 0x0F] + HEX_CHARS[h4 >>> 20 & 0x0F] + HEX_CHARS[h4 >>> 16 & 0x0F] + HEX_CHARS[h4 >>> 12 & 0x0F] + HEX_CHARS[h4 >>> 8 & 0x0F] + HEX_CHARS[h4 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h4] + HEX_CHARS[h5 >>> 28 & 0x0F] + HEX_CHARS[h5 >>> 24 & 0x0F] + HEX_CHARS[h5 >>> 20 & 0x0F] + HEX_CHARS[h5 >>> 16 & 0x0F] + HEX_CHARS[h5 >>> 12 & 0x0F] + HEX_CHARS[h5 >>> 8 & 0x0F] + HEX_CHARS[h5 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h5] + HEX_CHARS[h6 >>> 28 & 0x0F] + HEX_CHARS[h6 >>> 24 & 0x0F] + HEX_CHARS[h6 >>> 20 & 0x0F] + HEX_CHARS[h6 >>> 16 & 0x0F] + HEX_CHARS[h6 >>> 12 & 0x0F] + HEX_CHARS[h6 >>> 8 & 0x0F] + HEX_CHARS[h6 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h6];\n if (!this.is224) hex += HEX_CHARS[h7 >>> 28 & 0x0F] + HEX_CHARS[h7 >>> 24 & 0x0F] + HEX_CHARS[h7 >>> 20 & 0x0F] + HEX_CHARS[h7 >>> 16 & 0x0F] + HEX_CHARS[h7 >>> 12 & 0x0F] + HEX_CHARS[h7 >>> 8 & 0x0F] + HEX_CHARS[h7 >>> 4 & 0x0F] + HEX_CHARS[0x0F & h7];\n return hex;\n };\n Sha256.prototype.toString = Sha256.prototype.hex;\n Sha256.prototype.digest = function() {\n this.finalize();\n var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5, h6 = this.h6, h7 = this.h7;\n var arr = [\n h0 >>> 24 & 0xFF,\n h0 >>> 16 & 0xFF,\n h0 >>> 8 & 0xFF,\n 0xFF & h0,\n h1 >>> 24 & 0xFF,\n h1 >>> 16 & 0xFF,\n h1 >>> 8 & 0xFF,\n 0xFF & h1,\n h2 >>> 24 & 0xFF,\n h2 >>> 16 & 0xFF,\n h2 >>> 8 & 0xFF,\n 0xFF & h2,\n h3 >>> 24 & 0xFF,\n h3 >>> 16 & 0xFF,\n h3 >>> 8 & 0xFF,\n 0xFF & h3,\n h4 >>> 24 & 0xFF,\n h4 >>> 16 & 0xFF,\n h4 >>> 8 & 0xFF,\n 0xFF & h4,\n h5 >>> 24 & 0xFF,\n h5 >>> 16 & 0xFF,\n h5 >>> 8 & 0xFF,\n 0xFF & h5,\n h6 >>> 24 & 0xFF,\n h6 >>> 16 & 0xFF,\n h6 >>> 8 & 0xFF,\n 0xFF & h6\n ];\n if (!this.is224) arr.push(h7 >>> 24 & 0xFF, h7 >>> 16 & 0xFF, h7 >>> 8 & 0xFF, 0xFF & h7);\n return arr;\n };\n Sha256.prototype.array = Sha256.prototype.digest;\n Sha256.prototype.arrayBuffer = function() {\n this.finalize();\n var buffer = new ArrayBuffer(this.is224 ? 28 : 32);\n var dataView = new DataView(buffer);\n dataView.setUint32(0, this.h0);\n dataView.setUint32(4, this.h1);\n dataView.setUint32(8, this.h2);\n dataView.setUint32(12, this.h3);\n dataView.setUint32(16, this.h4);\n dataView.setUint32(20, this.h5);\n dataView.setUint32(24, this.h6);\n if (!this.is224) dataView.setUint32(28, this.h7);\n return buffer;\n };\n function HmacSha256(key, is224, sharedMemory) {\n var i, type = typeof key;\n if ('string' === type) {\n var bytes = [], length = key.length, index = 0, code;\n for(i = 0; i < length; ++i){\n code = key.charCodeAt(i);\n if (code < 0x80) bytes[index++] = code;\n else if (code < 0x800) {\n bytes[index++] = 0xc0 | code >>> 6;\n bytes[index++] = 0x80 | 0x3f & code;\n } else if (code < 0xd800 || code >= 0xe000) {\n bytes[index++] = 0xe0 | code >>> 12;\n bytes[index++] = 0x80 | code >>> 6 & 0x3f;\n bytes[index++] = 0x80 | 0x3f & code;\n } else {\n code = 0x10000 + ((0x3ff & code) << 10 | 0x3ff & key.charCodeAt(++i));\n bytes[index++] = 0xf0 | code >>> 18;\n bytes[index++] = 0x80 | code >>> 12 & 0x3f;\n bytes[index++] = 0x80 | code >>> 6 & 0x3f;\n bytes[index++] = 0x80 | 0x3f & code;\n }\n }\n key = bytes;\n } else if ('object' === type) {\n if (null === key) throw new Error(ERROR);\n else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) key = new Uint8Array(key);\n else if (!Array.isArray(key)) {\n if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) throw new Error(ERROR);\n }\n } else throw new Error(ERROR);\n if (key.length > 64) key = new Sha256(is224, true).update(key).array();\n var oKeyPad = [], iKeyPad = [];\n for(i = 0; i < 64; ++i){\n var b = key[i] || 0;\n oKeyPad[i] = 0x5c ^ b;\n iKeyPad[i] = 0x36 ^ b;\n }\n Sha256.call(this, is224, sharedMemory);\n this.update(iKeyPad);\n this.oKeyPad = oKeyPad;\n this.inner = true;\n this.sharedMemory = sharedMemory;\n }\n HmacSha256.prototype = new Sha256();\n HmacSha256.prototype.finalize = function() {\n Sha256.prototype.finalize.call(this);\n if (this.inner) {\n this.inner = false;\n var innerHash = this.array();\n Sha256.call(this, this.is224, this.sharedMemory);\n this.update(this.oKeyPad);\n this.update(innerHash);\n Sha256.prototype.finalize.call(this);\n }\n };\n var exports = createMethod();\n exports.sha256 = exports;\n exports.sha224 = createMethod(true);\n exports.sha256.hmac = createHmacMethod();\n exports.sha224.hmac = createHmacMethod(true);\n if (COMMON_JS) module.exports = exports;\n else {\n root.sha256 = exports.sha256;\n root.sha224 = exports.sha224;\n if (AMD) define(function() {\n return exports;\n });\n }\n })();\n },\n \"?4999\" () {},\n \"?c118\" () {}\n };\n var __webpack_module_cache__ = {};\n function __webpack_require__(moduleId) {\n var cachedModule = __webpack_module_cache__[moduleId];\n if (void 0 !== cachedModule) return cachedModule.exports;\n var module = __webpack_module_cache__[moduleId] = {\n id: moduleId,\n loaded: false,\n exports: {}\n };\n __webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n module.loaded = true;\n return module.exports;\n }\n (()=>{\n __webpack_require__.d = (exports, definition)=>{\n for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {\n enumerable: true,\n get: definition[key]\n });\n };\n })();\n (()=>{\n __webpack_require__.g = (()=>{\n if ('object' == typeof globalThis) return globalThis;\n try {\n return this || new Function('return this')();\n } catch (e) {\n if ('object' == typeof window) return window;\n }\n })();\n })();\n (()=>{\n __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);\n })();\n (()=>{\n __webpack_require__.r = (exports)=>{\n if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n };\n })();\n (()=>{\n __webpack_require__.nmd = (module)=>{\n module.paths = [];\n if (!module.children) module.children = [];\n return module;\n };\n })();\n var __webpack_exports__ = {};\n (()=>{\n \"use strict\";\n __webpack_require__.r(__webpack_exports__);\n __webpack_require__.d(__webpack_exports__, {\n getNodeInfoByXpath: ()=>getNodeInfoByXpath,\n getXpathsById: ()=>getXpathsById,\n trimAttributes: ()=>trimAttributes,\n webExtractNodeTreeAsString: ()=>extractTreeNodeAsString,\n getElementXpath: ()=>getElementXpath,\n webExtractNodeTree: ()=>extractTreeNode,\n generateElementByRect: ()=>generateElementByRect,\n descriptionOfTree: ()=>descriptionOfTree,\n getXpathsByPoint: ()=>getXpathsByPoint,\n webExtractTextWithPosition: ()=>web_extractor_extractTextWithPosition,\n treeToList: ()=>treeToList,\n traverseTree: ()=>traverseTree,\n isNotContainerElement: ()=>isNotContainerElement,\n truncateText: ()=>truncateText,\n getElementInfoByXpath: ()=>getElementInfoByXpath\n });\n function truncateText(text, maxLength = 150) {\n if (void 0 === text) return '';\n if ('object' == typeof text) text = JSON.stringify(text);\n if ('number' == typeof text) return text.toString();\n if ('string' == typeof text && text.length > maxLength) return `${text.slice(0, maxLength)}...`;\n if ('string' == typeof text) return text.trim();\n return '';\n }\n function trimAttributes(attributes, truncateTextLength) {\n const tailorAttributes = Object.keys(attributes).reduce((res, currentKey)=>{\n const attributeVal = attributes[currentKey];\n if ('style' === currentKey || 'htmlTagName' === currentKey || 'nodeType' === currentKey) return res;\n res[currentKey] = truncateText(attributeVal, truncateTextLength);\n return res;\n }, {});\n return tailorAttributes;\n }\n const nodeSizeThreshold = 4;\n function descriptionOfTree(tree, truncateTextLength, filterNonTextContent = false, visibleOnly = true) {\n const attributesString = (kv)=>Object.entries(kv).map(([key, value])=>`${key}=\"${truncateText(value, truncateTextLength)}\"`).join(' ');\n function buildContentTree(node, indent = 0, visibleOnly = true) {\n let before = '';\n let contentWithIndent = '';\n let after = '';\n let emptyNode = true;\n const indentStr = ' '.repeat(indent);\n let children = '';\n for(let i = 0; i < (node.children || []).length; i++){\n const childContent = buildContentTree(node.children[i], indent + 1, visibleOnly);\n if (childContent) children += `\\n${childContent}`;\n }\n if (node.node && node.node.rect.width > nodeSizeThreshold && node.node.rect.height > nodeSizeThreshold && (!filterNonTextContent || filterNonTextContent && node.node.content) && (!visibleOnly || visibleOnly && node.node.isVisible)) {\n emptyNode = false;\n let nodeTypeString;\n nodeTypeString = node.node.attributes?.htmlTagName ? node.node.attributes.htmlTagName.replace(/[<>]/g, '') : node.node.attributes.nodeType.replace(/\\sNode$/, '').toLowerCase();\n const rectAttribute = node.node.rect ? {\n left: node.node.rect.left,\n top: node.node.rect.top,\n width: node.node.rect.width,\n height: node.node.rect.height\n } : {};\n before = `<${nodeTypeString} id=\"${node.node.id}\" ${attributesString(trimAttributes(node.node.attributes || {}, truncateTextLength))} ${attributesString(rectAttribute)}>`;\n const content = truncateText(node.node.content, truncateTextLength);\n contentWithIndent = content ? `\\n${indentStr} ${content}` : '';\n after = `</${nodeTypeString}>`;\n } else if (!filterNonTextContent) {\n if (!children.trim().startsWith('<>')) {\n before = '<>';\n contentWithIndent = '';\n after = '</>';\n }\n }\n if (emptyNode && !children.trim()) return '';\n const result = `${indentStr}${before}${contentWithIndent}${children}\\n${indentStr}${after}`;\n if (result.trim()) return result;\n return '';\n }\n const result = buildContentTree(tree, 0, visibleOnly);\n return result.replace(/^\\s*\\n/gm, '');\n }\n function treeToList(tree) {\n const result = [];\n function dfs(node) {\n if (node.node) result.push(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return result;\n }\n function traverseTree(tree, onNode) {\n function dfs(node) {\n if (node.node) node.node = onNode(node.node);\n for (const child of node.children)dfs(child);\n }\n dfs(tree);\n return tree;\n }\n const CONTAINER_MINI_HEIGHT = 3;\n const CONTAINER_MINI_WIDTH = 3;\n function isFormElement(node) {\n return node instanceof HTMLElement && ('input' === node.tagName.toLowerCase() || 'textarea' === node.tagName.toLowerCase() || 'select' === node.tagName.toLowerCase() || 'option' === node.tagName.toLowerCase());\n }\n function isButtonElement(node) {\n return node instanceof HTMLElement && 'button' === node.tagName.toLowerCase();\n }\n function isAElement(node) {\n return node instanceof HTMLElement && 'a' === node.tagName.toLowerCase();\n }\n function isSvgElement(node) {\n return node instanceof SVGElement;\n }\n function isImgElement(node) {\n if (!includeBaseElement(node) && node instanceof Element) {\n const computedStyle = window.getComputedStyle(node);\n const backgroundImage = computedStyle.getPropertyValue('background-image');\n if ('none' !== backgroundImage) return true;\n }\n if (isIconfont(node)) return true;\n return node instanceof HTMLElement && 'img' === node.tagName.toLowerCase() || node instanceof SVGElement && 'svg' === node.tagName.toLowerCase();\n }\n function isIconfont(node) {\n if (node instanceof Element) {\n const computedStyle = window.getComputedStyle(node);\n const fontFamilyValue = computedStyle.fontFamily || '';\n return fontFamilyValue.toLowerCase().indexOf('iconfont') >= 0;\n }\n return false;\n }\n function isNotContainerElement(node) {\n return isTextElement(node) || isIconfont(node) || isImgElement(node) || isButtonElement(node) || isAElement(node) || isFormElement(node);\n }\n function isTextElement(node) {\n if (node instanceof Element) {\n if (node?.childNodes?.length === 1 && node?.childNodes[0] instanceof Text) return true;\n }\n return node.nodeName?.toLowerCase?.() === '#text' && !isIconfont(node);\n }\n function isContainerElement(node) {\n if (!(node instanceof HTMLElement)) return false;\n if (includeBaseElement(node)) return false;\n const computedStyle = window.getComputedStyle(node);\n const backgroundColor = computedStyle.getPropertyValue('background-color');\n if (backgroundColor) return true;\n return false;\n }\n function includeBaseElement(node) {\n if (!(node instanceof HTMLElement)) return false;\n if (node.innerText) return true;\n const includeList = [\n 'svg',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'option',\n 'img',\n 'a'\n ];\n for (const tagName of includeList){\n const element = node.querySelectorAll(tagName);\n if (element.length > 0) return true;\n }\n return false;\n }\n function generateElementByRect(sourceRect, description, _edgeSize = 8) {\n const centerX = sourceRect.left + Math.floor((sourceRect.width - 1) / 2);\n const centerY = sourceRect.top + Math.floor((sourceRect.height - 1) / 2);\n return {\n rect: sourceRect,\n center: [\n centerX,\n centerY\n ],\n description: description || ''\n };\n }\n var sha256 = __webpack_require__(\"../../node_modules/.pnpm/js-sha256@0.11.0/node_modules/js-sha256/src/sha256.js\");\n 'undefined' != typeof process && process.versions?.node;\n const hashMap = {};\n function generateHashId(rect, content = '') {\n const combined = JSON.stringify({\n content,\n rect\n });\n let sliceLength = 5;\n let slicedHash = '';\n const hashHex = sha256.sha256.create().update(combined).hex();\n const toLetters = (hex)=>hex.split('').map((char)=>{\n const code = Number.parseInt(char, 16);\n return String.fromCharCode(97 + code % 26);\n }).join('');\n const hashLetters = toLetters(hashHex);\n while(sliceLength < hashLetters.length - 1){\n slicedHash = hashLetters.slice(0, sliceLength);\n if (hashMap[slicedHash] && hashMap[slicedHash] !== combined) {\n sliceLength++;\n continue;\n }\n hashMap[slicedHash] = combined;\n break;\n }\n return slicedHash;\n }\n const MAX_VALUE_LENGTH = 300;\n let util_debugMode = false;\n function setDebugMode(mode) {\n util_debugMode = mode;\n }\n function logger(..._msg) {\n if (!util_debugMode) return;\n console.log(..._msg);\n }\n function isElementPartiallyInViewport(rect, currentWindow, currentDocument, visibleAreaRatio = 2 / 3) {\n const elementHeight = rect.height;\n const elementWidth = rect.width;\n const viewportRect = {\n left: 0,\n top: 0,\n width: currentWindow.innerWidth || currentDocument.documentElement.clientWidth,\n height: currentWindow.innerHeight || currentDocument.documentElement.clientHeight,\n right: currentWindow.innerWidth || currentDocument.documentElement.clientWidth,\n bottom: currentWindow.innerHeight || currentDocument.documentElement.clientHeight,\n x: 0,\n y: 0,\n zoom: 1\n };\n const overlapRect = overlappedRect(rect, viewportRect);\n if (!overlapRect) return false;\n const visibleArea = overlapRect.width * overlapRect.height;\n const totalArea = elementHeight * elementWidth;\n return visibleArea / totalArea >= visibleAreaRatio;\n }\n function getPseudoElementContent(element, currentWindow) {\n if (!(element instanceof currentWindow.HTMLElement)) return {\n before: '',\n after: ''\n };\n const beforeContent = currentWindow.getComputedStyle(element, '::before').getPropertyValue('content');\n const afterContent = currentWindow.getComputedStyle(element, '::after').getPropertyValue('content');\n return {\n before: 'none' === beforeContent ? '' : beforeContent.replace(/\"/g, ''),\n after: 'none' === afterContent ? '' : afterContent.replace(/\"/g, '')\n };\n }\n function overlappedRect(rect1, rect2) {\n const left = Math.max(rect1.left, rect2.left);\n const top = Math.max(rect1.top, rect2.top);\n const right = Math.min(rect1.right, rect2.right);\n const bottom = Math.min(rect1.bottom, rect2.bottom);\n if (left < right && top < bottom) return {\n left,\n top,\n right,\n bottom,\n width: right - left,\n height: bottom - top,\n x: left,\n y: top,\n zoom: 1\n };\n return null;\n }\n function getRect(el, baseZoom, currentWindow) {\n let originalRect;\n let newZoom = 1;\n const hasGetBoundingClientRect = el instanceof Element;\n if (hasGetBoundingClientRect) {\n originalRect = el.getBoundingClientRect();\n if (el instanceof currentWindow.HTMLElement && !('currentCSSZoom' in el)) newZoom = Number.parseFloat(currentWindow.getComputedStyle(el).zoom) || 1;\n } else {\n const range = currentWindow.document.createRange();\n range.selectNodeContents(el);\n originalRect = range.getBoundingClientRect();\n }\n const zoom = newZoom * baseZoom;\n return {\n width: originalRect.width * zoom,\n height: originalRect.height * zoom,\n left: originalRect.left * zoom,\n top: originalRect.top * zoom,\n right: originalRect.right * zoom,\n bottom: originalRect.bottom * zoom,\n x: originalRect.x * zoom,\n y: originalRect.y * zoom,\n zoom\n };\n }\n const isElementCovered = (el, rect, currentWindow)=>{\n const x = rect.left + rect.width / 2;\n const y = rect.top + rect.height / 2;\n const topElement = currentWindow.document.elementFromPoint(x, y);\n if (!topElement) return false;\n if (topElement === el) return false;\n if (el?.contains(topElement)) return false;\n if (topElement?.contains(el)) return false;\n const rectOfTopElement = getRect(topElement, 1, currentWindow);\n const overlapRect = overlappedRect(rect, rectOfTopElement);\n if (!overlapRect) return false;\n logger(el, 'Element is covered by another element', {\n topElement,\n el,\n rect,\n x,\n y\n });\n return true;\n };\n function elementRect(el, currentWindow, currentDocument, baseZoom = 1) {\n if (!el) {\n logger(el, 'Element is not in the DOM hierarchy');\n return false;\n }\n if (!(el instanceof currentWindow.HTMLElement) && el.nodeType !== Node.TEXT_NODE && 'svg' !== el.nodeName.toLowerCase()) {\n logger(el, 'Element is not in the DOM hierarchy');\n return false;\n }\n if (el instanceof currentWindow.HTMLElement) {\n const style = currentWindow.getComputedStyle(el);\n if ('none' === style.display || 'hidden' === style.visibility || '0' === style.opacity && 'INPUT' !== el.tagName) {\n logger(el, 'Element is hidden');\n return false;\n }\n }\n const rect = getRect(el, baseZoom, currentWindow);\n if (0 === rect.width && 0 === rect.height) {\n logger(el, 'Element has no size');\n return false;\n }\n if (1 === baseZoom && isElementCovered(el, rect, currentWindow)) return false;\n const isVisible = isElementPartiallyInViewport(rect, currentWindow, currentDocument);\n let parent = el;\n const parentUntilNonStatic = (currentNode)=>{\n let parent = currentNode?.parentElement;\n while(parent){\n const style = currentWindow.getComputedStyle(parent);\n if ('static' !== style.position) return parent;\n parent = parent.parentElement;\n }\n return null;\n };\n while(parent && parent !== currentDocument.body){\n if (!(parent instanceof currentWindow.HTMLElement)) {\n parent = parent.parentElement;\n continue;\n }\n const parentStyle = currentWindow.getComputedStyle(parent);\n if ('hidden' === parentStyle.overflow) {\n const parentRect = getRect(parent, 1, currentWindow);\n const tolerance = 10;\n if (rect.right < parentRect.left - tolerance || rect.left > parentRect.right + tolerance || rect.bottom < parentRect.top - tolerance || rect.top > parentRect.bottom + tolerance) {\n logger(el, 'element is partially or totally hidden by an ancestor', {\n rect,\n parentRect\n });\n return false;\n }\n }\n if ('fixed' === parentStyle.position || 'sticky' === parentStyle.position) break;\n parent = 'absolute' === parentStyle.position ? parentUntilNonStatic(parent) : parent.parentElement;\n }\n return {\n left: Math.round(rect.left),\n top: Math.round(rect.top),\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n zoom: rect.zoom,\n isVisible\n };\n }\n function getNodeAttributes(node, currentWindow) {\n if (!node || !(node instanceof currentWindow.HTMLElement) || !node.attributes) return {};\n const attributesList = Array.from(node.attributes).map((attr)=>{\n if ('class' === attr.name) return [\n attr.name,\n `.${attr.value.split(' ').join('.')}`\n ];\n let value = attr.value;\n if (value.startsWith('data:image')) value = 'image';\n if (value.length > MAX_VALUE_LENGTH) value = `${value.slice(0, MAX_VALUE_LENGTH)}...`;\n return [\n attr.name,\n value\n ];\n });\n return Object.fromEntries(attributesList);\n }\n const NODE_CACHE_MAX_SIZE = 2000;\n function setNodeHashCacheListOnWindow() {\n if ('undefined' != typeof window) window.midsceneNodeHashCache = new Map();\n }\n function getNodeCacheMap() {\n if ('undefined' == typeof window) return;\n return window.midsceneNodeHashCache;\n }\n function setNodeToCacheList(node, id) {\n const cache = getNodeCacheMap();\n if (!cache) return;\n if (cache.has(id)) return;\n if (cache.size >= NODE_CACHE_MAX_SIZE) {\n const firstKey = cache.keys().next().value;\n if (void 0 !== firstKey) cache.delete(firstKey);\n }\n cache.set(id, node);\n }\n function getNodeFromCacheList(id) {\n return getNodeCacheMap()?.get(id);\n }\n function midsceneGenerateHash(node, content, rect) {\n const slicedHash = generateHashId(rect, content);\n if (node) {\n if ('undefined' != typeof window && !getNodeCacheMap()) setNodeHashCacheListOnWindow();\n setNodeToCacheList(node, slicedHash);\n }\n return slicedHash;\n }\n function getTopDocument() {\n const container = document.body || document;\n return container;\n }\n let indexId = 0;\n function tagNameOfNode(node) {\n let tagName = '';\n if (node instanceof HTMLElement) tagName = node.tagName?.toLowerCase();\n else {\n const parentElement = node.parentElement;\n if (parentElement && parentElement instanceof HTMLElement) tagName = parentElement.tagName?.toLowerCase();\n }\n return tagName ? `<${tagName}>` : '';\n }\n function collectElementInfo(node, currentWindow, currentDocument, baseZoom = 1, basePoint = {\n left: 0,\n top: 0\n }, isContainer = false) {\n const rect = elementRect(node, currentWindow, currentDocument, baseZoom);\n if (!rect) return null;\n if (rect.width < CONTAINER_MINI_WIDTH || rect.height < CONTAINER_MINI_HEIGHT) return null;\n if (0 !== basePoint.left || 0 !== basePoint.top) {\n rect.left += basePoint.left;\n rect.top += basePoint.top;\n }\n if (rect.height >= window.innerHeight && rect.width >= window.innerWidth) return null;\n if (isFormElement(node)) {\n const attributes = getNodeAttributes(node, currentWindow);\n let valueContent = attributes.value || attributes.placeholder || node.textContent || '';\n const nodeHashId = midsceneGenerateHash(node, valueContent, rect);\n const tagName = node.tagName.toLowerCase();\n if ('select' === node.tagName.toLowerCase()) {\n const selectedOption = node.options[node.selectedIndex];\n valueContent = selectedOption?.textContent || '';\n }\n if (('input' === node.tagName.toLowerCase() || 'textarea' === node.tagName.toLowerCase()) && node.value) valueContent = node.value;\n const elementInfo = {\n id: nodeHashId,\n nodeHashId,\n nodeType: \"FORM_ITEM Node\",\n indexId: indexId++,\n attributes: {\n ...attributes,\n htmlTagName: `<${tagName}>`,\n nodeType: \"FORM_ITEM Node\"\n },\n content: valueContent.trim(),\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isButtonElement(node)) {\n const rect = mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom);\n if (!rect) return null;\n const attributes = getNodeAttributes(node, currentWindow);\n const pseudo = getPseudoElementContent(node, currentWindow);\n const content = node.innerText || pseudo.before || pseudo.after || '';\n const nodeHashId = midsceneGenerateHash(node, content, rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n nodeType: \"BUTTON Node\",\n attributes: {\n ...attributes,\n htmlTagName: tagNameOfNode(node),\n nodeType: \"BUTTON Node\"\n },\n content,\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isImgElement(node)) {\n const attributes = getNodeAttributes(node, currentWindow);\n const nodeHashId = midsceneGenerateHash(node, '', rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n attributes: {\n ...attributes,\n ...node.nodeName?.toLowerCase() === 'svg' ? {\n svgContent: 'true'\n } : {},\n nodeType: \"IMG Node\",\n htmlTagName: tagNameOfNode(node)\n },\n nodeType: \"IMG Node\",\n content: '',\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isTextElement(node)) {\n const text = node.textContent?.trim().replace(/\\n+/g, ' ');\n if (!text) return null;\n const attributes = getNodeAttributes(node, currentWindow);\n const attributeKeys = Object.keys(attributes);\n if (!text.trim() && 0 === attributeKeys.length) return null;\n const nodeHashId = midsceneGenerateHash(node, text, rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n nodeType: \"TEXT Node\",\n attributes: {\n ...attributes,\n nodeType: \"TEXT Node\",\n htmlTagName: tagNameOfNode(node)\n },\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n content: text,\n rect,\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isAElement(node)) {\n const attributes = getNodeAttributes(node, currentWindow);\n const pseudo = getPseudoElementContent(node, currentWindow);\n const content = node.innerText || pseudo.before || pseudo.after || '';\n const nodeHashId = midsceneGenerateHash(node, content, rect);\n const elementInfo = {\n id: nodeHashId,\n indexId: indexId++,\n nodeHashId,\n nodeType: \"Anchor Node\",\n attributes: {\n ...attributes,\n htmlTagName: tagNameOfNode(node),\n nodeType: \"Anchor Node\"\n },\n content,\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n if (isContainerElement(node) || isContainer) {\n const attributes = getNodeAttributes(node, currentWindow);\n const nodeHashId = midsceneGenerateHash(node, '', rect);\n const elementInfo = {\n id: nodeHashId,\n nodeHashId,\n indexId: indexId++,\n nodeType: \"CONTAINER Node\",\n attributes: {\n ...attributes,\n nodeType: \"CONTAINER Node\",\n htmlTagName: tagNameOfNode(node)\n },\n content: '',\n rect,\n center: [\n Math.round(rect.left + rect.width / 2),\n Math.round(rect.top + rect.height / 2)\n ],\n zoom: rect.zoom,\n isVisible: rect.isVisible\n };\n return elementInfo;\n }\n return null;\n }\n function web_extractor_extractTextWithPosition(initNode, debugMode = false) {\n const elementNode = extractTreeNode(initNode, debugMode);\n const elementInfoArray = [];\n function dfsTopChildren(node) {\n if (node.node) elementInfoArray.push(node.node);\n for(let i = 0; i < node.children.length; i++)dfsTopChildren(node.children[i]);\n }\n dfsTopChildren({\n children: elementNode.children,\n node: elementNode.node\n });\n return elementInfoArray;\n }\n function extractTreeNodeAsString(initNode, visibleOnly = false, debugMode = false) {\n const elementNode = extractTreeNode(initNode, debugMode);\n return descriptionOfTree(elementNode, void 0, false, visibleOnly);\n }\n function extractTreeNode(initNode, debugMode = false) {\n setDebugMode(debugMode);\n indexId = 0;\n const topDocument = getTopDocument();\n const startNode = initNode || topDocument;\n const topChildren = [];\n function dfs(node, currentWindow, currentDocument, baseZoom = 1, basePoint = {\n left: 0,\n top: 0\n }) {\n if (!node) return null;\n if (node.nodeType && 10 === node.nodeType) return null;\n const elementInfo = collectElementInfo(node, currentWindow, currentDocument, baseZoom, basePoint);\n if (node instanceof currentWindow.HTMLIFrameElement) {\n if (node.contentWindow && node.contentWindow) return null;\n }\n const nodeInfo = {\n node: elementInfo,\n children: []\n };\n if (elementInfo?.nodeType === \"BUTTON Node\" || elementInfo?.nodeType === \"IMG Node\" || elementInfo?.nodeType === \"TEXT Node\" || elementInfo?.nodeType === \"FORM_ITEM Node\" || elementInfo?.nodeType === \"CONTAINER Node\") return nodeInfo;\n const rect = getRect(node, baseZoom, currentWindow);\n for(let i = 0; i < node.childNodes.length; i++){\n logger('will dfs', node.childNodes[i]);\n const childNodeInfo = dfs(node.childNodes[i], currentWindow, currentDocument, rect.zoom, basePoint);\n if (Array.isArray(childNodeInfo)) nodeInfo.children.push(...childNodeInfo);\n else if (childNodeInfo) nodeInfo.children.push(childNodeInfo);\n }\n if (null === nodeInfo.node) {\n if (0 === nodeInfo.children.length) return null;\n return nodeInfo.children;\n }\n return nodeInfo;\n }\n const rootNodeInfo = dfs(startNode, window, document, 1, {\n left: 0,\n top: 0\n });\n if (Array.isArray(rootNodeInfo)) topChildren.push(...rootNodeInfo);\n else if (rootNodeInfo) topChildren.push(rootNodeInfo);\n if (startNode === topDocument) {\n const iframes = document.querySelectorAll('iframe');\n for(let i = 0; i < iframes.length; i++){\n const iframe = iframes[i];\n if (iframe.contentDocument && iframe.contentWindow) {\n const iframeInfo = collectElementInfo(iframe, window, document, 1);\n if (iframeInfo) {\n const iframeChildren = dfs(iframe.contentDocument.body, iframe.contentWindow, iframe.contentDocument, 1, {\n left: iframeInfo.rect.left,\n top: iframeInfo.rect.top\n });\n if (Array.isArray(iframeChildren)) topChildren.push(...iframeChildren);\n else if (iframeChildren) topChildren.push(iframeChildren);\n }\n }\n }\n }\n return {\n node: null,\n children: topChildren\n };\n }\n function mergeElementAndChildrenRects(node, currentWindow, currentDocument, baseZoom = 1) {\n const selfRect = elementRect(node, currentWindow, currentDocument, baseZoom);\n if (!selfRect) return null;\n let minLeft = selfRect.left;\n let minTop = selfRect.top;\n let maxRight = selfRect.left + selfRect.width;\n let maxBottom = selfRect.top + selfRect.height;\n function traverse(child) {\n for(let i = 0; i < child.childNodes.length; i++){\n const sub = child.childNodes[i];\n if (1 === sub.nodeType) {\n const rect = elementRect(sub, currentWindow, currentDocument, baseZoom);\n if (rect) {\n minLeft = Math.min(minLeft, rect.left);\n minTop = Math.min(minTop, rect.top);\n maxRight = Math.max(maxRight, rect.left + rect.width);\n maxBottom = Math.max(maxBottom, rect.top + rect.height);\n }\n traverse(sub);\n }\n }\n }\n traverse(node);\n return {\n ...selfRect,\n left: minLeft,\n top: minTop,\n width: maxRight - minLeft,\n height: maxBottom - minTop\n };\n }\n const SUB_XPATH_SEPARATOR = '|>>|';\n function parseCSSZoom(style) {\n return Number.parseFloat(style.zoom ?? '1') || 1;\n }\n function calculateIframeOffset(nodeOwnerDoc, rootDoc) {\n let leftOffset = 0;\n let topOffset = 0;\n let iterDoc = nodeOwnerDoc;\n while(iterDoc && iterDoc !== rootDoc)try {\n const frameElement = iterDoc.defaultView?.frameElement;\n if (!frameElement) break;\n const rect = frameElement.getBoundingClientRect();\n const parentWin = iterDoc.defaultView?.parent;\n let borderLeft = 0;\n let borderTop = 0;\n let zoom = 1;\n try {\n if (parentWin) {\n const style = parentWin.getComputedStyle(frameElement);\n borderLeft = Number.parseFloat(style.borderLeftWidth) || 0;\n borderTop = Number.parseFloat(style.borderTopWidth) || 0;\n zoom = parseCSSZoom(style);\n }\n } catch {}\n leftOffset = leftOffset / zoom + rect.left + borderLeft;\n topOffset = topOffset / zoom + rect.top + borderTop;\n iterDoc = frameElement.ownerDocument;\n } catch {\n break;\n }\n return {\n left: leftOffset,\n top: topOffset\n };\n }\n function translatePointToIframeCoordinates(point, iframeElement, parentWindow) {\n const rect = iframeElement.getBoundingClientRect();\n const style = parentWindow.getComputedStyle(iframeElement);\n const clientLeft = iframeElement.clientLeft;\n const clientTop = iframeElement.clientTop;\n const paddingLeft = Number.parseFloat(style.paddingLeft) || 0;\n const paddingTop = Number.parseFloat(style.paddingTop) || 0;\n const zoom = parseCSSZoom(style);\n return {\n left: (point.left - rect.left - clientLeft - paddingLeft) / zoom,\n top: (point.top - rect.top - clientTop - paddingTop) / zoom\n };\n }\n const getElementXpathIndex = (element)=>{\n let index = 1;\n let prev = element.previousElementSibling;\n while(prev){\n if (prev.nodeName.toLowerCase() === element.nodeName.toLowerCase()) index++;\n prev = prev.previousElementSibling;\n }\n return index;\n };\n const normalizeXpathText = (text)=>{\n if ('string' != typeof text) return '';\n return text.replace(/\\s+/g, ' ').trim();\n };\n const buildCurrentElementXpath = (element, isOrderSensitive, isLeafElement, limitToCurrentDocument = false)=>{\n const parentPath = element.parentNode ? getElementXpath(element.parentNode, isOrderSensitive, false, limitToCurrentDocument) : '';\n const prefix = parentPath ? `${parentPath}/` : '/';\n const tagName = element.nodeName.toLowerCase();\n const textContent = element.textContent?.trim();\n const isSVGNamespace = 'http://www.w3.org/2000/svg' === element.namespaceURI;\n const tagSelector = isSVGNamespace ? `*[name()=\"${tagName}\"]` : tagName;\n if (isOrderSensitive) {\n const index = getElementXpathIndex(element);\n return `${prefix}${tagSelector}[${index}]`;\n }\n if (isLeafElement && textContent) return `${prefix}${tagSelector}[normalize-space()=\"${normalizeXpathText(textContent)}\"]`;\n const index = getElementXpathIndex(element);\n return `${prefix}${tagSelector}[${index}]`;\n };\n const getElementXpath = (element, isOrderSensitive = false, isLeafElement = false, limitToCurrentDocument = false)=>{\n if (element.nodeType === Node.TEXT_NODE) {\n const parentNode = element.parentNode;\n if (parentNode && parentNode.nodeType === Node.ELEMENT_NODE) {\n const parentXPath = getElementXpath(parentNode, isOrderSensitive, true, limitToCurrentDocument);\n const textContent = element.textContent?.trim();\n if (textContent) return `${parentXPath}/text()[normalize-space()=\"${normalizeXpathText(textContent)}\"]`;\n return `${parentXPath}/text()`;\n }\n return '';\n }\n if (element.nodeType !== Node.ELEMENT_NODE) return '';\n const el = element;\n try {\n const nodeName = el.nodeName.toLowerCase();\n if (el === el.ownerDocument?.documentElement || 'html' === nodeName) {\n if (!limitToCurrentDocument) {\n const frameElement = el.ownerDocument?.defaultView?.frameElement;\n if (frameElement) {\n const framePath = getElementXpath(frameElement, isOrderSensitive, false, limitToCurrentDocument);\n return `${framePath}${SUB_XPATH_SEPARATOR}/html`;\n }\n }\n return '/html';\n }\n if (el === el.ownerDocument?.body || 'body' === nodeName) {\n if (!limitToCurrentDocument) {\n const frameElement = el.ownerDocument?.defaultView?.frameElement;\n if (frameElement) {\n const framePath = getElementXpath(frameElement, isOrderSensitive, false, limitToCurrentDocument);\n return `${framePath}${SUB_XPATH_SEPARATOR}/html/body`;\n }\n }\n return '/html/body';\n }\n } catch (error) {\n logger('[midscene:locator] ownerDocument access failed:', error);\n if ('html' === el.nodeName.toLowerCase()) return '/html';\n if ('body' === el.nodeName.toLowerCase()) return '/html/body';\n }\n if (isSvgElement(el)) {\n const tagName = el.nodeName.toLowerCase();\n if ('svg' === tagName) return buildCurrentElementXpath(el, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n let parent = el.parentNode;\n while(parent && parent.nodeType === Node.ELEMENT_NODE){\n const parentEl = parent;\n if (!isSvgElement(parentEl)) return getElementXpath(parentEl, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n const parentTag = parentEl.nodeName.toLowerCase();\n if ('svg' === parentTag) return getElementXpath(parentEl, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n parent = parent.parentNode;\n }\n const fallbackParent = el.parentNode;\n if (fallbackParent && fallbackParent.nodeType === Node.ELEMENT_NODE) return getElementXpath(fallbackParent, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n return '';\n }\n return buildCurrentElementXpath(el, isOrderSensitive, isLeafElement, limitToCurrentDocument);\n };\n function getXpathsById(id) {\n const node = getNodeFromCacheList(id);\n if (!node) return null;\n const fullXPath = getElementXpath(node, false, true, true);\n return [\n fullXPath\n ];\n }\n function getXpathsByPoint(point, isOrderSensitive) {\n let currentWindow = 'undefined' != typeof window ? window : void 0;\n let currentDocument = 'undefined' != typeof document ? document : void 0;\n let { left, top } = point;\n let depth = 0;\n const MAX_DEPTH = 10;\n let xpathPrefix = '';\n let lastFoundElement = null;\n while(depth < MAX_DEPTH){\n depth++;\n const element = currentDocument.elementFromPoint(left, top);\n if (!element) {\n if (lastFoundElement) {\n const fullXPath = getElementXpath(lastFoundElement, isOrderSensitive, true, true);\n return [\n xpathPrefix + fullXPath\n ];\n }\n return null;\n }\n lastFoundElement = element;\n const tag = element.tagName.toLowerCase();\n if ('iframe' === tag || 'frame' === tag) try {\n const contentWindow = element.contentWindow;\n const contentDocument = element.contentDocument;\n if (contentWindow && contentDocument) {\n const localPoint = translatePointToIframeCoordinates({\n left,\n top\n }, element, currentWindow);\n const currentIframeXpath = getElementXpath(element, isOrderSensitive, false, true);\n xpathPrefix += currentIframeXpath + SUB_XPATH_SEPARATOR;\n currentWindow = contentWindow;\n currentDocument = contentDocument;\n left = localPoint.left;\n top = localPoint.top;\n continue;\n }\n } catch (error) {\n logger('[midscene:locator] iframe penetration failed (cross-origin?):', error);\n }\n const fullXPath = getElementXpath(element, isOrderSensitive, true, true);\n return [\n xpathPrefix + fullXPath\n ];\n }\n if (lastFoundElement) {\n const fullXPath = getElementXpath(lastFoundElement, isOrderSensitive, true, true);\n return [\n xpathPrefix + fullXPath\n ];\n }\n return null;\n }\n function getNodeInfoByXpath(xpath) {\n const parts = xpath.split(SUB_XPATH_SEPARATOR).map((p)=>p.trim()).filter(Boolean);\n if (0 === parts.length) return null;\n let currentDocument = 'undefined' != typeof document ? document : void 0;\n let node = null;\n for(let i = 0; i < parts.length; i++){\n const currentXpath = parts[i];\n const xpathResult = currentDocument.evaluate(currentXpath, currentDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\n if (1 !== xpathResult.snapshotLength) {\n logger(`[midscene:locator] XPath \"${currentXpath}\" matched ${xpathResult.snapshotLength} elements (expected 1), discarding.`);\n return null;\n }\n node = xpathResult.snapshotItem(0);\n if (i < parts.length - 1) if (!node || node.nodeType !== Node.ELEMENT_NODE || 'iframe' !== node.tagName.toLowerCase()) return null;\n else try {\n const contentDocument = node.contentDocument;\n if (contentDocument) currentDocument = contentDocument;\n else {\n logger('[midscene:locator] iframe contentDocument is null (cross-origin?)');\n return null;\n }\n } catch (error) {\n logger('[midscene:locator] iframe contentDocument access failed:', error);\n return null;\n }\n }\n return node;\n }\n function getElementInfoByXpath(xpath) {\n const node = getNodeInfoByXpath(xpath);\n if (!node) return null;\n let targetWindow = 'undefined' != typeof window ? window : void 0;\n let targetDocument = 'undefined' != typeof document ? document : void 0;\n if (node.ownerDocument?.defaultView) {\n targetWindow = node.ownerDocument.defaultView;\n targetDocument = node.ownerDocument;\n }\n const rootDoc = 'undefined' != typeof document ? document : null;\n const iframeOffset = calculateIframeOffset(node.ownerDocument ?? null, rootDoc);\n const targetWin = targetWindow;\n const targetDoc = targetDocument;\n if (node instanceof targetWin.HTMLElement) {\n const rect = getRect(node, 1, targetWin);\n const isVisible = isElementPartiallyInViewport(rect, targetWin, targetDoc, 1);\n if (!isVisible) node.scrollIntoView({\n behavior: 'instant',\n block: 'center'\n });\n }\n return collectElementInfo(node, targetWin, targetDoc, 1, iframeOffset, true);\n }\n })();\n window.midscene_element_inspector = __webpack_exports__;\n})();\n";
76
76
  if (!htmlElementScript) throw new Error('HTML_ELEMENT_SCRIPT inject failed.');
77
77
  return htmlElementScript;
78
78
  }
@@ -1,2 +1,2 @@
1
1
  export declare const PLAYWRIGHT_EXAMPLE_CODE = "\n// Reference the following code to generate Midscene test cases\n// The following is test code for Midscene AI, for reference\n// The following is Playwright syntax, you can use Playwright to assist in test generation\nIMPORTANT: Follow these exact type signatures for AI functions:\n\n// Type signatures for AI functions:\naiAct(prompt: string, options?: { cacheable?: boolean, deepThink?: 'unset' | true | false }): Promise<void>\naiInput(text: string, locate: string, options?: { deepLocate?: boolean, xpath?: string, cacheable?: boolean }): Promise<void>\naiTap(locate: string, options?: { deepLocate?: boolean, xpath?: string, cacheable?: boolean }): Promise<void>\naiHover(locate: string, options?: { deepLocate?: boolean, xpath?: string, cacheable?: boolean }): Promise<void>\naiDoubleClick(locate: string, options?: { deepLocate?: boolean, xpath?: string, cacheable?: boolean }): Promise<void>\naiKeyboardPress(key: string, locate?: string, options?: { deepLocate?: boolean, xpath?: string, cacheable?: boolean }): Promise<void>\naiScroll(locate: string | undefined, options: {\n direction?: 'up' | 'down' | 'left' | 'right',\n scrollType?: 'singleAction' | 'scrollToBottom' | 'scrollToTop' | 'scrollToRight' | 'scrollToLeft',\n distance?: number | null,\n deepLocate?: boolean,\n xpath?: string,\n cacheable?: boolean\n}): Promise<void>\naiAssert(assertion: string, options?: { errorMessage?: string }): Promise<void>\naiWaitFor(prompt: string, options?: { timeout?: number }): Promise<void>\naiQuery<T>(queryObject: Record<string, string>): Promise<T> // Extracts data from page based on descriptions\n\n// examples:\n// Reference the following code to generate Midscene test cases\n// The following is test code for Midscene AI, for reference\n// The following is Playwright syntax, you can use Playwright to assist in test generation\nimport { test as base } from '@playwright/test';\nimport type { PlayWrightAiFixtureType } from '@midscene/web/playwright';\nimport { PlaywrightAiFixture } from '@midscene/web/playwright';\n\nconst test = base.extend<PlayWrightAiFixtureType>(PlaywrightAiFixture({\n waitForNetworkIdleTimeout: 2000, // optional, the timeout for waiting for network idle between each action, default is 2000ms\n}));\n\n\ntest.beforeEach(async ({ page }) => {\n await page.goto('https://www.xxx.com/');\n await page.setViewportSize({ width: 1920, height: 1080 });\n});\n\ntest('ai shop', async ({\n aiAct,\n aiInput,\n aiAssert,\n aiQuery,\n aiKeyboardPress,\n aiHover,\n aiTap,\n aiWaitFor,\n agentForPage,\n page,\n}) => {\n // login\n await aiAssert('The page shows the login interface');\n await aiInput('user_name', 'in user name input');\n await aiInput('password', 'in password input');\n await aiKeyboardPress('Enter', 'Login Button');\n\n // check the login success\n await aiWaitFor('The page shows that the loading is complete');\n await aiAssert('The current page shows the product detail page');\n\n // check the product info\n const dataA = await aiQuery({\n userInfo: 'User information in the format {name: string}',\n theFirstProductInfo: 'The first product info in the format {name: string, price: number}',\n });\n expect(dataA.theFirstProductInfo.name).toBe('xxx');\n expect(dataA.theFirstProductInfo.price).toBe(100);\n\n\n // add to cart\n await aiTap('click add to cart button');\n \n await aiTap('click right top cart icon');\n await aiAssert('The cart icon shows the number 1');\n});\n";
2
- export declare const YAML_EXAMPLE_CODE = "\n1. Format:\n\nweb:\n url: \"starting_url\"\n viewportWidth: 1280\n viewportHeight: 960\n\ntasks:\n - name: \"descriptive task name\"\n flow:\n - aiTap: \"element description\"\n - aiInput: 'text value'\n locate: 'input field description'\n - aiScroll:\n direction: down/up\n scrollType: scrollToBottom/scrollToTop/singleAction\n - aiAssert: \"expected state\"\n - sleep: milliseconds\n\n2. Action Types:\n- aiTap: for clicks (natural language targeting)\n- aiInput: for text input with 'locate' field\n- aiScroll: with direction and scrollType\n- aiAssert: for validations\n- sleep: for delays (milliseconds)\n\n3. Best Practices:\n- Group related actions into logical tasks\n- Use natural language descriptions\n- Add deepLocate: true for complex interactions\n- Keep task names concise but descriptive\n\n4. CRITICAL - YAML Indentation Rules:\n- For actions with additional parameters (aiScroll, aiInput, aiKeyboardPress), the parameters must be SIBLING keys, NOT nested children\n- Parameters like direction, scrollType, locate must align with the action key, not indented further\n- CORRECT indentation example:\n - aiScroll:\n direction: down\n scrollType: singleAction\n- WRONG indentation (DO NOT do this):\n - aiScroll:\n direction: down\n scrollType: singleAction\n\n\n\nYAML type\ntasks:\n - name: <name>\n continueOnError: <boolean> # Optional, whether to continue to the next task on error, defaults to false.\n flow:\n # Auto Planning (.ai)\n # ----------------\n\n # Perform an interaction. `ai` is a shorthand for `aiAct`.\n - ai: <prompt>\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # This usage is the same as `ai`.\n - aiAct: <prompt>\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Instant Action (.aiTap, .aiDoubleClick, .aiHover, .aiInput, .aiKeyboardPress, .aiScroll)\n # ----------------\n\n # Tap an element described by a prompt.\n - aiTap: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Double click an element described by a prompt.\n - aiDoubleClick: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Hover over an element described by a prompt.\n - aiHover: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Input text into an element described by a prompt.\n - aiInput: <final text content of the input>\n locate: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Press a key (e.g., Enter, Tab, Escape) on an element described by a prompt.\n - aiKeyboardPress: <key>\n locate: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Scroll globally or on an element described by a prompt.\n - aiScroll:\n direction: 'up' # or 'down' | 'left' | 'right'\n scrollType: 'singleAction' # or 'scrollToTop' | 'scrollToBottom' | 'scrollToLeft' | 'scrollToRight'\n distance: <number> # Optional, the scroll distance in pixels.\n locate: <prompt> # Optional, the element to scroll on.\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Record the current screenshot with a description in the report file.\n - recordToReport: <title> # Optional, the title of the screenshot. If not provided, the title will be 'untitled'.\n content: <content> # Optional, the description of the screenshot.\n\n # Data Extraction\n # ----------------\n\n # Perform a query that returns a JSON object.\n - aiQuery: <prompt> # Remember to describe the format of the result in the prompt.\n name: <name> # The key for the query result in the JSON output.\n\n # More APIs\n # ----------------\n\n # Wait for a condition to be met, with a timeout (in ms, optional, defaults to 30000).\n - aiWaitFor: <prompt>\n timeout: <ms>\n\n # Perform an assertion.\n - aiAssert: <prompt>\n errorMessage: <error-message> # Optional, the error message to print if the assertion fails.\n\n # Wait for a specified amount of time.\n - sleep: <ms>\n\n # Execute a piece of JavaScript code in the web page context.\n - javascript: <javascript>\n name: <name> # Optional, assign a name to the return value, which will be used as a key in the JSON output.\n\n - name: <name>\n flow:\n # ...\n";
2
+ export declare const YAML_EXAMPLE_CODE = "\nCRITICAL - YAML Indentation Rules:\nFor actions with additional parameters (aiScroll, aiInput, aiKeyboardPress), the parameters must be SIBLING keys at the SAME indentation level as the action key, NOT nested children indented further.\nCORRECT (parameters align with the action key):\n - aiScroll:\n direction: 'down'\n scrollType: 'singleAction'\n distance: 500\n locate: \"main content area\"\n - aiInput: 'text value'\n locate: 'input field description'\nWRONG (parameters are indented further than the action key, DO NOT do this):\n - aiScroll:\n direction: 'down'\n scrollType: 'singleAction'\n - aiInput: 'text value'\n locate: 'input field description'\n\n1. Format:\n\nweb:\n url: \"starting_url\"\n viewportWidth: 1280\n viewportHeight: 960\n\ntasks:\n - name: \"descriptive task name\"\n flow:\n - aiTap: \"element description\"\n xpath: '/html/body/div[1]/button[1]'\n - aiInput: 'text value'\n locate: 'input field description'\n xpath: '/html/body/div[1]/input[1]'\n - aiScroll:\n direction: 'down'\n scrollType: 'singleAction'\n distance: 500\n locate: \"scrollable area description\"\n xpath: '/html/body/div[1]/main[1]'\n - aiAssert: \"expected state\"\n - sleep: 1000\n\n2. Action Types:\n- aiTap: for clicks (natural language targeting)\n- aiInput: for text input with 'locate' field\n- aiScroll: with direction and scrollType\n- aiAssert: for validations\n- sleep: for delays (milliseconds)\n\n\n\nYAML type\ntasks:\n - name: <name>\n continueOnError: <boolean> # Optional, whether to continue to the next task on error, defaults to false.\n flow:\n # Auto Planning (.ai)\n # ----------------\n\n # Perform an interaction. `ai` is a shorthand for `aiAct`.\n - ai: <prompt>\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # This usage is the same as `ai`.\n - aiAct: <prompt>\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Instant Action (.aiTap, .aiDoubleClick, .aiHover, .aiInput, .aiKeyboardPress, .aiScroll)\n # ----------------\n\n # Tap an element described by a prompt.\n - aiTap: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Double click an element described by a prompt.\n - aiDoubleClick: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Hover over an element described by a prompt.\n - aiHover: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Input text into an element described by a prompt.\n - aiInput: <final text content of the input>\n locate: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Press a key (e.g., Enter, Tab, Escape) on an element described by a prompt.\n - aiKeyboardPress: <key>\n locate: <prompt>\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Scroll globally or on an element described by a prompt.\n - aiScroll:\n direction: 'up' # or 'down' | 'left' | 'right'\n scrollType: 'singleAction' # or 'scrollToTop' | 'scrollToBottom' | 'scrollToLeft' | 'scrollToRight'\n distance: <number> # Optional, the scroll distance in pixels.\n locate: <prompt> # Optional, the element to scroll on.\n deepLocate: <boolean> # Optional, whether to use deepLocate to precisely locate the element. Defaults to False.\n xpath: <xpath> # Optional, the xpath of the target element for the operation. If provided, Midscene will prioritize this xpath to find the element before using the cache and the AI model. Defaults to empty.\n cacheable: <boolean> # Optional, whether to cache the result of this API call when the [caching feature](./caching.mdx) is enabled. Defaults to True.\n\n # Record the current screenshot with a description in the report file.\n - recordToReport: <title> # Optional, the title of the screenshot. If not provided, the title will be 'untitled'.\n content: <content> # Optional, the description of the screenshot.\n\n # Data Extraction\n # ----------------\n\n # Perform a query that returns a JSON object.\n - aiQuery: <prompt> # Remember to describe the format of the result in the prompt.\n name: <name> # The key for the query result in the JSON output.\n\n # More APIs\n # ----------------\n\n # Wait for a condition to be met, with a timeout (in ms, optional, defaults to 30000).\n - aiWaitFor: <prompt>\n timeout: <ms>\n\n # Perform an assertion.\n - aiAssert: <prompt>\n errorMessage: <error-message> # Optional, the error message to print if the assertion fails.\n\n # Wait for a specified amount of time.\n - sleep: <ms>\n\n # Execute a piece of JavaScript code in the web page context.\n - javascript: <javascript>\n name: <name> # Optional, assign a name to the return value, which will be used as a key in the JSON output.\n\n - name: <name>\n flow:\n # ...\n";
@@ -37,7 +37,8 @@ export declare function isContainerElement(node: globalThis.Node): node is globa
37
37
  export declare function generateElementByPoint(center: [number, number], description: string, edgeSize?: number): LocateResultElement;
38
38
  /**
39
39
  * Generate a LocateResultElement from a rect.
40
- * This function calculates the center point from the rect and expands the rect by edgeSize.
40
+ * This function calculates the center point from the rect and preserves the
41
+ * original rect as the returned element boundary.
41
42
  *
42
43
  * Note: The rect uses inclusive coordinates where:
43
44
  * - A rect from [left=10, top=10] with [width=1, height=1] covers exactly 1 pixel
@@ -45,12 +46,12 @@ export declare function generateElementByPoint(center: [number, number], descrip
45
46
  *
46
47
  * @param sourceRect - The source rect to generate element from (typically contains integer values)
47
48
  * @param description - Description of the element
48
- * @param edgeSize - Size to expand around the center point (default: 8)
49
- * @returns A LocateResultElement with rect, center (always integers), and description
49
+ * @param edgeSize - Deprecated, retained for backward compatibility
50
+ * @returns A LocateResultElement with the original rect, center (always integers), and description
50
51
  */
51
52
  export declare function generateElementByRect(sourceRect: {
52
53
  left: number;
53
54
  top: number;
54
55
  width: number;
55
56
  height: number;
56
- }, description: string, edgeSize?: number): LocateResultElement;
57
+ }, description: string, _edgeSize?: number): LocateResultElement;
@@ -83,6 +83,7 @@ export interface BaseAgent {
83
83
  page?: {
84
84
  screenshotBase64(): Promise<string>;
85
85
  };
86
+ callActionInActionSpace?: (actionName: string, params?: unknown) => Promise<unknown>;
86
87
  aiAction?: (description: string, params?: Record<string, unknown>) => Promise<unknown>;
87
88
  aiWaitFor?: (assertion: string, options: Record<string, unknown>) => Promise<unknown>;
88
89
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midscene/shared",
3
- "version": "1.6.1-beta-20260331083547.0",
3
+ "version": "1.6.1",
4
4
  "repository": "https://github.com/web-infra-dev/midscene",
5
5
  "homepage": "https://midscenejs.com/",
6
6
  "types": "./dist/types/index.d.ts",
@@ -81,6 +81,23 @@ test('ai shop', async ({
81
81
  `;
82
82
 
83
83
  export const YAML_EXAMPLE_CODE = `
84
+ CRITICAL - YAML Indentation Rules:
85
+ For actions with additional parameters (aiScroll, aiInput, aiKeyboardPress), the parameters must be SIBLING keys at the SAME indentation level as the action key, NOT nested children indented further.
86
+ CORRECT (parameters align with the action key):
87
+ - aiScroll:
88
+ direction: 'down'
89
+ scrollType: 'singleAction'
90
+ distance: 500
91
+ locate: "main content area"
92
+ - aiInput: 'text value'
93
+ locate: 'input field description'
94
+ WRONG (parameters are indented further than the action key, DO NOT do this):
95
+ - aiScroll:
96
+ direction: 'down'
97
+ scrollType: 'singleAction'
98
+ - aiInput: 'text value'
99
+ locate: 'input field description'
100
+
84
101
  1. Format:
85
102
 
86
103
  web:
@@ -92,13 +109,18 @@ tasks:
92
109
  - name: "descriptive task name"
93
110
  flow:
94
111
  - aiTap: "element description"
112
+ xpath: '/html/body/div[1]/button[1]'
95
113
  - aiInput: 'text value'
96
114
  locate: 'input field description'
115
+ xpath: '/html/body/div[1]/input[1]'
97
116
  - aiScroll:
98
- direction: down/up
99
- scrollType: scrollToBottom/scrollToTop/singleAction
117
+ direction: 'down'
118
+ scrollType: 'singleAction'
119
+ distance: 500
120
+ locate: "scrollable area description"
121
+ xpath: '/html/body/div[1]/main[1]'
100
122
  - aiAssert: "expected state"
101
- - sleep: milliseconds
123
+ - sleep: 1000
102
124
 
103
125
  2. Action Types:
104
126
  - aiTap: for clicks (natural language targeting)
@@ -107,24 +129,6 @@ tasks:
107
129
  - aiAssert: for validations
108
130
  - sleep: for delays (milliseconds)
109
131
 
110
- 3. Best Practices:
111
- - Group related actions into logical tasks
112
- - Use natural language descriptions
113
- - Add deepLocate: true for complex interactions
114
- - Keep task names concise but descriptive
115
-
116
- 4. CRITICAL - YAML Indentation Rules:
117
- - For actions with additional parameters (aiScroll, aiInput, aiKeyboardPress), the parameters must be SIBLING keys, NOT nested children
118
- - Parameters like direction, scrollType, locate must align with the action key, not indented further
119
- - CORRECT indentation example:
120
- - aiScroll:
121
- direction: down
122
- scrollType: singleAction
123
- - WRONG indentation (DO NOT do this):
124
- - aiScroll:
125
- direction: down
126
- scrollType: singleAction
127
-
128
132
 
129
133
 
130
134
  YAML type
@@ -181,7 +181,8 @@ export function generateElementByPoint(
181
181
 
182
182
  /**
183
183
  * Generate a LocateResultElement from a rect.
184
- * This function calculates the center point from the rect and expands the rect by edgeSize.
184
+ * This function calculates the center point from the rect and preserves the
185
+ * original rect as the returned element boundary.
185
186
  *
186
187
  * Note: The rect uses inclusive coordinates where:
187
188
  * - A rect from [left=10, top=10] with [width=1, height=1] covers exactly 1 pixel
@@ -189,13 +190,13 @@ export function generateElementByPoint(
189
190
  *
190
191
  * @param sourceRect - The source rect to generate element from (typically contains integer values)
191
192
  * @param description - Description of the element
192
- * @param edgeSize - Size to expand around the center point (default: 8)
193
- * @returns A LocateResultElement with rect, center (always integers), and description
193
+ * @param edgeSize - Deprecated, retained for backward compatibility
194
+ * @returns A LocateResultElement with the original rect, center (always integers), and description
194
195
  */
195
196
  export function generateElementByRect(
196
197
  sourceRect: { left: number; top: number; width: number; height: number },
197
198
  description: string,
198
- edgeSize = 8,
199
+ _edgeSize = 8,
199
200
  ): LocateResultElement {
200
201
  /**
201
202
  * Calculate center point from rect
@@ -222,5 +223,9 @@ export function generateElementByRect(
222
223
  const centerX = sourceRect.left + Math.floor((sourceRect.width - 1) / 2);
223
224
  const centerY = sourceRect.top + Math.floor((sourceRect.height - 1) / 2);
224
225
 
225
- return generateElementByPoint([centerX, centerY], description, edgeSize);
226
+ return {
227
+ rect: sourceRect,
228
+ center: [centerX, centerY],
229
+ description: description || '',
230
+ };
226
231
  }