@jagreehal/workflow 1.14.0 → 1.15.0
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.
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/visualize.cjs +27 -27
- package/dist/visualize.cjs.map +1 -1
- package/dist/visualize.d.cts +105 -2
- package/dist/visualize.d.ts +105 -2
- package/dist/visualize.js +26 -26
- package/dist/visualize.js.map +1 -1
- package/docs/pino-logging-example.md +106 -3
- package/package.json +2 -1
package/dist/visualize.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs","../src/visualize/index.ts","../src/visualize/utils/timing.ts","../src/visualize/parallel-detector.ts","../src/visualize/ir-builder.ts","../src/visualize/types.ts","../src/visualize/renderers/colors.ts","../src/visualize/renderers/ascii.ts","../src/visualize/performance-analyzer.ts","../src/visualize/renderers/mermaid.ts","../src/visualize/renderers/html-styles.ts","../src/visualize/renderers/html-client.ts","../src/visualize/renderers/html.ts","../src/visualize/live-visualizer.ts","../src/visualize/decision-tracker.ts","../src/visualize/time-travel.ts","../src/visualize/dev-server.ts"],"sourcesContent":["'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n * @param {Boolean} [isServer=false] Create the instance in either server or\n * client mode\n * @param {Number} [maxPayload=0] The maximum allowed message length\n */\n constructor(options, isServer, maxPayload) {\n this._maxPayload = maxPayload | 0;\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._isServer = !!isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else {\n buf.set(data, 2);\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch (e) {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate(\n opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},\n false,\n opts.maxPayload\n );\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate(\n this.options.perMessageDeflate,\n true,\n this.options.maxPayload\n );\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };\nexport default WebSocket;\n","/**\n * Workflow Visualization Module\n *\n * Provides tools for visualizing workflow execution with color-coded\n * step states and support for parallel/race operations.\n *\n * @example\n * ```typescript\n * import { createVisualizer } from '@jagreehal/workflow/visualize';\n *\n * const viz = createVisualizer({ workflowName: 'checkout' });\n * const workflow = createWorkflow(deps, { onEvent: viz.handleEvent });\n *\n * await workflow(async (step) => {\n * await step(() => validateCart(cart), 'Validate cart');\n * await step(() => processPayment(payment), 'Process payment');\n * });\n *\n * console.log(viz.render());\n * ```\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n OutputFormat,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n VisualizerOptions,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, mermaidRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// Re-exports\n// =============================================================================\n\nexport * from \"./types\";\nexport { createIRBuilder, type IRBuilderOptions } from \"./ir-builder\";\nexport { asciiRenderer, mermaidRenderer, defaultColorScheme } from \"./renderers\";\nexport { htmlRenderer, renderToHTML } from \"./renderers/html\";\nexport { detectParallelGroups, createParallelDetector, type ParallelDetectorOptions } from \"./parallel-detector\";\nexport { createLiveVisualizer, type LiveVisualizer } from \"./live-visualizer\";\nexport { trackDecision, trackIf, trackSwitch, type DecisionTracker, type IfTracker, type SwitchTracker } from \"./decision-tracker\";\n\n// Time-travel debugging\nexport {\n createTimeTravelController,\n type TimeTravelController,\n type TimeTravelOptions,\n} from \"./time-travel\";\n\n// Performance analysis\nexport {\n createPerformanceAnalyzer,\n getHeatLevel,\n type PerformanceAnalyzer,\n type WorkflowRun,\n} from \"./performance-analyzer\";\n\n// Dev server (WebSocket-based live visualization)\n// Note: ws is an optional peer dependency\nexport {\n createDevServer,\n type DevServer,\n type DevServerOptions,\n} from \"./dev-server\";\n\n// =============================================================================\n// Visualizer Interface\n// =============================================================================\n\n/**\n * Workflow visualizer that processes events and renders output.\n */\nexport interface WorkflowVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Process a scope event (parallel/race) */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n\n /** Process a decision event (conditional branches) */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n\n /** Get current IR state */\n getIR: () => WorkflowIR;\n\n /** Render current state using the default renderer */\n render: () => string;\n\n /** Render to a specific format */\n renderAs: (format: OutputFormat) => string;\n\n /** Reset state for a new workflow */\n reset: () => void;\n\n /** Subscribe to IR updates (for live visualization) */\n onUpdate: (callback: (ir: WorkflowIR) => void) => () => void;\n}\n\n// =============================================================================\n// Create Visualizer\n// =============================================================================\n\n/**\n * Create a workflow visualizer.\n *\n * @example\n * ```typescript\n * const viz = createVisualizer({ workflowName: 'my-workflow' });\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: viz.handleEvent,\n * });\n *\n * await workflow(async (step) => { ... });\n *\n * console.log(viz.render());\n * ```\n */\nexport function createVisualizer(\n options: VisualizerOptions = {}\n): WorkflowVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const updateCallbacks: Set<(ir: WorkflowIR) => void> = new Set();\n\n // Renderers\n const ascii = asciiRenderer();\n const mermaid = mermaidRenderer();\n\n // Build render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: process.stdout?.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n function notifyUpdate(): void {\n if (updateCallbacks.size > 0) {\n const ir = builder.getIR();\n for (const callback of updateCallbacks) {\n callback(ir);\n }\n }\n }\n\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n // Set workflow name if provided\n if (event.type === \"workflow_start\" && workflowName) {\n // Note: We'd need to extend the builder to support setting name\n // For now, the name is passed in render options\n }\n\n notifyUpdate();\n }\n\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n notifyUpdate();\n }\n\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n notifyUpdate();\n }\n\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n // Apply workflow name if provided\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n function render(): string {\n const ir = getIR();\n return ascii.render(ir, renderOptions);\n }\n\n function renderAs(format: OutputFormat): string {\n const ir = getIR();\n\n switch (format) {\n case \"ascii\":\n return ascii.render(ir, renderOptions);\n\n case \"mermaid\":\n return mermaid.render(ir, renderOptions);\n\n case \"json\":\n return JSON.stringify(ir, null, 2);\n\n default:\n throw new Error(`Unknown format: ${format}`);\n }\n }\n\n function reset(): void {\n builder.reset();\n notifyUpdate();\n }\n\n function onUpdate(callback: (ir: WorkflowIR) => void): () => void {\n updateCallbacks.add(callback);\n return () => updateCallbacks.delete(callback);\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n renderAs,\n reset,\n onUpdate,\n };\n}\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Union type for all collectable/visualizable events (workflow + decision).\n */\nexport type CollectableEvent =\n | WorkflowEvent<unknown>\n | DecisionStartEvent\n | DecisionBranchEvent\n | DecisionEndEvent;\n\n/**\n * Visualize collected events (post-execution).\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const events: CollectableEvent[] = [];\n * const workflow = createWorkflow(deps, {\n * onEvent: (e) => events.push(e),\n * });\n *\n * await workflow(async (step) => {\n * const decision = trackIf('check', condition, {\n * emit: (e) => events.push(e),\n * });\n * // ...\n * });\n *\n * console.log(visualizeEvents(events));\n * ```\n */\nexport function visualizeEvents(\n events: CollectableEvent[],\n options: VisualizerOptions = {}\n): string {\n const viz = createVisualizer(options);\n\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n\n return viz.render();\n}\n\n/**\n * Create an event collector for later visualization.\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const collector = createEventCollector();\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: collector.handleEvent,\n * });\n *\n * await workflow(async (step) => {\n * // Decision events can also be collected\n * const decision = trackIf('check', condition, {\n * emit: collector.handleDecisionEvent,\n * });\n * // ...\n * });\n *\n * console.log(collector.visualize());\n * ```\n */\nexport function createEventCollector(options: VisualizerOptions = {}) {\n const events: CollectableEvent[] = [];\n\n return {\n /** Handle a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => {\n events.push(event);\n },\n\n /** Handle a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => {\n events.push(event);\n },\n\n /** Get all collected events */\n getEvents: () => [...events],\n\n /** Get workflow events only */\n getWorkflowEvents: () => events.filter((e): e is WorkflowEvent<unknown> =>\n !e.type.startsWith(\"decision_\")\n ),\n\n /** Get decision events only */\n getDecisionEvents: () => events.filter((e): e is DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent =>\n e.type.startsWith(\"decision_\")\n ),\n\n /** Clear collected events */\n clear: () => {\n events.length = 0;\n },\n\n /** Visualize collected events */\n visualize: () => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.render();\n },\n\n /** Visualize in a specific format */\n visualizeAs: (format: OutputFormat) => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.renderAs(format);\n },\n };\n}\n\n","/**\n * Timing utilities for workflow visualization.\n */\n\n/**\n * Format duration in milliseconds to a human-readable string.\n *\n * @example\n * formatDuration(23) // \"23ms\"\n * formatDuration(1500) // \"1.5s\"\n * formatDuration(65000) // \"1m 5s\"\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`;\n }\n\n if (ms < 60000) {\n const seconds = ms / 1000;\n // Show one decimal for seconds\n return `${seconds.toFixed(1).replace(/\\.0$/, \"\")}s`;\n }\n\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.round((ms % 60000) / 1000);\n\n if (seconds === 0) {\n return `${minutes}m`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n\n/**\n * Generate a unique ID for nodes.\n */\nexport function generateId(): string {\n return `node_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n","/**\n * Parallel Detection - Heuristic detection of parallel execution from timing.\n *\n * When steps overlap in time (one starts before another ends), they are\n * likely running in parallel. This module detects such patterns and\n * groups overlapping steps into ParallelNode structures.\n */\n\nimport type { FlowNode, ParallelNode, StepNode } from \"./types\";\n\n/**\n * Options for parallel detection.\n */\nexport interface ParallelDetectorOptions {\n /**\n * Minimum overlap in milliseconds to consider steps parallel.\n * Default: 0 (any overlap counts)\n */\n minOverlapMs?: number;\n\n /**\n * Maximum gap in milliseconds to still consider steps as part of same parallel group.\n * Default: 5 (steps starting within 5ms are grouped)\n */\n maxGapMs?: number;\n}\n\n/**\n * Step timing information for overlap detection.\n */\ninterface StepTiming {\n node: StepNode;\n startTs: number;\n endTs: number;\n}\n\n/**\n * Check if nodes contain real scope nodes (from scope_start/scope_end events).\n * When real scope nodes exist, heuristic detection should be skipped to avoid\n * duplicating or conflicting with the explicit structure.\n */\nfunction hasRealScopeNodes(nodes: FlowNode[]): boolean {\n for (const node of nodes) {\n // Real scope nodes are parallel/race/sequence that came from scope events\n // (not from heuristic detection, which uses ids starting with \"detected_\")\n if (\n (node.type === \"parallel\" || node.type === \"race\" || node.type === \"sequence\") &&\n !node.id.startsWith(\"detected_\")\n ) {\n return true;\n }\n // Also check for decision nodes if present\n if (\"decisionId\" in node) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Group overlapping steps into parallel nodes.\n *\n * Algorithm:\n * 1. Sort steps by start time\n * 2. For each step, check if it overlaps with existing parallel groups\n * 3. If it overlaps, add to group; otherwise start new sequence\n * 4. Merge overlapping groups when step bridges them\n *\n * Note: If real scope nodes (from scope_start/scope_end) are present,\n * heuristic detection is skipped to avoid conflicts.\n */\nexport function detectParallelGroups(\n nodes: FlowNode[],\n options: ParallelDetectorOptions = {}\n): FlowNode[] {\n // If real scope nodes exist, skip heuristic detection\n // The explicit scope events provide accurate structure\n if (hasRealScopeNodes(nodes)) {\n return nodes;\n }\n\n const { minOverlapMs = 0, maxGapMs = 5 } = options;\n\n // Extract step nodes with timing info, preserving indices for position restoration\n const stepsWithTiming: (StepTiming & { originalIndex: number })[] = [];\n const nonStepNodes: { node: FlowNode; originalIndex: number }[] = [];\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if (node.type === \"step\" && node.startTs !== undefined) {\n stepsWithTiming.push({\n node,\n startTs: node.startTs,\n endTs: node.endTs ?? node.startTs + (node.durationMs ?? 0),\n originalIndex: i,\n });\n } else {\n // Keep non-step nodes with their original position\n nonStepNodes.push({ node, originalIndex: i });\n }\n }\n\n if (stepsWithTiming.length <= 1) {\n return nodes; // Nothing to group\n }\n\n // Sort by start time\n stepsWithTiming.sort((a, b) => a.startTs - b.startTs);\n\n // Group overlapping steps\n type StepTimingWithIndex = StepTiming & { originalIndex: number };\n const groups: StepTimingWithIndex[][] = [];\n let currentGroup: StepTimingWithIndex[] = [stepsWithTiming[0]];\n\n for (let i = 1; i < stepsWithTiming.length; i++) {\n const step = stepsWithTiming[i];\n const groupStart = Math.min(...currentGroup.map((s) => s.startTs));\n const groupEnd = Math.max(...currentGroup.map((s) => s.endTs));\n\n // Two ways steps can be parallel:\n // 1. They started together (within maxGapMs) - handles timing jitter\n // 2. They genuinely overlap (step starts before group ends)\n const startedTogether = step.startTs <= groupStart + maxGapMs;\n const hasTrueOverlap = step.startTs < groupEnd;\n\n if (!startedTogether && !hasTrueOverlap) {\n // Sequential: step started after group ended AND not with the group\n groups.push(currentGroup);\n currentGroup = [step];\n continue;\n }\n\n // Check minOverlapMs threshold for overlap duration\n // For steps that started together, overlap is measured from step start to group end\n // For steps with true overlap, it's from step start to min(step end, group end)\n const overlapDuration = hasTrueOverlap\n ? Math.min(step.endTs, groupEnd) - step.startTs\n : 0;\n\n // Started together bypasses minOverlapMs (they're parallel by definition)\n // True overlap must meet the minOverlapMs threshold\n if (startedTogether || overlapDuration >= minOverlapMs) {\n currentGroup.push(step);\n } else {\n // Overlap too small - treat as sequential\n groups.push(currentGroup);\n currentGroup = [step];\n }\n }\n groups.push(currentGroup);\n\n // Convert groups to nodes with position tracking\n const groupedNodes: { node: FlowNode; position: number }[] = [];\n\n for (const group of groups) {\n // Use the minimum original index as the position for the group\n const position = Math.min(...group.map((s) => s.originalIndex));\n\n if (group.length === 1) {\n // Single step - no parallel grouping needed\n groupedNodes.push({ node: group[0].node, position });\n } else {\n // Multiple overlapping steps - create parallel node\n const children = group.map((s) => s.node);\n const startTs = Math.min(...group.map((s) => s.startTs));\n const endTs = Math.max(...group.map((s) => s.endTs));\n\n const parallelNode: ParallelNode = {\n type: \"parallel\",\n id: `detected_parallel_${startTs}`,\n name: `${children.length} parallel steps`,\n state: deriveGroupState(children),\n mode: \"all\",\n children,\n startTs,\n endTs,\n durationMs: endTs - startTs,\n };\n\n groupedNodes.push({ node: parallelNode, position });\n }\n }\n\n // Add non-step nodes with their original positions\n for (const { node, originalIndex } of nonStepNodes) {\n groupedNodes.push({ node, position: originalIndex });\n }\n\n // Sort by original position to preserve ordering\n groupedNodes.sort((a, b) => a.position - b.position);\n\n return groupedNodes.map((g) => g.node);\n}\n\n/**\n * Derive the state of a group from its children.\n */\nfunction deriveGroupState(\n children: FlowNode[]\n): \"pending\" | \"running\" | \"success\" | \"error\" | \"aborted\" | \"cached\" {\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n const hasPending = children.some((c) => c.state === \"pending\");\n if (hasPending) return \"pending\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n return \"success\";\n}\n\n/**\n * Create a parallel detector that processes nodes.\n */\nexport function createParallelDetector(options: ParallelDetectorOptions = {}) {\n return {\n /**\n * Process nodes and group overlapping ones into parallel nodes.\n */\n detect: (nodes: FlowNode[]) => detectParallelGroups(nodes, options),\n };\n}\n","/**\n * IR Builder - Converts workflow events to Intermediate Representation.\n *\n * The builder maintains state as events arrive, constructing a tree\n * representation of the workflow execution that can be rendered.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n FlowNode,\n ScopeEndEvent,\n ScopeStartEvent,\n ScopeType,\n StepNode,\n StepState,\n WorkflowIR,\n WorkflowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n DecisionBranch,\n IRSnapshot,\n ActiveStepSnapshot,\n WorkflowHooks,\n HookExecution,\n} from \"./types\";\nimport { generateId } from \"./utils/timing\";\nimport { detectParallelGroups, type ParallelDetectorOptions } from \"./parallel-detector\";\n\n// =============================================================================\n// Builder Options\n// =============================================================================\n\n/**\n * Options for the IR builder.\n */\nexport interface IRBuilderOptions {\n /**\n * Enable heuristic parallel detection based on timing.\n * When true, overlapping steps are grouped into ParallelNodes.\n * Default: true\n */\n detectParallel?: boolean;\n\n /**\n * Options for parallel detection.\n */\n parallelDetection?: ParallelDetectorOptions;\n\n /**\n * Enable snapshot recording for time-travel debugging.\n * When true, the builder captures IR state after each event.\n * Default: false\n */\n enableSnapshots?: boolean;\n\n /**\n * Maximum number of snapshots to keep (ring buffer behavior).\n * When exceeded, oldest snapshots are discarded.\n * Default: 1000\n */\n maxSnapshots?: number;\n}\n\n// =============================================================================\n// Builder State\n// =============================================================================\n\ninterface ActiveStep {\n id: string;\n name?: string;\n key?: string;\n startTs: number;\n retryCount: number;\n timedOut: boolean;\n timeoutMs?: number;\n}\n\ninterface ActiveScope {\n id: string;\n name?: string;\n type: ScopeType;\n startTs: number;\n children: FlowNode[];\n}\n\ninterface ActiveDecision {\n id: string;\n name?: string;\n condition?: string;\n decisionValue?: unknown;\n startTs: number;\n branches: Map<string, DecisionBranch>;\n branchTaken?: string | boolean;\n}\n\n// =============================================================================\n// IR Builder\n// =============================================================================\n\n/**\n * Creates an IR builder that processes workflow events.\n */\nexport function createIRBuilder(options: IRBuilderOptions = {}) {\n const {\n detectParallel = true,\n parallelDetection,\n enableSnapshots = false,\n maxSnapshots = 1000,\n } = options;\n\n // Current workflow state\n let workflowId: string | undefined;\n let workflowStartTs: number | undefined;\n let workflowState: StepState = \"pending\";\n let workflowError: unknown;\n let workflowDurationMs: number | undefined;\n\n // Active steps (currently running)\n const activeSteps = new Map<string, ActiveStep>();\n\n // Active scopes (parallel/race blocks)\n const scopeStack: ActiveScope[] = [];\n\n // Active decisions (conditional branches)\n const decisionStack: ActiveDecision[] = [];\n\n // Completed nodes at the current scope level\n let currentNodes: FlowNode[] = [];\n\n // Metadata\n let createdAt = Date.now();\n let lastUpdatedAt = createdAt;\n\n // Hook executions\n let hookState: WorkflowHooks = {\n onAfterStep: new Map(),\n };\n\n // Snapshot state for time-travel debugging\n const snapshots: IRSnapshot[] = [];\n let eventIndex = 0;\n\n /**\n * Get the step ID from an event.\n * Uses stepId if available (new events), then falls back to stepKey or name,\n * and finally generates a random ID for backwards compatibility.\n */\n function getStepId(event: { stepId?: string; stepKey?: string; name?: string }): string {\n return event.stepId ?? event.stepKey ?? event.name ?? generateId();\n }\n\n /**\n * Add a completed node to the current scope or decision branch.\n */\n function addNode(node: FlowNode): void {\n // If we're in a decision, add to the taken branch\n if (decisionStack.length > 0) {\n const decision = decisionStack[decisionStack.length - 1];\n // Find the taken branch\n for (const branch of decision.branches.values()) {\n if (branch.taken) {\n branch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n // If no branch is marked as taken yet, add to the first branch\n // (this handles cases where steps execute before branch is marked)\n const firstBranch = Array.from(decision.branches.values())[0];\n if (firstBranch) {\n firstBranch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n\n // If we're in a scope, add to the scope\n if (scopeStack.length > 0) {\n // Add to the innermost scope\n scopeStack[scopeStack.length - 1].children.push(node);\n } else {\n // Add to the root level\n currentNodes.push(node);\n }\n lastUpdatedAt = Date.now();\n }\n\n /**\n * Capture a snapshot of the current IR state (for time-travel debugging).\n * Called after each event is processed.\n */\n function captureSnapshot(event: WorkflowEvent<unknown>): void {\n if (!enableSnapshots) return;\n\n // Deep clone the current IR state\n const ir = getIR();\n\n // Clone active steps for debugging\n const activeStepsCopy = new Map<string, ActiveStepSnapshot>();\n for (const [id, step] of activeSteps) {\n activeStepsCopy.set(id, {\n id: step.id,\n name: step.name,\n key: step.key,\n startTs: step.startTs,\n retryCount: step.retryCount,\n timedOut: step.timedOut,\n timeoutMs: step.timeoutMs,\n });\n }\n\n const snapshot: IRSnapshot = {\n id: `snapshot_${eventIndex}`,\n eventIndex,\n event: structuredClone(event),\n ir: structuredClone(ir),\n timestamp: Date.now(),\n activeSteps: activeStepsCopy,\n };\n\n snapshots.push(snapshot);\n\n // Ring buffer: remove oldest if we exceed max\n if (snapshots.length > maxSnapshots) {\n snapshots.shift();\n }\n\n eventIndex++;\n }\n\n /**\n * Handle a workflow event and update the IR.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n switch (event.type) {\n case \"workflow_start\":\n workflowId = event.workflowId;\n workflowStartTs = event.ts;\n workflowState = \"running\";\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n // Note: Don't clear hookState here - shouldRun and onBeforeStart\n // events are emitted BEFORE workflow_start. Only clear onAfterStep\n // since those are per-step and should reset for each workflow run.\n hookState.onAfterStep = new Map();\n break;\n\n case \"workflow_success\":\n workflowState = \"success\";\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"workflow_error\":\n workflowState = \"error\";\n workflowError = event.error;\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_start\": {\n const id = getStepId(event);\n activeSteps.set(id, {\n id,\n name: event.name,\n key: event.stepKey,\n startTs: event.ts,\n retryCount: 0,\n timedOut: false,\n });\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_success\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"success\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_error\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"error\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_aborted\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"aborted\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_cache_hit\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"cached\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n\n case \"step_cache_miss\":\n // Cache miss just means the step will execute normally\n // We'll get a step_start event next\n break;\n\n case \"step_complete\":\n // step_complete is for state persistence, not visualization\n // We already handled the step via step_success/step_error\n break;\n\n case \"step_timeout\": {\n // Timeout is an intermediate event - step may retry or will get step_error\n // Track timeout info on the active step\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.timedOut = true;\n active.timeoutMs = event.timeoutMs;\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retry\": {\n // Retry is an intermediate event - increment retry counter\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.retryCount = (event.attempt ?? 1) - 1; // attempt is 1-indexed, retryCount is 0-indexed\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retries_exhausted\":\n // All retries exhausted - step_error will follow\n // The error state will be set by step_error handler\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_skipped\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"skipped\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n\n // Hook events\n case \"hook_should_run\": {\n const hookExec: HookExecution = {\n type: \"shouldRun\",\n state: \"success\",\n ts: event.ts,\n durationMs: event.durationMs,\n context: {\n result: event.result,\n skipped: event.skipped,\n },\n };\n hookState.shouldRun = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_should_run_error\": {\n const hookExec: HookExecution = {\n type: \"shouldRun\",\n state: \"error\",\n ts: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n };\n hookState.shouldRun = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_before_start\": {\n const hookExec: HookExecution = {\n type: \"onBeforeStart\",\n state: \"success\",\n ts: event.ts,\n durationMs: event.durationMs,\n context: {\n result: event.result,\n skipped: event.skipped,\n },\n };\n hookState.onBeforeStart = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_before_start_error\": {\n const hookExec: HookExecution = {\n type: \"onBeforeStart\",\n state: \"error\",\n ts: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n };\n hookState.onBeforeStart = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_after_step\": {\n const hookExec: HookExecution = {\n type: \"onAfterStep\",\n state: \"success\",\n ts: event.ts,\n durationMs: event.durationMs,\n context: {\n stepKey: event.stepKey,\n },\n };\n hookState.onAfterStep.set(event.stepKey, hookExec);\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_after_step_error\": {\n const hookExec: HookExecution = {\n type: \"onAfterStep\",\n state: \"error\",\n ts: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n context: {\n stepKey: event.stepKey,\n },\n };\n hookState.onAfterStep.set(event.stepKey, hookExec);\n lastUpdatedAt = Date.now();\n break;\n }\n }\n\n // Capture snapshot after processing event (for time-travel)\n captureSnapshot(event);\n }\n\n /**\n * Handle a scope event (parallel/race start/end).\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n if (event.type === \"scope_start\") {\n scopeStack.push({\n id: event.scopeId,\n name: event.name,\n type: event.scopeType,\n startTs: event.ts,\n children: [],\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"scope_end\") {\n const scope = scopeStack.pop();\n if (scope) {\n const node: ParallelNode | RaceNode =\n scope.type === \"race\"\n ? {\n type: \"race\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n winnerId: event.winnerId,\n }\n : {\n type: \"parallel\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n mode: scope.type === \"allSettled\" ? \"allSettled\" : \"all\",\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Handle a decision event (conditional branch start/branch/end).\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n if (event.type === \"decision_start\") {\n decisionStack.push({\n id: event.decisionId,\n name: event.name,\n condition: event.condition,\n decisionValue: event.decisionValue,\n startTs: event.ts,\n branches: new Map(),\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"decision_branch\") {\n const decision = decisionStack[decisionStack.length - 1];\n if (decision && decision.id === event.decisionId) {\n // Find or create branch\n const branchKey = event.branchLabel;\n const existing = decision.branches.get(branchKey);\n if (existing) {\n // Update existing branch\n existing.taken = event.taken;\n } else {\n // Create new branch\n decision.branches.set(branchKey, {\n label: event.branchLabel,\n condition: event.condition,\n taken: event.taken,\n children: [],\n });\n }\n lastUpdatedAt = Date.now();\n }\n } else if (event.type === \"decision_end\") {\n const decision = decisionStack.pop();\n if (decision && decision.id === event.decisionId) {\n // Convert branches map to array\n const branches: DecisionBranch[] = Array.from(decision.branches.values());\n\n const node: DecisionNode = {\n type: \"decision\",\n id: decision.id,\n name: decision.name,\n state: deriveState(\n branches.flatMap((b) => (b.taken ? b.children : []))\n ),\n startTs: decision.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n condition: decision.condition,\n decisionValue: decision.decisionValue,\n branchTaken: event.branchTaken ?? decision.branchTaken,\n branches,\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Derive the state of a parent node from its children.\n */\n function deriveState(children: FlowNode[]): StepState {\n if (children.length === 0) return \"success\";\n\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n return \"pending\";\n }\n\n /**\n * Get the current nodes including any active (running) steps.\n */\n function getCurrentNodes(): FlowNode[] {\n const nodes = [...currentNodes];\n\n // Add active steps as running nodes\n for (const [, active] of activeSteps) {\n nodes.push({\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"running\",\n startTs: active.startTs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n });\n }\n\n return nodes;\n }\n\n /**\n * Build and return the current IR state.\n */\n function getIR(): WorkflowIR {\n let children = getCurrentNodes();\n\n // Apply parallel detection if enabled\n if (detectParallel) {\n children = detectParallelGroups(children, parallelDetection);\n }\n\n const root: WorkflowNode = {\n type: \"workflow\",\n id: workflowId ?? generateId(),\n workflowId: workflowId ?? \"unknown\",\n state: workflowState,\n startTs: workflowStartTs,\n durationMs: workflowDurationMs,\n children,\n error: workflowError,\n };\n\n // Include hooks if any have been recorded\n const hasHooks =\n hookState.shouldRun !== undefined ||\n hookState.onBeforeStart !== undefined ||\n hookState.onAfterStep.size > 0;\n\n return {\n root,\n metadata: {\n createdAt,\n lastUpdatedAt,\n },\n ...(hasHooks && { hooks: hookState }),\n };\n }\n\n /**\n * Reset the builder state.\n */\n function reset(): void {\n workflowId = undefined;\n workflowStartTs = undefined;\n workflowState = \"pending\";\n workflowError = undefined;\n workflowDurationMs = undefined;\n activeSteps.clear();\n scopeStack.length = 0;\n decisionStack.length = 0;\n currentNodes = [];\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n // Clear hooks\n hookState = {\n onAfterStep: new Map(),\n };\n // Clear snapshots\n snapshots.length = 0;\n eventIndex = 0;\n }\n\n /**\n * Get all recorded snapshots.\n */\n function getSnapshots(): IRSnapshot[] {\n return [...snapshots];\n }\n\n /**\n * Get a snapshot at a specific index.\n */\n function getSnapshotAt(index: number): IRSnapshot | undefined {\n return snapshots[index];\n }\n\n /**\n * Get the IR state at a specific snapshot index.\n */\n function getIRAt(index: number): WorkflowIR | undefined {\n return snapshots[index]?.ir;\n }\n\n /**\n * Clear all recorded snapshots.\n */\n function clearSnapshots(): void {\n snapshots.length = 0;\n eventIndex = 0;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n reset,\n // Snapshot methods for time-travel\n getSnapshots,\n getSnapshotAt,\n getIRAt,\n clearSnapshots,\n /** Check if there are active (running) steps */\n get hasActiveSteps() {\n return activeSteps.size > 0;\n },\n /** Get the current workflow state */\n get state() {\n return workflowState;\n },\n /** Get the number of recorded snapshots */\n get snapshotCount() {\n return snapshots.length;\n },\n /** Check if snapshot recording is enabled */\n get snapshotsEnabled() {\n return enableSnapshots;\n },\n };\n}\n\n/**\n * Type for the IR builder instance.\n */\nexport type IRBuilder = ReturnType<typeof createIRBuilder>;\n","/**\n * Workflow Visualization - Intermediate Representation Types\n *\n * The IR (Intermediate Representation) is a DSL that represents workflow\n * execution structure. Events are converted to IR, which can then be\n * rendered to various output formats (ASCII, Mermaid, JSON, etc.).\n */\n\n// =============================================================================\n// Step States\n// =============================================================================\n\n/**\n * Execution state of a step with semantic meaning for visualization.\n *\n * Color mapping:\n * - pending → white/clear (not started)\n * - running → yellow (currently executing)\n * - success → green (completed successfully)\n * - error → red (failed with error)\n * - aborted → gray (cancelled, e.g., in race)\n * - cached → blue (served from cache)\n * - skipped → dim gray (not executed due to conditional logic)\n */\nexport type StepState =\n | \"pending\"\n | \"running\"\n | \"success\"\n | \"error\"\n | \"aborted\"\n | \"cached\"\n | \"skipped\";\n\n// =============================================================================\n// Node Types\n// =============================================================================\n\n/**\n * Base properties shared by all IR nodes.\n */\nexport interface BaseNode {\n /** Unique identifier for this node */\n id: string;\n /** Human-readable name (from step options or inferred) */\n name?: string;\n /** Cache key if this is a keyed step */\n key?: string;\n /** Current execution state */\n state: StepState;\n /** Timestamp when execution started */\n startTs?: number;\n /** Timestamp when execution ended */\n endTs?: number;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error value if state is 'error' */\n error?: unknown;\n /** Input value that triggered this step (for decision understanding) */\n input?: unknown;\n /** Output value from this step (for decision understanding) */\n output?: unknown;\n /** Number of retry attempts made (0 = no retries, 1 = one retry, etc.) */\n retryCount?: number;\n /** Whether this step experienced a timeout (may have retried after) */\n timedOut?: boolean;\n /** Timeout duration in ms (if timed out) */\n timeoutMs?: number;\n}\n\n/**\n * A single step execution node.\n */\nexport interface StepNode extends BaseNode {\n type: \"step\";\n}\n\n/**\n * Sequential execution - steps run one after another.\n * This is the implicit structure when steps are awaited in sequence.\n */\nexport interface SequenceNode extends BaseNode {\n type: \"sequence\";\n children: FlowNode[];\n}\n\n/**\n * Parallel execution - all branches run simultaneously.\n * Created by allAsync() or allSettledAsync().\n */\nexport interface ParallelNode extends BaseNode {\n type: \"parallel\";\n children: FlowNode[];\n /**\n * Execution mode:\n * - 'all': Fails on first error (allAsync)\n * - 'allSettled': Collects all results (allSettledAsync)\n */\n mode: \"all\" | \"allSettled\";\n}\n\n/**\n * Race execution - first to complete wins.\n * Created by anyAsync().\n */\nexport interface RaceNode extends BaseNode {\n type: \"race\";\n children: FlowNode[];\n /** ID of the winning branch (first to succeed) */\n winnerId?: string;\n}\n\n/**\n * Decision point - conditional branch (if/switch).\n * Shows which branch was taken and why.\n */\nexport interface DecisionNode extends BaseNode {\n type: \"decision\";\n /** Condition that was evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value that was evaluated (the input to the decision) */\n decisionValue?: unknown;\n /** Which branch was taken (true/false, or the matched case) */\n branchTaken?: string | boolean;\n /** All possible branches (including skipped ones) */\n branches: DecisionBranch[];\n}\n\n/**\n * A branch in a decision node.\n */\nexport interface DecisionBranch {\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n label: string;\n /** Condition that would trigger this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n /** Steps in this branch */\n children: FlowNode[];\n}\n\n/**\n * Union of all flow node types.\n */\nexport type FlowNode = StepNode | SequenceNode | ParallelNode | RaceNode | DecisionNode;\n\n/**\n * Root node representing the entire workflow.\n */\nexport interface WorkflowNode extends BaseNode {\n type: \"workflow\";\n /** Correlation ID from the workflow execution */\n workflowId: string;\n /** Child nodes (steps, parallel blocks, etc.) */\n children: FlowNode[];\n}\n\n// =============================================================================\n// Workflow IR\n// =============================================================================\n\n/**\n * Complete workflow intermediate representation.\n * This is the main data structure produced by the IR builder.\n */\nexport interface WorkflowIR {\n /** Root workflow node */\n root: WorkflowNode;\n /** Metadata about the IR */\n metadata: {\n /** When the IR was first created */\n createdAt: number;\n /** When the IR was last updated */\n lastUpdatedAt: number;\n };\n /** Hook executions (if any hooks are configured) */\n hooks?: WorkflowHooks;\n}\n\n// =============================================================================\n// Scope Events (for parallel/race detection)\n// =============================================================================\n\n// Re-export ScopeType from core for consistency\nexport type { ScopeType } from \"../core\";\nimport type { ScopeType } from \"../core\";\n\n/**\n * Event emitted when entering a parallel/race scope.\n * This matches the scope_start event in WorkflowEvent.\n */\nexport interface ScopeStartEvent {\n type: \"scope_start\";\n workflowId: string;\n scopeId: string;\n scopeType: ScopeType;\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when exiting a parallel/race scope.\n */\nexport interface ScopeEndEvent {\n type: \"scope_end\";\n workflowId: string;\n scopeId: string;\n ts: number;\n durationMs: number;\n /** For race scopes, the ID of the winning branch */\n winnerId?: string;\n}\n\n/**\n * Event emitted when a decision point is encountered.\n * Use this to track conditional logic (if/switch).\n */\nexport interface DecisionStartEvent {\n type: \"decision_start\";\n workflowId: string;\n decisionId: string;\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n decisionValue?: unknown;\n /** Name/label for this decision point */\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when a decision branch is taken.\n */\nexport interface DecisionBranchEvent {\n type: \"decision_branch\";\n workflowId: string;\n decisionId: string;\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n branchLabel: string;\n /** Condition for this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n ts: number;\n}\n\n/**\n * Event emitted when a decision point completes.\n */\nexport interface DecisionEndEvent {\n type: \"decision_end\";\n workflowId: string;\n decisionId: string;\n /** Which branch was taken */\n branchTaken?: string | boolean;\n ts: number;\n durationMs: number;\n}\n\n/**\n * Event emitted when a step is skipped due to conditional logic.\n */\nexport interface StepSkippedEvent {\n type: \"step_skipped\";\n workflowId: string;\n stepKey?: string;\n name?: string;\n /** Reason why this step was skipped (e.g., \"condition was false\") */\n reason?: string;\n /** The decision that caused this skip */\n decisionId?: string;\n ts: number;\n}\n\n/**\n * Union of scope-related events.\n */\nexport type ScopeEvent = ScopeStartEvent | ScopeEndEvent;\n\n/**\n * Union of decision-related events.\n */\nexport type DecisionEvent = DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent;\n\n// =============================================================================\n// Renderer Types\n// =============================================================================\n\n/**\n * Color scheme for rendering step states.\n */\nexport interface ColorScheme {\n pending: string;\n running: string;\n success: string;\n error: string;\n aborted: string;\n cached: string;\n skipped: string;\n}\n\n/**\n * Options passed to renderers.\n */\nexport interface RenderOptions {\n /** Show timing information (duration) */\n showTimings: boolean;\n /** Show step cache keys */\n showKeys: boolean;\n /** Terminal width for ASCII renderer */\n terminalWidth?: number;\n /** Color scheme */\n colors: ColorScheme;\n}\n\n/**\n * Extended options for Mermaid renderer.\n * Controls how edges are displayed for retries, errors, and timeouts.\n */\nexport interface MermaidRenderOptions extends RenderOptions {\n /** Show retry as self-loop edge (default: true) */\n showRetryEdges?: boolean;\n /** Show error flow to error node (default: true) */\n showErrorEdges?: boolean;\n /** Show timeout as alternative path (default: true) */\n showTimeoutEdges?: boolean;\n}\n\n/**\n * Renderer interface - transforms IR to output format.\n */\nexport interface Renderer {\n /** Unique identifier for this renderer */\n readonly name: string;\n /** Render IR to string output */\n render(ir: WorkflowIR, options: RenderOptions): string;\n /** Whether this renderer supports live (incremental) updates */\n supportsLive?: boolean;\n /** Render incremental update (optional) */\n renderUpdate?(\n ir: WorkflowIR,\n changedNodes: FlowNode[],\n options: RenderOptions\n ): string;\n}\n\n// =============================================================================\n// Visualizer Types\n// =============================================================================\n\n/**\n * Output format for rendering.\n */\nexport type OutputFormat = \"ascii\" | \"mermaid\" | \"json\";\n\n/**\n * Options for creating a visualizer.\n */\nexport interface VisualizerOptions {\n /** Name for the workflow in visualizations */\n workflowName?: string;\n /** Enable parallel detection heuristics (default: true) */\n detectParallel?: boolean;\n /** Show timing information (default: true) */\n showTimings?: boolean;\n /** Show step keys (default: false) */\n showKeys?: boolean;\n /** Custom color scheme */\n colors?: Partial<ColorScheme>;\n}\n\n/**\n * Options for live visualization.\n */\nexport interface LiveVisualizerOptions extends VisualizerOptions {\n /** Output stream (default: process.stdout) */\n stream?: NodeJS.WriteStream;\n /** Update interval in ms (default: 100) */\n updateInterval?: number;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a node is a StepNode.\n */\nexport function isStepNode(node: FlowNode): node is StepNode {\n return node.type === \"step\";\n}\n\n/**\n * Check if a node is a SequenceNode.\n */\nexport function isSequenceNode(node: FlowNode): node is SequenceNode {\n return node.type === \"sequence\";\n}\n\n/**\n * Check if a node is a ParallelNode.\n */\nexport function isParallelNode(node: FlowNode): node is ParallelNode {\n return node.type === \"parallel\";\n}\n\n/**\n * Check if a node is a RaceNode.\n */\nexport function isRaceNode(node: FlowNode): node is RaceNode {\n return node.type === \"race\";\n}\n\n/**\n * Check if a node is a DecisionNode.\n */\nexport function isDecisionNode(node: FlowNode): node is DecisionNode {\n return node.type === \"decision\";\n}\n\n/**\n * Check if a node has children.\n */\nexport function hasChildren(\n node: FlowNode\n): node is SequenceNode | ParallelNode | RaceNode | DecisionNode {\n return \"children\" in node || (node.type === \"decision\" && \"branches\" in node);\n}\n\n// =============================================================================\n// Time Travel Types\n// =============================================================================\n\n/**\n * Snapshot of an active step's state at a point in time.\n */\nexport interface ActiveStepSnapshot {\n id: string;\n name?: string;\n key?: string;\n startTs: number;\n retryCount: number;\n timedOut: boolean;\n timeoutMs?: number;\n}\n\n/**\n * A snapshot of the complete IR state at a specific point in time.\n * Used for time-travel debugging - each event creates a snapshot.\n */\nexport interface IRSnapshot {\n /** Unique identifier for this snapshot */\n id: string;\n /** Index in the event sequence (0-based) */\n eventIndex: number;\n /** The event that triggered this snapshot */\n event: unknown; // WorkflowEvent - avoid circular import\n /** Complete IR state at this moment */\n ir: WorkflowIR;\n /** Timestamp when snapshot was taken */\n timestamp: number;\n /** Active step states at this moment (for debugging) */\n activeSteps: Map<string, ActiveStepSnapshot>;\n}\n\n/**\n * State of the time-travel controller.\n */\nexport interface TimeTravelState {\n /** All recorded snapshots */\n snapshots: IRSnapshot[];\n /** Current snapshot index (for playback position) */\n currentIndex: number;\n /** Whether playback is active */\n isPlaying: boolean;\n /** Playback speed multiplier (1.0 = realtime, 2.0 = 2x speed) */\n playbackSpeed: number;\n /** Whether recording is active */\n isRecording: boolean;\n}\n\n// =============================================================================\n// Performance Analysis Types\n// =============================================================================\n\n/**\n * Performance metrics for a single node across multiple runs.\n */\nexport interface NodePerformance {\n /** Node identifier (name or step ID) */\n nodeId: string;\n /** Average duration across all samples */\n avgDurationMs: number;\n /** Minimum duration observed */\n minDurationMs: number;\n /** Maximum duration observed */\n maxDurationMs: number;\n /** Standard deviation of durations */\n stdDevMs: number;\n /** Number of timing samples collected */\n samples: number;\n /** Retry frequency (0-1, where 1 = always retries) */\n retryRate: number;\n /** Timeout frequency (0-1) */\n timeoutRate: number;\n /** Error rate (0-1) */\n errorRate: number;\n /** Percentile data for distribution analysis */\n percentiles: {\n p50: number;\n p90: number;\n p95: number;\n p99: number;\n };\n}\n\n/**\n * Heatmap data for visualizing performance across nodes.\n */\nexport interface HeatmapData {\n /** Map of node ID to heat level (0-1, where 1 is hottest/slowest) */\n heat: Map<string, number>;\n /** The metric used for heat calculation */\n metric: \"duration\" | \"retryRate\" | \"errorRate\";\n /** Statistics used to compute heat values */\n stats: {\n /** Minimum value in the dataset */\n min: number;\n /** Maximum value in the dataset */\n max: number;\n /** Mean value */\n mean: number;\n /** Threshold above which a node is considered \"hot\" */\n threshold: number;\n };\n}\n\n/**\n * Heat level for visual styling.\n */\nexport type HeatLevel = \"cold\" | \"cool\" | \"neutral\" | \"warm\" | \"hot\" | \"critical\";\n\n// =============================================================================\n// HTML Renderer Types\n// =============================================================================\n\n/**\n * Theme for the HTML visualizer.\n */\nexport type HTMLTheme = \"light\" | \"dark\" | \"auto\";\n\n/**\n * Layout direction for the workflow diagram.\n */\nexport type LayoutDirection = \"TB\" | \"LR\" | \"BT\" | \"RL\";\n\n/**\n * Options for the HTML renderer.\n */\nexport interface HTMLRenderOptions extends RenderOptions {\n /** Enable interactive features (click to inspect, zoom/pan) */\n interactive: boolean;\n /** Include time-travel controls */\n timeTravel: boolean;\n /** Include performance heatmap overlay */\n heatmap: boolean;\n /** Animation duration for transitions (ms) */\n animationDuration: number;\n /** Color theme */\n theme: HTMLTheme;\n /** Diagram layout direction */\n layout: LayoutDirection;\n /** Heatmap data (if heatmap is enabled) */\n heatmapData?: HeatmapData;\n /** WebSocket URL for live updates (if streaming) */\n wsUrl?: string;\n}\n\n/**\n * Message sent from the web visualizer to the dev server.\n */\nexport interface WebVisualizerMessage {\n type:\n | \"time_travel_seek\"\n | \"time_travel_play\"\n | \"time_travel_pause\"\n | \"time_travel_step_forward\"\n | \"time_travel_step_backward\"\n | \"request_snapshots\"\n | \"toggle_heatmap\"\n | \"set_heatmap_metric\";\n payload?: unknown;\n}\n\n/**\n * Message sent from the dev server to the web visualizer.\n */\nexport interface ServerMessage {\n type:\n | \"ir_update\"\n | \"snapshot\"\n | \"snapshots_list\"\n | \"performance_data\"\n | \"workflow_complete\"\n | \"time_travel_state\";\n payload: unknown;\n}\n\n// =============================================================================\n// Enhanced ASCII Renderer Types\n// =============================================================================\n\n/**\n * Extended render options for the enhanced ASCII renderer.\n */\nexport interface EnhancedRenderOptions extends RenderOptions {\n /** Show performance heatmap coloring */\n showHeatmap?: boolean;\n /** Heatmap data for coloring nodes */\n heatmapData?: HeatmapData;\n /** Show timing sparklines (requires historical data) */\n showSparklines?: boolean;\n /** Historical timing data for sparklines: nodeId → array of durations */\n timingHistory?: Map<string, number[]>;\n}\n\n// =============================================================================\n// Hook Execution Types\n// =============================================================================\n\n/**\n * State of a hook execution.\n */\nexport type HookState = \"pending\" | \"running\" | \"success\" | \"error\";\n\n/**\n * Execution record for a workflow hook.\n */\nexport interface HookExecution {\n /** Hook type identifier */\n type: \"shouldRun\" | \"onBeforeStart\" | \"onAfterStep\";\n /** Execution state */\n state: HookState;\n /** Timestamp when hook started */\n ts: number;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error if hook failed */\n error?: unknown;\n /** Additional context (e.g., stepKey for onAfterStep) */\n context?: {\n /** Step key for onAfterStep hooks */\n stepKey?: string;\n /** Result of shouldRun hook */\n result?: boolean;\n /** Whether workflow was skipped due to shouldRun returning false */\n skipped?: boolean;\n };\n}\n\n/**\n * Hook execution summary for the workflow.\n */\nexport interface WorkflowHooks {\n /** shouldRun hook execution (if configured) */\n shouldRun?: HookExecution;\n /** onBeforeStart hook execution (if configured) */\n onBeforeStart?: HookExecution;\n /** onAfterStep hook executions (keyed by stepKey) */\n onAfterStep: Map<string, HookExecution>;\n}\n","/**\n * ANSI color utilities for terminal output.\n */\n\nimport type { ColorScheme, StepState } from \"../types\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\n\n// Foreground colors\nconst FG_RED = \"\\x1b[31m\";\nconst FG_GREEN = \"\\x1b[32m\";\nconst FG_YELLOW = \"\\x1b[33m\";\nconst FG_BLUE = \"\\x1b[34m\";\nconst FG_GRAY = \"\\x1b[90m\";\nconst FG_WHITE = \"\\x1b[37m\";\n\n// =============================================================================\n// Color Functions\n// =============================================================================\n\n/**\n * Apply ANSI color to text.\n */\nexport function colorize(text: string, color: string): string {\n if (!color) return text;\n return `${color}${text}${RESET}`;\n}\n\n/**\n * Make text bold.\n */\nexport function bold(text: string): string {\n return `${BOLD}${text}${RESET}`;\n}\n\n/**\n * Make text dim.\n */\nexport function dim(text: string): string {\n return `${DIM}${text}${RESET}`;\n}\n\n// =============================================================================\n// Default Color Scheme\n// =============================================================================\n\n/**\n * Default ANSI color scheme for step states.\n */\nexport const defaultColorScheme: ColorScheme = {\n pending: FG_WHITE,\n running: FG_YELLOW,\n success: FG_GREEN,\n error: FG_RED,\n aborted: FG_GRAY,\n cached: FG_BLUE,\n skipped: DIM + FG_GRAY, // Dim gray for skipped steps\n};\n\n// =============================================================================\n// State Symbols\n// =============================================================================\n\n/**\n * Get the symbol for a step state.\n */\nexport function getStateSymbol(state: StepState): string {\n switch (state) {\n case \"pending\":\n return \"○\"; // Empty circle\n case \"running\":\n return \"⟳\"; // Rotating arrows\n case \"success\":\n return \"✓\"; // Check mark\n case \"error\":\n return \"✗\"; // X mark\n case \"aborted\":\n return \"⊘\"; // Circled slash\n case \"cached\":\n return \"↺\"; // Cached/replay\n case \"skipped\":\n return \"⊘\"; // Circled slash (same as aborted, but different color)\n }\n}\n\n/**\n * Get the colored symbol for a step state.\n */\nexport function getColoredSymbol(state: StepState, colors: ColorScheme): string {\n const symbol = getStateSymbol(state);\n return colorize(symbol, colors[state]);\n}\n\n/**\n * Get colored text based on step state.\n */\nexport function colorByState(\n text: string,\n state: StepState,\n colors: ColorScheme\n): string {\n return colorize(text, colors[state]);\n}\n\n// =============================================================================\n// Strip ANSI\n// =============================================================================\n\n/**\n * Strip ANSI escape codes from a string.\n * Useful for calculating visible string length.\n */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n/**\n * Get the visible length of a string (without ANSI codes).\n */\nexport function visibleLength(str: string): string {\n return stripAnsi(str);\n}\n","/**\n * ASCII Terminal Renderer\n *\n * Renders the workflow IR as ASCII art with box-drawing characters\n * and ANSI colors for terminal display.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n StepNode,\n WorkflowIR,\n EnhancedRenderOptions,\n HeatLevel,\n WorkflowHooks,\n HookExecution,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\nimport {\n bold,\n colorByState,\n colorize,\n defaultColorScheme,\n dim,\n getColoredSymbol,\n stripAnsi,\n} from \"./colors\";\n\n// =============================================================================\n// Box Drawing Characters\n// =============================================================================\n\nconst BOX = {\n topLeft: \"┌\",\n topRight: \"┐\",\n bottomLeft: \"└\",\n bottomRight: \"┘\",\n horizontal: \"─\",\n vertical: \"│\",\n teeRight: \"├\",\n teeLeft: \"┤\",\n teeDown: \"┬\",\n teeUp: \"┴\",\n cross: \"┼\",\n} as const;\n\n// =============================================================================\n// Heatmap Colors (ANSI)\n// =============================================================================\n\n/**\n * ANSI color codes for heatmap visualization.\n */\nconst HEAT_COLORS: Record<HeatLevel, string> = {\n cold: \"\\x1b[34m\", // Blue\n cool: \"\\x1b[36m\", // Cyan\n neutral: \"\", // Default (no color)\n warm: \"\\x1b[33m\", // Yellow\n hot: \"\\x1b[31m\", // Red\n critical: \"\\x1b[41m\", // Red background\n};\n\nconst RESET = \"\\x1b[0m\";\n\n/**\n * Get ANSI color code for a heat level.\n */\nfunction getHeatColor(heat: number): string {\n if (heat < 0.2) return HEAT_COLORS.cold;\n if (heat < 0.4) return HEAT_COLORS.cool;\n if (heat < 0.6) return HEAT_COLORS.neutral;\n if (heat < 0.8) return HEAT_COLORS.warm;\n if (heat < 0.95) return HEAT_COLORS.hot;\n return HEAT_COLORS.critical;\n}\n\n/**\n * Apply heat coloring to a string.\n */\nfunction applyHeatColor(text: string, heat: number): string {\n const color = getHeatColor(heat);\n if (!color) return text;\n return `${color}${text}${RESET}`;\n}\n\n// =============================================================================\n// Sparkline Characters\n// =============================================================================\n\nconst SPARK_CHARS = \"▁▂▃▄▅▆▇█\";\n\n/**\n * Render a sparkline from an array of values.\n *\n * @param values Array of numeric values\n * @param width Maximum characters to use (default: 10)\n * @returns Sparkline string\n */\nexport function renderSparkline(values: number[], width = 10): string {\n if (values.length === 0) return \"\";\n\n // Take last N values\n const subset = values.slice(-width);\n const min = Math.min(...subset);\n const max = Math.max(...subset);\n const range = max - min || 1;\n\n return subset\n .map((v) => {\n const normalized = (v - min) / range;\n const index = Math.floor(normalized * (SPARK_CHARS.length - 1));\n return SPARK_CHARS[index];\n })\n .join(\"\");\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Pad a string to a fixed width, accounting for ANSI codes.\n */\nfunction padEnd(str: string, width: number): string {\n const visibleLen = stripAnsi(str).length;\n const padding = Math.max(0, width - visibleLen);\n return str + \" \".repeat(padding);\n}\n\n/**\n * Create a horizontal line with optional title.\n */\nfunction horizontalLine(width: number, title?: string): string {\n if (!title) {\n return BOX.horizontal.repeat(width);\n }\n\n const titleText = ` ${title} `;\n const remainingWidth = width - titleText.length;\n if (remainingWidth < 4) {\n return BOX.horizontal.repeat(width);\n }\n\n const leftPad = 2;\n const rightPad = remainingWidth - leftPad;\n\n return (\n BOX.horizontal.repeat(leftPad) + titleText + BOX.horizontal.repeat(rightPad)\n );\n}\n\n// =============================================================================\n// Hook Rendering\n// =============================================================================\n\n/**\n * Render a single hook execution.\n */\nfunction renderHookExecution(\n hook: HookExecution,\n label: string,\n colors: ReturnType<typeof Object.assign>\n): string {\n const symbol = hook.state === \"success\"\n ? colorize(\"⚙\", colors.success)\n : colorize(\"⚠\", colors.error);\n\n const timing = hook.durationMs !== undefined\n ? dim(` [${formatDuration(hook.durationMs)}]`)\n : \"\";\n\n let context = \"\";\n if (hook.type === \"shouldRun\" && hook.context?.skipped) {\n context = dim(\" → workflow skipped\");\n } else if (hook.type === \"shouldRun\" && hook.context?.result === true) {\n context = dim(\" → proceed\");\n } else if (hook.type === \"onBeforeStart\" && hook.context?.skipped) {\n context = dim(\" → workflow skipped\");\n } else if (hook.type === \"onAfterStep\" && hook.context?.stepKey) {\n context = dim(` (${hook.context.stepKey})`);\n }\n\n const error = hook.state === \"error\" && hook.error\n ? dim(` error: ${String(hook.error)}`)\n : \"\";\n\n return `${symbol} ${dim(label)}${context}${timing}${error}`;\n}\n\n/**\n * Render workflow hooks section.\n */\nfunction renderHooks(\n hooks: WorkflowHooks,\n colors: ReturnType<typeof Object.assign>\n): string[] {\n const lines: string[] = [];\n\n // Render shouldRun hook\n if (hooks.shouldRun) {\n lines.push(renderHookExecution(hooks.shouldRun, \"shouldRun\", colors));\n }\n\n // Render onBeforeStart hook\n if (hooks.onBeforeStart) {\n lines.push(renderHookExecution(hooks.onBeforeStart, \"onBeforeStart\", colors));\n }\n\n // We don't render onAfterStep hooks here - they're shown inline with steps\n // But if there are any, add a separator\n if (lines.length > 0) {\n lines.push(dim(\"────────────────────\")); // Separator between hooks and steps\n }\n\n return lines;\n}\n\n// =============================================================================\n// ASCII Renderer\n// =============================================================================\n\n/**\n * Create the ASCII terminal renderer.\n */\nexport function asciiRenderer(): Renderer {\n return {\n name: \"ascii\",\n supportsLive: true,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n const colors = { ...defaultColorScheme, ...options.colors };\n const width = options.terminalWidth ?? 60;\n const innerWidth = width - 4; // Account for borders\n\n const lines: string[] = [];\n\n // Header\n const workflowName = ir.root.name ?? \"workflow\";\n const headerTitle = bold(workflowName);\n lines.push(\n `${BOX.topLeft}${horizontalLine(width - 2, headerTitle)}${BOX.topRight}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n // Render hooks (if any)\n if (ir.hooks) {\n const hookLines = renderHooks(ir.hooks, colors);\n for (const line of hookLines) {\n lines.push(\n `${BOX.vertical} ${padEnd(line, innerWidth)}${BOX.vertical}`\n );\n }\n }\n\n // Render children\n const childLines = renderNodes(ir.root.children, options, colors, 0, ir.hooks);\n for (const line of childLines) {\n lines.push(\n `${BOX.vertical} ${padEnd(line, innerWidth)}${BOX.vertical}`\n );\n }\n\n // Footer with timing\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n if (ir.root.durationMs !== undefined && options.showTimings) {\n const status = ir.root.state === \"success\" ? \"Completed\" : \"Failed\";\n const statusColored = colorByState(status, ir.root.state, colors);\n const footer = `${statusColored} in ${formatDuration(ir.root.durationMs)}`;\n lines.push(\n `${BOX.vertical} ${padEnd(footer, innerWidth)}${BOX.vertical}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n }\n\n lines.push(\n `${BOX.bottomLeft}${BOX.horizontal.repeat(width - 2)}${BOX.bottomRight}`\n );\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render a list of nodes.\n */\nfunction renderNodes(\n nodes: FlowNode[],\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n\n for (const node of nodes) {\n if (isStepNode(node)) {\n lines.push(renderStepNode(node, options, colors, hooks));\n } else if (isParallelNode(node)) {\n lines.push(...renderParallelNode(node, options, colors, depth, hooks));\n } else if (isRaceNode(node)) {\n lines.push(...renderRaceNode(node, options, colors, depth, hooks));\n } else if (isDecisionNode(node)) {\n lines.push(...renderDecisionNode(node, options, colors, depth, hooks));\n }\n }\n\n return lines;\n}\n\n/**\n * Render a single step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n hooks?: WorkflowHooks\n): string {\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? node.key ?? \"step\";\n\n // Check for enhanced options\n const enhanced = options as EnhancedRenderOptions;\n const nodeId = node.name ?? node.id;\n\n // Get heat value for this node (if heatmap is enabled)\n const heat = enhanced.showHeatmap && enhanced.heatmapData\n ? enhanced.heatmapData.heat.get(node.id) ?? enhanced.heatmapData.heat.get(nodeId)\n : undefined;\n\n // Apply heat coloring or default state coloring\n let nameColored: string;\n if (heat !== undefined) {\n nameColored = applyHeatColor(name, heat);\n } else {\n nameColored = colorByState(name, node.state, colors);\n }\n\n let line = `${symbol} ${nameColored}`;\n\n // Add key if requested\n if (options.showKeys && node.key) {\n line += dim(` [key: ${node.key}]`);\n }\n\n // Add input/output if available (for decision understanding)\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\"\n ? node.input\n : JSON.stringify(node.input).slice(0, 30);\n line += dim(` [in: ${inputStr}${inputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? node.output\n : JSON.stringify(node.output).slice(0, 30);\n line += dim(` [out: ${outputStr}${outputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n\n // Add timing if available and requested\n if (options.showTimings && node.durationMs !== undefined) {\n // Apply heat coloring to timing if enabled\n const timingStr = formatDuration(node.durationMs);\n const timingDisplay = heat !== undefined\n ? applyHeatColor(`[${timingStr}]`, heat)\n : dim(`[${timingStr}]`);\n line += ` ${timingDisplay}`;\n }\n\n // Add sparkline if enabled and history available\n if (enhanced.showSparklines && enhanced.timingHistory) {\n const history = enhanced.timingHistory.get(nodeId);\n if (history && history.length > 1) {\n line += ` ${dim(renderSparkline(history))}`;\n }\n }\n\n // Add retry indicator if retries occurred\n if (node.retryCount !== undefined && node.retryCount > 0) {\n line += dim(` [${node.retryCount} ${node.retryCount === 1 ? \"retry\" : \"retries\"}]`);\n }\n\n // Add timeout indicator if step timed out\n if (node.timedOut) {\n const timeoutInfo = node.timeoutMs !== undefined ? ` ${node.timeoutMs}ms` : \"\";\n line += dim(` [timeout${timeoutInfo}]`);\n }\n\n // Add onAfterStep hook indicator if present\n if (hooks && node.key && hooks.onAfterStep.has(node.key)) {\n const hookExec = hooks.onAfterStep.get(node.key)!;\n const hookSymbol = hookExec.state === \"success\"\n ? colorize(\"⚙\", colors.success)\n : colorize(\"⚠\", colors.error);\n const hookTiming = hookExec.durationMs !== undefined\n ? dim(` ${formatDuration(hookExec.durationMs)}`)\n : \"\";\n line += ` ${hookSymbol}${hookTiming}`;\n }\n\n return line;\n}\n\n/**\n * Render a parallel node (allAsync).\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"parallel\";\n const mode = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n lines.push(`${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${mode}`);\n\n // Children\n if (node.children.length === 0) {\n // Empty parallel scope - operations inside allAsync/anyAsync weren't tracked as steps\n lines.push(`${indent}${BOX.vertical} ${dim(\"(operations not individually tracked)\")}`);\n lines.push(`${indent}${BOX.vertical} ${dim(\"(wrap each operation with step() to see individual steps)\")}`);\n } else {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors, hooks)}`);\n } else {\n // Nested structure - recurse\n const nestedLines = renderNodes([child], options, colors, depth + 1, hooks);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a race node (anyAsync).\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with lightning bolt for race\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"race\";\n lines.push(`${indent}${BOX.teeRight}⚡ ${symbol} ${bold(name)}`);\n\n // Children\n if (node.children.length === 0) {\n // Empty race scope - operations inside anyAsync weren't tracked as steps\n lines.push(`${indent}${BOX.vertical} ${dim(\"(operations not individually tracked)\")}`);\n lines.push(`${indent}${BOX.vertical} ${dim(\"(wrap each operation with step() to see individual steps)\")}`);\n } else {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Mark winner\n const isWinner = node.winnerId && child.id === node.winnerId;\n const winnerSuffix = isWinner ? dim(\" (winner)\") : \"\";\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors, hooks)}${winnerSuffix}`);\n } else {\n const nestedLines = renderNodes([child], options, colors, depth + 1, hooks);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a decision node (conditional branch).\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with decision info\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"decision\";\n const condition = node.condition\n ? dim(` (${node.condition})`)\n : \"\";\n const decisionValue = node.decisionValue !== undefined\n ? dim(` = ${String(node.decisionValue)}`)\n : \"\";\n const branchTaken = node.branchTaken !== undefined\n ? dim(` → ${String(node.branchTaken)}`)\n : \"\";\n\n lines.push(\n `${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${condition}${decisionValue}${branchTaken}`\n );\n\n // Render branches\n for (let i = 0; i < node.branches.length; i++) {\n const branch = node.branches[i];\n const isLast = i === node.branches.length - 1;\n const prefix = isLast\n ? `${indent}${BOX.vertical} ${BOX.bottomLeft}`\n : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Branch label with taken/skipped indicator\n const branchSymbol = branch.taken ? \"✓\" : \"⊘\";\n const branchColor = branch.taken ? colors.success : colors.skipped;\n const branchLabel = colorize(\n `${branchSymbol} ${branch.label}`,\n branchColor\n );\n const branchCondition = branch.condition\n ? dim(` (${branch.condition})`)\n : \"\";\n\n lines.push(`${prefix} ${branchLabel}${branchCondition}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n const childLines = renderNodes(branch.children, options, colors, depth + 1, hooks);\n for (const line of childLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n } else if (!branch.taken) {\n // Show that this branch was skipped\n lines.push(\n `${indent}${BOX.vertical} ${dim(\"(skipped)\")}`\n );\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(\n `${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`\n );\n }\n\n return lines;\n}\n\nexport { defaultColorScheme };\n","/**\n * Performance Analyzer\n *\n * Analyzes workflow execution data to identify:\n * - Slow steps (bottlenecks)\n * - Retry patterns\n * - Error-prone steps\n * - Timing anomalies\n *\n * Aggregates metrics across multiple workflow runs to provide\n * statistical insights and heatmap visualization data.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n NodePerformance,\n HeatmapData,\n WorkflowIR,\n FlowNode,\n HeatLevel,\n} from \"./types\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * A recorded workflow run for analysis.\n */\nexport interface WorkflowRun {\n /** Unique identifier for this run */\n id: string;\n /** Workflow start timestamp */\n startTime: number;\n /** All events from the workflow execution */\n events: WorkflowEvent<unknown>[];\n}\n\n/**\n * Performance analyzer interface.\n */\nexport interface PerformanceAnalyzer {\n /** Add a completed workflow run for analysis */\n addRun: (run: WorkflowRun) => void;\n\n /** Add events incrementally (alternative to addRun) */\n addEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Finalize current run (when using addEvent) */\n finalizeRun: (runId: string) => void;\n\n /** Get performance stats for a specific node */\n getNodePerformance: (nodeId: string) => NodePerformance | undefined;\n\n /** Get heatmap data for an IR */\n getHeatmap: (\n ir: WorkflowIR,\n metric?: \"duration\" | \"retryRate\" | \"errorRate\"\n ) => HeatmapData;\n\n /** Get slowest nodes */\n getSlowestNodes: (limit?: number) => NodePerformance[];\n\n /** Get error-prone nodes */\n getErrorProneNodes: (limit?: number) => NodePerformance[];\n\n /** Get retry-prone nodes */\n getRetryProneNodes: (limit?: number) => NodePerformance[];\n\n /** Get all performance data */\n getAllPerformance: () => Map<string, NodePerformance>;\n\n /** Export performance data as JSON */\n exportData: () => string;\n\n /** Import performance data from JSON */\n importData: (json: string) => void;\n\n /** Clear all collected data */\n clear: () => void;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Flatten all nodes from an IR tree.\n */\nfunction flattenNodes(nodes: FlowNode[]): FlowNode[] {\n const result: FlowNode[] = [];\n for (const node of nodes) {\n result.push(node);\n if (\"children\" in node && Array.isArray(node.children)) {\n result.push(...flattenNodes(node.children));\n }\n if (\"branches\" in node) {\n for (const branch of node.branches) {\n result.push(...flattenNodes(branch.children));\n }\n }\n }\n return result;\n}\n\n/**\n * Calculate percentile value from sorted array.\n */\nfunction percentile(sortedValues: number[], p: number): number {\n if (sortedValues.length === 0) return 0;\n const index = Math.floor(sortedValues.length * p);\n return sortedValues[Math.min(index, sortedValues.length - 1)];\n}\n\n/**\n * Get heat level from normalized value (0-1).\n */\nexport function getHeatLevel(heat: number): HeatLevel {\n if (heat < 0.2) return \"cold\";\n if (heat < 0.4) return \"cool\";\n if (heat < 0.6) return \"neutral\";\n if (heat < 0.8) return \"warm\";\n if (heat < 0.95) return \"hot\";\n return \"critical\";\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Create a performance analyzer for workflow metrics.\n *\n * @example\n * ```typescript\n * const analyzer = createPerformanceAnalyzer();\n *\n * // Add completed runs\n * analyzer.addRun({ id: 'run-1', startTime: Date.now(), events });\n *\n * // Get insights\n * const slowest = analyzer.getSlowestNodes(5);\n * const heatmap = analyzer.getHeatmap(ir, 'duration');\n * ```\n */\nexport function createPerformanceAnalyzer(): PerformanceAnalyzer {\n // Timing data: nodeId → array of durations (ms)\n const timingData = new Map<string, number[]>();\n\n // Retry data: nodeId → { retried runs, total runs }\n const retryData = new Map<string, { retried: number; total: number }>();\n\n // Error data: nodeId → { error runs, total runs }\n const errorData = new Map<string, { errors: number; total: number }>();\n\n // Timeout data: nodeId → { timed out, total }\n const timeoutData = new Map<string, { timedOut: number; total: number }>();\n\n // Current run state (for incremental event adding)\n let currentRunEvents: WorkflowEvent<unknown>[] = [];\n\n /**\n * Get node ID from event (uses name or stepId).\n */\n function getNodeId(event: {\n stepId?: string;\n stepKey?: string;\n name?: string;\n }): string {\n return event.name ?? event.stepKey ?? event.stepId ?? \"unknown\";\n }\n\n /**\n * Process events from a workflow run.\n */\n function processEvents(events: WorkflowEvent<unknown>[]): void {\n // Track step state during processing\n const stepState = new Map<\n string,\n {\n retried: boolean;\n timedOut: boolean;\n }\n >();\n\n for (const event of events) {\n switch (event.type) {\n case \"step_start\": {\n const id = getNodeId(event);\n stepState.set(id, { retried: false, timedOut: false });\n break;\n }\n\n case \"step_retry\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n if (state) {\n state.retried = true;\n }\n break;\n }\n\n case \"step_timeout\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n if (state) {\n state.timedOut = true;\n }\n // Track timeout stats\n const timeout = timeoutData.get(id) ?? { timedOut: 0, total: 0 };\n timeout.timedOut++;\n timeout.total++;\n timeoutData.set(id, timeout);\n break;\n }\n\n case \"step_success\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n\n // Record timing\n const timings = timingData.get(id) ?? [];\n timings.push(event.durationMs);\n timingData.set(id, timings);\n\n // Record retry status\n const retry = retryData.get(id) ?? { retried: 0, total: 0 };\n retry.total++;\n if (state?.retried) retry.retried++;\n retryData.set(id, retry);\n\n // Record success (no error)\n const error = errorData.get(id) ?? { errors: 0, total: 0 };\n error.total++;\n errorData.set(id, error);\n\n stepState.delete(id);\n break;\n }\n\n case \"step_error\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n\n // Record timing\n const timings = timingData.get(id) ?? [];\n timings.push(event.durationMs);\n timingData.set(id, timings);\n\n // Record retry status\n const retry = retryData.get(id) ?? { retried: 0, total: 0 };\n retry.total++;\n if (state?.retried) retry.retried++;\n retryData.set(id, retry);\n\n // Record error\n const error = errorData.get(id) ?? { errors: 0, total: 0 };\n error.total++;\n error.errors++;\n errorData.set(id, error);\n\n stepState.delete(id);\n break;\n }\n }\n }\n }\n\n /**\n * Add a completed workflow run.\n */\n function addRun(run: WorkflowRun): void {\n processEvents(run.events);\n }\n\n /**\n * Add an event incrementally.\n */\n function addEvent(event: WorkflowEvent<unknown>): void {\n currentRunEvents.push(event);\n }\n\n /**\n * Finalize current run (process accumulated events).\n */\n function finalizeRun(_runId: string): void {\n if (currentRunEvents.length > 0) {\n processEvents(currentRunEvents);\n currentRunEvents = [];\n }\n }\n\n /**\n * Compute performance metrics for a node.\n */\n function computePerformance(nodeId: string): NodePerformance | undefined {\n const timings = timingData.get(nodeId);\n if (!timings || timings.length === 0) return undefined;\n\n const sorted = [...timings].sort((a, b) => a - b);\n const sum = sorted.reduce((a, b) => a + b, 0);\n const mean = sum / sorted.length;\n const variance =\n sorted.reduce((acc, t) => acc + (t - mean) ** 2, 0) / sorted.length;\n\n const retry = retryData.get(nodeId) ?? { retried: 0, total: 1 };\n const error = errorData.get(nodeId) ?? { errors: 0, total: 1 };\n const timeout = timeoutData.get(nodeId) ?? { timedOut: 0, total: 1 };\n\n return {\n nodeId,\n avgDurationMs: mean,\n minDurationMs: sorted[0],\n maxDurationMs: sorted[sorted.length - 1],\n stdDevMs: Math.sqrt(variance),\n samples: sorted.length,\n retryRate: retry.total > 0 ? retry.retried / retry.total : 0,\n timeoutRate: timeout.total > 0 ? timeout.timedOut / timeout.total : 0,\n errorRate: error.total > 0 ? error.errors / error.total : 0,\n percentiles: {\n p50: percentile(sorted, 0.5),\n p90: percentile(sorted, 0.9),\n p95: percentile(sorted, 0.95),\n p99: percentile(sorted, 0.99),\n },\n };\n }\n\n /**\n * Get performance stats for a specific node.\n */\n function getNodePerformance(nodeId: string): NodePerformance | undefined {\n return computePerformance(nodeId);\n }\n\n /**\n * Get heatmap data for an IR.\n */\n function getHeatmap(\n ir: WorkflowIR,\n metric: \"duration\" | \"retryRate\" | \"errorRate\" = \"duration\"\n ): HeatmapData {\n const heat = new Map<string, number>();\n const allNodes = flattenNodes(ir.root.children);\n\n // Compute values for all nodes\n const values: Array<{ id: string; value: number }> = [];\n for (const node of allNodes) {\n // Try node.name first, then node.id\n const nodeId = node.name ?? node.id;\n const perf = computePerformance(nodeId);\n if (perf) {\n let value: number;\n switch (metric) {\n case \"duration\":\n value = perf.avgDurationMs;\n break;\n case \"retryRate\":\n value = perf.retryRate;\n break;\n case \"errorRate\":\n value = perf.errorRate;\n break;\n }\n values.push({ id: node.id, value });\n }\n }\n\n if (values.length === 0) {\n return {\n heat,\n metric,\n stats: { min: 0, max: 0, mean: 0, threshold: 0 },\n };\n }\n\n // Compute statistics\n const vals = values.map((v) => v.value);\n const min = Math.min(...vals);\n const max = Math.max(...vals);\n const mean = vals.reduce((a, b) => a + b, 0) / vals.length;\n const range = max - min || 1;\n\n // Normalize to 0-1 heat values\n for (const { id, value } of values) {\n heat.set(id, (value - min) / range);\n }\n\n return {\n heat,\n metric,\n stats: {\n min,\n max,\n mean,\n threshold: mean + (max - mean) * 0.5, // 50% above mean is \"hot\"\n },\n };\n }\n\n /**\n * Get all performance data.\n */\n function getAllPerformance(): Map<string, NodePerformance> {\n const result = new Map<string, NodePerformance>();\n for (const nodeId of timingData.keys()) {\n const perf = computePerformance(nodeId);\n if (perf) result.set(nodeId, perf);\n }\n return result;\n }\n\n /**\n * Get slowest nodes by average duration.\n */\n function getSlowestNodes(limit = 10): NodePerformance[] {\n const all = getAllPerformance();\n return [...all.values()]\n .sort((a, b) => b.avgDurationMs - a.avgDurationMs)\n .slice(0, limit);\n }\n\n /**\n * Get error-prone nodes by error rate.\n */\n function getErrorProneNodes(limit = 10): NodePerformance[] {\n const all = getAllPerformance();\n return [...all.values()]\n .filter((p) => p.errorRate > 0)\n .sort((a, b) => b.errorRate - a.errorRate)\n .slice(0, limit);\n }\n\n /**\n * Get retry-prone nodes by retry rate.\n */\n function getRetryProneNodes(limit = 10): NodePerformance[] {\n const all = getAllPerformance();\n return [...all.values()]\n .filter((p) => p.retryRate > 0)\n .sort((a, b) => b.retryRate - a.retryRate)\n .slice(0, limit);\n }\n\n /**\n * Export performance data as JSON.\n */\n function exportData(): string {\n return JSON.stringify({\n timingData: Object.fromEntries(timingData),\n retryData: Object.fromEntries(retryData),\n errorData: Object.fromEntries(errorData),\n timeoutData: Object.fromEntries(timeoutData),\n });\n }\n\n /**\n * Import performance data from JSON.\n */\n function importData(json: string): void {\n const data = JSON.parse(json) as {\n timingData?: Record<string, number[]>;\n retryData?: Record<string, { retried: number; total: number }>;\n errorData?: Record<string, { errors: number; total: number }>;\n timeoutData?: Record<string, { timedOut: number; total: number }>;\n };\n\n // Clear existing data\n timingData.clear();\n retryData.clear();\n errorData.clear();\n timeoutData.clear();\n\n // Import timing data\n for (const [k, v] of Object.entries(data.timingData ?? {})) {\n timingData.set(k, v);\n }\n\n // Import retry data\n for (const [k, v] of Object.entries(data.retryData ?? {})) {\n retryData.set(k, v);\n }\n\n // Import error data\n for (const [k, v] of Object.entries(data.errorData ?? {})) {\n errorData.set(k, v);\n }\n\n // Import timeout data\n for (const [k, v] of Object.entries(data.timeoutData ?? {})) {\n timeoutData.set(k, v);\n }\n }\n\n /**\n * Clear all collected data.\n */\n function clear(): void {\n timingData.clear();\n retryData.clear();\n errorData.clear();\n timeoutData.clear();\n currentRunEvents = [];\n }\n\n return {\n addRun,\n addEvent,\n finalizeRun,\n getNodePerformance,\n getHeatmap,\n getSlowestNodes,\n getErrorProneNodes,\n getRetryProneNodes,\n getAllPerformance,\n exportData,\n importData,\n clear,\n };\n}\n","/**\n * Mermaid Diagram Renderer\n *\n * Renders the workflow IR as a Mermaid flowchart diagram.\n * Supports sequential flows, parallel (subgraph), and race patterns.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n MermaidRenderOptions,\n StepNode,\n StepState,\n WorkflowIR,\n EnhancedRenderOptions,\n HeatLevel,\n WorkflowHooks,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\nimport { getHeatLevel } from \"../performance-analyzer\";\n\n// =============================================================================\n// Mermaid Style Definitions\n// =============================================================================\n\n/**\n * Get Mermaid class definition for step states.\n * Colors inspired by AWS Step Functions and XState visualizers for professional appearance.\n */\nfunction getStyleDefinitions(): string[] {\n return [\n // Pending - light gray, subtle\n \" classDef pending fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#374151\",\n // Running - amber/yellow, indicates active execution\n \" classDef running fill:#fef3c7,stroke:#f59e0b,stroke-width:3px,color:#92400e\",\n // Success - green, clear positive indicator\n \" classDef success fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#065f46\",\n // Error - red, clear negative indicator\n \" classDef error fill:#fee2e2,stroke:#ef4444,stroke-width:3px,color:#991b1b\",\n // Aborted - gray, indicates cancellation\n \" classDef aborted fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#4b5563,stroke-dasharray: 5 5\",\n // Cached - blue, indicates cache hit\n \" classDef cached fill:#dbeafe,stroke:#3b82f6,stroke-width:3px,color:#1e40af\",\n // Skipped - light gray with dashed border\n \" classDef skipped fill:#f9fafb,stroke:#d1d5db,stroke-width:2px,color:#6b7280,stroke-dasharray: 5 5\",\n ];\n}\n\n/**\n * Get Mermaid class definitions for heatmap visualization.\n */\nfunction getHeatmapStyleDefinitions(): string[] {\n return [\n // Heatmap colors - cold to hot\n \" classDef heat_cold fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e40af\",\n \" classDef heat_cool fill:#ccfbf1,stroke:#14b8a6,stroke-width:2px,color:#0f766e\",\n \" classDef heat_neutral fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#374151\",\n \" classDef heat_warm fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e\",\n \" classDef heat_hot fill:#fed7aa,stroke:#f97316,stroke-width:3px,color:#c2410c\",\n \" classDef heat_critical fill:#fecaca,stroke:#ef4444,stroke-width:3px,color:#b91c1c\",\n ];\n}\n\n/**\n * Get the Mermaid class name for a heat level.\n */\nfunction getHeatClass(level: HeatLevel): string {\n return `heat_${level}`;\n}\n\n/**\n * Get the Mermaid class name for a step state.\n */\nfunction getStateClass(state: StepState): string {\n return state;\n}\n\n/**\n * Get Mermaid class definitions for hook visualization.\n */\nfunction getHookStyleDefinitions(): string[] {\n return [\n // Hook styles - gear icon aesthetic\n \" classDef hook_success fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e\",\n \" classDef hook_error fill:#fef2f2,stroke:#dc2626,stroke-width:2px,color:#7f1d1d\",\n ];\n}\n\n/**\n * Render hooks as nodes before the workflow starts.\n * Returns the ID of the last hook node (to connect to workflow start).\n */\nfunction renderHooks(\n hooks: WorkflowHooks,\n lines: string[],\n options: RenderOptions\n): { lastHookId: string | undefined } {\n let lastHookId: string | undefined;\n\n // Render shouldRun hook\n if (hooks.shouldRun) {\n const hookId = \"hook_shouldRun\";\n const state = hooks.shouldRun.state === \"success\" ? \"hook_success\" : \"hook_error\";\n const icon = hooks.shouldRun.state === \"success\" ? \"⚙\" : \"⚠\";\n const timing = options.showTimings && hooks.shouldRun.durationMs !== undefined\n ? ` ${formatDuration(hooks.shouldRun.durationMs)}`\n : \"\";\n const context = hooks.shouldRun.context?.skipped\n ? \"\\\\nskipped workflow\"\n : hooks.shouldRun.context?.result === true\n ? \"\\\\nproceed\"\n : \"\";\n\n lines.push(` ${hookId}[[\"${icon} shouldRun${context}${timing}\"]]:::${state}`);\n lastHookId = hookId;\n }\n\n // Render onBeforeStart hook\n if (hooks.onBeforeStart) {\n const hookId = \"hook_beforeStart\";\n const state = hooks.onBeforeStart.state === \"success\" ? \"hook_success\" : \"hook_error\";\n const icon = hooks.onBeforeStart.state === \"success\" ? \"⚙\" : \"⚠\";\n const timing = options.showTimings && hooks.onBeforeStart.durationMs !== undefined\n ? ` ${formatDuration(hooks.onBeforeStart.durationMs)}`\n : \"\";\n const context = hooks.onBeforeStart.context?.skipped\n ? \"\\\\nskipped workflow\"\n : \"\";\n\n lines.push(` ${hookId}[[\"${icon} onBeforeStart${context}${timing}\"]]:::${state}`);\n\n // Connect from previous hook if exists\n if (lastHookId) {\n lines.push(` ${lastHookId} --> ${hookId}`);\n }\n lastHookId = hookId;\n }\n\n return { lastHookId };\n}\n\n// =============================================================================\n// Node ID Generation\n// =============================================================================\n\nlet nodeCounter = 0;\n\nfunction generateNodeId(prefix: string = \"node\"): string {\n return `${prefix}_${++nodeCounter}`;\n}\n\nfunction resetNodeCounter(): void {\n nodeCounter = 0;\n}\n\n// =============================================================================\n// Mermaid Text Escaping\n// =============================================================================\n\n/**\n * Escape text for use in Mermaid diagrams.\n * Removes characters that break Mermaid parsing.\n * \n * Characters removed:\n * - {}[]() - Brackets and parentheses break parsing in labels\n * - <> - Angle brackets can cause issues\n * - \" - Double quotes replaced with single quotes\n * \n * @param text - Text to escape\n * @returns Escaped text safe for Mermaid\n */\nfunction escapeMermaidText(text: string): string {\n return text\n .replace(/[{}[\\]()]/g, \"\") // Remove brackets and parentheses (they break parsing)\n .replace(/[<>]/g, \"\") // Remove angle brackets\n .replace(/\"/g, \"'\") // Replace double quotes with single\n .trim();\n}\n\n/**\n * Escape text for use in Mermaid subgraph names.\n * Subgraph names in brackets need special handling.\n * \n * @param text - Text to escape for subgraph name\n * @returns Escaped text safe for subgraph names\n */\nfunction escapeSubgraphName(text: string): string {\n return escapeMermaidText(text)\n .replace(/[[\\]]/g, \"\"); // Also remove brackets from subgraph names\n}\n\n// =============================================================================\n// Mermaid Renderer\n// =============================================================================\n\n/**\n * Create the Mermaid diagram renderer.\n */\nexport function mermaidRenderer(): Renderer {\n return {\n name: \"mermaid\",\n supportsLive: false,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n resetNodeCounter();\n const lines: string[] = [];\n\n // Check for enhanced options (heatmap)\n const enhanced = options as EnhancedRenderOptions;\n\n // Diagram header\n lines.push(\"flowchart TD\");\n\n // Render hooks first (if any)\n let hookExitId: string | undefined;\n if (ir.hooks) {\n const hookResult = renderHooks(ir.hooks, lines, options);\n hookExitId = hookResult.lastHookId;\n }\n\n // Start node - more visually distinctive\n const startId = \"start\";\n lines.push(` ${startId}((\"▶ Start\"))`);\n\n // Connect hooks to start node\n if (hookExitId) {\n lines.push(` ${hookExitId} --> ${startId}`);\n }\n\n // Track the last node for connections\n let prevNodeId = startId;\n\n // Render children (passing hooks for onAfterStep annotations)\n for (const child of ir.root.children) {\n const result = renderNode(child, options, lines, enhanced, ir.hooks);\n lines.push(` ${prevNodeId} --> ${result.entryId}`);\n prevNodeId = result.exitId;\n }\n\n // End node (if workflow completed) - more visually distinctive\n if (ir.root.state === \"success\" || ir.root.state === \"error\") {\n const endId = \"finish\";\n const endIcon = ir.root.state === \"success\" ? \"✓\" : \"✗\";\n const endLabel = ir.root.state === \"success\" ? \"Done\" : \"Failed\";\n const endShape = `((\"${endIcon} ${endLabel}\"))`;\n const endClass =\n ir.root.state === \"success\" ? \":::success\" : \":::error\";\n lines.push(` ${endId}${endShape}${endClass}`);\n lines.push(` ${prevNodeId} --> ${endId}`);\n }\n\n // Add style definitions\n lines.push(\"\");\n lines.push(...getStyleDefinitions());\n\n // Add heatmap styles if enabled\n if (enhanced.showHeatmap) {\n lines.push(...getHeatmapStyleDefinitions());\n }\n\n // Add hook styles if hooks were rendered\n if (ir.hooks) {\n lines.push(...getHookStyleDefinitions());\n }\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render result with entry and exit node IDs.\n */\ninterface RenderResult {\n entryId: string;\n exitId: string;\n}\n\n/**\n * Render a node and return its entry/exit IDs.\n */\nfunction renderNode(\n node: FlowNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n if (isStepNode(node)) {\n return renderStepNode(node, options, lines, enhanced, hooks);\n } else if (isParallelNode(node)) {\n return renderParallelNode(node, options, lines, enhanced, hooks);\n } else if (isRaceNode(node)) {\n return renderRaceNode(node, options, lines, enhanced, hooks);\n } else if (isDecisionNode(node)) {\n return renderDecisionNode(node, options, lines, enhanced, hooks);\n }\n\n // Fallback for sequence or unknown nodes\n const id = generateNodeId(\"unknown\");\n lines.push(` ${id}[Unknown Node]`);\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n // Cast to MermaidRenderOptions to access extended options\n const mermaidOpts = options as MermaidRenderOptions;\n const showRetryEdges = mermaidOpts.showRetryEdges ?? true;\n const showErrorEdges = mermaidOpts.showErrorEdges ?? true;\n const showTimeoutEdges = mermaidOpts.showTimeoutEdges ?? true;\n\n const id = node.key\n ? `step_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"step\");\n\n const label = escapeMermaidText(node.name ?? node.key ?? \"Step\");\n\n // Format timing - use space instead of parentheses to avoid Mermaid parse errors\n const timing =\n options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n\n // Add visual indicators based on state (like XState/AWS Step Functions)\n let stateIcon = \"\";\n switch (node.state) {\n case \"success\":\n stateIcon = \"✓ \";\n break;\n case \"error\":\n stateIcon = \"✗ \";\n break;\n case \"cached\":\n stateIcon = \"💾 \";\n break;\n case \"running\":\n stateIcon = \"⏳ \";\n break;\n case \"skipped\":\n stateIcon = \"⊘ \";\n break;\n }\n\n // Add input/output info if available\n // Use newlines for multi-line labels, but escape special characters\n let ioInfo = \"\";\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\"\n ? escapeMermaidText(node.input)\n : escapeMermaidText(JSON.stringify(node.input).slice(0, 20));\n ioInfo += `\\\\nin: ${inputStr}`;\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? escapeMermaidText(node.output)\n : escapeMermaidText(JSON.stringify(node.output).slice(0, 20));\n ioInfo += `\\\\nout: ${outputStr}`;\n }\n\n // Add onAfterStep hook info if present\n let hookInfo = \"\";\n if (hooks && node.key && hooks.onAfterStep.has(node.key)) {\n const hookExec = hooks.onAfterStep.get(node.key)!;\n const hookIcon = hookExec.state === \"success\" ? \"⚙\" : \"⚠\";\n const hookTiming = options.showTimings && hookExec.durationMs !== undefined\n ? ` ${formatDuration(hookExec.durationMs)}`\n : \"\";\n hookInfo = `\\\\n${hookIcon} hook${hookTiming}`;\n }\n\n // Combine all label parts with icon (retry/timeout info moved to edges)\n const escapedLabel = (stateIcon + label + ioInfo + hookInfo + timing).trim();\n\n // Determine class: use heatmap if enabled and data available, otherwise use state\n let nodeClass: string;\n const nodeId = node.name ?? node.id;\n const heat = enhanced?.showHeatmap && enhanced.heatmapData\n ? enhanced.heatmapData.heat.get(node.id) ?? enhanced.heatmapData.heat.get(nodeId)\n : undefined;\n\n if (heat !== undefined) {\n const level = getHeatLevel(heat);\n nodeClass = getHeatClass(level);\n } else {\n nodeClass = getStateClass(node.state);\n }\n\n // Use different shapes based on state (like AWS Step Functions)\n let shape: string;\n switch (node.state) {\n case \"error\":\n // Hexagon for errors (more distinctive)\n shape = `{{${escapedLabel}}}`;\n break;\n case \"cached\":\n // Rounded rectangle with double border for cached\n shape = `[(${escapedLabel})]`;\n break;\n case \"skipped\":\n // Dashed border for skipped\n shape = `[${escapedLabel}]:::skipped`;\n break;\n default:\n // Standard rectangle for normal steps\n shape = `[${escapedLabel}]`;\n }\n\n lines.push(` ${id}${shape}:::${nodeClass}`);\n\n // NEW: Add retry loop edge (self-loop showing retries)\n if (showRetryEdges && node.retryCount !== undefined && node.retryCount > 0) {\n const retryLabel = `↻ ${node.retryCount} retr${node.retryCount === 1 ? \"y\" : \"ies\"}`;\n lines.push(` ${id} -.->|\"${retryLabel}\"| ${id}`);\n }\n\n // NEW: Add error path edge (flow to error node)\n if (showErrorEdges && node.state === \"error\" && node.error !== undefined) {\n const errorNodeId = `ERR_${id}`;\n const errorLabel = escapeMermaidText(String(node.error)).slice(0, 30);\n lines.push(` ${errorNodeId}{{${errorLabel}}}`);\n lines.push(` ${id} -->|error| ${errorNodeId}`);\n lines.push(` style ${errorNodeId} fill:#fee2e2,stroke:#dc2626`);\n }\n\n // NEW: Add timeout edge (alternative timeout path)\n if (showTimeoutEdges && node.timedOut) {\n const timeoutNodeId = `TO_${id}`;\n const timeoutMs = node.timeoutMs !== undefined ? `${node.timeoutMs}ms` : \"\";\n lines.push(` ${timeoutNodeId}{{⏱ Timeout ${timeoutMs}}}`);\n lines.push(` ${id} -.->|timeout| ${timeoutNodeId}`);\n lines.push(` style ${timeoutNodeId} fill:#fef3c7,stroke:#f59e0b`);\n }\n\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a parallel node as a subgraph with fork/join.\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n const subgraphId = generateNodeId(\"parallel\");\n const forkId = `${subgraphId}_fork`;\n const joinId = `${subgraphId}_join`;\n const name = escapeSubgraphName(node.name ?? \"Parallel\");\n const modeLabel = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n\n // If no children, render as a simple step-like node with note\n if (node.children.length === 0) {\n const id = subgraphId;\n const label = escapeMermaidText(`${name}${modeLabel}`);\n const note = \"operations not individually tracked\";\n const timing = options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n \n // Use a rounded rectangle to indicate it's a parallel operation\n lines.push(` ${id}[${label}${timing}\\\\n${note}]:::${getStateClass(node.state)}`);\n return { entryId: id, exitId: id };\n }\n\n // Subgraph for parallel block with proper visual hierarchy\n lines.push(` subgraph ${subgraphId}[\"${name}${modeLabel}\"]`);\n lines.push(` direction TB`);\n\n // Fork node (diamond) - more visually distinct\n lines.push(` ${forkId}{\"⚡ Fork\"}`);\n\n // Child branches - render in parallel columns\n const childExitIds: string[] = [];\n for (const child of node.children) {\n const result = renderNode(child, options, lines, enhanced, hooks);\n lines.push(` ${forkId} --> ${result.entryId}`);\n childExitIds.push(result.exitId);\n }\n\n // Join node (diamond) - visually distinct\n lines.push(` ${joinId}{\"✓ Join\"}`);\n for (const exitId of childExitIds) {\n lines.push(` ${exitId} --> ${joinId}`);\n }\n\n lines.push(` end`);\n\n // Apply state styling to subgraph\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: forkId, exitId: joinId };\n}\n\n/**\n * Render a race node as a subgraph with racing indicator.\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n const subgraphId = generateNodeId(\"race\");\n const startId = `${subgraphId}_start`;\n const endId = `${subgraphId}_end`;\n const name = escapeSubgraphName(node.name ?? \"Race\");\n\n // If no children, render as a simple step-like node with note\n if (node.children.length === 0) {\n const id = subgraphId;\n const label = escapeMermaidText(name);\n const note = \"operations not individually tracked\";\n const timing = options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n \n lines.push(` ${id}[⚡ ${label}${timing}\\\\n${note}]:::${getStateClass(node.state)}`);\n return { entryId: id, exitId: id };\n }\n\n // Subgraph for race block - escape name and emoji is safe in quoted strings\n lines.push(` subgraph ${subgraphId}[\"⚡ ${name}\"]`);\n lines.push(` direction TB`);\n\n // Start node - use a more distinctive shape\n lines.push(` ${startId}((\"🏁 Start\"))`);\n\n // Child branches\n const childExitIds: Array<{ exitId: string; isWinner: boolean }> = [];\n let winnerExitId: string | undefined;\n\n for (const child of node.children) {\n const result = renderNode(child, options, lines, enhanced, hooks);\n const isWinner = isStepNode(child) && node.winnerId === child.id;\n lines.push(` ${startId} --> ${result.entryId}`);\n\n if (isWinner) {\n winnerExitId = result.exitId;\n }\n childExitIds.push({ exitId: result.exitId, isWinner });\n }\n\n // End node - more distinctive\n lines.push(` ${endId}((\"✓ First\"))`);\n \n // Connect winner with thick line, others with dashed (cancelled)\n for (const { exitId, isWinner } of childExitIds) {\n if (isWinner && winnerExitId) {\n lines.push(` ${exitId} ==>|🏆 Winner| ${endId}`);\n } else if (node.winnerId) {\n // Non-winner: show as cancelled\n lines.push(` ${exitId} -. cancelled .-> ${endId}`);\n } else {\n // No winner determined, normal connection\n lines.push(` ${exitId} --> ${endId}`);\n }\n }\n\n lines.push(` end`);\n\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: startId, exitId: endId };\n}\n\n/**\n * Render a decision node as a diamond with branches.\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n const decisionId = node.key\n ? `decision_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"decision\");\n\n // Escape condition and decision value - remove characters that break Mermaid\n const condition = escapeMermaidText(node.condition ?? \"condition\");\n const decisionValue = node.decisionValue !== undefined\n ? ` = ${escapeMermaidText(String(node.decisionValue)).slice(0, 30)}`\n : \"\";\n\n // Decision diamond - ensure no invalid characters\n const decisionLabel = `${condition}${decisionValue}`.trim();\n lines.push(` ${decisionId}{${decisionLabel}}`);\n\n // Render branches\n const branchExitIds: string[] = [];\n let takenBranchExitId: string | undefined;\n\n for (const branch of node.branches) {\n const branchId = `${decisionId}_${branch.label.replace(/[^a-zA-Z0-9]/g, \"_\")}`;\n // Escape branch label - remove parentheses and other special chars\n const branchLabelText = escapeMermaidText(branch.label);\n const branchLabel = branch.taken\n ? `${branchLabelText} ✓`\n : `${branchLabelText} skipped`;\n const branchClass = branch.taken ? \":::success\" : \":::skipped\";\n\n // Branch label node\n lines.push(` ${branchId}[${branchLabel}]${branchClass}`);\n\n // Connect decision to branch\n // Mermaid edge labels must be simple text - escape special characters\n // Also remove pipe character as it's used for edge label syntax\n const edgeLabel = branch.condition \n ? `|${escapeMermaidText(branch.condition).replace(/\\|/g, \"\")}|` \n : \"\";\n lines.push(` ${decisionId} -->${edgeLabel} ${branchId}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n let prevId = branchId;\n for (const child of branch.children) {\n const result = renderNode(child, options, lines, enhanced, hooks);\n lines.push(` ${prevId} --> ${result.entryId}`);\n prevId = result.exitId;\n }\n branchExitIds.push(prevId);\n if (branch.taken) {\n takenBranchExitId = prevId;\n }\n } else {\n branchExitIds.push(branchId);\n if (branch.taken) {\n takenBranchExitId = branchId;\n }\n }\n }\n\n // Join point (if we have a taken branch)\n if (takenBranchExitId) {\n return { entryId: decisionId, exitId: takenBranchExitId };\n }\n\n // If no branch was taken, return decision as exit\n return { entryId: decisionId, exitId: decisionId };\n}\n\nexport { mermaidRenderer as default };\n","/**\n * HTML Visualizer Styles\n *\n * CSS styles for the interactive HTML workflow visualizer.\n * Supports light, dark, and auto (system preference) themes.\n */\n\n/**\n * Generate CSS styles for the HTML visualizer.\n */\nexport function generateStyles(theme: \"light\" | \"dark\" | \"auto\"): string {\n const lightColors = {\n bg: \"#ffffff\",\n bgSecondary: \"#f8f9fa\",\n text: \"#212529\",\n textMuted: \"#6c757d\",\n border: \"#dee2e6\",\n primary: \"#0d6efd\",\n success: \"#198754\",\n error: \"#dc3545\",\n warning: \"#ffc107\",\n info: \"#0dcaf0\",\n muted: \"#6c757d\",\n // Node colors\n nodePending: \"#e9ecef\",\n nodeRunning: \"#fff3cd\",\n nodeSuccess: \"#d1e7dd\",\n nodeError: \"#f8d7da\",\n nodeAborted: \"#e9ecef\",\n nodeCached: \"#cfe2ff\",\n nodeSkipped: \"#f8f9fa\",\n // Heatmap colors\n heatCold: \"#0d6efd\",\n heatCool: \"#0dcaf0\",\n heatNeutral: \"#6c757d\",\n heatWarm: \"#ffc107\",\n heatHot: \"#fd7e14\",\n heatCritical: \"#dc3545\",\n };\n\n const darkColors = {\n bg: \"#212529\",\n bgSecondary: \"#343a40\",\n text: \"#f8f9fa\",\n textMuted: \"#adb5bd\",\n border: \"#495057\",\n primary: \"#0d6efd\",\n success: \"#198754\",\n error: \"#dc3545\",\n warning: \"#ffc107\",\n info: \"#0dcaf0\",\n muted: \"#6c757d\",\n // Node colors\n nodePending: \"#495057\",\n nodeRunning: \"#664d03\",\n nodeSuccess: \"#0f5132\",\n nodeError: \"#842029\",\n nodeAborted: \"#495057\",\n nodeCached: \"#084298\",\n nodeSkipped: \"#343a40\",\n // Heatmap colors\n heatCold: \"#0d6efd\",\n heatCool: \"#0dcaf0\",\n heatNeutral: \"#6c757d\",\n heatWarm: \"#ffc107\",\n heatHot: \"#fd7e14\",\n heatCritical: \"#dc3545\",\n };\n\n const generateThemeVars = (colors: typeof lightColors) => `\n --bg: ${colors.bg};\n --bg-secondary: ${colors.bgSecondary};\n --text: ${colors.text};\n --text-muted: ${colors.textMuted};\n --border: ${colors.border};\n --primary: ${colors.primary};\n --success: ${colors.success};\n --error: ${colors.error};\n --warning: ${colors.warning};\n --info: ${colors.info};\n --muted: ${colors.muted};\n --node-pending: ${colors.nodePending};\n --node-running: ${colors.nodeRunning};\n --node-success: ${colors.nodeSuccess};\n --node-error: ${colors.nodeError};\n --node-aborted: ${colors.nodeAborted};\n --node-cached: ${colors.nodeCached};\n --node-skipped: ${colors.nodeSkipped};\n --heat-cold: ${colors.heatCold};\n --heat-cool: ${colors.heatCool};\n --heat-neutral: ${colors.heatNeutral};\n --heat-warm: ${colors.heatWarm};\n --heat-hot: ${colors.heatHot};\n --heat-critical: ${colors.heatCritical};\n `;\n\n let themeCSS: string;\n\n if (theme === \"auto\") {\n themeCSS = `\n :root {\n ${generateThemeVars(lightColors)}\n }\n @media (prefers-color-scheme: dark) {\n :root {\n ${generateThemeVars(darkColors)}\n }\n }\n `;\n } else if (theme === \"dark\") {\n themeCSS = `\n :root {\n ${generateThemeVars(darkColors)}\n }\n `;\n } else {\n themeCSS = `\n :root {\n ${generateThemeVars(lightColors)}\n }\n `;\n }\n\n return `\n${themeCSS}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n background-color: var(--bg);\n color: var(--text);\n line-height: 1.5;\n}\n\n.workflow-visualizer {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n}\n\n/* Header */\n.wv-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n background-color: var(--bg-secondary);\n border-bottom: 1px solid var(--border);\n}\n\n.wv-header h1 {\n font-size: 1.25rem;\n font-weight: 600;\n}\n\n.wv-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.wv-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 6px 12px;\n font-size: 0.875rem;\n font-weight: 500;\n border: 1px solid var(--border);\n border-radius: 6px;\n background-color: var(--bg);\n color: var(--text);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.wv-btn:hover {\n background-color: var(--bg-secondary);\n}\n\n.wv-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.wv-btn--primary {\n background-color: var(--primary);\n border-color: var(--primary);\n color: white;\n}\n\n.wv-btn--primary:hover {\n opacity: 0.9;\n}\n\n.wv-btn--icon {\n padding: 6px;\n min-width: 32px;\n}\n\n/* Main content area */\n.wv-main {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n\n/* Diagram container */\n.wv-diagram {\n flex: 1;\n position: relative;\n overflow: hidden;\n background-color: var(--bg);\n background-image:\n radial-gradient(circle, var(--border) 1px, transparent 1px);\n background-size: 20px 20px;\n}\n\n.wv-diagram svg {\n width: 100%;\n height: 100%;\n}\n\n/* SVG Node styles */\n.wv-node {\n cursor: pointer;\n transition: transform 0.15s ease;\n}\n\n.wv-node:hover {\n transform: scale(1.02);\n}\n\n.wv-node rect,\n.wv-node circle {\n stroke: var(--border);\n stroke-width: 2;\n transition: all 0.2s ease;\n}\n\n.wv-node--pending rect { fill: var(--node-pending); }\n.wv-node--running rect { fill: var(--node-running); stroke: var(--warning); }\n.wv-node--success rect { fill: var(--node-success); stroke: var(--success); }\n.wv-node--error rect { fill: var(--node-error); stroke: var(--error); }\n.wv-node--aborted rect { fill: var(--node-aborted); }\n.wv-node--cached rect { fill: var(--node-cached); stroke: var(--info); }\n.wv-node--skipped rect { fill: var(--node-skipped); opacity: 0.6; }\n\n.wv-node--selected rect {\n stroke: var(--primary);\n stroke-width: 3;\n}\n\n.wv-node text {\n fill: var(--text);\n font-size: 12px;\n font-weight: 500;\n dominant-baseline: middle;\n text-anchor: middle;\n}\n\n.wv-node .wv-node-timing {\n fill: var(--text-muted);\n font-size: 10px;\n}\n\n/* Edge styles */\n.wv-edge {\n fill: none;\n stroke: var(--border);\n stroke-width: 2;\n}\n\n.wv-edge--active {\n stroke: var(--success);\n stroke-width: 2.5;\n}\n\n.wv-edge-arrow {\n fill: var(--border);\n}\n\n/* Parallel/Race container */\n.wv-container {\n fill: transparent;\n stroke: var(--border);\n stroke-dasharray: 5 3;\n}\n\n.wv-container--parallel { stroke: var(--info); }\n.wv-container--race { stroke: var(--warning); }\n\n.wv-container-label {\n fill: var(--text-muted);\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Heatmap overlay */\n.wv-node--heat-cold rect { fill: var(--heat-cold) !important; opacity: 0.7; }\n.wv-node--heat-cool rect { fill: var(--heat-cool) !important; opacity: 0.7; }\n.wv-node--heat-neutral rect { fill: var(--heat-neutral) !important; opacity: 0.7; }\n.wv-node--heat-warm rect { fill: var(--heat-warm) !important; opacity: 0.7; }\n.wv-node--heat-hot rect { fill: var(--heat-hot) !important; opacity: 0.7; }\n.wv-node--heat-critical rect { fill: var(--heat-critical) !important; opacity: 0.85; }\n\n/* Timeline scrubber */\n.wv-timeline {\n height: 80px;\n padding: 12px 20px;\n background-color: var(--bg-secondary);\n border-top: 1px solid var(--border);\n}\n\n.wv-timeline-track {\n position: relative;\n height: 24px;\n background-color: var(--bg);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.wv-timeline-progress {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background-color: var(--primary);\n opacity: 0.3;\n transition: width 0.1s ease;\n}\n\n.wv-timeline-marker {\n position: absolute;\n top: 0;\n width: 3px;\n height: 100%;\n background-color: var(--primary);\n cursor: ew-resize;\n}\n\n.wv-timeline-events {\n display: flex;\n gap: 2px;\n height: 100%;\n align-items: center;\n padding: 4px;\n}\n\n.wv-timeline-event {\n width: 4px;\n height: 16px;\n border-radius: 2px;\n background-color: var(--muted);\n}\n\n.wv-timeline-event--success { background-color: var(--success); }\n.wv-timeline-event--error { background-color: var(--error); }\n.wv-timeline-event--running { background-color: var(--warning); }\n\n.wv-timeline-controls {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n align-items: center;\n}\n\n.wv-timeline-time {\n font-size: 0.75rem;\n color: var(--text-muted);\n font-family: monospace;\n}\n\n/* Inspector panel */\n.wv-inspector {\n width: 320px;\n background-color: var(--bg-secondary);\n border-left: 1px solid var(--border);\n overflow-y: auto;\n transition: width 0.2s ease;\n}\n\n.wv-inspector--collapsed {\n width: 0;\n}\n\n.wv-inspector-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--border);\n}\n\n.wv-inspector-header h2 {\n font-size: 0.875rem;\n font-weight: 600;\n}\n\n.wv-inspector-content {\n padding: 16px;\n}\n\n.wv-inspector-section {\n margin-bottom: 20px;\n}\n\n.wv-inspector-section h3 {\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text-muted);\n margin-bottom: 8px;\n}\n\n.wv-inspector-row {\n display: flex;\n justify-content: space-between;\n padding: 4px 0;\n font-size: 0.875rem;\n}\n\n.wv-inspector-label {\n color: var(--text-muted);\n}\n\n.wv-inspector-value {\n font-weight: 500;\n font-family: monospace;\n}\n\n.wv-inspector-value--success { color: var(--success); }\n.wv-inspector-value--error { color: var(--error); }\n.wv-inspector-value--running { color: var(--warning); }\n\n/* Status badge */\n.wv-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 4px;\n text-transform: capitalize;\n}\n\n.wv-badge--pending { background-color: var(--node-pending); }\n.wv-badge--running { background-color: var(--node-running); color: #664d03; }\n.wv-badge--success { background-color: var(--node-success); color: #0f5132; }\n.wv-badge--error { background-color: var(--node-error); color: #842029; }\n.wv-badge--cached { background-color: var(--node-cached); color: #084298; }\n\n/* Live indicator */\n.wv-live {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background-color: var(--error);\n color: white;\n font-size: 0.75rem;\n font-weight: 600;\n border-radius: 4px;\n}\n\n.wv-live-dot {\n width: 8px;\n height: 8px;\n background-color: white;\n border-radius: 50%;\n animation: wv-pulse 1.5s infinite;\n}\n\n@keyframes wv-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n\n/* Performance stats */\n.wv-perf-bar {\n height: 8px;\n background-color: var(--bg);\n border-radius: 4px;\n overflow: hidden;\n margin-top: 4px;\n}\n\n.wv-perf-bar-fill {\n height: 100%;\n border-radius: 4px;\n transition: width 0.3s ease;\n}\n\n.wv-perf-bar-fill--cold { background-color: var(--heat-cold); }\n.wv-perf-bar-fill--cool { background-color: var(--heat-cool); }\n.wv-perf-bar-fill--neutral { background-color: var(--heat-neutral); }\n.wv-perf-bar-fill--warm { background-color: var(--heat-warm); }\n.wv-perf-bar-fill--hot { background-color: var(--heat-hot); }\n.wv-perf-bar-fill--critical { background-color: var(--heat-critical); }\n\n/* Tooltip */\n.wv-tooltip {\n position: fixed;\n padding: 8px 12px;\n background-color: var(--text);\n color: var(--bg);\n font-size: 0.75rem;\n border-radius: 4px;\n pointer-events: none;\n z-index: 1000;\n max-width: 300px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n/* Loading state */\n.wv-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-muted);\n}\n\n.wv-spinner {\n width: 24px;\n height: 24px;\n border: 3px solid var(--border);\n border-top-color: var(--primary);\n border-radius: 50%;\n animation: wv-spin 1s linear infinite;\n margin-right: 8px;\n}\n\n@keyframes wv-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Empty state */\n.wv-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-muted);\n text-align: center;\n padding: 40px;\n}\n\n.wv-empty svg {\n width: 64px;\n height: 64px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .wv-inspector {\n position: fixed;\n right: 0;\n top: 0;\n bottom: 0;\n z-index: 100;\n box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);\n }\n\n .wv-timeline {\n height: auto;\n }\n}\n`;\n}\n","/**\n * HTML Visualizer Client-Side JavaScript\n *\n * Handles interactivity in the browser:\n * - Zoom and pan\n * - Node selection and inspection\n * - Time-travel controls\n * - WebSocket live updates\n * - Heatmap toggle\n */\n\n/**\n * Generate client-side JavaScript for the HTML visualizer.\n */\nexport function generateClientScript(options: {\n wsUrl?: string;\n interactive: boolean;\n timeTravel: boolean;\n heatmap: boolean;\n}): string {\n return `\n(function() {\n 'use strict';\n\n // State\n let selectedNodeId = null;\n let transform = { x: 0, y: 0, scale: 1 };\n let isDragging = false;\n let dragStart = { x: 0, y: 0 };\n let ws = null;\n let snapshots = [];\n let currentSnapshotIndex = -1;\n let isPlaying = false;\n let playbackSpeed = 1;\n let heatmapEnabled = false;\n let heatmapMetric = 'duration';\n\n // DOM elements\n const diagram = document.getElementById('diagram');\n const svg = diagram?.querySelector('svg');\n const inspector = document.getElementById('inspector');\n const timeline = document.getElementById('timeline');\n\n // Initialize\n document.addEventListener('DOMContentLoaded', init);\n\n function init() {\n ${options.interactive ? \"setupInteractivity();\" : \"\"}\n ${options.timeTravel ? \"setupTimeTravel();\" : \"\"}\n ${options.wsUrl ? `setupWebSocket('${options.wsUrl}');` : \"\"}\n ${options.heatmap ? \"setupHeatmap();\" : \"\"}\n setupKeyboardShortcuts();\n }\n\n // Interactivity\n function setupInteractivity() {\n if (!diagram || !svg) return;\n\n // Zoom with mouse wheel\n diagram.addEventListener('wheel', (e) => {\n e.preventDefault();\n const delta = e.deltaY > 0 ? 0.9 : 1.1;\n const rect = diagram.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n // Zoom towards cursor position\n transform.scale *= delta;\n transform.scale = Math.max(0.1, Math.min(5, transform.scale));\n transform.x = x - (x - transform.x) * delta;\n transform.y = y - (y - transform.y) * delta;\n\n applyTransform();\n });\n\n // Pan with drag\n diagram.addEventListener('mousedown', (e) => {\n if (e.target === diagram || e.target === svg) {\n isDragging = true;\n dragStart = { x: e.clientX - transform.x, y: e.clientY - transform.y };\n diagram.style.cursor = 'grabbing';\n }\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n transform.x = e.clientX - dragStart.x;\n transform.y = e.clientY - dragStart.y;\n applyTransform();\n });\n\n document.addEventListener('mouseup', () => {\n isDragging = false;\n if (diagram) diagram.style.cursor = 'grab';\n });\n\n // Node selection\n document.querySelectorAll('.wv-node').forEach((node) => {\n node.addEventListener('click', (e) => {\n e.stopPropagation();\n selectNode(node.dataset.nodeId);\n });\n });\n\n // Deselect on background click\n diagram.addEventListener('click', (e) => {\n if (e.target === diagram || e.target === svg) {\n selectNode(null);\n }\n });\n\n // Zoom buttons\n document.getElementById('zoom-in')?.addEventListener('click', () => zoom(1.2));\n document.getElementById('zoom-out')?.addEventListener('click', () => zoom(0.8));\n document.getElementById('zoom-reset')?.addEventListener('click', resetZoom);\n\n // Set initial cursor\n diagram.style.cursor = 'grab';\n }\n\n function applyTransform() {\n if (!svg) return;\n const g = svg.querySelector('g.wv-root');\n if (g) {\n g.setAttribute('transform', 'translate(' + transform.x + ',' + transform.y + ') scale(' + transform.scale + ')');\n }\n }\n\n function zoom(factor) {\n if (!diagram) return;\n const rect = diagram.getBoundingClientRect();\n const centerX = rect.width / 2;\n const centerY = rect.height / 2;\n\n transform.scale *= factor;\n transform.scale = Math.max(0.1, Math.min(5, transform.scale));\n transform.x = centerX - (centerX - transform.x) * factor;\n transform.y = centerY - (centerY - transform.y) * factor;\n\n applyTransform();\n }\n\n function resetZoom() {\n transform = { x: 0, y: 0, scale: 1 };\n applyTransform();\n }\n\n function selectNode(nodeId) {\n // Remove previous selection\n document.querySelectorAll('.wv-node--selected').forEach((n) => {\n n.classList.remove('wv-node--selected');\n });\n\n selectedNodeId = nodeId;\n\n if (nodeId) {\n const node = document.querySelector('[data-node-id=\"' + nodeId + '\"]');\n if (node) {\n node.classList.add('wv-node--selected');\n updateInspector(nodeId);\n }\n } else {\n clearInspector();\n }\n }\n\n function updateInspector(nodeId) {\n const content = document.getElementById('inspector-content');\n if (!content) return;\n\n const nodeData = window.__WORKFLOW_DATA__?.nodes?.[nodeId];\n if (!nodeData) {\n // Clear and add empty message using safe DOM methods\n while (content.firstChild) content.removeChild(content.firstChild);\n const p = document.createElement('p');\n p.className = 'wv-empty';\n p.textContent = 'No data available';\n content.appendChild(p);\n return;\n }\n\n renderInspectorContent(content, nodeData);\n }\n\n function renderInspectorContent(container, node) {\n // Clear container using safe DOM method\n while (container.firstChild) container.removeChild(container.firstChild);\n\n // Node Info section\n const infoSection = createSection('Node Info');\n infoSection.appendChild(createRow('Name', node.name || node.id));\n infoSection.appendChild(createRow('Type', node.type));\n\n // State badge\n const stateRow = document.createElement('div');\n stateRow.className = 'wv-inspector-row';\n const stateLabel = document.createElement('span');\n stateLabel.className = 'wv-inspector-label';\n stateLabel.textContent = 'State';\n const stateBadge = document.createElement('span');\n stateBadge.className = 'wv-badge wv-badge--' + node.state;\n stateBadge.textContent = node.state;\n stateRow.appendChild(stateLabel);\n stateRow.appendChild(stateBadge);\n infoSection.appendChild(stateRow);\n\n if (node.key) {\n infoSection.appendChild(createRow('Key', node.key));\n }\n container.appendChild(infoSection);\n\n // Timing section\n if (node.durationMs !== undefined) {\n const timingSection = createSection('Timing');\n timingSection.appendChild(createRow('Duration', formatDuration(node.durationMs)));\n if (node.startTs) {\n timingSection.appendChild(createRow('Started', new Date(node.startTs).toLocaleTimeString()));\n }\n container.appendChild(timingSection);\n }\n\n // Retries section\n if (node.retryCount !== undefined && node.retryCount > 0) {\n const retrySection = createSection('Retries');\n retrySection.appendChild(createRow('Retry Count', String(node.retryCount)));\n container.appendChild(retrySection);\n }\n\n // Error section\n if (node.error) {\n const errorSection = createSection('Error');\n const pre = document.createElement('pre');\n pre.style.cssText = 'font-size:11px;overflow:auto;max-height:150px;background:var(--bg);padding:8px;border-radius:4px;';\n pre.textContent = String(node.error);\n errorSection.appendChild(pre);\n container.appendChild(errorSection);\n }\n }\n\n function createSection(title) {\n const section = document.createElement('div');\n section.className = 'wv-inspector-section';\n const h3 = document.createElement('h3');\n h3.textContent = title;\n section.appendChild(h3);\n return section;\n }\n\n function createRow(label, value) {\n const row = document.createElement('div');\n row.className = 'wv-inspector-row';\n const labelSpan = document.createElement('span');\n labelSpan.className = 'wv-inspector-label';\n labelSpan.textContent = label;\n const valueSpan = document.createElement('span');\n valueSpan.className = 'wv-inspector-value';\n valueSpan.textContent = value;\n row.appendChild(labelSpan);\n row.appendChild(valueSpan);\n return row;\n }\n\n function clearInspector() {\n const content = document.getElementById('inspector-content');\n if (content) {\n while (content.firstChild) content.removeChild(content.firstChild);\n const p = document.createElement('p');\n p.className = 'wv-empty';\n p.textContent = 'Select a node to inspect';\n content.appendChild(p);\n }\n }\n\n // Time Travel\n function setupTimeTravel() {\n const playBtn = document.getElementById('tt-play');\n const pauseBtn = document.getElementById('tt-pause');\n const prevBtn = document.getElementById('tt-prev');\n const nextBtn = document.getElementById('tt-next');\n const speedSelect = document.getElementById('tt-speed');\n const slider = document.getElementById('tt-slider');\n\n playBtn?.addEventListener('click', play);\n pauseBtn?.addEventListener('click', pause);\n prevBtn?.addEventListener('click', stepBackward);\n nextBtn?.addEventListener('click', stepForward);\n speedSelect?.addEventListener('change', (e) => {\n playbackSpeed = parseFloat(e.target.value);\n });\n slider?.addEventListener('input', (e) => {\n seek(parseInt(e.target.value, 10));\n });\n }\n\n function play() {\n if (snapshots.length === 0) return;\n isPlaying = true;\n updatePlaybackUI();\n playNext();\n }\n\n function pause() {\n isPlaying = false;\n updatePlaybackUI();\n }\n\n function playNext() {\n if (!isPlaying) return;\n if (currentSnapshotIndex < snapshots.length - 1) {\n const current = snapshots[currentSnapshotIndex];\n const next = snapshots[currentSnapshotIndex + 1];\n const delay = (next.timestamp - current.timestamp) / playbackSpeed;\n\n setTimeout(() => {\n stepForward();\n playNext();\n }, Math.max(16, delay));\n } else {\n pause();\n }\n }\n\n function stepForward() {\n if (currentSnapshotIndex < snapshots.length - 1) {\n seek(currentSnapshotIndex + 1);\n }\n }\n\n function stepBackward() {\n if (currentSnapshotIndex > 0) {\n seek(currentSnapshotIndex - 1);\n }\n }\n\n function seek(index) {\n if (index < 0 || index >= snapshots.length) return;\n currentSnapshotIndex = index;\n updateTimelineUI();\n\n // Request IR update from server or use cached\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'time_travel_seek', payload: { index } }));\n } else if (snapshots[index]?.ir) {\n renderIR(snapshots[index].ir);\n }\n }\n\n function updatePlaybackUI() {\n const playBtn = document.getElementById('tt-play');\n const pauseBtn = document.getElementById('tt-pause');\n\n if (playBtn) playBtn.style.display = isPlaying ? 'none' : 'inline-flex';\n if (pauseBtn) pauseBtn.style.display = isPlaying ? 'inline-flex' : 'none';\n }\n\n function updateTimelineUI() {\n const slider = document.getElementById('tt-slider');\n const timeDisplay = document.getElementById('tt-time');\n\n if (slider) {\n slider.max = String(Math.max(0, snapshots.length - 1));\n slider.value = String(currentSnapshotIndex);\n }\n\n if (timeDisplay) {\n timeDisplay.textContent = (currentSnapshotIndex + 1) + ' / ' + snapshots.length;\n }\n }\n\n // WebSocket\n function setupWebSocket(url) {\n ws = new WebSocket(url);\n\n ws.onopen = () => {\n console.log('[Visualizer] Connected to server');\n showLiveIndicator(true);\n };\n\n ws.onclose = () => {\n console.log('[Visualizer] Disconnected from server');\n showLiveIndicator(false);\n // Attempt reconnect after 2 seconds\n setTimeout(() => setupWebSocket(url), 2000);\n };\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n handleServerMessage(msg);\n } catch (e) {\n console.error('[Visualizer] Failed to parse message:', e);\n }\n };\n\n ws.onerror = (error) => {\n console.error('[Visualizer] WebSocket error:', error);\n };\n }\n\n function handleServerMessage(msg) {\n switch (msg.type) {\n case 'ir_update':\n renderIR(msg.payload);\n break;\n case 'snapshot':\n snapshots.push(msg.payload);\n currentSnapshotIndex = snapshots.length - 1;\n updateTimelineUI();\n break;\n case 'snapshots_list':\n snapshots = msg.payload;\n currentSnapshotIndex = snapshots.length - 1;\n updateTimelineUI();\n break;\n case 'performance_data':\n window.__PERFORMANCE_DATA__ = msg.payload;\n if (heatmapEnabled) applyHeatmap();\n break;\n case 'workflow_complete':\n showLiveIndicator(false);\n break;\n case 'time_travel_state':\n currentSnapshotIndex = msg.payload.currentIndex;\n isPlaying = msg.payload.isPlaying;\n playbackSpeed = msg.payload.playbackSpeed;\n updateTimelineUI();\n updatePlaybackUI();\n break;\n }\n }\n\n function showLiveIndicator(show) {\n const indicator = document.getElementById('live-indicator');\n if (indicator) {\n indicator.style.display = show ? 'flex' : 'none';\n }\n }\n\n // Heatmap\n function setupHeatmap() {\n const toggle = document.getElementById('heatmap-toggle');\n const metricSelect = document.getElementById('heatmap-metric');\n\n toggle?.addEventListener('click', () => {\n heatmapEnabled = !heatmapEnabled;\n toggle.classList.toggle('wv-btn--primary', heatmapEnabled);\n if (heatmapEnabled) {\n applyHeatmap();\n } else {\n removeHeatmap();\n }\n });\n\n metricSelect?.addEventListener('change', (e) => {\n heatmapMetric = e.target.value;\n if (heatmapEnabled) applyHeatmap();\n });\n }\n\n function applyHeatmap() {\n const perfData = window.__PERFORMANCE_DATA__;\n if (!perfData) return;\n\n document.querySelectorAll('.wv-node').forEach((node) => {\n const nodeId = node.dataset.nodeId;\n const heat = perfData.heat?.[nodeId];\n\n // Remove existing heat classes\n node.classList.remove(\n 'wv-node--heat-cold',\n 'wv-node--heat-cool',\n 'wv-node--heat-neutral',\n 'wv-node--heat-warm',\n 'wv-node--heat-hot',\n 'wv-node--heat-critical'\n );\n\n if (heat !== undefined) {\n const level = getHeatLevel(heat);\n node.classList.add('wv-node--heat-' + level);\n }\n });\n }\n\n function removeHeatmap() {\n document.querySelectorAll('.wv-node').forEach((node) => {\n node.classList.remove(\n 'wv-node--heat-cold',\n 'wv-node--heat-cool',\n 'wv-node--heat-neutral',\n 'wv-node--heat-warm',\n 'wv-node--heat-hot',\n 'wv-node--heat-critical'\n );\n });\n }\n\n function getHeatLevel(heat) {\n if (heat < 0.2) return 'cold';\n if (heat < 0.4) return 'cool';\n if (heat < 0.6) return 'neutral';\n if (heat < 0.8) return 'warm';\n if (heat < 0.95) return 'hot';\n return 'critical';\n }\n\n // Keyboard shortcuts\n function setupKeyboardShortcuts() {\n document.addEventListener('keydown', (e) => {\n // Don't trigger shortcuts when typing in inputs\n if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;\n\n switch (e.key) {\n case ' ':\n e.preventDefault();\n isPlaying ? pause() : play();\n break;\n case 'ArrowLeft':\n e.preventDefault();\n stepBackward();\n break;\n case 'ArrowRight':\n e.preventDefault();\n stepForward();\n break;\n case '0':\n resetZoom();\n break;\n case '+':\n case '=':\n zoom(1.2);\n break;\n case '-':\n zoom(0.8);\n break;\n case 'h':\n ${options.heatmap ? \"document.getElementById('heatmap-toggle')?.click();\" : \"\"}\n break;\n case 'Escape':\n selectNode(null);\n break;\n }\n });\n }\n\n // Render functions\n function renderIR(ir) {\n // Store node data for inspector\n window.__WORKFLOW_DATA__ = {\n nodes: flattenNodes(ir.root.children).reduce((acc, n) => {\n acc[n.id] = n;\n return acc;\n }, {})\n };\n\n // Update SVG node states\n document.querySelectorAll('.wv-node').forEach((node) => {\n const nodeId = node.dataset.nodeId;\n const nodeData = window.__WORKFLOW_DATA__.nodes[nodeId];\n if (nodeData) {\n // Update state class\n node.className = node.className.replace(/wv-node--\\\\w+/g, '');\n node.classList.add('wv-node', 'wv-node--' + nodeData.state);\n\n // Update timing text if present\n const timing = node.querySelector('.wv-node-timing');\n if (timing && nodeData.durationMs !== undefined) {\n timing.textContent = formatDuration(nodeData.durationMs);\n }\n }\n });\n\n // Update selected node inspector\n if (selectedNodeId) {\n updateInspector(selectedNodeId);\n }\n }\n\n function flattenNodes(nodes) {\n const result = [];\n for (const node of nodes) {\n result.push(node);\n if (node.children) {\n result.push(...flattenNodes(node.children));\n }\n if (node.branches) {\n for (const branch of node.branches) {\n result.push(...flattenNodes(branch.children));\n }\n }\n }\n return result;\n }\n\n // Utilities\n function formatDuration(ms) {\n if (ms < 1) return '<1ms';\n if (ms < 1000) return Math.round(ms) + 'ms';\n if (ms < 60000) return (ms / 1000).toFixed(2) + 's';\n return (ms / 60000).toFixed(1) + 'm';\n }\n})();\n`;\n}\n","/**\n * HTML Renderer\n *\n * Renders the workflow IR as an interactive HTML page with:\n * - SVG-based workflow diagram\n * - Zoom and pan\n * - Node inspection\n * - Time-travel controls\n * - Performance heatmap overlay\n */\n\nimport type {\n FlowNode,\n HTMLRenderOptions,\n Renderer,\n WorkflowIR,\n StepState,\n RenderOptions,\n LayoutDirection,\n} from \"../types\";\nimport {\n isStepNode,\n isParallelNode,\n isRaceNode,\n isDecisionNode,\n} from \"../types\";\nimport { generateStyles } from \"./html-styles\";\nimport { generateClientScript } from \"./html-client\";\nimport { formatDuration } from \"../utils/timing\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst NODE_WIDTH = 160;\nconst NODE_HEIGHT = 50;\nconst NODE_SPACING_H = 40;\nconst NODE_SPACING_V = 30;\nconst CONTAINER_PADDING = 20;\n\n// =============================================================================\n// Layout Types\n// =============================================================================\n\ninterface LayoutNode {\n id: string;\n name: string;\n type: string;\n state: StepState;\n x: number;\n y: number;\n width: number;\n height: number;\n durationMs?: number;\n children?: LayoutNode[];\n containerType?: \"parallel\" | \"race\" | \"decision\";\n containerLabel?: string;\n}\n\ninterface LayoutResult {\n nodes: LayoutNode[];\n width: number;\n height: number;\n}\n\n// =============================================================================\n// Layout Functions\n// =============================================================================\n\n/**\n * Layout workflow nodes for SVG rendering.\n * Uses a simple top-to-bottom layout algorithm.\n */\nfunction layoutWorkflow(\n nodes: FlowNode[],\n direction: LayoutDirection = \"TB\"\n): LayoutResult {\n const isVertical = direction === \"TB\" || direction === \"BT\";\n const layoutNodes: LayoutNode[] = [];\n let currentX = CONTAINER_PADDING;\n let currentY = CONTAINER_PADDING;\n let maxWidth = 0;\n let maxHeight = 0;\n\n for (const node of nodes) {\n const result = layoutFlowNode(node, currentX, currentY, isVertical);\n layoutNodes.push(result.node);\n\n if (isVertical) {\n currentY += result.height + NODE_SPACING_V;\n maxWidth = Math.max(maxWidth, result.width);\n maxHeight = currentY;\n } else {\n currentX += result.width + NODE_SPACING_H;\n maxHeight = Math.max(maxHeight, result.height);\n maxWidth = currentX;\n }\n }\n\n return {\n nodes: layoutNodes,\n width: maxWidth + CONTAINER_PADDING,\n height: maxHeight + CONTAINER_PADDING,\n };\n}\n\n/**\n * Layout a single flow node.\n */\nfunction layoutFlowNode(\n node: FlowNode,\n x: number,\n y: number,\n _isVertical: boolean\n): { node: LayoutNode; width: number; height: number } {\n if (isStepNode(node)) {\n return {\n node: {\n id: node.id,\n name: node.name ?? node.key ?? \"step\",\n type: \"step\",\n state: node.state,\n x,\n y,\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n durationMs: node.durationMs,\n },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n };\n }\n\n if (isParallelNode(node) || isRaceNode(node)) {\n const containerType = isParallelNode(node) ? \"parallel\" : \"race\";\n const label = node.name ?? containerType;\n const children: LayoutNode[] = [];\n\n let innerX = x + CONTAINER_PADDING;\n const innerY = y + CONTAINER_PADDING + 20; // Extra space for label\n let innerMaxWidth = 0;\n let innerMaxHeight = 0;\n\n // Layout children horizontally in parallel\n for (const child of node.children) {\n const result = layoutFlowNode(child, innerX, innerY, true);\n children.push(result.node);\n innerX += result.width + NODE_SPACING_H;\n innerMaxHeight = Math.max(innerMaxHeight, result.height);\n }\n\n innerMaxWidth = innerX - x - CONTAINER_PADDING;\n const containerWidth = Math.max(\n innerMaxWidth + CONTAINER_PADDING,\n NODE_WIDTH + CONTAINER_PADDING * 2\n );\n const containerHeight =\n innerMaxHeight + CONTAINER_PADDING * 2 + 20; // Extra for label\n\n return {\n node: {\n id: node.id,\n name: label,\n type: containerType,\n state: node.state,\n x,\n y,\n width: containerWidth,\n height: containerHeight,\n durationMs: node.durationMs,\n children,\n containerType,\n containerLabel: containerType === \"parallel\" ? \"PARALLEL\" : \"RACE\",\n },\n width: containerWidth,\n height: containerHeight,\n };\n }\n\n if (isDecisionNode(node)) {\n const label = node.name ?? \"decision\";\n const children: LayoutNode[] = [];\n\n let innerX = x + CONTAINER_PADDING;\n const innerY = y + CONTAINER_PADDING + 20;\n let innerMaxHeight = 0;\n\n // Layout branches horizontally\n for (const branch of node.branches) {\n for (const child of branch.children) {\n const result = layoutFlowNode(child, innerX, innerY, true);\n children.push(result.node);\n innerX += result.width + NODE_SPACING_H;\n innerMaxHeight = Math.max(innerMaxHeight, result.height);\n }\n }\n\n const containerWidth = Math.max(\n innerX - x,\n NODE_WIDTH + CONTAINER_PADDING * 2\n );\n const containerHeight = innerMaxHeight + CONTAINER_PADDING * 2 + 20;\n\n return {\n node: {\n id: node.id,\n name: label,\n type: \"decision\",\n state: node.state,\n x,\n y,\n width: containerWidth,\n height: containerHeight,\n durationMs: node.durationMs,\n children,\n containerType: \"decision\",\n containerLabel: \"DECISION\",\n },\n width: containerWidth,\n height: containerHeight,\n };\n }\n\n // Default fallback\n return {\n node: {\n id: node.id,\n name: node.name ?? \"unknown\",\n type: node.type,\n state: node.state,\n x,\n y,\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n };\n}\n\n// =============================================================================\n// SVG Rendering\n// =============================================================================\n\n/**\n * Render a layout node to SVG.\n */\nfunction renderLayoutNodeSVG(node: LayoutNode, showTimings: boolean): string {\n if (node.containerType) {\n return renderContainerSVG(node, showTimings);\n }\n return renderStepSVG(node, showTimings);\n}\n\n/**\n * Render a step node as SVG.\n */\nfunction renderStepSVG(node: LayoutNode, showTimings: boolean): string {\n const rx = 8; // Border radius\n const timing =\n showTimings && node.durationMs !== undefined\n ? formatDuration(node.durationMs)\n : \"\";\n\n return `\n <g class=\"wv-node wv-node--${node.state}\" data-node-id=\"${escapeAttr(node.id)}\" transform=\"translate(${node.x}, ${node.y})\">\n <rect width=\"${node.width}\" height=\"${node.height}\" rx=\"${rx}\" ry=\"${rx}\" />\n <text x=\"${node.width / 2}\" y=\"${node.height / 2 - (timing ? 4 : 0)}\">${escapeXml(truncate(node.name, 20))}</text>\n ${timing ? `<text class=\"wv-node-timing\" x=\"${node.width / 2}\" y=\"${node.height / 2 + 12}\">${timing}</text>` : \"\"}\n </g>\n `;\n}\n\n/**\n * Render a container (parallel/race/decision) as SVG.\n */\nfunction renderContainerSVG(node: LayoutNode, showTimings: boolean): string {\n const rx = 12;\n const childrenSVG =\n node.children?.map((c) => renderLayoutNodeSVG(c, showTimings)).join(\"\\n\") ??\n \"\";\n\n return `\n <g class=\"wv-container wv-container--${node.containerType}\" data-node-id=\"${escapeAttr(node.id)}\" transform=\"translate(${node.x}, ${node.y})\">\n <rect width=\"${node.width}\" height=\"${node.height}\" rx=\"${rx}\" ry=\"${rx}\" />\n <text class=\"wv-container-label\" x=\"${CONTAINER_PADDING}\" y=\"16\">${node.containerLabel}</text>\n <g transform=\"translate(${-node.x}, ${-node.y})\">\n ${childrenSVG}\n </g>\n </g>\n `;\n}\n\n/**\n * Render edges between sequential nodes.\n */\nfunction renderEdgesSVG(nodes: LayoutNode[]): string {\n const edges: string[] = [];\n\n for (let i = 0; i < nodes.length - 1; i++) {\n const from = nodes[i];\n const to = nodes[i + 1];\n\n const x1 = from.x + from.width / 2;\n const y1 = from.y + from.height;\n const x2 = to.x + to.width / 2;\n const y2 = to.y;\n\n // Simple straight line with arrow\n edges.push(`\n <path class=\"wv-edge\" d=\"M ${x1} ${y1} L ${x2} ${y2 - 8}\" />\n <polygon class=\"wv-edge-arrow\" points=\"${x2 - 4},${y2 - 8} ${x2 + 4},${y2 - 8} ${x2},${y2}\" />\n `);\n }\n\n return edges.join(\"\\n\");\n}\n\n// =============================================================================\n// HTML Generation\n// =============================================================================\n\n/**\n * Generate complete HTML page.\n */\nfunction generateHTML(\n ir: WorkflowIR,\n options: HTMLRenderOptions\n): string {\n const layout = layoutWorkflow(ir.root.children, options.layout);\n const svgWidth = Math.max(layout.width, 400);\n const svgHeight = Math.max(layout.height, 300);\n\n const nodesSVG = layout.nodes\n .map((n) => renderLayoutNodeSVG(n, options.showTimings))\n .join(\"\\n\");\n const edgesSVG = renderEdgesSVG(layout.nodes);\n\n const workflowName = ir.root.name ?? \"Workflow\";\n const css = generateStyles(options.theme);\n const js = generateClientScript({\n wsUrl: options.wsUrl,\n interactive: options.interactive,\n timeTravel: options.timeTravel,\n heatmap: options.heatmap,\n });\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeXml(workflowName)} - Workflow Visualizer</title>\n <style>${css}</style>\n</head>\n<body>\n <div class=\"workflow-visualizer\">\n <header class=\"wv-header\">\n <h1>${escapeXml(workflowName)}</h1>\n <div class=\"wv-controls\">\n ${options.wsUrl ? `<div id=\"live-indicator\" class=\"wv-live\" style=\"display:none\"><span class=\"wv-live-dot\"></span>LIVE</div>` : \"\"}\n ${options.heatmap ? `\n <button id=\"heatmap-toggle\" class=\"wv-btn\">Heatmap</button>\n <select id=\"heatmap-metric\" class=\"wv-btn\">\n <option value=\"duration\">Duration</option>\n <option value=\"retryRate\">Retry Rate</option>\n <option value=\"errorRate\">Error Rate</option>\n </select>\n ` : \"\"}\n ${options.interactive ? `\n <button id=\"zoom-out\" class=\"wv-btn wv-btn--icon\" title=\"Zoom out (-)\">−</button>\n <button id=\"zoom-reset\" class=\"wv-btn wv-btn--icon\" title=\"Reset zoom (0)\">⟲</button>\n <button id=\"zoom-in\" class=\"wv-btn wv-btn--icon\" title=\"Zoom in (+)\">+</button>\n ` : \"\"}\n </div>\n </header>\n\n <div class=\"wv-main\">\n <div id=\"diagram\" class=\"wv-diagram\">\n <svg viewBox=\"0 0 ${svgWidth} ${svgHeight}\" preserveAspectRatio=\"xMidYMid meet\">\n <g class=\"wv-root\">\n ${edgesSVG}\n ${nodesSVG}\n </g>\n </svg>\n </div>\n\n ${options.interactive ? `\n <aside id=\"inspector\" class=\"wv-inspector\">\n <div class=\"wv-inspector-header\">\n <h2>Inspector</h2>\n </div>\n <div id=\"inspector-content\" class=\"wv-inspector-content\">\n <p class=\"wv-empty\">Select a node to inspect</p>\n </div>\n </aside>\n ` : \"\"}\n </div>\n\n ${options.timeTravel ? `\n <div id=\"timeline\" class=\"wv-timeline\">\n <div class=\"wv-timeline-track\">\n <input type=\"range\" id=\"tt-slider\" min=\"0\" max=\"0\" value=\"0\" style=\"width:100%\">\n </div>\n <div class=\"wv-timeline-controls\">\n <button id=\"tt-prev\" class=\"wv-btn wv-btn--icon\" title=\"Step backward (←)\">⏮</button>\n <button id=\"tt-play\" class=\"wv-btn wv-btn--icon\" title=\"Play (Space)\">▶</button>\n <button id=\"tt-pause\" class=\"wv-btn wv-btn--icon\" style=\"display:none\" title=\"Pause (Space)\">⏸</button>\n <button id=\"tt-next\" class=\"wv-btn wv-btn--icon\" title=\"Step forward (→)\">⏭</button>\n <select id=\"tt-speed\" class=\"wv-btn\">\n <option value=\"0.5\">0.5x</option>\n <option value=\"1\" selected>1x</option>\n <option value=\"2\">2x</option>\n <option value=\"4\">4x</option>\n <option value=\"10\">10x</option>\n </select>\n <span id=\"tt-time\" class=\"wv-timeline-time\">0 / 0</span>\n </div>\n </div>\n ` : \"\"}\n </div>\n\n <script>\n window.__WORKFLOW_DATA__ = ${serializeWorkflowData(ir)};\n </script>\n <script>${js}</script>\n</body>\n</html>`;\n}\n\n/**\n * Build workflow data structure for client-side access.\n */\nfunction buildWorkflowData(ir: WorkflowIR): { nodes: Record<string, unknown> } {\n const nodes: Record<string, unknown> = {};\n\n function collectNodes(flowNodes: FlowNode[]): void {\n for (const node of flowNodes) {\n nodes[node.id] = {\n id: node.id,\n name: node.name,\n type: node.type,\n state: node.state,\n key: node.key,\n durationMs: node.durationMs,\n startTs: node.startTs,\n error: node.error ? String(node.error) : undefined,\n retryCount: node.retryCount,\n };\n\n if (\"children\" in node && Array.isArray(node.children)) {\n collectNodes(node.children);\n }\n if (\"branches\" in node) {\n for (const branch of node.branches) {\n collectNodes(branch.children);\n }\n }\n }\n }\n\n collectNodes(ir.root.children);\n return { nodes };\n}\n\n/**\n * Serialize workflow data for safe embedding inside a <script> tag.\n */\nfunction serializeWorkflowData(ir: WorkflowIR): string {\n const json = JSON.stringify(buildWorkflowData(ir));\n // Escape characters that could break out of the script context\n return json\n .replace(/</g, \"\\\\u003c\")\n .replace(/>/g, \"\\\\u003e\")\n .replace(/&/g, \"\\\\u0026\")\n .replace(/\\u2028/g, \"\\\\u2028\")\n .replace(/\\u2029/g, \"\\\\u2029\");\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/\"/g, \""\").replace(/'/g, \"'\");\n}\n\nfunction truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 1) + \"…\";\n}\n\n// =============================================================================\n// Renderer Export\n// =============================================================================\n\n/**\n * Default HTML render options.\n */\nconst defaultHTMLOptions: Omit<HTMLRenderOptions, keyof RenderOptions> = {\n interactive: true,\n timeTravel: true,\n heatmap: true,\n animationDuration: 200,\n theme: \"auto\",\n layout: \"TB\",\n};\n\n/**\n * Create the HTML renderer.\n */\nexport function htmlRenderer(): Renderer {\n return {\n name: \"html\",\n supportsLive: true,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n const htmlOptions: HTMLRenderOptions = {\n ...options,\n ...defaultHTMLOptions,\n ...(options as Partial<HTMLRenderOptions>),\n };\n\n return generateHTML(ir, htmlOptions);\n },\n };\n}\n\n/**\n * Render workflow IR to HTML with custom options.\n */\nexport function renderToHTML(\n ir: WorkflowIR,\n options: Partial<HTMLRenderOptions> = {}\n): string {\n const fullOptions: HTMLRenderOptions = {\n showTimings: true,\n showKeys: false,\n colors: {\n pending: \"#6c757d\",\n running: \"#ffc107\",\n success: \"#198754\",\n error: \"#dc3545\",\n aborted: \"#6c757d\",\n cached: \"#0dcaf0\",\n skipped: \"#adb5bd\",\n },\n ...defaultHTMLOptions,\n ...options,\n };\n\n return generateHTML(ir, fullOptions);\n}\n","/**\n * Live Visualizer - Real-time terminal updates during workflow execution.\n *\n * Uses ANSI escape codes to update the terminal in-place, showing\n * workflow progress as it happens.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n LiveVisualizerOptions,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst ANSI = {\n /** Clear from cursor to end of screen */\n clearToEnd: \"\\x1b[J\",\n /** Move cursor up N lines */\n cursorUp: (n: number) => `\\x1b[${n}A`,\n /** Move cursor to beginning of line */\n cursorToStart: \"\\x1b[G\",\n /** Hide cursor */\n hideCursor: \"\\x1b[?25l\",\n /** Show cursor */\n showCursor: \"\\x1b[?25h\",\n /** Save cursor position */\n saveCursor: \"\\x1b[s\",\n /** Restore cursor position */\n restoreCursor: \"\\x1b[u\",\n};\n\n// =============================================================================\n// Live Visualizer Interface\n// =============================================================================\n\n/**\n * Live visualizer with real-time terminal updates.\n */\nexport interface LiveVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Process a scope event */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n /** Process a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n /** Get current IR state */\n getIR: () => WorkflowIR;\n /** Render current state to string (without terminal output) */\n render: () => string;\n /** Start live rendering to terminal */\n start: () => void;\n /** Stop live rendering */\n stop: () => void;\n /** Force an immediate redraw */\n refresh: () => void;\n /** Reset state for a new workflow */\n reset: () => void;\n}\n\n// =============================================================================\n// Create Live Visualizer\n// =============================================================================\n\n/**\n * Create a live visualizer for real-time terminal updates.\n *\n * @example\n * ```typescript\n * const live = createLiveVisualizer({ workflowName: 'my-workflow' });\n * const workflow = createWorkflow(deps, { onEvent: live.handleEvent });\n *\n * live.start();\n * await workflow(async (step) => { ... });\n * live.stop();\n * ```\n */\nexport function createLiveVisualizer(\n options: LiveVisualizerOptions = {}\n): LiveVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n stream = process.stdout,\n updateInterval = 100,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const renderer = asciiRenderer();\n\n // Render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: stream.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n // State\n let isRunning = false;\n let lastOutput = \"\";\n let lastLineCount = 0;\n let throttleTimeout: ReturnType<typeof setTimeout> | null = null;\n let pendingUpdate = false;\n\n /**\n * Write to the output stream.\n */\n function write(text: string): void {\n if (stream.writable) {\n stream.write(text);\n }\n }\n\n /**\n * Clear the previous output and write new content.\n */\n function redraw(): void {\n if (!isRunning) return;\n\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n // If output hasn't changed, skip redraw\n if (output === lastOutput) return;\n\n // Clear previous output\n if (lastLineCount > 0) {\n // Move cursor up and clear\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n // Write new output\n write(output);\n write(\"\\n\");\n\n // Track line count for next clear\n lastOutput = output;\n lastLineCount = output.split(\"\\n\").length;\n }\n\n /**\n * Schedule a throttled redraw.\n */\n function scheduleRedraw(): void {\n if (!isRunning) return;\n\n pendingUpdate = true;\n\n if (throttleTimeout === null) {\n throttleTimeout = setTimeout(() => {\n throttleTimeout = null;\n if (pendingUpdate) {\n pendingUpdate = false;\n redraw();\n }\n }, updateInterval);\n }\n }\n\n /**\n * Handle a workflow event.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n if (isRunning) {\n // Immediate redraw for start/end events, throttled for others\n if (\n event.type === \"workflow_start\" ||\n event.type === \"workflow_success\" ||\n event.type === \"workflow_error\"\n ) {\n redraw();\n } else {\n scheduleRedraw();\n }\n }\n }\n\n /**\n * Handle a scope event.\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Handle a decision event.\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Get the current IR state.\n */\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n /**\n * Render current state to string.\n */\n function render(): string {\n return renderer.render(getIR(), renderOptions);\n }\n\n /**\n * Start live rendering.\n */\n function start(): void {\n if (isRunning) return;\n\n isRunning = true;\n lastOutput = \"\";\n lastLineCount = 0;\n\n // Hide cursor during updates\n write(ANSI.hideCursor);\n\n // Initial render\n redraw();\n }\n\n /**\n * Stop live rendering.\n */\n function stop(): void {\n if (!isRunning) return;\n\n isRunning = false;\n\n // Clear any pending throttle\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n\n // Final redraw to show completed state\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n if (lastLineCount > 0) {\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n write(output);\n write(\"\\n\");\n\n // Show cursor again\n write(ANSI.showCursor);\n }\n\n /**\n * Force an immediate redraw.\n */\n function refresh(): void {\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n pendingUpdate = false;\n redraw();\n }\n\n /**\n * Reset state for a new workflow.\n */\n function reset(): void {\n builder.reset();\n lastOutput = \"\";\n lastLineCount = 0;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n start,\n stop,\n refresh,\n reset,\n };\n}\n","/**\n * Decision Tracker - Helper for tracking conditional logic in workflows.\n *\n * This module provides utilities to track decision points (if/switch statements)\n * so they can be visualized in workflow diagrams.\n *\n * @example\n * ```typescript\n * import { trackDecision } from '@jagreehal/workflow/visualize';\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: (event) => {\n * // Pass events to visualizer\n * viz.handleEvent(event);\n * }\n * });\n *\n * await workflow(async (step) => {\n * const user = await step(fetchUser(id));\n *\n * // Track a decision point\n * const decision = trackDecision('user-role-check', {\n * condition: 'user.role === \"admin\"',\n * value: user.role\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * await step(processAdminAction(user));\n * } else {\n * decision.takeBranch('user', false);\n * await step(processUserAction(user));\n * }\n *\n * decision.end();\n * });\n * ```\n */\n\nimport type {\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n} from \"./types\";\n\n// =============================================================================\n// Decision Tracker\n// =============================================================================\n\n/**\n * Options for creating a decision tracker.\n */\nexport interface DecisionTrackerOptions {\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n value?: unknown;\n /** Name/label for this decision point */\n name?: string;\n /** Workflow ID (auto-generated if not provided) */\n workflowId?: string;\n /** Event emitter function */\n emit?: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n}\n\n/**\n * Track a decision point in your workflow.\n *\n * Use this to annotate conditional logic (if/switch) so it appears\n * in workflow visualizations.\n *\n * @param decisionId - Unique identifier for this decision\n * @param options - Decision tracking options\n * @returns A tracker object with methods to track branches\n *\n * @example\n * ```typescript\n * const decision = trackDecision('check-role', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (event) => viz.handleDecisionEvent(event)\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * // ... admin logic\n * } else {\n * decision.takeBranch('user', false);\n * // ... user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackDecision(\n decisionId: string,\n options: DecisionTrackerOptions = {}\n): DecisionTracker {\n const {\n condition,\n value,\n name,\n workflowId = crypto.randomUUID(),\n emit,\n } = options;\n\n const startTs = Date.now();\n let branchTaken: string | boolean | undefined;\n const branches: Array<{ label: string; condition?: string; taken: boolean }> = [];\n\n function takeBranch(\n label: string,\n taken: boolean,\n branchCondition?: string\n ): void {\n branches.push({ label, condition: branchCondition, taken });\n if (taken) {\n branchTaken = label;\n }\n\n emit?.({\n type: \"decision_branch\",\n workflowId,\n decisionId,\n branchLabel: label,\n condition: branchCondition,\n taken,\n ts: Date.now(),\n });\n }\n\n function end(): void {\n const durationMs = Date.now() - startTs;\n emit?.({\n type: \"decision_end\",\n workflowId,\n decisionId,\n branchTaken,\n ts: Date.now(),\n durationMs,\n });\n }\n\n // Emit start event immediately\n emit?.({\n type: \"decision_start\",\n workflowId,\n decisionId,\n condition,\n decisionValue: value,\n name,\n ts: startTs,\n });\n\n return {\n takeBranch,\n end,\n getBranchTaken: () => branchTaken,\n getBranches: () => [...branches],\n };\n}\n\n/**\n * Decision tracker instance.\n */\nexport interface DecisionTracker {\n /**\n * Mark that a branch was taken or skipped.\n * @param label - Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\")\n * @param taken - Whether this branch was executed\n * @param branchCondition - Optional condition for this specific branch\n */\n takeBranch(label: string, taken: boolean, branchCondition?: string): void;\n\n /**\n * End the decision tracking.\n * Call this after all branches have been evaluated.\n */\n end(): void;\n\n /**\n * Get which branch was taken.\n */\n getBranchTaken(): string | boolean | undefined;\n\n /**\n * Get all branches (taken and skipped).\n */\n getBranches(): Array<{ label: string; condition?: string; taken: boolean }>;\n}\n\n// =============================================================================\n// Convenience Helpers\n// =============================================================================\n\n/**\n * Track a simple if/else decision.\n *\n * @example\n * ```typescript\n * const decision = trackIf('check-admin', user.role === 'admin', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * if (decision.condition) {\n * decision.then();\n * // admin logic\n * } else {\n * decision.else();\n * // user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackIf(\n decisionId: string,\n condition: boolean,\n options: Omit<DecisionTrackerOptions, \"value\"> & { value?: unknown } = {}\n): IfTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? String(condition),\n value: options.value ?? condition,\n });\n\n return {\n ...tracker,\n condition,\n then: () => {\n tracker.takeBranch(\"if\", true);\n },\n else: () => {\n // Mark else branch as taken (true) when the else block executes\n tracker.takeBranch(\"else\", true);\n },\n };\n}\n\n/**\n * If tracker with convenience methods.\n */\nexport interface IfTracker extends DecisionTracker {\n /** The condition value */\n condition: boolean;\n /** Mark the \"if\" branch as taken */\n then(): void;\n /** Mark the \"else\" branch as taken */\n else(): void;\n}\n\n/**\n * Track a switch statement decision.\n *\n * @example\n * ```typescript\n * const decision = trackSwitch('process-type', user.type, {\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * switch (user.type) {\n * case 'admin':\n * decision.case('admin', true);\n * // admin logic\n * break;\n * case 'user':\n * decision.case('user', true);\n * // user logic\n * break;\n * default:\n * decision.default(true);\n * // default logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackSwitch(\n decisionId: string,\n value: unknown,\n options: Omit<DecisionTrackerOptions, \"value\"> = {}\n): SwitchTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? `switch(${String(value)})`,\n value,\n });\n\n return {\n ...tracker,\n value,\n case: (caseValue: string | number, taken: boolean) => {\n tracker.takeBranch(`case '${caseValue}'`, taken, `value === '${caseValue}'`);\n },\n default: (taken: boolean) => {\n tracker.takeBranch(\"default\", taken);\n },\n };\n}\n\n/**\n * Switch tracker with convenience methods.\n */\nexport interface SwitchTracker extends DecisionTracker {\n /** The value being switched on */\n value: unknown;\n /** Mark a case branch */\n case(caseValue: string | number, taken: boolean): void;\n /** Mark the default branch */\n default(taken: boolean): void;\n}\n","/**\n * Time Travel Debugger\n *\n * Records IR snapshots at each event, enabling:\n * - Step-by-step forward/backward navigation\n * - Seeking to any point in execution\n * - Playback at various speeds\n * - State inspection at any moment\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n IRSnapshot,\n TimeTravelState,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder, type IRBuilder, type IRBuilderOptions } from \"./ir-builder\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for the time-travel controller.\n */\nexport interface TimeTravelOptions {\n /** Maximum snapshots to store (ring buffer) */\n maxSnapshots?: number;\n /** Automatically record snapshots on each event */\n autoRecord?: boolean;\n /** IR builder options (passed through) */\n builderOptions?: Omit<IRBuilderOptions, \"enableSnapshots\" | \"maxSnapshots\">;\n}\n\n/**\n * Time-travel controller interface.\n */\nexport interface TimeTravelController {\n /** Handle a workflow event (records snapshot if recording) */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Navigate to specific snapshot index */\n seek: (index: number) => WorkflowIR | undefined;\n\n /** Move one step forward */\n stepForward: () => WorkflowIR | undefined;\n\n /** Move one step backward */\n stepBackward: () => WorkflowIR | undefined;\n\n /** Start playback at given speed (1.0 = realtime) */\n play: (speed?: number) => void;\n\n /** Pause playback */\n pause: () => void;\n\n /** Get current IR state */\n getCurrentIR: () => WorkflowIR;\n\n /** Get IR at specific snapshot index */\n getIRAt: (index: number) => WorkflowIR | undefined;\n\n /** Get all snapshots */\n getSnapshots: () => IRSnapshot[];\n\n /** Get snapshot at specific index */\n getSnapshotAt: (index: number) => IRSnapshot | undefined;\n\n /** Get current time-travel state */\n getState: () => TimeTravelState;\n\n /** Subscribe to state changes */\n onStateChange: (callback: (state: TimeTravelState) => void) => () => void;\n\n /** Start/resume recording */\n startRecording: () => void;\n\n /** Stop recording */\n stopRecording: () => void;\n\n /** Reset to initial state */\n reset: () => void;\n\n /** Get the underlying IR builder */\n getBuilder: () => IRBuilder;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Create a time-travel controller for workflow debugging.\n *\n * @example\n * ```typescript\n * const controller = createTimeTravelController();\n *\n * // Feed events from workflow execution\n * workflow.onEvent(event => controller.handleEvent(event));\n *\n * // After execution, explore the timeline\n * controller.seek(0); // Go to start\n * controller.stepForward(); // Step through\n * controller.play(2); // Playback at 2x speed\n * ```\n */\nexport function createTimeTravelController(\n options: TimeTravelOptions = {}\n): TimeTravelController {\n const { maxSnapshots = 1000, autoRecord = true, builderOptions = {} } = options;\n\n // Create IR builder with snapshots enabled\n const builder = createIRBuilder({\n ...builderOptions,\n enableSnapshots: true,\n maxSnapshots,\n });\n\n // Controller state\n let state: TimeTravelState = {\n snapshots: [],\n currentIndex: -1,\n isPlaying: false,\n playbackSpeed: 1.0,\n isRecording: autoRecord,\n };\n\n // State change listeners\n const listeners = new Set<(state: TimeTravelState) => void>();\n\n // Playback timer\n let playbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Notify all listeners of state change.\n */\n function notifyListeners(): void {\n const currentState = getState();\n for (const listener of listeners) {\n listener(currentState);\n }\n }\n\n /**\n * Sync state from builder snapshots.\n */\n function syncFromBuilder(): void {\n state.snapshots = builder.getSnapshots();\n if (state.isRecording && state.snapshots.length > 0) {\n state.currentIndex = state.snapshots.length - 1;\n }\n }\n\n /**\n * Handle a workflow event.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Always forward to builder\n builder.handleEvent(event);\n\n // Sync snapshots if recording\n if (state.isRecording) {\n syncFromBuilder();\n notifyListeners();\n }\n }\n\n /**\n * Seek to a specific snapshot index.\n */\n function seek(index: number): WorkflowIR | undefined {\n const snapshots = builder.getSnapshots();\n if (index < 0 || index >= snapshots.length) {\n return undefined;\n }\n\n state.currentIndex = index;\n state.snapshots = snapshots;\n notifyListeners();\n\n return snapshots[index].ir;\n }\n\n /**\n * Move one step forward.\n */\n function stepForward(): WorkflowIR | undefined {\n return seek(state.currentIndex + 1);\n }\n\n /**\n * Move one step backward.\n */\n function stepBackward(): WorkflowIR | undefined {\n return seek(state.currentIndex - 1);\n }\n\n /**\n * Start playback at given speed.\n */\n function play(speed = 1.0): void {\n state.playbackSpeed = speed;\n state.isPlaying = true;\n notifyListeners();\n\n const playNext = (): void => {\n if (!state.isPlaying) return;\n\n const snapshots = builder.getSnapshots();\n if (state.currentIndex < snapshots.length - 1) {\n const current = snapshots[state.currentIndex];\n const next = snapshots[state.currentIndex + 1];\n\n // Calculate delay based on actual event timing\n const realDelay = next.timestamp - current.timestamp;\n const scaledDelay = realDelay / state.playbackSpeed;\n\n playbackTimer = setTimeout(() => {\n stepForward();\n playNext();\n }, Math.max(16, scaledDelay)); // Minimum 16ms (~60fps) for smooth updates\n } else {\n // Reached end of timeline\n pause();\n }\n };\n\n playNext();\n }\n\n /**\n * Pause playback.\n */\n function pause(): void {\n state.isPlaying = false;\n if (playbackTimer) {\n clearTimeout(playbackTimer);\n playbackTimer = null;\n }\n notifyListeners();\n }\n\n /**\n * Get current IR state.\n */\n function getCurrentIR(): WorkflowIR {\n const snapshots = builder.getSnapshots();\n if (state.currentIndex >= 0 && state.currentIndex < snapshots.length) {\n return snapshots[state.currentIndex].ir;\n }\n // Return live IR if no valid snapshot\n return builder.getIR();\n }\n\n /**\n * Get IR at specific snapshot index.\n */\n function getIRAt(index: number): WorkflowIR | undefined {\n return builder.getIRAt(index);\n }\n\n /**\n * Get all snapshots.\n */\n function getSnapshots(): IRSnapshot[] {\n return builder.getSnapshots();\n }\n\n /**\n * Get snapshot at specific index.\n */\n function getSnapshotAt(index: number): IRSnapshot | undefined {\n return builder.getSnapshotAt(index);\n }\n\n /**\n * Get current time-travel state.\n */\n function getState(): TimeTravelState {\n return {\n snapshots: builder.getSnapshots(),\n currentIndex: state.currentIndex,\n isPlaying: state.isPlaying,\n playbackSpeed: state.playbackSpeed,\n isRecording: state.isRecording,\n };\n }\n\n /**\n * Subscribe to state changes.\n */\n function onStateChange(\n callback: (state: TimeTravelState) => void\n ): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n }\n\n /**\n * Start or resume recording.\n */\n function startRecording(): void {\n state.isRecording = true;\n notifyListeners();\n }\n\n /**\n * Stop recording.\n */\n function stopRecording(): void {\n state.isRecording = false;\n notifyListeners();\n }\n\n /**\n * Reset to initial state.\n */\n function reset(): void {\n pause();\n builder.reset();\n state = {\n snapshots: [],\n currentIndex: -1,\n isPlaying: false,\n playbackSpeed: 1.0,\n isRecording: autoRecord,\n };\n notifyListeners();\n }\n\n /**\n * Get the underlying IR builder.\n */\n function getBuilder(): IRBuilder {\n return builder;\n }\n\n return {\n handleEvent,\n seek,\n stepForward,\n stepBackward,\n play,\n pause,\n getCurrentIR,\n getIRAt,\n getSnapshots,\n getSnapshotAt,\n getState,\n onStateChange,\n startRecording,\n stopRecording,\n reset,\n getBuilder,\n };\n}\n","/**\n * Development Server\n *\n * Provides a local HTTP server with WebSocket support for:\n * - Serving the HTML visualizer\n * - Live streaming workflow events\n * - Time-travel control from the browser\n * - Performance data broadcasting\n *\n * The `ws` package is an optional peer dependency.\n * Install it with: npm install ws\n */\n\nimport type { Server as HTTPServer, IncomingMessage, ServerResponse } from \"node:http\";\nimport { createServer } from \"node:http\";\nimport { execFile } from \"node:child_process\";\nimport type { WorkflowEvent } from \"../core\";\nimport type { WorkflowIR, ServerMessage, WebVisualizerMessage, HeatmapData } from \"./types\";\nimport { createTimeTravelController, type TimeTravelController } from \"./time-travel\";\nimport { createPerformanceAnalyzer, type PerformanceAnalyzer } from \"./performance-analyzer\";\nimport { renderToHTML } from \"./renderers/html\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * WebSocket interface (matches `ws` package).\n */\ninterface WebSocketLike {\n send(data: string): void;\n on(event: \"message\", listener: (data: Buffer | string) => void): void;\n on(event: \"close\", listener: () => void): void;\n on(event: \"error\", listener: (error: Error) => void): void;\n readyState: number;\n OPEN: number;\n}\n\n/**\n * WebSocket server interface (matches `ws` package).\n */\ninterface WebSocketServerLike {\n clients: Set<WebSocketLike>;\n on(event: \"connection\", listener: (ws: WebSocketLike, req: IncomingMessage) => void): void;\n close(): void;\n}\n\n/**\n * Options for the dev server.\n */\nexport interface DevServerOptions {\n /** Port to listen on (default: 3377) */\n port?: number;\n /** Hostname to bind to (default: localhost) */\n host?: string;\n /** Auto-open browser when starting (default: true) */\n autoOpen?: boolean;\n /** Workflow name for the visualizer title */\n workflowName?: string;\n /** Enable time-travel debugging (default: true) */\n timeTravel?: boolean;\n /** Enable performance heatmap (default: true) */\n heatmap?: boolean;\n /** Max snapshots for time-travel (default: 1000) */\n maxSnapshots?: number;\n}\n\n/**\n * Dev server interface.\n */\nexport interface DevServer {\n /** Start the server */\n start(): Promise<{ port: number; url: string }>;\n /** Stop the server */\n stop(): Promise<void>;\n /** Handle a workflow event (forwards to time-travel and broadcasts) */\n handleEvent(event: WorkflowEvent<unknown>): void;\n /** Push an IR update to all clients */\n pushUpdate(ir: WorkflowIR): void;\n /** Push heatmap data to all clients */\n pushHeatmap(data: HeatmapData): void;\n /** Mark workflow as complete */\n complete(): void;\n /** Get the time-travel controller */\n getTimeTravel(): TimeTravelController;\n /** Get the performance analyzer */\n getAnalyzer(): PerformanceAnalyzer;\n /** Get current IR */\n getCurrentIR(): WorkflowIR;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Create a development server for the workflow visualizer.\n *\n * @example\n * ```typescript\n * const server = createDevServer({ port: 3377 });\n * await server.start();\n *\n * // Forward events from workflow execution\n * workflow.onEvent(event => server.handleEvent(event));\n *\n * // When done\n * server.complete();\n * await server.stop();\n * ```\n */\nexport async function createDevServer(\n options: DevServerOptions = {}\n): Promise<DevServer> {\n const {\n port = 3377,\n host = \"localhost\",\n autoOpen = true,\n workflowName = \"Workflow\",\n timeTravel = true,\n heatmap = true,\n maxSnapshots = 1000,\n } = options;\n\n // Suppress unused variable warning - workflowName reserved for future use\n void workflowName;\n\n // Create time-travel controller and performance analyzer\n const ttController = createTimeTravelController({ maxSnapshots });\n const analyzer = createPerformanceAnalyzer();\n\n // Server state\n let httpServer: HTTPServer | null = null;\n let wsServer: WebSocketServerLike | null = null;\n let actualPort = port;\n let isRunning = false;\n\n /**\n * Broadcast a message to all connected WebSocket clients.\n */\n function broadcast(message: ServerMessage): void {\n if (!wsServer) return;\n const data = JSON.stringify(message);\n for (const client of wsServer.clients) {\n if (client.readyState === client.OPEN) {\n client.send(data);\n }\n }\n }\n\n /**\n * Handle incoming WebSocket message.\n */\n function handleClientMessage(ws: WebSocketLike, raw: Buffer | string): void {\n try {\n const msg = JSON.parse(\n typeof raw === \"string\" ? raw : raw.toString()\n ) as WebVisualizerMessage;\n\n switch (msg.type) {\n case \"time_travel_seek\": {\n const payload = msg.payload as { index: number };\n const ir = ttController.seek(payload.index);\n if (ir) {\n ws.send(JSON.stringify({ type: \"ir_update\", payload: ir }));\n }\n break;\n }\n case \"time_travel_play\": {\n const payload = msg.payload as { speed?: number } | undefined;\n ttController.play(payload?.speed);\n break;\n }\n case \"time_travel_pause\":\n ttController.pause();\n break;\n case \"time_travel_step_forward\": {\n const ir = ttController.stepForward();\n if (ir) {\n ws.send(JSON.stringify({ type: \"ir_update\", payload: ir }));\n }\n break;\n }\n case \"time_travel_step_backward\": {\n const ir = ttController.stepBackward();\n if (ir) {\n ws.send(JSON.stringify({ type: \"ir_update\", payload: ir }));\n }\n break;\n }\n case \"request_snapshots\": {\n const snapshots = ttController.getSnapshots().map((s) => ({\n id: s.id,\n eventIndex: s.eventIndex,\n timestamp: s.timestamp,\n }));\n ws.send(JSON.stringify({ type: \"snapshots_list\", payload: snapshots }));\n break;\n }\n case \"toggle_heatmap\":\n case \"set_heatmap_metric\": {\n // Client handles these locally, but we can use to sync state\n break;\n }\n }\n } catch (e) {\n console.error(\"[DevServer] Failed to handle message:\", e);\n }\n }\n\n /**\n * Generate HTML for the current state.\n */\n function generatePage(): string {\n const ir = ttController.getCurrentIR();\n const wsUrl = `ws://${host}:${actualPort}`;\n\n return renderToHTML(ir, {\n interactive: true,\n timeTravel,\n heatmap,\n theme: \"auto\",\n layout: \"TB\",\n wsUrl,\n });\n }\n\n /**\n * Handle HTTP requests.\n */\n function handleRequest(req: IncomingMessage, res: ServerResponse): void {\n const url = req.url ?? \"/\";\n\n if (url === \"/\" || url === \"/index.html\") {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(generatePage());\n return;\n }\n\n if (url === \"/api/snapshots\") {\n const snapshots = ttController.getSnapshots().map((s) => ({\n id: s.id,\n eventIndex: s.eventIndex,\n timestamp: s.timestamp,\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(snapshots));\n return;\n }\n\n if (url === \"/api/performance\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(analyzer.exportData());\n return;\n }\n\n if (url === \"/api/ir\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(ttController.getCurrentIR()));\n return;\n }\n\n // 404\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not Found\");\n }\n\n /**\n * Try to dynamically import `ws` package.\n */\n async function loadWebSocketServer(): Promise<WebSocketServerLike | null> {\n try {\n // Dynamic import of optional peer dependency (ws is optional)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - ws is an optional peer dependency\n const wsModule = await import(\"ws\");\n const ws = wsModule as {\n WebSocketServer?: new (options: { noServer: boolean }) => WebSocketServerLike;\n default?: {\n WebSocketServer?: new (options: { noServer: boolean }) => WebSocketServerLike;\n };\n };\n const WebSocketServer = ws.WebSocketServer ?? ws.default?.WebSocketServer;\n if (!WebSocketServer) {\n console.warn(\"[DevServer] WebSocket server class not found in ws module\");\n return null;\n }\n return new WebSocketServer({ noServer: true });\n } catch {\n console.warn(\n \"[DevServer] ws package not installed. Live updates disabled.\\n\" +\n \"Install with: npm install ws\"\n );\n return null;\n }\n }\n\n /**\n * Open URL in browser using platform-specific command.\n * Uses execFile for safety (no shell injection possible).\n */\n function openBrowser(url: string): void {\n const platform = process.platform;\n\n // Validate URL format to ensure it's a localhost URL\n if (!url.startsWith(\"http://localhost:\") && !url.startsWith(\"http://127.0.0.1:\")) {\n console.warn(\"[DevServer] Refusing to open non-localhost URL\");\n return;\n }\n\n if (platform === \"darwin\") {\n execFile(\"open\", [url], (err) => {\n if (err) console.warn(\"[DevServer] Failed to open browser:\", err.message);\n });\n } else if (platform === \"win32\") {\n // On Windows, use cmd.exe with /c start to handle URLs properly\n execFile(\"cmd.exe\", [\"/c\", \"start\", \"\", url], (err) => {\n if (err) console.warn(\"[DevServer] Failed to open browser:\", err.message);\n });\n } else {\n // Linux and other Unix-like systems\n execFile(\"xdg-open\", [url], (err) => {\n if (err) console.warn(\"[DevServer] Failed to open browser:\", err.message);\n });\n }\n }\n\n // =============================================================================\n // Public Interface\n // =============================================================================\n\n async function start(): Promise<{ port: number; url: string }> {\n if (isRunning) {\n return { port: actualPort, url: `http://${host}:${actualPort}` };\n }\n\n // Create HTTP server\n httpServer = createServer(handleRequest);\n\n // Try to load WebSocket server\n wsServer = await loadWebSocketServer();\n\n if (wsServer) {\n // Handle WebSocket upgrade\n httpServer.on(\"upgrade\", (request, socket, head) => {\n if (!wsServer) return;\n\n // Manual WebSocket handshake\n const ws = wsServer as unknown as {\n handleUpgrade: (\n req: IncomingMessage,\n socket: unknown,\n head: Buffer,\n callback: (ws: WebSocketLike) => void\n ) => void;\n };\n\n ws.handleUpgrade(request, socket, head, (client) => {\n // Send initial state\n client.send(\n JSON.stringify({\n type: \"ir_update\",\n payload: ttController.getCurrentIR(),\n })\n );\n\n // Handle messages\n client.on(\"message\", (data) => handleClientMessage(client, data));\n client.on(\"error\", (err) => console.error(\"[DevServer] WS error:\", err));\n });\n });\n\n // Subscribe to time-travel state changes\n ttController.onStateChange((state) => {\n broadcast({ type: \"time_travel_state\", payload: state });\n });\n }\n\n // Start listening\n return new Promise((resolve, reject) => {\n if (!httpServer) {\n reject(new Error(\"HTTP server not initialized\"));\n return;\n }\n\n httpServer.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Try next port\n actualPort++;\n httpServer?.listen(actualPort, host);\n } else {\n reject(err);\n }\n });\n\n httpServer.on(\"listening\", () => {\n isRunning = true;\n const url = `http://${host}:${actualPort}`;\n console.log(`[DevServer] Visualizer running at ${url}`);\n\n if (autoOpen) {\n openBrowser(url);\n }\n\n resolve({ port: actualPort, url });\n });\n\n httpServer.listen(actualPort, host);\n });\n }\n\n async function stop(): Promise<void> {\n if (!isRunning) return;\n\n return new Promise((resolve) => {\n if (wsServer) {\n wsServer.close();\n wsServer = null;\n }\n\n if (httpServer) {\n httpServer.close(() => {\n httpServer = null;\n isRunning = false;\n resolve();\n });\n } else {\n resolve();\n }\n });\n }\n\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Forward to time-travel controller\n ttController.handleEvent(event);\n\n // Forward to performance analyzer\n analyzer.addEvent(event);\n\n // Broadcast IR update\n broadcast({ type: \"ir_update\", payload: ttController.getCurrentIR() });\n }\n\n function pushUpdate(ir: WorkflowIR): void {\n broadcast({ type: \"ir_update\", payload: ir });\n }\n\n function pushHeatmap(data: HeatmapData): void {\n // Convert Map to object for JSON serialization\n const heat: Record<string, number> = {};\n for (const [k, v] of data.heat) {\n heat[k] = v;\n }\n broadcast({\n type: \"performance_data\",\n payload: { ...data, heat },\n });\n }\n\n function complete(): void {\n // Finalize analyzer run\n analyzer.finalizeRun(\"current\");\n broadcast({ type: \"workflow_complete\", payload: null });\n }\n\n function getTimeTravel(): TimeTravelController {\n return ttController;\n }\n\n function getAnalyzer(): PerformanceAnalyzer {\n return analyzer;\n }\n\n function getCurrentIR(): WorkflowIR {\n return ttController.getCurrentIR();\n }\n\n return {\n start,\n stop,\n handleEvent,\n pushUpdate,\n pushHeatmap,\n complete,\n getTimeTravel,\n getAnalyzer,\n getCurrentIR,\n };\n}\n"],"mappings":"6qBAAA,IAAAA,EAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAe,CAAC,aAAc,cAAe,WAAW,EACxDC,GAAU,OAAO,KAAS,IAE5BA,IAASD,GAAa,KAAK,MAAM,EAErCD,GAAO,QAAU,CACf,aAAAC,GACA,cAAe,IACf,aAAc,OAAO,MAAM,CAAC,EAC5B,KAAM,uCACN,QAAAC,GACA,qBAAsB,OAAO,wBAAwB,EACrD,UAAW,OAAO,WAAW,EAC7B,YAAa,OAAO,aAAa,EACjC,WAAY,OAAO,WAAW,EAC9B,KAAM,IAAM,CAAC,CACf,IClBA,IAAAC,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CAAE,aAAAC,EAAa,EAAI,IAEnBC,GAAa,OAAO,OAAO,OAAO,EAUxC,SAASC,GAAOC,EAAMC,EAAa,CACjC,GAAID,EAAK,SAAW,EAAG,OAAOH,GAC9B,GAAIG,EAAK,SAAW,EAAG,OAAOA,EAAK,CAAC,EAEpC,IAAME,EAAS,OAAO,YAAYD,CAAW,EACzCE,EAAS,EAEb,QAASC,EAAI,EAAGA,EAAIJ,EAAK,OAAQI,IAAK,CACpC,IAAMC,EAAML,EAAKI,CAAC,EAClBF,EAAO,IAAIG,EAAKF,CAAM,EACtBA,GAAUE,EAAI,MAChB,CAEA,OAAIF,EAASF,EACJ,IAAIH,GAAWI,EAAO,OAAQA,EAAO,WAAYC,CAAM,EAGzDD,CACT,CAYA,SAASI,GAAMC,EAAQC,EAAMC,EAAQN,EAAQO,EAAQ,CACnD,QAASN,EAAI,EAAGA,EAAIM,EAAQN,IAC1BK,EAAON,EAASC,CAAC,EAAIG,EAAOH,CAAC,EAAII,EAAKJ,EAAI,CAAC,CAE/C,CASA,SAASO,GAAQC,EAAQJ,EAAM,CAC7B,QAASJ,EAAI,EAAGA,EAAIQ,EAAO,OAAQR,IACjCQ,EAAOR,CAAC,GAAKI,EAAKJ,EAAI,CAAC,CAE3B,CASA,SAASS,GAAcR,EAAK,CAC1B,OAAIA,EAAI,SAAWA,EAAI,OAAO,WACrBA,EAAI,OAGNA,EAAI,OAAO,MAAMA,EAAI,WAAYA,EAAI,WAAaA,EAAI,MAAM,CACrE,CAUA,SAASS,GAASC,EAAM,CAGtB,GAFAD,GAAS,SAAW,GAEhB,OAAO,SAASC,CAAI,EAAG,OAAOA,EAElC,IAAIV,EAEJ,OAAIU,aAAgB,YAClBV,EAAM,IAAIP,GAAWiB,CAAI,EAChB,YAAY,OAAOA,CAAI,EAChCV,EAAM,IAAIP,GAAWiB,EAAK,OAAQA,EAAK,WAAYA,EAAK,UAAU,GAElEV,EAAM,OAAO,KAAKU,CAAI,EACtBD,GAAS,SAAW,IAGfT,CACT,CAEAT,GAAO,QAAU,CACf,OAAAG,GACA,KAAMO,GACN,cAAAO,GACA,SAAAC,GACA,OAAQH,EACV,EAGA,GAAI,CAAC,QAAQ,IAAI,kBACf,GAAI,CACF,IAAMK,EAAa,QAAQ,YAAY,EAEvCpB,GAAO,QAAQ,KAAO,SAAUW,EAAQC,EAAMC,EAAQN,EAAQO,EAAQ,CAChEA,EAAS,GAAIJ,GAAMC,EAAQC,EAAMC,EAAQN,EAAQO,CAAM,EACtDM,EAAW,KAAKT,EAAQC,EAAMC,EAAQN,EAAQO,CAAM,CAC3D,EAEAd,GAAO,QAAQ,OAAS,SAAUgB,EAAQJ,EAAM,CAC1CI,EAAO,OAAS,GAAID,GAAQC,EAAQJ,CAAI,EACvCQ,EAAW,OAAOJ,EAAQJ,CAAI,CACrC,CACF,MAAY,CAEZ,ICjIF,IAAAS,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAQ,OAAO,OAAO,EACtBC,GAAO,OAAO,MAAM,EAMpBC,GAAN,KAAc,CAOZ,YAAYC,EAAa,CACvB,KAAKH,EAAK,EAAI,IAAM,CAClB,KAAK,UACL,KAAKC,EAAI,EAAE,CACb,EACA,KAAK,YAAcE,GAAe,IAClC,KAAK,KAAO,CAAC,EACb,KAAK,QAAU,CACjB,CAQA,IAAIC,EAAK,CACP,KAAK,KAAK,KAAKA,CAAG,EAClB,KAAKH,EAAI,EAAE,CACb,CAOA,CAACA,EAAI,GAAI,CACP,GAAI,KAAK,UAAY,KAAK,aAEtB,KAAK,KAAK,OAAQ,CACpB,IAAMG,EAAM,KAAK,KAAK,MAAM,EAE5B,KAAK,UACLA,EAAI,KAAKJ,EAAK,CAAC,CACjB,CACF,CACF,EAEAD,GAAO,QAAUG,KCtDjB,IAAAG,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,IAAMC,GAAO,QAAQ,MAAM,EAErBC,GAAa,KACbC,GAAU,KACV,CAAE,YAAAC,EAAY,EAAI,IAElBC,GAAa,OAAO,OAAO,OAAO,EAClCC,GAAU,OAAO,KAAK,CAAC,EAAM,EAAM,IAAM,GAAI,CAAC,EAC9CC,GAAqB,OAAO,oBAAoB,EAChDC,GAAe,OAAO,cAAc,EACpCC,GAAY,OAAO,UAAU,EAC7BC,GAAW,OAAO,SAAS,EAC3BC,GAAS,OAAO,OAAO,EASzBC,GAKEC,GAAN,KAAwB,CAyBtB,YAAYC,EAASC,EAAUC,EAAY,CAWzC,GAVA,KAAK,YAAcA,EAAa,EAChC,KAAK,SAAWF,GAAW,CAAC,EAC5B,KAAK,WACH,KAAK,SAAS,YAAc,OAAY,KAAK,SAAS,UAAY,KACpE,KAAK,UAAY,CAAC,CAACC,EACnB,KAAK,SAAW,KAChB,KAAK,SAAW,KAEhB,KAAK,OAAS,KAEV,CAACH,GAAa,CAChB,IAAMK,EACJ,KAAK,SAAS,mBAAqB,OAC/B,KAAK,SAAS,iBACd,GACNL,GAAc,IAAIT,GAAQc,CAAW,CACvC,CACF,CAKA,WAAW,eAAgB,CACzB,MAAO,oBACT,CAQA,OAAQ,CACN,IAAMC,EAAS,CAAC,EAEhB,OAAI,KAAK,SAAS,0BAChBA,EAAO,2BAA6B,IAElC,KAAK,SAAS,0BAChBA,EAAO,2BAA6B,IAElC,KAAK,SAAS,sBAChBA,EAAO,uBAAyB,KAAK,SAAS,qBAE5C,KAAK,SAAS,oBAChBA,EAAO,uBAAyB,KAAK,SAAS,oBACrC,KAAK,SAAS,qBAAuB,OAC9CA,EAAO,uBAAyB,IAG3BA,CACT,CASA,OAAOC,EAAgB,CACrB,OAAAA,EAAiB,KAAK,gBAAgBA,CAAc,EAEpD,KAAK,OAAS,KAAK,UACf,KAAK,eAAeA,CAAc,EAClC,KAAK,eAAeA,CAAc,EAE/B,KAAK,MACd,CAOA,SAAU,CAMR,GALI,KAAK,WACP,KAAK,SAAS,MAAM,EACpB,KAAK,SAAW,MAGd,KAAK,SAAU,CACjB,IAAMC,EAAW,KAAK,SAASX,EAAS,EAExC,KAAK,SAAS,MAAM,EACpB,KAAK,SAAW,KAEZW,GACFA,EACE,IAAI,MACF,8DACF,CACF,CAEJ,CACF,CASA,eAAeC,EAAQ,CACrB,IAAMC,EAAO,KAAK,SACZC,EAAWF,EAAO,KAAMH,GAEzB,EAAAI,EAAK,0BAA4B,IAChCJ,EAAO,4BACRA,EAAO,yBACLI,EAAK,sBAAwB,IAC3B,OAAOA,EAAK,qBAAwB,UACnCA,EAAK,oBAAsBJ,EAAO,yBACvC,OAAOI,EAAK,qBAAwB,UACnC,CAACJ,EAAO,uBAMb,EAED,GAAI,CAACK,EACH,MAAM,IAAI,MAAM,8CAA8C,EAGhE,OAAID,EAAK,0BACPC,EAAS,2BAA6B,IAEpCD,EAAK,0BACPC,EAAS,2BAA6B,IAEpC,OAAOD,EAAK,qBAAwB,WACtCC,EAAS,uBAAyBD,EAAK,qBAErC,OAAOA,EAAK,qBAAwB,SACtCC,EAAS,uBAAyBD,EAAK,qBAEvCC,EAAS,yBAA2B,IACpCD,EAAK,sBAAwB,KAE7B,OAAOC,EAAS,uBAGXA,CACT,CASA,eAAeC,EAAU,CACvB,IAAMN,EAASM,EAAS,CAAC,EAEzB,GACE,KAAK,SAAS,0BAA4B,IAC1CN,EAAO,2BAEP,MAAM,IAAI,MAAM,mDAAmD,EAGrE,GAAI,CAACA,EAAO,uBACN,OAAO,KAAK,SAAS,qBAAwB,WAC/CA,EAAO,uBAAyB,KAAK,SAAS,6BAGhD,KAAK,SAAS,sBAAwB,IACrC,OAAO,KAAK,SAAS,qBAAwB,UAC5CA,EAAO,uBAAyB,KAAK,SAAS,oBAEhD,MAAM,IAAI,MACR,0DACF,EAGF,OAAOA,CACT,CASA,gBAAgBC,EAAgB,CAC9B,OAAAA,EAAe,QAASD,GAAW,CACjC,OAAO,KAAKA,CAAM,EAAE,QAASO,GAAQ,CACnC,IAAIC,EAAQR,EAAOO,CAAG,EAEtB,GAAIC,EAAM,OAAS,EACjB,MAAM,IAAI,MAAM,cAAcD,CAAG,iCAAiC,EAKpE,GAFAC,EAAQA,EAAM,CAAC,EAEXD,IAAQ,0BACV,GAAIC,IAAU,GAAM,CAClB,IAAMC,EAAM,CAACD,EACb,GAAI,CAAC,OAAO,UAAUC,CAAG,GAAKA,EAAM,GAAKA,EAAM,GAC7C,MAAM,IAAI,UACR,gCAAgCF,CAAG,MAAMC,CAAK,EAChD,EAEFA,EAAQC,CACV,SAAW,CAAC,KAAK,UACf,MAAM,IAAI,UACR,gCAAgCF,CAAG,MAAMC,CAAK,EAChD,UAEOD,IAAQ,yBAA0B,CAC3C,IAAME,EAAM,CAACD,EACb,GAAI,CAAC,OAAO,UAAUC,CAAG,GAAKA,EAAM,GAAKA,EAAM,GAC7C,MAAM,IAAI,UACR,gCAAgCF,CAAG,MAAMC,CAAK,EAChD,EAEFA,EAAQC,CACV,SACEF,IAAQ,8BACRA,IAAQ,8BAER,GAAIC,IAAU,GACZ,MAAM,IAAI,UACR,gCAAgCD,CAAG,MAAMC,CAAK,EAChD,MAGF,OAAM,IAAI,MAAM,sBAAsBD,CAAG,GAAG,EAG9CP,EAAOO,CAAG,EAAIC,CAChB,CAAC,CACH,CAAC,EAEMP,CACT,CAUA,WAAWS,EAAMC,EAAKT,EAAU,CAC9BR,GAAY,IAAKkB,GAAS,CACxB,KAAK,YAAYF,EAAMC,EAAK,CAACE,EAAKC,IAAW,CAC3CF,EAAK,EACLV,EAASW,EAAKC,CAAM,CACtB,CAAC,CACH,CAAC,CACH,CAUA,SAASJ,EAAMC,EAAKT,EAAU,CAC5BR,GAAY,IAAKkB,GAAS,CACxB,KAAK,UAAUF,EAAMC,EAAK,CAACE,EAAKC,IAAW,CACzCF,EAAK,EACLV,EAASW,EAAKC,CAAM,CACtB,CAAC,CACH,CAAC,CACH,CAUA,YAAYJ,EAAMC,EAAKT,EAAU,CAC/B,IAAMa,EAAW,KAAK,UAAY,SAAW,SAE7C,GAAI,CAAC,KAAK,SAAU,CAClB,IAAMR,EAAM,GAAGQ,CAAQ,mBACjBC,EACJ,OAAO,KAAK,OAAOT,CAAG,GAAM,SACxBxB,GAAK,qBACL,KAAK,OAAOwB,CAAG,EAErB,KAAK,SAAWxB,GAAK,iBAAiB,CACpC,GAAG,KAAK,SAAS,mBACjB,WAAAiC,CACF,CAAC,EACD,KAAK,SAAS3B,EAAkB,EAAI,KACpC,KAAK,SAASC,EAAY,EAAI,EAC9B,KAAK,SAASE,EAAQ,EAAI,CAAC,EAC3B,KAAK,SAAS,GAAG,QAASyB,EAAc,EACxC,KAAK,SAAS,GAAG,OAAQC,EAAa,CACxC,CAEA,KAAK,SAAS3B,EAAS,EAAIW,EAE3B,KAAK,SAAS,MAAMQ,CAAI,EACpBC,GAAK,KAAK,SAAS,MAAMvB,EAAO,EAEpC,KAAK,SAAS,MAAM,IAAM,CACxB,IAAMyB,EAAM,KAAK,SAASpB,EAAM,EAEhC,GAAIoB,EAAK,CACP,KAAK,SAAS,MAAM,EACpB,KAAK,SAAW,KAChBX,EAASW,CAAG,EACZ,MACF,CAEA,IAAMH,EAAO1B,GAAW,OACtB,KAAK,SAASQ,EAAQ,EACtB,KAAK,SAASF,EAAY,CAC5B,EAEI,KAAK,SAAS,eAAe,YAC/B,KAAK,SAAS,MAAM,EACpB,KAAK,SAAW,OAEhB,KAAK,SAASA,EAAY,EAAI,EAC9B,KAAK,SAASE,EAAQ,EAAI,CAAC,EAEvBmB,GAAO,KAAK,OAAO,GAAGI,CAAQ,sBAAsB,GACtD,KAAK,SAAS,MAAM,GAIxBb,EAAS,KAAMQ,CAAI,CACrB,CAAC,CACH,CAUA,UAAUA,EAAMC,EAAKT,EAAU,CAC7B,IAAMa,EAAW,KAAK,UAAY,SAAW,SAE7C,GAAI,CAAC,KAAK,SAAU,CAClB,IAAMR,EAAM,GAAGQ,CAAQ,mBACjBC,EACJ,OAAO,KAAK,OAAOT,CAAG,GAAM,SACxBxB,GAAK,qBACL,KAAK,OAAOwB,CAAG,EAErB,KAAK,SAAWxB,GAAK,iBAAiB,CACpC,GAAG,KAAK,SAAS,mBACjB,WAAAiC,CACF,CAAC,EAED,KAAK,SAAS1B,EAAY,EAAI,EAC9B,KAAK,SAASE,EAAQ,EAAI,CAAC,EAE3B,KAAK,SAAS,GAAG,OAAQ2B,EAAa,CACxC,CAEA,KAAK,SAAS5B,EAAS,EAAIW,EAE3B,KAAK,SAAS,MAAMQ,CAAI,EACxB,KAAK,SAAS,MAAM3B,GAAK,aAAc,IAAM,CAC3C,GAAI,CAAC,KAAK,SAIR,OAGF,IAAI2B,EAAO1B,GAAW,OACpB,KAAK,SAASQ,EAAQ,EACtB,KAAK,SAASF,EAAY,CAC5B,EAEIqB,IACFD,EAAO,IAAIvB,GAAWuB,EAAK,OAAQA,EAAK,WAAYA,EAAK,OAAS,CAAC,GAOrE,KAAK,SAASnB,EAAS,EAAI,KAE3B,KAAK,SAASD,EAAY,EAAI,EAC9B,KAAK,SAASE,EAAQ,EAAI,CAAC,EAEvBmB,GAAO,KAAK,OAAO,GAAGI,CAAQ,sBAAsB,GACtD,KAAK,SAAS,MAAM,EAGtBb,EAAS,KAAMQ,CAAI,CACrB,CAAC,CACH,CACF,EAEA5B,GAAO,QAAUa,GAQjB,SAASwB,GAAcC,EAAO,CAC5B,KAAK5B,EAAQ,EAAE,KAAK4B,CAAK,EACzB,KAAK9B,EAAY,GAAK8B,EAAM,MAC9B,CAQA,SAASF,GAAcE,EAAO,CAG5B,GAFA,KAAK9B,EAAY,GAAK8B,EAAM,OAG1B,KAAK/B,EAAkB,EAAE,YAAc,GACvC,KAAKC,EAAY,GAAK,KAAKD,EAAkB,EAAE,YAC/C,CACA,KAAKG,EAAQ,EAAE,KAAK4B,CAAK,EACzB,MACF,CAEA,KAAK3B,EAAM,EAAI,IAAI,WAAW,2BAA2B,EACzD,KAAKA,EAAM,EAAE,KAAO,oCACpB,KAAKA,EAAM,EAAEP,EAAW,EAAI,KAC5B,KAAK,eAAe,OAAQgC,EAAa,EASzC,KAAK,MAAM,CACb,CAQA,SAASD,GAAeJ,EAAK,CAO3B,GAFA,KAAKxB,EAAkB,EAAE,SAAW,KAEhC,KAAKI,EAAM,EAAG,CAChB,KAAKF,EAAS,EAAE,KAAKE,EAAM,CAAC,EAC5B,MACF,CAEAoB,EAAI3B,EAAW,EAAI,KACnB,KAAKK,EAAS,EAAEsB,CAAG,CACrB,IC/gBA,IAAAQ,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CAAE,OAAAC,EAAO,EAAI,QAAQ,QAAQ,EAE7B,CAAE,QAAAC,EAAQ,EAAI,IAcdC,GAAa,CACjB,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAC7C,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAC/C,EASA,SAASC,GAAkBC,EAAM,CAC/B,OACGA,GAAQ,KACPA,GAAQ,MACRA,IAAS,MACTA,IAAS,MACTA,IAAS,MACVA,GAAQ,KAAQA,GAAQ,IAE7B,CAWA,SAASC,GAAaC,EAAK,CACzB,IAAMC,EAAMD,EAAI,OACZE,EAAI,EAER,KAAOA,EAAID,GACT,IAAKD,EAAIE,CAAC,EAAI,OAAU,EAEtBA,aACUF,EAAIE,CAAC,EAAI,OAAU,IAAM,CAEnC,GACEA,EAAI,IAAMD,IACTD,EAAIE,EAAI,CAAC,EAAI,OAAU,MACvBF,EAAIE,CAAC,EAAI,OAAU,IAEpB,MAAO,GAGTA,GAAK,CACP,UAAYF,EAAIE,CAAC,EAAI,OAAU,IAAM,CAEnC,GACEA,EAAI,GAAKD,IACRD,EAAIE,EAAI,CAAC,EAAI,OAAU,MACvBF,EAAIE,EAAI,CAAC,EAAI,OAAU,KACvBF,EAAIE,CAAC,IAAM,MAASF,EAAIE,EAAI,CAAC,EAAI,OAAU,KAC3CF,EAAIE,CAAC,IAAM,MAASF,EAAIE,EAAI,CAAC,EAAI,OAAU,IAE5C,MAAO,GAGTA,GAAK,CACP,UAAYF,EAAIE,CAAC,EAAI,OAAU,IAAM,CAEnC,GACEA,EAAI,GAAKD,IACRD,EAAIE,EAAI,CAAC,EAAI,OAAU,MACvBF,EAAIE,EAAI,CAAC,EAAI,OAAU,MACvBF,EAAIE,EAAI,CAAC,EAAI,OAAU,KACvBF,EAAIE,CAAC,IAAM,MAASF,EAAIE,EAAI,CAAC,EAAI,OAAU,KAC3CF,EAAIE,CAAC,IAAM,KAAQF,EAAIE,EAAI,CAAC,EAAI,KACjCF,EAAIE,CAAC,EAAI,IAET,MAAO,GAGTA,GAAK,CACP,KACE,OAAO,GAIX,MAAO,EACT,CASA,SAASC,GAAOC,EAAO,CACrB,OACET,IACA,OAAOS,GAAU,UACjB,OAAOA,EAAM,aAAgB,YAC7B,OAAOA,EAAM,MAAS,UACtB,OAAOA,EAAM,QAAW,aACvBA,EAAM,OAAO,WAAW,IAAM,QAC7BA,EAAM,OAAO,WAAW,IAAM,OAEpC,CAEAX,GAAO,QAAU,CACf,OAAAU,GACA,kBAAAN,GACA,YAAaE,GACb,WAAAH,EACF,EAEA,GAAIF,GACFD,GAAO,QAAQ,YAAc,SAAUO,EAAK,CAC1C,OAAOA,EAAI,OAAS,GAAKD,GAAaC,CAAG,EAAIN,GAAOM,CAAG,CACzD,UACqC,CAAC,QAAQ,IAAI,qBAClD,GAAI,CACF,IAAMK,EAAc,QAAQ,gBAAgB,EAE5CZ,GAAO,QAAQ,YAAc,SAAUO,EAAK,CAC1C,OAAOA,EAAI,OAAS,GAAKD,GAAaC,CAAG,EAAIK,EAAYL,CAAG,CAC9D,CACF,MAAY,CAEZ,ICtJF,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CAAE,SAAAC,EAAS,EAAI,QAAQ,QAAQ,EAE/BC,GAAoB,KACpB,CACJ,aAAAC,GACA,aAAAC,GACA,YAAAC,GACA,WAAAC,EACF,EAAI,IACE,CAAE,OAAAC,GAAQ,cAAAC,GAAe,OAAAC,EAAO,EAAI,KACpC,CAAE,kBAAAC,GAAmB,YAAAC,EAAY,EAAI,KAErCC,GAAa,OAAO,OAAO,OAAO,EAElCC,EAAW,EACXC,GAAwB,EACxBC,GAAwB,EACxBC,GAAW,EACXC,GAAW,EACXC,GAAY,EACZC,GAAc,EAOdC,GAAN,cAAuBnB,EAAS,CAiB9B,YAAYoB,EAAU,CAAC,EAAG,CACxB,MAAM,EAEN,KAAK,wBACHA,EAAQ,yBAA2B,OAC/BA,EAAQ,uBACR,GACN,KAAK,YAAcA,EAAQ,YAAclB,GAAa,CAAC,EACvD,KAAK,YAAckB,EAAQ,YAAc,CAAC,EAC1C,KAAK,UAAY,CAAC,CAACA,EAAQ,SAC3B,KAAK,YAAcA,EAAQ,WAAa,EACxC,KAAK,oBAAsB,CAAC,CAACA,EAAQ,mBACrC,KAAKf,EAAU,EAAI,OAEnB,KAAK,eAAiB,EACtB,KAAK,SAAW,CAAC,EAEjB,KAAK,YAAc,GACnB,KAAK,eAAiB,EACtB,KAAK,MAAQ,OACb,KAAK,YAAc,EACnB,KAAK,QAAU,GACf,KAAK,KAAO,GACZ,KAAK,QAAU,EAEf,KAAK,oBAAsB,EAC3B,KAAK,eAAiB,EACtB,KAAK,WAAa,CAAC,EAEnB,KAAK,SAAW,GAChB,KAAK,MAAQ,GACb,KAAK,OAASO,CAChB,CAUA,OAAOS,EAAOC,EAAUC,EAAI,CAC1B,GAAI,KAAK,UAAY,GAAQ,KAAK,QAAUX,EAAU,OAAOW,EAAG,EAEhE,KAAK,gBAAkBF,EAAM,OAC7B,KAAK,SAAS,KAAKA,CAAK,EACxB,KAAK,UAAUE,CAAE,CACnB,CASA,QAAQC,EAAG,CAGT,GAFA,KAAK,gBAAkBA,EAEnBA,IAAM,KAAK,SAAS,CAAC,EAAE,OAAQ,OAAO,KAAK,SAAS,MAAM,EAE9D,GAAIA,EAAI,KAAK,SAAS,CAAC,EAAE,OAAQ,CAC/B,IAAMC,EAAM,KAAK,SAAS,CAAC,EAC3B,YAAK,SAAS,CAAC,EAAI,IAAId,GACrBc,EAAI,OACJA,EAAI,WAAaD,EACjBC,EAAI,OAASD,CACf,EAEO,IAAIb,GAAWc,EAAI,OAAQA,EAAI,WAAYD,CAAC,CACrD,CAEA,IAAME,EAAM,OAAO,YAAYF,CAAC,EAEhC,EAAG,CACD,IAAMC,EAAM,KAAK,SAAS,CAAC,EACrBE,EAASD,EAAI,OAASF,EAExBA,GAAKC,EAAI,OACXC,EAAI,IAAI,KAAK,SAAS,MAAM,EAAGC,CAAM,GAErCD,EAAI,IAAI,IAAI,WAAWD,EAAI,OAAQA,EAAI,WAAYD,CAAC,EAAGG,CAAM,EAC7D,KAAK,SAAS,CAAC,EAAI,IAAIhB,GACrBc,EAAI,OACJA,EAAI,WAAaD,EACjBC,EAAI,OAASD,CACf,GAGFA,GAAKC,EAAI,MACX,OAASD,EAAI,GAEb,OAAOE,CACT,CAQA,UAAUH,EAAI,CACZ,KAAK,MAAQ,GAEb,EACE,QAAQ,KAAK,OAAQ,CACnB,KAAKX,EACH,KAAK,QAAQW,CAAE,EACf,MACF,KAAKV,GACH,KAAK,mBAAmBU,CAAE,EAC1B,MACF,KAAKT,GACH,KAAK,mBAAmBS,CAAE,EAC1B,MACF,KAAKR,GACH,KAAK,QAAQ,EACb,MACF,KAAKC,GACH,KAAK,QAAQO,CAAE,EACf,MACF,KAAKN,GACL,KAAKC,GACH,KAAK,MAAQ,GACb,MACJ,OACO,KAAK,OAET,KAAK,UAAUK,EAAG,CACzB,CAQA,QAAQA,EAAI,CACV,GAAI,KAAK,eAAiB,EAAG,CAC3B,KAAK,MAAQ,GACb,MACF,CAEA,IAAME,EAAM,KAAK,QAAQ,CAAC,EAE1B,IAAKA,EAAI,CAAC,EAAI,MAAU,EAAM,CAC5B,IAAMG,EAAQ,KAAK,YACjB,WACA,8BACA,GACA,KACA,2BACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,IAAMC,GAAcJ,EAAI,CAAC,EAAI,MAAU,GAEvC,GAAII,GAAc,CAAC,KAAK,YAAY5B,GAAkB,aAAa,EAAG,CACpE,IAAM2B,EAAQ,KAAK,YACjB,WACA,qBACA,GACA,KACA,yBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAMA,GAJA,KAAK,MAAQH,EAAI,CAAC,EAAI,OAAU,IAChC,KAAK,QAAUA,EAAI,CAAC,EAAI,GACxB,KAAK,eAAiBA,EAAI,CAAC,EAAI,IAE3B,KAAK,UAAY,EAAM,CACzB,GAAII,EAAY,CACd,IAAMD,EAAQ,KAAK,YACjB,WACA,qBACA,GACA,KACA,yBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,GAAI,CAAC,KAAK,YAAa,CACrB,IAAMA,EAAQ,KAAK,YACjB,WACA,mBACA,GACA,KACA,uBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,KAAK,QAAU,KAAK,WACtB,SAAW,KAAK,UAAY,GAAQ,KAAK,UAAY,EAAM,CACzD,GAAI,KAAK,YAAa,CACpB,IAAMA,EAAQ,KAAK,YACjB,WACA,kBAAkB,KAAK,OAAO,GAC9B,GACA,KACA,uBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,KAAK,YAAcC,CACrB,SAAW,KAAK,QAAU,GAAQ,KAAK,QAAU,GAAM,CACrD,GAAI,CAAC,KAAK,KAAM,CACd,IAAMD,EAAQ,KAAK,YACjB,WACA,kBACA,GACA,KACA,qBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,GAAIC,EAAY,CACd,IAAMD,EAAQ,KAAK,YACjB,WACA,qBACA,GACA,KACA,yBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,GACE,KAAK,eAAiB,KACrB,KAAK,UAAY,GAAQ,KAAK,iBAAmB,EAClD,CACA,IAAMA,EAAQ,KAAK,YACjB,WACA,0BAA0B,KAAK,cAAc,GAC7C,GACA,KACA,uCACF,EAEAL,EAAGK,CAAK,EACR,MACF,CACF,KAAO,CACL,IAAMA,EAAQ,KAAK,YACjB,WACA,kBAAkB,KAAK,OAAO,GAC9B,GACA,KACA,uBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAKA,GAHI,CAAC,KAAK,MAAQ,CAAC,KAAK,cAAa,KAAK,YAAc,KAAK,SAC7D,KAAK,SAAWH,EAAI,CAAC,EAAI,OAAU,IAE/B,KAAK,WACP,GAAI,CAAC,KAAK,QAAS,CACjB,IAAMG,EAAQ,KAAK,YACjB,WACA,mBACA,GACA,KACA,sBACF,EAEAL,EAAGK,CAAK,EACR,MACF,UACS,KAAK,QAAS,CACvB,IAAMA,EAAQ,KAAK,YACjB,WACA,qBACA,GACA,KACA,wBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEI,KAAK,iBAAmB,IAAK,KAAK,OAASf,GACtC,KAAK,iBAAmB,IAAK,KAAK,OAASC,GAC/C,KAAK,WAAWS,CAAE,CACzB,CAQA,mBAAmBA,EAAI,CACrB,GAAI,KAAK,eAAiB,EAAG,CAC3B,KAAK,MAAQ,GACb,MACF,CAEA,KAAK,eAAiB,KAAK,QAAQ,CAAC,EAAE,aAAa,CAAC,EACpD,KAAK,WAAWA,CAAE,CACpB,CAQA,mBAAmBA,EAAI,CACrB,GAAI,KAAK,eAAiB,EAAG,CAC3B,KAAK,MAAQ,GACb,MACF,CAEA,IAAME,EAAM,KAAK,QAAQ,CAAC,EACpBK,EAAML,EAAI,aAAa,CAAC,EAM9B,GAAIK,EAAM,KAAK,IAAI,EAAG,EAAO,EAAI,EAAG,CAClC,IAAMF,EAAQ,KAAK,YACjB,WACA,yDACA,GACA,KACA,wCACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,KAAK,eAAiBE,EAAM,KAAK,IAAI,EAAG,EAAE,EAAIL,EAAI,aAAa,CAAC,EAChE,KAAK,WAAWF,CAAE,CACpB,CAQA,WAAWA,EAAI,CACb,GAAI,KAAK,gBAAkB,KAAK,QAAU,IACxC,KAAK,qBAAuB,KAAK,eAC7B,KAAK,oBAAsB,KAAK,aAAe,KAAK,YAAc,GAAG,CACvE,IAAMK,EAAQ,KAAK,YACjB,WACA,4BACA,GACA,KACA,mCACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAGE,KAAK,QAAS,KAAK,OAASb,GAC3B,KAAK,OAASC,EACrB,CAOA,SAAU,CACR,GAAI,KAAK,eAAiB,EAAG,CAC3B,KAAK,MAAQ,GACb,MACF,CAEA,KAAK,MAAQ,KAAK,QAAQ,CAAC,EAC3B,KAAK,OAASA,EAChB,CAQA,QAAQO,EAAI,CACV,IAAIQ,EAAO5B,GAEX,GAAI,KAAK,eAAgB,CACvB,GAAI,KAAK,eAAiB,KAAK,eAAgB,CAC7C,KAAK,MAAQ,GACb,MACF,CAEA4B,EAAO,KAAK,QAAQ,KAAK,cAAc,EAGrC,KAAK,UACJ,KAAK,MAAM,CAAC,EAAI,KAAK,MAAM,CAAC,EAAI,KAAK,MAAM,CAAC,EAAI,KAAK,MAAM,CAAC,KAAO,GAEpEvB,GAAOuB,EAAM,KAAK,KAAK,CAE3B,CAEA,GAAI,KAAK,QAAU,EAAM,CACvB,KAAK,eAAeA,EAAMR,CAAE,EAC5B,MACF,CAEA,GAAI,KAAK,YAAa,CACpB,KAAK,OAASN,GACd,KAAK,WAAWc,EAAMR,CAAE,EACxB,MACF,CAEIQ,EAAK,SAKP,KAAK,eAAiB,KAAK,oBAC3B,KAAK,WAAW,KAAKA,CAAI,GAG3B,KAAK,YAAYR,CAAE,CACrB,CASA,WAAWQ,EAAMR,EAAI,CACO,KAAK,YAAYtB,GAAkB,aAAa,EAExD,WAAW8B,EAAM,KAAK,KAAM,CAACC,EAAKP,IAAQ,CAC1D,GAAIO,EAAK,OAAOT,EAAGS,CAAG,EAEtB,GAAIP,EAAI,OAAQ,CAEd,GADA,KAAK,gBAAkBA,EAAI,OACvB,KAAK,eAAiB,KAAK,aAAe,KAAK,YAAc,EAAG,CAClE,IAAMG,EAAQ,KAAK,YACjB,WACA,4BACA,GACA,KACA,mCACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,KAAK,WAAW,KAAKH,CAAG,CAC1B,CAEA,KAAK,YAAYF,CAAE,EACf,KAAK,SAAWX,GAAU,KAAK,UAAUW,CAAE,CACjD,CAAC,CACH,CAQA,YAAYA,EAAI,CACd,GAAI,CAAC,KAAK,KAAM,CACd,KAAK,OAASX,EACd,MACF,CAEA,IAAMqB,EAAgB,KAAK,eACrBC,EAAY,KAAK,WAOvB,GALA,KAAK,oBAAsB,EAC3B,KAAK,eAAiB,EACtB,KAAK,YAAc,EACnB,KAAK,WAAa,CAAC,EAEf,KAAK,UAAY,EAAG,CACtB,IAAIH,EAEA,KAAK,cAAgB,aACvBA,EAAOzB,GAAO4B,EAAWD,CAAa,EAC7B,KAAK,cAAgB,cAC9BF,EAAOxB,GAAcD,GAAO4B,EAAWD,CAAa,CAAC,EAC5C,KAAK,cAAgB,OAC9BF,EAAO,IAAI,KAAKG,CAAS,EAEzBH,EAAOG,EAGL,KAAK,yBACP,KAAK,KAAK,UAAWH,EAAM,EAAI,EAC/B,KAAK,OAASnB,IAEd,KAAK,OAASM,GACd,aAAa,IAAM,CACjB,KAAK,KAAK,UAAWa,EAAM,EAAI,EAC/B,KAAK,OAASnB,EACd,KAAK,UAAUW,CAAE,CACnB,CAAC,EAEL,KAAO,CACL,IAAME,EAAMnB,GAAO4B,EAAWD,CAAa,EAE3C,GAAI,CAAC,KAAK,qBAAuB,CAACvB,GAAYe,CAAG,EAAG,CAClD,IAAMG,EAAQ,KAAK,YACjB,MACA,yBACA,GACA,KACA,qBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEI,KAAK,SAAWX,IAAa,KAAK,yBACpC,KAAK,KAAK,UAAWQ,EAAK,EAAK,EAC/B,KAAK,OAASb,IAEd,KAAK,OAASM,GACd,aAAa,IAAM,CACjB,KAAK,KAAK,UAAWO,EAAK,EAAK,EAC/B,KAAK,OAASb,EACd,KAAK,UAAUW,CAAE,CACnB,CAAC,EAEL,CACF,CASA,eAAeQ,EAAMR,EAAI,CACvB,GAAI,KAAK,UAAY,EAAM,CACzB,GAAIQ,EAAK,SAAW,EAClB,KAAK,MAAQ,GACb,KAAK,KAAK,WAAY,KAAM5B,EAAY,EACxC,KAAK,IAAI,MACJ,CACL,IAAMgC,EAAOJ,EAAK,aAAa,CAAC,EAEhC,GAAI,CAACtB,GAAkB0B,CAAI,EAAG,CAC5B,IAAMP,EAAQ,KAAK,YACjB,WACA,uBAAuBO,CAAI,GAC3B,GACA,KACA,2BACF,EAEAZ,EAAGK,CAAK,EACR,MACF,CAEA,IAAMH,EAAM,IAAId,GACdoB,EAAK,OACLA,EAAK,WAAa,EAClBA,EAAK,OAAS,CAChB,EAEA,GAAI,CAAC,KAAK,qBAAuB,CAACrB,GAAYe,CAAG,EAAG,CAClD,IAAMG,EAAQ,KAAK,YACjB,MACA,yBACA,GACA,KACA,qBACF,EAEAL,EAAGK,CAAK,EACR,MACF,CAEA,KAAK,MAAQ,GACb,KAAK,KAAK,WAAYO,EAAMV,CAAG,EAC/B,KAAK,IAAI,CACX,CAEA,KAAK,OAASb,EACd,MACF,CAEI,KAAK,yBACP,KAAK,KAAK,KAAK,UAAY,EAAO,OAAS,OAAQmB,CAAI,EACvD,KAAK,OAASnB,IAEd,KAAK,OAASM,GACd,aAAa,IAAM,CACjB,KAAK,KAAK,KAAK,UAAY,EAAO,OAAS,OAAQa,CAAI,EACvD,KAAK,OAASnB,EACd,KAAK,UAAUW,CAAE,CACnB,CAAC,EAEL,CAcA,YAAYa,EAAWC,EAASC,EAAQC,EAAYC,EAAW,CAC7D,KAAK,MAAQ,GACb,KAAK,SAAW,GAEhB,IAAMR,EAAM,IAAII,EACdE,EAAS,4BAA4BD,CAAO,GAAKA,CACnD,EAEA,aAAM,kBAAkBL,EAAK,KAAK,WAAW,EAC7CA,EAAI,KAAOQ,EACXR,EAAI5B,EAAW,EAAImC,EACZP,CACT,CACF,EAEAjC,GAAO,QAAUoB,KCjsBjB,IAAAsB,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAIA,GAAM,CAAE,OAAAC,EAAO,EAAI,QAAQ,QAAQ,EAC7B,CAAE,eAAAC,EAAe,EAAI,QAAQ,QAAQ,EAErCC,GAAoB,KACpB,CAAE,aAAAC,GAAc,WAAAC,GAAY,KAAAC,EAAK,EAAI,IACrC,CAAE,OAAAC,GAAQ,kBAAAC,EAAkB,EAAI,KAChC,CAAE,KAAMC,GAAW,SAAAC,EAAS,EAAI,KAEhCC,EAAc,OAAO,aAAa,EAClCC,GAAa,OAAO,MAAM,CAAC,EAC3BC,GAAmB,EAAI,KACzBC,GACAC,GAAoBF,GAElBG,EAAU,EACVC,GAAY,EACZC,GAAgB,EAKhBC,GAAN,MAAMC,CAAO,CASX,YAAYC,EAAQC,EAAYC,EAAc,CAC5C,KAAK,YAAcD,GAAc,CAAC,EAE9BC,IACF,KAAK,cAAgBA,EACrB,KAAK,YAAc,OAAO,MAAM,CAAC,GAGnC,KAAK,QAAUF,EAEf,KAAK,eAAiB,GACtB,KAAK,UAAY,GAEjB,KAAK,eAAiB,EACtB,KAAK,OAAS,CAAC,EACf,KAAK,OAASL,EACd,KAAK,QAAUV,GACf,KAAKD,EAAU,EAAI,MACrB,CAuBA,OAAO,MAAMmB,EAAMC,EAAS,CAC1B,IAAIC,EACAC,EAAQ,GACRC,EAAS,EACTC,EAAc,GAEdJ,EAAQ,OACVC,EAAOD,EAAQ,YAAcb,GAEzBa,EAAQ,aACVA,EAAQ,aAAaC,CAAI,GAErBX,KAAsBF,KAEpBC,KAAe,SAKjBA,GAAa,OAAO,MAAMD,EAAgB,GAG5CX,GAAeY,GAAY,EAAGD,EAAgB,EAC9CE,GAAoB,GAGtBW,EAAK,CAAC,EAAIZ,GAAWC,IAAmB,EACxCW,EAAK,CAAC,EAAIZ,GAAWC,IAAmB,EACxCW,EAAK,CAAC,EAAIZ,GAAWC,IAAmB,EACxCW,EAAK,CAAC,EAAIZ,GAAWC,IAAmB,GAG1Cc,GAAeH,EAAK,CAAC,EAAIA,EAAK,CAAC,EAAIA,EAAK,CAAC,EAAIA,EAAK,CAAC,KAAO,EAC1DE,EAAS,GAGX,IAAIE,EAEA,OAAON,GAAS,UAEf,CAACC,EAAQ,MAAQI,IAClBJ,EAAQd,CAAW,IAAM,OAEzBmB,EAAaL,EAAQd,CAAW,GAEhCa,EAAO,OAAO,KAAKA,CAAI,EACvBM,EAAaN,EAAK,SAGpBM,EAAaN,EAAK,OAClBG,EAAQF,EAAQ,MAAQA,EAAQ,UAAY,CAACI,GAG/C,IAAIE,EAAgBD,EAEhBA,GAAc,OAChBF,GAAU,EACVG,EAAgB,KACPD,EAAa,MACtBF,GAAU,EACVG,EAAgB,KAGlB,IAAMC,EAAS,OAAO,YAAYL,EAAQG,EAAaF,EAASA,CAAM,EActE,OAZAI,EAAO,CAAC,EAAIP,EAAQ,IAAMA,EAAQ,OAAS,IAAOA,EAAQ,OACtDA,EAAQ,OAAMO,EAAO,CAAC,GAAK,IAE/BA,EAAO,CAAC,EAAID,EAERA,IAAkB,IACpBC,EAAO,cAAcF,EAAY,CAAC,EACzBC,IAAkB,MAC3BC,EAAO,CAAC,EAAIA,EAAO,CAAC,EAAI,EACxBA,EAAO,YAAYF,EAAY,EAAG,CAAC,GAGhCL,EAAQ,MAEbO,EAAO,CAAC,GAAK,IACbA,EAAOJ,EAAS,CAAC,EAAIF,EAAK,CAAC,EAC3BM,EAAOJ,EAAS,CAAC,EAAIF,EAAK,CAAC,EAC3BM,EAAOJ,EAAS,CAAC,EAAIF,EAAK,CAAC,EAC3BM,EAAOJ,EAAS,CAAC,EAAIF,EAAK,CAAC,EAEvBG,EAAoB,CAACG,EAAQR,CAAI,EAEjCG,GACFlB,GAAUe,EAAME,EAAMM,EAAQJ,EAAQE,CAAU,EACzC,CAACE,CAAM,IAGhBvB,GAAUe,EAAME,EAAMF,EAAM,EAAGM,CAAU,EAClC,CAACE,EAAQR,CAAI,IAhBM,CAACQ,EAAQR,CAAI,CAiBzC,CAWA,MAAMS,EAAMT,EAAME,EAAMQ,EAAI,CAC1B,IAAIC,EAEJ,GAAIF,IAAS,OACXE,EAAM/B,OACD,IAAI,OAAO6B,GAAS,UAAY,CAACzB,GAAkByB,CAAI,EAC5D,MAAM,IAAI,UAAU,kDAAkD,EACjE,GAAIT,IAAS,QAAa,CAACA,EAAK,OACrCW,EAAM,OAAO,YAAY,CAAC,EAC1BA,EAAI,cAAcF,EAAM,CAAC,MACpB,CACL,IAAMG,EAAS,OAAO,WAAWZ,CAAI,EAErC,GAAIY,EAAS,IACX,MAAM,IAAI,WAAW,gDAAgD,EAGvED,EAAM,OAAO,YAAY,EAAIC,CAAM,EACnCD,EAAI,cAAcF,EAAM,CAAC,EAErB,OAAOT,GAAS,SAClBW,EAAI,MAAMX,EAAM,CAAC,EAEjBW,EAAI,IAAIX,EAAM,CAAC,CAEnB,EAEA,IAAMC,EAAU,CACd,CAACd,CAAW,EAAGwB,EAAI,OACnB,IAAK,GACL,aAAc,KAAK,cACnB,KAAAT,EACA,WAAY,KAAK,YACjB,OAAQ,EACR,SAAU,GACV,KAAM,EACR,EAEI,KAAK,SAAWV,EAClB,KAAK,QAAQ,CAAC,KAAK,SAAUmB,EAAK,GAAOV,EAASS,CAAE,CAAC,EAErD,KAAK,UAAUd,EAAO,MAAMe,EAAKV,CAAO,EAAGS,CAAE,CAEjD,CAUA,KAAKV,EAAME,EAAMQ,EAAI,CACnB,IAAIG,EACAC,EAcJ,GAZI,OAAOd,GAAS,UAClBa,EAAa,OAAO,WAAWb,CAAI,EACnCc,EAAW,IACF/B,GAAOiB,CAAI,GACpBa,EAAab,EAAK,KAClBc,EAAW,KAEXd,EAAOd,GAASc,CAAI,EACpBa,EAAab,EAAK,OAClBc,EAAW5B,GAAS,UAGlB2B,EAAa,IACf,MAAM,IAAI,WAAW,kDAAkD,EAGzE,IAAMZ,EAAU,CACd,CAACd,CAAW,EAAG0B,EACf,IAAK,GACL,aAAc,KAAK,cACnB,KAAAX,EACA,WAAY,KAAK,YACjB,OAAQ,EACR,SAAAY,EACA,KAAM,EACR,EAEI/B,GAAOiB,CAAI,EACT,KAAK,SAAWR,EAClB,KAAK,QAAQ,CAAC,KAAK,YAAaQ,EAAM,GAAOC,EAASS,CAAE,CAAC,EAEzD,KAAK,YAAYV,EAAM,GAAOC,EAASS,CAAE,EAElC,KAAK,SAAWlB,EACzB,KAAK,QAAQ,CAAC,KAAK,SAAUQ,EAAM,GAAOC,EAASS,CAAE,CAAC,EAEtD,KAAK,UAAUd,EAAO,MAAMI,EAAMC,CAAO,EAAGS,CAAE,CAElD,CAUA,KAAKV,EAAME,EAAMQ,EAAI,CACnB,IAAIG,EACAC,EAcJ,GAZI,OAAOd,GAAS,UAClBa,EAAa,OAAO,WAAWb,CAAI,EACnCc,EAAW,IACF/B,GAAOiB,CAAI,GACpBa,EAAab,EAAK,KAClBc,EAAW,KAEXd,EAAOd,GAASc,CAAI,EACpBa,EAAab,EAAK,OAClBc,EAAW5B,GAAS,UAGlB2B,EAAa,IACf,MAAM,IAAI,WAAW,kDAAkD,EAGzE,IAAMZ,EAAU,CACd,CAACd,CAAW,EAAG0B,EACf,IAAK,GACL,aAAc,KAAK,cACnB,KAAAX,EACA,WAAY,KAAK,YACjB,OAAQ,GACR,SAAAY,EACA,KAAM,EACR,EAEI/B,GAAOiB,CAAI,EACT,KAAK,SAAWR,EAClB,KAAK,QAAQ,CAAC,KAAK,YAAaQ,EAAM,GAAOC,EAASS,CAAE,CAAC,EAEzD,KAAK,YAAYV,EAAM,GAAOC,EAASS,CAAE,EAElC,KAAK,SAAWlB,EACzB,KAAK,QAAQ,CAAC,KAAK,SAAUQ,EAAM,GAAOC,EAASS,CAAE,CAAC,EAEtD,KAAK,UAAUd,EAAO,MAAMI,EAAMC,CAAO,EAAGS,CAAE,CAElD,CAkBA,KAAKV,EAAMC,EAASS,EAAI,CACtB,IAAMK,EAAoB,KAAK,YAAYpC,GAAkB,aAAa,EACtEqC,EAASf,EAAQ,OAAS,EAAI,EAC9BgB,EAAOhB,EAAQ,SAEfY,EACAC,EAEA,OAAOd,GAAS,UAClBa,EAAa,OAAO,WAAWb,CAAI,EACnCc,EAAW,IACF/B,GAAOiB,CAAI,GACpBa,EAAab,EAAK,KAClBc,EAAW,KAEXd,EAAOd,GAASc,CAAI,EACpBa,EAAab,EAAK,OAClBc,EAAW5B,GAAS,UAGlB,KAAK,gBACP,KAAK,eAAiB,GAEpB+B,GACAF,GACAA,EAAkB,OAChBA,EAAkB,UACd,6BACA,4BACN,IAEAE,EAAOJ,GAAcE,EAAkB,YAEzC,KAAK,UAAYE,IAEjBA,EAAO,GACPD,EAAS,GAGPf,EAAQ,MAAK,KAAK,eAAiB,IAEvC,IAAMiB,EAAO,CACX,CAAC/B,CAAW,EAAG0B,EACf,IAAKZ,EAAQ,IACb,aAAc,KAAK,cACnB,KAAMA,EAAQ,KACd,WAAY,KAAK,YACjB,OAAAe,EACA,SAAAF,EACA,KAAAG,CACF,EAEIlC,GAAOiB,CAAI,EACT,KAAK,SAAWR,EAClB,KAAK,QAAQ,CAAC,KAAK,YAAaQ,EAAM,KAAK,UAAWkB,EAAMR,CAAE,CAAC,EAE/D,KAAK,YAAYV,EAAM,KAAK,UAAWkB,EAAMR,CAAE,EAExC,KAAK,SAAWlB,EACzB,KAAK,QAAQ,CAAC,KAAK,SAAUQ,EAAM,KAAK,UAAWkB,EAAMR,CAAE,CAAC,EAE5D,KAAK,SAASV,EAAM,KAAK,UAAWkB,EAAMR,CAAE,CAEhD,CAyBA,YAAYS,EAAMC,EAAUnB,EAASS,EAAI,CACvC,KAAK,gBAAkBT,EAAQd,CAAW,EAC1C,KAAK,OAASO,GAEdyB,EACG,YAAY,EACZ,KAAME,GAAgB,CACrB,GAAI,KAAK,QAAQ,UAAW,CAC1B,IAAMC,EAAM,IAAI,MACd,qDACF,EAOA,QAAQ,SAASC,GAAe,KAAMD,EAAKZ,CAAE,EAC7C,MACF,CAEA,KAAK,gBAAkBT,EAAQd,CAAW,EAC1C,IAAMa,EAAOd,GAASmC,CAAW,EAE5BD,EAKH,KAAK,SAASpB,EAAMoB,EAAUnB,EAASS,CAAE,GAJzC,KAAK,OAASlB,EACd,KAAK,UAAUI,EAAO,MAAMI,EAAMC,CAAO,EAAGS,CAAE,EAC9C,KAAK,QAAQ,EAIjB,CAAC,EACA,MAAOY,GAAQ,CAKd,QAAQ,SAASE,GAAS,KAAMF,EAAKZ,CAAE,CACzC,CAAC,CACL,CAyBA,SAASV,EAAMoB,EAAUnB,EAASS,EAAI,CACpC,GAAI,CAACU,EAAU,CACb,KAAK,UAAUxB,EAAO,MAAMI,EAAMC,CAAO,EAAGS,CAAE,EAC9C,MACF,CAEA,IAAMK,EAAoB,KAAK,YAAYpC,GAAkB,aAAa,EAE1E,KAAK,gBAAkBsB,EAAQd,CAAW,EAC1C,KAAK,OAASM,GACdsB,EAAkB,SAASf,EAAMC,EAAQ,IAAK,CAACwB,EAAGd,IAAQ,CACxD,GAAI,KAAK,QAAQ,UAAW,CAC1B,IAAMW,EAAM,IAAI,MACd,uDACF,EAEAC,GAAc,KAAMD,EAAKZ,CAAE,EAC3B,MACF,CAEA,KAAK,gBAAkBT,EAAQd,CAAW,EAC1C,KAAK,OAASK,EACdS,EAAQ,SAAW,GACnB,KAAK,UAAUL,EAAO,MAAMe,EAAKV,CAAO,EAAGS,CAAE,EAC7C,KAAK,QAAQ,CACf,CAAC,CACH,CAOA,SAAU,CACR,KAAO,KAAK,SAAWlB,GAAW,KAAK,OAAO,QAAQ,CACpD,IAAMkC,EAAS,KAAK,OAAO,MAAM,EAEjC,KAAK,gBAAkBA,EAAO,CAAC,EAAEvC,CAAW,EAC5C,QAAQ,MAAMuC,EAAO,CAAC,EAAG,KAAMA,EAAO,MAAM,CAAC,CAAC,CAChD,CACF,CAQA,QAAQA,EAAQ,CACd,KAAK,gBAAkBA,EAAO,CAAC,EAAEvC,CAAW,EAC5C,KAAK,OAAO,KAAKuC,CAAM,CACzB,CASA,UAAUC,EAAMjB,EAAI,CACdiB,EAAK,SAAW,GAClB,KAAK,QAAQ,KAAK,EAClB,KAAK,QAAQ,MAAMA,EAAK,CAAC,CAAC,EAC1B,KAAK,QAAQ,MAAMA,EAAK,CAAC,EAAGjB,CAAE,EAC9B,KAAK,QAAQ,OAAO,GAEpB,KAAK,QAAQ,MAAMiB,EAAK,CAAC,EAAGjB,CAAE,CAElC,CACF,EAEAlC,GAAO,QAAUmB,GAUjB,SAAS4B,GAAcK,EAAQN,EAAKZ,EAAI,CAClC,OAAOA,GAAO,YAAYA,EAAGY,CAAG,EAEpC,QAASO,EAAI,EAAGA,EAAID,EAAO,OAAO,OAAQC,IAAK,CAC7C,IAAMH,EAASE,EAAO,OAAOC,CAAC,EACxBC,EAAWJ,EAAOA,EAAO,OAAS,CAAC,EAErC,OAAOI,GAAa,YAAYA,EAASR,CAAG,CAClD,CACF,CAUA,SAASE,GAAQI,EAAQN,EAAKZ,EAAI,CAChCa,GAAcK,EAAQN,EAAKZ,CAAE,EAC7BkB,EAAO,QAAQN,CAAG,CACpB,ICzlBA,IAAAS,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CAAE,qBAAAC,GAAsB,UAAAC,EAAU,EAAI,IAEtCC,GAAQ,OAAO,OAAO,EACtBC,GAAQ,OAAO,OAAO,EACtBC,GAAS,OAAO,QAAQ,EACxBC,GAAW,OAAO,UAAU,EAC5BC,GAAU,OAAO,SAAS,EAC1BC,GAAU,OAAO,SAAS,EAC1BC,GAAQ,OAAO,OAAO,EACtBC,GAAY,OAAO,WAAW,EAK9BC,GAAN,KAAY,CAOV,YAAYC,EAAM,CAChB,KAAKJ,EAAO,EAAI,KAChB,KAAKC,EAAK,EAAIG,CAChB,CAKA,IAAI,QAAS,CACX,OAAO,KAAKJ,EAAO,CACrB,CAKA,IAAI,MAAO,CACT,OAAO,KAAKC,EAAK,CACnB,CACF,EAEA,OAAO,eAAeE,GAAM,UAAW,SAAU,CAAE,WAAY,EAAK,CAAC,EACrE,OAAO,eAAeA,GAAM,UAAW,OAAQ,CAAE,WAAY,EAAK,CAAC,EAOnE,IAAME,GAAN,cAAyBF,EAAM,CAc7B,YAAYC,EAAME,EAAU,CAAC,EAAG,CAC9B,MAAMF,CAAI,EAEV,KAAKT,EAAK,EAAIW,EAAQ,OAAS,OAAY,EAAIA,EAAQ,KACvD,KAAKP,EAAO,EAAIO,EAAQ,SAAW,OAAY,GAAKA,EAAQ,OAC5D,KAAKJ,EAAS,EAAII,EAAQ,WAAa,OAAY,GAAQA,EAAQ,QACrE,CAKA,IAAI,MAAO,CACT,OAAO,KAAKX,EAAK,CACnB,CAKA,IAAI,QAAS,CACX,OAAO,KAAKI,EAAO,CACrB,CAKA,IAAI,UAAW,CACb,OAAO,KAAKG,EAAS,CACvB,CACF,EAEA,OAAO,eAAeG,GAAW,UAAW,OAAQ,CAAE,WAAY,EAAK,CAAC,EACxE,OAAO,eAAeA,GAAW,UAAW,SAAU,CAAE,WAAY,EAAK,CAAC,EAC1E,OAAO,eAAeA,GAAW,UAAW,WAAY,CAAE,WAAY,EAAK,CAAC,EAO5E,IAAME,GAAN,cAAyBJ,EAAM,CAU7B,YAAYC,EAAME,EAAU,CAAC,EAAG,CAC9B,MAAMF,CAAI,EAEV,KAAKP,EAAM,EAAIS,EAAQ,QAAU,OAAY,KAAOA,EAAQ,MAC5D,KAAKR,EAAQ,EAAIQ,EAAQ,UAAY,OAAY,GAAKA,EAAQ,OAChE,CAKA,IAAI,OAAQ,CACV,OAAO,KAAKT,EAAM,CACpB,CAKA,IAAI,SAAU,CACZ,OAAO,KAAKC,EAAQ,CACtB,CACF,EAEA,OAAO,eAAeS,GAAW,UAAW,QAAS,CAAE,WAAY,EAAK,CAAC,EACzE,OAAO,eAAeA,GAAW,UAAW,UAAW,CAAE,WAAY,EAAK,CAAC,EAO3E,IAAMC,GAAN,cAA2BL,EAAM,CAS/B,YAAYC,EAAME,EAAU,CAAC,EAAG,CAC9B,MAAMF,CAAI,EAEV,KAAKR,EAAK,EAAIU,EAAQ,OAAS,OAAY,KAAOA,EAAQ,IAC5D,CAKA,IAAI,MAAO,CACT,OAAO,KAAKV,EAAK,CACnB,CACF,EAEA,OAAO,eAAeY,GAAa,UAAW,OAAQ,CAAE,WAAY,EAAK,CAAC,EAQ1E,IAAMC,GAAc,CAalB,iBAAiBL,EAAMM,EAASJ,EAAU,CAAC,EAAG,CAC5C,QAAWK,KAAY,KAAK,UAAUP,CAAI,EACxC,GACE,CAACE,EAAQb,EAAoB,GAC7BkB,EAASjB,EAAS,IAAMgB,GACxB,CAACC,EAASlB,EAAoB,EAE9B,OAIJ,IAAImB,EAEJ,GAAIR,IAAS,UACXQ,EAAU,SAAmBC,EAAMC,EAAU,CAC3C,IAAMC,EAAQ,IAAIP,GAAa,UAAW,CACxC,KAAMM,EAAWD,EAAOA,EAAK,SAAS,CACxC,CAAC,EAEDE,EAAMf,EAAO,EAAI,KACjBgB,GAAaN,EAAS,KAAMK,CAAK,CACnC,UACSX,IAAS,QAClBQ,EAAU,SAAiBK,EAAMC,EAAS,CACxC,IAAMH,EAAQ,IAAIV,GAAW,QAAS,CACpC,KAAAY,EACA,OAAQC,EAAQ,SAAS,EACzB,SAAU,KAAK,qBAAuB,KAAK,eAC7C,CAAC,EAEDH,EAAMf,EAAO,EAAI,KACjBgB,GAAaN,EAAS,KAAMK,CAAK,CACnC,UACSX,IAAS,QAClBQ,EAAU,SAAiBO,EAAO,CAChC,IAAMJ,EAAQ,IAAIR,GAAW,QAAS,CACpC,MAAAY,EACA,QAASA,EAAM,OACjB,CAAC,EAEDJ,EAAMf,EAAO,EAAI,KACjBgB,GAAaN,EAAS,KAAMK,CAAK,CACnC,UACSX,IAAS,OAClBQ,EAAU,UAAkB,CAC1B,IAAMG,EAAQ,IAAIZ,GAAM,MAAM,EAE9BY,EAAMf,EAAO,EAAI,KACjBgB,GAAaN,EAAS,KAAMK,CAAK,CACnC,MAEA,QAGFH,EAAQnB,EAAoB,EAAI,CAAC,CAACa,EAAQb,EAAoB,EAC9DmB,EAAQlB,EAAS,EAAIgB,EAEjBJ,EAAQ,KACV,KAAK,KAAKF,EAAMQ,CAAO,EAEvB,KAAK,GAAGR,EAAMQ,CAAO,CAEzB,EASA,oBAAoBR,EAAMM,EAAS,CACjC,QAAWC,KAAY,KAAK,UAAUP,CAAI,EACxC,GAAIO,EAASjB,EAAS,IAAMgB,GAAW,CAACC,EAASlB,EAAoB,EAAG,CACtE,KAAK,eAAeW,EAAMO,CAAQ,EAClC,KACF,CAEJ,CACF,EAEAnB,GAAO,QAAU,CACf,WAAAa,GACA,WAAAE,GACA,MAAAJ,GACA,YAAAM,GACA,aAAAD,EACF,EAUA,SAASQ,GAAaL,EAAUS,EAASL,EAAO,CAC1C,OAAOJ,GAAa,UAAYA,EAAS,YAC3CA,EAAS,YAAY,KAAKA,EAAUI,CAAK,EAEzCJ,EAAS,KAAKS,EAASL,CAAK,CAEhC,ICnSA,IAAAM,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CAAE,WAAAC,EAAW,EAAI,KAYvB,SAASC,EAAKC,EAAMC,EAAMC,EAAM,CAC1BF,EAAKC,CAAI,IAAM,OAAWD,EAAKC,CAAI,EAAI,CAACC,CAAI,EAC3CF,EAAKC,CAAI,EAAE,KAAKC,CAAI,CAC3B,CASA,SAASC,GAAMC,EAAQ,CACrB,IAAMC,EAAS,OAAO,OAAO,IAAI,EAC7BC,EAAS,OAAO,OAAO,IAAI,EAC3BC,EAAe,GACfC,EAAa,GACbC,EAAW,GACXC,EACAC,EACAC,EAAQ,GACRC,EAAO,GACPC,EAAM,GACNC,EAAI,EAER,KAAOA,EAAIX,EAAO,OAAQW,IAGxB,GAFAF,EAAOT,EAAO,WAAWW,CAAC,EAEtBL,IAAkB,OACpB,GAAII,IAAQ,IAAMhB,GAAWe,CAAI,IAAM,EACjCD,IAAU,KAAIA,EAAQG,WAE1BA,IAAM,IACLF,IAAS,IAAkBA,IAAS,GAEjCC,IAAQ,IAAMF,IAAU,KAAIE,EAAMC,WAC7BF,IAAS,IAAkBA,IAAS,GAAgB,CAC7D,GAAID,IAAU,GACZ,MAAM,IAAI,YAAY,iCAAiCG,CAAC,EAAE,EAGxDD,IAAQ,KAAIA,EAAMC,GACtB,IAAMd,EAAOG,EAAO,MAAMQ,EAAOE,CAAG,EAChCD,IAAS,IACXd,EAAKM,EAAQJ,EAAMK,CAAM,EACzBA,EAAS,OAAO,OAAO,IAAI,GAE3BI,EAAgBT,EAGlBW,EAAQE,EAAM,EAChB,KACE,OAAM,IAAI,YAAY,iCAAiCC,CAAC,EAAE,UAEnDJ,IAAc,OACvB,GAAIG,IAAQ,IAAMhB,GAAWe,CAAI,IAAM,EACjCD,IAAU,KAAIA,EAAQG,WACjBF,IAAS,IAAQA,IAAS,EAC/BC,IAAQ,IAAMF,IAAU,KAAIE,EAAMC,WAC7BF,IAAS,IAAQA,IAAS,GAAM,CACzC,GAAID,IAAU,GACZ,MAAM,IAAI,YAAY,iCAAiCG,CAAC,EAAE,EAGxDD,IAAQ,KAAIA,EAAMC,GACtBhB,EAAKO,EAAQF,EAAO,MAAMQ,EAAOE,CAAG,EAAG,EAAI,EACvCD,IAAS,KACXd,EAAKM,EAAQK,EAAeJ,CAAM,EAClCA,EAAS,OAAO,OAAO,IAAI,EAC3BI,EAAgB,QAGlBE,EAAQE,EAAM,EAChB,SAAWD,IAAS,IAAkBD,IAAU,IAAME,IAAQ,GAC5DH,EAAYP,EAAO,MAAMQ,EAAOG,CAAC,EACjCH,EAAQE,EAAM,OAEd,OAAM,IAAI,YAAY,iCAAiCC,CAAC,EAAE,UAQxDP,EAAY,CACd,GAAIV,GAAWe,CAAI,IAAM,EACvB,MAAM,IAAI,YAAY,iCAAiCE,CAAC,EAAE,EAExDH,IAAU,GAAIA,EAAQG,EAChBR,IAAcA,EAAe,IACvCC,EAAa,EACf,SAAWC,EACT,GAAIX,GAAWe,CAAI,IAAM,EACnBD,IAAU,KAAIA,EAAQG,WACjBF,IAAS,IAAkBD,IAAU,GAC9CH,EAAW,GACXK,EAAMC,UACGF,IAAS,GAClBL,EAAa,OAEb,OAAM,IAAI,YAAY,iCAAiCO,CAAC,EAAE,UAEnDF,IAAS,IAAQT,EAAO,WAAWW,EAAI,CAAC,IAAM,GACvDN,EAAW,WACFK,IAAQ,IAAMhB,GAAWe,CAAI,IAAM,EACxCD,IAAU,KAAIA,EAAQG,WACjBH,IAAU,KAAOC,IAAS,IAAQA,IAAS,GAChDC,IAAQ,KAAIA,EAAMC,WACbF,IAAS,IAAQA,IAAS,GAAM,CACzC,GAAID,IAAU,GACZ,MAAM,IAAI,YAAY,iCAAiCG,CAAC,EAAE,EAGxDD,IAAQ,KAAIA,EAAMC,GACtB,IAAIC,EAAQZ,EAAO,MAAMQ,EAAOE,CAAG,EAC/BP,IACFS,EAAQA,EAAM,QAAQ,MAAO,EAAE,EAC/BT,EAAe,IAEjBR,EAAKO,EAAQK,EAAWK,CAAK,EACzBH,IAAS,KACXd,EAAKM,EAAQK,EAAeJ,CAAM,EAClCA,EAAS,OAAO,OAAO,IAAI,EAC3BI,EAAgB,QAGlBC,EAAY,OACZC,EAAQE,EAAM,EAChB,KACE,OAAM,IAAI,YAAY,iCAAiCC,CAAC,EAAE,EAKhE,GAAIH,IAAU,IAAMH,GAAYI,IAAS,IAAQA,IAAS,EACxD,MAAM,IAAI,YAAY,yBAAyB,EAG7CC,IAAQ,KAAIA,EAAMC,GACtB,IAAME,EAAQb,EAAO,MAAMQ,EAAOE,CAAG,EACrC,OAAIJ,IAAkB,OACpBX,EAAKM,EAAQY,EAAOX,CAAM,GAEtBK,IAAc,OAChBZ,EAAKO,EAAQW,EAAO,EAAI,EACfV,EACTR,EAAKO,EAAQK,EAAWM,EAAM,QAAQ,MAAO,EAAE,CAAC,EAEhDlB,EAAKO,EAAQK,EAAWM,CAAK,EAE/BlB,EAAKM,EAAQK,EAAeJ,CAAM,GAG7BD,CACT,CASA,SAASa,GAAOC,EAAY,CAC1B,OAAO,OAAO,KAAKA,CAAU,EAC1B,IAAKC,GAAc,CAClB,IAAIC,EAAiBF,EAAWC,CAAS,EACzC,OAAK,MAAM,QAAQC,CAAc,IAAGA,EAAiB,CAACA,CAAc,GAC7DA,EACJ,IAAKf,GACG,CAACc,CAAS,EACd,OACC,OAAO,KAAKd,CAAM,EAAE,IAAKgB,GAAM,CAC7B,IAAIC,EAASjB,EAAOgB,CAAC,EACrB,OAAK,MAAM,QAAQC,CAAM,IAAGA,EAAS,CAACA,CAAM,GACrCA,EACJ,IAAKC,GAAOA,IAAM,GAAOF,EAAI,GAAGA,CAAC,IAAIE,CAAC,EAAG,EACzC,KAAK,IAAI,CACd,CAAC,CACH,EACC,KAAK,IAAI,CACb,EACA,KAAK,IAAI,CACd,CAAC,EACA,KAAK,IAAI,CACd,CAEA3B,GAAO,QAAU,CAAE,OAAAqB,GAAQ,MAAAf,EAAM,IC1MjC,IAAAsB,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAIA,IAAMC,GAAe,QAAQ,QAAQ,EAC/BC,GAAQ,QAAQ,OAAO,EACvBC,GAAO,QAAQ,MAAM,EACrBC,GAAM,QAAQ,KAAK,EACnBC,GAAM,QAAQ,KAAK,EACnB,CAAE,YAAAC,GAAa,WAAAC,EAAW,EAAI,QAAQ,QAAQ,EAC9C,CAAE,OAAAC,GAAQ,SAAAC,EAAS,EAAI,QAAQ,QAAQ,EACvC,CAAE,IAAAC,EAAI,EAAI,QAAQ,KAAK,EAEvBC,GAAoB,KACpBC,GAAW,KACXC,GAAS,KACT,CAAE,OAAAC,EAAO,EAAI,KAEb,CACJ,aAAAC,GACA,cAAAC,GACA,aAAAC,GACA,KAAAC,GACA,qBAAAC,GACA,UAAAC,GACA,YAAAC,GACA,WAAAC,EACA,KAAAC,EACF,EAAI,IACE,CACJ,YAAa,CAAE,iBAAAC,GAAkB,oBAAAC,EAAoB,CACvD,EAAI,KACE,CAAE,OAAAC,GAAQ,MAAAC,EAAM,EAAI,KACpB,CAAE,SAAAC,EAAS,EAAI,KAEfC,GAAW,OAAO,UAAU,EAC5BC,GAAmB,CAAC,EAAG,EAAE,EACzBC,GAAc,CAAC,aAAc,OAAQ,UAAW,QAAQ,EACxDC,GAAmB,iCAOnBC,EAAN,MAAMC,UAAkBjC,EAAa,CAQnC,YAAYkC,EAASC,EAAWC,EAAS,CACvC,MAAM,EAEN,KAAK,YAActB,GAAa,CAAC,EACjC,KAAK,WAAa,KAClB,KAAK,oBAAsB,GAC3B,KAAK,gBAAkB,GACvB,KAAK,cAAgBE,GACrB,KAAK,YAAc,KACnB,KAAK,cAAgB,GACrB,KAAK,YAAc,CAAC,EACpB,KAAK,QAAU,GACf,KAAK,UAAY,GACjB,KAAK,YAAciB,EAAU,WAC7B,KAAK,UAAY,KACjB,KAAK,QAAU,KACf,KAAK,QAAU,KAEXC,IAAY,MACd,KAAK,gBAAkB,EACvB,KAAK,UAAY,GACjB,KAAK,WAAa,EAEdC,IAAc,OAChBA,EAAY,CAAC,EACH,MAAM,QAAQA,CAAS,IAC7B,OAAOA,GAAc,UAAYA,IAAc,MACjDC,EAAUD,EACVA,EAAY,CAAC,GAEbA,EAAY,CAACA,CAAS,GAI1BE,GAAa,KAAMH,EAASC,EAAWC,CAAO,IAE9C,KAAK,UAAYA,EAAQ,SACzB,KAAK,cAAgBA,EAAQ,aAC7B,KAAK,UAAY,GAErB,CAQA,IAAI,YAAa,CACf,OAAO,KAAK,WACd,CAEA,IAAI,WAAWE,EAAM,CACdxB,GAAa,SAASwB,CAAI,IAE/B,KAAK,YAAcA,EAKf,KAAK,YAAW,KAAK,UAAU,YAAcA,GACnD,CAKA,IAAI,gBAAiB,CACnB,OAAK,KAAK,QAEH,KAAK,QAAQ,eAAe,OAAS,KAAK,QAAQ,eAF/B,KAAK,eAGjC,CAKA,IAAI,YAAa,CACf,OAAO,OAAO,KAAK,KAAK,WAAW,EAAE,KAAK,CAC5C,CAKA,IAAI,UAAW,CACb,OAAO,KAAK,OACd,CAMA,IAAI,SAAU,CACZ,OAAO,IACT,CAMA,IAAI,SAAU,CACZ,OAAO,IACT,CAMA,IAAI,QAAS,CACX,OAAO,IACT,CAMA,IAAI,WAAY,CACd,OAAO,IACT,CAKA,IAAI,UAAW,CACb,OAAO,KAAK,SACd,CAKA,IAAI,YAAa,CACf,OAAO,KAAK,WACd,CAKA,IAAI,KAAM,CACR,OAAO,KAAK,IACd,CAkBA,UAAUC,EAAQC,EAAMJ,EAAS,CAC/B,IAAMK,EAAW,IAAI9B,GAAS,CAC5B,uBAAwByB,EAAQ,uBAChC,WAAY,KAAK,WACjB,WAAY,KAAK,YACjB,SAAU,KAAK,UACf,WAAYA,EAAQ,WACpB,mBAAoBA,EAAQ,kBAC9B,CAAC,EAEKM,EAAS,IAAI9B,GAAO2B,EAAQ,KAAK,YAAaH,EAAQ,YAAY,EAExE,KAAK,UAAYK,EACjB,KAAK,QAAUC,EACf,KAAK,QAAUH,EAEfE,EAASpB,CAAU,EAAI,KACvBqB,EAAOrB,CAAU,EAAI,KACrBkB,EAAOlB,CAAU,EAAI,KAErBoB,EAAS,GAAG,WAAYE,EAAkB,EAC1CF,EAAS,GAAG,QAASG,EAAe,EACpCH,EAAS,GAAG,QAASI,EAAe,EACpCJ,EAAS,GAAG,UAAWK,EAAiB,EACxCL,EAAS,GAAG,OAAQM,EAAc,EAClCN,EAAS,GAAG,OAAQO,EAAc,EAElCN,EAAO,QAAUO,GAKbV,EAAO,YAAYA,EAAO,WAAW,CAAC,EACtCA,EAAO,YAAYA,EAAO,WAAW,EAErCC,EAAK,OAAS,GAAGD,EAAO,QAAQC,CAAI,EAExCD,EAAO,GAAG,QAASW,EAAa,EAChCX,EAAO,GAAG,OAAQY,EAAY,EAC9BZ,EAAO,GAAG,MAAOa,EAAW,EAC5Bb,EAAO,GAAG,QAASc,EAAa,EAEhC,KAAK,YAAcpB,EAAU,KAC7B,KAAK,KAAK,MAAM,CAClB,CAOA,WAAY,CACV,GAAI,CAAC,KAAK,QAAS,CACjB,KAAK,YAAcA,EAAU,OAC7B,KAAK,KAAK,QAAS,KAAK,WAAY,KAAK,aAAa,EACtD,MACF,CAEI,KAAK,YAAYvB,GAAkB,aAAa,GAClD,KAAK,YAAYA,GAAkB,aAAa,EAAE,QAAQ,EAG5D,KAAK,UAAU,mBAAmB,EAClC,KAAK,YAAcuB,EAAU,OAC7B,KAAK,KAAK,QAAS,KAAK,WAAY,KAAK,aAAa,CACxD,CAsBA,MAAMqB,EAAMC,EAAM,CAChB,GAAI,KAAK,aAAetB,EAAU,OAClC,IAAI,KAAK,aAAeA,EAAU,WAAY,CAE5CuB,EAAe,KAAM,KAAK,KADd,4DACuB,EACnC,MACF,CAEA,GAAI,KAAK,aAAevB,EAAU,QAAS,CAEvC,KAAK,kBACJ,KAAK,qBAAuB,KAAK,UAAU,eAAe,eAE3D,KAAK,QAAQ,IAAI,EAGnB,MACF,CAEA,KAAK,YAAcA,EAAU,QAC7B,KAAK,QAAQ,MAAMqB,EAAMC,EAAM,CAAC,KAAK,UAAYE,GAAQ,CAKnDA,IAEJ,KAAK,gBAAkB,IAGrB,KAAK,qBACL,KAAK,UAAU,eAAe,eAE9B,KAAK,QAAQ,IAAI,EAErB,CAAC,EAEDC,GAAc,IAAI,EACpB,CAOA,OAAQ,CAEJ,KAAK,aAAezB,EAAU,YAC9B,KAAK,aAAeA,EAAU,SAKhC,KAAK,QAAU,GACf,KAAK,QAAQ,MAAM,EACrB,CAUA,KAAKsB,EAAMI,EAAMC,EAAI,CACnB,GAAI,KAAK,aAAe3B,EAAU,WAChC,MAAM,IAAI,MAAM,kDAAkD,EAapE,GAVI,OAAOsB,GAAS,YAClBK,EAAKL,EACLA,EAAOI,EAAO,QACL,OAAOA,GAAS,aACzBC,EAAKD,EACLA,EAAO,QAGL,OAAOJ,GAAS,WAAUA,EAAOA,EAAK,SAAS,GAE/C,KAAK,aAAetB,EAAU,KAAM,CACtC4B,GAAe,KAAMN,EAAMK,CAAE,EAC7B,MACF,CAEID,IAAS,SAAWA,EAAO,CAAC,KAAK,WACrC,KAAK,QAAQ,KAAKJ,GAAQvC,GAAc2C,EAAMC,CAAE,CAClD,CAUA,KAAKL,EAAMI,EAAMC,EAAI,CACnB,GAAI,KAAK,aAAe3B,EAAU,WAChC,MAAM,IAAI,MAAM,kDAAkD,EAapE,GAVI,OAAOsB,GAAS,YAClBK,EAAKL,EACLA,EAAOI,EAAO,QACL,OAAOA,GAAS,aACzBC,EAAKD,EACLA,EAAO,QAGL,OAAOJ,GAAS,WAAUA,EAAOA,EAAK,SAAS,GAE/C,KAAK,aAAetB,EAAU,KAAM,CACtC4B,GAAe,KAAMN,EAAMK,CAAE,EAC7B,MACF,CAEID,IAAS,SAAWA,EAAO,CAAC,KAAK,WACrC,KAAK,QAAQ,KAAKJ,GAAQvC,GAAc2C,EAAMC,CAAE,CAClD,CAOA,QAAS,CAEL,KAAK,aAAe3B,EAAU,YAC9B,KAAK,aAAeA,EAAU,SAKhC,KAAK,QAAU,GACV,KAAK,UAAU,eAAe,WAAW,KAAK,QAAQ,OAAO,EACpE,CAiBA,KAAKsB,EAAMnB,EAASwB,EAAI,CACtB,GAAI,KAAK,aAAe3B,EAAU,WAChC,MAAM,IAAI,MAAM,kDAAkD,EAUpE,GAPI,OAAOG,GAAY,aACrBwB,EAAKxB,EACLA,EAAU,CAAC,GAGT,OAAOmB,GAAS,WAAUA,EAAOA,EAAK,SAAS,GAE/C,KAAK,aAAetB,EAAU,KAAM,CACtC4B,GAAe,KAAMN,EAAMK,CAAE,EAC7B,MACF,CAEA,IAAME,EAAO,CACX,OAAQ,OAAOP,GAAS,SACxB,KAAM,CAAC,KAAK,UACZ,SAAU,GACV,IAAK,GACL,GAAGnB,CACL,EAEK,KAAK,YAAY1B,GAAkB,aAAa,IACnDoD,EAAK,SAAW,IAGlB,KAAK,QAAQ,KAAKP,GAAQvC,GAAc8C,EAAMF,CAAE,CAClD,CAOA,WAAY,CACV,GAAI,KAAK,aAAe3B,EAAU,OAClC,IAAI,KAAK,aAAeA,EAAU,WAAY,CAE5CuB,EAAe,KAAM,KAAK,KADd,4DACuB,EACnC,MACF,CAEI,KAAK,UACP,KAAK,YAAcvB,EAAU,QAC7B,KAAK,QAAQ,QAAQ,GAEzB,CACF,EAMA,OAAO,eAAeD,EAAW,aAAc,CAC7C,WAAY,GACZ,MAAOF,GAAY,QAAQ,YAAY,CACzC,CAAC,EAMD,OAAO,eAAeE,EAAU,UAAW,aAAc,CACvD,WAAY,GACZ,MAAOF,GAAY,QAAQ,YAAY,CACzC,CAAC,EAMD,OAAO,eAAeE,EAAW,OAAQ,CACvC,WAAY,GACZ,MAAOF,GAAY,QAAQ,MAAM,CACnC,CAAC,EAMD,OAAO,eAAeE,EAAU,UAAW,OAAQ,CACjD,WAAY,GACZ,MAAOF,GAAY,QAAQ,MAAM,CACnC,CAAC,EAMD,OAAO,eAAeE,EAAW,UAAW,CAC1C,WAAY,GACZ,MAAOF,GAAY,QAAQ,SAAS,CACtC,CAAC,EAMD,OAAO,eAAeE,EAAU,UAAW,UAAW,CACpD,WAAY,GACZ,MAAOF,GAAY,QAAQ,SAAS,CACtC,CAAC,EAMD,OAAO,eAAeE,EAAW,SAAU,CACzC,WAAY,GACZ,MAAOF,GAAY,QAAQ,QAAQ,CACrC,CAAC,EAMD,OAAO,eAAeE,EAAU,UAAW,SAAU,CACnD,WAAY,GACZ,MAAOF,GAAY,QAAQ,QAAQ,CACrC,CAAC,EAED,CACE,aACA,iBACA,aACA,WACA,WACA,aACA,KACF,EAAE,QAASiC,GAAa,CACtB,OAAO,eAAe/B,EAAU,UAAW+B,EAAU,CAAE,WAAY,EAAK,CAAC,CAC3E,CAAC,EAMD,CAAC,OAAQ,QAAS,QAAS,SAAS,EAAE,QAASC,GAAW,CACxD,OAAO,eAAehC,EAAU,UAAW,KAAKgC,CAAM,GAAI,CACxD,WAAY,GACZ,KAAM,CACJ,QAAWC,KAAY,KAAK,UAAUD,CAAM,EAC1C,GAAIC,EAAS/C,EAAoB,EAAG,OAAO+C,EAAS9C,EAAS,EAG/D,OAAO,IACT,EACA,IAAI+C,EAAS,CACX,QAAWD,KAAY,KAAK,UAAUD,CAAM,EAC1C,GAAIC,EAAS/C,EAAoB,EAAG,CAClC,KAAK,eAAe8C,EAAQC,CAAQ,EACpC,KACF,CAGE,OAAOC,GAAY,YAEvB,KAAK,iBAAiBF,EAAQE,EAAS,CACrC,CAAChD,EAAoB,EAAG,EAC1B,CAAC,CACH,CACF,CAAC,CACH,CAAC,EAEDc,EAAU,UAAU,iBAAmBT,GACvCS,EAAU,UAAU,oBAAsBR,GAE1CzB,GAAO,QAAUiC,EAsCjB,SAASK,GAAa8B,EAAWjC,EAASC,EAAWC,EAAS,CAC5D,IAAM0B,EAAO,CACX,uBAAwB,GACxB,SAAU,GACV,aAAc/C,GACd,gBAAiBc,GAAiB,CAAC,EACnC,WAAY,UACZ,mBAAoB,GACpB,kBAAmB,GACnB,gBAAiB,GACjB,aAAc,GACd,GAAGO,EACH,WAAY,OACZ,SAAU,OACV,SAAU,OACV,QAAS,OACT,OAAQ,MACR,KAAM,OACN,KAAM,OACN,KAAM,MACR,EAKA,GAHA+B,EAAU,UAAYL,EAAK,SAC3BK,EAAU,cAAgBL,EAAK,aAE3B,CAACjC,GAAiB,SAASiC,EAAK,eAAe,EACjD,MAAM,IAAI,WACR,iCAAiCA,EAAK,eAAe,yBAC3BjC,GAAiB,KAAK,IAAI,CAAC,GACvD,EAGF,IAAIuC,EAEJ,GAAIlC,aAAmBzB,GACrB2D,EAAYlC,MAEZ,IAAI,CACFkC,EAAY,IAAI3D,GAAIyB,CAAO,CAC7B,MAAY,CACV,MAAM,IAAI,YAAY,gBAAgBA,CAAO,EAAE,CACjD,CAGEkC,EAAU,WAAa,QACzBA,EAAU,SAAW,MACZA,EAAU,WAAa,WAChCA,EAAU,SAAW,QAGvBD,EAAU,KAAOC,EAAU,KAE3B,IAAMC,EAAWD,EAAU,WAAa,OAClCE,EAAWF,EAAU,WAAa,WACpCG,EAYJ,GAVIH,EAAU,WAAa,OAAS,CAACC,GAAY,CAACC,EAChDC,EACE,oFAEOD,GAAY,CAACF,EAAU,SAChCG,EAAoB,8BACXH,EAAU,OACnBG,EAAoB,0CAGlBA,EAAmB,CACrB,IAAMd,EAAM,IAAI,YAAYc,CAAiB,EAE7C,GAAIJ,EAAU,aAAe,EAC3B,MAAMV,EAENe,GAAkBL,EAAWV,CAAG,EAChC,MAEJ,CAEA,IAAMgB,EAAcJ,EAAW,IAAM,GAC/BK,EAAMrE,GAAY,EAAE,EAAE,SAAS,QAAQ,EACvCsE,EAAUN,EAAWpE,GAAM,QAAUC,GAAK,QAC1C0E,EAAc,IAAI,IACpBC,EA6BJ,GA3BAf,EAAK,iBACHA,EAAK,mBAAqBO,EAAWS,GAAaC,IACpDjB,EAAK,YAAcA,EAAK,aAAeW,EACvCX,EAAK,KAAOM,EAAU,MAAQK,EAC9BX,EAAK,KAAOM,EAAU,SAAS,WAAW,GAAG,EACzCA,EAAU,SAAS,MAAM,EAAG,EAAE,EAC9BA,EAAU,SACdN,EAAK,QAAU,CACb,GAAGA,EAAK,QACR,wBAAyBA,EAAK,gBAC9B,oBAAqBY,EACrB,WAAY,UACZ,QAAS,WACX,EACAZ,EAAK,KAAOM,EAAU,SAAWA,EAAU,OAC3CN,EAAK,QAAUA,EAAK,iBAEhBA,EAAK,oBACPe,EAAoB,IAAInE,GACtBoD,EAAK,oBAAsB,GAAOA,EAAK,kBAAoB,CAAC,EAC5D,GACAA,EAAK,UACP,EACAA,EAAK,QAAQ,0BAA0B,EAAIrC,GAAO,CAChD,CAACf,GAAkB,aAAa,EAAGmE,EAAkB,MAAM,CAC7D,CAAC,GAEC1C,EAAU,OAAQ,CACpB,QAAW6C,KAAY7C,EAAW,CAChC,GACE,OAAO6C,GAAa,UACpB,CAACjD,GAAiB,KAAKiD,CAAQ,GAC/BJ,EAAY,IAAII,CAAQ,EAExB,MAAM,IAAI,YACR,oDACF,EAGFJ,EAAY,IAAII,CAAQ,CAC1B,CAEAlB,EAAK,QAAQ,wBAAwB,EAAI3B,EAAU,KAAK,GAAG,CAC7D,CAYA,GAXI2B,EAAK,SACHA,EAAK,gBAAkB,GACzBA,EAAK,QAAQ,sBAAsB,EAAIA,EAAK,OAE5CA,EAAK,QAAQ,OAASA,EAAK,SAG3BM,EAAU,UAAYA,EAAU,YAClCN,EAAK,KAAO,GAAGM,EAAU,QAAQ,IAAIA,EAAU,QAAQ,IAGrDE,EAAU,CACZ,IAAMW,EAAQnB,EAAK,KAAK,MAAM,GAAG,EAEjCA,EAAK,WAAamB,EAAM,CAAC,EACzBnB,EAAK,KAAOmB,EAAM,CAAC,CACrB,CAEA,IAAIC,EAEJ,GAAIpB,EAAK,gBAAiB,CACxB,GAAIK,EAAU,aAAe,EAAG,CAC9BA,EAAU,aAAeG,EACzBH,EAAU,gBAAkBE,EAC5BF,EAAU,0BAA4BG,EAClCR,EAAK,WACLM,EAAU,KAEd,IAAMe,EAAU/C,GAAWA,EAAQ,QAQnC,GAFAA,EAAU,CAAE,GAAGA,EAAS,QAAS,CAAC,CAAE,EAEhC+C,EACF,OAAW,CAACT,EAAKU,CAAK,IAAK,OAAO,QAAQD,CAAO,EAC/C/C,EAAQ,QAAQsC,EAAI,YAAY,CAAC,EAAIU,CAG3C,SAAWjB,EAAU,cAAc,UAAU,IAAM,EAAG,CACpD,IAAMkB,EAAaf,EACfH,EAAU,aACRL,EAAK,aAAeK,EAAU,0BAC9B,GACFA,EAAU,aACR,GACAC,EAAU,OAASD,EAAU,2BAE/B,CAACkB,GAAelB,EAAU,iBAAmB,CAACE,KAKhD,OAAOP,EAAK,QAAQ,cACpB,OAAOA,EAAK,QAAQ,OAEfuB,GAAY,OAAOvB,EAAK,QAAQ,KAErCA,EAAK,KAAO,OAEhB,CAOIA,EAAK,MAAQ,CAAC1B,EAAQ,QAAQ,gBAChCA,EAAQ,QAAQ,cACd,SAAW,OAAO,KAAK0B,EAAK,IAAI,EAAE,SAAS,QAAQ,GAGvDoB,EAAMf,EAAU,KAAOQ,EAAQb,CAAI,EAE/BK,EAAU,YAUZA,EAAU,KAAK,WAAYA,EAAU,IAAKe,CAAG,CAEjD,MACEA,EAAMf,EAAU,KAAOQ,EAAQb,CAAI,EAGjCA,EAAK,SACPoB,EAAI,GAAG,UAAW,IAAM,CACtB1B,EAAeW,EAAWe,EAAK,iCAAiC,CAClE,CAAC,EAGHA,EAAI,GAAG,QAAUzB,GAAQ,CACnByB,IAAQ,MAAQA,EAAItD,EAAQ,IAEhCsD,EAAMf,EAAU,KAAO,KACvBK,GAAkBL,EAAWV,CAAG,EAClC,CAAC,EAEDyB,EAAI,GAAG,WAAaI,GAAQ,CAC1B,IAAMC,EAAWD,EAAI,QAAQ,SACvBE,EAAaF,EAAI,WAEvB,GACEC,GACAzB,EAAK,iBACL0B,GAAc,KACdA,EAAa,IACb,CACA,GAAI,EAAErB,EAAU,WAAaL,EAAK,aAAc,CAC9CN,EAAeW,EAAWe,EAAK,4BAA4B,EAC3D,MACF,CAEAA,EAAI,MAAM,EAEV,IAAIO,EAEJ,GAAI,CACFA,EAAO,IAAIhF,GAAI8E,EAAUrD,CAAO,CAClC,MAAY,CACV,IAAMuB,EAAM,IAAI,YAAY,gBAAgB8B,CAAQ,EAAE,EACtDf,GAAkBL,EAAWV,CAAG,EAChC,MACF,CAEApB,GAAa8B,EAAWsB,EAAMtD,EAAWC,CAAO,CAClD,MAAY+B,EAAU,KAAK,sBAAuBe,EAAKI,CAAG,GACxD9B,EACEW,EACAe,EACA,+BAA+BI,EAAI,UAAU,EAC/C,CAEJ,CAAC,EAEDJ,EAAI,GAAG,UAAW,CAACI,EAAK/C,EAAQC,IAAS,CAOvC,GANA2B,EAAU,KAAK,UAAWmB,CAAG,EAMzBnB,EAAU,aAAenC,EAAU,WAAY,OAEnDkD,EAAMf,EAAU,KAAO,KAEvB,IAAMuB,EAAUJ,EAAI,QAAQ,QAE5B,GAAII,IAAY,QAAaA,EAAQ,YAAY,IAAM,YAAa,CAClElC,EAAeW,EAAW5B,EAAQ,wBAAwB,EAC1D,MACF,CAEA,IAAMoD,EAASrF,GAAW,MAAM,EAC7B,OAAOoE,EAAMzD,EAAI,EACjB,OAAO,QAAQ,EAElB,GAAIqE,EAAI,QAAQ,sBAAsB,IAAMK,EAAQ,CAClDnC,EAAeW,EAAW5B,EAAQ,qCAAqC,EACvE,MACF,CAEA,IAAMqD,EAAaN,EAAI,QAAQ,wBAAwB,EACnDO,EAYJ,GAVID,IAAe,OACZhB,EAAY,KAELA,EAAY,IAAIgB,CAAU,IACpCC,EAAY,sCAFZA,EAAY,mDAILjB,EAAY,OACrBiB,EAAY,8BAGVA,EAAW,CACbrC,EAAeW,EAAW5B,EAAQsD,CAAS,EAC3C,MACF,CAEID,IAAYzB,EAAU,UAAYyB,GAEtC,IAAME,EAAyBR,EAAI,QAAQ,0BAA0B,EAErE,GAAIQ,IAA2B,OAAW,CACxC,GAAI,CAACjB,EAAmB,CAItBrB,EAAeW,EAAW5B,EAFxB,8EAEuC,EACzC,MACF,CAEA,IAAIwD,EAEJ,GAAI,CACFA,EAAarE,GAAMoE,CAAsB,CAC3C,MAAc,CAEZtC,EAAeW,EAAW5B,EADV,yCACyB,EACzC,MACF,CAEA,IAAMyD,EAAiB,OAAO,KAAKD,CAAU,EAE7C,GACEC,EAAe,SAAW,GAC1BA,EAAe,CAAC,IAAMtF,GAAkB,cACxC,CAEA8C,EAAeW,EAAW5B,EADV,sDACyB,EACzC,MACF,CAEA,GAAI,CACFsC,EAAkB,OAAOkB,EAAWrF,GAAkB,aAAa,CAAC,CACtE,MAAc,CAEZ8C,EAAeW,EAAW5B,EADV,yCACyB,EACzC,MACF,CAEA4B,EAAU,YAAYzD,GAAkB,aAAa,EACnDmE,CACJ,CAEAV,EAAU,UAAU5B,EAAQC,EAAM,CAChC,uBAAwBsB,EAAK,uBAC7B,aAAcA,EAAK,aACnB,WAAYA,EAAK,WACjB,mBAAoBA,EAAK,kBAC3B,CAAC,CACH,CAAC,EAEGA,EAAK,cACPA,EAAK,cAAcoB,EAAKf,CAAS,EAEjCe,EAAI,IAAI,CAEZ,CASA,SAASV,GAAkBL,EAAWV,EAAK,CACzCU,EAAU,YAAcnC,EAAU,QAKlCmC,EAAU,cAAgB,GAC1BA,EAAU,KAAK,QAASV,CAAG,EAC3BU,EAAU,UAAU,CACtB,CASA,SAASY,GAAW3C,EAAS,CAC3B,OAAAA,EAAQ,KAAOA,EAAQ,WAChBjC,GAAI,QAAQiC,CAAO,CAC5B,CASA,SAAS0C,GAAW1C,EAAS,CAC3B,OAAAA,EAAQ,KAAO,OAEX,CAACA,EAAQ,YAAcA,EAAQ,aAAe,KAChDA,EAAQ,WAAajC,GAAI,KAAKiC,EAAQ,IAAI,EAAI,GAAKA,EAAQ,MAGtDhC,GAAI,QAAQgC,CAAO,CAC5B,CAWA,SAASoB,EAAeW,EAAW8B,EAAQC,EAAS,CAClD/B,EAAU,YAAcnC,EAAU,QAElC,IAAMyB,EAAM,IAAI,MAAMyC,CAAO,EAC7B,MAAM,kBAAkBzC,EAAKD,CAAc,EAEvCyC,EAAO,WACTA,EAAOrE,EAAQ,EAAI,GACnBqE,EAAO,MAAM,EAETA,EAAO,QAAU,CAACA,EAAO,OAAO,WAMlCA,EAAO,OAAO,QAAQ,EAGxB,QAAQ,SAASzB,GAAmBL,EAAWV,CAAG,IAElDwC,EAAO,QAAQxC,CAAG,EAClBwC,EAAO,KAAK,QAAS9B,EAAU,KAAK,KAAKA,EAAW,OAAO,CAAC,EAC5D8B,EAAO,KAAK,QAAS9B,EAAU,UAAU,KAAKA,CAAS,CAAC,EAE5D,CAWA,SAASN,GAAeM,EAAWZ,EAAMK,EAAI,CAC3C,GAAIL,EAAM,CACR,IAAM4C,EAAStF,GAAO0C,CAAI,EAAIA,EAAK,KAAO5B,GAAS4B,CAAI,EAAE,OAQrDY,EAAU,QAASA,EAAU,QAAQ,gBAAkBgC,EACtDhC,EAAU,iBAAmBgC,CACpC,CAEA,GAAIvC,EAAI,CACN,IAAMH,EAAM,IAAI,MACd,qCAAqCU,EAAU,UAAU,KACnDrC,GAAYqC,EAAU,UAAU,CAAC,GACzC,EACA,QAAQ,SAASP,EAAIH,CAAG,CAC1B,CACF,CASA,SAASd,GAAmBW,EAAM8C,EAAQ,CACxC,IAAMjC,EAAY,KAAK9C,CAAU,EAEjC8C,EAAU,oBAAsB,GAChCA,EAAU,cAAgBiC,EAC1BjC,EAAU,WAAab,EAEnBa,EAAU,QAAQ9C,CAAU,IAAM,SAEtC8C,EAAU,QAAQ,eAAe,OAAQhB,EAAY,EACrD,QAAQ,SAASkD,GAAQlC,EAAU,OAAO,EAEtCb,IAAS,KAAMa,EAAU,MAAM,EAC9BA,EAAU,MAAMb,EAAM8C,CAAM,EACnC,CAOA,SAASxD,IAAkB,CACzB,IAAMuB,EAAY,KAAK9C,CAAU,EAE5B8C,EAAU,UAAUA,EAAU,QAAQ,OAAO,CACpD,CAQA,SAAStB,GAAgBY,EAAK,CAC5B,IAAMU,EAAY,KAAK9C,CAAU,EAE7B8C,EAAU,QAAQ9C,CAAU,IAAM,SACpC8C,EAAU,QAAQ,eAAe,OAAQhB,EAAY,EAMrD,QAAQ,SAASkD,GAAQlC,EAAU,OAAO,EAE1CA,EAAU,MAAMV,EAAIrC,EAAW,CAAC,GAG7B+C,EAAU,gBACbA,EAAU,cAAgB,GAC1BA,EAAU,KAAK,QAASV,CAAG,EAE/B,CAOA,SAAS6C,IAAmB,CAC1B,KAAKjF,CAAU,EAAE,UAAU,CAC7B,CASA,SAASyB,GAAkBS,EAAMgD,EAAU,CACzC,KAAKlF,CAAU,EAAE,KAAK,UAAWkC,EAAMgD,CAAQ,CACjD,CAQA,SAASxD,GAAeQ,EAAM,CAC5B,IAAMY,EAAY,KAAK9C,CAAU,EAE7B8C,EAAU,WAAWA,EAAU,KAAKZ,EAAM,CAAC,KAAK,UAAWjC,EAAI,EACnE6C,EAAU,KAAK,OAAQZ,CAAI,CAC7B,CAQA,SAASP,GAAeO,EAAM,CAC5B,KAAKlC,CAAU,EAAE,KAAK,OAAQkC,CAAI,CACpC,CAQA,SAAS8C,GAAOJ,EAAQ,CACtBA,EAAO,OAAO,CAChB,CAQA,SAAShD,GAAcQ,EAAK,CAC1B,IAAMU,EAAY,KAAK9C,CAAU,EAE7B8C,EAAU,aAAenC,EAAU,SACnCmC,EAAU,aAAenC,EAAU,OACrCmC,EAAU,YAAcnC,EAAU,QAClC0B,GAAcS,CAAS,GAQzB,KAAK,QAAQ,IAAI,EAEZA,EAAU,gBACbA,EAAU,cAAgB,GAC1BA,EAAU,KAAK,QAASV,CAAG,GAE/B,CAQA,SAASC,GAAcS,EAAW,CAChCA,EAAU,YAAc,WACtBA,EAAU,QAAQ,QAAQ,KAAKA,EAAU,OAAO,EAChDA,EAAU,aACZ,CACF,CAOA,SAASjB,IAAgB,CACvB,IAAMiB,EAAY,KAAK9C,CAAU,EAiBjC,GAfA,KAAK,eAAe,QAAS6B,EAAa,EAC1C,KAAK,eAAe,OAAQC,EAAY,EACxC,KAAK,eAAe,MAAOC,EAAW,EAEtCe,EAAU,YAAcnC,EAAU,QAYhC,CAAC,KAAK,eAAe,YACrB,CAACmC,EAAU,qBACX,CAACA,EAAU,UAAU,eAAe,cACpC,KAAK,eAAe,SAAW,EAC/B,CACA,IAAMqC,EAAQ,KAAK,KAAK,KAAK,eAAe,MAAM,EAElDrC,EAAU,UAAU,MAAMqC,CAAK,CACjC,CAEArC,EAAU,UAAU,IAAI,EAExB,KAAK9C,CAAU,EAAI,OAEnB,aAAa8C,EAAU,WAAW,EAGhCA,EAAU,UAAU,eAAe,UACnCA,EAAU,UAAU,eAAe,aAEnCA,EAAU,UAAU,GAEpBA,EAAU,UAAU,GAAG,QAASmC,EAAgB,EAChDnC,EAAU,UAAU,GAAG,SAAUmC,EAAgB,EAErD,CAQA,SAASnD,GAAaqD,EAAO,CACtB,KAAKnF,CAAU,EAAE,UAAU,MAAMmF,CAAK,GACzC,KAAK,MAAM,CAEf,CAOA,SAASpD,IAAc,CACrB,IAAMe,EAAY,KAAK9C,CAAU,EAEjC8C,EAAU,YAAcnC,EAAU,QAClCmC,EAAU,UAAU,IAAI,EACxB,KAAK,IAAI,CACX,CAOA,SAASd,IAAgB,CACvB,IAAMc,EAAY,KAAK9C,CAAU,EAEjC,KAAK,eAAe,QAASgC,EAAa,EAC1C,KAAK,GAAG,QAAS/B,EAAI,EAEjB6C,IACFA,EAAU,YAAcnC,EAAU,QAClC,KAAK,QAAQ,EAEjB,ICh3CA,IAAAyE,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAGA,IAAMC,GAAY,KACZ,CAAE,OAAAC,EAAO,EAAI,QAAQ,QAAQ,EAQnC,SAASC,GAAUC,EAAQ,CACzBA,EAAO,KAAK,OAAO,CACrB,CAOA,SAASC,IAAc,CACjB,CAAC,KAAK,WAAa,KAAK,eAAe,UACzC,KAAK,QAAQ,CAEjB,CAQA,SAASC,GAAcC,EAAK,CAC1B,KAAK,eAAe,QAASD,EAAa,EAC1C,KAAK,QAAQ,EACT,KAAK,cAAc,OAAO,IAAM,GAElC,KAAK,KAAK,QAASC,CAAG,CAE1B,CAUA,SAASC,GAAsBC,EAAIC,EAAS,CAC1C,IAAIC,EAAqB,GAEnBC,EAAS,IAAIV,GAAO,CACxB,GAAGQ,EACH,YAAa,GACb,UAAW,GACX,WAAY,GACZ,mBAAoB,EACtB,CAAC,EAED,OAAAD,EAAG,GAAG,UAAW,SAAiBI,EAAKC,EAAU,CAC/C,IAAMC,EACJ,CAACD,GAAYF,EAAO,eAAe,WAAaC,EAAI,SAAS,EAAIA,EAE9DD,EAAO,KAAKG,CAAI,GAAGN,EAAG,MAAM,CACnC,CAAC,EAEDA,EAAG,KAAK,QAAS,SAAeF,EAAK,CAC/BK,EAAO,YAWXD,EAAqB,GACrBC,EAAO,QAAQL,CAAG,EACpB,CAAC,EAEDE,EAAG,KAAK,QAAS,UAAiB,CAC5BG,EAAO,WAEXA,EAAO,KAAK,IAAI,CAClB,CAAC,EAEDA,EAAO,SAAW,SAAUL,EAAKS,EAAU,CACzC,GAAIP,EAAG,aAAeA,EAAG,OAAQ,CAC/BO,EAAST,CAAG,EACZ,QAAQ,SAASJ,GAAWS,CAAM,EAClC,MACF,CAEA,IAAIK,EAAS,GAEbR,EAAG,KAAK,QAAS,SAAeF,EAAK,CACnCU,EAAS,GACTD,EAAST,CAAG,CACd,CAAC,EAEDE,EAAG,KAAK,QAAS,UAAiB,CAC3BQ,GAAQD,EAAST,CAAG,EACzB,QAAQ,SAASJ,GAAWS,CAAM,CACpC,CAAC,EAEGD,GAAoBF,EAAG,UAAU,CACvC,EAEAG,EAAO,OAAS,SAAUI,EAAU,CAClC,GAAIP,EAAG,aAAeA,EAAG,WAAY,CACnCA,EAAG,KAAK,OAAQ,UAAgB,CAC9BG,EAAO,OAAOI,CAAQ,CACxB,CAAC,EACD,MACF,CAMIP,EAAG,UAAY,OAEfA,EAAG,QAAQ,eAAe,UAC5BO,EAAS,EACLJ,EAAO,eAAe,YAAYA,EAAO,QAAQ,IAErDH,EAAG,QAAQ,KAAK,SAAU,UAAkB,CAI1CO,EAAS,CACX,CAAC,EACDP,EAAG,MAAM,GAEb,EAEAG,EAAO,MAAQ,UAAY,CACrBH,EAAG,UAAUA,EAAG,OAAO,CAC7B,EAEAG,EAAO,OAAS,SAAUM,EAAOC,EAAUH,EAAU,CACnD,GAAIP,EAAG,aAAeA,EAAG,WAAY,CACnCA,EAAG,KAAK,OAAQ,UAAgB,CAC9BG,EAAO,OAAOM,EAAOC,EAAUH,CAAQ,CACzC,CAAC,EACD,MACF,CAEAP,EAAG,KAAKS,EAAOF,CAAQ,CACzB,EAEAJ,EAAO,GAAG,MAAOP,EAAW,EAC5BO,EAAO,GAAG,QAASN,EAAa,EACzBM,CACT,CAEAZ,GAAO,QAAUQ,KChKjB,IAAAY,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAEA,GAAM,CAAE,WAAAC,EAAW,EAAI,KASvB,SAASC,GAAMC,EAAQ,CACrB,IAAMC,EAAY,IAAI,IAClBC,EAAQ,GACRC,EAAM,GACNC,EAAI,EAER,IAAKA,EAAGA,EAAIJ,EAAO,OAAQI,IAAK,CAC9B,IAAMC,EAAOL,EAAO,WAAWI,CAAC,EAEhC,GAAID,IAAQ,IAAML,GAAWO,CAAI,IAAM,EACjCH,IAAU,KAAIA,EAAQE,WAE1BA,IAAM,IACLC,IAAS,IAAkBA,IAAS,GAEjCF,IAAQ,IAAMD,IAAU,KAAIC,EAAMC,WAC7BC,IAAS,GAAgB,CAClC,GAAIH,IAAU,GACZ,MAAM,IAAI,YAAY,iCAAiCE,CAAC,EAAE,EAGxDD,IAAQ,KAAIA,EAAMC,GAEtB,IAAME,EAAWN,EAAO,MAAME,EAAOC,CAAG,EAExC,GAAIF,EAAU,IAAIK,CAAQ,EACxB,MAAM,IAAI,YAAY,QAAQA,CAAQ,6BAA6B,EAGrEL,EAAU,IAAIK,CAAQ,EACtBJ,EAAQC,EAAM,EAChB,KACE,OAAM,IAAI,YAAY,iCAAiCC,CAAC,EAAE,CAE9D,CAEA,GAAIF,IAAU,IAAMC,IAAQ,GAC1B,MAAM,IAAI,YAAY,yBAAyB,EAGjD,IAAMG,EAAWN,EAAO,MAAME,EAAOE,CAAC,EAEtC,GAAIH,EAAU,IAAIK,CAAQ,EACxB,MAAM,IAAI,YAAY,QAAQA,CAAQ,6BAA6B,EAGrE,OAAAL,EAAU,IAAIK,CAAQ,EACfL,CACT,CAEAJ,GAAO,QAAU,CAAE,MAAAE,EAAM,IC7DzB,IAAAQ,GAAAC,EAAA,CAAAC,GAAAC,KAAA,cAIA,IAAMC,GAAe,QAAQ,QAAQ,EAC/BC,GAAO,QAAQ,MAAM,EACrB,CAAE,OAAAC,EAAO,EAAI,QAAQ,QAAQ,EAC7B,CAAE,WAAAC,EAAW,EAAI,QAAQ,QAAQ,EAEjCC,GAAY,KACZC,GAAoB,KACpBC,GAAc,KACdC,GAAY,KACZ,CAAE,cAAAC,GAAe,KAAAC,GAAM,WAAAC,EAAW,EAAI,IAEtCC,GAAW,wBAEXC,GAAU,EACVC,GAAU,EACVC,GAAS,EAOTC,GAAN,cAA8Bf,EAAa,CAmCzC,YAAYgB,EAASC,EAAU,CAuB7B,GAtBA,MAAM,EAEND,EAAU,CACR,uBAAwB,GACxB,SAAU,GACV,WAAY,IAAM,KAAO,KACzB,mBAAoB,GACpB,kBAAmB,GACnB,gBAAiB,KACjB,eAAgB,GAChB,aAAcR,GACd,aAAc,KACd,SAAU,GACV,QAAS,KACT,OAAQ,KACR,KAAM,KACN,KAAM,KACN,KAAM,KACN,UAAAD,GACA,GAAGS,CACL,EAGGA,EAAQ,MAAQ,MAAQ,CAACA,EAAQ,QAAU,CAACA,EAAQ,UACpDA,EAAQ,MAAQ,OAASA,EAAQ,QAAUA,EAAQ,WACnDA,EAAQ,QAAUA,EAAQ,SAE3B,MAAM,IAAI,UACR,mFAEF,EAuBF,GApBIA,EAAQ,MAAQ,MAClB,KAAK,QAAUf,GAAK,aAAa,CAACiB,EAAKC,IAAQ,CAC7C,IAAMC,EAAOnB,GAAK,aAAa,GAAG,EAElCkB,EAAI,UAAU,IAAK,CACjB,iBAAkBC,EAAK,OACvB,eAAgB,YAClB,CAAC,EACDD,EAAI,IAAIC,CAAI,CACd,CAAC,EACD,KAAK,QAAQ,OACXJ,EAAQ,KACRA,EAAQ,KACRA,EAAQ,QACRC,CACF,GACSD,EAAQ,SACjB,KAAK,QAAUA,EAAQ,QAGrB,KAAK,QAAS,CAChB,IAAMK,EAAiB,KAAK,KAAK,KAAK,KAAM,YAAY,EAExD,KAAK,iBAAmBC,GAAa,KAAK,QAAS,CACjD,UAAW,KAAK,KAAK,KAAK,KAAM,WAAW,EAC3C,MAAO,KAAK,KAAK,KAAK,KAAM,OAAO,EACnC,QAAS,CAACJ,EAAKK,EAAQC,IAAS,CAC9B,KAAK,cAAcN,EAAKK,EAAQC,EAAMH,CAAc,CACtD,CACF,CAAC,CACH,CAEIL,EAAQ,oBAAsB,KAAMA,EAAQ,kBAAoB,CAAC,GACjEA,EAAQ,iBACV,KAAK,QAAU,IAAI,IACnB,KAAK,iBAAmB,IAG1B,KAAK,QAAUA,EACf,KAAK,OAASJ,EAChB,CAWA,SAAU,CACR,GAAI,KAAK,QAAQ,SACf,MAAM,IAAI,MAAM,4CAA4C,EAG9D,OAAK,KAAK,QACH,KAAK,QAAQ,QAAQ,EADF,IAE5B,CASA,MAAMa,EAAI,CACR,GAAI,KAAK,SAAWX,GAAQ,CACtBW,GACF,KAAK,KAAK,QAAS,IAAM,CACvBA,EAAG,IAAI,MAAM,2BAA2B,CAAC,CAC3C,CAAC,EAGH,QAAQ,SAASC,GAAW,IAAI,EAChC,MACF,CAIA,GAFID,GAAI,KAAK,KAAK,QAASA,CAAE,EAEzB,KAAK,SAAWZ,GAGpB,GAFA,KAAK,OAASA,GAEV,KAAK,QAAQ,UAAY,KAAK,QAAQ,OACpC,KAAK,UACP,KAAK,iBAAiB,EACtB,KAAK,iBAAmB,KAAK,QAAU,MAGrC,KAAK,QACF,KAAK,QAAQ,KAGhB,KAAK,iBAAmB,GAFxB,QAAQ,SAASa,GAAW,IAAI,EAKlC,QAAQ,SAASA,GAAW,IAAI,MAE7B,CACL,IAAMC,EAAS,KAAK,QAEpB,KAAK,iBAAiB,EACtB,KAAK,iBAAmB,KAAK,QAAU,KAMvCA,EAAO,MAAM,IAAM,CACjBD,GAAU,IAAI,CAChB,CAAC,CACH,CACF,CASA,aAAaR,EAAK,CAChB,GAAI,KAAK,QAAQ,KAAM,CACrB,IAAMU,EAAQV,EAAI,IAAI,QAAQ,GAAG,EAGjC,IAFiBU,IAAU,GAAKV,EAAI,IAAI,MAAM,EAAGU,CAAK,EAAIV,EAAI,OAE7C,KAAK,QAAQ,KAAM,MAAO,EAC7C,CAEA,MAAO,EACT,CAWA,cAAcA,EAAKK,EAAQC,EAAMC,EAAI,CACnCF,EAAO,GAAG,QAASM,EAAa,EAEhC,IAAMC,EAAMZ,EAAI,QAAQ,mBAAmB,EACrCa,EAAUb,EAAI,QAAQ,QACtBc,EAAU,CAACd,EAAI,QAAQ,uBAAuB,EAEpD,GAAIA,EAAI,SAAW,MAAO,CAExBe,GAAkC,KAAMf,EAAKK,EAAQ,IADrC,qBACiD,EACjE,MACF,CAEA,GAAIQ,IAAY,QAAaA,EAAQ,YAAY,IAAM,YAAa,CAElEE,GAAkC,KAAMf,EAAKK,EAAQ,IADrC,wBACiD,EACjE,MACF,CAEA,GAAIO,IAAQ,QAAa,CAACnB,GAAS,KAAKmB,CAAG,EAAG,CAE5CG,GAAkC,KAAMf,EAAKK,EAAQ,IADrC,6CACiD,EACjE,MACF,CAEA,GAAIS,IAAY,IAAMA,IAAY,EAAG,CAEnCC,GAAkC,KAAMf,EAAKK,EAAQ,IADrC,kDACmD,CACjE,wBAAyB,OAC3B,CAAC,EACD,MACF,CAEA,GAAI,CAAC,KAAK,aAAaL,CAAG,EAAG,CAC3BgB,GAAeX,EAAQ,GAAG,EAC1B,MACF,CAEA,IAAMY,EAAuBjB,EAAI,QAAQ,wBAAwB,EAC7DkB,EAAY,IAAI,IAEpB,GAAID,IAAyB,OAC3B,GAAI,CACFC,EAAY9B,GAAY,MAAM6B,CAAoB,CACpD,MAAc,CAEZF,GAAkC,KAAMf,EAAKK,EAAQ,IADrC,uCACiD,EACjE,MACF,CAGF,IAAMc,EAAyBnB,EAAI,QAAQ,0BAA0B,EAC/DoB,EAAa,CAAC,EAEpB,GACE,KAAK,QAAQ,mBACbD,IAA2B,OAC3B,CACA,IAAME,EAAoB,IAAIlC,GAC5B,KAAK,QAAQ,kBACb,GACA,KAAK,QAAQ,UACf,EAEA,GAAI,CACF,IAAMmC,EAASpC,GAAU,MAAMiC,CAAsB,EAEjDG,EAAOnC,GAAkB,aAAa,IACxCkC,EAAkB,OAAOC,EAAOnC,GAAkB,aAAa,CAAC,EAChEiC,EAAWjC,GAAkB,aAAa,EAAIkC,EAElD,MAAc,CAGZN,GAAkC,KAAMf,EAAKK,EAAQ,IADnD,yDAC+D,EACjE,MACF,CACF,CAKA,GAAI,KAAK,QAAQ,aAAc,CAC7B,IAAMkB,EAAO,CACX,OACEvB,EAAI,QAAQ,GAAGc,IAAY,EAAI,uBAAyB,QAAQ,EAAE,EACpE,OAAQ,CAAC,EAAEd,EAAI,OAAO,YAAcA,EAAI,OAAO,WAC/C,IAAAA,CACF,EAEA,GAAI,KAAK,QAAQ,aAAa,SAAW,EAAG,CAC1C,KAAK,QAAQ,aAAauB,EAAM,CAACC,EAAUC,EAAMC,EAASC,IAAY,CACpE,GAAI,CAACH,EACH,OAAOR,GAAeX,EAAQoB,GAAQ,IAAKC,EAASC,CAAO,EAG7D,KAAK,gBACHP,EACAR,EACAM,EACAlB,EACAK,EACAC,EACAC,CACF,CACF,CAAC,EACD,MACF,CAEA,GAAI,CAAC,KAAK,QAAQ,aAAagB,CAAI,EAAG,OAAOP,GAAeX,EAAQ,GAAG,CACzE,CAEA,KAAK,gBAAgBe,EAAYR,EAAKM,EAAWlB,EAAKK,EAAQC,EAAMC,CAAE,CACxE,CAeA,gBAAgBa,EAAYR,EAAKM,EAAWlB,EAAKK,EAAQC,EAAMC,EAAI,CAIjE,GAAI,CAACF,EAAO,UAAY,CAACA,EAAO,SAAU,OAAOA,EAAO,QAAQ,EAEhE,GAAIA,EAAOb,EAAU,EACnB,MAAM,IAAI,MACR,2GAEF,EAGF,GAAI,KAAK,OAASE,GAAS,OAAOsB,GAAeX,EAAQ,GAAG,EAM5D,IAAMsB,EAAU,CACd,mCACA,qBACA,sBACA,yBARa1C,GAAW,MAAM,EAC7B,OAAO2B,EAAMrB,EAAI,EACjB,OAAO,QAAQ,CAMe,EACjC,EAEMqC,EAAK,IAAI,KAAK,QAAQ,UAAU,KAAM,OAAW,KAAK,OAAO,EAEnE,GAAIV,EAAU,KAAM,CAIlB,IAAMW,EAAW,KAAK,QAAQ,gBAC1B,KAAK,QAAQ,gBAAgBX,EAAWlB,CAAG,EAC3CkB,EAAU,OAAO,EAAE,KAAK,EAAE,MAE1BW,IACFF,EAAQ,KAAK,2BAA2BE,CAAQ,EAAE,EAClDD,EAAG,UAAYC,EAEnB,CAEA,GAAIT,EAAWjC,GAAkB,aAAa,EAAG,CAC/C,IAAM2C,EAASV,EAAWjC,GAAkB,aAAa,EAAE,OACrD4C,EAAQ7C,GAAU,OAAO,CAC7B,CAACC,GAAkB,aAAa,EAAG,CAAC2C,CAAM,CAC5C,CAAC,EACDH,EAAQ,KAAK,6BAA6BI,CAAK,EAAE,EACjDH,EAAG,YAAcR,CACnB,CAKA,KAAK,KAAK,UAAWO,EAAS3B,CAAG,EAEjCK,EAAO,MAAMsB,EAAQ,OAAO;AAAA,CAAM,EAAE,KAAK;AAAA,CAAM,CAAC,EAChDtB,EAAO,eAAe,QAASM,EAAa,EAE5CiB,EAAG,UAAUvB,EAAQC,EAAM,CACzB,uBAAwB,KAAK,QAAQ,uBACrC,WAAY,KAAK,QAAQ,WACzB,mBAAoB,KAAK,QAAQ,kBACnC,CAAC,EAEG,KAAK,UACP,KAAK,QAAQ,IAAIsB,CAAE,EACnBA,EAAG,GAAG,QAAS,IAAM,CACnB,KAAK,QAAQ,OAAOA,CAAE,EAElB,KAAK,kBAAoB,CAAC,KAAK,QAAQ,MACzC,QAAQ,SAASpB,GAAW,IAAI,CAEpC,CAAC,GAGHD,EAAGqB,EAAI5B,CAAG,CACZ,CACF,EAEAnB,GAAO,QAAUgB,GAYjB,SAASO,GAAaK,EAAQuB,EAAK,CACjC,QAAWC,KAAS,OAAO,KAAKD,CAAG,EAAGvB,EAAO,GAAGwB,EAAOD,EAAIC,CAAK,CAAC,EAEjE,OAAO,UAA2B,CAChC,QAAWA,KAAS,OAAO,KAAKD,CAAG,EACjCvB,EAAO,eAAewB,EAAOD,EAAIC,CAAK,CAAC,CAE3C,CACF,CAQA,SAASzB,GAAUC,EAAQ,CACzBA,EAAO,OAASb,GAChBa,EAAO,KAAK,OAAO,CACrB,CAOA,SAASE,IAAgB,CACvB,KAAK,QAAQ,CACf,CAWA,SAASK,GAAeX,EAAQoB,EAAMC,EAASC,EAAS,CAStDD,EAAUA,GAAW3C,GAAK,aAAa0C,CAAI,EAC3CE,EAAU,CACR,WAAY,QACZ,eAAgB,YAChB,iBAAkB,OAAO,WAAWD,CAAO,EAC3C,GAAGC,CACL,EAEAtB,EAAO,KAAK,SAAUA,EAAO,OAAO,EAEpCA,EAAO,IACL,YAAYoB,CAAI,IAAI1C,GAAK,aAAa0C,CAAI,CAAC;AAAA,EACzC,OAAO,KAAKE,CAAO,EAChB,IAAKO,GAAM,GAAGA,CAAC,KAAKP,EAAQO,CAAC,CAAC,EAAE,EAChC,KAAK;AAAA,CAAM,EACd;AAAA;AAAA,EACAR,CACJ,CACF,CAcA,SAASX,GACPN,EACAT,EACAK,EACAoB,EACAC,EACAC,EACA,CACA,GAAIlB,EAAO,cAAc,eAAe,EAAG,CACzC,IAAM0B,EAAM,IAAI,MAAMT,CAAO,EAC7B,MAAM,kBAAkBS,EAAKpB,EAAiC,EAE9DN,EAAO,KAAK,gBAAiB0B,EAAK9B,EAAQL,CAAG,CAC/C,MACEgB,GAAeX,EAAQoB,EAAMC,EAASC,CAAO,CAEjD,ICziBA,IAAAS,GAAA,GAAAC,GAAAD,GAAA,iBAAAE,QAAA,cAAAC,QAAA,iBAAAC,QAAA,uBAAAC,QAAA,6BAAAC,QAAA,YAAAC,KAAA,IAAAC,GACAC,GACAC,GACAC,GACAC,GAGOL,GAPPM,GAAAC,GAAA,kBAAAN,GAAkC,WAClCC,GAAqB,WACrBC,GAAmB,WACnBC,GAAsB,WACtBC,GAA4B,WAGrBL,GAAQ,GAAAH,UCPf,IAAAW,GAAA,GAAAC,GAAAD,GAAA,mBAAAE,GAAA,oBAAAC,GAAA,yBAAAC,GAAA,oBAAAC,GAAA,yBAAAC,GAAA,2BAAAC,GAAA,8BAAAC,GAAA,+BAAAC,GAAA,qBAAAC,GAAA,uBAAAC,EAAA,yBAAAC,GAAA,iBAAAC,GAAA,gBAAAC,GAAA,iBAAAC,GAAA,mBAAAC,GAAA,mBAAAC,GAAA,eAAAC,GAAA,mBAAAC,GAAA,eAAAC,EAAA,oBAAAC,GAAA,iBAAAC,GAAA,kBAAAC,GAAA,YAAAC,GAAA,gBAAAC,GAAA,oBAAAC,KAAA,eAAAC,GAAA3B,ICYO,SAAS4B,EAAeC,EAAoB,CACjD,GAAIA,EAAK,IACP,MAAO,GAAG,KAAK,MAAMA,CAAE,CAAC,KAG1B,GAAIA,EAAK,IAGP,MAAO,IAFSA,EAAK,KAEH,QAAQ,CAAC,EAAE,QAAQ,OAAQ,EAAE,CAAC,IAGlD,IAAMC,EAAU,KAAK,MAAMD,EAAK,GAAK,EAC/BE,EAAU,KAAK,MAAOF,EAAK,IAAS,GAAI,EAE9C,OAAIE,IAAY,EACP,GAAGD,CAAO,IAGZ,GAAGA,CAAO,KAAKC,CAAO,GAC/B,CAKO,SAASC,IAAqB,CACnC,MAAO,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAG,CAAC,CAAC,EACrE,CCGA,SAASC,GAAkBC,EAA4B,CACrD,QAAWC,KAAQD,EAUjB,IANGC,EAAK,OAAS,YAAcA,EAAK,OAAS,QAAUA,EAAK,OAAS,aACnE,CAACA,EAAK,GAAG,WAAW,WAAW,GAK7B,eAAgBA,EAClB,MAAO,GAGX,MAAO,EACT,CAcO,SAASC,GACdF,EACAG,EAAmC,CAAC,EACxB,CAGZ,GAAIJ,GAAkBC,CAAK,EACzB,OAAOA,EAGT,GAAM,CAAE,aAAAI,EAAe,EAAG,SAAAC,EAAW,CAAE,EAAIF,EAGrCG,EAA8D,CAAC,EAC/DC,EAA4D,CAAC,EAEnE,QAASC,EAAI,EAAGA,EAAIR,EAAM,OAAQQ,IAAK,CACrC,IAAMP,EAAOD,EAAMQ,CAAC,EAChBP,EAAK,OAAS,QAAUA,EAAK,UAAY,OAC3CK,EAAgB,KAAK,CACnB,KAAAL,EACA,QAASA,EAAK,QACd,MAAOA,EAAK,OAASA,EAAK,SAAWA,EAAK,YAAc,GACxD,cAAeO,CACjB,CAAC,EAGDD,EAAa,KAAK,CAAE,KAAAN,EAAM,cAAeO,CAAE,CAAC,CAEhD,CAEA,GAAIF,EAAgB,QAAU,EAC5B,OAAON,EAITM,EAAgB,KAAK,CAAC,EAAGG,IAAM,EAAE,QAAUA,EAAE,OAAO,EAIpD,IAAMC,EAAkC,CAAC,EACrCC,EAAsC,CAACL,EAAgB,CAAC,CAAC,EAE7D,QAASE,EAAI,EAAGA,EAAIF,EAAgB,OAAQE,IAAK,CAC/C,IAAMI,EAAON,EAAgBE,CAAC,EACxBK,EAAa,KAAK,IAAI,GAAGF,EAAa,IAAKG,GAAMA,EAAE,OAAO,CAAC,EAC3DC,EAAW,KAAK,IAAI,GAAGJ,EAAa,IAAKG,GAAMA,EAAE,KAAK,CAAC,EAKvDE,EAAkBJ,EAAK,SAAWC,EAAaR,EAC/CY,EAAiBL,EAAK,QAAUG,EAEtC,GAAI,CAACC,GAAmB,CAACC,EAAgB,CAEvCP,EAAO,KAAKC,CAAY,EACxBA,EAAe,CAACC,CAAI,EACpB,QACF,CAKA,IAAMM,EAAkBD,EACpB,KAAK,IAAIL,EAAK,MAAOG,CAAQ,EAAIH,EAAK,QACtC,EAIAI,GAAmBE,GAAmBd,EACxCO,EAAa,KAAKC,CAAI,GAGtBF,EAAO,KAAKC,CAAY,EACxBA,EAAe,CAACC,CAAI,EAExB,CACAF,EAAO,KAAKC,CAAY,EAGxB,IAAMQ,EAAuD,CAAC,EAE9D,QAAWC,KAASV,EAAQ,CAE1B,IAAMW,EAAW,KAAK,IAAI,GAAGD,EAAM,IAAKN,GAAMA,EAAE,aAAa,CAAC,EAE9D,GAAIM,EAAM,SAAW,EAEnBD,EAAa,KAAK,CAAE,KAAMC,EAAM,CAAC,EAAE,KAAM,SAAAC,CAAS,CAAC,MAC9C,CAEL,IAAMC,EAAWF,EAAM,IAAKN,GAAMA,EAAE,IAAI,EAClCS,EAAU,KAAK,IAAI,GAAGH,EAAM,IAAKN,GAAMA,EAAE,OAAO,CAAC,EACjDU,EAAQ,KAAK,IAAI,GAAGJ,EAAM,IAAKN,GAAMA,EAAE,KAAK,CAAC,EAE7CW,EAA6B,CACjC,KAAM,WACN,GAAI,qBAAqBF,CAAO,GAChC,KAAM,GAAGD,EAAS,MAAM,kBACxB,MAAOI,GAAiBJ,CAAQ,EAChC,KAAM,MACN,SAAAA,EACA,QAAAC,EACA,MAAAC,EACA,WAAYA,EAAQD,CACtB,EAEAJ,EAAa,KAAK,CAAE,KAAMM,EAAc,SAAAJ,CAAS,CAAC,CACpD,CACF,CAGA,OAAW,CAAE,KAAApB,EAAM,cAAA0B,CAAc,IAAKpB,EACpCY,EAAa,KAAK,CAAE,KAAAlB,EAAM,SAAU0B,CAAc,CAAC,EAIrD,OAAAR,EAAa,KAAK,CAAC,EAAGV,IAAM,EAAE,SAAWA,EAAE,QAAQ,EAE5CU,EAAa,IAAKS,GAAMA,EAAE,IAAI,CACvC,CAKA,SAASF,GACPJ,EACoE,CAEpE,OADiBA,EAAS,KAAMO,GAAMA,EAAE,QAAU,OAAO,EACpC,QAEFP,EAAS,KAAMO,GAAMA,EAAE,QAAU,SAAS,EACtC,UAEJP,EAAS,KAAMO,GAAMA,EAAE,QAAU,SAAS,EACtC,WAEJP,EAAS,MACzBO,GAAMA,EAAE,QAAU,WAAaA,EAAE,QAAU,QAC9C,EACuB,UAGzB,CAKO,SAASC,GAAuB3B,EAAmC,CAAC,EAAG,CAC5E,MAAO,CAIL,OAASH,GAAsBE,GAAqBF,EAAOG,CAAO,CACpE,CACF,CCzHO,SAAS4B,GAAgBC,EAA4B,CAAC,EAAG,CAC9D,GAAM,CACJ,eAAAC,EAAiB,GACjB,kBAAAC,EACA,gBAAAC,EAAkB,GAClB,aAAAC,EAAe,GACjB,EAAIJ,EAGAK,EACAC,EACAC,EAA2B,UAC3BC,EACAC,EAGEC,EAAc,IAAI,IAGlBC,EAA4B,CAAC,EAG7BC,EAAkC,CAAC,EAGrCC,EAA2B,CAAC,EAG5BC,EAAY,KAAK,IAAI,EACrBC,EAAgBD,EAGhBE,EAA2B,CAC7B,YAAa,IAAI,GACnB,EAGMC,EAA0B,CAAC,EAC7BC,EAAa,EAOjB,SAASC,EAAUC,EAAqE,CACtF,OAAOA,EAAM,QAAUA,EAAM,SAAWA,EAAM,MAAQC,GAAW,CACnE,CAKA,SAASC,EAAQC,EAAsB,CAErC,GAAIX,EAAc,OAAS,EAAG,CAC5B,IAAMY,EAAWZ,EAAcA,EAAc,OAAS,CAAC,EAEvD,QAAWa,KAAUD,EAAS,SAAS,OAAO,EAC5C,GAAIC,EAAO,MAAO,CAChBA,EAAO,SAAS,KAAKF,CAAI,EACzBR,EAAgB,KAAK,IAAI,EACzB,MACF,CAIF,IAAMW,EAAc,MAAM,KAAKF,EAAS,SAAS,OAAO,CAAC,EAAE,CAAC,EAC5D,GAAIE,EAAa,CACfA,EAAY,SAAS,KAAKH,CAAI,EAC9BR,EAAgB,KAAK,IAAI,EACzB,MACF,CACF,CAGIJ,EAAW,OAAS,EAEtBA,EAAWA,EAAW,OAAS,CAAC,EAAE,SAAS,KAAKY,CAAI,EAGpDV,EAAa,KAAKU,CAAI,EAExBR,EAAgB,KAAK,IAAI,CAC3B,CAMA,SAASY,EAAgBP,EAAqC,CAC5D,GAAI,CAACjB,EAAiB,OAGtB,IAAMyB,EAAKC,EAAM,EAGXC,EAAkB,IAAI,IAC5B,OAAW,CAACC,EAAIC,EAAI,IAAKtB,EACvBoB,EAAgB,IAAIC,EAAI,CACtB,GAAIC,GAAK,GACT,KAAMA,GAAK,KACX,IAAKA,GAAK,IACV,QAASA,GAAK,QACd,WAAYA,GAAK,WACjB,SAAUA,GAAK,SACf,UAAWA,GAAK,SAClB,CAAC,EAGH,IAAMC,EAAuB,CAC3B,GAAI,YAAYf,CAAU,GAC1B,WAAAA,EACA,MAAO,gBAAgBE,CAAK,EAC5B,GAAI,gBAAgBQ,CAAE,EACtB,UAAW,KAAK,IAAI,EACpB,YAAaE,CACf,EAEAb,EAAU,KAAKgB,CAAQ,EAGnBhB,EAAU,OAASb,GACrBa,EAAU,MAAM,EAGlBC,GACF,CAKA,SAASgB,EAAYd,EAAqC,CACxD,OAAQA,EAAM,KAAM,CAClB,IAAK,iBACHf,EAAae,EAAM,WACnBd,EAAkBc,EAAM,GACxBb,EAAgB,UAChBO,EAAY,KAAK,IAAI,EACrBC,EAAgBD,EAIhBE,EAAU,YAAc,IAAI,IAC5B,MAEF,IAAK,mBACHT,EAAgB,UAChBE,EAAqBW,EAAM,WAC3BL,EAAgB,KAAK,IAAI,EACzB,MAEF,IAAK,iBACHR,EAAgB,QAChBC,EAAgBY,EAAM,MACtBX,EAAqBW,EAAM,WAC3BL,EAAgB,KAAK,IAAI,EACzB,MAEF,IAAK,aAAc,CACjB,IAAMgB,EAAKZ,EAAUC,CAAK,EAC1BV,EAAY,IAAIqB,EAAI,CAClB,GAAAA,EACA,KAAMX,EAAM,KACZ,IAAKA,EAAM,QACX,QAASA,EAAM,GACf,WAAY,EACZ,SAAU,EACZ,CAAC,EACDL,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,eAAgB,CACnB,IAAMgB,EAAKZ,EAAUC,CAAK,EACpBe,EAASzB,EAAY,IAAIqB,CAAE,EACjC,GAAII,EAAQ,CACV,IAAMZ,EAAiB,CACrB,KAAM,OACN,GAAIY,EAAO,GACX,KAAMA,EAAO,KACb,IAAKA,EAAO,IACZ,MAAO,UACP,QAASA,EAAO,QAChB,MAAOf,EAAM,GACb,WAAYA,EAAM,WAClB,GAAIe,EAAO,WAAa,GAAK,CAAE,WAAYA,EAAO,UAAW,EAC7D,GAAIA,EAAO,UAAY,CAAE,SAAU,GAAM,UAAWA,EAAO,SAAU,CACvE,EACAb,EAAQC,CAAI,EACZb,EAAY,OAAOqB,CAAE,CACvB,CACA,KACF,CAEA,IAAK,aAAc,CACjB,IAAMA,EAAKZ,EAAUC,CAAK,EACpBe,EAASzB,EAAY,IAAIqB,CAAE,EACjC,GAAII,EAAQ,CACV,IAAMZ,EAAiB,CACrB,KAAM,OACN,GAAIY,EAAO,GACX,KAAMA,EAAO,KACb,IAAKA,EAAO,IACZ,MAAO,QACP,QAASA,EAAO,QAChB,MAAOf,EAAM,GACb,WAAYA,EAAM,WAClB,MAAOA,EAAM,MACb,GAAIe,EAAO,WAAa,GAAK,CAAE,WAAYA,EAAO,UAAW,EAC7D,GAAIA,EAAO,UAAY,CAAE,SAAU,GAAM,UAAWA,EAAO,SAAU,CACvE,EACAb,EAAQC,CAAI,EACZb,EAAY,OAAOqB,CAAE,CACvB,CACA,KACF,CAEA,IAAK,eAAgB,CACnB,IAAMA,EAAKZ,EAAUC,CAAK,EACpBe,EAASzB,EAAY,IAAIqB,CAAE,EACjC,GAAII,EAAQ,CACV,IAAMZ,EAAiB,CACrB,KAAM,OACN,GAAIY,EAAO,GACX,KAAMA,EAAO,KACb,IAAKA,EAAO,IACZ,MAAO,UACP,QAASA,EAAO,QAChB,MAAOf,EAAM,GACb,WAAYA,EAAM,WAClB,GAAIe,EAAO,WAAa,GAAK,CAAE,WAAYA,EAAO,UAAW,EAC7D,GAAIA,EAAO,UAAY,CAAE,SAAU,GAAM,UAAWA,EAAO,SAAU,CACvE,EACAb,EAAQC,CAAI,EACZb,EAAY,OAAOqB,CAAE,CACvB,CACA,KACF,CAEA,IAAK,iBAAkB,CAErB,IAAMR,EAAiB,CACrB,KAAM,OACN,GAHSJ,EAAUC,CAAK,EAIxB,KAAMA,EAAM,KACZ,IAAKA,EAAM,QACX,MAAO,SACP,QAASA,EAAM,GACf,MAAOA,EAAM,GACb,WAAY,CACd,EACAE,EAAQC,CAAI,EACZ,KACF,CAEA,IAAK,kBAGH,MAEF,IAAK,gBAGH,MAEF,IAAK,eAAgB,CAGnB,IAAMQ,EAAKZ,EAAUC,CAAK,EACpBe,EAASzB,EAAY,IAAIqB,CAAE,EAC7BI,IACFA,EAAO,SAAW,GAClBA,EAAO,UAAYf,EAAM,WAE3BL,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,aAAc,CAEjB,IAAMgB,EAAKZ,EAAUC,CAAK,EACpBe,EAASzB,EAAY,IAAIqB,CAAE,EAC7BI,IACFA,EAAO,YAAcf,EAAM,SAAW,GAAK,GAE7CL,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,yBAGHA,EAAgB,KAAK,IAAI,EACzB,MAEF,IAAK,eAAgB,CAEnB,IAAMQ,EAAiB,CACrB,KAAM,OACN,GAHSJ,EAAUC,CAAK,EAIxB,KAAMA,EAAM,KACZ,IAAKA,EAAM,QACX,MAAO,UACP,QAASA,EAAM,GACf,MAAOA,EAAM,GACb,WAAY,CACd,EACAE,EAAQC,CAAI,EACZ,KACF,CAGA,IAAK,kBAAmB,CACtB,IAAMa,EAA0B,CAC9B,KAAM,YACN,MAAO,UACP,GAAIhB,EAAM,GACV,WAAYA,EAAM,WAClB,QAAS,CACP,OAAQA,EAAM,OACd,QAASA,EAAM,OACjB,CACF,EACAJ,EAAU,UAAYoB,EACtBrB,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,wBAAyB,CAC5B,IAAMqB,EAA0B,CAC9B,KAAM,YACN,MAAO,QACP,GAAIhB,EAAM,GACV,WAAYA,EAAM,WAClB,MAAOA,EAAM,KACf,EACAJ,EAAU,UAAYoB,EACtBrB,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,oBAAqB,CACxB,IAAMqB,EAA0B,CAC9B,KAAM,gBACN,MAAO,UACP,GAAIhB,EAAM,GACV,WAAYA,EAAM,WAClB,QAAS,CACP,OAAQA,EAAM,OACd,QAASA,EAAM,OACjB,CACF,EACAJ,EAAU,cAAgBoB,EAC1BrB,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,0BAA2B,CAC9B,IAAMqB,EAA0B,CAC9B,KAAM,gBACN,MAAO,QACP,GAAIhB,EAAM,GACV,WAAYA,EAAM,WAClB,MAAOA,EAAM,KACf,EACAJ,EAAU,cAAgBoB,EAC1BrB,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,kBAAmB,CACtB,IAAMqB,EAA0B,CAC9B,KAAM,cACN,MAAO,UACP,GAAIhB,EAAM,GACV,WAAYA,EAAM,WAClB,QAAS,CACP,QAASA,EAAM,OACjB,CACF,EACAJ,EAAU,YAAY,IAAII,EAAM,QAASgB,CAAQ,EACjDrB,EAAgB,KAAK,IAAI,EACzB,KACF,CAEA,IAAK,wBAAyB,CAC5B,IAAMqB,EAA0B,CAC9B,KAAM,cACN,MAAO,QACP,GAAIhB,EAAM,GACV,WAAYA,EAAM,WAClB,MAAOA,EAAM,MACb,QAAS,CACP,QAASA,EAAM,OACjB,CACF,EACAJ,EAAU,YAAY,IAAII,EAAM,QAASgB,CAAQ,EACjDrB,EAAgB,KAAK,IAAI,EACzB,KACF,CACF,CAGAY,EAAgBP,CAAK,CACvB,CAKA,SAASiB,EAAiBjB,EAA8C,CACtE,GAAIA,EAAM,OAAS,cACjBT,EAAW,KAAK,CACd,GAAIS,EAAM,QACV,KAAMA,EAAM,KACZ,KAAMA,EAAM,UACZ,QAASA,EAAM,GACf,SAAU,CAAC,CACb,CAAC,EACDL,EAAgB,KAAK,IAAI,UAChBK,EAAM,OAAS,YAAa,CACrC,IAAMkB,EAAQ3B,EAAW,IAAI,EAC7B,GAAI2B,EAAO,CACT,IAAMf,EACJe,EAAM,OAAS,OACX,CACE,KAAM,OACN,GAAIA,EAAM,GACV,KAAMA,EAAM,KACZ,MAAOC,EAAYD,EAAM,QAAQ,EACjC,QAASA,EAAM,QACf,MAAOlB,EAAM,GACb,WAAYA,EAAM,WAClB,SAAUkB,EAAM,SAChB,SAAUlB,EAAM,QAClB,EACA,CACE,KAAM,WACN,GAAIkB,EAAM,GACV,KAAMA,EAAM,KACZ,MAAOC,EAAYD,EAAM,QAAQ,EACjC,QAASA,EAAM,QACf,MAAOlB,EAAM,GACb,WAAYA,EAAM,WAClB,SAAUkB,EAAM,SAChB,KAAMA,EAAM,OAAS,aAAe,aAAe,KACrD,EACNhB,EAAQC,CAAI,CACd,CACF,CACF,CAKA,SAASiB,EACPpB,EACM,CACN,GAAIA,EAAM,OAAS,iBACjBR,EAAc,KAAK,CACjB,GAAIQ,EAAM,WACV,KAAMA,EAAM,KACZ,UAAWA,EAAM,UACjB,cAAeA,EAAM,cACrB,QAASA,EAAM,GACf,SAAU,IAAI,GAChB,CAAC,EACDL,EAAgB,KAAK,IAAI,UAChBK,EAAM,OAAS,kBAAmB,CAC3C,IAAMI,EAAWZ,EAAcA,EAAc,OAAS,CAAC,EACvD,GAAIY,GAAYA,EAAS,KAAOJ,EAAM,WAAY,CAEhD,IAAMqB,EAAYrB,EAAM,YAClBsB,EAAWlB,EAAS,SAAS,IAAIiB,CAAS,EAC5CC,EAEFA,EAAS,MAAQtB,EAAM,MAGvBI,EAAS,SAAS,IAAIiB,EAAW,CAC/B,MAAOrB,EAAM,YACb,UAAWA,EAAM,UACjB,MAAOA,EAAM,MACb,SAAU,CAAC,CACb,CAAC,EAEHL,EAAgB,KAAK,IAAI,CAC3B,CACF,SAAWK,EAAM,OAAS,eAAgB,CACxC,IAAMI,EAAWZ,EAAc,IAAI,EACnC,GAAIY,GAAYA,EAAS,KAAOJ,EAAM,WAAY,CAEhD,IAAMuB,EAA6B,MAAM,KAAKnB,EAAS,SAAS,OAAO,CAAC,EAElED,EAAqB,CACzB,KAAM,WACN,GAAIC,EAAS,GACb,KAAMA,EAAS,KACf,MAAOe,EACLI,EAAS,QAASC,GAAOA,EAAE,MAAQA,EAAE,SAAW,CAAC,CAAE,CACrD,EACA,QAASpB,EAAS,QAClB,MAAOJ,EAAM,GACb,WAAYA,EAAM,WAClB,UAAWI,EAAS,UACpB,cAAeA,EAAS,cACxB,YAAaJ,EAAM,aAAeI,EAAS,YAC3C,SAAAmB,CACF,EACArB,EAAQC,CAAI,CACd,CACF,CACF,CAKA,SAASgB,EAAYM,EAAiC,CACpD,OAAIA,EAAS,SAAW,EAAU,UAEjBA,EAAS,KAAMC,GAAMA,EAAE,QAAU,OAAO,EACpC,QAEFD,EAAS,MACzBC,GAAMA,EAAE,QAAU,WAAaA,EAAE,QAAU,QAC9C,EACuB,UAEJD,EAAS,KAAMC,GAAMA,EAAE,QAAU,SAAS,EACtC,UAEhB,SACT,CAKA,SAASC,GAA8B,CACrC,IAAMC,EAAQ,CAAC,GAAGnC,CAAY,EAG9B,OAAW,CAAC,CAAEsB,CAAM,IAAKzB,EACvBsC,EAAM,KAAK,CACT,KAAM,OACN,GAAIb,EAAO,GACX,KAAMA,EAAO,KACb,IAAKA,EAAO,IACZ,MAAO,UACP,QAASA,EAAO,QAChB,GAAIA,EAAO,WAAa,GAAK,CAAE,WAAYA,EAAO,UAAW,EAC7D,GAAIA,EAAO,UAAY,CAAE,SAAU,GAAM,UAAWA,EAAO,SAAU,CACvE,CAAC,EAGH,OAAOa,CACT,CAKA,SAASnB,GAAoB,CAC3B,IAAIgB,EAAWE,EAAgB,EAG3B9C,IACF4C,EAAWI,GAAqBJ,EAAU3C,CAAiB,GAG7D,IAAMgD,EAAqB,CACzB,KAAM,WACN,GAAI7C,GAAcgB,GAAW,EAC7B,WAAYhB,GAAc,UAC1B,MAAOE,EACP,QAASD,EACT,WAAYG,EACZ,SAAAoC,EACA,MAAOrC,CACT,EAGM2C,EACJnC,EAAU,YAAc,QACxBA,EAAU,gBAAkB,QAC5BA,EAAU,YAAY,KAAO,EAE/B,MAAO,CACL,KAAAkC,EACA,SAAU,CACR,UAAApC,EACA,cAAAC,CACF,EACA,GAAIoC,GAAY,CAAE,MAAOnC,CAAU,CACrC,CACF,CAKA,SAASoC,GAAc,CACrB/C,EAAa,OACbC,EAAkB,OAClBC,EAAgB,UAChBC,EAAgB,OAChBC,EAAqB,OACrBC,EAAY,MAAM,EAClBC,EAAW,OAAS,EACpBC,EAAc,OAAS,EACvBC,EAAe,CAAC,EAChBC,EAAY,KAAK,IAAI,EACrBC,EAAgBD,EAEhBE,EAAY,CACV,YAAa,IAAI,GACnB,EAEAC,EAAU,OAAS,EACnBC,EAAa,CACf,CAKA,SAASmC,GAA6B,CACpC,MAAO,CAAC,GAAGpC,CAAS,CACtB,CAKA,SAASqC,EAAcC,EAAuC,CAC5D,OAAOtC,EAAUsC,CAAK,CACxB,CAKA,SAASC,EAAQD,EAAuC,CACtD,OAAOtC,EAAUsC,CAAK,GAAG,EAC3B,CAKA,SAASE,GAAuB,CAC9BxC,EAAU,OAAS,EACnBC,EAAa,CACf,CAEA,MAAO,CACL,YAAAgB,EACA,iBAAAG,EACA,oBAAAG,EACA,MAAAX,EACA,MAAAuB,EAEA,aAAAC,EACA,cAAAC,EACA,QAAAE,EACA,eAAAC,EAEA,IAAI,gBAAiB,CACnB,OAAO/C,EAAY,KAAO,CAC5B,EAEA,IAAI,OAAQ,CACV,OAAOH,CACT,EAEA,IAAI,eAAgB,CAClB,OAAOU,EAAU,MACnB,EAEA,IAAI,kBAAmB,CACrB,OAAOd,CACT,CACF,CACF,CCzYO,SAASuD,EAAWC,EAAkC,CAC3D,OAAOA,EAAK,OAAS,MACvB,CAKO,SAASC,GAAeD,EAAsC,CACnE,OAAOA,EAAK,OAAS,UACvB,CAKO,SAASE,GAAeF,EAAsC,CACnE,OAAOA,EAAK,OAAS,UACvB,CAKO,SAASG,GAAWH,EAAkC,CAC3D,OAAOA,EAAK,OAAS,MACvB,CAKO,SAASI,GAAeJ,EAAsC,CACnE,OAAOA,EAAK,OAAS,UACvB,CAKO,SAASK,GACdL,EAC+D,CAC/D,MAAO,aAAcA,GAASA,EAAK,OAAS,YAAc,aAAcA,CAC1E,CCjaA,IAAMM,GAAQ,UACRC,GAAO,UACPC,GAAM,UAGNC,GAAS,WACTC,GAAW,WACXC,GAAY,WACZC,GAAU,WACVC,GAAU,WACVC,GAAW,WASV,SAASC,GAASC,EAAcC,EAAuB,CAC5D,OAAKA,EACE,GAAGA,CAAK,GAAGD,CAAI,GAAGV,EAAK,GADXU,CAErB,CAKO,SAASE,GAAKF,EAAsB,CACzC,MAAO,GAAGT,EAAI,GAAGS,CAAI,GAAGV,EAAK,EAC/B,CAKO,SAASa,EAAIH,EAAsB,CACxC,MAAO,GAAGR,EAAG,GAAGQ,CAAI,GAAGV,EAAK,EAC9B,CASO,IAAMc,EAAkC,CAC7C,QAASN,GACT,QAASH,GACT,QAASD,GACT,MAAOD,GACP,QAASI,GACT,OAAQD,GACR,QAASJ,GAAMK,EACjB,EASO,SAASQ,GAAeC,EAA0B,CACvD,OAAQA,EAAO,CACb,IAAK,UACH,MAAO,SACT,IAAK,UACH,MAAO,SACT,IAAK,UACH,MAAO,SACT,IAAK,QACH,MAAO,SACT,IAAK,UACH,MAAO,SACT,IAAK,SACH,MAAO,SACT,IAAK,UACH,MAAO,QACX,CACF,CAKO,SAASC,GAAiBD,EAAkBE,EAA6B,CAC9E,IAAMC,EAASJ,GAAeC,CAAK,EACnC,OAAOP,GAASU,EAAQD,EAAOF,CAAK,CAAC,CACvC,CAKO,SAASI,GACdV,EACAM,EACAE,EACQ,CACR,OAAOT,GAASC,EAAMQ,EAAOF,CAAK,CAAC,CACrC,CAUO,SAASK,GAAUC,EAAqB,CAE7C,OAAOA,EAAI,QAAQ,kBAAmB,EAAE,CAC1C,CCpFA,IAAMC,EAAM,CACV,QAAS,SACT,SAAU,SACV,WAAY,SACZ,YAAa,SACb,WAAY,SACZ,SAAU,SACV,SAAU,SACV,QAAS,SACT,QAAS,SACT,MAAO,SACP,MAAO,QACT,EASMC,GAAyC,CAC7C,KAAM,WACN,KAAM,WACN,QAAS,GACT,KAAM,WACN,IAAK,WACL,SAAU,UACZ,EAEMC,GAAQ,UAKd,SAASC,GAAaC,EAAsB,CAC1C,OAAIA,EAAO,GAAYH,GAAY,KAC/BG,EAAO,GAAYH,GAAY,KAC/BG,EAAO,GAAYH,GAAY,QAC/BG,EAAO,GAAYH,GAAY,KAC/BG,EAAO,IAAaH,GAAY,IAC7BA,GAAY,QACrB,CAKA,SAASI,GAAeC,EAAcF,EAAsB,CAC1D,IAAMG,EAAQJ,GAAaC,CAAI,EAC/B,OAAKG,EACE,GAAGA,CAAK,GAAGD,CAAI,GAAGJ,EAAK,GADXI,CAErB,CAMA,IAAME,GAAc,mDASb,SAASC,GAAgBC,EAAkBC,EAAQ,GAAY,CACpE,GAAID,EAAO,SAAW,EAAG,MAAO,GAGhC,IAAME,EAASF,EAAO,MAAM,CAACC,CAAK,EAC5BE,EAAM,KAAK,IAAI,GAAGD,CAAM,EAExBE,EADM,KAAK,IAAI,GAAGF,CAAM,EACVC,GAAO,EAE3B,OAAOD,EACJ,IAAKG,GAAM,CACV,IAAMC,GAAcD,EAAIF,GAAOC,EACzBG,EAAQ,KAAK,MAAMD,GAAcR,GAAY,OAAS,EAAE,EAC9D,OAAOA,GAAYS,CAAK,CAC1B,CAAC,EACA,KAAK,EAAE,CACZ,CASA,SAASC,GAAOC,EAAaR,EAAuB,CAClD,IAAMS,EAAaC,GAAUF,CAAG,EAAE,OAC5BG,EAAU,KAAK,IAAI,EAAGX,EAAQS,CAAU,EAC9C,OAAOD,EAAM,IAAI,OAAOG,CAAO,CACjC,CAKA,SAASC,GAAeZ,EAAea,EAAwB,CAC7D,GAAI,CAACA,EACH,OAAOxB,EAAI,WAAW,OAAOW,CAAK,EAGpC,IAAMc,EAAY,IAAID,CAAK,IACrBE,EAAiBf,EAAQc,EAAU,OACzC,GAAIC,EAAiB,EACnB,OAAO1B,EAAI,WAAW,OAAOW,CAAK,EAGpC,IAAMgB,EAAU,EACVC,EAAWF,EAAiBC,EAElC,OACE3B,EAAI,WAAW,OAAO2B,CAAO,EAAIF,EAAYzB,EAAI,WAAW,OAAO4B,CAAQ,CAE/E,CASA,SAASC,GACPC,EACAC,EACAC,EACQ,CACR,IAAMC,EAASH,EAAK,QAAU,UAC1BI,GAAS,SAAKF,EAAO,OAAO,EAC5BE,GAAS,SAAKF,EAAO,KAAK,EAExBG,EAASL,EAAK,aAAe,OAC/BM,EAAI,KAAKC,EAAeP,EAAK,UAAU,CAAC,GAAG,EAC3C,GAEAQ,EAAU,GACVR,EAAK,OAAS,aAAeA,EAAK,SAAS,QAC7CQ,EAAUF,EAAI,0BAAqB,EAC1BN,EAAK,OAAS,aAAeA,EAAK,SAAS,SAAW,GAC/DQ,EAAUF,EAAI,iBAAY,EACjBN,EAAK,OAAS,iBAAmBA,EAAK,SAAS,QACxDQ,EAAUF,EAAI,0BAAqB,EAC1BN,EAAK,OAAS,eAAiBA,EAAK,SAAS,UACtDQ,EAAUF,EAAI,KAAKN,EAAK,QAAQ,OAAO,GAAG,GAG5C,IAAMS,EAAQT,EAAK,QAAU,SAAWA,EAAK,MACzCM,EAAI,WAAW,OAAON,EAAK,KAAK,CAAC,EAAE,EACnC,GAEJ,MAAO,GAAGG,CAAM,IAAIG,EAAIL,CAAK,CAAC,GAAGO,CAAO,GAAGH,CAAM,GAAGI,CAAK,EAC3D,CAKA,SAASC,GACPC,EACAT,EACU,CACV,IAAMU,EAAkB,CAAC,EAGzB,OAAID,EAAM,WACRC,EAAM,KAAKb,GAAoBY,EAAM,UAAW,YAAaT,CAAM,CAAC,EAIlES,EAAM,eACRC,EAAM,KAAKb,GAAoBY,EAAM,cAAe,gBAAiBT,CAAM,CAAC,EAK1EU,EAAM,OAAS,GACjBA,EAAM,KAAKN,EAAI,0HAAsB,CAAC,EAGjCM,CACT,CASO,SAASC,IAA0B,CACxC,MAAO,CACL,KAAM,QACN,aAAc,GAEd,OAAOC,EAAgBC,EAAgC,CACrD,IAAMb,EAAS,CAAE,GAAGc,EAAoB,GAAGD,EAAQ,MAAO,EACpDlC,EAAQkC,EAAQ,eAAiB,GACjCE,EAAapC,EAAQ,EAErB+B,EAAkB,CAAC,EAGnBM,EAAeJ,EAAG,KAAK,MAAQ,WAC/BK,EAAcC,GAAKF,CAAY,EAOrC,GANAN,EAAM,KACJ,GAAG1C,EAAI,OAAO,GAAGuB,GAAeZ,EAAQ,EAAGsC,CAAW,CAAC,GAAGjD,EAAI,QAAQ,EACxE,EACA0C,EAAM,KAAK,GAAG1C,EAAI,QAAQ,GAAG,IAAI,OAAOW,EAAQ,CAAC,CAAC,GAAGX,EAAI,QAAQ,EAAE,EAG/D4C,EAAG,MAAO,CACZ,IAAMO,EAAYX,GAAYI,EAAG,MAAOZ,CAAM,EAC9C,QAAWoB,KAAQD,EACjBT,EAAM,KACJ,GAAG1C,EAAI,QAAQ,KAAKkB,GAAOkC,EAAML,CAAU,CAAC,GAAG/C,EAAI,QAAQ,EAC7D,CAEJ,CAGA,IAAMqD,EAAaC,GAAYV,EAAG,KAAK,SAAUC,EAASb,EAAQ,EAAGY,EAAG,KAAK,EAC7E,QAAWQ,KAAQC,EACjBX,EAAM,KACJ,GAAG1C,EAAI,QAAQ,KAAKkB,GAAOkC,EAAML,CAAU,CAAC,GAAG/C,EAAI,QAAQ,EAC7D,EAMF,GAFA0C,EAAM,KAAK,GAAG1C,EAAI,QAAQ,GAAG,IAAI,OAAOW,EAAQ,CAAC,CAAC,GAAGX,EAAI,QAAQ,EAAE,EAE/D4C,EAAG,KAAK,aAAe,QAAaC,EAAQ,YAAa,CAC3D,IAAMU,EAASX,EAAG,KAAK,QAAU,UAAY,YAAc,SAErDY,EAAS,GADOC,GAAaF,EAAQX,EAAG,KAAK,MAAOZ,CAAM,CACjC,OAAOK,EAAeO,EAAG,KAAK,UAAU,CAAC,GACxEF,EAAM,KACJ,GAAG1C,EAAI,QAAQ,KAAKkB,GAAOsC,EAAQT,CAAU,CAAC,GAAG/C,EAAI,QAAQ,EAC/D,EACA0C,EAAM,KAAK,GAAG1C,EAAI,QAAQ,GAAG,IAAI,OAAOW,EAAQ,CAAC,CAAC,GAAGX,EAAI,QAAQ,EAAE,CACrE,CAEA,OAAA0C,EAAM,KACJ,GAAG1C,EAAI,UAAU,GAAGA,EAAI,WAAW,OAAOW,EAAQ,CAAC,CAAC,GAAGX,EAAI,WAAW,EACxE,EAEO0C,EAAM,KAAK;AAAA,CAAI,CACxB,CACF,CACF,CAKA,SAASY,GACPI,EACAb,EACAb,EACA2B,EACAlB,EACU,CACV,IAAMC,EAAkB,CAAC,EAEzB,QAAWkB,KAAQF,EACbG,EAAWD,CAAI,EACjBlB,EAAM,KAAKoB,GAAeF,EAAMf,EAASb,EAAQS,CAAK,CAAC,EAC9CsB,GAAeH,CAAI,EAC5BlB,EAAM,KAAK,GAAGsB,GAAmBJ,EAAMf,EAASb,EAAQ2B,EAAOlB,CAAK,CAAC,EAC5DwB,GAAWL,CAAI,EACxBlB,EAAM,KAAK,GAAGwB,GAAeN,EAAMf,EAASb,EAAQ2B,EAAOlB,CAAK,CAAC,EACxD0B,GAAeP,CAAI,GAC5BlB,EAAM,KAAK,GAAG0B,GAAmBR,EAAMf,EAASb,EAAQ2B,EAAOlB,CAAK,CAAC,EAIzE,OAAOC,CACT,CAKA,SAASoB,GACPF,EACAf,EACAb,EACAS,EACQ,CACR,IAAMR,EAASoC,GAAiBT,EAAK,MAAO5B,CAAM,EAC5CsC,EAAOV,EAAK,MAAQA,EAAK,KAAO,OAGhCW,EAAW1B,EACX2B,EAASZ,EAAK,MAAQA,EAAK,GAG3BxD,EAAOmE,EAAS,aAAeA,EAAS,YAC1CA,EAAS,YAAY,KAAK,IAAIX,EAAK,EAAE,GAAKW,EAAS,YAAY,KAAK,IAAIC,CAAM,EAC9E,OAGAC,EACArE,IAAS,OACXqE,EAAcpE,GAAeiE,EAAMlE,CAAI,EAEvCqE,EAAchB,GAAaa,EAAMV,EAAK,MAAO5B,CAAM,EAGrD,IAAIoB,EAAO,GAAGnB,CAAM,IAAIwC,CAAW,GAQnC,GALI5B,EAAQ,UAAYe,EAAK,MAC3BR,GAAQhB,EAAI,UAAUwB,EAAK,GAAG,GAAG,GAI/BA,EAAK,QAAU,OAAW,CAC5B,IAAMc,EAAW,OAAOd,EAAK,OAAU,SACnCA,EAAK,MACL,KAAK,UAAUA,EAAK,KAAK,EAAE,MAAM,EAAG,EAAE,EAC1CR,GAAQhB,EAAI,SAASsC,CAAQ,GAAGA,EAAS,QAAU,GAAK,MAAQ,EAAE,GAAG,CACvE,CACA,GAAId,EAAK,SAAW,QAAaA,EAAK,QAAU,UAAW,CACzD,IAAMe,EAAY,OAAOf,EAAK,QAAW,SACrCA,EAAK,OACL,KAAK,UAAUA,EAAK,MAAM,EAAE,MAAM,EAAG,EAAE,EAC3CR,GAAQhB,EAAI,UAAUuC,CAAS,GAAGA,EAAU,QAAU,GAAK,MAAQ,EAAE,GAAG,CAC1E,CAGA,GAAI9B,EAAQ,aAAee,EAAK,aAAe,OAAW,CAExD,IAAMgB,EAAYvC,EAAeuB,EAAK,UAAU,EAC1CiB,EAAgBzE,IAAS,OAC3BC,GAAe,IAAIuE,CAAS,IAAKxE,CAAI,EACrCgC,EAAI,IAAIwC,CAAS,GAAG,EACxBxB,GAAQ,IAAIyB,CAAa,EAC3B,CAGA,GAAIN,EAAS,gBAAkBA,EAAS,cAAe,CACrD,IAAMO,EAAUP,EAAS,cAAc,IAAIC,CAAM,EAC7CM,GAAWA,EAAQ,OAAS,IAC9B1B,GAAQ,IAAIhB,EAAI3B,GAAgBqE,CAAO,CAAC,CAAC,GAE7C,CAQA,GALIlB,EAAK,aAAe,QAAaA,EAAK,WAAa,IACrDR,GAAQhB,EAAI,KAAKwB,EAAK,UAAU,IAAIA,EAAK,aAAe,EAAI,QAAU,SAAS,GAAG,GAIhFA,EAAK,SAAU,CACjB,IAAMmB,EAAcnB,EAAK,YAAc,OAAY,IAAIA,EAAK,SAAS,KAAO,GAC5ER,GAAQhB,EAAI,YAAY2C,CAAW,GAAG,CACxC,CAGA,GAAItC,GAASmB,EAAK,KAAOnB,EAAM,YAAY,IAAImB,EAAK,GAAG,EAAG,CACxD,IAAMoB,EAAWvC,EAAM,YAAY,IAAImB,EAAK,GAAG,EACzCqB,EAAaD,EAAS,QAAU,UAClC9C,GAAS,SAAKF,EAAO,OAAO,EAC5BE,GAAS,SAAKF,EAAO,KAAK,EACxBkD,EAAaF,EAAS,aAAe,OACvC5C,EAAI,IAAIC,EAAe2C,EAAS,UAAU,CAAC,EAAE,EAC7C,GACJ5B,GAAQ,IAAI6B,CAAU,GAAGC,CAAU,EACrC,CAEA,OAAO9B,CACT,CAKA,SAASY,GACPJ,EACAf,EACAb,EACA2B,EACAlB,EACU,CACV,IAAMC,EAAkB,CAAC,EACnByC,EAAS,KAAK,OAAOxB,CAAK,EAG1B1B,EAASoC,GAAiBT,EAAK,MAAO5B,CAAM,EAC5CsC,EAAOV,EAAK,MAAQ,WACpBwB,EAAOxB,EAAK,OAAS,aAAe,gBAAkB,GAI5D,GAHAlB,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,GAAGA,EAAI,OAAO,GAAGA,EAAI,UAAU,IAAIiC,CAAM,IAAIiB,GAAKoB,CAAI,CAAC,GAAGc,CAAI,EAAE,EAG/FxB,EAAK,SAAS,SAAW,EAE3BlB,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,IAAIoC,EAAI,uCAAuC,CAAC,EAAE,EACrFM,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,IAAIoC,EAAI,2DAA2D,CAAC,EAAE,MAEzG,SAASiD,EAAI,EAAGA,EAAIzB,EAAK,SAAS,OAAQyB,IAAK,CAC7C,IAAMC,EAAQ1B,EAAK,SAASyB,CAAC,EAEvBE,EADSF,IAAMzB,EAAK,SAAS,OAAS,EACpB,GAAGuB,CAAM,GAAGnF,EAAI,QAAQ,IAAIA,EAAI,UAAU,GAAK,GAAGmF,CAAM,GAAGnF,EAAI,QAAQ,IAAIA,EAAI,QAAQ,GAE/G,GAAI6D,EAAWyB,CAAK,EAClB5C,EAAM,KAAK,GAAG6C,CAAM,IAAIzB,GAAewB,EAAOzC,EAASb,EAAQS,CAAK,CAAC,EAAE,MAClE,CAEL,IAAM+C,EAAclC,GAAY,CAACgC,CAAK,EAAGzC,EAASb,EAAQ2B,EAAQ,EAAGlB,CAAK,EAC1E,QAAWW,KAAQoC,EACjB9C,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,MAAMoD,CAAI,EAAE,CAEnD,CACF,CAIF,OAAIP,EAAQ,aAAee,EAAK,aAAe,QAC7ClB,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,UAAU,GAAGA,EAAI,UAAU,GAAGA,EAAI,UAAU,IAAIoC,EAAI,IAAIC,EAAeuB,EAAK,UAAU,CAAC,GAAG,CAAC,EAAE,EAGnHlB,CACT,CAKA,SAASwB,GACPN,EACAf,EACAb,EACA2B,EACAlB,EACU,CACV,IAAMC,EAAkB,CAAC,EACnByC,EAAS,KAAK,OAAOxB,CAAK,EAG1B1B,EAASoC,GAAiBT,EAAK,MAAO5B,CAAM,EAC5CsC,EAAOV,EAAK,MAAQ,OAI1B,GAHAlB,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,UAAKiC,CAAM,IAAIiB,GAAKoB,CAAI,CAAC,EAAE,EAG1DV,EAAK,SAAS,SAAW,EAE3BlB,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,IAAIoC,EAAI,uCAAuC,CAAC,EAAE,EACrFM,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,IAAIoC,EAAI,2DAA2D,CAAC,EAAE,MAEzG,SAASiD,EAAI,EAAGA,EAAIzB,EAAK,SAAS,OAAQyB,IAAK,CAC7C,IAAMC,EAAQ1B,EAAK,SAASyB,CAAC,EAEvBE,EADSF,IAAMzB,EAAK,SAAS,OAAS,EACpB,GAAGuB,CAAM,GAAGnF,EAAI,QAAQ,IAAIA,EAAI,UAAU,GAAK,GAAGmF,CAAM,GAAGnF,EAAI,QAAQ,IAAIA,EAAI,QAAQ,GAIzGyF,EADW7B,EAAK,UAAY0B,EAAM,KAAO1B,EAAK,SACpBxB,EAAI,WAAW,EAAI,GAEnD,GAAIyB,EAAWyB,CAAK,EAClB5C,EAAM,KAAK,GAAG6C,CAAM,IAAIzB,GAAewB,EAAOzC,EAASb,EAAQS,CAAK,CAAC,GAAGgD,CAAY,EAAE,MACjF,CACL,IAAMD,EAAclC,GAAY,CAACgC,CAAK,EAAGzC,EAASb,EAAQ2B,EAAQ,EAAGlB,CAAK,EAC1E,QAAWW,KAAQoC,EACjB9C,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,MAAMoD,CAAI,EAAE,CAEnD,CACF,CAIF,OAAIP,EAAQ,aAAee,EAAK,aAAe,QAC7ClB,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,UAAU,GAAGA,EAAI,UAAU,GAAGA,EAAI,UAAU,IAAIoC,EAAI,IAAIC,EAAeuB,EAAK,UAAU,CAAC,GAAG,CAAC,EAAE,EAGnHlB,CACT,CAKA,SAAS0B,GACPR,EACAf,EACAb,EACA2B,EACAlB,EACU,CACV,IAAMC,EAAkB,CAAC,EACnByC,EAAS,KAAK,OAAOxB,CAAK,EAG1B1B,EAASoC,GAAiBT,EAAK,MAAO5B,CAAM,EAC5CsC,EAAOV,EAAK,MAAQ,WACpB8B,EAAY9B,EAAK,UACnBxB,EAAI,KAAKwB,EAAK,SAAS,GAAG,EAC1B,GACE+B,EAAgB/B,EAAK,gBAAkB,OACzCxB,EAAI,MAAM,OAAOwB,EAAK,aAAa,CAAC,EAAE,EACtC,GACEgC,EAAchC,EAAK,cAAgB,OACrCxB,EAAI,WAAM,OAAOwB,EAAK,WAAW,CAAC,EAAE,EACpC,GAEJlB,EAAM,KACJ,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,GAAGA,EAAI,OAAO,GAAGA,EAAI,UAAU,IAAIiC,CAAM,IAAIiB,GAAKoB,CAAI,CAAC,GAAGoB,CAAS,GAAGC,CAAa,GAAGC,CAAW,EAC3H,EAGA,QAASP,EAAI,EAAGA,EAAIzB,EAAK,SAAS,OAAQyB,IAAK,CAC7C,IAAMQ,EAASjC,EAAK,SAASyB,CAAC,EAExBE,EADSF,IAAMzB,EAAK,SAAS,OAAS,EAExC,GAAGuB,CAAM,GAAGnF,EAAI,QAAQ,IAAIA,EAAI,UAAU,GAC1C,GAAGmF,CAAM,GAAGnF,EAAI,QAAQ,IAAIA,EAAI,QAAQ,GAGtC8F,EAAeD,EAAO,MAAQ,SAAM,SACpCE,EAAcF,EAAO,MAAQ7D,EAAO,QAAUA,EAAO,QACrDgE,EAAc9D,GAClB,GAAG4D,CAAY,IAAID,EAAO,KAAK,GAC/BE,CACF,EACME,EAAkBJ,EAAO,UAC3BzD,EAAI,KAAKyD,EAAO,SAAS,GAAG,EAC5B,GAKJ,GAHAnD,EAAM,KAAK,GAAG6C,CAAM,IAAIS,CAAW,GAAGC,CAAe,EAAE,EAGnDJ,EAAO,SAAS,OAAS,EAAG,CAC9B,IAAMxC,EAAaC,GAAYuC,EAAO,SAAUhD,EAASb,EAAQ2B,EAAQ,EAAGlB,CAAK,EACjF,QAAWW,KAAQC,EACjBX,EAAM,KAAK,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,MAAMoD,CAAI,EAAE,CAEnD,MAAYyC,EAAO,OAEjBnD,EAAM,KACJ,GAAGyC,CAAM,GAAGnF,EAAI,QAAQ,MAAMoC,EAAI,WAAW,CAAC,EAChD,CAEJ,CAGA,OAAIS,EAAQ,aAAee,EAAK,aAAe,QAC7ClB,EAAM,KACJ,GAAGyC,CAAM,GAAGnF,EAAI,UAAU,GAAGA,EAAI,UAAU,GAAGA,EAAI,UAAU,IAAIoC,EAAI,IAAIC,EAAeuB,EAAK,UAAU,CAAC,GAAG,CAAC,EAC7G,EAGKlB,CACT,CChfA,SAASwD,GAAaC,EAA+B,CACnD,IAAMC,EAAqB,CAAC,EAC5B,QAAWC,KAAQF,EAKjB,GAJAC,EAAO,KAAKC,CAAI,EACZ,aAAcA,GAAQ,MAAM,QAAQA,EAAK,QAAQ,GACnDD,EAAO,KAAK,GAAGF,GAAaG,EAAK,QAAQ,CAAC,EAExC,aAAcA,EAChB,QAAWC,KAAUD,EAAK,SACxBD,EAAO,KAAK,GAAGF,GAAaI,EAAO,QAAQ,CAAC,EAIlD,OAAOF,CACT,CAKA,SAASG,GAAWC,EAAwBC,EAAmB,CAC7D,GAAID,EAAa,SAAW,EAAG,MAAO,GACtC,IAAME,EAAQ,KAAK,MAAMF,EAAa,OAASC,CAAC,EAChD,OAAOD,EAAa,KAAK,IAAIE,EAAOF,EAAa,OAAS,CAAC,CAAC,CAC9D,CAKO,SAASG,GAAaC,EAAyB,CACpD,OAAIA,EAAO,GAAY,OACnBA,EAAO,GAAY,OACnBA,EAAO,GAAY,UACnBA,EAAO,GAAY,OACnBA,EAAO,IAAa,MACjB,UACT,CAqBO,SAASC,IAAiD,CAE/D,IAAMC,EAAa,IAAI,IAGjBC,EAAY,IAAI,IAGhBC,EAAY,IAAI,IAGhBC,EAAc,IAAI,IAGpBC,EAA6C,CAAC,EAKlD,SAASC,EAAUC,EAIR,CACT,OAAOA,EAAM,MAAQA,EAAM,SAAWA,EAAM,QAAU,SACxD,CAKA,SAASC,EAAcC,EAAwC,CAE7D,IAAMC,EAAY,IAAI,IAQtB,QAAWH,KAASE,EAClB,OAAQF,EAAM,KAAM,CAClB,IAAK,aAAc,CACjB,IAAMI,EAAKL,EAAUC,CAAK,EAC1BG,EAAU,IAAIC,EAAI,CAAE,QAAS,GAAO,SAAU,EAAM,CAAC,EACrD,KACF,CAEA,IAAK,aAAc,CACjB,IAAMA,EAAKL,EAAUC,CAAK,EACpBK,EAAQF,EAAU,IAAIC,CAAE,EAC1BC,IACFA,EAAM,QAAU,IAElB,KACF,CAEA,IAAK,eAAgB,CACnB,IAAMD,EAAKL,EAAUC,CAAK,EACpBK,EAAQF,EAAU,IAAIC,CAAE,EAC1BC,IACFA,EAAM,SAAW,IAGnB,IAAMC,EAAUT,EAAY,IAAIO,CAAE,GAAK,CAAE,SAAU,EAAG,MAAO,CAAE,EAC/DE,EAAQ,WACRA,EAAQ,QACRT,EAAY,IAAIO,EAAIE,CAAO,EAC3B,KACF,CAEA,IAAK,eAAgB,CACnB,IAAMF,EAAKL,EAAUC,CAAK,EACpBK,EAAQF,EAAU,IAAIC,CAAE,EAGxBG,EAAUb,EAAW,IAAIU,CAAE,GAAK,CAAC,EACvCG,EAAQ,KAAKP,EAAM,UAAU,EAC7BN,EAAW,IAAIU,EAAIG,CAAO,EAG1B,IAAMC,EAAQb,EAAU,IAAIS,CAAE,GAAK,CAAE,QAAS,EAAG,MAAO,CAAE,EAC1DI,EAAM,QACFH,GAAO,SAASG,EAAM,UAC1Bb,EAAU,IAAIS,EAAII,CAAK,EAGvB,IAAMC,EAAQb,EAAU,IAAIQ,CAAE,GAAK,CAAE,OAAQ,EAAG,MAAO,CAAE,EACzDK,EAAM,QACNb,EAAU,IAAIQ,EAAIK,CAAK,EAEvBN,EAAU,OAAOC,CAAE,EACnB,KACF,CAEA,IAAK,aAAc,CACjB,IAAMA,EAAKL,EAAUC,CAAK,EACpBK,EAAQF,EAAU,IAAIC,CAAE,EAGxBG,EAAUb,EAAW,IAAIU,CAAE,GAAK,CAAC,EACvCG,EAAQ,KAAKP,EAAM,UAAU,EAC7BN,EAAW,IAAIU,EAAIG,CAAO,EAG1B,IAAMC,EAAQb,EAAU,IAAIS,CAAE,GAAK,CAAE,QAAS,EAAG,MAAO,CAAE,EAC1DI,EAAM,QACFH,GAAO,SAASG,EAAM,UAC1Bb,EAAU,IAAIS,EAAII,CAAK,EAGvB,IAAMC,EAAQb,EAAU,IAAIQ,CAAE,GAAK,CAAE,OAAQ,EAAG,MAAO,CAAE,EACzDK,EAAM,QACNA,EAAM,SACNb,EAAU,IAAIQ,EAAIK,CAAK,EAEvBN,EAAU,OAAOC,CAAE,EACnB,KACF,CACF,CAEJ,CAKA,SAASM,EAAOC,EAAwB,CACtCV,EAAcU,EAAI,MAAM,CAC1B,CAKA,SAASC,EAASZ,EAAqC,CACrDF,EAAiB,KAAKE,CAAK,CAC7B,CAKA,SAASa,EAAYC,EAAsB,CACrChB,EAAiB,OAAS,IAC5BG,EAAcH,CAAgB,EAC9BA,EAAmB,CAAC,EAExB,CAKA,SAASiB,EAAmBC,EAA6C,CACvE,IAAMT,EAAUb,EAAW,IAAIsB,CAAM,EACrC,GAAI,CAACT,GAAWA,EAAQ,SAAW,EAAG,OAEtC,IAAMU,EAAS,CAAC,GAAGV,CAAO,EAAE,KAAK,CAACW,EAAGC,IAAMD,EAAIC,CAAC,EAE1CC,EADMH,EAAO,OAAO,CAACC,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EACzBF,EAAO,OACpBI,EACJJ,EAAO,OAAO,CAACK,EAAKC,IAAMD,GAAOC,EAAIH,IAAS,EAAG,CAAC,EAAIH,EAAO,OAEzDT,EAAQb,EAAU,IAAIqB,CAAM,GAAK,CAAE,QAAS,EAAG,MAAO,CAAE,EACxDP,EAAQb,EAAU,IAAIoB,CAAM,GAAK,CAAE,OAAQ,EAAG,MAAO,CAAE,EACvDV,EAAUT,EAAY,IAAImB,CAAM,GAAK,CAAE,SAAU,EAAG,MAAO,CAAE,EAEnE,MAAO,CACL,OAAAA,EACA,cAAeI,EACf,cAAeH,EAAO,CAAC,EACvB,cAAeA,EAAOA,EAAO,OAAS,CAAC,EACvC,SAAU,KAAK,KAAKI,CAAQ,EAC5B,QAASJ,EAAO,OAChB,UAAWT,EAAM,MAAQ,EAAIA,EAAM,QAAUA,EAAM,MAAQ,EAC3D,YAAaF,EAAQ,MAAQ,EAAIA,EAAQ,SAAWA,EAAQ,MAAQ,EACpE,UAAWG,EAAM,MAAQ,EAAIA,EAAM,OAASA,EAAM,MAAQ,EAC1D,YAAa,CACX,IAAKtB,GAAW8B,EAAQ,EAAG,EAC3B,IAAK9B,GAAW8B,EAAQ,EAAG,EAC3B,IAAK9B,GAAW8B,EAAQ,GAAI,EAC5B,IAAK9B,GAAW8B,EAAQ,GAAI,CAC9B,CACF,CACF,CAKA,SAASO,EAAmBR,EAA6C,CACvE,OAAOD,EAAmBC,CAAM,CAClC,CAKA,SAASS,EACPC,EACAC,EAAiD,WACpC,CACb,IAAMnC,EAAO,IAAI,IACXoC,EAAW9C,GAAa4C,EAAG,KAAK,QAAQ,EAGxCG,EAA+C,CAAC,EACtD,QAAW5C,KAAQ2C,EAAU,CAE3B,IAAMZ,EAAS/B,EAAK,MAAQA,EAAK,GAC3B6C,EAAOf,EAAmBC,CAAM,EACtC,GAAIc,EAAM,CACR,IAAIC,EACJ,OAAQJ,EAAQ,CACd,IAAK,WACHI,EAAQD,EAAK,cACb,MACF,IAAK,YACHC,EAAQD,EAAK,UACb,MACF,IAAK,YACHC,EAAQD,EAAK,UACb,KACJ,CACAD,EAAO,KAAK,CAAE,GAAI5C,EAAK,GAAI,MAAA8C,CAAM,CAAC,CACpC,CACF,CAEA,GAAIF,EAAO,SAAW,EACpB,MAAO,CACL,KAAArC,EACA,OAAAmC,EACA,MAAO,CAAE,IAAK,EAAG,IAAK,EAAG,KAAM,EAAG,UAAW,CAAE,CACjD,EAIF,IAAMK,EAAOH,EAAO,IAAKI,GAAMA,EAAE,KAAK,EAChCC,EAAM,KAAK,IAAI,GAAGF,CAAI,EACtBG,EAAM,KAAK,IAAI,GAAGH,CAAI,EACtBZ,EAAOY,EAAK,OAAO,CAACd,EAAGC,IAAMD,EAAIC,EAAG,CAAC,EAAIa,EAAK,OAC9CI,EAAQD,EAAMD,GAAO,EAG3B,OAAW,CAAE,GAAA9B,EAAI,MAAA2B,CAAM,IAAKF,EAC1BrC,EAAK,IAAIY,GAAK2B,EAAQG,GAAOE,CAAK,EAGpC,MAAO,CACL,KAAA5C,EACA,OAAAmC,EACA,MAAO,CACL,IAAAO,EACA,IAAAC,EACA,KAAAf,EACA,UAAWA,GAAQe,EAAMf,GAAQ,EACnC,CACF,CACF,CAKA,SAASiB,GAAkD,CACzD,IAAMrD,EAAS,IAAI,IACnB,QAAWgC,KAAUtB,EAAW,KAAK,EAAG,CACtC,IAAMoC,EAAOf,EAAmBC,CAAM,EAClCc,GAAM9C,EAAO,IAAIgC,EAAQc,CAAI,CACnC,CACA,OAAO9C,CACT,CAKA,SAASsD,EAAgBC,EAAQ,GAAuB,CAEtD,MAAO,CAAC,GADIF,EAAkB,EACf,OAAO,CAAC,EACpB,KAAK,CAACnB,EAAGC,IAAMA,EAAE,cAAgBD,EAAE,aAAa,EAChD,MAAM,EAAGqB,CAAK,CACnB,CAKA,SAASC,EAAmBD,EAAQ,GAAuB,CAEzD,MAAO,CAAC,GADIF,EAAkB,EACf,OAAO,CAAC,EACpB,OAAQhD,GAAMA,EAAE,UAAY,CAAC,EAC7B,KAAK,CAAC6B,EAAGC,IAAMA,EAAE,UAAYD,EAAE,SAAS,EACxC,MAAM,EAAGqB,CAAK,CACnB,CAKA,SAASE,EAAmBF,EAAQ,GAAuB,CAEzD,MAAO,CAAC,GADIF,EAAkB,EACf,OAAO,CAAC,EACpB,OAAQhD,GAAMA,EAAE,UAAY,CAAC,EAC7B,KAAK,CAAC6B,EAAGC,IAAMA,EAAE,UAAYD,EAAE,SAAS,EACxC,MAAM,EAAGqB,CAAK,CACnB,CAKA,SAASG,GAAqB,CAC5B,OAAO,KAAK,UAAU,CACpB,WAAY,OAAO,YAAYhD,CAAU,EACzC,UAAW,OAAO,YAAYC,CAAS,EACvC,UAAW,OAAO,YAAYC,CAAS,EACvC,YAAa,OAAO,YAAYC,CAAW,CAC7C,CAAC,CACH,CAKA,SAAS8C,EAAWC,EAAoB,CACtC,IAAMC,EAAO,KAAK,MAAMD,CAAI,EAQ5BlD,EAAW,MAAM,EACjBC,EAAU,MAAM,EAChBC,EAAU,MAAM,EAChBC,EAAY,MAAM,EAGlB,OAAW,CAACiD,EAAGb,CAAC,IAAK,OAAO,QAAQY,EAAK,YAAc,CAAC,CAAC,EACvDnD,EAAW,IAAIoD,EAAGb,CAAC,EAIrB,OAAW,CAACa,EAAGb,CAAC,IAAK,OAAO,QAAQY,EAAK,WAAa,CAAC,CAAC,EACtDlD,EAAU,IAAImD,EAAGb,CAAC,EAIpB,OAAW,CAACa,EAAGb,CAAC,IAAK,OAAO,QAAQY,EAAK,WAAa,CAAC,CAAC,EACtDjD,EAAU,IAAIkD,EAAGb,CAAC,EAIpB,OAAW,CAACa,EAAGb,CAAC,IAAK,OAAO,QAAQY,EAAK,aAAe,CAAC,CAAC,EACxDhD,EAAY,IAAIiD,EAAGb,CAAC,CAExB,CAKA,SAASc,GAAc,CACrBrD,EAAW,MAAM,EACjBC,EAAU,MAAM,EAChBC,EAAU,MAAM,EAChBC,EAAY,MAAM,EAClBC,EAAmB,CAAC,CACtB,CAEA,MAAO,CACL,OAAAY,EACA,SAAAE,EACA,YAAAC,EACA,mBAAAW,EACA,WAAAC,EACA,gBAAAa,EACA,mBAAAE,EACA,mBAAAC,EACA,kBAAAJ,EACA,WAAAK,EACA,WAAAC,EACA,MAAAI,CACF,CACF,CCreA,SAASC,IAAgC,CACvC,MAAO,CAEL,kFAEA,kFAEA,kFAEA,gFAEA,wGAEA,iFAEA,uGACF,CACF,CAKA,SAASC,IAAuC,CAC9C,MAAO,CAEL,oFACA,oFACA,uFACA,oFACA,mFACA,uFACF,CACF,CAKA,SAASC,GAAaC,EAA0B,CAC9C,MAAO,QAAQA,CAAK,EACtB,CAYA,SAASC,IAAoC,CAC3C,MAAO,CAEL,uFACA,oFACF,CACF,CAMA,SAASC,GACPC,EACAC,EACAC,EACoC,CACpC,IAAIC,EAGJ,GAAIH,EAAM,UAAW,CACnB,IAAMI,EAAS,iBACTC,EAAQL,EAAM,UAAU,QAAU,UAAY,eAAiB,aAC/DM,EAAON,EAAM,UAAU,QAAU,UAAY,SAAM,SACnDO,EAASL,EAAQ,aAAeF,EAAM,UAAU,aAAe,OACjE,IAAIQ,EAAeR,EAAM,UAAU,UAAU,CAAC,GAC9C,GACES,EAAUT,EAAM,UAAU,SAAS,QACrC,sBACAA,EAAM,UAAU,SAAS,SAAW,GAClC,aACA,GAENC,EAAM,KAAK,OAAOG,CAAM,MAAME,CAAI,aAAaG,CAAO,GAAGF,CAAM,SAASF,CAAK,EAAE,EAC/EF,EAAaC,CACf,CAGA,GAAIJ,EAAM,cAAe,CACvB,IAAMI,EAAS,mBACTC,EAAQL,EAAM,cAAc,QAAU,UAAY,eAAiB,aACnEM,EAAON,EAAM,cAAc,QAAU,UAAY,SAAM,SACvDO,EAASL,EAAQ,aAAeF,EAAM,cAAc,aAAe,OACrE,IAAIQ,EAAeR,EAAM,cAAc,UAAU,CAAC,GAClD,GACES,EAAUT,EAAM,cAAc,SAAS,QACzC,sBACA,GAEJC,EAAM,KAAK,OAAOG,CAAM,MAAME,CAAI,iBAAiBG,CAAO,GAAGF,CAAM,SAASF,CAAK,EAAE,EAG/EF,GACFF,EAAM,KAAK,OAAOE,CAAU,QAAQC,CAAM,EAAE,EAE9CD,EAAaC,CACf,CAEA,MAAO,CAAE,WAAAD,CAAW,CACtB,CAMA,IAAIO,GAAc,EAElB,SAASC,GAAeC,EAAiB,OAAgB,CACvD,MAAO,GAAGA,CAAM,IAAI,EAAEF,EAAW,EACnC,CAEA,SAASG,IAAyB,CAChCH,GAAc,CAChB,CAkBA,SAASI,EAAkBC,EAAsB,CAC/C,OAAOA,EACJ,QAAQ,aAAc,EAAE,EACxB,QAAQ,QAAS,EAAE,EACnB,QAAQ,KAAM,GAAG,EACjB,KAAK,CACV,CASA,SAASC,GAAmBD,EAAsB,CAChD,OAAOD,EAAkBC,CAAI,EAC1B,QAAQ,SAAU,EAAE,CACzB,CASO,SAASE,IAA4B,CAC1C,MAAO,CACL,KAAM,UACN,aAAc,GAEd,OAAOC,EAAgBhB,EAAgC,CACrDW,GAAiB,EACjB,IAAMZ,EAAkB,CAAC,EAGnBkB,EAAWjB,EAGjBD,EAAM,KAAK,cAAc,EAGzB,IAAImB,EACAF,EAAG,QAELE,EADmBrB,GAAYmB,EAAG,MAAOjB,EAAOC,CAAO,EAC/B,YAI1B,IAAMmB,EAAU,QAChBpB,EAAM,KAAK,OAAOoB,CAAO,oBAAe,EAGpCD,GACFnB,EAAM,KAAK,OAAOmB,CAAU,QAAQC,CAAO,EAAE,EAI/C,IAAIC,EAAaD,EAGjB,QAAWE,KAASL,EAAG,KAAK,SAAU,CACpC,IAAMM,EAASC,GAAWF,EAAOrB,EAASD,EAAOkB,EAAUD,EAAG,KAAK,EACnEjB,EAAM,KAAK,OAAOqB,CAAU,QAAQE,EAAO,OAAO,EAAE,EACpDF,EAAaE,EAAO,MACtB,CAGA,GAAIN,EAAG,KAAK,QAAU,WAAaA,EAAG,KAAK,QAAU,QAAS,CAC5D,IAAMQ,EAAQ,SACRC,EAAUT,EAAG,KAAK,QAAU,UAAY,SAAM,SAC9CU,EAAWV,EAAG,KAAK,QAAU,UAAY,OAAS,SAClDW,EAAW,MAAMF,CAAO,IAAIC,CAAQ,MACpCE,EACJZ,EAAG,KAAK,QAAU,UAAY,aAAe,WAC/CjB,EAAM,KAAK,OAAOyB,CAAK,GAAGG,CAAQ,GAAGC,CAAQ,EAAE,EAC/C7B,EAAM,KAAK,OAAOqB,CAAU,QAAQI,CAAK,EAAE,CAC7C,CAGA,OAAAzB,EAAM,KAAK,EAAE,EACbA,EAAM,KAAK,GAAG8B,GAAoB,CAAC,EAG/BZ,EAAS,aACXlB,EAAM,KAAK,GAAG+B,GAA2B,CAAC,EAIxCd,EAAG,OACLjB,EAAM,KAAK,GAAGH,GAAwB,CAAC,EAGlCG,EAAM,KAAK;AAAA,CAAI,CACxB,CACF,CACF,CAaA,SAASwB,GACPQ,EACA/B,EACAD,EACAkB,EACAnB,EACc,CACd,GAAIkC,EAAWD,CAAI,EACjB,OAAOE,GAAeF,EAAM/B,EAASD,EAAOkB,EAAUnB,CAAK,EACtD,GAAIoC,GAAeH,CAAI,EAC5B,OAAOI,GAAmBJ,EAAM/B,EAASD,EAAOkB,EAAUnB,CAAK,EAC1D,GAAIsC,GAAWL,CAAI,EACxB,OAAOM,GAAeN,EAAM/B,EAASD,EAAOkB,EAAUnB,CAAK,EACtD,GAAIwC,GAAeP,CAAI,EAC5B,OAAOQ,GAAmBR,EAAM/B,EAASD,EAAOkB,EAAUnB,CAAK,EAIjE,IAAM0C,EAAK/B,GAAe,SAAS,EACnC,OAAAV,EAAM,KAAK,OAAOyC,CAAE,gBAAgB,EAC7B,CAAE,QAASA,EAAI,OAAQA,CAAG,CACnC,CAKA,SAASP,GACPF,EACA/B,EACAD,EACAkB,EACAnB,EACc,CAEd,IAAM2C,EAAczC,EACd0C,EAAiBD,EAAY,gBAAkB,GAC/CE,EAAiBF,EAAY,gBAAkB,GAC/CG,EAAmBH,EAAY,kBAAoB,GAEnDD,EAAKT,EAAK,IACZ,QAAQA,EAAK,IAAI,QAAQ,gBAAiB,GAAG,CAAC,GAC9CtB,GAAe,MAAM,EAEnBoC,EAAQjC,EAAkBmB,EAAK,MAAQA,EAAK,KAAO,MAAM,EAGzD1B,EACJL,EAAQ,aAAe+B,EAAK,aAAe,OACvC,IAAIzB,EAAeyB,EAAK,UAAU,CAAC,GACnC,GAGFe,EAAY,GAChB,OAAQf,EAAK,MAAO,CAClB,IAAK,UACHe,EAAY,UACZ,MACF,IAAK,QACHA,EAAY,UACZ,MACF,IAAK,SACHA,EAAY,aACZ,MACF,IAAK,UACHA,EAAY,UACZ,MACF,IAAK,UACHA,EAAY,UACZ,KACJ,CAIA,IAAIC,EAAS,GACb,GAAIhB,EAAK,QAAU,OAAW,CAC5B,IAAMiB,EAAW,OAAOjB,EAAK,OAAU,SACnCnB,EAAkBmB,EAAK,KAAK,EAC5BnB,EAAkB,KAAK,UAAUmB,EAAK,KAAK,EAAE,MAAM,EAAG,EAAE,CAAC,EAC7DgB,GAAU,UAAUC,CAAQ,EAC9B,CACA,GAAIjB,EAAK,SAAW,QAAaA,EAAK,QAAU,UAAW,CACzD,IAAMkB,EAAY,OAAOlB,EAAK,QAAW,SACrCnB,EAAkBmB,EAAK,MAAM,EAC7BnB,EAAkB,KAAK,UAAUmB,EAAK,MAAM,EAAE,MAAM,EAAG,EAAE,CAAC,EAC9DgB,GAAU,WAAWE,CAAS,EAChC,CAGA,IAAIC,EAAW,GACf,GAAIpD,GAASiC,EAAK,KAAOjC,EAAM,YAAY,IAAIiC,EAAK,GAAG,EAAG,CACxD,IAAMoB,EAAWrD,EAAM,YAAY,IAAIiC,EAAK,GAAG,EACzCqB,EAAWD,EAAS,QAAU,UAAY,SAAM,SAChDE,EAAarD,EAAQ,aAAemD,EAAS,aAAe,OAC9D,IAAI7C,EAAe6C,EAAS,UAAU,CAAC,GACvC,GACJD,EAAW,MAAME,CAAQ,QAAQC,CAAU,EAC7C,CAGA,IAAMC,GAAgBR,EAAYD,EAAQE,EAASG,EAAW7C,GAAQ,KAAK,EAGvEkD,EACEC,EAASzB,EAAK,MAAQA,EAAK,GAC3B0B,EAAOxC,GAAU,aAAeA,EAAS,YAC3CA,EAAS,YAAY,KAAK,IAAIc,EAAK,EAAE,GAAKd,EAAS,YAAY,KAAK,IAAIuC,CAAM,EAC9E,OAEJ,GAAIC,IAAS,OAAW,CACtB,IAAMC,EAAQC,GAAaF,CAAI,EAC/BF,EAAYK,GAAaF,CAAK,CAChC,MACEH,EAA0BxB,EAAK,MAIjC,IAAI8B,EACJ,OAAQ9B,EAAK,MAAO,CAClB,IAAK,QAEH8B,EAAQ,KAAKP,CAAY,KACzB,MACF,IAAK,SAEHO,EAAQ,KAAKP,CAAY,KACzB,MACF,IAAK,UAEHO,EAAQ,IAAIP,CAAY,cACxB,MACF,QAEEO,EAAQ,IAAIP,CAAY,GAC5B,CAKA,GAHAvD,EAAM,KAAK,OAAOyC,CAAE,GAAGqB,CAAK,MAAMN,CAAS,EAAE,EAGzCb,GAAkBX,EAAK,aAAe,QAAaA,EAAK,WAAa,EAAG,CAC1E,IAAM+B,EAAa,UAAK/B,EAAK,UAAU,QAAQA,EAAK,aAAe,EAAI,IAAM,KAAK,GAClFhC,EAAM,KAAK,OAAOyC,CAAE,UAAUsB,CAAU,MAAMtB,CAAE,EAAE,CACpD,CAGA,GAAIG,GAAkBZ,EAAK,QAAU,SAAWA,EAAK,QAAU,OAAW,CACxE,IAAMgC,EAAc,OAAOvB,CAAE,GACvBwB,EAAapD,EAAkB,OAAOmB,EAAK,KAAK,CAAC,EAAE,MAAM,EAAG,EAAE,EACpEhC,EAAM,KAAK,OAAOgE,CAAW,KAAKC,CAAU,IAAI,EAChDjE,EAAM,KAAK,OAAOyC,CAAE,eAAeuB,CAAW,EAAE,EAChDhE,EAAM,KAAK,aAAagE,CAAW,8BAA8B,CACnE,CAGA,GAAInB,GAAoBb,EAAK,SAAU,CACrC,IAAMkC,EAAgB,MAAMzB,CAAE,GACxB0B,EAAYnC,EAAK,YAAc,OAAY,GAAGA,EAAK,SAAS,KAAO,GACzEhC,EAAM,KAAK,OAAOkE,CAAa,oBAAeC,CAAS,IAAI,EAC3DnE,EAAM,KAAK,OAAOyC,CAAE,kBAAkByB,CAAa,EAAE,EACrDlE,EAAM,KAAK,aAAakE,CAAa,8BAA8B,CACrE,CAEA,MAAO,CAAE,QAASzB,EAAI,OAAQA,CAAG,CACnC,CAKA,SAASL,GACPJ,EACA/B,EACAD,EACAkB,EACAnB,EACc,CACd,IAAMqE,EAAa1D,GAAe,UAAU,EACtC2D,EAAS,GAAGD,CAAU,QACtBE,EAAS,GAAGF,CAAU,QACtBG,EAAOxD,GAAmBiB,EAAK,MAAQ,UAAU,EACjDwC,EAAYxC,EAAK,OAAS,aAAe,gBAAkB,GAGjE,GAAIA,EAAK,SAAS,SAAW,EAAG,CAC9B,IAAMS,EAAK2B,EACLtB,EAAQjC,EAAkB,GAAG0D,CAAI,GAAGC,CAAS,EAAE,EAC/CC,EAAO,sCACPnE,EAASL,EAAQ,aAAe+B,EAAK,aAAe,OACtD,IAAIzB,EAAeyB,EAAK,UAAU,CAAC,GACnC,GAGJ,OAAAhC,EAAM,KAAK,OAAOyC,CAAE,IAAIK,CAAK,GAAGxC,CAAM,MAAMmE,CAAI,OAAqBzC,EAAK,KAAM,EAAE,EAC3E,CAAE,QAASS,EAAI,OAAQA,CAAG,CACnC,CAGAzC,EAAM,KAAK,gBAAgBoE,CAAU,KAAKG,CAAI,GAAGC,CAAS,IAAI,EAC9DxE,EAAM,KAAK,kBAAkB,EAG7BA,EAAM,KAAK,OAAOqE,CAAM,iBAAY,EAGpC,IAAMK,EAAyB,CAAC,EAChC,QAAWpD,KAASU,EAAK,SAAU,CACjC,IAAMT,EAASC,GAAWF,EAAOrB,EAASD,EAAOkB,EAAUnB,CAAK,EAChEC,EAAM,KAAK,OAAOqE,CAAM,QAAQ9C,EAAO,OAAO,EAAE,EAChDmD,EAAa,KAAKnD,EAAO,MAAM,CACjC,CAGAvB,EAAM,KAAK,OAAOsE,CAAM,iBAAY,EACpC,QAAWK,KAAUD,EACnB1E,EAAM,KAAK,OAAO2E,CAAM,QAAQL,CAAM,EAAE,EAG1CtE,EAAM,KAAK,SAAS,EAGpB,IAAM4E,EAA2B5C,EAAK,MACtC,OAAAhC,EAAM,KAAK,aAAaoE,CAAU,IAAIQ,CAAU,EAAE,EAE3C,CAAE,QAASP,EAAQ,OAAQC,CAAO,CAC3C,CAKA,SAAShC,GACPN,EACA/B,EACAD,EACAkB,EACAnB,EACc,CACd,IAAMqE,EAAa1D,GAAe,MAAM,EAClCU,EAAU,GAAGgD,CAAU,SACvB3C,EAAQ,GAAG2C,CAAU,OACrBG,EAAOxD,GAAmBiB,EAAK,MAAQ,MAAM,EAGnD,GAAIA,EAAK,SAAS,SAAW,EAAG,CAC9B,IAAMS,EAAK2B,EACLtB,EAAQjC,EAAkB0D,CAAI,EAC9BE,EAAO,sCACPnE,EAASL,EAAQ,aAAe+B,EAAK,aAAe,OACtD,IAAIzB,EAAeyB,EAAK,UAAU,CAAC,GACnC,GAEJ,OAAAhC,EAAM,KAAK,OAAOyC,CAAE,WAAMK,CAAK,GAAGxC,CAAM,MAAMmE,CAAI,OAAqBzC,EAAK,KAAM,EAAE,EAC7E,CAAE,QAASS,EAAI,OAAQA,CAAG,CACnC,CAGAzC,EAAM,KAAK,gBAAgBoE,CAAU,YAAOG,CAAI,IAAI,EACpDvE,EAAM,KAAK,kBAAkB,EAG7BA,EAAM,KAAK,OAAOoB,CAAO,uBAAgB,EAGzC,IAAMsD,EAA6D,CAAC,EAChEG,EAEJ,QAAWvD,KAASU,EAAK,SAAU,CACjC,IAAMT,EAASC,GAAWF,EAAOrB,EAASD,EAAOkB,EAAUnB,CAAK,EAC1D+E,EAAW7C,EAAWX,CAAK,GAAKU,EAAK,WAAaV,EAAM,GAC9DtB,EAAM,KAAK,OAAOoB,CAAO,QAAQG,EAAO,OAAO,EAAE,EAE7CuD,IACFD,EAAetD,EAAO,QAExBmD,EAAa,KAAK,CAAE,OAAQnD,EAAO,OAAQ,SAAAuD,CAAS,CAAC,CACvD,CAGA9E,EAAM,KAAK,OAAOyB,CAAK,oBAAe,EAGtC,OAAW,CAAE,OAAAkD,EAAQ,SAAAG,CAAS,IAAKJ,EAC7BI,GAAYD,EACd7E,EAAM,KAAK,OAAO2E,CAAM,0BAAmBlD,CAAK,EAAE,EACzCO,EAAK,SAEdhC,EAAM,KAAK,OAAO2E,CAAM,qBAAqBlD,CAAK,EAAE,EAGpDzB,EAAM,KAAK,OAAO2E,CAAM,QAAQlD,CAAK,EAAE,EAI3CzB,EAAM,KAAK,SAAS,EAEpB,IAAM4E,EAA2B5C,EAAK,MACtC,OAAAhC,EAAM,KAAK,aAAaoE,CAAU,IAAIQ,CAAU,EAAE,EAE3C,CAAE,QAASxD,EAAS,OAAQK,CAAM,CAC3C,CAKA,SAASe,GACPR,EACA/B,EACAD,EACAkB,EACAnB,EACc,CACd,IAAMgF,EAAa/C,EAAK,IACpB,YAAYA,EAAK,IAAI,QAAQ,gBAAiB,GAAG,CAAC,GAClDtB,GAAe,UAAU,EAGvBsE,EAAYnE,EAAkBmB,EAAK,WAAa,WAAW,EAC3DiD,EAAgBjD,EAAK,gBAAkB,OACzC,MAAMnB,EAAkB,OAAOmB,EAAK,aAAa,CAAC,EAAE,MAAM,EAAG,EAAE,CAAC,GAChE,GAGEkD,EAAgB,GAAGF,CAAS,GAAGC,CAAa,GAAG,KAAK,EAC1DjF,EAAM,KAAK,OAAO+E,CAAU,IAAIG,CAAa,GAAG,EAGhD,IAAMC,EAA0B,CAAC,EAC7BC,EAEJ,QAAWC,KAAUrD,EAAK,SAAU,CAClC,IAAMsD,EAAW,GAAGP,CAAU,IAAIM,EAAO,MAAM,QAAQ,gBAAiB,GAAG,CAAC,GAEtEE,EAAkB1E,EAAkBwE,EAAO,KAAK,EAChDG,EAAcH,EAAO,MACvB,GAAGE,CAAe,UAClB,GAAGA,CAAe,WAChBE,EAAcJ,EAAO,MAAQ,aAAe,aAGlDrF,EAAM,KAAK,OAAOsF,CAAQ,IAAIE,CAAW,IAAIC,CAAW,EAAE,EAK1D,IAAMC,EAAYL,EAAO,UACrB,IAAIxE,EAAkBwE,EAAO,SAAS,EAAE,QAAQ,MAAO,EAAE,CAAC,IAC1D,GAIJ,GAHArF,EAAM,KAAK,OAAO+E,CAAU,OAAOW,CAAS,IAAIJ,CAAQ,EAAE,EAGtDD,EAAO,SAAS,OAAS,EAAG,CAC9B,IAAIM,EAASL,EACb,QAAWhE,KAAS+D,EAAO,SAAU,CACnC,IAAM9D,EAASC,GAAWF,EAAOrB,EAASD,EAAOkB,EAAUnB,CAAK,EAChEC,EAAM,KAAK,OAAO2F,CAAM,QAAQpE,EAAO,OAAO,EAAE,EAChDoE,EAASpE,EAAO,MAClB,CACA4D,EAAc,KAAKQ,CAAM,EACrBN,EAAO,QACTD,EAAoBO,EAExB,MACER,EAAc,KAAKG,CAAQ,EACvBD,EAAO,QACTD,EAAoBE,EAG1B,CAGA,OAAIF,EACK,CAAE,QAASL,EAAY,OAAQK,CAAkB,EAInD,CAAE,QAASL,EAAY,OAAQA,CAAW,CACnD,CCzoBO,SAASa,GAAeC,EAA0C,CACvE,IAAMC,EAAc,CAClB,GAAI,UACJ,YAAa,UACb,KAAM,UACN,UAAW,UACX,OAAQ,UACR,QAAS,UACT,QAAS,UACT,MAAO,UACP,QAAS,UACT,KAAM,UACN,MAAO,UAEP,YAAa,UACb,YAAa,UACb,YAAa,UACb,UAAW,UACX,YAAa,UACb,WAAY,UACZ,YAAa,UAEb,SAAU,UACV,SAAU,UACV,YAAa,UACb,SAAU,UACV,QAAS,UACT,aAAc,SAChB,EAEMC,EAAa,CACjB,GAAI,UACJ,YAAa,UACb,KAAM,UACN,UAAW,UACX,OAAQ,UACR,QAAS,UACT,QAAS,UACT,MAAO,UACP,QAAS,UACT,KAAM,UACN,MAAO,UAEP,YAAa,UACb,YAAa,UACb,YAAa,UACb,UAAW,UACX,YAAa,UACb,WAAY,UACZ,YAAa,UAEb,SAAU,UACV,SAAU,UACV,YAAa,UACb,SAAU,UACV,QAAS,UACT,aAAc,SAChB,EAEMC,EAAqBC,GAA+B;AAAA,YAChDA,EAAO,EAAE;AAAA,sBACCA,EAAO,WAAW;AAAA,cAC1BA,EAAO,IAAI;AAAA,oBACLA,EAAO,SAAS;AAAA,gBACpBA,EAAO,MAAM;AAAA,iBACZA,EAAO,OAAO;AAAA,iBACdA,EAAO,OAAO;AAAA,eAChBA,EAAO,KAAK;AAAA,iBACVA,EAAO,OAAO;AAAA,cACjBA,EAAO,IAAI;AAAA,eACVA,EAAO,KAAK;AAAA,sBACLA,EAAO,WAAW;AAAA,sBAClBA,EAAO,WAAW;AAAA,sBAClBA,EAAO,WAAW;AAAA,oBACpBA,EAAO,SAAS;AAAA,sBACdA,EAAO,WAAW;AAAA,qBACnBA,EAAO,UAAU;AAAA,sBAChBA,EAAO,WAAW;AAAA,mBACrBA,EAAO,QAAQ;AAAA,mBACfA,EAAO,QAAQ;AAAA,sBACZA,EAAO,WAAW;AAAA,mBACrBA,EAAO,QAAQ;AAAA,kBAChBA,EAAO,OAAO;AAAA,uBACTA,EAAO,YAAY;AAAA,IAGpCC,EAEJ,OAAIL,IAAU,OACZK,EAAW;AAAA;AAAA,UAELF,EAAkBF,CAAW,CAAC;AAAA;AAAA;AAAA;AAAA,YAI5BE,EAAkBD,CAAU,CAAC;AAAA;AAAA;AAAA,MAI5BF,IAAU,OACnBK,EAAW;AAAA;AAAA,UAELF,EAAkBD,CAAU,CAAC;AAAA;AAAA,MAInCG,EAAW;AAAA;AAAA,UAELF,EAAkBF,CAAW,CAAC;AAAA;AAAA,MAK/B;AAAA,EACPI,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAycV,CCvjBO,SAASC,GAAqBC,EAK1B,CACT,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA2BHA,EAAQ,YAAc,wBAA0B,EAAE;AAAA,MAClDA,EAAQ,WAAa,qBAAuB,EAAE;AAAA,MAC9CA,EAAQ,MAAQ,mBAAmBA,EAAQ,KAAK,MAAQ,EAAE;AAAA,MAC1DA,EAAQ,QAAU,kBAAoB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["require_constants","__commonJSMin","exports","module","BINARY_TYPES","hasBlob","require_buffer_util","__commonJSMin","exports","module","EMPTY_BUFFER","FastBuffer","concat","list","totalLength","target","offset","i","buf","_mask","source","mask","output","length","_unmask","buffer","toArrayBuffer","toBuffer","data","bufferUtil","require_limiter","__commonJSMin","exports","module","kDone","kRun","Limiter","concurrency","job","require_permessage_deflate","__commonJSMin","exports","module","zlib","bufferUtil","Limiter","kStatusCode","FastBuffer","TRAILER","kPerMessageDeflate","kTotalLength","kCallback","kBuffers","kError","zlibLimiter","PerMessageDeflate","options","isServer","maxPayload","concurrency","params","configurations","callback","offers","opts","accepted","response","key","value","num","data","fin","done","err","result","endpoint","windowBits","inflateOnError","inflateOnData","deflateOnData","chunk","require_validation","__commonJSMin","exports","module","isUtf8","hasBlob","tokenChars","isValidStatusCode","code","_isValidUTF8","buf","len","i","isBlob","value","isValidUTF8","require_receiver","__commonJSMin","exports","module","Writable","PerMessageDeflate","BINARY_TYPES","EMPTY_BUFFER","kStatusCode","kWebSocket","concat","toArrayBuffer","unmask","isValidStatusCode","isValidUTF8","FastBuffer","GET_INFO","GET_PAYLOAD_LENGTH_16","GET_PAYLOAD_LENGTH_64","GET_MASK","GET_DATA","INFLATING","DEFER_EVENT","Receiver","options","chunk","encoding","cb","n","buf","dst","offset","error","compressed","num","data","err","messageLength","fragments","code","ErrorCtor","message","prefix","statusCode","errorCode","require_sender","__commonJSMin","exports","module","Duplex","randomFillSync","PerMessageDeflate","EMPTY_BUFFER","kWebSocket","NOOP","isBlob","isValidStatusCode","applyMask","toBuffer","kByteLength","maskBuffer","RANDOM_POOL_SIZE","randomPool","randomPoolPointer","DEFAULT","DEFLATING","GET_BLOB_DATA","Sender","_Sender","socket","extensions","generateMask","data","options","mask","merge","offset","skipMasking","dataLength","payloadLength","target","code","cb","buf","length","byteLength","readOnly","perMessageDeflate","opcode","rsv1","opts","blob","compress","arrayBuffer","err","callCallbacks","onError","_","params","list","sender","i","callback","require_event_target","__commonJSMin","exports","module","kForOnEventAttribute","kListener","kCode","kData","kError","kMessage","kReason","kTarget","kType","kWasClean","Event","type","CloseEvent","options","ErrorEvent","MessageEvent","EventTarget","handler","listener","wrapper","data","isBinary","event","callListener","code","message","error","thisArg","require_extension","__commonJSMin","exports","module","tokenChars","push","dest","name","elem","parse","header","offers","params","mustUnescape","isEscaping","inQuotes","extensionName","paramName","start","code","end","i","value","token","format","extensions","extension","configurations","k","values","v","require_websocket","__commonJSMin","exports","module","EventEmitter","https","http","net","tls","randomBytes","createHash","Duplex","Readable","URL","PerMessageDeflate","Receiver","Sender","isBlob","BINARY_TYPES","CLOSE_TIMEOUT","EMPTY_BUFFER","GUID","kForOnEventAttribute","kListener","kStatusCode","kWebSocket","NOOP","addEventListener","removeEventListener","format","parse","toBuffer","kAborted","protocolVersions","readyStates","subprotocolRegex","WebSocket","_WebSocket","address","protocols","options","initAsClient","type","socket","head","receiver","sender","receiverOnConclude","receiverOnDrain","receiverOnError","receiverOnMessage","receiverOnPing","receiverOnPong","senderOnError","socketOnClose","socketOnData","socketOnEnd","socketOnError","code","data","abortHandshake","err","setCloseTimer","mask","cb","sendAfterClose","opts","property","method","listener","handler","websocket","parsedUrl","isSecure","isIpcUrl","invalidUrlMessage","emitErrorAndClose","defaultPort","key","request","protocolSet","perMessageDeflate","tlsConnect","netConnect","protocol","parts","req","headers","value","isSameHost","res","location","statusCode","addr","upgrade","digest","serverProt","protError","secWebSocketExtensions","extensions","extensionNames","stream","message","length","reason","resume","receiverOnFinish","isBinary","chunk","require_stream","__commonJSMin","exports","module","WebSocket","Duplex","emitClose","stream","duplexOnEnd","duplexOnError","err","createWebSocketStream","ws","options","terminateOnDestroy","duplex","msg","isBinary","data","callback","called","chunk","encoding","require_subprotocol","__commonJSMin","exports","module","tokenChars","parse","header","protocols","start","end","i","code","protocol","require_websocket_server","__commonJSMin","exports","module","EventEmitter","http","Duplex","createHash","extension","PerMessageDeflate","subprotocol","WebSocket","CLOSE_TIMEOUT","GUID","kWebSocket","keyRegex","RUNNING","CLOSING","CLOSED","WebSocketServer","options","callback","req","res","body","emitConnection","addListeners","socket","head","cb","emitClose","server","index","socketOnError","key","upgrade","version","abortHandshakeOrEmitwsClientError","abortHandshake","secWebSocketProtocol","protocols","secWebSocketExtensions","extensions","perMessageDeflate","offers","info","verified","code","message","headers","ws","protocol","params","value","map","event","h","err","wrapper_exports","__export","Receiver","Sender","WebSocket","WebSocketServer","createWebSocketStream","wrapper_default","import_stream","import_receiver","import_sender","import_websocket","import_websocket_server","init_wrapper","__esmMin","visualize_exports","__export","asciiRenderer","createDevServer","createEventCollector","createIRBuilder","createLiveVisualizer","createParallelDetector","createPerformanceAnalyzer","createTimeTravelController","createVisualizer","defaultColorScheme","detectParallelGroups","getHeatLevel","hasChildren","htmlRenderer","isDecisionNode","isParallelNode","isRaceNode","isSequenceNode","isStepNode","mermaidRenderer","renderToHTML","trackDecision","trackIf","trackSwitch","visualizeEvents","__toCommonJS","formatDuration","ms","minutes","seconds","generateId","hasRealScopeNodes","nodes","node","detectParallelGroups","options","minOverlapMs","maxGapMs","stepsWithTiming","nonStepNodes","i","b","groups","currentGroup","step","groupStart","s","groupEnd","startedTogether","hasTrueOverlap","overlapDuration","groupedNodes","group","position","children","startTs","endTs","parallelNode","deriveGroupState","originalIndex","g","c","createParallelDetector","createIRBuilder","options","detectParallel","parallelDetection","enableSnapshots","maxSnapshots","workflowId","workflowStartTs","workflowState","workflowError","workflowDurationMs","activeSteps","scopeStack","decisionStack","currentNodes","createdAt","lastUpdatedAt","hookState","snapshots","eventIndex","getStepId","event","generateId","addNode","node","decision","branch","firstBranch","captureSnapshot","ir","getIR","activeStepsCopy","id","step","snapshot","handleEvent","active","hookExec","handleScopeEvent","scope","deriveState","handleDecisionEvent","branchKey","existing","branches","b","children","c","getCurrentNodes","nodes","detectParallelGroups","root","hasHooks","reset","getSnapshots","getSnapshotAt","index","getIRAt","clearSnapshots","isStepNode","node","isSequenceNode","isParallelNode","isRaceNode","isDecisionNode","hasChildren","RESET","BOLD","DIM","FG_RED","FG_GREEN","FG_YELLOW","FG_BLUE","FG_GRAY","FG_WHITE","colorize","text","color","bold","dim","defaultColorScheme","getStateSymbol","state","getColoredSymbol","colors","symbol","colorByState","stripAnsi","str","BOX","HEAT_COLORS","RESET","getHeatColor","heat","applyHeatColor","text","color","SPARK_CHARS","renderSparkline","values","width","subset","min","range","v","normalized","index","padEnd","str","visibleLen","stripAnsi","padding","horizontalLine","title","titleText","remainingWidth","leftPad","rightPad","renderHookExecution","hook","label","colors","symbol","colorize","timing","dim","formatDuration","context","error","renderHooks","hooks","lines","asciiRenderer","ir","options","defaultColorScheme","innerWidth","workflowName","headerTitle","bold","hookLines","line","childLines","renderNodes","status","footer","colorByState","nodes","depth","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","getColoredSymbol","name","enhanced","nodeId","nameColored","inputStr","outputStr","timingStr","timingDisplay","history","timeoutInfo","hookExec","hookSymbol","hookTiming","indent","mode","i","child","prefix","nestedLines","winnerSuffix","condition","decisionValue","branchTaken","branch","branchSymbol","branchColor","branchLabel","branchCondition","flattenNodes","nodes","result","node","branch","percentile","sortedValues","p","index","getHeatLevel","heat","createPerformanceAnalyzer","timingData","retryData","errorData","timeoutData","currentRunEvents","getNodeId","event","processEvents","events","stepState","id","state","timeout","timings","retry","error","addRun","run","addEvent","finalizeRun","_runId","computePerformance","nodeId","sorted","a","b","mean","variance","acc","t","getNodePerformance","getHeatmap","ir","metric","allNodes","values","perf","value","vals","v","min","max","range","getAllPerformance","getSlowestNodes","limit","getErrorProneNodes","getRetryProneNodes","exportData","importData","json","data","k","clear","getStyleDefinitions","getHeatmapStyleDefinitions","getHeatClass","level","getHookStyleDefinitions","renderHooks","hooks","lines","options","lastHookId","hookId","state","icon","timing","formatDuration","context","nodeCounter","generateNodeId","prefix","resetNodeCounter","escapeMermaidText","text","escapeSubgraphName","mermaidRenderer","ir","enhanced","hookExitId","startId","prevNodeId","child","result","renderNode","endId","endIcon","endLabel","endShape","endClass","getStyleDefinitions","getHeatmapStyleDefinitions","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","id","mermaidOpts","showRetryEdges","showErrorEdges","showTimeoutEdges","label","stateIcon","ioInfo","inputStr","outputStr","hookInfo","hookExec","hookIcon","hookTiming","escapedLabel","nodeClass","nodeId","heat","level","getHeatLevel","getHeatClass","shape","retryLabel","errorNodeId","errorLabel","timeoutNodeId","timeoutMs","subgraphId","forkId","joinId","name","modeLabel","note","childExitIds","exitId","stateClass","winnerExitId","isWinner","decisionId","condition","decisionValue","decisionLabel","branchExitIds","takenBranchExitId","branch","branchId","branchLabelText","branchLabel","branchClass","edgeLabel","prevId","generateStyles","theme","lightColors","darkColors","generateThemeVars","colors","themeCSS","generateClientScript","options","NODE_WIDTH","NODE_HEIGHT","NODE_SPACING_H","NODE_SPACING_V","CONTAINER_PADDING","layoutWorkflow","nodes","direction","isVertical","layoutNodes","currentX","currentY","maxWidth","maxHeight","node","result","layoutFlowNode","x","y","_isVertical","isStepNode","isParallelNode","isRaceNode","containerType","label","children","innerX","innerY","innerMaxWidth","innerMaxHeight","child","containerWidth","containerHeight","isDecisionNode","branch","renderLayoutNodeSVG","showTimings","renderContainerSVG","renderStepSVG","timing","formatDuration","escapeAttr","escapeXml","truncate","childrenSVG","c","renderEdgesSVG","edges","i","from","to","x1","y1","x2","y2","generateHTML","ir","options","layout","svgWidth","svgHeight","nodesSVG","n","edgesSVG","workflowName","css","generateStyles","js","generateClientScript","serializeWorkflowData","buildWorkflowData","collectNodes","flowNodes","str","maxLen","defaultHTMLOptions","htmlRenderer","htmlOptions","renderToHTML","fullOptions","ANSI","n","createLiveVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","stream","updateInterval","builder","createIRBuilder","renderer","asciiRenderer","renderOptions","defaultColorScheme","isRunning","lastOutput","lastLineCount","throttleTimeout","pendingUpdate","write","text","redraw","ir","getIR","output","scheduleRedraw","handleEvent","event","handleScopeEvent","handleDecisionEvent","render","start","stop","refresh","reset","trackDecision","decisionId","options","condition","value","name","workflowId","emit","startTs","branchTaken","branches","takeBranch","label","taken","branchCondition","end","durationMs","trackIf","tracker","trackSwitch","caseValue","createTimeTravelController","options","maxSnapshots","autoRecord","builderOptions","builder","createIRBuilder","state","listeners","playbackTimer","notifyListeners","currentState","getState","listener","syncFromBuilder","handleEvent","event","seek","index","snapshots","stepForward","stepBackward","play","speed","playNext","current","scaledDelay","pause","getCurrentIR","getIRAt","getSnapshots","getSnapshotAt","onStateChange","callback","startRecording","stopRecording","reset","getBuilder","import_node_http","import_node_child_process","createDevServer","options","port","host","autoOpen","workflowName","timeTravel","heatmap","maxSnapshots","ttController","createTimeTravelController","analyzer","createPerformanceAnalyzer","httpServer","wsServer","actualPort","isRunning","broadcast","message","data","client","handleClientMessage","ws","raw","msg","payload","ir","snapshots","s","e","generatePage","wsUrl","renderToHTML","handleRequest","req","res","url","loadWebSocketServer","WebSocketServer","openBrowser","platform","err","start","request","socket","head","state","resolve","reject","stop","handleEvent","event","pushUpdate","pushHeatmap","heat","k","v","complete","getTimeTravel","getAnalyzer","getCurrentIR","createVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","builder","createIRBuilder","updateCallbacks","ascii","asciiRenderer","mermaid","mermaidRenderer","renderOptions","defaultColorScheme","notifyUpdate","ir","callback","handleEvent","event","handleScopeEvent","handleDecisionEvent","getIR","render","renderAs","format","reset","onUpdate","visualizeEvents","events","viz","createEventCollector","e"]}
|
|
1
|
+
{"version":3,"sources":["../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/constants.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/buffer-util.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/limiter.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/permessage-deflate.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/validation.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/receiver.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/sender.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/event-target.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/extension.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/stream.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/subprotocol.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/lib/websocket-server.js","../node_modules/.pnpm/ws@8.19.0/node_modules/ws/wrapper.mjs","../src/visualize/index.ts","../src/visualize/utils/timing.ts","../src/visualize/parallel-detector.ts","../src/visualize/ir-builder.ts","../src/visualize/types.ts","../src/visualize/renderers/colors.ts","../src/visualize/renderers/ascii.ts","../src/visualize/performance-analyzer.ts","../src/visualize/renderers/mermaid.ts","../src/visualize/renderers/logger.ts","../src/visualize/renderers/html-styles.ts","../src/visualize/renderers/html-client.ts","../src/visualize/renderers/html.ts","../src/visualize/live-visualizer.ts","../src/visualize/decision-tracker.ts","../src/visualize/time-travel.ts","../src/visualize/dev-server.ts"],"sourcesContent":["'use strict';\n\nconst BINARY_TYPES = ['nodebuffer', 'arraybuffer', 'fragments'];\nconst hasBlob = typeof Blob !== 'undefined';\n\nif (hasBlob) BINARY_TYPES.push('blob');\n\nmodule.exports = {\n BINARY_TYPES,\n CLOSE_TIMEOUT: 30000,\n EMPTY_BUFFER: Buffer.alloc(0),\n GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',\n hasBlob,\n kForOnEventAttribute: Symbol('kIsForOnEventAttribute'),\n kListener: Symbol('kListener'),\n kStatusCode: Symbol('status-code'),\n kWebSocket: Symbol('websocket'),\n NOOP: () => {}\n};\n","'use strict';\n\nconst { EMPTY_BUFFER } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\n\n/**\n * Merges an array of buffers into a new buffer.\n *\n * @param {Buffer[]} list The array of buffers to concat\n * @param {Number} totalLength The total length of buffers in the list\n * @return {Buffer} The resulting buffer\n * @public\n */\nfunction concat(list, totalLength) {\n if (list.length === 0) return EMPTY_BUFFER;\n if (list.length === 1) return list[0];\n\n const target = Buffer.allocUnsafe(totalLength);\n let offset = 0;\n\n for (let i = 0; i < list.length; i++) {\n const buf = list[i];\n target.set(buf, offset);\n offset += buf.length;\n }\n\n if (offset < totalLength) {\n return new FastBuffer(target.buffer, target.byteOffset, offset);\n }\n\n return target;\n}\n\n/**\n * Masks a buffer using the given mask.\n *\n * @param {Buffer} source The buffer to mask\n * @param {Buffer} mask The mask to use\n * @param {Buffer} output The buffer where to store the result\n * @param {Number} offset The offset at which to start writing\n * @param {Number} length The number of bytes to mask.\n * @public\n */\nfunction _mask(source, mask, output, offset, length) {\n for (let i = 0; i < length; i++) {\n output[offset + i] = source[i] ^ mask[i & 3];\n }\n}\n\n/**\n * Unmasks a buffer using the given mask.\n *\n * @param {Buffer} buffer The buffer to unmask\n * @param {Buffer} mask The mask to use\n * @public\n */\nfunction _unmask(buffer, mask) {\n for (let i = 0; i < buffer.length; i++) {\n buffer[i] ^= mask[i & 3];\n }\n}\n\n/**\n * Converts a buffer to an `ArrayBuffer`.\n *\n * @param {Buffer} buf The buffer to convert\n * @return {ArrayBuffer} Converted buffer\n * @public\n */\nfunction toArrayBuffer(buf) {\n if (buf.length === buf.buffer.byteLength) {\n return buf.buffer;\n }\n\n return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length);\n}\n\n/**\n * Converts `data` to a `Buffer`.\n *\n * @param {*} data The data to convert\n * @return {Buffer} The buffer\n * @throws {TypeError}\n * @public\n */\nfunction toBuffer(data) {\n toBuffer.readOnly = true;\n\n if (Buffer.isBuffer(data)) return data;\n\n let buf;\n\n if (data instanceof ArrayBuffer) {\n buf = new FastBuffer(data);\n } else if (ArrayBuffer.isView(data)) {\n buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength);\n } else {\n buf = Buffer.from(data);\n toBuffer.readOnly = false;\n }\n\n return buf;\n}\n\nmodule.exports = {\n concat,\n mask: _mask,\n toArrayBuffer,\n toBuffer,\n unmask: _unmask\n};\n\n/* istanbul ignore else */\nif (!process.env.WS_NO_BUFFER_UTIL) {\n try {\n const bufferUtil = require('bufferutil');\n\n module.exports.mask = function (source, mask, output, offset, length) {\n if (length < 48) _mask(source, mask, output, offset, length);\n else bufferUtil.mask(source, mask, output, offset, length);\n };\n\n module.exports.unmask = function (buffer, mask) {\n if (buffer.length < 32) _unmask(buffer, mask);\n else bufferUtil.unmask(buffer, mask);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst kDone = Symbol('kDone');\nconst kRun = Symbol('kRun');\n\n/**\n * A very simple job queue with adjustable concurrency. Adapted from\n * https://github.com/STRML/async-limiter\n */\nclass Limiter {\n /**\n * Creates a new `Limiter`.\n *\n * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed\n * to run concurrently\n */\n constructor(concurrency) {\n this[kDone] = () => {\n this.pending--;\n this[kRun]();\n };\n this.concurrency = concurrency || Infinity;\n this.jobs = [];\n this.pending = 0;\n }\n\n /**\n * Adds a job to the queue.\n *\n * @param {Function} job The job to run\n * @public\n */\n add(job) {\n this.jobs.push(job);\n this[kRun]();\n }\n\n /**\n * Removes a job from the queue and runs it if possible.\n *\n * @private\n */\n [kRun]() {\n if (this.pending === this.concurrency) return;\n\n if (this.jobs.length) {\n const job = this.jobs.shift();\n\n this.pending++;\n job(this[kDone]);\n }\n }\n}\n\nmodule.exports = Limiter;\n","'use strict';\n\nconst zlib = require('zlib');\n\nconst bufferUtil = require('./buffer-util');\nconst Limiter = require('./limiter');\nconst { kStatusCode } = require('./constants');\n\nconst FastBuffer = Buffer[Symbol.species];\nconst TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);\nconst kPerMessageDeflate = Symbol('permessage-deflate');\nconst kTotalLength = Symbol('total-length');\nconst kCallback = Symbol('callback');\nconst kBuffers = Symbol('buffers');\nconst kError = Symbol('error');\n\n//\n// We limit zlib concurrency, which prevents severe memory fragmentation\n// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913\n// and https://github.com/websockets/ws/issues/1202\n//\n// Intentionally global; it's the global thread pool that's an issue.\n//\nlet zlibLimiter;\n\n/**\n * permessage-deflate implementation.\n */\nclass PerMessageDeflate {\n /**\n * Creates a PerMessageDeflate instance.\n *\n * @param {Object} [options] Configuration options\n * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support\n * for, or request, a custom client window size\n * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/\n * acknowledge disabling of client context takeover\n * @param {Number} [options.concurrencyLimit=10] The number of concurrent\n * calls to zlib\n * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the\n * use of a custom server window size\n * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept\n * disabling of server context takeover\n * @param {Number} [options.threshold=1024] Size (in bytes) below which\n * messages should not be compressed if context takeover is disabled\n * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on\n * deflate\n * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on\n * inflate\n * @param {Boolean} [isServer=false] Create the instance in either server or\n * client mode\n * @param {Number} [maxPayload=0] The maximum allowed message length\n */\n constructor(options, isServer, maxPayload) {\n this._maxPayload = maxPayload | 0;\n this._options = options || {};\n this._threshold =\n this._options.threshold !== undefined ? this._options.threshold : 1024;\n this._isServer = !!isServer;\n this._deflate = null;\n this._inflate = null;\n\n this.params = null;\n\n if (!zlibLimiter) {\n const concurrency =\n this._options.concurrencyLimit !== undefined\n ? this._options.concurrencyLimit\n : 10;\n zlibLimiter = new Limiter(concurrency);\n }\n }\n\n /**\n * @type {String}\n */\n static get extensionName() {\n return 'permessage-deflate';\n }\n\n /**\n * Create an extension negotiation offer.\n *\n * @return {Object} Extension parameters\n * @public\n */\n offer() {\n const params = {};\n\n if (this._options.serverNoContextTakeover) {\n params.server_no_context_takeover = true;\n }\n if (this._options.clientNoContextTakeover) {\n params.client_no_context_takeover = true;\n }\n if (this._options.serverMaxWindowBits) {\n params.server_max_window_bits = this._options.serverMaxWindowBits;\n }\n if (this._options.clientMaxWindowBits) {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n } else if (this._options.clientMaxWindowBits == null) {\n params.client_max_window_bits = true;\n }\n\n return params;\n }\n\n /**\n * Accept an extension negotiation offer/response.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Object} Accepted configuration\n * @public\n */\n accept(configurations) {\n configurations = this.normalizeParams(configurations);\n\n this.params = this._isServer\n ? this.acceptAsServer(configurations)\n : this.acceptAsClient(configurations);\n\n return this.params;\n }\n\n /**\n * Releases all resources used by the extension.\n *\n * @public\n */\n cleanup() {\n if (this._inflate) {\n this._inflate.close();\n this._inflate = null;\n }\n\n if (this._deflate) {\n const callback = this._deflate[kCallback];\n\n this._deflate.close();\n this._deflate = null;\n\n if (callback) {\n callback(\n new Error(\n 'The deflate stream was closed while data was being processed'\n )\n );\n }\n }\n }\n\n /**\n * Accept an extension negotiation offer.\n *\n * @param {Array} offers The extension negotiation offers\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsServer(offers) {\n const opts = this._options;\n const accepted = offers.find((params) => {\n if (\n (opts.serverNoContextTakeover === false &&\n params.server_no_context_takeover) ||\n (params.server_max_window_bits &&\n (opts.serverMaxWindowBits === false ||\n (typeof opts.serverMaxWindowBits === 'number' &&\n opts.serverMaxWindowBits > params.server_max_window_bits))) ||\n (typeof opts.clientMaxWindowBits === 'number' &&\n !params.client_max_window_bits)\n ) {\n return false;\n }\n\n return true;\n });\n\n if (!accepted) {\n throw new Error('None of the extension offers can be accepted');\n }\n\n if (opts.serverNoContextTakeover) {\n accepted.server_no_context_takeover = true;\n }\n if (opts.clientNoContextTakeover) {\n accepted.client_no_context_takeover = true;\n }\n if (typeof opts.serverMaxWindowBits === 'number') {\n accepted.server_max_window_bits = opts.serverMaxWindowBits;\n }\n if (typeof opts.clientMaxWindowBits === 'number') {\n accepted.client_max_window_bits = opts.clientMaxWindowBits;\n } else if (\n accepted.client_max_window_bits === true ||\n opts.clientMaxWindowBits === false\n ) {\n delete accepted.client_max_window_bits;\n }\n\n return accepted;\n }\n\n /**\n * Accept the extension negotiation response.\n *\n * @param {Array} response The extension negotiation response\n * @return {Object} Accepted configuration\n * @private\n */\n acceptAsClient(response) {\n const params = response[0];\n\n if (\n this._options.clientNoContextTakeover === false &&\n params.client_no_context_takeover\n ) {\n throw new Error('Unexpected parameter \"client_no_context_takeover\"');\n }\n\n if (!params.client_max_window_bits) {\n if (typeof this._options.clientMaxWindowBits === 'number') {\n params.client_max_window_bits = this._options.clientMaxWindowBits;\n }\n } else if (\n this._options.clientMaxWindowBits === false ||\n (typeof this._options.clientMaxWindowBits === 'number' &&\n params.client_max_window_bits > this._options.clientMaxWindowBits)\n ) {\n throw new Error(\n 'Unexpected or invalid parameter \"client_max_window_bits\"'\n );\n }\n\n return params;\n }\n\n /**\n * Normalize parameters.\n *\n * @param {Array} configurations The extension negotiation offers/reponse\n * @return {Array} The offers/response with normalized parameters\n * @private\n */\n normalizeParams(configurations) {\n configurations.forEach((params) => {\n Object.keys(params).forEach((key) => {\n let value = params[key];\n\n if (value.length > 1) {\n throw new Error(`Parameter \"${key}\" must have only a single value`);\n }\n\n value = value[0];\n\n if (key === 'client_max_window_bits') {\n if (value !== true) {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (!this._isServer) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else if (key === 'server_max_window_bits') {\n const num = +value;\n if (!Number.isInteger(num) || num < 8 || num > 15) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n value = num;\n } else if (\n key === 'client_no_context_takeover' ||\n key === 'server_no_context_takeover'\n ) {\n if (value !== true) {\n throw new TypeError(\n `Invalid value for parameter \"${key}\": ${value}`\n );\n }\n } else {\n throw new Error(`Unknown parameter \"${key}\"`);\n }\n\n params[key] = value;\n });\n });\n\n return configurations;\n }\n\n /**\n * Decompress data. Concurrency limited.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n decompress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._decompress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Compress data. Concurrency limited.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @public\n */\n compress(data, fin, callback) {\n zlibLimiter.add((done) => {\n this._compress(data, fin, (err, result) => {\n done();\n callback(err, result);\n });\n });\n }\n\n /**\n * Decompress data.\n *\n * @param {Buffer} data Compressed data\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _decompress(data, fin, callback) {\n const endpoint = this._isServer ? 'client' : 'server';\n\n if (!this._inflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._inflate = zlib.createInflateRaw({\n ...this._options.zlibInflateOptions,\n windowBits\n });\n this._inflate[kPerMessageDeflate] = this;\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n this._inflate.on('error', inflateOnError);\n this._inflate.on('data', inflateOnData);\n }\n\n this._inflate[kCallback] = callback;\n\n this._inflate.write(data);\n if (fin) this._inflate.write(TRAILER);\n\n this._inflate.flush(() => {\n const err = this._inflate[kError];\n\n if (err) {\n this._inflate.close();\n this._inflate = null;\n callback(err);\n return;\n }\n\n const data = bufferUtil.concat(\n this._inflate[kBuffers],\n this._inflate[kTotalLength]\n );\n\n if (this._inflate._readableState.endEmitted) {\n this._inflate.close();\n this._inflate = null;\n } else {\n this._inflate[kTotalLength] = 0;\n this._inflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._inflate.reset();\n }\n }\n\n callback(null, data);\n });\n }\n\n /**\n * Compress data.\n *\n * @param {(Buffer|String)} data Data to compress\n * @param {Boolean} fin Specifies whether or not this is the last fragment\n * @param {Function} callback Callback\n * @private\n */\n _compress(data, fin, callback) {\n const endpoint = this._isServer ? 'server' : 'client';\n\n if (!this._deflate) {\n const key = `${endpoint}_max_window_bits`;\n const windowBits =\n typeof this.params[key] !== 'number'\n ? zlib.Z_DEFAULT_WINDOWBITS\n : this.params[key];\n\n this._deflate = zlib.createDeflateRaw({\n ...this._options.zlibDeflateOptions,\n windowBits\n });\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n this._deflate.on('data', deflateOnData);\n }\n\n this._deflate[kCallback] = callback;\n\n this._deflate.write(data);\n this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {\n if (!this._deflate) {\n //\n // The deflate stream was closed while data was being processed.\n //\n return;\n }\n\n let data = bufferUtil.concat(\n this._deflate[kBuffers],\n this._deflate[kTotalLength]\n );\n\n if (fin) {\n data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4);\n }\n\n //\n // Ensure that the callback will not be called again in\n // `PerMessageDeflate#cleanup()`.\n //\n this._deflate[kCallback] = null;\n\n this._deflate[kTotalLength] = 0;\n this._deflate[kBuffers] = [];\n\n if (fin && this.params[`${endpoint}_no_context_takeover`]) {\n this._deflate.reset();\n }\n\n callback(null, data);\n });\n }\n}\n\nmodule.exports = PerMessageDeflate;\n\n/**\n * The listener of the `zlib.DeflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction deflateOnData(chunk) {\n this[kBuffers].push(chunk);\n this[kTotalLength] += chunk.length;\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction inflateOnData(chunk) {\n this[kTotalLength] += chunk.length;\n\n if (\n this[kPerMessageDeflate]._maxPayload < 1 ||\n this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload\n ) {\n this[kBuffers].push(chunk);\n return;\n }\n\n this[kError] = new RangeError('Max payload size exceeded');\n this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';\n this[kError][kStatusCode] = 1009;\n this.removeListener('data', inflateOnData);\n\n //\n // The choice to employ `zlib.reset()` over `zlib.close()` is dictated by the\n // fact that in Node.js versions prior to 13.10.0, the callback for\n // `zlib.flush()` is not called if `zlib.close()` is used. Utilizing\n // `zlib.reset()` ensures that either the callback is invoked or an error is\n // emitted.\n //\n this.reset();\n}\n\n/**\n * The listener of the `zlib.InflateRaw` stream `'error'` event.\n *\n * @param {Error} err The emitted error\n * @private\n */\nfunction inflateOnError(err) {\n //\n // There is no need to call `Zlib#close()` as the handle is automatically\n // closed when an error is emitted.\n //\n this[kPerMessageDeflate]._inflate = null;\n\n if (this[kError]) {\n this[kCallback](this[kError]);\n return;\n }\n\n err[kStatusCode] = 1007;\n this[kCallback](err);\n}\n","'use strict';\n\nconst { isUtf8 } = require('buffer');\n\nconst { hasBlob } = require('./constants');\n\n//\n// Allowed token characters:\n//\n// '!', '#', '$', '%', '&', ''', '*', '+', '-',\n// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'\n//\n// tokenChars[32] === 0 // ' '\n// tokenChars[33] === 1 // '!'\n// tokenChars[34] === 0 // '\"'\n// ...\n//\n// prettier-ignore\nconst tokenChars = [\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15\n 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31\n 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63\n 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111\n 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127\n];\n\n/**\n * Checks if a status code is allowed in a close frame.\n *\n * @param {Number} code The status code\n * @return {Boolean} `true` if the status code is valid, else `false`\n * @public\n */\nfunction isValidStatusCode(code) {\n return (\n (code >= 1000 &&\n code <= 1014 &&\n code !== 1004 &&\n code !== 1005 &&\n code !== 1006) ||\n (code >= 3000 && code <= 4999)\n );\n}\n\n/**\n * Checks if a given buffer contains only correct UTF-8.\n * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by\n * Markus Kuhn.\n *\n * @param {Buffer} buf The buffer to check\n * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`\n * @public\n */\nfunction _isValidUTF8(buf) {\n const len = buf.length;\n let i = 0;\n\n while (i < len) {\n if ((buf[i] & 0x80) === 0) {\n // 0xxxxxxx\n i++;\n } else if ((buf[i] & 0xe0) === 0xc0) {\n // 110xxxxx 10xxxxxx\n if (\n i + 1 === len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i] & 0xfe) === 0xc0 // Overlong\n ) {\n return false;\n }\n\n i += 2;\n } else if ((buf[i] & 0xf0) === 0xe0) {\n // 1110xxxx 10xxxxxx 10xxxxxx\n if (\n i + 2 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong\n (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)\n ) {\n return false;\n }\n\n i += 3;\n } else if ((buf[i] & 0xf8) === 0xf0) {\n // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n if (\n i + 3 >= len ||\n (buf[i + 1] & 0xc0) !== 0x80 ||\n (buf[i + 2] & 0xc0) !== 0x80 ||\n (buf[i + 3] & 0xc0) !== 0x80 ||\n (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong\n (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||\n buf[i] > 0xf4 // > U+10FFFF\n ) {\n return false;\n }\n\n i += 4;\n } else {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Determines whether a value is a `Blob`.\n *\n * @param {*} value The value to be tested\n * @return {Boolean} `true` if `value` is a `Blob`, else `false`\n * @private\n */\nfunction isBlob(value) {\n return (\n hasBlob &&\n typeof value === 'object' &&\n typeof value.arrayBuffer === 'function' &&\n typeof value.type === 'string' &&\n typeof value.stream === 'function' &&\n (value[Symbol.toStringTag] === 'Blob' ||\n value[Symbol.toStringTag] === 'File')\n );\n}\n\nmodule.exports = {\n isBlob,\n isValidStatusCode,\n isValidUTF8: _isValidUTF8,\n tokenChars\n};\n\nif (isUtf8) {\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf);\n };\n} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) {\n try {\n const isValidUTF8 = require('utf-8-validate');\n\n module.exports.isValidUTF8 = function (buf) {\n return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf);\n };\n } catch (e) {\n // Continue regardless of the error.\n }\n}\n","'use strict';\n\nconst { Writable } = require('stream');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst {\n BINARY_TYPES,\n EMPTY_BUFFER,\n kStatusCode,\n kWebSocket\n} = require('./constants');\nconst { concat, toArrayBuffer, unmask } = require('./buffer-util');\nconst { isValidStatusCode, isValidUTF8 } = require('./validation');\n\nconst FastBuffer = Buffer[Symbol.species];\n\nconst GET_INFO = 0;\nconst GET_PAYLOAD_LENGTH_16 = 1;\nconst GET_PAYLOAD_LENGTH_64 = 2;\nconst GET_MASK = 3;\nconst GET_DATA = 4;\nconst INFLATING = 5;\nconst DEFER_EVENT = 6;\n\n/**\n * HyBi Receiver implementation.\n *\n * @extends Writable\n */\nclass Receiver extends Writable {\n /**\n * Creates a Receiver instance.\n *\n * @param {Object} [options] Options object\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {String} [options.binaryType=nodebuffer] The type for binary data\n * @param {Object} [options.extensions] An object containing the negotiated\n * extensions\n * @param {Boolean} [options.isServer=false] Specifies whether to operate in\n * client or server mode\n * @param {Number} [options.maxPayload=0] The maximum allowed message length\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n */\n constructor(options = {}) {\n super();\n\n this._allowSynchronousEvents =\n options.allowSynchronousEvents !== undefined\n ? options.allowSynchronousEvents\n : true;\n this._binaryType = options.binaryType || BINARY_TYPES[0];\n this._extensions = options.extensions || {};\n this._isServer = !!options.isServer;\n this._maxPayload = options.maxPayload | 0;\n this._skipUTF8Validation = !!options.skipUTF8Validation;\n this[kWebSocket] = undefined;\n\n this._bufferedBytes = 0;\n this._buffers = [];\n\n this._compressed = false;\n this._payloadLength = 0;\n this._mask = undefined;\n this._fragmented = 0;\n this._masked = false;\n this._fin = false;\n this._opcode = 0;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragments = [];\n\n this._errored = false;\n this._loop = false;\n this._state = GET_INFO;\n }\n\n /**\n * Implements `Writable.prototype._write()`.\n *\n * @param {Buffer} chunk The chunk of data to write\n * @param {String} encoding The character encoding of `chunk`\n * @param {Function} cb Callback\n * @private\n */\n _write(chunk, encoding, cb) {\n if (this._opcode === 0x08 && this._state == GET_INFO) return cb();\n\n this._bufferedBytes += chunk.length;\n this._buffers.push(chunk);\n this.startLoop(cb);\n }\n\n /**\n * Consumes `n` bytes from the buffered data.\n *\n * @param {Number} n The number of bytes to consume\n * @return {Buffer} The consumed bytes\n * @private\n */\n consume(n) {\n this._bufferedBytes -= n;\n\n if (n === this._buffers[0].length) return this._buffers.shift();\n\n if (n < this._buffers[0].length) {\n const buf = this._buffers[0];\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n\n return new FastBuffer(buf.buffer, buf.byteOffset, n);\n }\n\n const dst = Buffer.allocUnsafe(n);\n\n do {\n const buf = this._buffers[0];\n const offset = dst.length - n;\n\n if (n >= buf.length) {\n dst.set(this._buffers.shift(), offset);\n } else {\n dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);\n this._buffers[0] = new FastBuffer(\n buf.buffer,\n buf.byteOffset + n,\n buf.length - n\n );\n }\n\n n -= buf.length;\n } while (n > 0);\n\n return dst;\n }\n\n /**\n * Starts the parsing loop.\n *\n * @param {Function} cb Callback\n * @private\n */\n startLoop(cb) {\n this._loop = true;\n\n do {\n switch (this._state) {\n case GET_INFO:\n this.getInfo(cb);\n break;\n case GET_PAYLOAD_LENGTH_16:\n this.getPayloadLength16(cb);\n break;\n case GET_PAYLOAD_LENGTH_64:\n this.getPayloadLength64(cb);\n break;\n case GET_MASK:\n this.getMask();\n break;\n case GET_DATA:\n this.getData(cb);\n break;\n case INFLATING:\n case DEFER_EVENT:\n this._loop = false;\n return;\n }\n } while (this._loop);\n\n if (!this._errored) cb();\n }\n\n /**\n * Reads the first two bytes of a frame.\n *\n * @param {Function} cb Callback\n * @private\n */\n getInfo(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(2);\n\n if ((buf[0] & 0x30) !== 0x00) {\n const error = this.createError(\n RangeError,\n 'RSV2 and RSV3 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_2_3'\n );\n\n cb(error);\n return;\n }\n\n const compressed = (buf[0] & 0x40) === 0x40;\n\n if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n this._fin = (buf[0] & 0x80) === 0x80;\n this._opcode = buf[0] & 0x0f;\n this._payloadLength = buf[1] & 0x7f;\n\n if (this._opcode === 0x00) {\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fragmented) {\n const error = this.createError(\n RangeError,\n 'invalid opcode 0',\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._opcode = this._fragmented;\n } else if (this._opcode === 0x01 || this._opcode === 0x02) {\n if (this._fragmented) {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n this._compressed = compressed;\n } else if (this._opcode > 0x07 && this._opcode < 0x0b) {\n if (!this._fin) {\n const error = this.createError(\n RangeError,\n 'FIN must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_FIN'\n );\n\n cb(error);\n return;\n }\n\n if (compressed) {\n const error = this.createError(\n RangeError,\n 'RSV1 must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_RSV_1'\n );\n\n cb(error);\n return;\n }\n\n if (\n this._payloadLength > 0x7d ||\n (this._opcode === 0x08 && this._payloadLength === 1)\n ) {\n const error = this.createError(\n RangeError,\n `invalid payload length ${this._payloadLength}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n } else {\n const error = this.createError(\n RangeError,\n `invalid opcode ${this._opcode}`,\n true,\n 1002,\n 'WS_ERR_INVALID_OPCODE'\n );\n\n cb(error);\n return;\n }\n\n if (!this._fin && !this._fragmented) this._fragmented = this._opcode;\n this._masked = (buf[1] & 0x80) === 0x80;\n\n if (this._isServer) {\n if (!this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be set',\n true,\n 1002,\n 'WS_ERR_EXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n } else if (this._masked) {\n const error = this.createError(\n RangeError,\n 'MASK must be clear',\n true,\n 1002,\n 'WS_ERR_UNEXPECTED_MASK'\n );\n\n cb(error);\n return;\n }\n\n if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;\n else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;\n else this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+16).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength16(cb) {\n if (this._bufferedBytes < 2) {\n this._loop = false;\n return;\n }\n\n this._payloadLength = this.consume(2).readUInt16BE(0);\n this.haveLength(cb);\n }\n\n /**\n * Gets extended payload length (7+64).\n *\n * @param {Function} cb Callback\n * @private\n */\n getPayloadLength64(cb) {\n if (this._bufferedBytes < 8) {\n this._loop = false;\n return;\n }\n\n const buf = this.consume(8);\n const num = buf.readUInt32BE(0);\n\n //\n // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned\n // if payload length is greater than this number.\n //\n if (num > Math.pow(2, 53 - 32) - 1) {\n const error = this.createError(\n RangeError,\n 'Unsupported WebSocket frame: payload length > 2^53 - 1',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);\n this.haveLength(cb);\n }\n\n /**\n * Payload length has been read.\n *\n * @param {Function} cb Callback\n * @private\n */\n haveLength(cb) {\n if (this._payloadLength && this._opcode < 0x08) {\n this._totalPayloadLength += this._payloadLength;\n if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n }\n\n if (this._masked) this._state = GET_MASK;\n else this._state = GET_DATA;\n }\n\n /**\n * Reads mask bytes.\n *\n * @private\n */\n getMask() {\n if (this._bufferedBytes < 4) {\n this._loop = false;\n return;\n }\n\n this._mask = this.consume(4);\n this._state = GET_DATA;\n }\n\n /**\n * Reads data bytes.\n *\n * @param {Function} cb Callback\n * @private\n */\n getData(cb) {\n let data = EMPTY_BUFFER;\n\n if (this._payloadLength) {\n if (this._bufferedBytes < this._payloadLength) {\n this._loop = false;\n return;\n }\n\n data = this.consume(this._payloadLength);\n\n if (\n this._masked &&\n (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0\n ) {\n unmask(data, this._mask);\n }\n }\n\n if (this._opcode > 0x07) {\n this.controlMessage(data, cb);\n return;\n }\n\n if (this._compressed) {\n this._state = INFLATING;\n this.decompress(data, cb);\n return;\n }\n\n if (data.length) {\n //\n // This message is not compressed so its length is the sum of the payload\n // length of all fragments.\n //\n this._messageLength = this._totalPayloadLength;\n this._fragments.push(data);\n }\n\n this.dataMessage(cb);\n }\n\n /**\n * Decompresses data.\n *\n * @param {Buffer} data Compressed data\n * @param {Function} cb Callback\n * @private\n */\n decompress(data, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n perMessageDeflate.decompress(data, this._fin, (err, buf) => {\n if (err) return cb(err);\n\n if (buf.length) {\n this._messageLength += buf.length;\n if (this._messageLength > this._maxPayload && this._maxPayload > 0) {\n const error = this.createError(\n RangeError,\n 'Max payload size exceeded',\n false,\n 1009,\n 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'\n );\n\n cb(error);\n return;\n }\n\n this._fragments.push(buf);\n }\n\n this.dataMessage(cb);\n if (this._state === GET_INFO) this.startLoop(cb);\n });\n }\n\n /**\n * Handles a data message.\n *\n * @param {Function} cb Callback\n * @private\n */\n dataMessage(cb) {\n if (!this._fin) {\n this._state = GET_INFO;\n return;\n }\n\n const messageLength = this._messageLength;\n const fragments = this._fragments;\n\n this._totalPayloadLength = 0;\n this._messageLength = 0;\n this._fragmented = 0;\n this._fragments = [];\n\n if (this._opcode === 2) {\n let data;\n\n if (this._binaryType === 'nodebuffer') {\n data = concat(fragments, messageLength);\n } else if (this._binaryType === 'arraybuffer') {\n data = toArrayBuffer(concat(fragments, messageLength));\n } else if (this._binaryType === 'blob') {\n data = new Blob(fragments);\n } else {\n data = fragments;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit('message', data, true);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', data, true);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n } else {\n const buf = concat(fragments, messageLength);\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n if (this._state === INFLATING || this._allowSynchronousEvents) {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit('message', buf, false);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n }\n\n /**\n * Handles a control message.\n *\n * @param {Buffer} data Data to handle\n * @return {(Error|RangeError|undefined)} A possible error\n * @private\n */\n controlMessage(data, cb) {\n if (this._opcode === 0x08) {\n if (data.length === 0) {\n this._loop = false;\n this.emit('conclude', 1005, EMPTY_BUFFER);\n this.end();\n } else {\n const code = data.readUInt16BE(0);\n\n if (!isValidStatusCode(code)) {\n const error = this.createError(\n RangeError,\n `invalid status code ${code}`,\n true,\n 1002,\n 'WS_ERR_INVALID_CLOSE_CODE'\n );\n\n cb(error);\n return;\n }\n\n const buf = new FastBuffer(\n data.buffer,\n data.byteOffset + 2,\n data.length - 2\n );\n\n if (!this._skipUTF8Validation && !isValidUTF8(buf)) {\n const error = this.createError(\n Error,\n 'invalid UTF-8 sequence',\n true,\n 1007,\n 'WS_ERR_INVALID_UTF8'\n );\n\n cb(error);\n return;\n }\n\n this._loop = false;\n this.emit('conclude', code, buf);\n this.end();\n }\n\n this._state = GET_INFO;\n return;\n }\n\n if (this._allowSynchronousEvents) {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n } else {\n this._state = DEFER_EVENT;\n setImmediate(() => {\n this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data);\n this._state = GET_INFO;\n this.startLoop(cb);\n });\n }\n }\n\n /**\n * Builds an error object.\n *\n * @param {function(new:Error|RangeError)} ErrorCtor The error constructor\n * @param {String} message The error message\n * @param {Boolean} prefix Specifies whether or not to add a default prefix to\n * `message`\n * @param {Number} statusCode The status code\n * @param {String} errorCode The exposed error code\n * @return {(Error|RangeError)} The error\n * @private\n */\n createError(ErrorCtor, message, prefix, statusCode, errorCode) {\n this._loop = false;\n this._errored = true;\n\n const err = new ErrorCtor(\n prefix ? `Invalid WebSocket frame: ${message}` : message\n );\n\n Error.captureStackTrace(err, this.createError);\n err.code = errorCode;\n err[kStatusCode] = statusCode;\n return err;\n }\n}\n\nmodule.exports = Receiver;\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex\" }] */\n\n'use strict';\n\nconst { Duplex } = require('stream');\nconst { randomFillSync } = require('crypto');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst { EMPTY_BUFFER, kWebSocket, NOOP } = require('./constants');\nconst { isBlob, isValidStatusCode } = require('./validation');\nconst { mask: applyMask, toBuffer } = require('./buffer-util');\n\nconst kByteLength = Symbol('kByteLength');\nconst maskBuffer = Buffer.alloc(4);\nconst RANDOM_POOL_SIZE = 8 * 1024;\nlet randomPool;\nlet randomPoolPointer = RANDOM_POOL_SIZE;\n\nconst DEFAULT = 0;\nconst DEFLATING = 1;\nconst GET_BLOB_DATA = 2;\n\n/**\n * HyBi Sender implementation.\n */\nclass Sender {\n /**\n * Creates a Sender instance.\n *\n * @param {Duplex} socket The connection socket\n * @param {Object} [extensions] An object containing the negotiated extensions\n * @param {Function} [generateMask] The function used to generate the masking\n * key\n */\n constructor(socket, extensions, generateMask) {\n this._extensions = extensions || {};\n\n if (generateMask) {\n this._generateMask = generateMask;\n this._maskBuffer = Buffer.alloc(4);\n }\n\n this._socket = socket;\n\n this._firstFragment = true;\n this._compress = false;\n\n this._bufferedBytes = 0;\n this._queue = [];\n this._state = DEFAULT;\n this.onerror = NOOP;\n this[kWebSocket] = undefined;\n }\n\n /**\n * Frames a piece of data according to the HyBi WebSocket protocol.\n *\n * @param {(Buffer|String)} data The data to frame\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @return {(Buffer|String)[]} The framed data\n * @public\n */\n static frame(data, options) {\n let mask;\n let merge = false;\n let offset = 2;\n let skipMasking = false;\n\n if (options.mask) {\n mask = options.maskBuffer || maskBuffer;\n\n if (options.generateMask) {\n options.generateMask(mask);\n } else {\n if (randomPoolPointer === RANDOM_POOL_SIZE) {\n /* istanbul ignore else */\n if (randomPool === undefined) {\n //\n // This is lazily initialized because server-sent frames must not\n // be masked so it may never be used.\n //\n randomPool = Buffer.alloc(RANDOM_POOL_SIZE);\n }\n\n randomFillSync(randomPool, 0, RANDOM_POOL_SIZE);\n randomPoolPointer = 0;\n }\n\n mask[0] = randomPool[randomPoolPointer++];\n mask[1] = randomPool[randomPoolPointer++];\n mask[2] = randomPool[randomPoolPointer++];\n mask[3] = randomPool[randomPoolPointer++];\n }\n\n skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0;\n offset = 6;\n }\n\n let dataLength;\n\n if (typeof data === 'string') {\n if (\n (!options.mask || skipMasking) &&\n options[kByteLength] !== undefined\n ) {\n dataLength = options[kByteLength];\n } else {\n data = Buffer.from(data);\n dataLength = data.length;\n }\n } else {\n dataLength = data.length;\n merge = options.mask && options.readOnly && !skipMasking;\n }\n\n let payloadLength = dataLength;\n\n if (dataLength >= 65536) {\n offset += 8;\n payloadLength = 127;\n } else if (dataLength > 125) {\n offset += 2;\n payloadLength = 126;\n }\n\n const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset);\n\n target[0] = options.fin ? options.opcode | 0x80 : options.opcode;\n if (options.rsv1) target[0] |= 0x40;\n\n target[1] = payloadLength;\n\n if (payloadLength === 126) {\n target.writeUInt16BE(dataLength, 2);\n } else if (payloadLength === 127) {\n target[2] = target[3] = 0;\n target.writeUIntBE(dataLength, 4, 6);\n }\n\n if (!options.mask) return [target, data];\n\n target[1] |= 0x80;\n target[offset - 4] = mask[0];\n target[offset - 3] = mask[1];\n target[offset - 2] = mask[2];\n target[offset - 1] = mask[3];\n\n if (skipMasking) return [target, data];\n\n if (merge) {\n applyMask(data, mask, target, offset, dataLength);\n return [target];\n }\n\n applyMask(data, mask, data, 0, dataLength);\n return [target, data];\n }\n\n /**\n * Sends a close message to the other peer.\n *\n * @param {Number} [code] The status code component of the body\n * @param {(String|Buffer)} [data] The message component of the body\n * @param {Boolean} [mask=false] Specifies whether or not to mask the message\n * @param {Function} [cb] Callback\n * @public\n */\n close(code, data, mask, cb) {\n let buf;\n\n if (code === undefined) {\n buf = EMPTY_BUFFER;\n } else if (typeof code !== 'number' || !isValidStatusCode(code)) {\n throw new TypeError('First argument must be a valid error code number');\n } else if (data === undefined || !data.length) {\n buf = Buffer.allocUnsafe(2);\n buf.writeUInt16BE(code, 0);\n } else {\n const length = Buffer.byteLength(data);\n\n if (length > 123) {\n throw new RangeError('The message must not be greater than 123 bytes');\n }\n\n buf = Buffer.allocUnsafe(2 + length);\n buf.writeUInt16BE(code, 0);\n\n if (typeof data === 'string') {\n buf.write(data, 2);\n } else {\n buf.set(data, 2);\n }\n }\n\n const options = {\n [kByteLength]: buf.length,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x08,\n readOnly: false,\n rsv1: false\n };\n\n if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, buf, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(buf, options), cb);\n }\n }\n\n /**\n * Sends a ping message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n ping(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x09,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a pong message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Boolean} [mask=false] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback\n * @public\n */\n pong(data, mask, cb) {\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (byteLength > 125) {\n throw new RangeError('The data size must not be greater than 125 bytes');\n }\n\n const options = {\n [kByteLength]: byteLength,\n fin: true,\n generateMask: this._generateMask,\n mask,\n maskBuffer: this._maskBuffer,\n opcode: 0x0a,\n readOnly,\n rsv1: false\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, false, options, cb]);\n } else {\n this.getBlobData(data, false, options, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, false, options, cb]);\n } else {\n this.sendFrame(Sender.frame(data, options), cb);\n }\n }\n\n /**\n * Sends a data message to the other peer.\n *\n * @param {*} data The message to send\n * @param {Object} options Options object\n * @param {Boolean} [options.binary=false] Specifies whether `data` is binary\n * or text\n * @param {Boolean} [options.compress=false] Specifies whether or not to\n * compress `data`\n * @param {Boolean} [options.fin=false] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Function} [cb] Callback\n * @public\n */\n send(data, options, cb) {\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n let opcode = options.binary ? 2 : 1;\n let rsv1 = options.compress;\n\n let byteLength;\n let readOnly;\n\n if (typeof data === 'string') {\n byteLength = Buffer.byteLength(data);\n readOnly = false;\n } else if (isBlob(data)) {\n byteLength = data.size;\n readOnly = false;\n } else {\n data = toBuffer(data);\n byteLength = data.length;\n readOnly = toBuffer.readOnly;\n }\n\n if (this._firstFragment) {\n this._firstFragment = false;\n if (\n rsv1 &&\n perMessageDeflate &&\n perMessageDeflate.params[\n perMessageDeflate._isServer\n ? 'server_no_context_takeover'\n : 'client_no_context_takeover'\n ]\n ) {\n rsv1 = byteLength >= perMessageDeflate._threshold;\n }\n this._compress = rsv1;\n } else {\n rsv1 = false;\n opcode = 0;\n }\n\n if (options.fin) this._firstFragment = true;\n\n const opts = {\n [kByteLength]: byteLength,\n fin: options.fin,\n generateMask: this._generateMask,\n mask: options.mask,\n maskBuffer: this._maskBuffer,\n opcode,\n readOnly,\n rsv1\n };\n\n if (isBlob(data)) {\n if (this._state !== DEFAULT) {\n this.enqueue([this.getBlobData, data, this._compress, opts, cb]);\n } else {\n this.getBlobData(data, this._compress, opts, cb);\n }\n } else if (this._state !== DEFAULT) {\n this.enqueue([this.dispatch, data, this._compress, opts, cb]);\n } else {\n this.dispatch(data, this._compress, opts, cb);\n }\n }\n\n /**\n * Gets the contents of a blob as binary data.\n *\n * @param {Blob} blob The blob\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * the data\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n getBlobData(blob, compress, options, cb) {\n this._bufferedBytes += options[kByteLength];\n this._state = GET_BLOB_DATA;\n\n blob\n .arrayBuffer()\n .then((arrayBuffer) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while the blob was being read'\n );\n\n //\n // `callCallbacks` is called in the next tick to ensure that errors\n // that might be thrown in the callbacks behave like errors thrown\n // outside the promise chain.\n //\n process.nextTick(callCallbacks, this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n const data = toBuffer(arrayBuffer);\n\n if (!compress) {\n this._state = DEFAULT;\n this.sendFrame(Sender.frame(data, options), cb);\n this.dequeue();\n } else {\n this.dispatch(data, compress, options, cb);\n }\n })\n .catch((err) => {\n //\n // `onError` is called in the next tick for the same reason that\n // `callCallbacks` above is.\n //\n process.nextTick(onError, this, err, cb);\n });\n }\n\n /**\n * Dispatches a message.\n *\n * @param {(Buffer|String)} data The message to send\n * @param {Boolean} [compress=false] Specifies whether or not to compress\n * `data`\n * @param {Object} options Options object\n * @param {Boolean} [options.fin=false] Specifies whether or not to set the\n * FIN bit\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Boolean} [options.mask=false] Specifies whether or not to mask\n * `data`\n * @param {Buffer} [options.maskBuffer] The buffer used to store the masking\n * key\n * @param {Number} options.opcode The opcode\n * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be\n * modified\n * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the\n * RSV1 bit\n * @param {Function} [cb] Callback\n * @private\n */\n dispatch(data, compress, options, cb) {\n if (!compress) {\n this.sendFrame(Sender.frame(data, options), cb);\n return;\n }\n\n const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];\n\n this._bufferedBytes += options[kByteLength];\n this._state = DEFLATING;\n perMessageDeflate.compress(data, options.fin, (_, buf) => {\n if (this._socket.destroyed) {\n const err = new Error(\n 'The socket was closed while data was being compressed'\n );\n\n callCallbacks(this, err, cb);\n return;\n }\n\n this._bufferedBytes -= options[kByteLength];\n this._state = DEFAULT;\n options.readOnly = false;\n this.sendFrame(Sender.frame(buf, options), cb);\n this.dequeue();\n });\n }\n\n /**\n * Executes queued send operations.\n *\n * @private\n */\n dequeue() {\n while (this._state === DEFAULT && this._queue.length) {\n const params = this._queue.shift();\n\n this._bufferedBytes -= params[3][kByteLength];\n Reflect.apply(params[0], this, params.slice(1));\n }\n }\n\n /**\n * Enqueues a send operation.\n *\n * @param {Array} params Send operation parameters.\n * @private\n */\n enqueue(params) {\n this._bufferedBytes += params[3][kByteLength];\n this._queue.push(params);\n }\n\n /**\n * Sends a frame.\n *\n * @param {(Buffer | String)[]} list The frame to send\n * @param {Function} [cb] Callback\n * @private\n */\n sendFrame(list, cb) {\n if (list.length === 2) {\n this._socket.cork();\n this._socket.write(list[0]);\n this._socket.write(list[1], cb);\n this._socket.uncork();\n } else {\n this._socket.write(list[0], cb);\n }\n }\n}\n\nmodule.exports = Sender;\n\n/**\n * Calls queued callbacks with an error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error to call the callbacks with\n * @param {Function} [cb] The first callback\n * @private\n */\nfunction callCallbacks(sender, err, cb) {\n if (typeof cb === 'function') cb(err);\n\n for (let i = 0; i < sender._queue.length; i++) {\n const params = sender._queue[i];\n const callback = params[params.length - 1];\n\n if (typeof callback === 'function') callback(err);\n }\n}\n\n/**\n * Handles a `Sender` error.\n *\n * @param {Sender} sender The `Sender` instance\n * @param {Error} err The error\n * @param {Function} [cb] The first pending callback\n * @private\n */\nfunction onError(sender, err, cb) {\n callCallbacks(sender, err, cb);\n sender.onerror(err);\n}\n","'use strict';\n\nconst { kForOnEventAttribute, kListener } = require('./constants');\n\nconst kCode = Symbol('kCode');\nconst kData = Symbol('kData');\nconst kError = Symbol('kError');\nconst kMessage = Symbol('kMessage');\nconst kReason = Symbol('kReason');\nconst kTarget = Symbol('kTarget');\nconst kType = Symbol('kType');\nconst kWasClean = Symbol('kWasClean');\n\n/**\n * Class representing an event.\n */\nclass Event {\n /**\n * Create a new `Event`.\n *\n * @param {String} type The name of the event\n * @throws {TypeError} If the `type` argument is not specified\n */\n constructor(type) {\n this[kTarget] = null;\n this[kType] = type;\n }\n\n /**\n * @type {*}\n */\n get target() {\n return this[kTarget];\n }\n\n /**\n * @type {String}\n */\n get type() {\n return this[kType];\n }\n}\n\nObject.defineProperty(Event.prototype, 'target', { enumerable: true });\nObject.defineProperty(Event.prototype, 'type', { enumerable: true });\n\n/**\n * Class representing a close event.\n *\n * @extends Event\n */\nclass CloseEvent extends Event {\n /**\n * Create a new `CloseEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {Number} [options.code=0] The status code explaining why the\n * connection was closed\n * @param {String} [options.reason=''] A human-readable string explaining why\n * the connection was closed\n * @param {Boolean} [options.wasClean=false] Indicates whether or not the\n * connection was cleanly closed\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kCode] = options.code === undefined ? 0 : options.code;\n this[kReason] = options.reason === undefined ? '' : options.reason;\n this[kWasClean] = options.wasClean === undefined ? false : options.wasClean;\n }\n\n /**\n * @type {Number}\n */\n get code() {\n return this[kCode];\n }\n\n /**\n * @type {String}\n */\n get reason() {\n return this[kReason];\n }\n\n /**\n * @type {Boolean}\n */\n get wasClean() {\n return this[kWasClean];\n }\n}\n\nObject.defineProperty(CloseEvent.prototype, 'code', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true });\nObject.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true });\n\n/**\n * Class representing an error event.\n *\n * @extends Event\n */\nclass ErrorEvent extends Event {\n /**\n * Create a new `ErrorEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.error=null] The error that generated this event\n * @param {String} [options.message=''] The error message\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kError] = options.error === undefined ? null : options.error;\n this[kMessage] = options.message === undefined ? '' : options.message;\n }\n\n /**\n * @type {*}\n */\n get error() {\n return this[kError];\n }\n\n /**\n * @type {String}\n */\n get message() {\n return this[kMessage];\n }\n}\n\nObject.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true });\nObject.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true });\n\n/**\n * Class representing a message event.\n *\n * @extends Event\n */\nclass MessageEvent extends Event {\n /**\n * Create a new `MessageEvent`.\n *\n * @param {String} type The name of the event\n * @param {Object} [options] A dictionary object that allows for setting\n * attributes via object members of the same name\n * @param {*} [options.data=null] The message content\n */\n constructor(type, options = {}) {\n super(type);\n\n this[kData] = options.data === undefined ? null : options.data;\n }\n\n /**\n * @type {*}\n */\n get data() {\n return this[kData];\n }\n}\n\nObject.defineProperty(MessageEvent.prototype, 'data', { enumerable: true });\n\n/**\n * This provides methods for emulating the `EventTarget` interface. It's not\n * meant to be used directly.\n *\n * @mixin\n */\nconst EventTarget = {\n /**\n * Register an event listener.\n *\n * @param {String} type A string representing the event type to listen for\n * @param {(Function|Object)} handler The listener to add\n * @param {Object} [options] An options object specifies characteristics about\n * the event listener\n * @param {Boolean} [options.once=false] A `Boolean` indicating that the\n * listener should be invoked at most once after being added. If `true`,\n * the listener would be automatically removed when invoked.\n * @public\n */\n addEventListener(type, handler, options = {}) {\n for (const listener of this.listeners(type)) {\n if (\n !options[kForOnEventAttribute] &&\n listener[kListener] === handler &&\n !listener[kForOnEventAttribute]\n ) {\n return;\n }\n }\n\n let wrapper;\n\n if (type === 'message') {\n wrapper = function onMessage(data, isBinary) {\n const event = new MessageEvent('message', {\n data: isBinary ? data : data.toString()\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'close') {\n wrapper = function onClose(code, message) {\n const event = new CloseEvent('close', {\n code,\n reason: message.toString(),\n wasClean: this._closeFrameReceived && this._closeFrameSent\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'error') {\n wrapper = function onError(error) {\n const event = new ErrorEvent('error', {\n error,\n message: error.message\n });\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else if (type === 'open') {\n wrapper = function onOpen() {\n const event = new Event('open');\n\n event[kTarget] = this;\n callListener(handler, this, event);\n };\n } else {\n return;\n }\n\n wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute];\n wrapper[kListener] = handler;\n\n if (options.once) {\n this.once(type, wrapper);\n } else {\n this.on(type, wrapper);\n }\n },\n\n /**\n * Remove an event listener.\n *\n * @param {String} type A string representing the event type to remove\n * @param {(Function|Object)} handler The listener to remove\n * @public\n */\n removeEventListener(type, handler) {\n for (const listener of this.listeners(type)) {\n if (listener[kListener] === handler && !listener[kForOnEventAttribute]) {\n this.removeListener(type, listener);\n break;\n }\n }\n }\n};\n\nmodule.exports = {\n CloseEvent,\n ErrorEvent,\n Event,\n EventTarget,\n MessageEvent\n};\n\n/**\n * Call an event listener\n *\n * @param {(Function|Object)} listener The listener to call\n * @param {*} thisArg The value to use as `this`` when calling the listener\n * @param {Event} event The event to pass to the listener\n * @private\n */\nfunction callListener(listener, thisArg, event) {\n if (typeof listener === 'object' && listener.handleEvent) {\n listener.handleEvent.call(listener, event);\n } else {\n listener.call(thisArg, event);\n }\n}\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Adds an offer to the map of extension offers or a parameter to the map of\n * parameters.\n *\n * @param {Object} dest The map of extension offers or parameters\n * @param {String} name The extension or parameter name\n * @param {(Object|Boolean|String)} elem The extension parameters or the\n * parameter value\n * @private\n */\nfunction push(dest, name, elem) {\n if (dest[name] === undefined) dest[name] = [elem];\n else dest[name].push(elem);\n}\n\n/**\n * Parses the `Sec-WebSocket-Extensions` header into an object.\n *\n * @param {String} header The field value of the header\n * @return {Object} The parsed object\n * @public\n */\nfunction parse(header) {\n const offers = Object.create(null);\n let params = Object.create(null);\n let mustUnescape = false;\n let isEscaping = false;\n let inQuotes = false;\n let extensionName;\n let paramName;\n let start = -1;\n let code = -1;\n let end = -1;\n let i = 0;\n\n for (; i < header.length; i++) {\n code = header.charCodeAt(i);\n\n if (extensionName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n const name = header.slice(start, end);\n if (code === 0x2c) {\n push(offers, name, params);\n params = Object.create(null);\n } else {\n extensionName = name;\n }\n\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (paramName === undefined) {\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x20 || code === 0x09) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n push(params, header.slice(start, end), true);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n start = end = -1;\n } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {\n paramName = header.slice(start, i);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else {\n //\n // The value of a quoted-string after unescaping must conform to the\n // token ABNF, so only token characters are valid.\n // Ref: https://tools.ietf.org/html/rfc6455#section-9.1\n //\n if (isEscaping) {\n if (tokenChars[code] !== 1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n if (start === -1) start = i;\n else if (!mustUnescape) mustUnescape = true;\n isEscaping = false;\n } else if (inQuotes) {\n if (tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (code === 0x22 /* '\"' */ && start !== -1) {\n inQuotes = false;\n end = i;\n } else if (code === 0x5c /* '\\' */) {\n isEscaping = true;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {\n inQuotes = true;\n } else if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (start !== -1 && (code === 0x20 || code === 0x09)) {\n if (end === -1) end = i;\n } else if (code === 0x3b || code === 0x2c) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n let value = header.slice(start, end);\n if (mustUnescape) {\n value = value.replace(/\\\\/g, '');\n mustUnescape = false;\n }\n push(params, paramName, value);\n if (code === 0x2c) {\n push(offers, extensionName, params);\n params = Object.create(null);\n extensionName = undefined;\n }\n\n paramName = undefined;\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n }\n\n if (start === -1 || inQuotes || code === 0x20 || code === 0x09) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n if (end === -1) end = i;\n const token = header.slice(start, end);\n if (extensionName === undefined) {\n push(offers, token, params);\n } else {\n if (paramName === undefined) {\n push(params, token, true);\n } else if (mustUnescape) {\n push(params, paramName, token.replace(/\\\\/g, ''));\n } else {\n push(params, paramName, token);\n }\n push(offers, extensionName, params);\n }\n\n return offers;\n}\n\n/**\n * Builds the `Sec-WebSocket-Extensions` header field value.\n *\n * @param {Object} extensions The map of extensions and parameters to format\n * @return {String} A string representing the given object\n * @public\n */\nfunction format(extensions) {\n return Object.keys(extensions)\n .map((extension) => {\n let configurations = extensions[extension];\n if (!Array.isArray(configurations)) configurations = [configurations];\n return configurations\n .map((params) => {\n return [extension]\n .concat(\n Object.keys(params).map((k) => {\n let values = params[k];\n if (!Array.isArray(values)) values = [values];\n return values\n .map((v) => (v === true ? k : `${k}=${v}`))\n .join('; ');\n })\n )\n .join('; ');\n })\n .join(', ');\n })\n .join(', ');\n}\n\nmodule.exports = { format, parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex|Readable$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst https = require('https');\nconst http = require('http');\nconst net = require('net');\nconst tls = require('tls');\nconst { randomBytes, createHash } = require('crypto');\nconst { Duplex, Readable } = require('stream');\nconst { URL } = require('url');\n\nconst PerMessageDeflate = require('./permessage-deflate');\nconst Receiver = require('./receiver');\nconst Sender = require('./sender');\nconst { isBlob } = require('./validation');\n\nconst {\n BINARY_TYPES,\n CLOSE_TIMEOUT,\n EMPTY_BUFFER,\n GUID,\n kForOnEventAttribute,\n kListener,\n kStatusCode,\n kWebSocket,\n NOOP\n} = require('./constants');\nconst {\n EventTarget: { addEventListener, removeEventListener }\n} = require('./event-target');\nconst { format, parse } = require('./extension');\nconst { toBuffer } = require('./buffer-util');\n\nconst kAborted = Symbol('kAborted');\nconst protocolVersions = [8, 13];\nconst readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];\nconst subprotocolRegex = /^[!#$%&'*+\\-.0-9A-Z^_`|a-z~]+$/;\n\n/**\n * Class representing a WebSocket.\n *\n * @extends EventEmitter\n */\nclass WebSocket extends EventEmitter {\n /**\n * Create a new `WebSocket`.\n *\n * @param {(String|URL)} address The URL to which to connect\n * @param {(String|String[])} [protocols] The subprotocols\n * @param {Object} [options] Connection options\n */\n constructor(address, protocols, options) {\n super();\n\n this._binaryType = BINARY_TYPES[0];\n this._closeCode = 1006;\n this._closeFrameReceived = false;\n this._closeFrameSent = false;\n this._closeMessage = EMPTY_BUFFER;\n this._closeTimer = null;\n this._errorEmitted = false;\n this._extensions = {};\n this._paused = false;\n this._protocol = '';\n this._readyState = WebSocket.CONNECTING;\n this._receiver = null;\n this._sender = null;\n this._socket = null;\n\n if (address !== null) {\n this._bufferedAmount = 0;\n this._isServer = false;\n this._redirects = 0;\n\n if (protocols === undefined) {\n protocols = [];\n } else if (!Array.isArray(protocols)) {\n if (typeof protocols === 'object' && protocols !== null) {\n options = protocols;\n protocols = [];\n } else {\n protocols = [protocols];\n }\n }\n\n initAsClient(this, address, protocols, options);\n } else {\n this._autoPong = options.autoPong;\n this._closeTimeout = options.closeTimeout;\n this._isServer = true;\n }\n }\n\n /**\n * For historical reasons, the custom \"nodebuffer\" type is used by the default\n * instead of \"blob\".\n *\n * @type {String}\n */\n get binaryType() {\n return this._binaryType;\n }\n\n set binaryType(type) {\n if (!BINARY_TYPES.includes(type)) return;\n\n this._binaryType = type;\n\n //\n // Allow to change `binaryType` on the fly.\n //\n if (this._receiver) this._receiver._binaryType = type;\n }\n\n /**\n * @type {Number}\n */\n get bufferedAmount() {\n if (!this._socket) return this._bufferedAmount;\n\n return this._socket._writableState.length + this._sender._bufferedBytes;\n }\n\n /**\n * @type {String}\n */\n get extensions() {\n return Object.keys(this._extensions).join();\n }\n\n /**\n * @type {Boolean}\n */\n get isPaused() {\n return this._paused;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onclose() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onerror() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onopen() {\n return null;\n }\n\n /**\n * @type {Function}\n */\n /* istanbul ignore next */\n get onmessage() {\n return null;\n }\n\n /**\n * @type {String}\n */\n get protocol() {\n return this._protocol;\n }\n\n /**\n * @type {Number}\n */\n get readyState() {\n return this._readyState;\n }\n\n /**\n * @type {String}\n */\n get url() {\n return this._url;\n }\n\n /**\n * Set up the socket and the internal resources.\n *\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Object} options Options object\n * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.maxPayload=0] The maximum allowed message size\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\n setSocket(socket, head, options) {\n const receiver = new Receiver({\n allowSynchronousEvents: options.allowSynchronousEvents,\n binaryType: this.binaryType,\n extensions: this._extensions,\n isServer: this._isServer,\n maxPayload: options.maxPayload,\n skipUTF8Validation: options.skipUTF8Validation\n });\n\n const sender = new Sender(socket, this._extensions, options.generateMask);\n\n this._receiver = receiver;\n this._sender = sender;\n this._socket = socket;\n\n receiver[kWebSocket] = this;\n sender[kWebSocket] = this;\n socket[kWebSocket] = this;\n\n receiver.on('conclude', receiverOnConclude);\n receiver.on('drain', receiverOnDrain);\n receiver.on('error', receiverOnError);\n receiver.on('message', receiverOnMessage);\n receiver.on('ping', receiverOnPing);\n receiver.on('pong', receiverOnPong);\n\n sender.onerror = senderOnError;\n\n //\n // These methods may not be available if `socket` is just a `Duplex`.\n //\n if (socket.setTimeout) socket.setTimeout(0);\n if (socket.setNoDelay) socket.setNoDelay();\n\n if (head.length > 0) socket.unshift(head);\n\n socket.on('close', socketOnClose);\n socket.on('data', socketOnData);\n socket.on('end', socketOnEnd);\n socket.on('error', socketOnError);\n\n this._readyState = WebSocket.OPEN;\n this.emit('open');\n }\n\n /**\n * Emit the `'close'` event.\n *\n * @private\n */\n emitClose() {\n if (!this._socket) {\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n return;\n }\n\n if (this._extensions[PerMessageDeflate.extensionName]) {\n this._extensions[PerMessageDeflate.extensionName].cleanup();\n }\n\n this._receiver.removeAllListeners();\n this._readyState = WebSocket.CLOSED;\n this.emit('close', this._closeCode, this._closeMessage);\n }\n\n /**\n * Start a closing handshake.\n *\n * +----------+ +-----------+ +----------+\n * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -\n * | +----------+ +-----------+ +----------+ |\n * +----------+ +-----------+ |\n * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING\n * +----------+ +-----------+ |\n * | | | +---+ |\n * +------------------------+-->|fin| - - - -\n * | +---+ | +---+\n * - - - - -|fin|<---------------------+\n * +---+\n *\n * @param {Number} [code] Status code explaining why the connection is closing\n * @param {(String|Buffer)} [data] The reason why the connection is\n * closing\n * @public\n */\n close(code, data) {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this.readyState === WebSocket.CLOSING) {\n if (\n this._closeFrameSent &&\n (this._closeFrameReceived || this._receiver._writableState.errorEmitted)\n ) {\n this._socket.end();\n }\n\n return;\n }\n\n this._readyState = WebSocket.CLOSING;\n this._sender.close(code, data, !this._isServer, (err) => {\n //\n // This error is handled by the `'error'` listener on the socket. We only\n // want to know if the close frame has been sent here.\n //\n if (err) return;\n\n this._closeFrameSent = true;\n\n if (\n this._closeFrameReceived ||\n this._receiver._writableState.errorEmitted\n ) {\n this._socket.end();\n }\n });\n\n setCloseTimer(this);\n }\n\n /**\n * Pause the socket.\n *\n * @public\n */\n pause() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = true;\n this._socket.pause();\n }\n\n /**\n * Send a ping.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the ping is sent\n * @public\n */\n ping(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.ping(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Send a pong.\n *\n * @param {*} [data] The data to send\n * @param {Boolean} [mask] Indicates whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when the pong is sent\n * @public\n */\n pong(data, mask, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof data === 'function') {\n cb = data;\n data = mask = undefined;\n } else if (typeof mask === 'function') {\n cb = mask;\n mask = undefined;\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n if (mask === undefined) mask = !this._isServer;\n this._sender.pong(data || EMPTY_BUFFER, mask, cb);\n }\n\n /**\n * Resume the socket.\n *\n * @public\n */\n resume() {\n if (\n this.readyState === WebSocket.CONNECTING ||\n this.readyState === WebSocket.CLOSED\n ) {\n return;\n }\n\n this._paused = false;\n if (!this._receiver._writableState.needDrain) this._socket.resume();\n }\n\n /**\n * Send a data message.\n *\n * @param {*} data The message to send\n * @param {Object} [options] Options object\n * @param {Boolean} [options.binary] Specifies whether `data` is binary or\n * text\n * @param {Boolean} [options.compress] Specifies whether or not to compress\n * `data`\n * @param {Boolean} [options.fin=true] Specifies whether the fragment is the\n * last one\n * @param {Boolean} [options.mask] Specifies whether or not to mask `data`\n * @param {Function} [cb] Callback which is executed when data is written out\n * @public\n */\n send(data, options, cb) {\n if (this.readyState === WebSocket.CONNECTING) {\n throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n }\n\n if (typeof options === 'function') {\n cb = options;\n options = {};\n }\n\n if (typeof data === 'number') data = data.toString();\n\n if (this.readyState !== WebSocket.OPEN) {\n sendAfterClose(this, data, cb);\n return;\n }\n\n const opts = {\n binary: typeof data !== 'string',\n mask: !this._isServer,\n compress: true,\n fin: true,\n ...options\n };\n\n if (!this._extensions[PerMessageDeflate.extensionName]) {\n opts.compress = false;\n }\n\n this._sender.send(data || EMPTY_BUFFER, opts, cb);\n }\n\n /**\n * Forcibly close the connection.\n *\n * @public\n */\n terminate() {\n if (this.readyState === WebSocket.CLOSED) return;\n if (this.readyState === WebSocket.CONNECTING) {\n const msg = 'WebSocket was closed before the connection was established';\n abortHandshake(this, this._req, msg);\n return;\n }\n\n if (this._socket) {\n this._readyState = WebSocket.CLOSING;\n this._socket.destroy();\n }\n }\n}\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} CONNECTING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CONNECTING', {\n enumerable: true,\n value: readyStates.indexOf('CONNECTING')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} OPEN\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'OPEN', {\n enumerable: true,\n value: readyStates.indexOf('OPEN')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSING\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSING', {\n enumerable: true,\n value: readyStates.indexOf('CLOSING')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket\n */\nObject.defineProperty(WebSocket, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n/**\n * @constant {Number} CLOSED\n * @memberof WebSocket.prototype\n */\nObject.defineProperty(WebSocket.prototype, 'CLOSED', {\n enumerable: true,\n value: readyStates.indexOf('CLOSED')\n});\n\n[\n 'binaryType',\n 'bufferedAmount',\n 'extensions',\n 'isPaused',\n 'protocol',\n 'readyState',\n 'url'\n].forEach((property) => {\n Object.defineProperty(WebSocket.prototype, property, { enumerable: true });\n});\n\n//\n// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.\n// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface\n//\n['open', 'error', 'close', 'message'].forEach((method) => {\n Object.defineProperty(WebSocket.prototype, `on${method}`, {\n enumerable: true,\n get() {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) return listener[kListener];\n }\n\n return null;\n },\n set(handler) {\n for (const listener of this.listeners(method)) {\n if (listener[kForOnEventAttribute]) {\n this.removeListener(method, listener);\n break;\n }\n }\n\n if (typeof handler !== 'function') return;\n\n this.addEventListener(method, handler, {\n [kForOnEventAttribute]: true\n });\n }\n });\n});\n\nWebSocket.prototype.addEventListener = addEventListener;\nWebSocket.prototype.removeEventListener = removeEventListener;\n\nmodule.exports = WebSocket;\n\n/**\n * Initialize a WebSocket client.\n *\n * @param {WebSocket} websocket The client to initialize\n * @param {(String|URL)} address The URL to which to connect\n * @param {Array} protocols The subprotocols\n * @param {Object} [options] Connection options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether any\n * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple\n * times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait\n * for the closing handshake to finish after `websocket.close()` is called\n * @param {Function} [options.finishRequest] A function which can be used to\n * customize the headers of each http request before it is sent\n * @param {Boolean} [options.followRedirects=false] Whether or not to follow\n * redirects\n * @param {Function} [options.generateMask] The function used to generate the\n * masking key\n * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the\n * handshake request\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Number} [options.maxRedirects=10] The maximum number of redirects\n * allowed\n * @param {String} [options.origin] Value of the `Origin` or\n * `Sec-WebSocket-Origin` header\n * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable\n * permessage-deflate\n * @param {Number} [options.protocolVersion=13] Value of the\n * `Sec-WebSocket-Version` header\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @private\n */\nfunction initAsClient(websocket, address, protocols, options) {\n const opts = {\n allowSynchronousEvents: true,\n autoPong: true,\n closeTimeout: CLOSE_TIMEOUT,\n protocolVersion: protocolVersions[1],\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: true,\n followRedirects: false,\n maxRedirects: 10,\n ...options,\n socketPath: undefined,\n hostname: undefined,\n protocol: undefined,\n timeout: undefined,\n method: 'GET',\n host: undefined,\n path: undefined,\n port: undefined\n };\n\n websocket._autoPong = opts.autoPong;\n websocket._closeTimeout = opts.closeTimeout;\n\n if (!protocolVersions.includes(opts.protocolVersion)) {\n throw new RangeError(\n `Unsupported protocol version: ${opts.protocolVersion} ` +\n `(supported versions: ${protocolVersions.join(', ')})`\n );\n }\n\n let parsedUrl;\n\n if (address instanceof URL) {\n parsedUrl = address;\n } else {\n try {\n parsedUrl = new URL(address);\n } catch (e) {\n throw new SyntaxError(`Invalid URL: ${address}`);\n }\n }\n\n if (parsedUrl.protocol === 'http:') {\n parsedUrl.protocol = 'ws:';\n } else if (parsedUrl.protocol === 'https:') {\n parsedUrl.protocol = 'wss:';\n }\n\n websocket._url = parsedUrl.href;\n\n const isSecure = parsedUrl.protocol === 'wss:';\n const isIpcUrl = parsedUrl.protocol === 'ws+unix:';\n let invalidUrlMessage;\n\n if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {\n invalidUrlMessage =\n 'The URL\\'s protocol must be one of \"ws:\", \"wss:\", ' +\n '\"http:\", \"https:\", or \"ws+unix:\"';\n } else if (isIpcUrl && !parsedUrl.pathname) {\n invalidUrlMessage = \"The URL's pathname is empty\";\n } else if (parsedUrl.hash) {\n invalidUrlMessage = 'The URL contains a fragment identifier';\n }\n\n if (invalidUrlMessage) {\n const err = new SyntaxError(invalidUrlMessage);\n\n if (websocket._redirects === 0) {\n throw err;\n } else {\n emitErrorAndClose(websocket, err);\n return;\n }\n }\n\n const defaultPort = isSecure ? 443 : 80;\n const key = randomBytes(16).toString('base64');\n const request = isSecure ? https.request : http.request;\n const protocolSet = new Set();\n let perMessageDeflate;\n\n opts.createConnection =\n opts.createConnection || (isSecure ? tlsConnect : netConnect);\n opts.defaultPort = opts.defaultPort || defaultPort;\n opts.port = parsedUrl.port || defaultPort;\n opts.host = parsedUrl.hostname.startsWith('[')\n ? parsedUrl.hostname.slice(1, -1)\n : parsedUrl.hostname;\n opts.headers = {\n ...opts.headers,\n 'Sec-WebSocket-Version': opts.protocolVersion,\n 'Sec-WebSocket-Key': key,\n Connection: 'Upgrade',\n Upgrade: 'websocket'\n };\n opts.path = parsedUrl.pathname + parsedUrl.search;\n opts.timeout = opts.handshakeTimeout;\n\n if (opts.perMessageDeflate) {\n perMessageDeflate = new PerMessageDeflate(\n opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},\n false,\n opts.maxPayload\n );\n opts.headers['Sec-WebSocket-Extensions'] = format({\n [PerMessageDeflate.extensionName]: perMessageDeflate.offer()\n });\n }\n if (protocols.length) {\n for (const protocol of protocols) {\n if (\n typeof protocol !== 'string' ||\n !subprotocolRegex.test(protocol) ||\n protocolSet.has(protocol)\n ) {\n throw new SyntaxError(\n 'An invalid or duplicated subprotocol was specified'\n );\n }\n\n protocolSet.add(protocol);\n }\n\n opts.headers['Sec-WebSocket-Protocol'] = protocols.join(',');\n }\n if (opts.origin) {\n if (opts.protocolVersion < 13) {\n opts.headers['Sec-WebSocket-Origin'] = opts.origin;\n } else {\n opts.headers.Origin = opts.origin;\n }\n }\n if (parsedUrl.username || parsedUrl.password) {\n opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;\n }\n\n if (isIpcUrl) {\n const parts = opts.path.split(':');\n\n opts.socketPath = parts[0];\n opts.path = parts[1];\n }\n\n let req;\n\n if (opts.followRedirects) {\n if (websocket._redirects === 0) {\n websocket._originalIpc = isIpcUrl;\n websocket._originalSecure = isSecure;\n websocket._originalHostOrSocketPath = isIpcUrl\n ? opts.socketPath\n : parsedUrl.host;\n\n const headers = options && options.headers;\n\n //\n // Shallow copy the user provided options so that headers can be changed\n // without mutating the original object.\n //\n options = { ...options, headers: {} };\n\n if (headers) {\n for (const [key, value] of Object.entries(headers)) {\n options.headers[key.toLowerCase()] = value;\n }\n }\n } else if (websocket.listenerCount('redirect') === 0) {\n const isSameHost = isIpcUrl\n ? websocket._originalIpc\n ? opts.socketPath === websocket._originalHostOrSocketPath\n : false\n : websocket._originalIpc\n ? false\n : parsedUrl.host === websocket._originalHostOrSocketPath;\n\n if (!isSameHost || (websocket._originalSecure && !isSecure)) {\n //\n // Match curl 7.77.0 behavior and drop the following headers. These\n // headers are also dropped when following a redirect to a subdomain.\n //\n delete opts.headers.authorization;\n delete opts.headers.cookie;\n\n if (!isSameHost) delete opts.headers.host;\n\n opts.auth = undefined;\n }\n }\n\n //\n // Match curl 7.77.0 behavior and make the first `Authorization` header win.\n // If the `Authorization` header is set, then there is nothing to do as it\n // will take precedence.\n //\n if (opts.auth && !options.headers.authorization) {\n options.headers.authorization =\n 'Basic ' + Buffer.from(opts.auth).toString('base64');\n }\n\n req = websocket._req = request(opts);\n\n if (websocket._redirects) {\n //\n // Unlike what is done for the `'upgrade'` event, no early exit is\n // triggered here if the user calls `websocket.close()` or\n // `websocket.terminate()` from a listener of the `'redirect'` event. This\n // is because the user can also call `request.destroy()` with an error\n // before calling `websocket.close()` or `websocket.terminate()` and this\n // would result in an error being emitted on the `request` object with no\n // `'error'` event listeners attached.\n //\n websocket.emit('redirect', websocket.url, req);\n }\n } else {\n req = websocket._req = request(opts);\n }\n\n if (opts.timeout) {\n req.on('timeout', () => {\n abortHandshake(websocket, req, 'Opening handshake has timed out');\n });\n }\n\n req.on('error', (err) => {\n if (req === null || req[kAborted]) return;\n\n req = websocket._req = null;\n emitErrorAndClose(websocket, err);\n });\n\n req.on('response', (res) => {\n const location = res.headers.location;\n const statusCode = res.statusCode;\n\n if (\n location &&\n opts.followRedirects &&\n statusCode >= 300 &&\n statusCode < 400\n ) {\n if (++websocket._redirects > opts.maxRedirects) {\n abortHandshake(websocket, req, 'Maximum redirects exceeded');\n return;\n }\n\n req.abort();\n\n let addr;\n\n try {\n addr = new URL(location, address);\n } catch (e) {\n const err = new SyntaxError(`Invalid URL: ${location}`);\n emitErrorAndClose(websocket, err);\n return;\n }\n\n initAsClient(websocket, addr, protocols, options);\n } else if (!websocket.emit('unexpected-response', req, res)) {\n abortHandshake(\n websocket,\n req,\n `Unexpected server response: ${res.statusCode}`\n );\n }\n });\n\n req.on('upgrade', (res, socket, head) => {\n websocket.emit('upgrade', res);\n\n //\n // The user may have closed the connection from a listener of the\n // `'upgrade'` event.\n //\n if (websocket.readyState !== WebSocket.CONNECTING) return;\n\n req = websocket._req = null;\n\n const upgrade = res.headers.upgrade;\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n abortHandshake(websocket, socket, 'Invalid Upgrade header');\n return;\n }\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n if (res.headers['sec-websocket-accept'] !== digest) {\n abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header');\n return;\n }\n\n const serverProt = res.headers['sec-websocket-protocol'];\n let protError;\n\n if (serverProt !== undefined) {\n if (!protocolSet.size) {\n protError = 'Server sent a subprotocol but none was requested';\n } else if (!protocolSet.has(serverProt)) {\n protError = 'Server sent an invalid subprotocol';\n }\n } else if (protocolSet.size) {\n protError = 'Server sent no subprotocol';\n }\n\n if (protError) {\n abortHandshake(websocket, socket, protError);\n return;\n }\n\n if (serverProt) websocket._protocol = serverProt;\n\n const secWebSocketExtensions = res.headers['sec-websocket-extensions'];\n\n if (secWebSocketExtensions !== undefined) {\n if (!perMessageDeflate) {\n const message =\n 'Server sent a Sec-WebSocket-Extensions header but no extension ' +\n 'was requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n let extensions;\n\n try {\n extensions = parse(secWebSocketExtensions);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n const extensionNames = Object.keys(extensions);\n\n if (\n extensionNames.length !== 1 ||\n extensionNames[0] !== PerMessageDeflate.extensionName\n ) {\n const message = 'Server indicated an extension that was not requested';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n try {\n perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Extensions header';\n abortHandshake(websocket, socket, message);\n return;\n }\n\n websocket._extensions[PerMessageDeflate.extensionName] =\n perMessageDeflate;\n }\n\n websocket.setSocket(socket, head, {\n allowSynchronousEvents: opts.allowSynchronousEvents,\n generateMask: opts.generateMask,\n maxPayload: opts.maxPayload,\n skipUTF8Validation: opts.skipUTF8Validation\n });\n });\n\n if (opts.finishRequest) {\n opts.finishRequest(req, websocket);\n } else {\n req.end();\n }\n}\n\n/**\n * Emit the `'error'` and `'close'` events.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {Error} The error to emit\n * @private\n */\nfunction emitErrorAndClose(websocket, err) {\n websocket._readyState = WebSocket.CLOSING;\n //\n // The following assignment is practically useless and is done only for\n // consistency.\n //\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n websocket.emitClose();\n}\n\n/**\n * Create a `net.Socket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {net.Socket} The newly created socket used to start the connection\n * @private\n */\nfunction netConnect(options) {\n options.path = options.socketPath;\n return net.connect(options);\n}\n\n/**\n * Create a `tls.TLSSocket` and initiate a connection.\n *\n * @param {Object} options Connection options\n * @return {tls.TLSSocket} The newly created socket used to start the connection\n * @private\n */\nfunction tlsConnect(options) {\n options.path = undefined;\n\n if (!options.servername && options.servername !== '') {\n options.servername = net.isIP(options.host) ? '' : options.host;\n }\n\n return tls.connect(options);\n}\n\n/**\n * Abort the handshake and emit an error.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to\n * abort or the socket to destroy\n * @param {String} message The error message\n * @private\n */\nfunction abortHandshake(websocket, stream, message) {\n websocket._readyState = WebSocket.CLOSING;\n\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshake);\n\n if (stream.setHeader) {\n stream[kAborted] = true;\n stream.abort();\n\n if (stream.socket && !stream.socket.destroyed) {\n //\n // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if\n // called after the request completed. See\n // https://github.com/websockets/ws/issues/1869.\n //\n stream.socket.destroy();\n }\n\n process.nextTick(emitErrorAndClose, websocket, err);\n } else {\n stream.destroy(err);\n stream.once('error', websocket.emit.bind(websocket, 'error'));\n stream.once('close', websocket.emitClose.bind(websocket));\n }\n}\n\n/**\n * Handle cases where the `ping()`, `pong()`, or `send()` methods are called\n * when the `readyState` attribute is `CLOSING` or `CLOSED`.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @param {*} [data] The data to send\n * @param {Function} [cb] Callback\n * @private\n */\nfunction sendAfterClose(websocket, data, cb) {\n if (data) {\n const length = isBlob(data) ? data.size : toBuffer(data).length;\n\n //\n // The `_bufferedAmount` property is used only when the peer is a client and\n // the opening handshake fails. Under these circumstances, in fact, the\n // `setSocket()` method is not called, so the `_socket` and `_sender`\n // properties are set to `null`.\n //\n if (websocket._socket) websocket._sender._bufferedBytes += length;\n else websocket._bufferedAmount += length;\n }\n\n if (cb) {\n const err = new Error(\n `WebSocket is not open: readyState ${websocket.readyState} ` +\n `(${readyStates[websocket.readyState]})`\n );\n process.nextTick(cb, err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'conclude'` event.\n *\n * @param {Number} code The status code\n * @param {Buffer} reason The reason for closing\n * @private\n */\nfunction receiverOnConclude(code, reason) {\n const websocket = this[kWebSocket];\n\n websocket._closeFrameReceived = true;\n websocket._closeMessage = reason;\n websocket._closeCode = code;\n\n if (websocket._socket[kWebSocket] === undefined) return;\n\n websocket._socket.removeListener('data', socketOnData);\n process.nextTick(resume, websocket._socket);\n\n if (code === 1005) websocket.close();\n else websocket.close(code, reason);\n}\n\n/**\n * The listener of the `Receiver` `'drain'` event.\n *\n * @private\n */\nfunction receiverOnDrain() {\n const websocket = this[kWebSocket];\n\n if (!websocket.isPaused) websocket._socket.resume();\n}\n\n/**\n * The listener of the `Receiver` `'error'` event.\n *\n * @param {(RangeError|Error)} err The emitted error\n * @private\n */\nfunction receiverOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket._socket[kWebSocket] !== undefined) {\n websocket._socket.removeListener('data', socketOnData);\n\n //\n // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See\n // https://github.com/websockets/ws/issues/1940.\n //\n process.nextTick(resume, websocket._socket);\n\n websocket.close(err[kStatusCode]);\n }\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * The listener of the `Receiver` `'finish'` event.\n *\n * @private\n */\nfunction receiverOnFinish() {\n this[kWebSocket].emitClose();\n}\n\n/**\n * The listener of the `Receiver` `'message'` event.\n *\n * @param {Buffer|ArrayBuffer|Buffer[])} data The message\n * @param {Boolean} isBinary Specifies whether the message is binary or not\n * @private\n */\nfunction receiverOnMessage(data, isBinary) {\n this[kWebSocket].emit('message', data, isBinary);\n}\n\n/**\n * The listener of the `Receiver` `'ping'` event.\n *\n * @param {Buffer} data The data included in the ping frame\n * @private\n */\nfunction receiverOnPing(data) {\n const websocket = this[kWebSocket];\n\n if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP);\n websocket.emit('ping', data);\n}\n\n/**\n * The listener of the `Receiver` `'pong'` event.\n *\n * @param {Buffer} data The data included in the pong frame\n * @private\n */\nfunction receiverOnPong(data) {\n this[kWebSocket].emit('pong', data);\n}\n\n/**\n * Resume a readable stream\n *\n * @param {Readable} stream The readable stream\n * @private\n */\nfunction resume(stream) {\n stream.resume();\n}\n\n/**\n * The `Sender` error event handler.\n *\n * @param {Error} The error\n * @private\n */\nfunction senderOnError(err) {\n const websocket = this[kWebSocket];\n\n if (websocket.readyState === WebSocket.CLOSED) return;\n if (websocket.readyState === WebSocket.OPEN) {\n websocket._readyState = WebSocket.CLOSING;\n setCloseTimer(websocket);\n }\n\n //\n // `socket.end()` is used instead of `socket.destroy()` to allow the other\n // peer to finish sending queued data. There is no need to set a timer here\n // because `CLOSING` means that it is already set or not needed.\n //\n this._socket.end();\n\n if (!websocket._errorEmitted) {\n websocket._errorEmitted = true;\n websocket.emit('error', err);\n }\n}\n\n/**\n * Set a timer to destroy the underlying raw socket of a WebSocket.\n *\n * @param {WebSocket} websocket The WebSocket instance\n * @private\n */\nfunction setCloseTimer(websocket) {\n websocket._closeTimer = setTimeout(\n websocket._socket.destroy.bind(websocket._socket),\n websocket._closeTimeout\n );\n}\n\n/**\n * The listener of the socket `'close'` event.\n *\n * @private\n */\nfunction socketOnClose() {\n const websocket = this[kWebSocket];\n\n this.removeListener('close', socketOnClose);\n this.removeListener('data', socketOnData);\n this.removeListener('end', socketOnEnd);\n\n websocket._readyState = WebSocket.CLOSING;\n\n //\n // The close frame might not have been received or the `'end'` event emitted,\n // for example, if the socket was destroyed due to an error. Ensure that the\n // `receiver` stream is closed after writing any remaining buffered data to\n // it. If the readable side of the socket is in flowing mode then there is no\n // buffered data as everything has been already written. If instead, the\n // socket is paused, any possible buffered data will be read as a single\n // chunk.\n //\n if (\n !this._readableState.endEmitted &&\n !websocket._closeFrameReceived &&\n !websocket._receiver._writableState.errorEmitted &&\n this._readableState.length !== 0\n ) {\n const chunk = this.read(this._readableState.length);\n\n websocket._receiver.write(chunk);\n }\n\n websocket._receiver.end();\n\n this[kWebSocket] = undefined;\n\n clearTimeout(websocket._closeTimer);\n\n if (\n websocket._receiver._writableState.finished ||\n websocket._receiver._writableState.errorEmitted\n ) {\n websocket.emitClose();\n } else {\n websocket._receiver.on('error', receiverOnFinish);\n websocket._receiver.on('finish', receiverOnFinish);\n }\n}\n\n/**\n * The listener of the socket `'data'` event.\n *\n * @param {Buffer} chunk A chunk of data\n * @private\n */\nfunction socketOnData(chunk) {\n if (!this[kWebSocket]._receiver.write(chunk)) {\n this.pause();\n }\n}\n\n/**\n * The listener of the socket `'end'` event.\n *\n * @private\n */\nfunction socketOnEnd() {\n const websocket = this[kWebSocket];\n\n websocket._readyState = WebSocket.CLOSING;\n websocket._receiver.end();\n this.end();\n}\n\n/**\n * The listener of the socket `'error'` event.\n *\n * @private\n */\nfunction socketOnError() {\n const websocket = this[kWebSocket];\n\n this.removeListener('error', socketOnError);\n this.on('error', NOOP);\n\n if (websocket) {\n websocket._readyState = WebSocket.CLOSING;\n this.destroy();\n }\n}\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^WebSocket$\" }] */\n'use strict';\n\nconst WebSocket = require('./websocket');\nconst { Duplex } = require('stream');\n\n/**\n * Emits the `'close'` event on a stream.\n *\n * @param {Duplex} stream The stream.\n * @private\n */\nfunction emitClose(stream) {\n stream.emit('close');\n}\n\n/**\n * The listener of the `'end'` event.\n *\n * @private\n */\nfunction duplexOnEnd() {\n if (!this.destroyed && this._writableState.finished) {\n this.destroy();\n }\n}\n\n/**\n * The listener of the `'error'` event.\n *\n * @param {Error} err The error\n * @private\n */\nfunction duplexOnError(err) {\n this.removeListener('error', duplexOnError);\n this.destroy();\n if (this.listenerCount('error') === 0) {\n // Do not suppress the throwing behavior.\n this.emit('error', err);\n }\n}\n\n/**\n * Wraps a `WebSocket` in a duplex stream.\n *\n * @param {WebSocket} ws The `WebSocket` to wrap\n * @param {Object} [options] The options for the `Duplex` constructor\n * @return {Duplex} The duplex stream\n * @public\n */\nfunction createWebSocketStream(ws, options) {\n let terminateOnDestroy = true;\n\n const duplex = new Duplex({\n ...options,\n autoDestroy: false,\n emitClose: false,\n objectMode: false,\n writableObjectMode: false\n });\n\n ws.on('message', function message(msg, isBinary) {\n const data =\n !isBinary && duplex._readableState.objectMode ? msg.toString() : msg;\n\n if (!duplex.push(data)) ws.pause();\n });\n\n ws.once('error', function error(err) {\n if (duplex.destroyed) return;\n\n // Prevent `ws.terminate()` from being called by `duplex._destroy()`.\n //\n // - If the `'error'` event is emitted before the `'open'` event, then\n // `ws.terminate()` is a noop as no socket is assigned.\n // - Otherwise, the error is re-emitted by the listener of the `'error'`\n // event of the `Receiver` object. The listener already closes the\n // connection by calling `ws.close()`. This allows a close frame to be\n // sent to the other peer. If `ws.terminate()` is called right after this,\n // then the close frame might not be sent.\n terminateOnDestroy = false;\n duplex.destroy(err);\n });\n\n ws.once('close', function close() {\n if (duplex.destroyed) return;\n\n duplex.push(null);\n });\n\n duplex._destroy = function (err, callback) {\n if (ws.readyState === ws.CLOSED) {\n callback(err);\n process.nextTick(emitClose, duplex);\n return;\n }\n\n let called = false;\n\n ws.once('error', function error(err) {\n called = true;\n callback(err);\n });\n\n ws.once('close', function close() {\n if (!called) callback(err);\n process.nextTick(emitClose, duplex);\n });\n\n if (terminateOnDestroy) ws.terminate();\n };\n\n duplex._final = function (callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._final(callback);\n });\n return;\n }\n\n // If the value of the `_socket` property is `null` it means that `ws` is a\n // client websocket and the handshake failed. In fact, when this happens, a\n // socket is never assigned to the websocket. Wait for the `'error'` event\n // that will be emitted by the websocket.\n if (ws._socket === null) return;\n\n if (ws._socket._writableState.finished) {\n callback();\n if (duplex._readableState.endEmitted) duplex.destroy();\n } else {\n ws._socket.once('finish', function finish() {\n // `duplex` is not destroyed here because the `'end'` event will be\n // emitted on `duplex` after this `'finish'` event. The EOF signaling\n // `null` chunk is, in fact, pushed when the websocket emits `'close'`.\n callback();\n });\n ws.close();\n }\n };\n\n duplex._read = function () {\n if (ws.isPaused) ws.resume();\n };\n\n duplex._write = function (chunk, encoding, callback) {\n if (ws.readyState === ws.CONNECTING) {\n ws.once('open', function open() {\n duplex._write(chunk, encoding, callback);\n });\n return;\n }\n\n ws.send(chunk, callback);\n };\n\n duplex.on('end', duplexOnEnd);\n duplex.on('error', duplexOnError);\n return duplex;\n}\n\nmodule.exports = createWebSocketStream;\n","'use strict';\n\nconst { tokenChars } = require('./validation');\n\n/**\n * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names.\n *\n * @param {String} header The field value of the header\n * @return {Set} The subprotocol names\n * @public\n */\nfunction parse(header) {\n const protocols = new Set();\n let start = -1;\n let end = -1;\n let i = 0;\n\n for (i; i < header.length; i++) {\n const code = header.charCodeAt(i);\n\n if (end === -1 && tokenChars[code] === 1) {\n if (start === -1) start = i;\n } else if (\n i !== 0 &&\n (code === 0x20 /* ' ' */ || code === 0x09) /* '\\t' */\n ) {\n if (end === -1 && start !== -1) end = i;\n } else if (code === 0x2c /* ',' */) {\n if (start === -1) {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n\n if (end === -1) end = i;\n\n const protocol = header.slice(start, end);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n start = end = -1;\n } else {\n throw new SyntaxError(`Unexpected character at index ${i}`);\n }\n }\n\n if (start === -1 || end !== -1) {\n throw new SyntaxError('Unexpected end of input');\n }\n\n const protocol = header.slice(start, i);\n\n if (protocols.has(protocol)) {\n throw new SyntaxError(`The \"${protocol}\" subprotocol is duplicated`);\n }\n\n protocols.add(protocol);\n return protocols;\n}\n\nmodule.exports = { parse };\n","/* eslint no-unused-vars: [\"error\", { \"varsIgnorePattern\": \"^Duplex$\", \"caughtErrors\": \"none\" }] */\n\n'use strict';\n\nconst EventEmitter = require('events');\nconst http = require('http');\nconst { Duplex } = require('stream');\nconst { createHash } = require('crypto');\n\nconst extension = require('./extension');\nconst PerMessageDeflate = require('./permessage-deflate');\nconst subprotocol = require('./subprotocol');\nconst WebSocket = require('./websocket');\nconst { CLOSE_TIMEOUT, GUID, kWebSocket } = require('./constants');\n\nconst keyRegex = /^[+/0-9A-Za-z]{22}==$/;\n\nconst RUNNING = 0;\nconst CLOSING = 1;\nconst CLOSED = 2;\n\n/**\n * Class representing a WebSocket server.\n *\n * @extends EventEmitter\n */\nclass WebSocketServer extends EventEmitter {\n /**\n * Create a `WebSocketServer` instance.\n *\n * @param {Object} options Configuration options\n * @param {Boolean} [options.allowSynchronousEvents=true] Specifies whether\n * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted\n * multiple times in the same tick\n * @param {Boolean} [options.autoPong=true] Specifies whether or not to\n * automatically send a pong in response to a ping\n * @param {Number} [options.backlog=511] The maximum length of the queue of\n * pending connections\n * @param {Boolean} [options.clientTracking=true] Specifies whether or not to\n * track clients\n * @param {Number} [options.closeTimeout=30000] Duration in milliseconds to\n * wait for the closing handshake to finish after `websocket.close()` is\n * called\n * @param {Function} [options.handleProtocols] A hook to handle protocols\n * @param {String} [options.host] The hostname where to bind the server\n * @param {Number} [options.maxPayload=104857600] The maximum allowed message\n * size\n * @param {Boolean} [options.noServer=false] Enable no server mode\n * @param {String} [options.path] Accept only connections matching this path\n * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable\n * permessage-deflate\n * @param {Number} [options.port] The port where to bind the server\n * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S\n * server to use\n * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or\n * not to skip UTF-8 validation for text and close messages\n * @param {Function} [options.verifyClient] A hook to reject connections\n * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket`\n * class to use. It must be the `WebSocket` class or class that extends it\n * @param {Function} [callback] A listener for the `listening` event\n */\n constructor(options, callback) {\n super();\n\n options = {\n allowSynchronousEvents: true,\n autoPong: true,\n maxPayload: 100 * 1024 * 1024,\n skipUTF8Validation: false,\n perMessageDeflate: false,\n handleProtocols: null,\n clientTracking: true,\n closeTimeout: CLOSE_TIMEOUT,\n verifyClient: null,\n noServer: false,\n backlog: null, // use default (511 as implemented in net.js)\n server: null,\n host: null,\n path: null,\n port: null,\n WebSocket,\n ...options\n };\n\n if (\n (options.port == null && !options.server && !options.noServer) ||\n (options.port != null && (options.server || options.noServer)) ||\n (options.server && options.noServer)\n ) {\n throw new TypeError(\n 'One and only one of the \"port\", \"server\", or \"noServer\" options ' +\n 'must be specified'\n );\n }\n\n if (options.port != null) {\n this._server = http.createServer((req, res) => {\n const body = http.STATUS_CODES[426];\n\n res.writeHead(426, {\n 'Content-Length': body.length,\n 'Content-Type': 'text/plain'\n });\n res.end(body);\n });\n this._server.listen(\n options.port,\n options.host,\n options.backlog,\n callback\n );\n } else if (options.server) {\n this._server = options.server;\n }\n\n if (this._server) {\n const emitConnection = this.emit.bind(this, 'connection');\n\n this._removeListeners = addListeners(this._server, {\n listening: this.emit.bind(this, 'listening'),\n error: this.emit.bind(this, 'error'),\n upgrade: (req, socket, head) => {\n this.handleUpgrade(req, socket, head, emitConnection);\n }\n });\n }\n\n if (options.perMessageDeflate === true) options.perMessageDeflate = {};\n if (options.clientTracking) {\n this.clients = new Set();\n this._shouldEmitClose = false;\n }\n\n this.options = options;\n this._state = RUNNING;\n }\n\n /**\n * Returns the bound address, the address family name, and port of the server\n * as reported by the operating system if listening on an IP socket.\n * If the server is listening on a pipe or UNIX domain socket, the name is\n * returned as a string.\n *\n * @return {(Object|String|null)} The address of the server\n * @public\n */\n address() {\n if (this.options.noServer) {\n throw new Error('The server is operating in \"noServer\" mode');\n }\n\n if (!this._server) return null;\n return this._server.address();\n }\n\n /**\n * Stop the server from accepting new connections and emit the `'close'` event\n * when all existing connections are closed.\n *\n * @param {Function} [cb] A one-time listener for the `'close'` event\n * @public\n */\n close(cb) {\n if (this._state === CLOSED) {\n if (cb) {\n this.once('close', () => {\n cb(new Error('The server is not running'));\n });\n }\n\n process.nextTick(emitClose, this);\n return;\n }\n\n if (cb) this.once('close', cb);\n\n if (this._state === CLOSING) return;\n this._state = CLOSING;\n\n if (this.options.noServer || this.options.server) {\n if (this._server) {\n this._removeListeners();\n this._removeListeners = this._server = null;\n }\n\n if (this.clients) {\n if (!this.clients.size) {\n process.nextTick(emitClose, this);\n } else {\n this._shouldEmitClose = true;\n }\n } else {\n process.nextTick(emitClose, this);\n }\n } else {\n const server = this._server;\n\n this._removeListeners();\n this._removeListeners = this._server = null;\n\n //\n // The HTTP/S server was created internally. Close it, and rely on its\n // `'close'` event.\n //\n server.close(() => {\n emitClose(this);\n });\n }\n }\n\n /**\n * See if a given request should be handled by this server instance.\n *\n * @param {http.IncomingMessage} req Request object to inspect\n * @return {Boolean} `true` if the request is valid, else `false`\n * @public\n */\n shouldHandle(req) {\n if (this.options.path) {\n const index = req.url.indexOf('?');\n const pathname = index !== -1 ? req.url.slice(0, index) : req.url;\n\n if (pathname !== this.options.path) return false;\n }\n\n return true;\n }\n\n /**\n * Handle a HTTP Upgrade request.\n *\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @public\n */\n handleUpgrade(req, socket, head, cb) {\n socket.on('error', socketOnError);\n\n const key = req.headers['sec-websocket-key'];\n const upgrade = req.headers.upgrade;\n const version = +req.headers['sec-websocket-version'];\n\n if (req.method !== 'GET') {\n const message = 'Invalid HTTP method';\n abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);\n return;\n }\n\n if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {\n const message = 'Invalid Upgrade header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (key === undefined || !keyRegex.test(key)) {\n const message = 'Missing or invalid Sec-WebSocket-Key header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n\n if (version !== 13 && version !== 8) {\n const message = 'Missing or invalid Sec-WebSocket-Version header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message, {\n 'Sec-WebSocket-Version': '13, 8'\n });\n return;\n }\n\n if (!this.shouldHandle(req)) {\n abortHandshake(socket, 400);\n return;\n }\n\n const secWebSocketProtocol = req.headers['sec-websocket-protocol'];\n let protocols = new Set();\n\n if (secWebSocketProtocol !== undefined) {\n try {\n protocols = subprotocol.parse(secWebSocketProtocol);\n } catch (err) {\n const message = 'Invalid Sec-WebSocket-Protocol header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n const secWebSocketExtensions = req.headers['sec-websocket-extensions'];\n const extensions = {};\n\n if (\n this.options.perMessageDeflate &&\n secWebSocketExtensions !== undefined\n ) {\n const perMessageDeflate = new PerMessageDeflate(\n this.options.perMessageDeflate,\n true,\n this.options.maxPayload\n );\n\n try {\n const offers = extension.parse(secWebSocketExtensions);\n\n if (offers[PerMessageDeflate.extensionName]) {\n perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);\n extensions[PerMessageDeflate.extensionName] = perMessageDeflate;\n }\n } catch (err) {\n const message =\n 'Invalid or unacceptable Sec-WebSocket-Extensions header';\n abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);\n return;\n }\n }\n\n //\n // Optionally call external client verification handler.\n //\n if (this.options.verifyClient) {\n const info = {\n origin:\n req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],\n secure: !!(req.socket.authorized || req.socket.encrypted),\n req\n };\n\n if (this.options.verifyClient.length === 2) {\n this.options.verifyClient(info, (verified, code, message, headers) => {\n if (!verified) {\n return abortHandshake(socket, code || 401, message, headers);\n }\n\n this.completeUpgrade(\n extensions,\n key,\n protocols,\n req,\n socket,\n head,\n cb\n );\n });\n return;\n }\n\n if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);\n }\n\n this.completeUpgrade(extensions, key, protocols, req, socket, head, cb);\n }\n\n /**\n * Upgrade the connection to WebSocket.\n *\n * @param {Object} extensions The accepted extensions\n * @param {String} key The value of the `Sec-WebSocket-Key` header\n * @param {Set} protocols The subprotocols\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The network socket between the server and client\n * @param {Buffer} head The first packet of the upgraded stream\n * @param {Function} cb Callback\n * @throws {Error} If called more than once with the same socket\n * @private\n */\n completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n //\n // Destroy the socket if the client has already sent a FIN packet.\n //\n if (!socket.readable || !socket.writable) return socket.destroy();\n\n if (socket[kWebSocket]) {\n throw new Error(\n 'server.handleUpgrade() was called more than once with the same ' +\n 'socket, possibly due to a misconfiguration'\n );\n }\n\n if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n const digest = createHash('sha1')\n .update(key + GUID)\n .digest('base64');\n\n const headers = [\n 'HTTP/1.1 101 Switching Protocols',\n 'Upgrade: websocket',\n 'Connection: Upgrade',\n `Sec-WebSocket-Accept: ${digest}`\n ];\n\n const ws = new this.options.WebSocket(null, undefined, this.options);\n\n if (protocols.size) {\n //\n // Optionally call external protocol selection handler.\n //\n const protocol = this.options.handleProtocols\n ? this.options.handleProtocols(protocols, req)\n : protocols.values().next().value;\n\n if (protocol) {\n headers.push(`Sec-WebSocket-Protocol: ${protocol}`);\n ws._protocol = protocol;\n }\n }\n\n if (extensions[PerMessageDeflate.extensionName]) {\n const params = extensions[PerMessageDeflate.extensionName].params;\n const value = extension.format({\n [PerMessageDeflate.extensionName]: [params]\n });\n headers.push(`Sec-WebSocket-Extensions: ${value}`);\n ws._extensions = extensions;\n }\n\n //\n // Allow external modification/inspection of handshake headers.\n //\n this.emit('headers', headers, req);\n\n socket.write(headers.concat('\\r\\n').join('\\r\\n'));\n socket.removeListener('error', socketOnError);\n\n ws.setSocket(socket, head, {\n allowSynchronousEvents: this.options.allowSynchronousEvents,\n maxPayload: this.options.maxPayload,\n skipUTF8Validation: this.options.skipUTF8Validation\n });\n\n if (this.clients) {\n this.clients.add(ws);\n ws.on('close', () => {\n this.clients.delete(ws);\n\n if (this._shouldEmitClose && !this.clients.size) {\n process.nextTick(emitClose, this);\n }\n });\n }\n\n cb(ws, req);\n }\n}\n\nmodule.exports = WebSocketServer;\n\n/**\n * Add event listeners on an `EventEmitter` using a map of <event, listener>\n * pairs.\n *\n * @param {EventEmitter} server The event emitter\n * @param {Object.<String, Function>} map The listeners to add\n * @return {Function} A function that will remove the added listeners when\n * called\n * @private\n */\nfunction addListeners(server, map) {\n for (const event of Object.keys(map)) server.on(event, map[event]);\n\n return function removeListeners() {\n for (const event of Object.keys(map)) {\n server.removeListener(event, map[event]);\n }\n };\n}\n\n/**\n * Emit a `'close'` event on an `EventEmitter`.\n *\n * @param {EventEmitter} server The event emitter\n * @private\n */\nfunction emitClose(server) {\n server._state = CLOSED;\n server.emit('close');\n}\n\n/**\n * Handle socket errors.\n *\n * @private\n */\nfunction socketOnError() {\n this.destroy();\n}\n\n/**\n * Close the connection when preconditions are not fulfilled.\n *\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} [message] The HTTP response body\n * @param {Object} [headers] Additional HTTP response headers\n * @private\n */\nfunction abortHandshake(socket, code, message, headers) {\n //\n // The socket is writable unless the user destroyed or ended it before calling\n // `server.handleUpgrade()` or in the `verifyClient` function, which is a user\n // error. Handling this does not make much sense as the worst that can happen\n // is that some of the data written by the user might be discarded due to the\n // call to `socket.end()` below, which triggers an `'error'` event that in\n // turn causes the socket to be destroyed.\n //\n message = message || http.STATUS_CODES[code];\n headers = {\n Connection: 'close',\n 'Content-Type': 'text/html',\n 'Content-Length': Buffer.byteLength(message),\n ...headers\n };\n\n socket.once('finish', socket.destroy);\n\n socket.end(\n `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\\r\\n` +\n Object.keys(headers)\n .map((h) => `${h}: ${headers[h]}`)\n .join('\\r\\n') +\n '\\r\\n\\r\\n' +\n message\n );\n}\n\n/**\n * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least\n * one listener for it, otherwise call `abortHandshake()`.\n *\n * @param {WebSocketServer} server The WebSocket server\n * @param {http.IncomingMessage} req The request object\n * @param {Duplex} socket The socket of the upgrade request\n * @param {Number} code The HTTP response status code\n * @param {String} message The HTTP response body\n * @param {Object} [headers] The HTTP response headers\n * @private\n */\nfunction abortHandshakeOrEmitwsClientError(\n server,\n req,\n socket,\n code,\n message,\n headers\n) {\n if (server.listenerCount('wsClientError')) {\n const err = new Error(message);\n Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);\n\n server.emit('wsClientError', err, socket, req);\n } else {\n abortHandshake(socket, code, message, headers);\n }\n}\n","import createWebSocketStream from './lib/stream.js';\nimport Receiver from './lib/receiver.js';\nimport Sender from './lib/sender.js';\nimport WebSocket from './lib/websocket.js';\nimport WebSocketServer from './lib/websocket-server.js';\n\nexport { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer };\nexport default WebSocket;\n","/**\n * Workflow Visualization Module\n *\n * Provides tools for visualizing workflow execution with color-coded\n * step states and support for parallel/race operations.\n *\n * @example\n * ```typescript\n * import { createVisualizer } from '@jagreehal/workflow/visualize';\n *\n * const viz = createVisualizer({ workflowName: 'checkout' });\n * const workflow = createWorkflow(deps, { onEvent: viz.handleEvent });\n *\n * await workflow(async (step) => {\n * await step(() => validateCart(cart), 'Validate cart');\n * await step(() => processPayment(payment), 'Process payment');\n * });\n *\n * console.log(viz.render());\n * ```\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n OutputFormat,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n VisualizerOptions,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, mermaidRenderer, loggerRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// Re-exports\n// =============================================================================\n\nexport * from \"./types\";\nexport { createIRBuilder, type IRBuilderOptions } from \"./ir-builder\";\nexport { asciiRenderer, mermaidRenderer, loggerRenderer, defaultColorScheme } from \"./renderers\";\nexport type { LoggerOutput, LoggerRenderOptions, StepLog, HookLog, WorkflowSummary } from \"./renderers\";\nexport { htmlRenderer, renderToHTML } from \"./renderers/html\";\nexport { detectParallelGroups, createParallelDetector, type ParallelDetectorOptions } from \"./parallel-detector\";\nexport { createLiveVisualizer, type LiveVisualizer } from \"./live-visualizer\";\nexport { trackDecision, trackIf, trackSwitch, type DecisionTracker, type IfTracker, type SwitchTracker } from \"./decision-tracker\";\n\n// Time-travel debugging\nexport {\n createTimeTravelController,\n type TimeTravelController,\n type TimeTravelOptions,\n} from \"./time-travel\";\n\n// Performance analysis\nexport {\n createPerformanceAnalyzer,\n getHeatLevel,\n type PerformanceAnalyzer,\n type WorkflowRun,\n} from \"./performance-analyzer\";\n\n// Dev server (WebSocket-based live visualization)\n// Note: ws is an optional peer dependency\nexport {\n createDevServer,\n type DevServer,\n type DevServerOptions,\n} from \"./dev-server\";\n\n// =============================================================================\n// Visualizer Interface\n// =============================================================================\n\n/**\n * Workflow visualizer that processes events and renders output.\n */\nexport interface WorkflowVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Process a scope event (parallel/race) */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n\n /** Process a decision event (conditional branches) */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n\n /** Get current IR state */\n getIR: () => WorkflowIR;\n\n /** Render current state using the default renderer */\n render: () => string;\n\n /** Render to a specific format */\n renderAs: (format: OutputFormat) => string;\n\n /** Reset state for a new workflow */\n reset: () => void;\n\n /** Subscribe to IR updates (for live visualization) */\n onUpdate: (callback: (ir: WorkflowIR) => void) => () => void;\n}\n\n// =============================================================================\n// Create Visualizer\n// =============================================================================\n\n/**\n * Create a workflow visualizer.\n *\n * @example\n * ```typescript\n * const viz = createVisualizer({ workflowName: 'my-workflow' });\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: viz.handleEvent,\n * });\n *\n * await workflow(async (step) => { ... });\n *\n * console.log(viz.render());\n * ```\n */\nexport function createVisualizer(\n options: VisualizerOptions = {}\n): WorkflowVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const updateCallbacks: Set<(ir: WorkflowIR) => void> = new Set();\n\n // Renderers\n const ascii = asciiRenderer();\n const mermaid = mermaidRenderer();\n const logger = loggerRenderer();\n\n // Build render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: process.stdout?.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n function notifyUpdate(): void {\n if (updateCallbacks.size > 0) {\n const ir = builder.getIR();\n for (const callback of updateCallbacks) {\n callback(ir);\n }\n }\n }\n\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n // Set workflow name if provided\n if (event.type === \"workflow_start\" && workflowName) {\n // Note: We'd need to extend the builder to support setting name\n // For now, the name is passed in render options\n }\n\n notifyUpdate();\n }\n\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n notifyUpdate();\n }\n\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n notifyUpdate();\n }\n\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n // Apply workflow name if provided\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n function render(): string {\n const ir = getIR();\n return ascii.render(ir, renderOptions);\n }\n\n function renderAs(format: OutputFormat): string {\n const ir = getIR();\n\n switch (format) {\n case \"ascii\":\n return ascii.render(ir, renderOptions);\n\n case \"mermaid\":\n return mermaid.render(ir, renderOptions);\n\n case \"json\":\n return JSON.stringify(ir, null, 2);\n\n case \"logger\":\n return logger.render(ir, renderOptions);\n\n default:\n throw new Error(`Unknown format: ${format}`);\n }\n }\n\n function reset(): void {\n builder.reset();\n notifyUpdate();\n }\n\n function onUpdate(callback: (ir: WorkflowIR) => void): () => void {\n updateCallbacks.add(callback);\n return () => updateCallbacks.delete(callback);\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n renderAs,\n reset,\n onUpdate,\n };\n}\n\n// =============================================================================\n// Convenience Functions\n// =============================================================================\n\n/**\n * Union type for all collectable/visualizable events (workflow + decision).\n */\nexport type CollectableEvent =\n | WorkflowEvent<unknown>\n | DecisionStartEvent\n | DecisionBranchEvent\n | DecisionEndEvent;\n\n/**\n * Visualize collected events (post-execution).\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const events: CollectableEvent[] = [];\n * const workflow = createWorkflow(deps, {\n * onEvent: (e) => events.push(e),\n * });\n *\n * await workflow(async (step) => {\n * const decision = trackIf('check', condition, {\n * emit: (e) => events.push(e),\n * });\n * // ...\n * });\n *\n * console.log(visualizeEvents(events));\n * ```\n */\nexport function visualizeEvents(\n events: CollectableEvent[],\n options: VisualizerOptions = {}\n): string {\n const viz = createVisualizer(options);\n\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n\n return viz.render();\n}\n\n/**\n * Create an event collector for later visualization.\n *\n * Supports both workflow events (from onEvent) and decision events\n * (from trackDecision/trackIf/trackSwitch).\n *\n * @example\n * ```typescript\n * const collector = createEventCollector();\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: collector.handleEvent,\n * });\n *\n * await workflow(async (step) => {\n * // Decision events can also be collected\n * const decision = trackIf('check', condition, {\n * emit: collector.handleDecisionEvent,\n * });\n * // ...\n * });\n *\n * console.log(collector.visualize());\n * ```\n */\nexport function createEventCollector(options: VisualizerOptions = {}) {\n const events: CollectableEvent[] = [];\n\n return {\n /** Handle a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => {\n events.push(event);\n },\n\n /** Handle a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => {\n events.push(event);\n },\n\n /** Get all collected events */\n getEvents: () => [...events],\n\n /** Get workflow events only */\n getWorkflowEvents: () => events.filter((e): e is WorkflowEvent<unknown> =>\n !e.type.startsWith(\"decision_\")\n ),\n\n /** Get decision events only */\n getDecisionEvents: () => events.filter((e): e is DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent =>\n e.type.startsWith(\"decision_\")\n ),\n\n /** Clear collected events */\n clear: () => {\n events.length = 0;\n },\n\n /** Visualize collected events */\n visualize: () => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.render();\n },\n\n /** Visualize in a specific format */\n visualizeAs: (format: OutputFormat) => {\n const viz = createVisualizer(options);\n for (const event of events) {\n if (event.type.startsWith(\"decision_\")) {\n viz.handleDecisionEvent(event as DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent);\n } else {\n viz.handleEvent(event as WorkflowEvent<unknown>);\n }\n }\n return viz.renderAs(format);\n },\n };\n}\n\n","/**\n * Timing utilities for workflow visualization.\n */\n\n/**\n * Format duration in milliseconds to a human-readable string.\n *\n * @example\n * formatDuration(23) // \"23ms\"\n * formatDuration(1500) // \"1.5s\"\n * formatDuration(65000) // \"1m 5s\"\n */\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`;\n }\n\n if (ms < 60000) {\n const seconds = ms / 1000;\n // Show one decimal for seconds\n return `${seconds.toFixed(1).replace(/\\.0$/, \"\")}s`;\n }\n\n const minutes = Math.floor(ms / 60000);\n const seconds = Math.round((ms % 60000) / 1000);\n\n if (seconds === 0) {\n return `${minutes}m`;\n }\n\n return `${minutes}m ${seconds}s`;\n}\n\n/**\n * Generate a unique ID for nodes.\n */\nexport function generateId(): string {\n return `node_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;\n}\n","/**\n * Parallel Detection - Heuristic detection of parallel execution from timing.\n *\n * When steps overlap in time (one starts before another ends), they are\n * likely running in parallel. This module detects such patterns and\n * groups overlapping steps into ParallelNode structures.\n */\n\nimport type { FlowNode, ParallelNode, StepNode } from \"./types\";\n\n/**\n * Options for parallel detection.\n */\nexport interface ParallelDetectorOptions {\n /**\n * Minimum overlap in milliseconds to consider steps parallel.\n * Default: 0 (any overlap counts)\n */\n minOverlapMs?: number;\n\n /**\n * Maximum gap in milliseconds to still consider steps as part of same parallel group.\n * Default: 5 (steps starting within 5ms are grouped)\n */\n maxGapMs?: number;\n}\n\n/**\n * Step timing information for overlap detection.\n */\ninterface StepTiming {\n node: StepNode;\n startTs: number;\n endTs: number;\n}\n\n/**\n * Check if nodes contain real scope nodes (from scope_start/scope_end events).\n * When real scope nodes exist, heuristic detection should be skipped to avoid\n * duplicating or conflicting with the explicit structure.\n */\nfunction hasRealScopeNodes(nodes: FlowNode[]): boolean {\n for (const node of nodes) {\n // Real scope nodes are parallel/race/sequence that came from scope events\n // (not from heuristic detection, which uses ids starting with \"detected_\")\n if (\n (node.type === \"parallel\" || node.type === \"race\" || node.type === \"sequence\") &&\n !node.id.startsWith(\"detected_\")\n ) {\n return true;\n }\n // Also check for decision nodes if present\n if (\"decisionId\" in node) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Group overlapping steps into parallel nodes.\n *\n * Algorithm:\n * 1. Sort steps by start time\n * 2. For each step, check if it overlaps with existing parallel groups\n * 3. If it overlaps, add to group; otherwise start new sequence\n * 4. Merge overlapping groups when step bridges them\n *\n * Note: If real scope nodes (from scope_start/scope_end) are present,\n * heuristic detection is skipped to avoid conflicts.\n */\nexport function detectParallelGroups(\n nodes: FlowNode[],\n options: ParallelDetectorOptions = {}\n): FlowNode[] {\n // If real scope nodes exist, skip heuristic detection\n // The explicit scope events provide accurate structure\n if (hasRealScopeNodes(nodes)) {\n return nodes;\n }\n\n const { minOverlapMs = 0, maxGapMs = 5 } = options;\n\n // Extract step nodes with timing info, preserving indices for position restoration\n const stepsWithTiming: (StepTiming & { originalIndex: number })[] = [];\n const nonStepNodes: { node: FlowNode; originalIndex: number }[] = [];\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n if (node.type === \"step\" && node.startTs !== undefined) {\n stepsWithTiming.push({\n node,\n startTs: node.startTs,\n endTs: node.endTs ?? node.startTs + (node.durationMs ?? 0),\n originalIndex: i,\n });\n } else {\n // Keep non-step nodes with their original position\n nonStepNodes.push({ node, originalIndex: i });\n }\n }\n\n if (stepsWithTiming.length <= 1) {\n return nodes; // Nothing to group\n }\n\n // Sort by start time\n stepsWithTiming.sort((a, b) => a.startTs - b.startTs);\n\n // Group overlapping steps\n type StepTimingWithIndex = StepTiming & { originalIndex: number };\n const groups: StepTimingWithIndex[][] = [];\n let currentGroup: StepTimingWithIndex[] = [stepsWithTiming[0]];\n\n for (let i = 1; i < stepsWithTiming.length; i++) {\n const step = stepsWithTiming[i];\n const groupStart = Math.min(...currentGroup.map((s) => s.startTs));\n const groupEnd = Math.max(...currentGroup.map((s) => s.endTs));\n\n // Two ways steps can be parallel:\n // 1. They started together (within maxGapMs) - handles timing jitter\n // 2. They genuinely overlap (step starts before group ends)\n const startedTogether = step.startTs <= groupStart + maxGapMs;\n const hasTrueOverlap = step.startTs < groupEnd;\n\n if (!startedTogether && !hasTrueOverlap) {\n // Sequential: step started after group ended AND not with the group\n groups.push(currentGroup);\n currentGroup = [step];\n continue;\n }\n\n // Check minOverlapMs threshold for overlap duration\n // For steps that started together, overlap is measured from step start to group end\n // For steps with true overlap, it's from step start to min(step end, group end)\n const overlapDuration = hasTrueOverlap\n ? Math.min(step.endTs, groupEnd) - step.startTs\n : 0;\n\n // Started together bypasses minOverlapMs (they're parallel by definition)\n // True overlap must meet the minOverlapMs threshold\n if (startedTogether || overlapDuration >= minOverlapMs) {\n currentGroup.push(step);\n } else {\n // Overlap too small - treat as sequential\n groups.push(currentGroup);\n currentGroup = [step];\n }\n }\n groups.push(currentGroup);\n\n // Convert groups to nodes with position tracking\n const groupedNodes: { node: FlowNode; position: number }[] = [];\n\n for (const group of groups) {\n // Use the minimum original index as the position for the group\n const position = Math.min(...group.map((s) => s.originalIndex));\n\n if (group.length === 1) {\n // Single step - no parallel grouping needed\n groupedNodes.push({ node: group[0].node, position });\n } else {\n // Multiple overlapping steps - create parallel node\n const children = group.map((s) => s.node);\n const startTs = Math.min(...group.map((s) => s.startTs));\n const endTs = Math.max(...group.map((s) => s.endTs));\n\n const parallelNode: ParallelNode = {\n type: \"parallel\",\n id: `detected_parallel_${startTs}`,\n name: `${children.length} parallel steps`,\n state: deriveGroupState(children),\n mode: \"all\",\n children,\n startTs,\n endTs,\n durationMs: endTs - startTs,\n };\n\n groupedNodes.push({ node: parallelNode, position });\n }\n }\n\n // Add non-step nodes with their original positions\n for (const { node, originalIndex } of nonStepNodes) {\n groupedNodes.push({ node, position: originalIndex });\n }\n\n // Sort by original position to preserve ordering\n groupedNodes.sort((a, b) => a.position - b.position);\n\n return groupedNodes.map((g) => g.node);\n}\n\n/**\n * Derive the state of a group from its children.\n */\nfunction deriveGroupState(\n children: FlowNode[]\n): \"pending\" | \"running\" | \"success\" | \"error\" | \"aborted\" | \"cached\" {\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n const hasPending = children.some((c) => c.state === \"pending\");\n if (hasPending) return \"pending\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n return \"success\";\n}\n\n/**\n * Create a parallel detector that processes nodes.\n */\nexport function createParallelDetector(options: ParallelDetectorOptions = {}) {\n return {\n /**\n * Process nodes and group overlapping ones into parallel nodes.\n */\n detect: (nodes: FlowNode[]) => detectParallelGroups(nodes, options),\n };\n}\n","/**\n * IR Builder - Converts workflow events to Intermediate Representation.\n *\n * The builder maintains state as events arrive, constructing a tree\n * representation of the workflow execution that can be rendered.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n FlowNode,\n ScopeEndEvent,\n ScopeStartEvent,\n ScopeType,\n StepNode,\n StepState,\n WorkflowIR,\n WorkflowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n DecisionBranch,\n IRSnapshot,\n ActiveStepSnapshot,\n WorkflowHooks,\n HookExecution,\n} from \"./types\";\nimport { generateId } from \"./utils/timing\";\nimport { detectParallelGroups, type ParallelDetectorOptions } from \"./parallel-detector\";\n\n// =============================================================================\n// Builder Options\n// =============================================================================\n\n/**\n * Options for the IR builder.\n */\nexport interface IRBuilderOptions {\n /**\n * Enable heuristic parallel detection based on timing.\n * When true, overlapping steps are grouped into ParallelNodes.\n * Default: true\n */\n detectParallel?: boolean;\n\n /**\n * Options for parallel detection.\n */\n parallelDetection?: ParallelDetectorOptions;\n\n /**\n * Enable snapshot recording for time-travel debugging.\n * When true, the builder captures IR state after each event.\n * Default: false\n */\n enableSnapshots?: boolean;\n\n /**\n * Maximum number of snapshots to keep (ring buffer behavior).\n * When exceeded, oldest snapshots are discarded.\n * Default: 1000\n */\n maxSnapshots?: number;\n}\n\n// =============================================================================\n// Builder State\n// =============================================================================\n\ninterface ActiveStep {\n id: string;\n name?: string;\n key?: string;\n startTs: number;\n retryCount: number;\n timedOut: boolean;\n timeoutMs?: number;\n}\n\ninterface ActiveScope {\n id: string;\n name?: string;\n type: ScopeType;\n startTs: number;\n children: FlowNode[];\n}\n\ninterface ActiveDecision {\n id: string;\n name?: string;\n condition?: string;\n decisionValue?: unknown;\n startTs: number;\n branches: Map<string, DecisionBranch>;\n branchTaken?: string | boolean;\n}\n\n// =============================================================================\n// IR Builder\n// =============================================================================\n\n/**\n * Creates an IR builder that processes workflow events.\n */\nexport function createIRBuilder(options: IRBuilderOptions = {}) {\n const {\n detectParallel = true,\n parallelDetection,\n enableSnapshots = false,\n maxSnapshots = 1000,\n } = options;\n\n // Current workflow state\n let workflowId: string | undefined;\n let workflowStartTs: number | undefined;\n let workflowState: StepState = \"pending\";\n let workflowError: unknown;\n let workflowDurationMs: number | undefined;\n\n // Active steps (currently running)\n const activeSteps = new Map<string, ActiveStep>();\n\n // Active scopes (parallel/race blocks)\n const scopeStack: ActiveScope[] = [];\n\n // Active decisions (conditional branches)\n const decisionStack: ActiveDecision[] = [];\n\n // Completed nodes at the current scope level\n let currentNodes: FlowNode[] = [];\n\n // Metadata\n let createdAt = Date.now();\n let lastUpdatedAt = createdAt;\n\n // Hook executions\n let hookState: WorkflowHooks = {\n onAfterStep: new Map(),\n };\n\n // Snapshot state for time-travel debugging\n const snapshots: IRSnapshot[] = [];\n let eventIndex = 0;\n\n /**\n * Get the step ID from an event.\n * Uses stepId if available (new events), then falls back to stepKey or name,\n * and finally generates a random ID for backwards compatibility.\n */\n function getStepId(event: { stepId?: string; stepKey?: string; name?: string }): string {\n return event.stepId ?? event.stepKey ?? event.name ?? generateId();\n }\n\n /**\n * Add a completed node to the current scope or decision branch.\n */\n function addNode(node: FlowNode): void {\n // If we're in a decision, add to the taken branch\n if (decisionStack.length > 0) {\n const decision = decisionStack[decisionStack.length - 1];\n // Find the taken branch\n for (const branch of decision.branches.values()) {\n if (branch.taken) {\n branch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n // If no branch is marked as taken yet, add to the first branch\n // (this handles cases where steps execute before branch is marked)\n const firstBranch = Array.from(decision.branches.values())[0];\n if (firstBranch) {\n firstBranch.children.push(node);\n lastUpdatedAt = Date.now();\n return;\n }\n }\n\n // If we're in a scope, add to the scope\n if (scopeStack.length > 0) {\n // Add to the innermost scope\n scopeStack[scopeStack.length - 1].children.push(node);\n } else {\n // Add to the root level\n currentNodes.push(node);\n }\n lastUpdatedAt = Date.now();\n }\n\n /**\n * Capture a snapshot of the current IR state (for time-travel debugging).\n * Called after each event is processed.\n */\n function captureSnapshot(event: WorkflowEvent<unknown>): void {\n if (!enableSnapshots) return;\n\n // Deep clone the current IR state\n const ir = getIR();\n\n // Clone active steps for debugging\n const activeStepsCopy = new Map<string, ActiveStepSnapshot>();\n for (const [id, step] of activeSteps) {\n activeStepsCopy.set(id, {\n id: step.id,\n name: step.name,\n key: step.key,\n startTs: step.startTs,\n retryCount: step.retryCount,\n timedOut: step.timedOut,\n timeoutMs: step.timeoutMs,\n });\n }\n\n const snapshot: IRSnapshot = {\n id: `snapshot_${eventIndex}`,\n eventIndex,\n event: structuredClone(event),\n ir: structuredClone(ir),\n timestamp: Date.now(),\n activeSteps: activeStepsCopy,\n };\n\n snapshots.push(snapshot);\n\n // Ring buffer: remove oldest if we exceed max\n if (snapshots.length > maxSnapshots) {\n snapshots.shift();\n }\n\n eventIndex++;\n }\n\n /**\n * Handle a workflow event and update the IR.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n switch (event.type) {\n case \"workflow_start\":\n workflowId = event.workflowId;\n workflowStartTs = event.ts;\n workflowState = \"running\";\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n // Note: Don't clear hookState here - shouldRun and onBeforeStart\n // events are emitted BEFORE workflow_start. Only clear onAfterStep\n // since those are per-step and should reset for each workflow run.\n hookState.onAfterStep = new Map();\n break;\n\n case \"workflow_success\":\n workflowState = \"success\";\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"workflow_error\":\n workflowState = \"error\";\n workflowError = event.error;\n workflowDurationMs = event.durationMs;\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_start\": {\n const id = getStepId(event);\n activeSteps.set(id, {\n id,\n name: event.name,\n key: event.stepKey,\n startTs: event.ts,\n retryCount: 0,\n timedOut: false,\n });\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_success\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"success\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_error\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"error\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_aborted\": {\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n const node: StepNode = {\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"aborted\",\n startTs: active.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n };\n addNode(node);\n activeSteps.delete(id);\n }\n break;\n }\n\n case \"step_cache_hit\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"cached\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n\n case \"step_cache_miss\":\n // Cache miss just means the step will execute normally\n // We'll get a step_start event next\n break;\n\n case \"step_complete\":\n // step_complete is for state persistence, not visualization\n // We already handled the step via step_success/step_error\n break;\n\n case \"step_timeout\": {\n // Timeout is an intermediate event - step may retry or will get step_error\n // Track timeout info on the active step\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.timedOut = true;\n active.timeoutMs = event.timeoutMs;\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retry\": {\n // Retry is an intermediate event - increment retry counter\n const id = getStepId(event);\n const active = activeSteps.get(id);\n if (active) {\n active.retryCount = (event.attempt ?? 1) - 1; // attempt is 1-indexed, retryCount is 0-indexed\n }\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"step_retries_exhausted\":\n // All retries exhausted - step_error will follow\n // The error state will be set by step_error handler\n lastUpdatedAt = Date.now();\n break;\n\n case \"step_skipped\": {\n const id = getStepId(event);\n const node: StepNode = {\n type: \"step\",\n id,\n name: event.name,\n key: event.stepKey,\n state: \"skipped\",\n startTs: event.ts,\n endTs: event.ts,\n durationMs: 0,\n };\n addNode(node);\n break;\n }\n\n // Hook events\n case \"hook_should_run\": {\n const hookExec: HookExecution = {\n type: \"shouldRun\",\n state: \"success\",\n ts: event.ts,\n durationMs: event.durationMs,\n context: {\n result: event.result,\n skipped: event.skipped,\n },\n };\n hookState.shouldRun = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_should_run_error\": {\n const hookExec: HookExecution = {\n type: \"shouldRun\",\n state: \"error\",\n ts: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n };\n hookState.shouldRun = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_before_start\": {\n const hookExec: HookExecution = {\n type: \"onBeforeStart\",\n state: \"success\",\n ts: event.ts,\n durationMs: event.durationMs,\n context: {\n result: event.result,\n skipped: event.skipped,\n },\n };\n hookState.onBeforeStart = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_before_start_error\": {\n const hookExec: HookExecution = {\n type: \"onBeforeStart\",\n state: \"error\",\n ts: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n };\n hookState.onBeforeStart = hookExec;\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_after_step\": {\n const hookExec: HookExecution = {\n type: \"onAfterStep\",\n state: \"success\",\n ts: event.ts,\n durationMs: event.durationMs,\n context: {\n stepKey: event.stepKey,\n },\n };\n hookState.onAfterStep.set(event.stepKey, hookExec);\n lastUpdatedAt = Date.now();\n break;\n }\n\n case \"hook_after_step_error\": {\n const hookExec: HookExecution = {\n type: \"onAfterStep\",\n state: \"error\",\n ts: event.ts,\n durationMs: event.durationMs,\n error: event.error,\n context: {\n stepKey: event.stepKey,\n },\n };\n hookState.onAfterStep.set(event.stepKey, hookExec);\n lastUpdatedAt = Date.now();\n break;\n }\n }\n\n // Capture snapshot after processing event (for time-travel)\n captureSnapshot(event);\n }\n\n /**\n * Handle a scope event (parallel/race start/end).\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n if (event.type === \"scope_start\") {\n scopeStack.push({\n id: event.scopeId,\n name: event.name,\n type: event.scopeType,\n startTs: event.ts,\n children: [],\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"scope_end\") {\n const scope = scopeStack.pop();\n if (scope) {\n const node: ParallelNode | RaceNode =\n scope.type === \"race\"\n ? {\n type: \"race\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n winnerId: event.winnerId,\n }\n : {\n type: \"parallel\",\n id: scope.id,\n name: scope.name,\n state: deriveState(scope.children),\n startTs: scope.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n children: scope.children,\n mode: scope.type === \"allSettled\" ? \"allSettled\" : \"all\",\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Handle a decision event (conditional branch start/branch/end).\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n if (event.type === \"decision_start\") {\n decisionStack.push({\n id: event.decisionId,\n name: event.name,\n condition: event.condition,\n decisionValue: event.decisionValue,\n startTs: event.ts,\n branches: new Map(),\n });\n lastUpdatedAt = Date.now();\n } else if (event.type === \"decision_branch\") {\n const decision = decisionStack[decisionStack.length - 1];\n if (decision && decision.id === event.decisionId) {\n // Find or create branch\n const branchKey = event.branchLabel;\n const existing = decision.branches.get(branchKey);\n if (existing) {\n // Update existing branch\n existing.taken = event.taken;\n } else {\n // Create new branch\n decision.branches.set(branchKey, {\n label: event.branchLabel,\n condition: event.condition,\n taken: event.taken,\n children: [],\n });\n }\n lastUpdatedAt = Date.now();\n }\n } else if (event.type === \"decision_end\") {\n const decision = decisionStack.pop();\n if (decision && decision.id === event.decisionId) {\n // Convert branches map to array\n const branches: DecisionBranch[] = Array.from(decision.branches.values());\n\n const node: DecisionNode = {\n type: \"decision\",\n id: decision.id,\n name: decision.name,\n state: deriveState(\n branches.flatMap((b) => (b.taken ? b.children : []))\n ),\n startTs: decision.startTs,\n endTs: event.ts,\n durationMs: event.durationMs,\n condition: decision.condition,\n decisionValue: decision.decisionValue,\n branchTaken: event.branchTaken ?? decision.branchTaken,\n branches,\n };\n addNode(node);\n }\n }\n }\n\n /**\n * Derive the state of a parent node from its children.\n */\n function deriveState(children: FlowNode[]): StepState {\n if (children.length === 0) return \"success\";\n\n const hasError = children.some((c) => c.state === \"error\");\n if (hasError) return \"error\";\n\n const allSuccess = children.every(\n (c) => c.state === \"success\" || c.state === \"cached\"\n );\n if (allSuccess) return \"success\";\n\n const hasRunning = children.some((c) => c.state === \"running\");\n if (hasRunning) return \"running\";\n\n return \"pending\";\n }\n\n /**\n * Get the current nodes including any active (running) steps.\n */\n function getCurrentNodes(): FlowNode[] {\n const nodes = [...currentNodes];\n\n // Add active steps as running nodes\n for (const [, active] of activeSteps) {\n nodes.push({\n type: \"step\",\n id: active.id,\n name: active.name,\n key: active.key,\n state: \"running\",\n startTs: active.startTs,\n ...(active.retryCount > 0 && { retryCount: active.retryCount }),\n ...(active.timedOut && { timedOut: true, timeoutMs: active.timeoutMs }),\n });\n }\n\n return nodes;\n }\n\n /**\n * Build and return the current IR state.\n */\n function getIR(): WorkflowIR {\n let children = getCurrentNodes();\n\n // Apply parallel detection if enabled\n if (detectParallel) {\n children = detectParallelGroups(children, parallelDetection);\n }\n\n const root: WorkflowNode = {\n type: \"workflow\",\n id: workflowId ?? generateId(),\n workflowId: workflowId ?? \"unknown\",\n state: workflowState,\n startTs: workflowStartTs,\n durationMs: workflowDurationMs,\n children,\n error: workflowError,\n };\n\n // Include hooks if any have been recorded\n const hasHooks =\n hookState.shouldRun !== undefined ||\n hookState.onBeforeStart !== undefined ||\n hookState.onAfterStep.size > 0;\n\n return {\n root,\n metadata: {\n createdAt,\n lastUpdatedAt,\n },\n ...(hasHooks && { hooks: hookState }),\n };\n }\n\n /**\n * Reset the builder state.\n */\n function reset(): void {\n workflowId = undefined;\n workflowStartTs = undefined;\n workflowState = \"pending\";\n workflowError = undefined;\n workflowDurationMs = undefined;\n activeSteps.clear();\n scopeStack.length = 0;\n decisionStack.length = 0;\n currentNodes = [];\n createdAt = Date.now();\n lastUpdatedAt = createdAt;\n // Clear hooks\n hookState = {\n onAfterStep: new Map(),\n };\n // Clear snapshots\n snapshots.length = 0;\n eventIndex = 0;\n }\n\n /**\n * Get all recorded snapshots.\n */\n function getSnapshots(): IRSnapshot[] {\n return [...snapshots];\n }\n\n /**\n * Get a snapshot at a specific index.\n */\n function getSnapshotAt(index: number): IRSnapshot | undefined {\n return snapshots[index];\n }\n\n /**\n * Get the IR state at a specific snapshot index.\n */\n function getIRAt(index: number): WorkflowIR | undefined {\n return snapshots[index]?.ir;\n }\n\n /**\n * Clear all recorded snapshots.\n */\n function clearSnapshots(): void {\n snapshots.length = 0;\n eventIndex = 0;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n reset,\n // Snapshot methods for time-travel\n getSnapshots,\n getSnapshotAt,\n getIRAt,\n clearSnapshots,\n /** Check if there are active (running) steps */\n get hasActiveSteps() {\n return activeSteps.size > 0;\n },\n /** Get the current workflow state */\n get state() {\n return workflowState;\n },\n /** Get the number of recorded snapshots */\n get snapshotCount() {\n return snapshots.length;\n },\n /** Check if snapshot recording is enabled */\n get snapshotsEnabled() {\n return enableSnapshots;\n },\n };\n}\n\n/**\n * Type for the IR builder instance.\n */\nexport type IRBuilder = ReturnType<typeof createIRBuilder>;\n","/**\n * Workflow Visualization - Intermediate Representation Types\n *\n * The IR (Intermediate Representation) is a DSL that represents workflow\n * execution structure. Events are converted to IR, which can then be\n * rendered to various output formats (ASCII, Mermaid, JSON, etc.).\n */\n\n// =============================================================================\n// Step States\n// =============================================================================\n\n/**\n * Execution state of a step with semantic meaning for visualization.\n *\n * Color mapping:\n * - pending → white/clear (not started)\n * - running → yellow (currently executing)\n * - success → green (completed successfully)\n * - error → red (failed with error)\n * - aborted → gray (cancelled, e.g., in race)\n * - cached → blue (served from cache)\n * - skipped → dim gray (not executed due to conditional logic)\n */\nexport type StepState =\n | \"pending\"\n | \"running\"\n | \"success\"\n | \"error\"\n | \"aborted\"\n | \"cached\"\n | \"skipped\";\n\n// =============================================================================\n// Node Types\n// =============================================================================\n\n/**\n * Base properties shared by all IR nodes.\n */\nexport interface BaseNode {\n /** Unique identifier for this node */\n id: string;\n /** Human-readable name (from step options or inferred) */\n name?: string;\n /** Cache key if this is a keyed step */\n key?: string;\n /** Current execution state */\n state: StepState;\n /** Timestamp when execution started */\n startTs?: number;\n /** Timestamp when execution ended */\n endTs?: number;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error value if state is 'error' */\n error?: unknown;\n /** Input value that triggered this step (for decision understanding) */\n input?: unknown;\n /** Output value from this step (for decision understanding) */\n output?: unknown;\n /** Number of retry attempts made (0 = no retries, 1 = one retry, etc.) */\n retryCount?: number;\n /** Whether this step experienced a timeout (may have retried after) */\n timedOut?: boolean;\n /** Timeout duration in ms (if timed out) */\n timeoutMs?: number;\n}\n\n/**\n * A single step execution node.\n */\nexport interface StepNode extends BaseNode {\n type: \"step\";\n}\n\n/**\n * Sequential execution - steps run one after another.\n * This is the implicit structure when steps are awaited in sequence.\n */\nexport interface SequenceNode extends BaseNode {\n type: \"sequence\";\n children: FlowNode[];\n}\n\n/**\n * Parallel execution - all branches run simultaneously.\n * Created by allAsync() or allSettledAsync().\n */\nexport interface ParallelNode extends BaseNode {\n type: \"parallel\";\n children: FlowNode[];\n /**\n * Execution mode:\n * - 'all': Fails on first error (allAsync)\n * - 'allSettled': Collects all results (allSettledAsync)\n */\n mode: \"all\" | \"allSettled\";\n}\n\n/**\n * Race execution - first to complete wins.\n * Created by anyAsync().\n */\nexport interface RaceNode extends BaseNode {\n type: \"race\";\n children: FlowNode[];\n /** ID of the winning branch (first to succeed) */\n winnerId?: string;\n}\n\n/**\n * Decision point - conditional branch (if/switch).\n * Shows which branch was taken and why.\n */\nexport interface DecisionNode extends BaseNode {\n type: \"decision\";\n /** Condition that was evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value that was evaluated (the input to the decision) */\n decisionValue?: unknown;\n /** Which branch was taken (true/false, or the matched case) */\n branchTaken?: string | boolean;\n /** All possible branches (including skipped ones) */\n branches: DecisionBranch[];\n}\n\n/**\n * A branch in a decision node.\n */\nexport interface DecisionBranch {\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n label: string;\n /** Condition that would trigger this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n /** Steps in this branch */\n children: FlowNode[];\n}\n\n/**\n * Union of all flow node types.\n */\nexport type FlowNode = StepNode | SequenceNode | ParallelNode | RaceNode | DecisionNode;\n\n/**\n * Root node representing the entire workflow.\n */\nexport interface WorkflowNode extends BaseNode {\n type: \"workflow\";\n /** Correlation ID from the workflow execution */\n workflowId: string;\n /** Child nodes (steps, parallel blocks, etc.) */\n children: FlowNode[];\n}\n\n// =============================================================================\n// Workflow IR\n// =============================================================================\n\n/**\n * Complete workflow intermediate representation.\n * This is the main data structure produced by the IR builder.\n */\nexport interface WorkflowIR {\n /** Root workflow node */\n root: WorkflowNode;\n /** Metadata about the IR */\n metadata: {\n /** When the IR was first created */\n createdAt: number;\n /** When the IR was last updated */\n lastUpdatedAt: number;\n };\n /** Hook executions (if any hooks are configured) */\n hooks?: WorkflowHooks;\n}\n\n// =============================================================================\n// Scope Events (for parallel/race detection)\n// =============================================================================\n\n// Re-export ScopeType from core for consistency\nexport type { ScopeType } from \"../core\";\nimport type { ScopeType } from \"../core\";\n\n/**\n * Event emitted when entering a parallel/race scope.\n * This matches the scope_start event in WorkflowEvent.\n */\nexport interface ScopeStartEvent {\n type: \"scope_start\";\n workflowId: string;\n scopeId: string;\n scopeType: ScopeType;\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when exiting a parallel/race scope.\n */\nexport interface ScopeEndEvent {\n type: \"scope_end\";\n workflowId: string;\n scopeId: string;\n ts: number;\n durationMs: number;\n /** For race scopes, the ID of the winning branch */\n winnerId?: string;\n}\n\n/**\n * Event emitted when a decision point is encountered.\n * Use this to track conditional logic (if/switch).\n */\nexport interface DecisionStartEvent {\n type: \"decision_start\";\n workflowId: string;\n decisionId: string;\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n decisionValue?: unknown;\n /** Name/label for this decision point */\n name?: string;\n ts: number;\n}\n\n/**\n * Event emitted when a decision branch is taken.\n */\nexport interface DecisionBranchEvent {\n type: \"decision_branch\";\n workflowId: string;\n decisionId: string;\n /** Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\") */\n branchLabel: string;\n /** Condition for this branch */\n condition?: string;\n /** Whether this branch was taken */\n taken: boolean;\n ts: number;\n}\n\n/**\n * Event emitted when a decision point completes.\n */\nexport interface DecisionEndEvent {\n type: \"decision_end\";\n workflowId: string;\n decisionId: string;\n /** Which branch was taken */\n branchTaken?: string | boolean;\n ts: number;\n durationMs: number;\n}\n\n/**\n * Event emitted when a step is skipped due to conditional logic.\n */\nexport interface StepSkippedEvent {\n type: \"step_skipped\";\n workflowId: string;\n stepKey?: string;\n name?: string;\n /** Reason why this step was skipped (e.g., \"condition was false\") */\n reason?: string;\n /** The decision that caused this skip */\n decisionId?: string;\n ts: number;\n}\n\n/**\n * Union of scope-related events.\n */\nexport type ScopeEvent = ScopeStartEvent | ScopeEndEvent;\n\n/**\n * Union of decision-related events.\n */\nexport type DecisionEvent = DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent;\n\n// =============================================================================\n// Renderer Types\n// =============================================================================\n\n/**\n * Color scheme for rendering step states.\n */\nexport interface ColorScheme {\n pending: string;\n running: string;\n success: string;\n error: string;\n aborted: string;\n cached: string;\n skipped: string;\n}\n\n/**\n * Options passed to renderers.\n */\nexport interface RenderOptions {\n /** Show timing information (duration) */\n showTimings: boolean;\n /** Show step cache keys */\n showKeys: boolean;\n /** Terminal width for ASCII renderer */\n terminalWidth?: number;\n /** Color scheme */\n colors: ColorScheme;\n}\n\n/**\n * Extended options for Mermaid renderer.\n * Controls how edges are displayed for retries, errors, and timeouts.\n */\nexport interface MermaidRenderOptions extends RenderOptions {\n /** Show retry as self-loop edge (default: true) */\n showRetryEdges?: boolean;\n /** Show error flow to error node (default: true) */\n showErrorEdges?: boolean;\n /** Show timeout as alternative path (default: true) */\n showTimeoutEdges?: boolean;\n}\n\n/**\n * Renderer interface - transforms IR to output format.\n */\nexport interface Renderer {\n /** Unique identifier for this renderer */\n readonly name: string;\n /** Render IR to string output */\n render(ir: WorkflowIR, options: RenderOptions): string;\n /** Whether this renderer supports live (incremental) updates */\n supportsLive?: boolean;\n /** Render incremental update (optional) */\n renderUpdate?(\n ir: WorkflowIR,\n changedNodes: FlowNode[],\n options: RenderOptions\n ): string;\n}\n\n// =============================================================================\n// Visualizer Types\n// =============================================================================\n\n/**\n * Output format for rendering.\n */\nexport type OutputFormat = \"ascii\" | \"mermaid\" | \"json\" | \"logger\";\n\n/**\n * Options for creating a visualizer.\n */\nexport interface VisualizerOptions {\n /** Name for the workflow in visualizations */\n workflowName?: string;\n /** Enable parallel detection heuristics (default: true) */\n detectParallel?: boolean;\n /** Show timing information (default: true) */\n showTimings?: boolean;\n /** Show step keys (default: false) */\n showKeys?: boolean;\n /** Custom color scheme */\n colors?: Partial<ColorScheme>;\n}\n\n/**\n * Options for live visualization.\n */\nexport interface LiveVisualizerOptions extends VisualizerOptions {\n /** Output stream (default: process.stdout) */\n stream?: NodeJS.WriteStream;\n /** Update interval in ms (default: 100) */\n updateInterval?: number;\n}\n\n// =============================================================================\n// Type Guards\n// =============================================================================\n\n/**\n * Check if a node is a StepNode.\n */\nexport function isStepNode(node: FlowNode): node is StepNode {\n return node.type === \"step\";\n}\n\n/**\n * Check if a node is a SequenceNode.\n */\nexport function isSequenceNode(node: FlowNode): node is SequenceNode {\n return node.type === \"sequence\";\n}\n\n/**\n * Check if a node is a ParallelNode.\n */\nexport function isParallelNode(node: FlowNode): node is ParallelNode {\n return node.type === \"parallel\";\n}\n\n/**\n * Check if a node is a RaceNode.\n */\nexport function isRaceNode(node: FlowNode): node is RaceNode {\n return node.type === \"race\";\n}\n\n/**\n * Check if a node is a DecisionNode.\n */\nexport function isDecisionNode(node: FlowNode): node is DecisionNode {\n return node.type === \"decision\";\n}\n\n/**\n * Check if a node has children.\n */\nexport function hasChildren(\n node: FlowNode\n): node is SequenceNode | ParallelNode | RaceNode | DecisionNode {\n return \"children\" in node || (node.type === \"decision\" && \"branches\" in node);\n}\n\n// =============================================================================\n// Time Travel Types\n// =============================================================================\n\n/**\n * Snapshot of an active step's state at a point in time.\n */\nexport interface ActiveStepSnapshot {\n id: string;\n name?: string;\n key?: string;\n startTs: number;\n retryCount: number;\n timedOut: boolean;\n timeoutMs?: number;\n}\n\n/**\n * A snapshot of the complete IR state at a specific point in time.\n * Used for time-travel debugging - each event creates a snapshot.\n */\nexport interface IRSnapshot {\n /** Unique identifier for this snapshot */\n id: string;\n /** Index in the event sequence (0-based) */\n eventIndex: number;\n /** The event that triggered this snapshot */\n event: unknown; // WorkflowEvent - avoid circular import\n /** Complete IR state at this moment */\n ir: WorkflowIR;\n /** Timestamp when snapshot was taken */\n timestamp: number;\n /** Active step states at this moment (for debugging) */\n activeSteps: Map<string, ActiveStepSnapshot>;\n}\n\n/**\n * State of the time-travel controller.\n */\nexport interface TimeTravelState {\n /** All recorded snapshots */\n snapshots: IRSnapshot[];\n /** Current snapshot index (for playback position) */\n currentIndex: number;\n /** Whether playback is active */\n isPlaying: boolean;\n /** Playback speed multiplier (1.0 = realtime, 2.0 = 2x speed) */\n playbackSpeed: number;\n /** Whether recording is active */\n isRecording: boolean;\n}\n\n// =============================================================================\n// Performance Analysis Types\n// =============================================================================\n\n/**\n * Performance metrics for a single node across multiple runs.\n */\nexport interface NodePerformance {\n /** Node identifier (name or step ID) */\n nodeId: string;\n /** Average duration across all samples */\n avgDurationMs: number;\n /** Minimum duration observed */\n minDurationMs: number;\n /** Maximum duration observed */\n maxDurationMs: number;\n /** Standard deviation of durations */\n stdDevMs: number;\n /** Number of timing samples collected */\n samples: number;\n /** Retry frequency (0-1, where 1 = always retries) */\n retryRate: number;\n /** Timeout frequency (0-1) */\n timeoutRate: number;\n /** Error rate (0-1) */\n errorRate: number;\n /** Percentile data for distribution analysis */\n percentiles: {\n p50: number;\n p90: number;\n p95: number;\n p99: number;\n };\n}\n\n/**\n * Heatmap data for visualizing performance across nodes.\n */\nexport interface HeatmapData {\n /** Map of node ID to heat level (0-1, where 1 is hottest/slowest) */\n heat: Map<string, number>;\n /** The metric used for heat calculation */\n metric: \"duration\" | \"retryRate\" | \"errorRate\";\n /** Statistics used to compute heat values */\n stats: {\n /** Minimum value in the dataset */\n min: number;\n /** Maximum value in the dataset */\n max: number;\n /** Mean value */\n mean: number;\n /** Threshold above which a node is considered \"hot\" */\n threshold: number;\n };\n}\n\n/**\n * Heat level for visual styling.\n */\nexport type HeatLevel = \"cold\" | \"cool\" | \"neutral\" | \"warm\" | \"hot\" | \"critical\";\n\n// =============================================================================\n// HTML Renderer Types\n// =============================================================================\n\n/**\n * Theme for the HTML visualizer.\n */\nexport type HTMLTheme = \"light\" | \"dark\" | \"auto\";\n\n/**\n * Layout direction for the workflow diagram.\n */\nexport type LayoutDirection = \"TB\" | \"LR\" | \"BT\" | \"RL\";\n\n/**\n * Options for the HTML renderer.\n */\nexport interface HTMLRenderOptions extends RenderOptions {\n /** Enable interactive features (click to inspect, zoom/pan) */\n interactive: boolean;\n /** Include time-travel controls */\n timeTravel: boolean;\n /** Include performance heatmap overlay */\n heatmap: boolean;\n /** Animation duration for transitions (ms) */\n animationDuration: number;\n /** Color theme */\n theme: HTMLTheme;\n /** Diagram layout direction */\n layout: LayoutDirection;\n /** Heatmap data (if heatmap is enabled) */\n heatmapData?: HeatmapData;\n /** WebSocket URL for live updates (if streaming) */\n wsUrl?: string;\n}\n\n/**\n * Message sent from the web visualizer to the dev server.\n */\nexport interface WebVisualizerMessage {\n type:\n | \"time_travel_seek\"\n | \"time_travel_play\"\n | \"time_travel_pause\"\n | \"time_travel_step_forward\"\n | \"time_travel_step_backward\"\n | \"request_snapshots\"\n | \"toggle_heatmap\"\n | \"set_heatmap_metric\";\n payload?: unknown;\n}\n\n/**\n * Message sent from the dev server to the web visualizer.\n */\nexport interface ServerMessage {\n type:\n | \"ir_update\"\n | \"snapshot\"\n | \"snapshots_list\"\n | \"performance_data\"\n | \"workflow_complete\"\n | \"time_travel_state\";\n payload: unknown;\n}\n\n// =============================================================================\n// Enhanced ASCII Renderer Types\n// =============================================================================\n\n/**\n * Extended render options for the enhanced ASCII renderer.\n */\nexport interface EnhancedRenderOptions extends RenderOptions {\n /** Show performance heatmap coloring */\n showHeatmap?: boolean;\n /** Heatmap data for coloring nodes */\n heatmapData?: HeatmapData;\n /** Show timing sparklines (requires historical data) */\n showSparklines?: boolean;\n /** Historical timing data for sparklines: nodeId → array of durations */\n timingHistory?: Map<string, number[]>;\n}\n\n// =============================================================================\n// Hook Execution Types\n// =============================================================================\n\n/**\n * State of a hook execution.\n */\nexport type HookState = \"pending\" | \"running\" | \"success\" | \"error\";\n\n/**\n * Execution record for a workflow hook.\n */\nexport interface HookExecution {\n /** Hook type identifier */\n type: \"shouldRun\" | \"onBeforeStart\" | \"onAfterStep\";\n /** Execution state */\n state: HookState;\n /** Timestamp when hook started */\n ts: number;\n /** Duration in milliseconds */\n durationMs?: number;\n /** Error if hook failed */\n error?: unknown;\n /** Additional context (e.g., stepKey for onAfterStep) */\n context?: {\n /** Step key for onAfterStep hooks */\n stepKey?: string;\n /** Result of shouldRun hook */\n result?: boolean;\n /** Whether workflow was skipped due to shouldRun returning false */\n skipped?: boolean;\n };\n}\n\n/**\n * Hook execution summary for the workflow.\n */\nexport interface WorkflowHooks {\n /** shouldRun hook execution (if configured) */\n shouldRun?: HookExecution;\n /** onBeforeStart hook execution (if configured) */\n onBeforeStart?: HookExecution;\n /** onAfterStep hook executions (keyed by stepKey) */\n onAfterStep: Map<string, HookExecution>;\n}\n","/**\n * ANSI color utilities for terminal output.\n */\n\nimport type { ColorScheme, StepState } from \"../types\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst RESET = \"\\x1b[0m\";\nconst BOLD = \"\\x1b[1m\";\nconst DIM = \"\\x1b[2m\";\n\n// Foreground colors\nconst FG_RED = \"\\x1b[31m\";\nconst FG_GREEN = \"\\x1b[32m\";\nconst FG_YELLOW = \"\\x1b[33m\";\nconst FG_BLUE = \"\\x1b[34m\";\nconst FG_GRAY = \"\\x1b[90m\";\nconst FG_WHITE = \"\\x1b[37m\";\n\n// =============================================================================\n// Color Functions\n// =============================================================================\n\n/**\n * Apply ANSI color to text.\n */\nexport function colorize(text: string, color: string): string {\n if (!color) return text;\n return `${color}${text}${RESET}`;\n}\n\n/**\n * Make text bold.\n */\nexport function bold(text: string): string {\n return `${BOLD}${text}${RESET}`;\n}\n\n/**\n * Make text dim.\n */\nexport function dim(text: string): string {\n return `${DIM}${text}${RESET}`;\n}\n\n// =============================================================================\n// Default Color Scheme\n// =============================================================================\n\n/**\n * Default ANSI color scheme for step states.\n */\nexport const defaultColorScheme: ColorScheme = {\n pending: FG_WHITE,\n running: FG_YELLOW,\n success: FG_GREEN,\n error: FG_RED,\n aborted: FG_GRAY,\n cached: FG_BLUE,\n skipped: DIM + FG_GRAY, // Dim gray for skipped steps\n};\n\n// =============================================================================\n// State Symbols\n// =============================================================================\n\n/**\n * Get the symbol for a step state.\n */\nexport function getStateSymbol(state: StepState): string {\n switch (state) {\n case \"pending\":\n return \"○\"; // Empty circle\n case \"running\":\n return \"⟳\"; // Rotating arrows\n case \"success\":\n return \"✓\"; // Check mark\n case \"error\":\n return \"✗\"; // X mark\n case \"aborted\":\n return \"⊘\"; // Circled slash\n case \"cached\":\n return \"↺\"; // Cached/replay\n case \"skipped\":\n return \"⊘\"; // Circled slash (same as aborted, but different color)\n }\n}\n\n/**\n * Get the colored symbol for a step state.\n */\nexport function getColoredSymbol(state: StepState, colors: ColorScheme): string {\n const symbol = getStateSymbol(state);\n return colorize(symbol, colors[state]);\n}\n\n/**\n * Get colored text based on step state.\n */\nexport function colorByState(\n text: string,\n state: StepState,\n colors: ColorScheme\n): string {\n return colorize(text, colors[state]);\n}\n\n// =============================================================================\n// Strip ANSI\n// =============================================================================\n\n/**\n * Strip ANSI escape codes from a string.\n * Useful for calculating visible string length.\n */\nexport function stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n/**\n * Get the visible length of a string (without ANSI codes).\n */\nexport function visibleLength(str: string): string {\n return stripAnsi(str);\n}\n","/**\n * ASCII Terminal Renderer\n *\n * Renders the workflow IR as ASCII art with box-drawing characters\n * and ANSI colors for terminal display.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n StepNode,\n WorkflowIR,\n EnhancedRenderOptions,\n HeatLevel,\n WorkflowHooks,\n HookExecution,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\nimport {\n bold,\n colorByState,\n colorize,\n defaultColorScheme,\n dim,\n getColoredSymbol,\n stripAnsi,\n} from \"./colors\";\n\n// =============================================================================\n// Box Drawing Characters\n// =============================================================================\n\nconst BOX = {\n topLeft: \"┌\",\n topRight: \"┐\",\n bottomLeft: \"└\",\n bottomRight: \"┘\",\n horizontal: \"─\",\n vertical: \"│\",\n teeRight: \"├\",\n teeLeft: \"┤\",\n teeDown: \"┬\",\n teeUp: \"┴\",\n cross: \"┼\",\n} as const;\n\n// =============================================================================\n// Heatmap Colors (ANSI)\n// =============================================================================\n\n/**\n * ANSI color codes for heatmap visualization.\n */\nconst HEAT_COLORS: Record<HeatLevel, string> = {\n cold: \"\\x1b[34m\", // Blue\n cool: \"\\x1b[36m\", // Cyan\n neutral: \"\", // Default (no color)\n warm: \"\\x1b[33m\", // Yellow\n hot: \"\\x1b[31m\", // Red\n critical: \"\\x1b[41m\", // Red background\n};\n\nconst RESET = \"\\x1b[0m\";\n\n/**\n * Get ANSI color code for a heat level.\n */\nfunction getHeatColor(heat: number): string {\n if (heat < 0.2) return HEAT_COLORS.cold;\n if (heat < 0.4) return HEAT_COLORS.cool;\n if (heat < 0.6) return HEAT_COLORS.neutral;\n if (heat < 0.8) return HEAT_COLORS.warm;\n if (heat < 0.95) return HEAT_COLORS.hot;\n return HEAT_COLORS.critical;\n}\n\n/**\n * Apply heat coloring to a string.\n */\nfunction applyHeatColor(text: string, heat: number): string {\n const color = getHeatColor(heat);\n if (!color) return text;\n return `${color}${text}${RESET}`;\n}\n\n// =============================================================================\n// Sparkline Characters\n// =============================================================================\n\nconst SPARK_CHARS = \"▁▂▃▄▅▆▇█\";\n\n/**\n * Render a sparkline from an array of values.\n *\n * @param values Array of numeric values\n * @param width Maximum characters to use (default: 10)\n * @returns Sparkline string\n */\nexport function renderSparkline(values: number[], width = 10): string {\n if (values.length === 0) return \"\";\n\n // Take last N values\n const subset = values.slice(-width);\n const min = Math.min(...subset);\n const max = Math.max(...subset);\n const range = max - min || 1;\n\n return subset\n .map((v) => {\n const normalized = (v - min) / range;\n const index = Math.floor(normalized * (SPARK_CHARS.length - 1));\n return SPARK_CHARS[index];\n })\n .join(\"\");\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Pad a string to a fixed width, accounting for ANSI codes.\n */\nfunction padEnd(str: string, width: number): string {\n const visibleLen = stripAnsi(str).length;\n const padding = Math.max(0, width - visibleLen);\n return str + \" \".repeat(padding);\n}\n\n/**\n * Create a horizontal line with optional title.\n */\nfunction horizontalLine(width: number, title?: string): string {\n if (!title) {\n return BOX.horizontal.repeat(width);\n }\n\n const titleText = ` ${title} `;\n const remainingWidth = width - titleText.length;\n if (remainingWidth < 4) {\n return BOX.horizontal.repeat(width);\n }\n\n const leftPad = 2;\n const rightPad = remainingWidth - leftPad;\n\n return (\n BOX.horizontal.repeat(leftPad) + titleText + BOX.horizontal.repeat(rightPad)\n );\n}\n\n// =============================================================================\n// Hook Rendering\n// =============================================================================\n\n/**\n * Render a single hook execution.\n */\nfunction renderHookExecution(\n hook: HookExecution,\n label: string,\n colors: ReturnType<typeof Object.assign>\n): string {\n const symbol = hook.state === \"success\"\n ? colorize(\"⚙\", colors.success)\n : colorize(\"⚠\", colors.error);\n\n const timing = hook.durationMs !== undefined\n ? dim(` [${formatDuration(hook.durationMs)}]`)\n : \"\";\n\n let context = \"\";\n if (hook.type === \"shouldRun\" && hook.context?.skipped) {\n context = dim(\" → workflow skipped\");\n } else if (hook.type === \"shouldRun\" && hook.context?.result === true) {\n context = dim(\" → proceed\");\n } else if (hook.type === \"onBeforeStart\" && hook.context?.skipped) {\n context = dim(\" → workflow skipped\");\n } else if (hook.type === \"onAfterStep\" && hook.context?.stepKey) {\n context = dim(` (${hook.context.stepKey})`);\n }\n\n const error = hook.state === \"error\" && hook.error\n ? dim(` error: ${String(hook.error)}`)\n : \"\";\n\n return `${symbol} ${dim(label)}${context}${timing}${error}`;\n}\n\n/**\n * Render workflow hooks section.\n */\nfunction renderHooks(\n hooks: WorkflowHooks,\n colors: ReturnType<typeof Object.assign>\n): string[] {\n const lines: string[] = [];\n\n // Render shouldRun hook\n if (hooks.shouldRun) {\n lines.push(renderHookExecution(hooks.shouldRun, \"shouldRun\", colors));\n }\n\n // Render onBeforeStart hook\n if (hooks.onBeforeStart) {\n lines.push(renderHookExecution(hooks.onBeforeStart, \"onBeforeStart\", colors));\n }\n\n // We don't render onAfterStep hooks here - they're shown inline with steps\n // But if there are any, add a separator\n if (lines.length > 0) {\n lines.push(dim(\"────────────────────\")); // Separator between hooks and steps\n }\n\n return lines;\n}\n\n// =============================================================================\n// ASCII Renderer\n// =============================================================================\n\n/**\n * Create the ASCII terminal renderer.\n */\nexport function asciiRenderer(): Renderer {\n return {\n name: \"ascii\",\n supportsLive: true,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n const colors = { ...defaultColorScheme, ...options.colors };\n const width = options.terminalWidth ?? 60;\n const innerWidth = width - 4; // Account for borders\n\n const lines: string[] = [];\n\n // Header\n const workflowName = ir.root.name ?? \"workflow\";\n const headerTitle = bold(workflowName);\n lines.push(\n `${BOX.topLeft}${horizontalLine(width - 2, headerTitle)}${BOX.topRight}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n // Render hooks (if any)\n if (ir.hooks) {\n const hookLines = renderHooks(ir.hooks, colors);\n for (const line of hookLines) {\n lines.push(\n `${BOX.vertical} ${padEnd(line, innerWidth)}${BOX.vertical}`\n );\n }\n }\n\n // Render children\n const childLines = renderNodes(ir.root.children, options, colors, 0, ir.hooks);\n for (const line of childLines) {\n lines.push(\n `${BOX.vertical} ${padEnd(line, innerWidth)}${BOX.vertical}`\n );\n }\n\n // Footer with timing\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n\n if (ir.root.durationMs !== undefined && options.showTimings) {\n const status = ir.root.state === \"success\" ? \"Completed\" : \"Failed\";\n const statusColored = colorByState(status, ir.root.state, colors);\n const footer = `${statusColored} in ${formatDuration(ir.root.durationMs)}`;\n lines.push(\n `${BOX.vertical} ${padEnd(footer, innerWidth)}${BOX.vertical}`\n );\n lines.push(`${BOX.vertical}${\" \".repeat(width - 2)}${BOX.vertical}`);\n }\n\n lines.push(\n `${BOX.bottomLeft}${BOX.horizontal.repeat(width - 2)}${BOX.bottomRight}`\n );\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render a list of nodes.\n */\nfunction renderNodes(\n nodes: FlowNode[],\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n\n for (const node of nodes) {\n if (isStepNode(node)) {\n lines.push(renderStepNode(node, options, colors, hooks));\n } else if (isParallelNode(node)) {\n lines.push(...renderParallelNode(node, options, colors, depth, hooks));\n } else if (isRaceNode(node)) {\n lines.push(...renderRaceNode(node, options, colors, depth, hooks));\n } else if (isDecisionNode(node)) {\n lines.push(...renderDecisionNode(node, options, colors, depth, hooks));\n }\n }\n\n return lines;\n}\n\n/**\n * Render a single step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n hooks?: WorkflowHooks\n): string {\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? node.key ?? \"step\";\n\n // Check for enhanced options\n const enhanced = options as EnhancedRenderOptions;\n const nodeId = node.name ?? node.id;\n\n // Get heat value for this node (if heatmap is enabled)\n const heat = enhanced.showHeatmap && enhanced.heatmapData\n ? enhanced.heatmapData.heat.get(node.id) ?? enhanced.heatmapData.heat.get(nodeId)\n : undefined;\n\n // Apply heat coloring or default state coloring\n let nameColored: string;\n if (heat !== undefined) {\n nameColored = applyHeatColor(name, heat);\n } else {\n nameColored = colorByState(name, node.state, colors);\n }\n\n let line = `${symbol} ${nameColored}`;\n\n // Add key if requested\n if (options.showKeys && node.key) {\n line += dim(` [key: ${node.key}]`);\n }\n\n // Add input/output if available (for decision understanding)\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\"\n ? node.input\n : JSON.stringify(node.input).slice(0, 30);\n line += dim(` [in: ${inputStr}${inputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? node.output\n : JSON.stringify(node.output).slice(0, 30);\n line += dim(` [out: ${outputStr}${outputStr.length >= 30 ? \"...\" : \"\"}]`);\n }\n\n // Add timing if available and requested\n if (options.showTimings && node.durationMs !== undefined) {\n // Apply heat coloring to timing if enabled\n const timingStr = formatDuration(node.durationMs);\n const timingDisplay = heat !== undefined\n ? applyHeatColor(`[${timingStr}]`, heat)\n : dim(`[${timingStr}]`);\n line += ` ${timingDisplay}`;\n }\n\n // Add sparkline if enabled and history available\n if (enhanced.showSparklines && enhanced.timingHistory) {\n const history = enhanced.timingHistory.get(nodeId);\n if (history && history.length > 1) {\n line += ` ${dim(renderSparkline(history))}`;\n }\n }\n\n // Add retry indicator if retries occurred\n if (node.retryCount !== undefined && node.retryCount > 0) {\n line += dim(` [${node.retryCount} ${node.retryCount === 1 ? \"retry\" : \"retries\"}]`);\n }\n\n // Add timeout indicator if step timed out\n if (node.timedOut) {\n const timeoutInfo = node.timeoutMs !== undefined ? ` ${node.timeoutMs}ms` : \"\";\n line += dim(` [timeout${timeoutInfo}]`);\n }\n\n // Add onAfterStep hook indicator if present\n if (hooks && node.key && hooks.onAfterStep.has(node.key)) {\n const hookExec = hooks.onAfterStep.get(node.key)!;\n const hookSymbol = hookExec.state === \"success\"\n ? colorize(\"⚙\", colors.success)\n : colorize(\"⚠\", colors.error);\n const hookTiming = hookExec.durationMs !== undefined\n ? dim(` ${formatDuration(hookExec.durationMs)}`)\n : \"\";\n line += ` ${hookSymbol}${hookTiming}`;\n }\n\n return line;\n}\n\n/**\n * Render a parallel node (allAsync).\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"parallel\";\n const mode = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n lines.push(`${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${mode}`);\n\n // Children\n if (node.children.length === 0) {\n // Empty parallel scope - operations inside allAsync/anyAsync weren't tracked as steps\n lines.push(`${indent}${BOX.vertical} ${dim(\"(operations not individually tracked)\")}`);\n lines.push(`${indent}${BOX.vertical} ${dim(\"(wrap each operation with step() to see individual steps)\")}`);\n } else {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors, hooks)}`);\n } else {\n // Nested structure - recurse\n const nestedLines = renderNodes([child], options, colors, depth + 1, hooks);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a race node (anyAsync).\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with lightning bolt for race\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"race\";\n lines.push(`${indent}${BOX.teeRight}⚡ ${symbol} ${bold(name)}`);\n\n // Children\n if (node.children.length === 0) {\n // Empty race scope - operations inside anyAsync weren't tracked as steps\n lines.push(`${indent}${BOX.vertical} ${dim(\"(operations not individually tracked)\")}`);\n lines.push(`${indent}${BOX.vertical} ${dim(\"(wrap each operation with step() to see individual steps)\")}`);\n } else {\n for (let i = 0; i < node.children.length; i++) {\n const child = node.children[i];\n const isLast = i === node.children.length - 1;\n const prefix = isLast ? `${indent}${BOX.vertical} ${BOX.bottomLeft}` : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Mark winner\n const isWinner = node.winnerId && child.id === node.winnerId;\n const winnerSuffix = isWinner ? dim(\" (winner)\") : \"\";\n\n if (isStepNode(child)) {\n lines.push(`${prefix} ${renderStepNode(child, options, colors, hooks)}${winnerSuffix}`);\n } else {\n const nestedLines = renderNodes([child], options, colors, depth + 1, hooks);\n for (const line of nestedLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n }\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(`${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`);\n }\n\n return lines;\n}\n\n/**\n * Render a decision node (conditional branch).\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n colors: ReturnType<typeof Object.assign>,\n depth: number,\n hooks?: WorkflowHooks\n): string[] {\n const lines: string[] = [];\n const indent = \" \".repeat(depth);\n\n // Header with decision info\n const symbol = getColoredSymbol(node.state, colors);\n const name = node.name ?? \"decision\";\n const condition = node.condition\n ? dim(` (${node.condition})`)\n : \"\";\n const decisionValue = node.decisionValue !== undefined\n ? dim(` = ${String(node.decisionValue)}`)\n : \"\";\n const branchTaken = node.branchTaken !== undefined\n ? dim(` → ${String(node.branchTaken)}`)\n : \"\";\n\n lines.push(\n `${indent}${BOX.teeRight}${BOX.teeDown}${BOX.horizontal} ${symbol} ${bold(name)}${condition}${decisionValue}${branchTaken}`\n );\n\n // Render branches\n for (let i = 0; i < node.branches.length; i++) {\n const branch = node.branches[i];\n const isLast = i === node.branches.length - 1;\n const prefix = isLast\n ? `${indent}${BOX.vertical} ${BOX.bottomLeft}`\n : `${indent}${BOX.vertical} ${BOX.teeRight}`;\n\n // Branch label with taken/skipped indicator\n const branchSymbol = branch.taken ? \"✓\" : \"⊘\";\n const branchColor = branch.taken ? colors.success : colors.skipped;\n const branchLabel = colorize(\n `${branchSymbol} ${branch.label}`,\n branchColor\n );\n const branchCondition = branch.condition\n ? dim(` (${branch.condition})`)\n : \"\";\n\n lines.push(`${prefix} ${branchLabel}${branchCondition}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n const childLines = renderNodes(branch.children, options, colors, depth + 1, hooks);\n for (const line of childLines) {\n lines.push(`${indent}${BOX.vertical} ${line}`);\n }\n } else if (!branch.taken) {\n // Show that this branch was skipped\n lines.push(\n `${indent}${BOX.vertical} ${dim(\"(skipped)\")}`\n );\n }\n }\n\n // Timing footer\n if (options.showTimings && node.durationMs !== undefined) {\n lines.push(\n `${indent}${BOX.bottomLeft}${BOX.horizontal}${BOX.horizontal} ${dim(`[${formatDuration(node.durationMs)}]`)}`\n );\n }\n\n return lines;\n}\n\nexport { defaultColorScheme };\n","/**\n * Performance Analyzer\n *\n * Analyzes workflow execution data to identify:\n * - Slow steps (bottlenecks)\n * - Retry patterns\n * - Error-prone steps\n * - Timing anomalies\n *\n * Aggregates metrics across multiple workflow runs to provide\n * statistical insights and heatmap visualization data.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n NodePerformance,\n HeatmapData,\n WorkflowIR,\n FlowNode,\n HeatLevel,\n} from \"./types\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * A recorded workflow run for analysis.\n */\nexport interface WorkflowRun {\n /** Unique identifier for this run */\n id: string;\n /** Workflow start timestamp */\n startTime: number;\n /** All events from the workflow execution */\n events: WorkflowEvent<unknown>[];\n}\n\n/**\n * Performance analyzer interface.\n */\nexport interface PerformanceAnalyzer {\n /** Add a completed workflow run for analysis */\n addRun: (run: WorkflowRun) => void;\n\n /** Add events incrementally (alternative to addRun) */\n addEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Finalize current run (when using addEvent) */\n finalizeRun: (runId: string) => void;\n\n /** Get performance stats for a specific node */\n getNodePerformance: (nodeId: string) => NodePerformance | undefined;\n\n /** Get heatmap data for an IR */\n getHeatmap: (\n ir: WorkflowIR,\n metric?: \"duration\" | \"retryRate\" | \"errorRate\"\n ) => HeatmapData;\n\n /** Get slowest nodes */\n getSlowestNodes: (limit?: number) => NodePerformance[];\n\n /** Get error-prone nodes */\n getErrorProneNodes: (limit?: number) => NodePerformance[];\n\n /** Get retry-prone nodes */\n getRetryProneNodes: (limit?: number) => NodePerformance[];\n\n /** Get all performance data */\n getAllPerformance: () => Map<string, NodePerformance>;\n\n /** Export performance data as JSON */\n exportData: () => string;\n\n /** Import performance data from JSON */\n importData: (json: string) => void;\n\n /** Clear all collected data */\n clear: () => void;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Flatten all nodes from an IR tree.\n */\nfunction flattenNodes(nodes: FlowNode[]): FlowNode[] {\n const result: FlowNode[] = [];\n for (const node of nodes) {\n result.push(node);\n if (\"children\" in node && Array.isArray(node.children)) {\n result.push(...flattenNodes(node.children));\n }\n if (\"branches\" in node) {\n for (const branch of node.branches) {\n result.push(...flattenNodes(branch.children));\n }\n }\n }\n return result;\n}\n\n/**\n * Calculate percentile value from sorted array.\n */\nfunction percentile(sortedValues: number[], p: number): number {\n if (sortedValues.length === 0) return 0;\n const index = Math.floor(sortedValues.length * p);\n return sortedValues[Math.min(index, sortedValues.length - 1)];\n}\n\n/**\n * Get heat level from normalized value (0-1).\n */\nexport function getHeatLevel(heat: number): HeatLevel {\n if (heat < 0.2) return \"cold\";\n if (heat < 0.4) return \"cool\";\n if (heat < 0.6) return \"neutral\";\n if (heat < 0.8) return \"warm\";\n if (heat < 0.95) return \"hot\";\n return \"critical\";\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Create a performance analyzer for workflow metrics.\n *\n * @example\n * ```typescript\n * const analyzer = createPerformanceAnalyzer();\n *\n * // Add completed runs\n * analyzer.addRun({ id: 'run-1', startTime: Date.now(), events });\n *\n * // Get insights\n * const slowest = analyzer.getSlowestNodes(5);\n * const heatmap = analyzer.getHeatmap(ir, 'duration');\n * ```\n */\nexport function createPerformanceAnalyzer(): PerformanceAnalyzer {\n // Timing data: nodeId → array of durations (ms)\n const timingData = new Map<string, number[]>();\n\n // Retry data: nodeId → { retried runs, total runs }\n const retryData = new Map<string, { retried: number; total: number }>();\n\n // Error data: nodeId → { error runs, total runs }\n const errorData = new Map<string, { errors: number; total: number }>();\n\n // Timeout data: nodeId → { timed out, total }\n const timeoutData = new Map<string, { timedOut: number; total: number }>();\n\n // Current run state (for incremental event adding)\n let currentRunEvents: WorkflowEvent<unknown>[] = [];\n\n /**\n * Get node ID from event (uses name or stepId).\n */\n function getNodeId(event: {\n stepId?: string;\n stepKey?: string;\n name?: string;\n }): string {\n return event.name ?? event.stepKey ?? event.stepId ?? \"unknown\";\n }\n\n /**\n * Process events from a workflow run.\n */\n function processEvents(events: WorkflowEvent<unknown>[]): void {\n // Track step state during processing\n const stepState = new Map<\n string,\n {\n retried: boolean;\n timedOut: boolean;\n }\n >();\n\n for (const event of events) {\n switch (event.type) {\n case \"step_start\": {\n const id = getNodeId(event);\n stepState.set(id, { retried: false, timedOut: false });\n break;\n }\n\n case \"step_retry\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n if (state) {\n state.retried = true;\n }\n break;\n }\n\n case \"step_timeout\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n if (state) {\n state.timedOut = true;\n }\n // Track timeout stats\n const timeout = timeoutData.get(id) ?? { timedOut: 0, total: 0 };\n timeout.timedOut++;\n timeout.total++;\n timeoutData.set(id, timeout);\n break;\n }\n\n case \"step_success\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n\n // Record timing\n const timings = timingData.get(id) ?? [];\n timings.push(event.durationMs);\n timingData.set(id, timings);\n\n // Record retry status\n const retry = retryData.get(id) ?? { retried: 0, total: 0 };\n retry.total++;\n if (state?.retried) retry.retried++;\n retryData.set(id, retry);\n\n // Record success (no error)\n const error = errorData.get(id) ?? { errors: 0, total: 0 };\n error.total++;\n errorData.set(id, error);\n\n stepState.delete(id);\n break;\n }\n\n case \"step_error\": {\n const id = getNodeId(event);\n const state = stepState.get(id);\n\n // Record timing\n const timings = timingData.get(id) ?? [];\n timings.push(event.durationMs);\n timingData.set(id, timings);\n\n // Record retry status\n const retry = retryData.get(id) ?? { retried: 0, total: 0 };\n retry.total++;\n if (state?.retried) retry.retried++;\n retryData.set(id, retry);\n\n // Record error\n const error = errorData.get(id) ?? { errors: 0, total: 0 };\n error.total++;\n error.errors++;\n errorData.set(id, error);\n\n stepState.delete(id);\n break;\n }\n }\n }\n }\n\n /**\n * Add a completed workflow run.\n */\n function addRun(run: WorkflowRun): void {\n processEvents(run.events);\n }\n\n /**\n * Add an event incrementally.\n */\n function addEvent(event: WorkflowEvent<unknown>): void {\n currentRunEvents.push(event);\n }\n\n /**\n * Finalize current run (process accumulated events).\n */\n function finalizeRun(_runId: string): void {\n if (currentRunEvents.length > 0) {\n processEvents(currentRunEvents);\n currentRunEvents = [];\n }\n }\n\n /**\n * Compute performance metrics for a node.\n */\n function computePerformance(nodeId: string): NodePerformance | undefined {\n const timings = timingData.get(nodeId);\n if (!timings || timings.length === 0) return undefined;\n\n const sorted = [...timings].sort((a, b) => a - b);\n const sum = sorted.reduce((a, b) => a + b, 0);\n const mean = sum / sorted.length;\n const variance =\n sorted.reduce((acc, t) => acc + (t - mean) ** 2, 0) / sorted.length;\n\n const retry = retryData.get(nodeId) ?? { retried: 0, total: 1 };\n const error = errorData.get(nodeId) ?? { errors: 0, total: 1 };\n const timeout = timeoutData.get(nodeId) ?? { timedOut: 0, total: 1 };\n\n return {\n nodeId,\n avgDurationMs: mean,\n minDurationMs: sorted[0],\n maxDurationMs: sorted[sorted.length - 1],\n stdDevMs: Math.sqrt(variance),\n samples: sorted.length,\n retryRate: retry.total > 0 ? retry.retried / retry.total : 0,\n timeoutRate: timeout.total > 0 ? timeout.timedOut / timeout.total : 0,\n errorRate: error.total > 0 ? error.errors / error.total : 0,\n percentiles: {\n p50: percentile(sorted, 0.5),\n p90: percentile(sorted, 0.9),\n p95: percentile(sorted, 0.95),\n p99: percentile(sorted, 0.99),\n },\n };\n }\n\n /**\n * Get performance stats for a specific node.\n */\n function getNodePerformance(nodeId: string): NodePerformance | undefined {\n return computePerformance(nodeId);\n }\n\n /**\n * Get heatmap data for an IR.\n */\n function getHeatmap(\n ir: WorkflowIR,\n metric: \"duration\" | \"retryRate\" | \"errorRate\" = \"duration\"\n ): HeatmapData {\n const heat = new Map<string, number>();\n const allNodes = flattenNodes(ir.root.children);\n\n // Compute values for all nodes\n const values: Array<{ id: string; value: number }> = [];\n for (const node of allNodes) {\n // Try node.name first, then node.id\n const nodeId = node.name ?? node.id;\n const perf = computePerformance(nodeId);\n if (perf) {\n let value: number;\n switch (metric) {\n case \"duration\":\n value = perf.avgDurationMs;\n break;\n case \"retryRate\":\n value = perf.retryRate;\n break;\n case \"errorRate\":\n value = perf.errorRate;\n break;\n }\n values.push({ id: node.id, value });\n }\n }\n\n if (values.length === 0) {\n return {\n heat,\n metric,\n stats: { min: 0, max: 0, mean: 0, threshold: 0 },\n };\n }\n\n // Compute statistics\n const vals = values.map((v) => v.value);\n const min = Math.min(...vals);\n const max = Math.max(...vals);\n const mean = vals.reduce((a, b) => a + b, 0) / vals.length;\n const range = max - min || 1;\n\n // Normalize to 0-1 heat values\n for (const { id, value } of values) {\n heat.set(id, (value - min) / range);\n }\n\n return {\n heat,\n metric,\n stats: {\n min,\n max,\n mean,\n threshold: mean + (max - mean) * 0.5, // 50% above mean is \"hot\"\n },\n };\n }\n\n /**\n * Get all performance data.\n */\n function getAllPerformance(): Map<string, NodePerformance> {\n const result = new Map<string, NodePerformance>();\n for (const nodeId of timingData.keys()) {\n const perf = computePerformance(nodeId);\n if (perf) result.set(nodeId, perf);\n }\n return result;\n }\n\n /**\n * Get slowest nodes by average duration.\n */\n function getSlowestNodes(limit = 10): NodePerformance[] {\n const all = getAllPerformance();\n return [...all.values()]\n .sort((a, b) => b.avgDurationMs - a.avgDurationMs)\n .slice(0, limit);\n }\n\n /**\n * Get error-prone nodes by error rate.\n */\n function getErrorProneNodes(limit = 10): NodePerformance[] {\n const all = getAllPerformance();\n return [...all.values()]\n .filter((p) => p.errorRate > 0)\n .sort((a, b) => b.errorRate - a.errorRate)\n .slice(0, limit);\n }\n\n /**\n * Get retry-prone nodes by retry rate.\n */\n function getRetryProneNodes(limit = 10): NodePerformance[] {\n const all = getAllPerformance();\n return [...all.values()]\n .filter((p) => p.retryRate > 0)\n .sort((a, b) => b.retryRate - a.retryRate)\n .slice(0, limit);\n }\n\n /**\n * Export performance data as JSON.\n */\n function exportData(): string {\n return JSON.stringify({\n timingData: Object.fromEntries(timingData),\n retryData: Object.fromEntries(retryData),\n errorData: Object.fromEntries(errorData),\n timeoutData: Object.fromEntries(timeoutData),\n });\n }\n\n /**\n * Import performance data from JSON.\n */\n function importData(json: string): void {\n const data = JSON.parse(json) as {\n timingData?: Record<string, number[]>;\n retryData?: Record<string, { retried: number; total: number }>;\n errorData?: Record<string, { errors: number; total: number }>;\n timeoutData?: Record<string, { timedOut: number; total: number }>;\n };\n\n // Clear existing data\n timingData.clear();\n retryData.clear();\n errorData.clear();\n timeoutData.clear();\n\n // Import timing data\n for (const [k, v] of Object.entries(data.timingData ?? {})) {\n timingData.set(k, v);\n }\n\n // Import retry data\n for (const [k, v] of Object.entries(data.retryData ?? {})) {\n retryData.set(k, v);\n }\n\n // Import error data\n for (const [k, v] of Object.entries(data.errorData ?? {})) {\n errorData.set(k, v);\n }\n\n // Import timeout data\n for (const [k, v] of Object.entries(data.timeoutData ?? {})) {\n timeoutData.set(k, v);\n }\n }\n\n /**\n * Clear all collected data.\n */\n function clear(): void {\n timingData.clear();\n retryData.clear();\n errorData.clear();\n timeoutData.clear();\n currentRunEvents = [];\n }\n\n return {\n addRun,\n addEvent,\n finalizeRun,\n getNodePerformance,\n getHeatmap,\n getSlowestNodes,\n getErrorProneNodes,\n getRetryProneNodes,\n getAllPerformance,\n exportData,\n importData,\n clear,\n };\n}\n","/**\n * Mermaid Diagram Renderer\n *\n * Renders the workflow IR as a Mermaid flowchart diagram.\n * Supports sequential flows, parallel (subgraph), and race patterns.\n */\n\nimport type {\n FlowNode,\n ParallelNode,\n RaceNode,\n DecisionNode,\n Renderer,\n RenderOptions,\n MermaidRenderOptions,\n StepNode,\n StepState,\n WorkflowIR,\n EnhancedRenderOptions,\n HeatLevel,\n WorkflowHooks,\n} from \"../types\";\nimport { isParallelNode, isRaceNode, isStepNode, isDecisionNode } from \"../types\";\nimport { formatDuration } from \"../utils/timing\";\nimport { getHeatLevel } from \"../performance-analyzer\";\n\n// =============================================================================\n// Mermaid Style Definitions\n// =============================================================================\n\n/**\n * Get Mermaid class definition for step states.\n * Colors inspired by AWS Step Functions and XState visualizers for professional appearance.\n */\nfunction getStyleDefinitions(): string[] {\n return [\n // Pending - light gray, subtle\n \" classDef pending fill:#f3f4f6,stroke:#9ca3af,stroke-width:2px,color:#374151\",\n // Running - amber/yellow, indicates active execution\n \" classDef running fill:#fef3c7,stroke:#f59e0b,stroke-width:3px,color:#92400e\",\n // Success - green, clear positive indicator\n \" classDef success fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#065f46\",\n // Error - red, clear negative indicator\n \" classDef error fill:#fee2e2,stroke:#ef4444,stroke-width:3px,color:#991b1b\",\n // Aborted - gray, indicates cancellation\n \" classDef aborted fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#4b5563,stroke-dasharray: 5 5\",\n // Cached - blue, indicates cache hit\n \" classDef cached fill:#dbeafe,stroke:#3b82f6,stroke-width:3px,color:#1e40af\",\n // Skipped - light gray with dashed border\n \" classDef skipped fill:#f9fafb,stroke:#d1d5db,stroke-width:2px,color:#6b7280,stroke-dasharray: 5 5\",\n ];\n}\n\n/**\n * Get Mermaid class definitions for heatmap visualization.\n */\nfunction getHeatmapStyleDefinitions(): string[] {\n return [\n // Heatmap colors - cold to hot\n \" classDef heat_cold fill:#dbeafe,stroke:#3b82f6,stroke-width:2px,color:#1e40af\",\n \" classDef heat_cool fill:#ccfbf1,stroke:#14b8a6,stroke-width:2px,color:#0f766e\",\n \" classDef heat_neutral fill:#f3f4f6,stroke:#6b7280,stroke-width:2px,color:#374151\",\n \" classDef heat_warm fill:#fef3c7,stroke:#f59e0b,stroke-width:2px,color:#92400e\",\n \" classDef heat_hot fill:#fed7aa,stroke:#f97316,stroke-width:3px,color:#c2410c\",\n \" classDef heat_critical fill:#fecaca,stroke:#ef4444,stroke-width:3px,color:#b91c1c\",\n ];\n}\n\n/**\n * Get the Mermaid class name for a heat level.\n */\nfunction getHeatClass(level: HeatLevel): string {\n return `heat_${level}`;\n}\n\n/**\n * Get the Mermaid class name for a step state.\n */\nfunction getStateClass(state: StepState): string {\n return state;\n}\n\n/**\n * Get Mermaid class definitions for hook visualization.\n */\nfunction getHookStyleDefinitions(): string[] {\n return [\n // Hook styles - gear icon aesthetic\n \" classDef hook_success fill:#e0f2fe,stroke:#0284c7,stroke-width:2px,color:#0c4a6e\",\n \" classDef hook_error fill:#fef2f2,stroke:#dc2626,stroke-width:2px,color:#7f1d1d\",\n ];\n}\n\n/**\n * Render hooks as nodes before the workflow starts.\n * Returns the ID of the last hook node (to connect to workflow start).\n */\nfunction renderHooks(\n hooks: WorkflowHooks,\n lines: string[],\n options: RenderOptions\n): { lastHookId: string | undefined } {\n let lastHookId: string | undefined;\n\n // Render shouldRun hook\n if (hooks.shouldRun) {\n const hookId = \"hook_shouldRun\";\n const state = hooks.shouldRun.state === \"success\" ? \"hook_success\" : \"hook_error\";\n const icon = hooks.shouldRun.state === \"success\" ? \"⚙\" : \"⚠\";\n const timing = options.showTimings && hooks.shouldRun.durationMs !== undefined\n ? ` ${formatDuration(hooks.shouldRun.durationMs)}`\n : \"\";\n const context = hooks.shouldRun.context?.skipped\n ? \"\\\\nskipped workflow\"\n : hooks.shouldRun.context?.result === true\n ? \"\\\\nproceed\"\n : \"\";\n\n lines.push(` ${hookId}[[\"${icon} shouldRun${context}${timing}\"]]:::${state}`);\n lastHookId = hookId;\n }\n\n // Render onBeforeStart hook\n if (hooks.onBeforeStart) {\n const hookId = \"hook_beforeStart\";\n const state = hooks.onBeforeStart.state === \"success\" ? \"hook_success\" : \"hook_error\";\n const icon = hooks.onBeforeStart.state === \"success\" ? \"⚙\" : \"⚠\";\n const timing = options.showTimings && hooks.onBeforeStart.durationMs !== undefined\n ? ` ${formatDuration(hooks.onBeforeStart.durationMs)}`\n : \"\";\n const context = hooks.onBeforeStart.context?.skipped\n ? \"\\\\nskipped workflow\"\n : \"\";\n\n lines.push(` ${hookId}[[\"${icon} onBeforeStart${context}${timing}\"]]:::${state}`);\n\n // Connect from previous hook if exists\n if (lastHookId) {\n lines.push(` ${lastHookId} --> ${hookId}`);\n }\n lastHookId = hookId;\n }\n\n return { lastHookId };\n}\n\n// =============================================================================\n// Node ID Generation\n// =============================================================================\n\nlet nodeCounter = 0;\n\nfunction generateNodeId(prefix: string = \"node\"): string {\n return `${prefix}_${++nodeCounter}`;\n}\n\nfunction resetNodeCounter(): void {\n nodeCounter = 0;\n}\n\n// =============================================================================\n// Mermaid Text Escaping\n// =============================================================================\n\n/**\n * Escape text for use in Mermaid diagrams.\n * Removes characters that break Mermaid parsing.\n * \n * Characters removed:\n * - {}[]() - Brackets and parentheses break parsing in labels\n * - <> - Angle brackets can cause issues\n * - \" - Double quotes replaced with single quotes\n * \n * @param text - Text to escape\n * @returns Escaped text safe for Mermaid\n */\nfunction escapeMermaidText(text: string): string {\n return text\n .replace(/[{}[\\]()]/g, \"\") // Remove brackets and parentheses (they break parsing)\n .replace(/[<>]/g, \"\") // Remove angle brackets\n .replace(/\"/g, \"'\") // Replace double quotes with single\n .trim();\n}\n\n/**\n * Escape text for use in Mermaid subgraph names.\n * Subgraph names in brackets need special handling.\n * \n * @param text - Text to escape for subgraph name\n * @returns Escaped text safe for subgraph names\n */\nfunction escapeSubgraphName(text: string): string {\n return escapeMermaidText(text)\n .replace(/[[\\]]/g, \"\"); // Also remove brackets from subgraph names\n}\n\n// =============================================================================\n// Mermaid Renderer\n// =============================================================================\n\n/**\n * Create the Mermaid diagram renderer.\n */\nexport function mermaidRenderer(): Renderer {\n return {\n name: \"mermaid\",\n supportsLive: false,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n resetNodeCounter();\n const lines: string[] = [];\n\n // Check for enhanced options (heatmap)\n const enhanced = options as EnhancedRenderOptions;\n\n // Diagram header\n lines.push(\"flowchart TD\");\n\n // Render hooks first (if any)\n let hookExitId: string | undefined;\n if (ir.hooks) {\n const hookResult = renderHooks(ir.hooks, lines, options);\n hookExitId = hookResult.lastHookId;\n }\n\n // Start node - more visually distinctive\n const startId = \"start\";\n lines.push(` ${startId}((\"▶ Start\"))`);\n\n // Connect hooks to start node\n if (hookExitId) {\n lines.push(` ${hookExitId} --> ${startId}`);\n }\n\n // Track the last node for connections\n let prevNodeId = startId;\n\n // Render children (passing hooks for onAfterStep annotations)\n for (const child of ir.root.children) {\n const result = renderNode(child, options, lines, enhanced, ir.hooks);\n lines.push(` ${prevNodeId} --> ${result.entryId}`);\n prevNodeId = result.exitId;\n }\n\n // End node (if workflow completed) - more visually distinctive\n if (ir.root.state === \"success\" || ir.root.state === \"error\") {\n const endId = \"finish\";\n const endIcon = ir.root.state === \"success\" ? \"✓\" : \"✗\";\n const endLabel = ir.root.state === \"success\" ? \"Done\" : \"Failed\";\n const endShape = `((\"${endIcon} ${endLabel}\"))`;\n const endClass =\n ir.root.state === \"success\" ? \":::success\" : \":::error\";\n lines.push(` ${endId}${endShape}${endClass}`);\n lines.push(` ${prevNodeId} --> ${endId}`);\n }\n\n // Add style definitions\n lines.push(\"\");\n lines.push(...getStyleDefinitions());\n\n // Add heatmap styles if enabled\n if (enhanced.showHeatmap) {\n lines.push(...getHeatmapStyleDefinitions());\n }\n\n // Add hook styles if hooks were rendered\n if (ir.hooks) {\n lines.push(...getHookStyleDefinitions());\n }\n\n return lines.join(\"\\n\");\n },\n };\n}\n\n/**\n * Render result with entry and exit node IDs.\n */\ninterface RenderResult {\n entryId: string;\n exitId: string;\n}\n\n/**\n * Render a node and return its entry/exit IDs.\n */\nfunction renderNode(\n node: FlowNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n if (isStepNode(node)) {\n return renderStepNode(node, options, lines, enhanced, hooks);\n } else if (isParallelNode(node)) {\n return renderParallelNode(node, options, lines, enhanced, hooks);\n } else if (isRaceNode(node)) {\n return renderRaceNode(node, options, lines, enhanced, hooks);\n } else if (isDecisionNode(node)) {\n return renderDecisionNode(node, options, lines, enhanced, hooks);\n }\n\n // Fallback for sequence or unknown nodes\n const id = generateNodeId(\"unknown\");\n lines.push(` ${id}[Unknown Node]`);\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a step node.\n */\nfunction renderStepNode(\n node: StepNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n // Cast to MermaidRenderOptions to access extended options\n const mermaidOpts = options as MermaidRenderOptions;\n const showRetryEdges = mermaidOpts.showRetryEdges ?? true;\n const showErrorEdges = mermaidOpts.showErrorEdges ?? true;\n const showTimeoutEdges = mermaidOpts.showTimeoutEdges ?? true;\n\n const id = node.key\n ? `step_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"step\");\n\n const label = escapeMermaidText(node.name ?? node.key ?? \"Step\");\n\n // Format timing - use space instead of parentheses to avoid Mermaid parse errors\n const timing =\n options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n\n // Add visual indicators based on state (like XState/AWS Step Functions)\n let stateIcon = \"\";\n switch (node.state) {\n case \"success\":\n stateIcon = \"✓ \";\n break;\n case \"error\":\n stateIcon = \"✗ \";\n break;\n case \"cached\":\n stateIcon = \"💾 \";\n break;\n case \"running\":\n stateIcon = \"⏳ \";\n break;\n case \"skipped\":\n stateIcon = \"⊘ \";\n break;\n }\n\n // Add input/output info if available\n // Use newlines for multi-line labels, but escape special characters\n let ioInfo = \"\";\n if (node.input !== undefined) {\n const inputStr = typeof node.input === \"string\"\n ? escapeMermaidText(node.input)\n : escapeMermaidText(JSON.stringify(node.input).slice(0, 20));\n ioInfo += `\\\\nin: ${inputStr}`;\n }\n if (node.output !== undefined && node.state === \"success\") {\n const outputStr = typeof node.output === \"string\"\n ? escapeMermaidText(node.output)\n : escapeMermaidText(JSON.stringify(node.output).slice(0, 20));\n ioInfo += `\\\\nout: ${outputStr}`;\n }\n\n // Add onAfterStep hook info if present\n let hookInfo = \"\";\n if (hooks && node.key && hooks.onAfterStep.has(node.key)) {\n const hookExec = hooks.onAfterStep.get(node.key)!;\n const hookIcon = hookExec.state === \"success\" ? \"⚙\" : \"⚠\";\n const hookTiming = options.showTimings && hookExec.durationMs !== undefined\n ? ` ${formatDuration(hookExec.durationMs)}`\n : \"\";\n hookInfo = `\\\\n${hookIcon} hook${hookTiming}`;\n }\n\n // Combine all label parts with icon (retry/timeout info moved to edges)\n const escapedLabel = (stateIcon + label + ioInfo + hookInfo + timing).trim();\n\n // Determine class: use heatmap if enabled and data available, otherwise use state\n let nodeClass: string;\n const nodeId = node.name ?? node.id;\n const heat = enhanced?.showHeatmap && enhanced.heatmapData\n ? enhanced.heatmapData.heat.get(node.id) ?? enhanced.heatmapData.heat.get(nodeId)\n : undefined;\n\n if (heat !== undefined) {\n const level = getHeatLevel(heat);\n nodeClass = getHeatClass(level);\n } else {\n nodeClass = getStateClass(node.state);\n }\n\n // Use different shapes based on state (like AWS Step Functions)\n let shape: string;\n switch (node.state) {\n case \"error\":\n // Hexagon for errors (more distinctive)\n shape = `{{${escapedLabel}}}`;\n break;\n case \"cached\":\n // Rounded rectangle with double border for cached\n shape = `[(${escapedLabel})]`;\n break;\n case \"skipped\":\n // Dashed border for skipped\n shape = `[${escapedLabel}]:::skipped`;\n break;\n default:\n // Standard rectangle for normal steps\n shape = `[${escapedLabel}]`;\n }\n\n lines.push(` ${id}${shape}:::${nodeClass}`);\n\n // NEW: Add retry loop edge (self-loop showing retries)\n if (showRetryEdges && node.retryCount !== undefined && node.retryCount > 0) {\n const retryLabel = `↻ ${node.retryCount} retr${node.retryCount === 1 ? \"y\" : \"ies\"}`;\n lines.push(` ${id} -.->|\"${retryLabel}\"| ${id}`);\n }\n\n // NEW: Add error path edge (flow to error node)\n if (showErrorEdges && node.state === \"error\" && node.error !== undefined) {\n const errorNodeId = `ERR_${id}`;\n const errorLabel = escapeMermaidText(String(node.error)).slice(0, 30);\n lines.push(` ${errorNodeId}{{${errorLabel}}}`);\n lines.push(` ${id} -->|error| ${errorNodeId}`);\n lines.push(` style ${errorNodeId} fill:#fee2e2,stroke:#dc2626`);\n }\n\n // NEW: Add timeout edge (alternative timeout path)\n if (showTimeoutEdges && node.timedOut) {\n const timeoutNodeId = `TO_${id}`;\n const timeoutMs = node.timeoutMs !== undefined ? `${node.timeoutMs}ms` : \"\";\n lines.push(` ${timeoutNodeId}{{⏱ Timeout ${timeoutMs}}}`);\n lines.push(` ${id} -.->|timeout| ${timeoutNodeId}`);\n lines.push(` style ${timeoutNodeId} fill:#fef3c7,stroke:#f59e0b`);\n }\n\n return { entryId: id, exitId: id };\n}\n\n/**\n * Render a parallel node as a subgraph with fork/join.\n */\nfunction renderParallelNode(\n node: ParallelNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n const subgraphId = generateNodeId(\"parallel\");\n const forkId = `${subgraphId}_fork`;\n const joinId = `${subgraphId}_join`;\n const name = escapeSubgraphName(node.name ?? \"Parallel\");\n const modeLabel = node.mode === \"allSettled\" ? \" (allSettled)\" : \"\";\n\n // If no children, render as a simple step-like node with note\n if (node.children.length === 0) {\n const id = subgraphId;\n const label = escapeMermaidText(`${name}${modeLabel}`);\n const note = \"operations not individually tracked\";\n const timing = options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n \n // Use a rounded rectangle to indicate it's a parallel operation\n lines.push(` ${id}[${label}${timing}\\\\n${note}]:::${getStateClass(node.state)}`);\n return { entryId: id, exitId: id };\n }\n\n // Subgraph for parallel block with proper visual hierarchy\n lines.push(` subgraph ${subgraphId}[\"${name}${modeLabel}\"]`);\n lines.push(` direction TB`);\n\n // Fork node (diamond) - more visually distinct\n lines.push(` ${forkId}{\"⚡ Fork\"}`);\n\n // Child branches - render in parallel columns\n const childExitIds: string[] = [];\n for (const child of node.children) {\n const result = renderNode(child, options, lines, enhanced, hooks);\n lines.push(` ${forkId} --> ${result.entryId}`);\n childExitIds.push(result.exitId);\n }\n\n // Join node (diamond) - visually distinct\n lines.push(` ${joinId}{\"✓ Join\"}`);\n for (const exitId of childExitIds) {\n lines.push(` ${exitId} --> ${joinId}`);\n }\n\n lines.push(` end`);\n\n // Apply state styling to subgraph\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: forkId, exitId: joinId };\n}\n\n/**\n * Render a race node as a subgraph with racing indicator.\n */\nfunction renderRaceNode(\n node: RaceNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n const subgraphId = generateNodeId(\"race\");\n const startId = `${subgraphId}_start`;\n const endId = `${subgraphId}_end`;\n const name = escapeSubgraphName(node.name ?? \"Race\");\n\n // If no children, render as a simple step-like node with note\n if (node.children.length === 0) {\n const id = subgraphId;\n const label = escapeMermaidText(name);\n const note = \"operations not individually tracked\";\n const timing = options.showTimings && node.durationMs !== undefined\n ? ` ${formatDuration(node.durationMs)}`\n : \"\";\n \n lines.push(` ${id}[⚡ ${label}${timing}\\\\n${note}]:::${getStateClass(node.state)}`);\n return { entryId: id, exitId: id };\n }\n\n // Subgraph for race block - escape name and emoji is safe in quoted strings\n lines.push(` subgraph ${subgraphId}[\"⚡ ${name}\"]`);\n lines.push(` direction TB`);\n\n // Start node - use a more distinctive shape\n lines.push(` ${startId}((\"🏁 Start\"))`);\n\n // Child branches\n const childExitIds: Array<{ exitId: string; isWinner: boolean }> = [];\n let winnerExitId: string | undefined;\n\n for (const child of node.children) {\n const result = renderNode(child, options, lines, enhanced, hooks);\n const isWinner = isStepNode(child) && node.winnerId === child.id;\n lines.push(` ${startId} --> ${result.entryId}`);\n\n if (isWinner) {\n winnerExitId = result.exitId;\n }\n childExitIds.push({ exitId: result.exitId, isWinner });\n }\n\n // End node - more distinctive\n lines.push(` ${endId}((\"✓ First\"))`);\n \n // Connect winner with thick line, others with dashed (cancelled)\n for (const { exitId, isWinner } of childExitIds) {\n if (isWinner && winnerExitId) {\n lines.push(` ${exitId} ==>|🏆 Winner| ${endId}`);\n } else if (node.winnerId) {\n // Non-winner: show as cancelled\n lines.push(` ${exitId} -. cancelled .-> ${endId}`);\n } else {\n // No winner determined, normal connection\n lines.push(` ${exitId} --> ${endId}`);\n }\n }\n\n lines.push(` end`);\n\n const stateClass = getStateClass(node.state);\n lines.push(` class ${subgraphId} ${stateClass}`);\n\n return { entryId: startId, exitId: endId };\n}\n\n/**\n * Render a decision node as a diamond with branches.\n */\nfunction renderDecisionNode(\n node: DecisionNode,\n options: RenderOptions,\n lines: string[],\n enhanced?: EnhancedRenderOptions,\n hooks?: WorkflowHooks\n): RenderResult {\n const decisionId = node.key\n ? `decision_${node.key.replace(/[^a-zA-Z0-9]/g, \"_\")}`\n : generateNodeId(\"decision\");\n\n // Escape condition and decision value - remove characters that break Mermaid\n const condition = escapeMermaidText(node.condition ?? \"condition\");\n const decisionValue = node.decisionValue !== undefined\n ? ` = ${escapeMermaidText(String(node.decisionValue)).slice(0, 30)}`\n : \"\";\n\n // Decision diamond - ensure no invalid characters\n const decisionLabel = `${condition}${decisionValue}`.trim();\n lines.push(` ${decisionId}{${decisionLabel}}`);\n\n // Render branches\n const branchExitIds: string[] = [];\n let takenBranchExitId: string | undefined;\n\n for (const branch of node.branches) {\n const branchId = `${decisionId}_${branch.label.replace(/[^a-zA-Z0-9]/g, \"_\")}`;\n // Escape branch label - remove parentheses and other special chars\n const branchLabelText = escapeMermaidText(branch.label);\n const branchLabel = branch.taken\n ? `${branchLabelText} ✓`\n : `${branchLabelText} skipped`;\n const branchClass = branch.taken ? \":::success\" : \":::skipped\";\n\n // Branch label node\n lines.push(` ${branchId}[${branchLabel}]${branchClass}`);\n\n // Connect decision to branch\n // Mermaid edge labels must be simple text - escape special characters\n // Also remove pipe character as it's used for edge label syntax\n const edgeLabel = branch.condition \n ? `|${escapeMermaidText(branch.condition).replace(/\\|/g, \"\")}|` \n : \"\";\n lines.push(` ${decisionId} -->${edgeLabel} ${branchId}`);\n\n // Render children of this branch\n if (branch.children.length > 0) {\n let prevId = branchId;\n for (const child of branch.children) {\n const result = renderNode(child, options, lines, enhanced, hooks);\n lines.push(` ${prevId} --> ${result.entryId}`);\n prevId = result.exitId;\n }\n branchExitIds.push(prevId);\n if (branch.taken) {\n takenBranchExitId = prevId;\n }\n } else {\n branchExitIds.push(branchId);\n if (branch.taken) {\n takenBranchExitId = branchId;\n }\n }\n }\n\n // Join point (if we have a taken branch)\n if (takenBranchExitId) {\n return { entryId: decisionId, exitId: takenBranchExitId };\n }\n\n // If no branch was taken, return decision as exit\n return { entryId: decisionId, exitId: decisionId };\n}\n\nexport { mermaidRenderer as default };\n","/**\n * Logger Renderer - Outputs structured JSON optimized for logging systems.\n *\n * Works with any structured logger (Pino, Winston, Bunyan, console).\n * Includes workflow summary, step details, and optional ASCII diagram.\n *\n * @example\n * ```typescript\n * const logData = JSON.parse(viz.renderAs('logger'));\n * logger.info(logData, 'Workflow completed');\n * ```\n */\n\nimport type {\n Renderer,\n RenderOptions,\n WorkflowIR,\n FlowNode,\n StepNode,\n WorkflowHooks,\n} from \"../types\";\nimport { isStepNode, isSequenceNode, isParallelNode, isRaceNode, isDecisionNode } from \"../types\";\nimport { asciiRenderer } from \"./ascii\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Step log entry with execution details.\n */\nexport interface StepLog {\n id: string;\n name: string;\n key?: string;\n state: string;\n durationMs?: number;\n startTs?: number;\n endTs?: number;\n retryCount?: number;\n timedOut?: boolean;\n timeoutMs?: number;\n error?: string;\n}\n\n/**\n * Hook execution log entry.\n */\nexport interface HookLog {\n shouldRun?: {\n result?: boolean;\n durationMs?: number;\n error?: string;\n };\n onBeforeStart?: {\n durationMs?: number;\n error?: string;\n };\n onAfterStep?: Array<{\n stepKey: string;\n durationMs?: number;\n error?: string;\n }>;\n}\n\n/**\n * Summary statistics for the workflow.\n */\nexport interface WorkflowSummary {\n totalSteps: number;\n successCount: number;\n errorCount: number;\n cacheHits: number;\n skippedCount: number;\n totalRetries: number;\n slowestStep?: { name: string; durationMs: number };\n}\n\n/**\n * Complete logger output structure.\n */\nexport interface LoggerOutput {\n workflow: {\n id: string;\n name?: string;\n state: string;\n durationMs?: number;\n startedAt?: number;\n completedAt?: number;\n };\n steps: StepLog[];\n summary: WorkflowSummary;\n hooks?: HookLog;\n diagram?: string;\n}\n\n/**\n * Extended render options for logger renderer.\n */\nexport interface LoggerRenderOptions extends RenderOptions {\n /** Include ASCII diagram in output (default: true) */\n includeDiagram?: boolean;\n /** Strip ANSI color codes from diagram (default: true) */\n stripAnsiColors?: boolean;\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Strip ANSI escape codes from a string.\n */\nfunction stripAnsi(str: string): string {\n // eslint-disable-next-line no-control-regex\n return str.replace(/\\x1b\\[[0-9;]*m/g, \"\");\n}\n\n/**\n * Collect all step nodes from the IR tree.\n */\nfunction collectSteps(nodes: FlowNode[]): StepNode[] {\n const steps: StepNode[] = [];\n\n function walk(nodeList: FlowNode[]): void {\n for (const node of nodeList) {\n if (isStepNode(node)) {\n steps.push(node);\n } else if (isSequenceNode(node)) {\n walk(node.children);\n } else if (isParallelNode(node) || isRaceNode(node)) {\n walk(node.children);\n } else if (isDecisionNode(node)) {\n for (const branch of node.branches) {\n walk(branch.children);\n }\n }\n }\n }\n\n walk(nodes);\n return steps;\n}\n\n/**\n * Convert a step node to a log entry.\n */\nfunction stepToLog(step: StepNode): StepLog {\n const log: StepLog = {\n id: step.id,\n name: step.name ?? step.key ?? step.id,\n state: step.state,\n };\n\n if (step.key) log.key = step.key;\n if (step.durationMs !== undefined) log.durationMs = step.durationMs;\n if (step.startTs !== undefined) log.startTs = step.startTs;\n if (step.endTs !== undefined) log.endTs = step.endTs;\n if (step.retryCount !== undefined && step.retryCount > 0) log.retryCount = step.retryCount;\n if (step.timedOut) {\n log.timedOut = true;\n if (step.timeoutMs !== undefined) log.timeoutMs = step.timeoutMs;\n }\n if (step.error !== undefined) {\n log.error = typeof step.error === \"string\" ? step.error : String(step.error);\n }\n\n return log;\n}\n\n/**\n * Calculate summary statistics from steps.\n */\nfunction calculateSummary(steps: StepNode[]): WorkflowSummary {\n let successCount = 0;\n let errorCount = 0;\n let cacheHits = 0;\n let skippedCount = 0;\n let totalRetries = 0;\n let slowestStep: { name: string; durationMs: number } | undefined;\n\n for (const step of steps) {\n if (step.state === \"success\") successCount++;\n if (step.state === \"error\") errorCount++;\n if (step.state === \"cached\") cacheHits++;\n if (step.state === \"skipped\") skippedCount++;\n if (step.retryCount !== undefined) totalRetries += step.retryCount;\n\n if (step.durationMs !== undefined) {\n if (!slowestStep || step.durationMs > slowestStep.durationMs) {\n slowestStep = {\n name: step.name ?? step.key ?? step.id,\n durationMs: step.durationMs,\n };\n }\n }\n }\n\n return {\n totalSteps: steps.length,\n successCount,\n errorCount,\n cacheHits,\n skippedCount,\n totalRetries,\n slowestStep,\n };\n}\n\n/**\n * Convert hooks to log format.\n */\nfunction hooksToLog(hooks: WorkflowHooks): HookLog {\n const log: HookLog = {};\n\n if (hooks.shouldRun) {\n log.shouldRun = {\n result: hooks.shouldRun.context?.result,\n durationMs: hooks.shouldRun.durationMs,\n };\n if (hooks.shouldRun.error) {\n log.shouldRun.error = String(hooks.shouldRun.error);\n }\n }\n\n if (hooks.onBeforeStart) {\n log.onBeforeStart = {\n durationMs: hooks.onBeforeStart.durationMs,\n };\n if (hooks.onBeforeStart.error) {\n log.onBeforeStart.error = String(hooks.onBeforeStart.error);\n }\n }\n\n if (hooks.onAfterStep.size > 0) {\n log.onAfterStep = [];\n for (const [stepKey, hook] of hooks.onAfterStep) {\n const entry: { stepKey: string; durationMs?: number; error?: string } = { stepKey };\n if (hook.durationMs !== undefined) entry.durationMs = hook.durationMs;\n if (hook.error) entry.error = String(hook.error);\n log.onAfterStep.push(entry);\n }\n }\n\n return log;\n}\n\n/**\n * Build the complete logger output from IR.\n */\nfunction buildLoggerOutput(ir: WorkflowIR, options: LoggerRenderOptions): LoggerOutput {\n const root = ir.root;\n const steps = collectSteps(root.children);\n const includeDiagram = options.includeDiagram ?? true;\n const stripColors = options.stripAnsiColors ?? true;\n\n const output: LoggerOutput = {\n workflow: {\n id: root.workflowId,\n name: root.name,\n state: root.state,\n durationMs: root.durationMs,\n startedAt: root.startTs,\n completedAt: root.endTs,\n },\n steps: steps.map(stepToLog),\n summary: calculateSummary(steps),\n };\n\n // Add hooks if present\n if (ir.hooks) {\n const hookLog = hooksToLog(ir.hooks);\n if (Object.keys(hookLog).length > 0) {\n output.hooks = hookLog;\n }\n }\n\n // Add ASCII diagram if requested\n if (includeDiagram) {\n const ascii = asciiRenderer();\n let diagram = ascii.render(ir, options);\n if (stripColors) {\n diagram = stripAnsi(diagram);\n }\n output.diagram = diagram;\n }\n\n return output;\n}\n\n// =============================================================================\n// Renderer\n// =============================================================================\n\n/**\n * Create a logger renderer that outputs structured JSON.\n *\n * @example\n * ```typescript\n * const viz = createVisualizer({ workflowName: 'checkout' });\n * // ... run workflow ...\n *\n * const logData = JSON.parse(viz.renderAs('logger'));\n * logger.info(logData, 'Workflow completed');\n * ```\n */\nexport function loggerRenderer(): Renderer {\n return {\n name: \"logger\",\n supportsLive: false,\n render(ir: WorkflowIR, options: RenderOptions): string {\n const loggerOptions = options as LoggerRenderOptions;\n const output = buildLoggerOutput(ir, loggerOptions);\n return JSON.stringify(output);\n },\n };\n}\n","/**\n * HTML Visualizer Styles\n *\n * CSS styles for the interactive HTML workflow visualizer.\n * Supports light, dark, and auto (system preference) themes.\n */\n\n/**\n * Generate CSS styles for the HTML visualizer.\n */\nexport function generateStyles(theme: \"light\" | \"dark\" | \"auto\"): string {\n const lightColors = {\n bg: \"#ffffff\",\n bgSecondary: \"#f8f9fa\",\n text: \"#212529\",\n textMuted: \"#6c757d\",\n border: \"#dee2e6\",\n primary: \"#0d6efd\",\n success: \"#198754\",\n error: \"#dc3545\",\n warning: \"#ffc107\",\n info: \"#0dcaf0\",\n muted: \"#6c757d\",\n // Node colors\n nodePending: \"#e9ecef\",\n nodeRunning: \"#fff3cd\",\n nodeSuccess: \"#d1e7dd\",\n nodeError: \"#f8d7da\",\n nodeAborted: \"#e9ecef\",\n nodeCached: \"#cfe2ff\",\n nodeSkipped: \"#f8f9fa\",\n // Heatmap colors\n heatCold: \"#0d6efd\",\n heatCool: \"#0dcaf0\",\n heatNeutral: \"#6c757d\",\n heatWarm: \"#ffc107\",\n heatHot: \"#fd7e14\",\n heatCritical: \"#dc3545\",\n };\n\n const darkColors = {\n bg: \"#212529\",\n bgSecondary: \"#343a40\",\n text: \"#f8f9fa\",\n textMuted: \"#adb5bd\",\n border: \"#495057\",\n primary: \"#0d6efd\",\n success: \"#198754\",\n error: \"#dc3545\",\n warning: \"#ffc107\",\n info: \"#0dcaf0\",\n muted: \"#6c757d\",\n // Node colors\n nodePending: \"#495057\",\n nodeRunning: \"#664d03\",\n nodeSuccess: \"#0f5132\",\n nodeError: \"#842029\",\n nodeAborted: \"#495057\",\n nodeCached: \"#084298\",\n nodeSkipped: \"#343a40\",\n // Heatmap colors\n heatCold: \"#0d6efd\",\n heatCool: \"#0dcaf0\",\n heatNeutral: \"#6c757d\",\n heatWarm: \"#ffc107\",\n heatHot: \"#fd7e14\",\n heatCritical: \"#dc3545\",\n };\n\n const generateThemeVars = (colors: typeof lightColors) => `\n --bg: ${colors.bg};\n --bg-secondary: ${colors.bgSecondary};\n --text: ${colors.text};\n --text-muted: ${colors.textMuted};\n --border: ${colors.border};\n --primary: ${colors.primary};\n --success: ${colors.success};\n --error: ${colors.error};\n --warning: ${colors.warning};\n --info: ${colors.info};\n --muted: ${colors.muted};\n --node-pending: ${colors.nodePending};\n --node-running: ${colors.nodeRunning};\n --node-success: ${colors.nodeSuccess};\n --node-error: ${colors.nodeError};\n --node-aborted: ${colors.nodeAborted};\n --node-cached: ${colors.nodeCached};\n --node-skipped: ${colors.nodeSkipped};\n --heat-cold: ${colors.heatCold};\n --heat-cool: ${colors.heatCool};\n --heat-neutral: ${colors.heatNeutral};\n --heat-warm: ${colors.heatWarm};\n --heat-hot: ${colors.heatHot};\n --heat-critical: ${colors.heatCritical};\n `;\n\n let themeCSS: string;\n\n if (theme === \"auto\") {\n themeCSS = `\n :root {\n ${generateThemeVars(lightColors)}\n }\n @media (prefers-color-scheme: dark) {\n :root {\n ${generateThemeVars(darkColors)}\n }\n }\n `;\n } else if (theme === \"dark\") {\n themeCSS = `\n :root {\n ${generateThemeVars(darkColors)}\n }\n `;\n } else {\n themeCSS = `\n :root {\n ${generateThemeVars(lightColors)}\n }\n `;\n }\n\n return `\n${themeCSS}\n\n* {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n background-color: var(--bg);\n color: var(--text);\n line-height: 1.5;\n}\n\n.workflow-visualizer {\n display: flex;\n flex-direction: column;\n height: 100vh;\n overflow: hidden;\n}\n\n/* Header */\n.wv-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 20px;\n background-color: var(--bg-secondary);\n border-bottom: 1px solid var(--border);\n}\n\n.wv-header h1 {\n font-size: 1.25rem;\n font-weight: 600;\n}\n\n.wv-controls {\n display: flex;\n gap: 8px;\n align-items: center;\n}\n\n.wv-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 6px 12px;\n font-size: 0.875rem;\n font-weight: 500;\n border: 1px solid var(--border);\n border-radius: 6px;\n background-color: var(--bg);\n color: var(--text);\n cursor: pointer;\n transition: all 0.15s ease;\n}\n\n.wv-btn:hover {\n background-color: var(--bg-secondary);\n}\n\n.wv-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.wv-btn--primary {\n background-color: var(--primary);\n border-color: var(--primary);\n color: white;\n}\n\n.wv-btn--primary:hover {\n opacity: 0.9;\n}\n\n.wv-btn--icon {\n padding: 6px;\n min-width: 32px;\n}\n\n/* Main content area */\n.wv-main {\n display: flex;\n flex: 1;\n overflow: hidden;\n}\n\n/* Diagram container */\n.wv-diagram {\n flex: 1;\n position: relative;\n overflow: hidden;\n background-color: var(--bg);\n background-image:\n radial-gradient(circle, var(--border) 1px, transparent 1px);\n background-size: 20px 20px;\n}\n\n.wv-diagram svg {\n width: 100%;\n height: 100%;\n}\n\n/* SVG Node styles */\n.wv-node {\n cursor: pointer;\n transition: transform 0.15s ease;\n}\n\n.wv-node:hover {\n transform: scale(1.02);\n}\n\n.wv-node rect,\n.wv-node circle {\n stroke: var(--border);\n stroke-width: 2;\n transition: all 0.2s ease;\n}\n\n.wv-node--pending rect { fill: var(--node-pending); }\n.wv-node--running rect { fill: var(--node-running); stroke: var(--warning); }\n.wv-node--success rect { fill: var(--node-success); stroke: var(--success); }\n.wv-node--error rect { fill: var(--node-error); stroke: var(--error); }\n.wv-node--aborted rect { fill: var(--node-aborted); }\n.wv-node--cached rect { fill: var(--node-cached); stroke: var(--info); }\n.wv-node--skipped rect { fill: var(--node-skipped); opacity: 0.6; }\n\n.wv-node--selected rect {\n stroke: var(--primary);\n stroke-width: 3;\n}\n\n.wv-node text {\n fill: var(--text);\n font-size: 12px;\n font-weight: 500;\n dominant-baseline: middle;\n text-anchor: middle;\n}\n\n.wv-node .wv-node-timing {\n fill: var(--text-muted);\n font-size: 10px;\n}\n\n/* Edge styles */\n.wv-edge {\n fill: none;\n stroke: var(--border);\n stroke-width: 2;\n}\n\n.wv-edge--active {\n stroke: var(--success);\n stroke-width: 2.5;\n}\n\n.wv-edge-arrow {\n fill: var(--border);\n}\n\n/* Parallel/Race container */\n.wv-container {\n fill: transparent;\n stroke: var(--border);\n stroke-dasharray: 5 3;\n}\n\n.wv-container--parallel { stroke: var(--info); }\n.wv-container--race { stroke: var(--warning); }\n\n.wv-container-label {\n fill: var(--text-muted);\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Heatmap overlay */\n.wv-node--heat-cold rect { fill: var(--heat-cold) !important; opacity: 0.7; }\n.wv-node--heat-cool rect { fill: var(--heat-cool) !important; opacity: 0.7; }\n.wv-node--heat-neutral rect { fill: var(--heat-neutral) !important; opacity: 0.7; }\n.wv-node--heat-warm rect { fill: var(--heat-warm) !important; opacity: 0.7; }\n.wv-node--heat-hot rect { fill: var(--heat-hot) !important; opacity: 0.7; }\n.wv-node--heat-critical rect { fill: var(--heat-critical) !important; opacity: 0.85; }\n\n/* Timeline scrubber */\n.wv-timeline {\n height: 80px;\n padding: 12px 20px;\n background-color: var(--bg-secondary);\n border-top: 1px solid var(--border);\n}\n\n.wv-timeline-track {\n position: relative;\n height: 24px;\n background-color: var(--bg);\n border-radius: 4px;\n overflow: hidden;\n}\n\n.wv-timeline-progress {\n position: absolute;\n top: 0;\n left: 0;\n height: 100%;\n background-color: var(--primary);\n opacity: 0.3;\n transition: width 0.1s ease;\n}\n\n.wv-timeline-marker {\n position: absolute;\n top: 0;\n width: 3px;\n height: 100%;\n background-color: var(--primary);\n cursor: ew-resize;\n}\n\n.wv-timeline-events {\n display: flex;\n gap: 2px;\n height: 100%;\n align-items: center;\n padding: 4px;\n}\n\n.wv-timeline-event {\n width: 4px;\n height: 16px;\n border-radius: 2px;\n background-color: var(--muted);\n}\n\n.wv-timeline-event--success { background-color: var(--success); }\n.wv-timeline-event--error { background-color: var(--error); }\n.wv-timeline-event--running { background-color: var(--warning); }\n\n.wv-timeline-controls {\n display: flex;\n gap: 8px;\n margin-top: 8px;\n align-items: center;\n}\n\n.wv-timeline-time {\n font-size: 0.75rem;\n color: var(--text-muted);\n font-family: monospace;\n}\n\n/* Inspector panel */\n.wv-inspector {\n width: 320px;\n background-color: var(--bg-secondary);\n border-left: 1px solid var(--border);\n overflow-y: auto;\n transition: width 0.2s ease;\n}\n\n.wv-inspector--collapsed {\n width: 0;\n}\n\n.wv-inspector-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--border);\n}\n\n.wv-inspector-header h2 {\n font-size: 0.875rem;\n font-weight: 600;\n}\n\n.wv-inspector-content {\n padding: 16px;\n}\n\n.wv-inspector-section {\n margin-bottom: 20px;\n}\n\n.wv-inspector-section h3 {\n font-size: 0.75rem;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--text-muted);\n margin-bottom: 8px;\n}\n\n.wv-inspector-row {\n display: flex;\n justify-content: space-between;\n padding: 4px 0;\n font-size: 0.875rem;\n}\n\n.wv-inspector-label {\n color: var(--text-muted);\n}\n\n.wv-inspector-value {\n font-weight: 500;\n font-family: monospace;\n}\n\n.wv-inspector-value--success { color: var(--success); }\n.wv-inspector-value--error { color: var(--error); }\n.wv-inspector-value--running { color: var(--warning); }\n\n/* Status badge */\n.wv-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n font-size: 0.75rem;\n font-weight: 500;\n border-radius: 4px;\n text-transform: capitalize;\n}\n\n.wv-badge--pending { background-color: var(--node-pending); }\n.wv-badge--running { background-color: var(--node-running); color: #664d03; }\n.wv-badge--success { background-color: var(--node-success); color: #0f5132; }\n.wv-badge--error { background-color: var(--node-error); color: #842029; }\n.wv-badge--cached { background-color: var(--node-cached); color: #084298; }\n\n/* Live indicator */\n.wv-live {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 4px 10px;\n background-color: var(--error);\n color: white;\n font-size: 0.75rem;\n font-weight: 600;\n border-radius: 4px;\n}\n\n.wv-live-dot {\n width: 8px;\n height: 8px;\n background-color: white;\n border-radius: 50%;\n animation: wv-pulse 1.5s infinite;\n}\n\n@keyframes wv-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n\n/* Performance stats */\n.wv-perf-bar {\n height: 8px;\n background-color: var(--bg);\n border-radius: 4px;\n overflow: hidden;\n margin-top: 4px;\n}\n\n.wv-perf-bar-fill {\n height: 100%;\n border-radius: 4px;\n transition: width 0.3s ease;\n}\n\n.wv-perf-bar-fill--cold { background-color: var(--heat-cold); }\n.wv-perf-bar-fill--cool { background-color: var(--heat-cool); }\n.wv-perf-bar-fill--neutral { background-color: var(--heat-neutral); }\n.wv-perf-bar-fill--warm { background-color: var(--heat-warm); }\n.wv-perf-bar-fill--hot { background-color: var(--heat-hot); }\n.wv-perf-bar-fill--critical { background-color: var(--heat-critical); }\n\n/* Tooltip */\n.wv-tooltip {\n position: fixed;\n padding: 8px 12px;\n background-color: var(--text);\n color: var(--bg);\n font-size: 0.75rem;\n border-radius: 4px;\n pointer-events: none;\n z-index: 1000;\n max-width: 300px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n}\n\n/* Loading state */\n.wv-loading {\n display: flex;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-muted);\n}\n\n.wv-spinner {\n width: 24px;\n height: 24px;\n border: 3px solid var(--border);\n border-top-color: var(--primary);\n border-radius: 50%;\n animation: wv-spin 1s linear infinite;\n margin-right: 8px;\n}\n\n@keyframes wv-spin {\n to { transform: rotate(360deg); }\n}\n\n/* Empty state */\n.wv-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n height: 100%;\n color: var(--text-muted);\n text-align: center;\n padding: 40px;\n}\n\n.wv-empty svg {\n width: 64px;\n height: 64px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .wv-inspector {\n position: fixed;\n right: 0;\n top: 0;\n bottom: 0;\n z-index: 100;\n box-shadow: -4px 0 12px rgba(0, 0, 0, 0.1);\n }\n\n .wv-timeline {\n height: auto;\n }\n}\n`;\n}\n","/**\n * HTML Visualizer Client-Side JavaScript\n *\n * Handles interactivity in the browser:\n * - Zoom and pan\n * - Node selection and inspection\n * - Time-travel controls\n * - WebSocket live updates\n * - Heatmap toggle\n */\n\n/**\n * Generate client-side JavaScript for the HTML visualizer.\n */\nexport function generateClientScript(options: {\n wsUrl?: string;\n interactive: boolean;\n timeTravel: boolean;\n heatmap: boolean;\n}): string {\n return `\n(function() {\n 'use strict';\n\n // State\n let selectedNodeId = null;\n let transform = { x: 0, y: 0, scale: 1 };\n let isDragging = false;\n let dragStart = { x: 0, y: 0 };\n let ws = null;\n let snapshots = [];\n let currentSnapshotIndex = -1;\n let isPlaying = false;\n let playbackSpeed = 1;\n let heatmapEnabled = false;\n let heatmapMetric = 'duration';\n\n // DOM elements\n const diagram = document.getElementById('diagram');\n const svg = diagram?.querySelector('svg');\n const inspector = document.getElementById('inspector');\n const timeline = document.getElementById('timeline');\n\n // Initialize\n document.addEventListener('DOMContentLoaded', init);\n\n function init() {\n ${options.interactive ? \"setupInteractivity();\" : \"\"}\n ${options.timeTravel ? \"setupTimeTravel();\" : \"\"}\n ${options.wsUrl ? `setupWebSocket('${options.wsUrl}');` : \"\"}\n ${options.heatmap ? \"setupHeatmap();\" : \"\"}\n setupKeyboardShortcuts();\n }\n\n // Interactivity\n function setupInteractivity() {\n if (!diagram || !svg) return;\n\n // Zoom with mouse wheel\n diagram.addEventListener('wheel', (e) => {\n e.preventDefault();\n const delta = e.deltaY > 0 ? 0.9 : 1.1;\n const rect = diagram.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n\n // Zoom towards cursor position\n transform.scale *= delta;\n transform.scale = Math.max(0.1, Math.min(5, transform.scale));\n transform.x = x - (x - transform.x) * delta;\n transform.y = y - (y - transform.y) * delta;\n\n applyTransform();\n });\n\n // Pan with drag\n diagram.addEventListener('mousedown', (e) => {\n if (e.target === diagram || e.target === svg) {\n isDragging = true;\n dragStart = { x: e.clientX - transform.x, y: e.clientY - transform.y };\n diagram.style.cursor = 'grabbing';\n }\n });\n\n document.addEventListener('mousemove', (e) => {\n if (!isDragging) return;\n transform.x = e.clientX - dragStart.x;\n transform.y = e.clientY - dragStart.y;\n applyTransform();\n });\n\n document.addEventListener('mouseup', () => {\n isDragging = false;\n if (diagram) diagram.style.cursor = 'grab';\n });\n\n // Node selection\n document.querySelectorAll('.wv-node').forEach((node) => {\n node.addEventListener('click', (e) => {\n e.stopPropagation();\n selectNode(node.dataset.nodeId);\n });\n });\n\n // Deselect on background click\n diagram.addEventListener('click', (e) => {\n if (e.target === diagram || e.target === svg) {\n selectNode(null);\n }\n });\n\n // Zoom buttons\n document.getElementById('zoom-in')?.addEventListener('click', () => zoom(1.2));\n document.getElementById('zoom-out')?.addEventListener('click', () => zoom(0.8));\n document.getElementById('zoom-reset')?.addEventListener('click', resetZoom);\n\n // Set initial cursor\n diagram.style.cursor = 'grab';\n }\n\n function applyTransform() {\n if (!svg) return;\n const g = svg.querySelector('g.wv-root');\n if (g) {\n g.setAttribute('transform', 'translate(' + transform.x + ',' + transform.y + ') scale(' + transform.scale + ')');\n }\n }\n\n function zoom(factor) {\n if (!diagram) return;\n const rect = diagram.getBoundingClientRect();\n const centerX = rect.width / 2;\n const centerY = rect.height / 2;\n\n transform.scale *= factor;\n transform.scale = Math.max(0.1, Math.min(5, transform.scale));\n transform.x = centerX - (centerX - transform.x) * factor;\n transform.y = centerY - (centerY - transform.y) * factor;\n\n applyTransform();\n }\n\n function resetZoom() {\n transform = { x: 0, y: 0, scale: 1 };\n applyTransform();\n }\n\n function selectNode(nodeId) {\n // Remove previous selection\n document.querySelectorAll('.wv-node--selected').forEach((n) => {\n n.classList.remove('wv-node--selected');\n });\n\n selectedNodeId = nodeId;\n\n if (nodeId) {\n const node = document.querySelector('[data-node-id=\"' + nodeId + '\"]');\n if (node) {\n node.classList.add('wv-node--selected');\n updateInspector(nodeId);\n }\n } else {\n clearInspector();\n }\n }\n\n function updateInspector(nodeId) {\n const content = document.getElementById('inspector-content');\n if (!content) return;\n\n const nodeData = window.__WORKFLOW_DATA__?.nodes?.[nodeId];\n if (!nodeData) {\n // Clear and add empty message using safe DOM methods\n while (content.firstChild) content.removeChild(content.firstChild);\n const p = document.createElement('p');\n p.className = 'wv-empty';\n p.textContent = 'No data available';\n content.appendChild(p);\n return;\n }\n\n renderInspectorContent(content, nodeData);\n }\n\n function renderInspectorContent(container, node) {\n // Clear container using safe DOM method\n while (container.firstChild) container.removeChild(container.firstChild);\n\n // Node Info section\n const infoSection = createSection('Node Info');\n infoSection.appendChild(createRow('Name', node.name || node.id));\n infoSection.appendChild(createRow('Type', node.type));\n\n // State badge\n const stateRow = document.createElement('div');\n stateRow.className = 'wv-inspector-row';\n const stateLabel = document.createElement('span');\n stateLabel.className = 'wv-inspector-label';\n stateLabel.textContent = 'State';\n const stateBadge = document.createElement('span');\n stateBadge.className = 'wv-badge wv-badge--' + node.state;\n stateBadge.textContent = node.state;\n stateRow.appendChild(stateLabel);\n stateRow.appendChild(stateBadge);\n infoSection.appendChild(stateRow);\n\n if (node.key) {\n infoSection.appendChild(createRow('Key', node.key));\n }\n container.appendChild(infoSection);\n\n // Timing section\n if (node.durationMs !== undefined) {\n const timingSection = createSection('Timing');\n timingSection.appendChild(createRow('Duration', formatDuration(node.durationMs)));\n if (node.startTs) {\n timingSection.appendChild(createRow('Started', new Date(node.startTs).toLocaleTimeString()));\n }\n container.appendChild(timingSection);\n }\n\n // Retries section\n if (node.retryCount !== undefined && node.retryCount > 0) {\n const retrySection = createSection('Retries');\n retrySection.appendChild(createRow('Retry Count', String(node.retryCount)));\n container.appendChild(retrySection);\n }\n\n // Error section\n if (node.error) {\n const errorSection = createSection('Error');\n const pre = document.createElement('pre');\n pre.style.cssText = 'font-size:11px;overflow:auto;max-height:150px;background:var(--bg);padding:8px;border-radius:4px;';\n pre.textContent = String(node.error);\n errorSection.appendChild(pre);\n container.appendChild(errorSection);\n }\n }\n\n function createSection(title) {\n const section = document.createElement('div');\n section.className = 'wv-inspector-section';\n const h3 = document.createElement('h3');\n h3.textContent = title;\n section.appendChild(h3);\n return section;\n }\n\n function createRow(label, value) {\n const row = document.createElement('div');\n row.className = 'wv-inspector-row';\n const labelSpan = document.createElement('span');\n labelSpan.className = 'wv-inspector-label';\n labelSpan.textContent = label;\n const valueSpan = document.createElement('span');\n valueSpan.className = 'wv-inspector-value';\n valueSpan.textContent = value;\n row.appendChild(labelSpan);\n row.appendChild(valueSpan);\n return row;\n }\n\n function clearInspector() {\n const content = document.getElementById('inspector-content');\n if (content) {\n while (content.firstChild) content.removeChild(content.firstChild);\n const p = document.createElement('p');\n p.className = 'wv-empty';\n p.textContent = 'Select a node to inspect';\n content.appendChild(p);\n }\n }\n\n // Time Travel\n function setupTimeTravel() {\n const playBtn = document.getElementById('tt-play');\n const pauseBtn = document.getElementById('tt-pause');\n const prevBtn = document.getElementById('tt-prev');\n const nextBtn = document.getElementById('tt-next');\n const speedSelect = document.getElementById('tt-speed');\n const slider = document.getElementById('tt-slider');\n\n playBtn?.addEventListener('click', play);\n pauseBtn?.addEventListener('click', pause);\n prevBtn?.addEventListener('click', stepBackward);\n nextBtn?.addEventListener('click', stepForward);\n speedSelect?.addEventListener('change', (e) => {\n playbackSpeed = parseFloat(e.target.value);\n });\n slider?.addEventListener('input', (e) => {\n seek(parseInt(e.target.value, 10));\n });\n }\n\n function play() {\n if (snapshots.length === 0) return;\n isPlaying = true;\n updatePlaybackUI();\n playNext();\n }\n\n function pause() {\n isPlaying = false;\n updatePlaybackUI();\n }\n\n function playNext() {\n if (!isPlaying) return;\n if (currentSnapshotIndex < snapshots.length - 1) {\n const current = snapshots[currentSnapshotIndex];\n const next = snapshots[currentSnapshotIndex + 1];\n const delay = (next.timestamp - current.timestamp) / playbackSpeed;\n\n setTimeout(() => {\n stepForward();\n playNext();\n }, Math.max(16, delay));\n } else {\n pause();\n }\n }\n\n function stepForward() {\n if (currentSnapshotIndex < snapshots.length - 1) {\n seek(currentSnapshotIndex + 1);\n }\n }\n\n function stepBackward() {\n if (currentSnapshotIndex > 0) {\n seek(currentSnapshotIndex - 1);\n }\n }\n\n function seek(index) {\n if (index < 0 || index >= snapshots.length) return;\n currentSnapshotIndex = index;\n updateTimelineUI();\n\n // Request IR update from server or use cached\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(JSON.stringify({ type: 'time_travel_seek', payload: { index } }));\n } else if (snapshots[index]?.ir) {\n renderIR(snapshots[index].ir);\n }\n }\n\n function updatePlaybackUI() {\n const playBtn = document.getElementById('tt-play');\n const pauseBtn = document.getElementById('tt-pause');\n\n if (playBtn) playBtn.style.display = isPlaying ? 'none' : 'inline-flex';\n if (pauseBtn) pauseBtn.style.display = isPlaying ? 'inline-flex' : 'none';\n }\n\n function updateTimelineUI() {\n const slider = document.getElementById('tt-slider');\n const timeDisplay = document.getElementById('tt-time');\n\n if (slider) {\n slider.max = String(Math.max(0, snapshots.length - 1));\n slider.value = String(currentSnapshotIndex);\n }\n\n if (timeDisplay) {\n timeDisplay.textContent = (currentSnapshotIndex + 1) + ' / ' + snapshots.length;\n }\n }\n\n // WebSocket\n function setupWebSocket(url) {\n ws = new WebSocket(url);\n\n ws.onopen = () => {\n console.log('[Visualizer] Connected to server');\n showLiveIndicator(true);\n };\n\n ws.onclose = () => {\n console.log('[Visualizer] Disconnected from server');\n showLiveIndicator(false);\n // Attempt reconnect after 2 seconds\n setTimeout(() => setupWebSocket(url), 2000);\n };\n\n ws.onmessage = (event) => {\n try {\n const msg = JSON.parse(event.data);\n handleServerMessage(msg);\n } catch (e) {\n console.error('[Visualizer] Failed to parse message:', e);\n }\n };\n\n ws.onerror = (error) => {\n console.error('[Visualizer] WebSocket error:', error);\n };\n }\n\n function handleServerMessage(msg) {\n switch (msg.type) {\n case 'ir_update':\n renderIR(msg.payload);\n break;\n case 'snapshot':\n snapshots.push(msg.payload);\n currentSnapshotIndex = snapshots.length - 1;\n updateTimelineUI();\n break;\n case 'snapshots_list':\n snapshots = msg.payload;\n currentSnapshotIndex = snapshots.length - 1;\n updateTimelineUI();\n break;\n case 'performance_data':\n window.__PERFORMANCE_DATA__ = msg.payload;\n if (heatmapEnabled) applyHeatmap();\n break;\n case 'workflow_complete':\n showLiveIndicator(false);\n break;\n case 'time_travel_state':\n currentSnapshotIndex = msg.payload.currentIndex;\n isPlaying = msg.payload.isPlaying;\n playbackSpeed = msg.payload.playbackSpeed;\n updateTimelineUI();\n updatePlaybackUI();\n break;\n }\n }\n\n function showLiveIndicator(show) {\n const indicator = document.getElementById('live-indicator');\n if (indicator) {\n indicator.style.display = show ? 'flex' : 'none';\n }\n }\n\n // Heatmap\n function setupHeatmap() {\n const toggle = document.getElementById('heatmap-toggle');\n const metricSelect = document.getElementById('heatmap-metric');\n\n toggle?.addEventListener('click', () => {\n heatmapEnabled = !heatmapEnabled;\n toggle.classList.toggle('wv-btn--primary', heatmapEnabled);\n if (heatmapEnabled) {\n applyHeatmap();\n } else {\n removeHeatmap();\n }\n });\n\n metricSelect?.addEventListener('change', (e) => {\n heatmapMetric = e.target.value;\n if (heatmapEnabled) applyHeatmap();\n });\n }\n\n function applyHeatmap() {\n const perfData = window.__PERFORMANCE_DATA__;\n if (!perfData) return;\n\n document.querySelectorAll('.wv-node').forEach((node) => {\n const nodeId = node.dataset.nodeId;\n const heat = perfData.heat?.[nodeId];\n\n // Remove existing heat classes\n node.classList.remove(\n 'wv-node--heat-cold',\n 'wv-node--heat-cool',\n 'wv-node--heat-neutral',\n 'wv-node--heat-warm',\n 'wv-node--heat-hot',\n 'wv-node--heat-critical'\n );\n\n if (heat !== undefined) {\n const level = getHeatLevel(heat);\n node.classList.add('wv-node--heat-' + level);\n }\n });\n }\n\n function removeHeatmap() {\n document.querySelectorAll('.wv-node').forEach((node) => {\n node.classList.remove(\n 'wv-node--heat-cold',\n 'wv-node--heat-cool',\n 'wv-node--heat-neutral',\n 'wv-node--heat-warm',\n 'wv-node--heat-hot',\n 'wv-node--heat-critical'\n );\n });\n }\n\n function getHeatLevel(heat) {\n if (heat < 0.2) return 'cold';\n if (heat < 0.4) return 'cool';\n if (heat < 0.6) return 'neutral';\n if (heat < 0.8) return 'warm';\n if (heat < 0.95) return 'hot';\n return 'critical';\n }\n\n // Keyboard shortcuts\n function setupKeyboardShortcuts() {\n document.addEventListener('keydown', (e) => {\n // Don't trigger shortcuts when typing in inputs\n if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;\n\n switch (e.key) {\n case ' ':\n e.preventDefault();\n isPlaying ? pause() : play();\n break;\n case 'ArrowLeft':\n e.preventDefault();\n stepBackward();\n break;\n case 'ArrowRight':\n e.preventDefault();\n stepForward();\n break;\n case '0':\n resetZoom();\n break;\n case '+':\n case '=':\n zoom(1.2);\n break;\n case '-':\n zoom(0.8);\n break;\n case 'h':\n ${options.heatmap ? \"document.getElementById('heatmap-toggle')?.click();\" : \"\"}\n break;\n case 'Escape':\n selectNode(null);\n break;\n }\n });\n }\n\n // Render functions\n function renderIR(ir) {\n // Store node data for inspector\n window.__WORKFLOW_DATA__ = {\n nodes: flattenNodes(ir.root.children).reduce((acc, n) => {\n acc[n.id] = n;\n return acc;\n }, {})\n };\n\n // Update SVG node states\n document.querySelectorAll('.wv-node').forEach((node) => {\n const nodeId = node.dataset.nodeId;\n const nodeData = window.__WORKFLOW_DATA__.nodes[nodeId];\n if (nodeData) {\n // Update state class\n node.className = node.className.replace(/wv-node--\\\\w+/g, '');\n node.classList.add('wv-node', 'wv-node--' + nodeData.state);\n\n // Update timing text if present\n const timing = node.querySelector('.wv-node-timing');\n if (timing && nodeData.durationMs !== undefined) {\n timing.textContent = formatDuration(nodeData.durationMs);\n }\n }\n });\n\n // Update selected node inspector\n if (selectedNodeId) {\n updateInspector(selectedNodeId);\n }\n }\n\n function flattenNodes(nodes) {\n const result = [];\n for (const node of nodes) {\n result.push(node);\n if (node.children) {\n result.push(...flattenNodes(node.children));\n }\n if (node.branches) {\n for (const branch of node.branches) {\n result.push(...flattenNodes(branch.children));\n }\n }\n }\n return result;\n }\n\n // Utilities\n function formatDuration(ms) {\n if (ms < 1) return '<1ms';\n if (ms < 1000) return Math.round(ms) + 'ms';\n if (ms < 60000) return (ms / 1000).toFixed(2) + 's';\n return (ms / 60000).toFixed(1) + 'm';\n }\n})();\n`;\n}\n","/**\n * HTML Renderer\n *\n * Renders the workflow IR as an interactive HTML page with:\n * - SVG-based workflow diagram\n * - Zoom and pan\n * - Node inspection\n * - Time-travel controls\n * - Performance heatmap overlay\n */\n\nimport type {\n FlowNode,\n HTMLRenderOptions,\n Renderer,\n WorkflowIR,\n StepState,\n RenderOptions,\n LayoutDirection,\n} from \"../types\";\nimport {\n isStepNode,\n isParallelNode,\n isRaceNode,\n isDecisionNode,\n} from \"../types\";\nimport { generateStyles } from \"./html-styles\";\nimport { generateClientScript } from \"./html-client\";\nimport { formatDuration } from \"../utils/timing\";\n\n// =============================================================================\n// Constants\n// =============================================================================\n\nconst NODE_WIDTH = 160;\nconst NODE_HEIGHT = 50;\nconst NODE_SPACING_H = 40;\nconst NODE_SPACING_V = 30;\nconst CONTAINER_PADDING = 20;\n\n// =============================================================================\n// Layout Types\n// =============================================================================\n\ninterface LayoutNode {\n id: string;\n name: string;\n type: string;\n state: StepState;\n x: number;\n y: number;\n width: number;\n height: number;\n durationMs?: number;\n children?: LayoutNode[];\n containerType?: \"parallel\" | \"race\" | \"decision\";\n containerLabel?: string;\n}\n\ninterface LayoutResult {\n nodes: LayoutNode[];\n width: number;\n height: number;\n}\n\n// =============================================================================\n// Layout Functions\n// =============================================================================\n\n/**\n * Layout workflow nodes for SVG rendering.\n * Uses a simple top-to-bottom layout algorithm.\n */\nfunction layoutWorkflow(\n nodes: FlowNode[],\n direction: LayoutDirection = \"TB\"\n): LayoutResult {\n const isVertical = direction === \"TB\" || direction === \"BT\";\n const layoutNodes: LayoutNode[] = [];\n let currentX = CONTAINER_PADDING;\n let currentY = CONTAINER_PADDING;\n let maxWidth = 0;\n let maxHeight = 0;\n\n for (const node of nodes) {\n const result = layoutFlowNode(node, currentX, currentY, isVertical);\n layoutNodes.push(result.node);\n\n if (isVertical) {\n currentY += result.height + NODE_SPACING_V;\n maxWidth = Math.max(maxWidth, result.width);\n maxHeight = currentY;\n } else {\n currentX += result.width + NODE_SPACING_H;\n maxHeight = Math.max(maxHeight, result.height);\n maxWidth = currentX;\n }\n }\n\n return {\n nodes: layoutNodes,\n width: maxWidth + CONTAINER_PADDING,\n height: maxHeight + CONTAINER_PADDING,\n };\n}\n\n/**\n * Layout a single flow node.\n */\nfunction layoutFlowNode(\n node: FlowNode,\n x: number,\n y: number,\n _isVertical: boolean\n): { node: LayoutNode; width: number; height: number } {\n if (isStepNode(node)) {\n return {\n node: {\n id: node.id,\n name: node.name ?? node.key ?? \"step\",\n type: \"step\",\n state: node.state,\n x,\n y,\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n durationMs: node.durationMs,\n },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n };\n }\n\n if (isParallelNode(node) || isRaceNode(node)) {\n const containerType = isParallelNode(node) ? \"parallel\" : \"race\";\n const label = node.name ?? containerType;\n const children: LayoutNode[] = [];\n\n let innerX = x + CONTAINER_PADDING;\n const innerY = y + CONTAINER_PADDING + 20; // Extra space for label\n let innerMaxWidth = 0;\n let innerMaxHeight = 0;\n\n // Layout children horizontally in parallel\n for (const child of node.children) {\n const result = layoutFlowNode(child, innerX, innerY, true);\n children.push(result.node);\n innerX += result.width + NODE_SPACING_H;\n innerMaxHeight = Math.max(innerMaxHeight, result.height);\n }\n\n innerMaxWidth = innerX - x - CONTAINER_PADDING;\n const containerWidth = Math.max(\n innerMaxWidth + CONTAINER_PADDING,\n NODE_WIDTH + CONTAINER_PADDING * 2\n );\n const containerHeight =\n innerMaxHeight + CONTAINER_PADDING * 2 + 20; // Extra for label\n\n return {\n node: {\n id: node.id,\n name: label,\n type: containerType,\n state: node.state,\n x,\n y,\n width: containerWidth,\n height: containerHeight,\n durationMs: node.durationMs,\n children,\n containerType,\n containerLabel: containerType === \"parallel\" ? \"PARALLEL\" : \"RACE\",\n },\n width: containerWidth,\n height: containerHeight,\n };\n }\n\n if (isDecisionNode(node)) {\n const label = node.name ?? \"decision\";\n const children: LayoutNode[] = [];\n\n let innerX = x + CONTAINER_PADDING;\n const innerY = y + CONTAINER_PADDING + 20;\n let innerMaxHeight = 0;\n\n // Layout branches horizontally\n for (const branch of node.branches) {\n for (const child of branch.children) {\n const result = layoutFlowNode(child, innerX, innerY, true);\n children.push(result.node);\n innerX += result.width + NODE_SPACING_H;\n innerMaxHeight = Math.max(innerMaxHeight, result.height);\n }\n }\n\n const containerWidth = Math.max(\n innerX - x,\n NODE_WIDTH + CONTAINER_PADDING * 2\n );\n const containerHeight = innerMaxHeight + CONTAINER_PADDING * 2 + 20;\n\n return {\n node: {\n id: node.id,\n name: label,\n type: \"decision\",\n state: node.state,\n x,\n y,\n width: containerWidth,\n height: containerHeight,\n durationMs: node.durationMs,\n children,\n containerType: \"decision\",\n containerLabel: \"DECISION\",\n },\n width: containerWidth,\n height: containerHeight,\n };\n }\n\n // Default fallback\n return {\n node: {\n id: node.id,\n name: node.name ?? \"unknown\",\n type: node.type,\n state: node.state,\n x,\n y,\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n },\n width: NODE_WIDTH,\n height: NODE_HEIGHT,\n };\n}\n\n// =============================================================================\n// SVG Rendering\n// =============================================================================\n\n/**\n * Render a layout node to SVG.\n */\nfunction renderLayoutNodeSVG(node: LayoutNode, showTimings: boolean): string {\n if (node.containerType) {\n return renderContainerSVG(node, showTimings);\n }\n return renderStepSVG(node, showTimings);\n}\n\n/**\n * Render a step node as SVG.\n */\nfunction renderStepSVG(node: LayoutNode, showTimings: boolean): string {\n const rx = 8; // Border radius\n const timing =\n showTimings && node.durationMs !== undefined\n ? formatDuration(node.durationMs)\n : \"\";\n\n return `\n <g class=\"wv-node wv-node--${node.state}\" data-node-id=\"${escapeAttr(node.id)}\" transform=\"translate(${node.x}, ${node.y})\">\n <rect width=\"${node.width}\" height=\"${node.height}\" rx=\"${rx}\" ry=\"${rx}\" />\n <text x=\"${node.width / 2}\" y=\"${node.height / 2 - (timing ? 4 : 0)}\">${escapeXml(truncate(node.name, 20))}</text>\n ${timing ? `<text class=\"wv-node-timing\" x=\"${node.width / 2}\" y=\"${node.height / 2 + 12}\">${timing}</text>` : \"\"}\n </g>\n `;\n}\n\n/**\n * Render a container (parallel/race/decision) as SVG.\n */\nfunction renderContainerSVG(node: LayoutNode, showTimings: boolean): string {\n const rx = 12;\n const childrenSVG =\n node.children?.map((c) => renderLayoutNodeSVG(c, showTimings)).join(\"\\n\") ??\n \"\";\n\n return `\n <g class=\"wv-container wv-container--${node.containerType}\" data-node-id=\"${escapeAttr(node.id)}\" transform=\"translate(${node.x}, ${node.y})\">\n <rect width=\"${node.width}\" height=\"${node.height}\" rx=\"${rx}\" ry=\"${rx}\" />\n <text class=\"wv-container-label\" x=\"${CONTAINER_PADDING}\" y=\"16\">${node.containerLabel}</text>\n <g transform=\"translate(${-node.x}, ${-node.y})\">\n ${childrenSVG}\n </g>\n </g>\n `;\n}\n\n/**\n * Render edges between sequential nodes.\n */\nfunction renderEdgesSVG(nodes: LayoutNode[]): string {\n const edges: string[] = [];\n\n for (let i = 0; i < nodes.length - 1; i++) {\n const from = nodes[i];\n const to = nodes[i + 1];\n\n const x1 = from.x + from.width / 2;\n const y1 = from.y + from.height;\n const x2 = to.x + to.width / 2;\n const y2 = to.y;\n\n // Simple straight line with arrow\n edges.push(`\n <path class=\"wv-edge\" d=\"M ${x1} ${y1} L ${x2} ${y2 - 8}\" />\n <polygon class=\"wv-edge-arrow\" points=\"${x2 - 4},${y2 - 8} ${x2 + 4},${y2 - 8} ${x2},${y2}\" />\n `);\n }\n\n return edges.join(\"\\n\");\n}\n\n// =============================================================================\n// HTML Generation\n// =============================================================================\n\n/**\n * Generate complete HTML page.\n */\nfunction generateHTML(\n ir: WorkflowIR,\n options: HTMLRenderOptions\n): string {\n const layout = layoutWorkflow(ir.root.children, options.layout);\n const svgWidth = Math.max(layout.width, 400);\n const svgHeight = Math.max(layout.height, 300);\n\n const nodesSVG = layout.nodes\n .map((n) => renderLayoutNodeSVG(n, options.showTimings))\n .join(\"\\n\");\n const edgesSVG = renderEdgesSVG(layout.nodes);\n\n const workflowName = ir.root.name ?? \"Workflow\";\n const css = generateStyles(options.theme);\n const js = generateClientScript({\n wsUrl: options.wsUrl,\n interactive: options.interactive,\n timeTravel: options.timeTravel,\n heatmap: options.heatmap,\n });\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeXml(workflowName)} - Workflow Visualizer</title>\n <style>${css}</style>\n</head>\n<body>\n <div class=\"workflow-visualizer\">\n <header class=\"wv-header\">\n <h1>${escapeXml(workflowName)}</h1>\n <div class=\"wv-controls\">\n ${options.wsUrl ? `<div id=\"live-indicator\" class=\"wv-live\" style=\"display:none\"><span class=\"wv-live-dot\"></span>LIVE</div>` : \"\"}\n ${options.heatmap ? `\n <button id=\"heatmap-toggle\" class=\"wv-btn\">Heatmap</button>\n <select id=\"heatmap-metric\" class=\"wv-btn\">\n <option value=\"duration\">Duration</option>\n <option value=\"retryRate\">Retry Rate</option>\n <option value=\"errorRate\">Error Rate</option>\n </select>\n ` : \"\"}\n ${options.interactive ? `\n <button id=\"zoom-out\" class=\"wv-btn wv-btn--icon\" title=\"Zoom out (-)\">−</button>\n <button id=\"zoom-reset\" class=\"wv-btn wv-btn--icon\" title=\"Reset zoom (0)\">⟲</button>\n <button id=\"zoom-in\" class=\"wv-btn wv-btn--icon\" title=\"Zoom in (+)\">+</button>\n ` : \"\"}\n </div>\n </header>\n\n <div class=\"wv-main\">\n <div id=\"diagram\" class=\"wv-diagram\">\n <svg viewBox=\"0 0 ${svgWidth} ${svgHeight}\" preserveAspectRatio=\"xMidYMid meet\">\n <g class=\"wv-root\">\n ${edgesSVG}\n ${nodesSVG}\n </g>\n </svg>\n </div>\n\n ${options.interactive ? `\n <aside id=\"inspector\" class=\"wv-inspector\">\n <div class=\"wv-inspector-header\">\n <h2>Inspector</h2>\n </div>\n <div id=\"inspector-content\" class=\"wv-inspector-content\">\n <p class=\"wv-empty\">Select a node to inspect</p>\n </div>\n </aside>\n ` : \"\"}\n </div>\n\n ${options.timeTravel ? `\n <div id=\"timeline\" class=\"wv-timeline\">\n <div class=\"wv-timeline-track\">\n <input type=\"range\" id=\"tt-slider\" min=\"0\" max=\"0\" value=\"0\" style=\"width:100%\">\n </div>\n <div class=\"wv-timeline-controls\">\n <button id=\"tt-prev\" class=\"wv-btn wv-btn--icon\" title=\"Step backward (←)\">⏮</button>\n <button id=\"tt-play\" class=\"wv-btn wv-btn--icon\" title=\"Play (Space)\">▶</button>\n <button id=\"tt-pause\" class=\"wv-btn wv-btn--icon\" style=\"display:none\" title=\"Pause (Space)\">⏸</button>\n <button id=\"tt-next\" class=\"wv-btn wv-btn--icon\" title=\"Step forward (→)\">⏭</button>\n <select id=\"tt-speed\" class=\"wv-btn\">\n <option value=\"0.5\">0.5x</option>\n <option value=\"1\" selected>1x</option>\n <option value=\"2\">2x</option>\n <option value=\"4\">4x</option>\n <option value=\"10\">10x</option>\n </select>\n <span id=\"tt-time\" class=\"wv-timeline-time\">0 / 0</span>\n </div>\n </div>\n ` : \"\"}\n </div>\n\n <script>\n window.__WORKFLOW_DATA__ = ${serializeWorkflowData(ir)};\n </script>\n <script>${js}</script>\n</body>\n</html>`;\n}\n\n/**\n * Build workflow data structure for client-side access.\n */\nfunction buildWorkflowData(ir: WorkflowIR): { nodes: Record<string, unknown> } {\n const nodes: Record<string, unknown> = {};\n\n function collectNodes(flowNodes: FlowNode[]): void {\n for (const node of flowNodes) {\n nodes[node.id] = {\n id: node.id,\n name: node.name,\n type: node.type,\n state: node.state,\n key: node.key,\n durationMs: node.durationMs,\n startTs: node.startTs,\n error: node.error ? String(node.error) : undefined,\n retryCount: node.retryCount,\n };\n\n if (\"children\" in node && Array.isArray(node.children)) {\n collectNodes(node.children);\n }\n if (\"branches\" in node) {\n for (const branch of node.branches) {\n collectNodes(branch.children);\n }\n }\n }\n }\n\n collectNodes(ir.root.children);\n return { nodes };\n}\n\n/**\n * Serialize workflow data for safe embedding inside a <script> tag.\n */\nfunction serializeWorkflowData(ir: WorkflowIR): string {\n const json = JSON.stringify(buildWorkflowData(ir));\n // Escape characters that could break out of the script context\n return json\n .replace(/</g, \"\\\\u003c\")\n .replace(/>/g, \"\\\\u003e\")\n .replace(/&/g, \"\\\\u0026\")\n .replace(/\\u2028/g, \"\\\\u2028\")\n .replace(/\\u2029/g, \"\\\\u2029\");\n}\n\n// =============================================================================\n// Utility Functions\n// =============================================================================\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction escapeAttr(str: string): string {\n return str.replace(/\"/g, \""\").replace(/'/g, \"'\");\n}\n\nfunction truncate(str: string, maxLen: number): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen - 1) + \"…\";\n}\n\n// =============================================================================\n// Renderer Export\n// =============================================================================\n\n/**\n * Default HTML render options.\n */\nconst defaultHTMLOptions: Omit<HTMLRenderOptions, keyof RenderOptions> = {\n interactive: true,\n timeTravel: true,\n heatmap: true,\n animationDuration: 200,\n theme: \"auto\",\n layout: \"TB\",\n};\n\n/**\n * Create the HTML renderer.\n */\nexport function htmlRenderer(): Renderer {\n return {\n name: \"html\",\n supportsLive: true,\n\n render(ir: WorkflowIR, options: RenderOptions): string {\n const htmlOptions: HTMLRenderOptions = {\n ...options,\n ...defaultHTMLOptions,\n ...(options as Partial<HTMLRenderOptions>),\n };\n\n return generateHTML(ir, htmlOptions);\n },\n };\n}\n\n/**\n * Render workflow IR to HTML with custom options.\n */\nexport function renderToHTML(\n ir: WorkflowIR,\n options: Partial<HTMLRenderOptions> = {}\n): string {\n const fullOptions: HTMLRenderOptions = {\n showTimings: true,\n showKeys: false,\n colors: {\n pending: \"#6c757d\",\n running: \"#ffc107\",\n success: \"#198754\",\n error: \"#dc3545\",\n aborted: \"#6c757d\",\n cached: \"#0dcaf0\",\n skipped: \"#adb5bd\",\n },\n ...defaultHTMLOptions,\n ...options,\n };\n\n return generateHTML(ir, fullOptions);\n}\n","/**\n * Live Visualizer - Real-time terminal updates during workflow execution.\n *\n * Uses ANSI escape codes to update the terminal in-place, showing\n * workflow progress as it happens.\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n LiveVisualizerOptions,\n RenderOptions,\n ScopeEndEvent,\n ScopeStartEvent,\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder } from \"./ir-builder\";\nimport { asciiRenderer, defaultColorScheme } from \"./renderers\";\n\n// =============================================================================\n// ANSI Escape Codes\n// =============================================================================\n\nconst ANSI = {\n /** Clear from cursor to end of screen */\n clearToEnd: \"\\x1b[J\",\n /** Move cursor up N lines */\n cursorUp: (n: number) => `\\x1b[${n}A`,\n /** Move cursor to beginning of line */\n cursorToStart: \"\\x1b[G\",\n /** Hide cursor */\n hideCursor: \"\\x1b[?25l\",\n /** Show cursor */\n showCursor: \"\\x1b[?25h\",\n /** Save cursor position */\n saveCursor: \"\\x1b[s\",\n /** Restore cursor position */\n restoreCursor: \"\\x1b[u\",\n};\n\n// =============================================================================\n// Live Visualizer Interface\n// =============================================================================\n\n/**\n * Live visualizer with real-time terminal updates.\n */\nexport interface LiveVisualizer {\n /** Process a workflow event */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n /** Process a scope event */\n handleScopeEvent: (event: ScopeStartEvent | ScopeEndEvent) => void;\n /** Process a decision event */\n handleDecisionEvent: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n /** Get current IR state */\n getIR: () => WorkflowIR;\n /** Render current state to string (without terminal output) */\n render: () => string;\n /** Start live rendering to terminal */\n start: () => void;\n /** Stop live rendering */\n stop: () => void;\n /** Force an immediate redraw */\n refresh: () => void;\n /** Reset state for a new workflow */\n reset: () => void;\n}\n\n// =============================================================================\n// Create Live Visualizer\n// =============================================================================\n\n/**\n * Create a live visualizer for real-time terminal updates.\n *\n * @example\n * ```typescript\n * const live = createLiveVisualizer({ workflowName: 'my-workflow' });\n * const workflow = createWorkflow(deps, { onEvent: live.handleEvent });\n *\n * live.start();\n * await workflow(async (step) => { ... });\n * live.stop();\n * ```\n */\nexport function createLiveVisualizer(\n options: LiveVisualizerOptions = {}\n): LiveVisualizer {\n const {\n workflowName,\n detectParallel = true,\n showTimings = true,\n showKeys = false,\n colors: customColors,\n stream = process.stdout,\n updateInterval = 100,\n } = options;\n\n const builder = createIRBuilder({ detectParallel });\n const renderer = asciiRenderer();\n\n // Render options\n const renderOptions: RenderOptions = {\n showTimings,\n showKeys,\n terminalWidth: stream.columns ?? 80,\n colors: { ...defaultColorScheme, ...customColors },\n };\n\n // State\n let isRunning = false;\n let lastOutput = \"\";\n let lastLineCount = 0;\n let throttleTimeout: ReturnType<typeof setTimeout> | null = null;\n let pendingUpdate = false;\n\n /**\n * Write to the output stream.\n */\n function write(text: string): void {\n if (stream.writable) {\n stream.write(text);\n }\n }\n\n /**\n * Clear the previous output and write new content.\n */\n function redraw(): void {\n if (!isRunning) return;\n\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n // If output hasn't changed, skip redraw\n if (output === lastOutput) return;\n\n // Clear previous output\n if (lastLineCount > 0) {\n // Move cursor up and clear\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n // Write new output\n write(output);\n write(\"\\n\");\n\n // Track line count for next clear\n lastOutput = output;\n lastLineCount = output.split(\"\\n\").length;\n }\n\n /**\n * Schedule a throttled redraw.\n */\n function scheduleRedraw(): void {\n if (!isRunning) return;\n\n pendingUpdate = true;\n\n if (throttleTimeout === null) {\n throttleTimeout = setTimeout(() => {\n throttleTimeout = null;\n if (pendingUpdate) {\n pendingUpdate = false;\n redraw();\n }\n }, updateInterval);\n }\n }\n\n /**\n * Handle a workflow event.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Route scope events to handleScopeEvent for proper IR building\n if (event.type === \"scope_start\" || event.type === \"scope_end\") {\n handleScopeEvent(event as ScopeStartEvent | ScopeEndEvent);\n return;\n }\n\n builder.handleEvent(event);\n\n if (isRunning) {\n // Immediate redraw for start/end events, throttled for others\n if (\n event.type === \"workflow_start\" ||\n event.type === \"workflow_success\" ||\n event.type === \"workflow_error\"\n ) {\n redraw();\n } else {\n scheduleRedraw();\n }\n }\n }\n\n /**\n * Handle a scope event.\n */\n function handleScopeEvent(event: ScopeStartEvent | ScopeEndEvent): void {\n builder.handleScopeEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Handle a decision event.\n */\n function handleDecisionEvent(\n event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent\n ): void {\n builder.handleDecisionEvent(event);\n if (isRunning) {\n scheduleRedraw();\n }\n }\n\n /**\n * Get the current IR state.\n */\n function getIR(): WorkflowIR {\n const ir = builder.getIR();\n if (workflowName && !ir.root.name) {\n ir.root.name = workflowName;\n }\n return ir;\n }\n\n /**\n * Render current state to string.\n */\n function render(): string {\n return renderer.render(getIR(), renderOptions);\n }\n\n /**\n * Start live rendering.\n */\n function start(): void {\n if (isRunning) return;\n\n isRunning = true;\n lastOutput = \"\";\n lastLineCount = 0;\n\n // Hide cursor during updates\n write(ANSI.hideCursor);\n\n // Initial render\n redraw();\n }\n\n /**\n * Stop live rendering.\n */\n function stop(): void {\n if (!isRunning) return;\n\n isRunning = false;\n\n // Clear any pending throttle\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n\n // Final redraw to show completed state\n const ir = getIR();\n const output = renderer.render(ir, renderOptions);\n\n if (lastLineCount > 0) {\n write(ANSI.cursorUp(lastLineCount));\n write(ANSI.cursorToStart);\n write(ANSI.clearToEnd);\n }\n\n write(output);\n write(\"\\n\");\n\n // Show cursor again\n write(ANSI.showCursor);\n }\n\n /**\n * Force an immediate redraw.\n */\n function refresh(): void {\n if (throttleTimeout !== null) {\n clearTimeout(throttleTimeout);\n throttleTimeout = null;\n }\n pendingUpdate = false;\n redraw();\n }\n\n /**\n * Reset state for a new workflow.\n */\n function reset(): void {\n builder.reset();\n lastOutput = \"\";\n lastLineCount = 0;\n }\n\n return {\n handleEvent,\n handleScopeEvent,\n handleDecisionEvent,\n getIR,\n render,\n start,\n stop,\n refresh,\n reset,\n };\n}\n","/**\n * Decision Tracker - Helper for tracking conditional logic in workflows.\n *\n * This module provides utilities to track decision points (if/switch statements)\n * so they can be visualized in workflow diagrams.\n *\n * @example\n * ```typescript\n * import { trackDecision } from '@jagreehal/workflow/visualize';\n *\n * const workflow = createWorkflow(deps, {\n * onEvent: (event) => {\n * // Pass events to visualizer\n * viz.handleEvent(event);\n * }\n * });\n *\n * await workflow(async (step) => {\n * const user = await step(fetchUser(id));\n *\n * // Track a decision point\n * const decision = trackDecision('user-role-check', {\n * condition: 'user.role === \"admin\"',\n * value: user.role\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * await step(processAdminAction(user));\n * } else {\n * decision.takeBranch('user', false);\n * await step(processUserAction(user));\n * }\n *\n * decision.end();\n * });\n * ```\n */\n\nimport type {\n DecisionStartEvent,\n DecisionBranchEvent,\n DecisionEndEvent,\n} from \"./types\";\n\n// =============================================================================\n// Decision Tracker\n// =============================================================================\n\n/**\n * Options for creating a decision tracker.\n */\nexport interface DecisionTrackerOptions {\n /** Condition being evaluated (e.g., \"user.role === 'admin'\") */\n condition?: string;\n /** Value being evaluated */\n value?: unknown;\n /** Name/label for this decision point */\n name?: string;\n /** Workflow ID (auto-generated if not provided) */\n workflowId?: string;\n /** Event emitter function */\n emit?: (event: DecisionStartEvent | DecisionBranchEvent | DecisionEndEvent) => void;\n}\n\n/**\n * Track a decision point in your workflow.\n *\n * Use this to annotate conditional logic (if/switch) so it appears\n * in workflow visualizations.\n *\n * @param decisionId - Unique identifier for this decision\n * @param options - Decision tracking options\n * @returns A tracker object with methods to track branches\n *\n * @example\n * ```typescript\n * const decision = trackDecision('check-role', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (event) => viz.handleDecisionEvent(event)\n * });\n *\n * if (user.role === 'admin') {\n * decision.takeBranch('admin', true);\n * // ... admin logic\n * } else {\n * decision.takeBranch('user', false);\n * // ... user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackDecision(\n decisionId: string,\n options: DecisionTrackerOptions = {}\n): DecisionTracker {\n const {\n condition,\n value,\n name,\n workflowId = crypto.randomUUID(),\n emit,\n } = options;\n\n const startTs = Date.now();\n let branchTaken: string | boolean | undefined;\n const branches: Array<{ label: string; condition?: string; taken: boolean }> = [];\n\n function takeBranch(\n label: string,\n taken: boolean,\n branchCondition?: string\n ): void {\n branches.push({ label, condition: branchCondition, taken });\n if (taken) {\n branchTaken = label;\n }\n\n emit?.({\n type: \"decision_branch\",\n workflowId,\n decisionId,\n branchLabel: label,\n condition: branchCondition,\n taken,\n ts: Date.now(),\n });\n }\n\n function end(): void {\n const durationMs = Date.now() - startTs;\n emit?.({\n type: \"decision_end\",\n workflowId,\n decisionId,\n branchTaken,\n ts: Date.now(),\n durationMs,\n });\n }\n\n // Emit start event immediately\n emit?.({\n type: \"decision_start\",\n workflowId,\n decisionId,\n condition,\n decisionValue: value,\n name,\n ts: startTs,\n });\n\n return {\n takeBranch,\n end,\n getBranchTaken: () => branchTaken,\n getBranches: () => [...branches],\n };\n}\n\n/**\n * Decision tracker instance.\n */\nexport interface DecisionTracker {\n /**\n * Mark that a branch was taken or skipped.\n * @param label - Label for this branch (e.g., \"if\", \"else\", \"case 'admin'\")\n * @param taken - Whether this branch was executed\n * @param branchCondition - Optional condition for this specific branch\n */\n takeBranch(label: string, taken: boolean, branchCondition?: string): void;\n\n /**\n * End the decision tracking.\n * Call this after all branches have been evaluated.\n */\n end(): void;\n\n /**\n * Get which branch was taken.\n */\n getBranchTaken(): string | boolean | undefined;\n\n /**\n * Get all branches (taken and skipped).\n */\n getBranches(): Array<{ label: string; condition?: string; taken: boolean }>;\n}\n\n// =============================================================================\n// Convenience Helpers\n// =============================================================================\n\n/**\n * Track a simple if/else decision.\n *\n * @example\n * ```typescript\n * const decision = trackIf('check-admin', user.role === 'admin', {\n * condition: 'user.role === \"admin\"',\n * value: user.role,\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * if (decision.condition) {\n * decision.then();\n * // admin logic\n * } else {\n * decision.else();\n * // user logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackIf(\n decisionId: string,\n condition: boolean,\n options: Omit<DecisionTrackerOptions, \"value\"> & { value?: unknown } = {}\n): IfTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? String(condition),\n value: options.value ?? condition,\n });\n\n return {\n ...tracker,\n condition,\n then: () => {\n tracker.takeBranch(\"if\", true);\n },\n else: () => {\n // Mark else branch as taken (true) when the else block executes\n tracker.takeBranch(\"else\", true);\n },\n };\n}\n\n/**\n * If tracker with convenience methods.\n */\nexport interface IfTracker extends DecisionTracker {\n /** The condition value */\n condition: boolean;\n /** Mark the \"if\" branch as taken */\n then(): void;\n /** Mark the \"else\" branch as taken */\n else(): void;\n}\n\n/**\n * Track a switch statement decision.\n *\n * @example\n * ```typescript\n * const decision = trackSwitch('process-type', user.type, {\n * emit: (e) => viz.handleDecisionEvent(e)\n * });\n *\n * switch (user.type) {\n * case 'admin':\n * decision.case('admin', true);\n * // admin logic\n * break;\n * case 'user':\n * decision.case('user', true);\n * // user logic\n * break;\n * default:\n * decision.default(true);\n * // default logic\n * }\n *\n * decision.end();\n * ```\n */\nexport function trackSwitch(\n decisionId: string,\n value: unknown,\n options: Omit<DecisionTrackerOptions, \"value\"> = {}\n): SwitchTracker {\n const tracker = trackDecision(decisionId, {\n ...options,\n condition: options.condition ?? `switch(${String(value)})`,\n value,\n });\n\n return {\n ...tracker,\n value,\n case: (caseValue: string | number, taken: boolean) => {\n tracker.takeBranch(`case '${caseValue}'`, taken, `value === '${caseValue}'`);\n },\n default: (taken: boolean) => {\n tracker.takeBranch(\"default\", taken);\n },\n };\n}\n\n/**\n * Switch tracker with convenience methods.\n */\nexport interface SwitchTracker extends DecisionTracker {\n /** The value being switched on */\n value: unknown;\n /** Mark a case branch */\n case(caseValue: string | number, taken: boolean): void;\n /** Mark the default branch */\n default(taken: boolean): void;\n}\n","/**\n * Time Travel Debugger\n *\n * Records IR snapshots at each event, enabling:\n * - Step-by-step forward/backward navigation\n * - Seeking to any point in execution\n * - Playback at various speeds\n * - State inspection at any moment\n */\n\nimport type { WorkflowEvent } from \"../core\";\nimport type {\n IRSnapshot,\n TimeTravelState,\n WorkflowIR,\n} from \"./types\";\nimport { createIRBuilder, type IRBuilder, type IRBuilderOptions } from \"./ir-builder\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Options for the time-travel controller.\n */\nexport interface TimeTravelOptions {\n /** Maximum snapshots to store (ring buffer) */\n maxSnapshots?: number;\n /** Automatically record snapshots on each event */\n autoRecord?: boolean;\n /** IR builder options (passed through) */\n builderOptions?: Omit<IRBuilderOptions, \"enableSnapshots\" | \"maxSnapshots\">;\n}\n\n/**\n * Time-travel controller interface.\n */\nexport interface TimeTravelController {\n /** Handle a workflow event (records snapshot if recording) */\n handleEvent: (event: WorkflowEvent<unknown>) => void;\n\n /** Navigate to specific snapshot index */\n seek: (index: number) => WorkflowIR | undefined;\n\n /** Move one step forward */\n stepForward: () => WorkflowIR | undefined;\n\n /** Move one step backward */\n stepBackward: () => WorkflowIR | undefined;\n\n /** Start playback at given speed (1.0 = realtime) */\n play: (speed?: number) => void;\n\n /** Pause playback */\n pause: () => void;\n\n /** Get current IR state */\n getCurrentIR: () => WorkflowIR;\n\n /** Get IR at specific snapshot index */\n getIRAt: (index: number) => WorkflowIR | undefined;\n\n /** Get all snapshots */\n getSnapshots: () => IRSnapshot[];\n\n /** Get snapshot at specific index */\n getSnapshotAt: (index: number) => IRSnapshot | undefined;\n\n /** Get current time-travel state */\n getState: () => TimeTravelState;\n\n /** Subscribe to state changes */\n onStateChange: (callback: (state: TimeTravelState) => void) => () => void;\n\n /** Start/resume recording */\n startRecording: () => void;\n\n /** Stop recording */\n stopRecording: () => void;\n\n /** Reset to initial state */\n reset: () => void;\n\n /** Get the underlying IR builder */\n getBuilder: () => IRBuilder;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Create a time-travel controller for workflow debugging.\n *\n * @example\n * ```typescript\n * const controller = createTimeTravelController();\n *\n * // Feed events from workflow execution\n * workflow.onEvent(event => controller.handleEvent(event));\n *\n * // After execution, explore the timeline\n * controller.seek(0); // Go to start\n * controller.stepForward(); // Step through\n * controller.play(2); // Playback at 2x speed\n * ```\n */\nexport function createTimeTravelController(\n options: TimeTravelOptions = {}\n): TimeTravelController {\n const { maxSnapshots = 1000, autoRecord = true, builderOptions = {} } = options;\n\n // Create IR builder with snapshots enabled\n const builder = createIRBuilder({\n ...builderOptions,\n enableSnapshots: true,\n maxSnapshots,\n });\n\n // Controller state\n let state: TimeTravelState = {\n snapshots: [],\n currentIndex: -1,\n isPlaying: false,\n playbackSpeed: 1.0,\n isRecording: autoRecord,\n };\n\n // State change listeners\n const listeners = new Set<(state: TimeTravelState) => void>();\n\n // Playback timer\n let playbackTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Notify all listeners of state change.\n */\n function notifyListeners(): void {\n const currentState = getState();\n for (const listener of listeners) {\n listener(currentState);\n }\n }\n\n /**\n * Sync state from builder snapshots.\n */\n function syncFromBuilder(): void {\n state.snapshots = builder.getSnapshots();\n if (state.isRecording && state.snapshots.length > 0) {\n state.currentIndex = state.snapshots.length - 1;\n }\n }\n\n /**\n * Handle a workflow event.\n */\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Always forward to builder\n builder.handleEvent(event);\n\n // Sync snapshots if recording\n if (state.isRecording) {\n syncFromBuilder();\n notifyListeners();\n }\n }\n\n /**\n * Seek to a specific snapshot index.\n */\n function seek(index: number): WorkflowIR | undefined {\n const snapshots = builder.getSnapshots();\n if (index < 0 || index >= snapshots.length) {\n return undefined;\n }\n\n state.currentIndex = index;\n state.snapshots = snapshots;\n notifyListeners();\n\n return snapshots[index].ir;\n }\n\n /**\n * Move one step forward.\n */\n function stepForward(): WorkflowIR | undefined {\n return seek(state.currentIndex + 1);\n }\n\n /**\n * Move one step backward.\n */\n function stepBackward(): WorkflowIR | undefined {\n return seek(state.currentIndex - 1);\n }\n\n /**\n * Start playback at given speed.\n */\n function play(speed = 1.0): void {\n state.playbackSpeed = speed;\n state.isPlaying = true;\n notifyListeners();\n\n const playNext = (): void => {\n if (!state.isPlaying) return;\n\n const snapshots = builder.getSnapshots();\n if (state.currentIndex < snapshots.length - 1) {\n const current = snapshots[state.currentIndex];\n const next = snapshots[state.currentIndex + 1];\n\n // Calculate delay based on actual event timing\n const realDelay = next.timestamp - current.timestamp;\n const scaledDelay = realDelay / state.playbackSpeed;\n\n playbackTimer = setTimeout(() => {\n stepForward();\n playNext();\n }, Math.max(16, scaledDelay)); // Minimum 16ms (~60fps) for smooth updates\n } else {\n // Reached end of timeline\n pause();\n }\n };\n\n playNext();\n }\n\n /**\n * Pause playback.\n */\n function pause(): void {\n state.isPlaying = false;\n if (playbackTimer) {\n clearTimeout(playbackTimer);\n playbackTimer = null;\n }\n notifyListeners();\n }\n\n /**\n * Get current IR state.\n */\n function getCurrentIR(): WorkflowIR {\n const snapshots = builder.getSnapshots();\n if (state.currentIndex >= 0 && state.currentIndex < snapshots.length) {\n return snapshots[state.currentIndex].ir;\n }\n // Return live IR if no valid snapshot\n return builder.getIR();\n }\n\n /**\n * Get IR at specific snapshot index.\n */\n function getIRAt(index: number): WorkflowIR | undefined {\n return builder.getIRAt(index);\n }\n\n /**\n * Get all snapshots.\n */\n function getSnapshots(): IRSnapshot[] {\n return builder.getSnapshots();\n }\n\n /**\n * Get snapshot at specific index.\n */\n function getSnapshotAt(index: number): IRSnapshot | undefined {\n return builder.getSnapshotAt(index);\n }\n\n /**\n * Get current time-travel state.\n */\n function getState(): TimeTravelState {\n return {\n snapshots: builder.getSnapshots(),\n currentIndex: state.currentIndex,\n isPlaying: state.isPlaying,\n playbackSpeed: state.playbackSpeed,\n isRecording: state.isRecording,\n };\n }\n\n /**\n * Subscribe to state changes.\n */\n function onStateChange(\n callback: (state: TimeTravelState) => void\n ): () => void {\n listeners.add(callback);\n return () => listeners.delete(callback);\n }\n\n /**\n * Start or resume recording.\n */\n function startRecording(): void {\n state.isRecording = true;\n notifyListeners();\n }\n\n /**\n * Stop recording.\n */\n function stopRecording(): void {\n state.isRecording = false;\n notifyListeners();\n }\n\n /**\n * Reset to initial state.\n */\n function reset(): void {\n pause();\n builder.reset();\n state = {\n snapshots: [],\n currentIndex: -1,\n isPlaying: false,\n playbackSpeed: 1.0,\n isRecording: autoRecord,\n };\n notifyListeners();\n }\n\n /**\n * Get the underlying IR builder.\n */\n function getBuilder(): IRBuilder {\n return builder;\n }\n\n return {\n handleEvent,\n seek,\n stepForward,\n stepBackward,\n play,\n pause,\n getCurrentIR,\n getIRAt,\n getSnapshots,\n getSnapshotAt,\n getState,\n onStateChange,\n startRecording,\n stopRecording,\n reset,\n getBuilder,\n };\n}\n","/**\n * Development Server\n *\n * Provides a local HTTP server with WebSocket support for:\n * - Serving the HTML visualizer\n * - Live streaming workflow events\n * - Time-travel control from the browser\n * - Performance data broadcasting\n *\n * The `ws` package is an optional peer dependency.\n * Install it with: npm install ws\n */\n\nimport type { Server as HTTPServer, IncomingMessage, ServerResponse } from \"node:http\";\nimport { createServer } from \"node:http\";\nimport { execFile } from \"node:child_process\";\nimport type { WorkflowEvent } from \"../core\";\nimport type { WorkflowIR, ServerMessage, WebVisualizerMessage, HeatmapData } from \"./types\";\nimport { createTimeTravelController, type TimeTravelController } from \"./time-travel\";\nimport { createPerformanceAnalyzer, type PerformanceAnalyzer } from \"./performance-analyzer\";\nimport { renderToHTML } from \"./renderers/html\";\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * WebSocket interface (matches `ws` package).\n */\ninterface WebSocketLike {\n send(data: string): void;\n on(event: \"message\", listener: (data: Buffer | string) => void): void;\n on(event: \"close\", listener: () => void): void;\n on(event: \"error\", listener: (error: Error) => void): void;\n readyState: number;\n OPEN: number;\n}\n\n/**\n * WebSocket server interface (matches `ws` package).\n */\ninterface WebSocketServerLike {\n clients: Set<WebSocketLike>;\n on(event: \"connection\", listener: (ws: WebSocketLike, req: IncomingMessage) => void): void;\n close(): void;\n}\n\n/**\n * Options for the dev server.\n */\nexport interface DevServerOptions {\n /** Port to listen on (default: 3377) */\n port?: number;\n /** Hostname to bind to (default: localhost) */\n host?: string;\n /** Auto-open browser when starting (default: true) */\n autoOpen?: boolean;\n /** Workflow name for the visualizer title */\n workflowName?: string;\n /** Enable time-travel debugging (default: true) */\n timeTravel?: boolean;\n /** Enable performance heatmap (default: true) */\n heatmap?: boolean;\n /** Max snapshots for time-travel (default: 1000) */\n maxSnapshots?: number;\n}\n\n/**\n * Dev server interface.\n */\nexport interface DevServer {\n /** Start the server */\n start(): Promise<{ port: number; url: string }>;\n /** Stop the server */\n stop(): Promise<void>;\n /** Handle a workflow event (forwards to time-travel and broadcasts) */\n handleEvent(event: WorkflowEvent<unknown>): void;\n /** Push an IR update to all clients */\n pushUpdate(ir: WorkflowIR): void;\n /** Push heatmap data to all clients */\n pushHeatmap(data: HeatmapData): void;\n /** Mark workflow as complete */\n complete(): void;\n /** Get the time-travel controller */\n getTimeTravel(): TimeTravelController;\n /** Get the performance analyzer */\n getAnalyzer(): PerformanceAnalyzer;\n /** Get current IR */\n getCurrentIR(): WorkflowIR;\n}\n\n// =============================================================================\n// Implementation\n// =============================================================================\n\n/**\n * Create a development server for the workflow visualizer.\n *\n * @example\n * ```typescript\n * const server = createDevServer({ port: 3377 });\n * await server.start();\n *\n * // Forward events from workflow execution\n * workflow.onEvent(event => server.handleEvent(event));\n *\n * // When done\n * server.complete();\n * await server.stop();\n * ```\n */\nexport async function createDevServer(\n options: DevServerOptions = {}\n): Promise<DevServer> {\n const {\n port = 3377,\n host = \"localhost\",\n autoOpen = true,\n workflowName = \"Workflow\",\n timeTravel = true,\n heatmap = true,\n maxSnapshots = 1000,\n } = options;\n\n // Suppress unused variable warning - workflowName reserved for future use\n void workflowName;\n\n // Create time-travel controller and performance analyzer\n const ttController = createTimeTravelController({ maxSnapshots });\n const analyzer = createPerformanceAnalyzer();\n\n // Server state\n let httpServer: HTTPServer | null = null;\n let wsServer: WebSocketServerLike | null = null;\n let actualPort = port;\n let isRunning = false;\n\n /**\n * Broadcast a message to all connected WebSocket clients.\n */\n function broadcast(message: ServerMessage): void {\n if (!wsServer) return;\n const data = JSON.stringify(message);\n for (const client of wsServer.clients) {\n if (client.readyState === client.OPEN) {\n client.send(data);\n }\n }\n }\n\n /**\n * Handle incoming WebSocket message.\n */\n function handleClientMessage(ws: WebSocketLike, raw: Buffer | string): void {\n try {\n const msg = JSON.parse(\n typeof raw === \"string\" ? raw : raw.toString()\n ) as WebVisualizerMessage;\n\n switch (msg.type) {\n case \"time_travel_seek\": {\n const payload = msg.payload as { index: number };\n const ir = ttController.seek(payload.index);\n if (ir) {\n ws.send(JSON.stringify({ type: \"ir_update\", payload: ir }));\n }\n break;\n }\n case \"time_travel_play\": {\n const payload = msg.payload as { speed?: number } | undefined;\n ttController.play(payload?.speed);\n break;\n }\n case \"time_travel_pause\":\n ttController.pause();\n break;\n case \"time_travel_step_forward\": {\n const ir = ttController.stepForward();\n if (ir) {\n ws.send(JSON.stringify({ type: \"ir_update\", payload: ir }));\n }\n break;\n }\n case \"time_travel_step_backward\": {\n const ir = ttController.stepBackward();\n if (ir) {\n ws.send(JSON.stringify({ type: \"ir_update\", payload: ir }));\n }\n break;\n }\n case \"request_snapshots\": {\n const snapshots = ttController.getSnapshots().map((s) => ({\n id: s.id,\n eventIndex: s.eventIndex,\n timestamp: s.timestamp,\n }));\n ws.send(JSON.stringify({ type: \"snapshots_list\", payload: snapshots }));\n break;\n }\n case \"toggle_heatmap\":\n case \"set_heatmap_metric\": {\n // Client handles these locally, but we can use to sync state\n break;\n }\n }\n } catch (e) {\n console.error(\"[DevServer] Failed to handle message:\", e);\n }\n }\n\n /**\n * Generate HTML for the current state.\n */\n function generatePage(): string {\n const ir = ttController.getCurrentIR();\n const wsUrl = `ws://${host}:${actualPort}`;\n\n return renderToHTML(ir, {\n interactive: true,\n timeTravel,\n heatmap,\n theme: \"auto\",\n layout: \"TB\",\n wsUrl,\n });\n }\n\n /**\n * Handle HTTP requests.\n */\n function handleRequest(req: IncomingMessage, res: ServerResponse): void {\n const url = req.url ?? \"/\";\n\n if (url === \"/\" || url === \"/index.html\") {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(generatePage());\n return;\n }\n\n if (url === \"/api/snapshots\") {\n const snapshots = ttController.getSnapshots().map((s) => ({\n id: s.id,\n eventIndex: s.eventIndex,\n timestamp: s.timestamp,\n }));\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(snapshots));\n return;\n }\n\n if (url === \"/api/performance\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(analyzer.exportData());\n return;\n }\n\n if (url === \"/api/ir\") {\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify(ttController.getCurrentIR()));\n return;\n }\n\n // 404\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"Not Found\");\n }\n\n /**\n * Try to dynamically import `ws` package.\n */\n async function loadWebSocketServer(): Promise<WebSocketServerLike | null> {\n try {\n // Dynamic import of optional peer dependency (ws is optional)\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore - ws is an optional peer dependency\n const wsModule = await import(\"ws\");\n const ws = wsModule as {\n WebSocketServer?: new (options: { noServer: boolean }) => WebSocketServerLike;\n default?: {\n WebSocketServer?: new (options: { noServer: boolean }) => WebSocketServerLike;\n };\n };\n const WebSocketServer = ws.WebSocketServer ?? ws.default?.WebSocketServer;\n if (!WebSocketServer) {\n console.warn(\"[DevServer] WebSocket server class not found in ws module\");\n return null;\n }\n return new WebSocketServer({ noServer: true });\n } catch {\n console.warn(\n \"[DevServer] ws package not installed. Live updates disabled.\\n\" +\n \"Install with: npm install ws\"\n );\n return null;\n }\n }\n\n /**\n * Open URL in browser using platform-specific command.\n * Uses execFile for safety (no shell injection possible).\n */\n function openBrowser(url: string): void {\n const platform = process.platform;\n\n // Validate URL format to ensure it's a localhost URL\n if (!url.startsWith(\"http://localhost:\") && !url.startsWith(\"http://127.0.0.1:\")) {\n console.warn(\"[DevServer] Refusing to open non-localhost URL\");\n return;\n }\n\n if (platform === \"darwin\") {\n execFile(\"open\", [url], (err) => {\n if (err) console.warn(\"[DevServer] Failed to open browser:\", err.message);\n });\n } else if (platform === \"win32\") {\n // On Windows, use cmd.exe with /c start to handle URLs properly\n execFile(\"cmd.exe\", [\"/c\", \"start\", \"\", url], (err) => {\n if (err) console.warn(\"[DevServer] Failed to open browser:\", err.message);\n });\n } else {\n // Linux and other Unix-like systems\n execFile(\"xdg-open\", [url], (err) => {\n if (err) console.warn(\"[DevServer] Failed to open browser:\", err.message);\n });\n }\n }\n\n // =============================================================================\n // Public Interface\n // =============================================================================\n\n async function start(): Promise<{ port: number; url: string }> {\n if (isRunning) {\n return { port: actualPort, url: `http://${host}:${actualPort}` };\n }\n\n // Create HTTP server\n httpServer = createServer(handleRequest);\n\n // Try to load WebSocket server\n wsServer = await loadWebSocketServer();\n\n if (wsServer) {\n // Handle WebSocket upgrade\n httpServer.on(\"upgrade\", (request, socket, head) => {\n if (!wsServer) return;\n\n // Manual WebSocket handshake\n const ws = wsServer as unknown as {\n handleUpgrade: (\n req: IncomingMessage,\n socket: unknown,\n head: Buffer,\n callback: (ws: WebSocketLike) => void\n ) => void;\n };\n\n ws.handleUpgrade(request, socket, head, (client) => {\n // Send initial state\n client.send(\n JSON.stringify({\n type: \"ir_update\",\n payload: ttController.getCurrentIR(),\n })\n );\n\n // Handle messages\n client.on(\"message\", (data) => handleClientMessage(client, data));\n client.on(\"error\", (err) => console.error(\"[DevServer] WS error:\", err));\n });\n });\n\n // Subscribe to time-travel state changes\n ttController.onStateChange((state) => {\n broadcast({ type: \"time_travel_state\", payload: state });\n });\n }\n\n // Start listening\n return new Promise((resolve, reject) => {\n if (!httpServer) {\n reject(new Error(\"HTTP server not initialized\"));\n return;\n }\n\n httpServer.on(\"error\", (err: NodeJS.ErrnoException) => {\n if (err.code === \"EADDRINUSE\") {\n // Try next port\n actualPort++;\n httpServer?.listen(actualPort, host);\n } else {\n reject(err);\n }\n });\n\n httpServer.on(\"listening\", () => {\n isRunning = true;\n const url = `http://${host}:${actualPort}`;\n console.log(`[DevServer] Visualizer running at ${url}`);\n\n if (autoOpen) {\n openBrowser(url);\n }\n\n resolve({ port: actualPort, url });\n });\n\n httpServer.listen(actualPort, host);\n });\n }\n\n async function stop(): Promise<void> {\n if (!isRunning) return;\n\n return new Promise((resolve) => {\n if (wsServer) {\n wsServer.close();\n wsServer = null;\n }\n\n if (httpServer) {\n httpServer.close(() => {\n httpServer = null;\n isRunning = false;\n resolve();\n });\n } else {\n resolve();\n }\n });\n }\n\n function handleEvent(event: WorkflowEvent<unknown>): void {\n // Forward to time-travel controller\n ttController.handleEvent(event);\n\n // Forward to performance analyzer\n analyzer.addEvent(event);\n\n // Broadcast IR update\n broadcast({ type: \"ir_update\", payload: ttController.getCurrentIR() });\n }\n\n function pushUpdate(ir: WorkflowIR): void {\n broadcast({ type: \"ir_update\", payload: ir });\n }\n\n function pushHeatmap(data: HeatmapData): void {\n // Convert Map to object for JSON serialization\n const heat: Record<string, number> = {};\n for (const [k, v] of data.heat) {\n heat[k] = v;\n }\n broadcast({\n type: \"performance_data\",\n payload: { ...data, heat },\n });\n }\n\n function complete(): void {\n // Finalize analyzer run\n analyzer.finalizeRun(\"current\");\n broadcast({ type: \"workflow_complete\", payload: null });\n }\n\n function getTimeTravel(): TimeTravelController {\n return ttController;\n }\n\n function getAnalyzer(): PerformanceAnalyzer {\n return analyzer;\n }\n\n function getCurrentIR(): WorkflowIR {\n return ttController.getCurrentIR();\n }\n\n return {\n start,\n stop,\n handleEvent,\n pushUpdate,\n pushHeatmap,\n complete,\n getTimeTravel,\n getAnalyzer,\n getCurrentIR,\n };\n}\n"],"mappings":"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A;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAycV,CCvjBO,SAASC,GAAqBC,EAK1B,CACT,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA2BHA,EAAQ,YAAc,wBAA0B,EAAE;AAAA,MAClDA,EAAQ,WAAa,qBAAuB,EAAE;AAAA,MAC9CA,EAAQ,MAAQ,mBAAmBA,EAAQ,KAAK,MAAQ,EAAE;AAAA,MAC1DA,EAAQ,QAAU,kBAAoB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["require_constants","__commonJSMin","exports","module","BINARY_TYPES","hasBlob","require_buffer_util","__commonJSMin","exports","module","EMPTY_BUFFER","FastBuffer","concat","list","totalLength","target","offset","i","buf","_mask","source","mask","output","length","_unmask","buffer","toArrayBuffer","toBuffer","data","bufferUtil","require_limiter","__commonJSMin","exports","module","kDone","kRun","Limiter","concurrency","job","require_permessage_deflate","__commonJSMin","exports","module","zlib","bufferUtil","Limiter","kStatusCode","FastBuffer","TRAILER","kPerMessageDeflate","kTotalLength","kCallback","kBuffers","kError","zlibLimiter","PerMessageDeflate","options","isServer","maxPayload","concurrency","params","configurations","callback","offers","opts","accepted","response","key","value","num","data","fin","done","err","result","endpoint","windowBits","inflateOnError","inflateOnData","deflateOnData","chunk","require_validation","__commonJSMin","exports","module","isUtf8","hasBlob","tokenChars","isValidStatusCode","code","_isValidUTF8","buf","len","i","isBlob","value","isValidUTF8","require_receiver","__commonJSMin","exports","module","Writable","PerMessageDeflate","BINARY_TYPES","EMPTY_BUFFER","kStatusCode","kWebSocket","concat","toArrayBuffer","unmask","isValidStatusCode","isValidUTF8","FastBuffer","GET_INFO","GET_PAYLOAD_LENGTH_16","GET_PAYLOAD_LENGTH_64","GET_MASK","GET_DATA","INFLATING","DEFER_EVENT","Receiver","options","chunk","encoding","cb","n","buf","dst","offset","error","compressed","num","data","err","messageLength","fragments","code","ErrorCtor","message","prefix","statusCode","errorCode","require_sender","__commonJSMin","exports","module","Duplex","randomFillSync","PerMessageDeflate","EMPTY_BUFFER","kWebSocket","NOOP","isBlob","isValidStatusCode","applyMask","toBuffer","kByteLength","maskBuffer","RANDOM_POOL_SIZE","randomPool","randomPoolPointer","DEFAULT","DEFLATING","GET_BLOB_DATA","Sender","_Sender","socket","extensions","generateMask","data","options","mask","merge","offset","skipMasking","dataLength","payloadLength","target","code","cb","buf","length","byteLength","readOnly","perMessageDeflate","opcode","rsv1","opts","blob","compress","arrayBuffer","err","callCallbacks","onError","_","params","list","sender","i","callback","require_event_target","__commonJSMin","exports","module","kForOnEventAttribute","kListener","kCode","kData","kError","kMessage","kReason","kTarget","kType","kWasClean","Event","type","CloseEvent","options","ErrorEvent","MessageEvent","EventTarget","handler","listener","wrapper","data","isBinary","event","callListener","code","message","error","thisArg","require_extension","__commonJSMin","exports","module","tokenChars","push","dest","name","elem","parse","header","offers","params","mustUnescape","isEscaping","inQuotes","extensionName","paramName","start","code","end","i","value","token","format","extensions","extension","configurations","k","values","v","require_websocket","__commonJSMin","exports","module","EventEmitter","https","http","net","tls","randomBytes","createHash","Duplex","Readable","URL","PerMessageDeflate","Receiver","Sender","isBlob","BINARY_TYPES","CLOSE_TIMEOUT","EMPTY_BUFFER","GUID","kForOnEventAttribute","kListener","kStatusCode","kWebSocket","NOOP","addEventListener","removeEventListener","format","parse","toBuffer","kAborted","protocolVersions","readyStates","subprotocolRegex","WebSocket","_WebSocket","address","protocols","options","initAsClient","type","socket","head","receiver","sender","receiverOnConclude","receiverOnDrain","receiverOnError","receiverOnMessage","receiverOnPing","receiverOnPong","senderOnError","socketOnClose","socketOnData","socketOnEnd","socketOnError","code","data","abortHandshake","err","setCloseTimer","mask","cb","sendAfterClose","opts","property","method","listener","handler","websocket","parsedUrl","isSecure","isIpcUrl","invalidUrlMessage","emitErrorAndClose","defaultPort","key","request","protocolSet","perMessageDeflate","tlsConnect","netConnect","protocol","parts","req","headers","value","isSameHost","res","location","statusCode","addr","upgrade","digest","serverProt","protError","secWebSocketExtensions","extensions","extensionNames","stream","message","length","reason","resume","receiverOnFinish","isBinary","chunk","require_stream","__commonJSMin","exports","module","WebSocket","Duplex","emitClose","stream","duplexOnEnd","duplexOnError","err","createWebSocketStream","ws","options","terminateOnDestroy","duplex","msg","isBinary","data","callback","called","chunk","encoding","require_subprotocol","__commonJSMin","exports","module","tokenChars","parse","header","protocols","start","end","i","code","protocol","require_websocket_server","__commonJSMin","exports","module","EventEmitter","http","Duplex","createHash","extension","PerMessageDeflate","subprotocol","WebSocket","CLOSE_TIMEOUT","GUID","kWebSocket","keyRegex","RUNNING","CLOSING","CLOSED","WebSocketServer","options","callback","req","res","body","emitConnection","addListeners","socket","head","cb","emitClose","server","index","socketOnError","key","upgrade","version","abortHandshakeOrEmitwsClientError","abortHandshake","secWebSocketProtocol","protocols","secWebSocketExtensions","extensions","perMessageDeflate","offers","info","verified","code","message","headers","ws","protocol","params","value","map","event","h","err","wrapper_exports","__export","Receiver","Sender","WebSocket","WebSocketServer","createWebSocketStream","wrapper_default","import_stream","import_receiver","import_sender","import_websocket","import_websocket_server","init_wrapper","__esmMin","visualize_exports","__export","asciiRenderer","createDevServer","createEventCollector","createIRBuilder","createLiveVisualizer","createParallelDetector","createPerformanceAnalyzer","createTimeTravelController","createVisualizer","defaultColorScheme","detectParallelGroups","getHeatLevel","hasChildren","htmlRenderer","isDecisionNode","isParallelNode","isRaceNode","isSequenceNode","isStepNode","loggerRenderer","mermaidRenderer","renderToHTML","trackDecision","trackIf","trackSwitch","visualizeEvents","__toCommonJS","formatDuration","ms","minutes","seconds","generateId","hasRealScopeNodes","nodes","node","detectParallelGroups","options","minOverlapMs","maxGapMs","stepsWithTiming","nonStepNodes","i","a","b","groups","currentGroup","step","groupStart","s","groupEnd","startedTogether","hasTrueOverlap","overlapDuration","groupedNodes","group","position","children","startTs","endTs","parallelNode","deriveGroupState","originalIndex","g","c","createParallelDetector","createIRBuilder","options","detectParallel","parallelDetection","enableSnapshots","maxSnapshots","workflowId","workflowStartTs","workflowState","workflowError","workflowDurationMs","activeSteps","scopeStack","decisionStack","currentNodes","createdAt","lastUpdatedAt","hookState","snapshots","eventIndex","getStepId","event","generateId","addNode","node","decision","branch","firstBranch","captureSnapshot","ir","getIR","activeStepsCopy","id","step","snapshot","handleEvent","active","hookExec","handleScopeEvent","scope","deriveState","handleDecisionEvent","branchKey","existing","branches","b","children","c","getCurrentNodes","nodes","detectParallelGroups","root","hasHooks","reset","getSnapshots","getSnapshotAt","index","getIRAt","clearSnapshots","isStepNode","node","isSequenceNode","isParallelNode","isRaceNode","isDecisionNode","hasChildren","RESET","BOLD","DIM","FG_RED","FG_GREEN","FG_YELLOW","FG_BLUE","FG_GRAY","FG_WHITE","colorize","text","color","bold","dim","defaultColorScheme","getStateSymbol","state","getColoredSymbol","colors","symbol","colorByState","stripAnsi","str","BOX","HEAT_COLORS","RESET","getHeatColor","heat","applyHeatColor","text","color","SPARK_CHARS","renderSparkline","values","width","subset","min","range","v","normalized","index","padEnd","str","visibleLen","stripAnsi","padding","horizontalLine","title","titleText","remainingWidth","leftPad","rightPad","renderHookExecution","hook","label","colors","symbol","colorize","timing","dim","formatDuration","context","error","renderHooks","hooks","lines","asciiRenderer","ir","options","defaultColorScheme","innerWidth","workflowName","headerTitle","bold","hookLines","line","childLines","renderNodes","status","footer","colorByState","nodes","depth","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","getColoredSymbol","name","enhanced","nodeId","nameColored","inputStr","outputStr","timingStr","timingDisplay","history","timeoutInfo","hookExec","hookSymbol","hookTiming","indent","mode","i","child","prefix","nestedLines","winnerSuffix","condition","decisionValue","branchTaken","branch","branchSymbol","branchColor","branchLabel","branchCondition","flattenNodes","nodes","result","node","branch","percentile","sortedValues","p","index","getHeatLevel","heat","createPerformanceAnalyzer","timingData","retryData","errorData","timeoutData","currentRunEvents","getNodeId","event","processEvents","events","stepState","id","state","timeout","timings","retry","error","addRun","run","addEvent","finalizeRun","_runId","computePerformance","nodeId","sorted","a","b","mean","variance","acc","t","getNodePerformance","getHeatmap","ir","metric","allNodes","values","perf","value","vals","v","min","max","range","getAllPerformance","getSlowestNodes","limit","getErrorProneNodes","getRetryProneNodes","exportData","importData","json","data","k","clear","getStyleDefinitions","getHeatmapStyleDefinitions","getHeatClass","level","getHookStyleDefinitions","renderHooks","hooks","lines","options","lastHookId","hookId","state","icon","timing","formatDuration","context","nodeCounter","generateNodeId","prefix","resetNodeCounter","escapeMermaidText","text","escapeSubgraphName","mermaidRenderer","ir","enhanced","hookExitId","startId","prevNodeId","child","result","renderNode","endId","endIcon","endLabel","endShape","endClass","getStyleDefinitions","getHeatmapStyleDefinitions","node","isStepNode","renderStepNode","isParallelNode","renderParallelNode","isRaceNode","renderRaceNode","isDecisionNode","renderDecisionNode","id","mermaidOpts","showRetryEdges","showErrorEdges","showTimeoutEdges","label","stateIcon","ioInfo","inputStr","outputStr","hookInfo","hookExec","hookIcon","hookTiming","escapedLabel","nodeClass","nodeId","heat","level","getHeatLevel","getHeatClass","shape","retryLabel","errorNodeId","errorLabel","timeoutNodeId","timeoutMs","subgraphId","forkId","joinId","name","modeLabel","note","childExitIds","exitId","stateClass","winnerExitId","isWinner","decisionId","condition","decisionValue","decisionLabel","branchExitIds","takenBranchExitId","branch","branchId","branchLabelText","branchLabel","branchClass","edgeLabel","prevId","stripAnsi","str","collectSteps","nodes","steps","walk","nodeList","node","isStepNode","isSequenceNode","isParallelNode","isRaceNode","isDecisionNode","branch","stepToLog","step","log","calculateSummary","successCount","errorCount","cacheHits","skippedCount","totalRetries","slowestStep","hooksToLog","hooks","stepKey","hook","entry","buildLoggerOutput","ir","options","root","includeDiagram","stripColors","output","hookLog","diagram","asciiRenderer","loggerRenderer","generateStyles","theme","lightColors","darkColors","generateThemeVars","colors","themeCSS","generateClientScript","options","NODE_WIDTH","NODE_HEIGHT","NODE_SPACING_H","NODE_SPACING_V","CONTAINER_PADDING","layoutWorkflow","nodes","direction","isVertical","layoutNodes","currentX","currentY","maxWidth","maxHeight","node","result","layoutFlowNode","x","y","_isVertical","isStepNode","isParallelNode","isRaceNode","containerType","label","children","innerX","innerY","innerMaxWidth","innerMaxHeight","child","containerWidth","containerHeight","isDecisionNode","branch","renderLayoutNodeSVG","showTimings","renderContainerSVG","renderStepSVG","timing","formatDuration","escapeAttr","escapeXml","truncate","childrenSVG","c","renderEdgesSVG","edges","i","from","to","x1","y1","x2","y2","generateHTML","ir","options","layout","svgWidth","svgHeight","nodesSVG","n","edgesSVG","workflowName","css","generateStyles","js","generateClientScript","serializeWorkflowData","buildWorkflowData","collectNodes","flowNodes","str","maxLen","defaultHTMLOptions","htmlRenderer","htmlOptions","renderToHTML","fullOptions","ANSI","n","createLiveVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","stream","updateInterval","builder","createIRBuilder","renderer","asciiRenderer","renderOptions","defaultColorScheme","isRunning","lastOutput","lastLineCount","throttleTimeout","pendingUpdate","write","text","redraw","ir","getIR","output","scheduleRedraw","handleEvent","event","handleScopeEvent","handleDecisionEvent","render","start","stop","refresh","reset","trackDecision","decisionId","options","condition","value","name","workflowId","emit","startTs","branchTaken","branches","takeBranch","label","taken","branchCondition","end","durationMs","trackIf","tracker","trackSwitch","caseValue","createTimeTravelController","options","maxSnapshots","autoRecord","builderOptions","builder","createIRBuilder","state","listeners","playbackTimer","notifyListeners","currentState","getState","listener","syncFromBuilder","handleEvent","event","seek","index","snapshots","stepForward","stepBackward","play","speed","playNext","current","scaledDelay","pause","getCurrentIR","getIRAt","getSnapshots","getSnapshotAt","onStateChange","callback","startRecording","stopRecording","reset","getBuilder","import_node_http","import_node_child_process","createDevServer","options","port","host","autoOpen","workflowName","timeTravel","heatmap","maxSnapshots","ttController","createTimeTravelController","analyzer","createPerformanceAnalyzer","httpServer","wsServer","actualPort","isRunning","broadcast","message","data","client","handleClientMessage","ws","raw","msg","payload","ir","snapshots","s","e","generatePage","wsUrl","renderToHTML","handleRequest","req","res","url","loadWebSocketServer","WebSocketServer","openBrowser","platform","err","start","request","socket","head","state","resolve","reject","stop","handleEvent","event","pushUpdate","pushHeatmap","heat","k","v","complete","getTimeTravel","getAnalyzer","getCurrentIR","createVisualizer","options","workflowName","detectParallel","showTimings","showKeys","customColors","builder","createIRBuilder","updateCallbacks","ascii","asciiRenderer","mermaid","mermaidRenderer","logger","loggerRenderer","renderOptions","defaultColorScheme","notifyUpdate","ir","callback","handleEvent","event","handleScopeEvent","handleDecisionEvent","getIR","render","renderAs","format","reset","onUpdate","visualizeEvents","events","viz","createEventCollector","e"]}
|