@etherna/docker 1.7.1 → 1.7.2
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/bin.cjs +5 -5
- package/dist/bin.cjs.map +1 -1
- package/dist/index.cjs +4 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["styles","process","sleep","sleep","sleep"],"sources":["../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js","../src/catalog.ts","../src/dependency-runner.ts","../src/consts.ts","../src/portless.ts","../src/env.ts","../src/resolve-options.ts","../src/utils.ts","../src/runtime/docker.ts","../src/runtime/names.ts","../src/ssl-trust.ts","../src/services/asp.ts","../src/web3.ts","../src/services/bee.ts","../src/services/context.ts","../src/services/elastic.ts","../src/services/mongo.ts","../src/builder.ts","../src/services/shkeeper.ts","../src/session.ts","../src/manager.ts"],"sourcesContent":["const ANSI_BACKGROUND_OFFSET = 10;\n\nconst wrapAnsi16 = (offset = 0) => code => `\\u001B[${code + offset}m`;\n\nconst wrapAnsi256 = (offset = 0) => code => `\\u001B[${38 + offset};5;${code}m`;\n\nconst wrapAnsi16m = (offset = 0) => (red, green, blue) => `\\u001B[${38 + offset};2;${red};${green};${blue}m`;\n\nconst styles = {\n\tmodifier: {\n\t\treset: [0, 0],\n\t\t// 21 isn't widely supported and 22 does the same thing\n\t\tbold: [1, 22],\n\t\tdim: [2, 22],\n\t\titalic: [3, 23],\n\t\tunderline: [4, 24],\n\t\toverline: [53, 55],\n\t\tinverse: [7, 27],\n\t\thidden: [8, 28],\n\t\tstrikethrough: [9, 29],\n\t},\n\tcolor: {\n\t\tblack: [30, 39],\n\t\tred: [31, 39],\n\t\tgreen: [32, 39],\n\t\tyellow: [33, 39],\n\t\tblue: [34, 39],\n\t\tmagenta: [35, 39],\n\t\tcyan: [36, 39],\n\t\twhite: [37, 39],\n\n\t\t// Bright color\n\t\tblackBright: [90, 39],\n\t\tgray: [90, 39], // Alias of `blackBright`\n\t\tgrey: [90, 39], // Alias of `blackBright`\n\t\tredBright: [91, 39],\n\t\tgreenBright: [92, 39],\n\t\tyellowBright: [93, 39],\n\t\tblueBright: [94, 39],\n\t\tmagentaBright: [95, 39],\n\t\tcyanBright: [96, 39],\n\t\twhiteBright: [97, 39],\n\t},\n\tbgColor: {\n\t\tbgBlack: [40, 49],\n\t\tbgRed: [41, 49],\n\t\tbgGreen: [42, 49],\n\t\tbgYellow: [43, 49],\n\t\tbgBlue: [44, 49],\n\t\tbgMagenta: [45, 49],\n\t\tbgCyan: [46, 49],\n\t\tbgWhite: [47, 49],\n\n\t\t// Bright color\n\t\tbgBlackBright: [100, 49],\n\t\tbgGray: [100, 49], // Alias of `bgBlackBright`\n\t\tbgGrey: [100, 49], // Alias of `bgBlackBright`\n\t\tbgRedBright: [101, 49],\n\t\tbgGreenBright: [102, 49],\n\t\tbgYellowBright: [103, 49],\n\t\tbgBlueBright: [104, 49],\n\t\tbgMagentaBright: [105, 49],\n\t\tbgCyanBright: [106, 49],\n\t\tbgWhiteBright: [107, 49],\n\t},\n};\n\nexport const modifierNames = Object.keys(styles.modifier);\nexport const foregroundColorNames = Object.keys(styles.color);\nexport const backgroundColorNames = Object.keys(styles.bgColor);\nexport const colorNames = [...foregroundColorNames, ...backgroundColorNames];\n\nfunction assembleStyles() {\n\tconst codes = new Map();\n\n\tfor (const [groupName, group] of Object.entries(styles)) {\n\t\tfor (const [styleName, style] of Object.entries(group)) {\n\t\t\tstyles[styleName] = {\n\t\t\t\topen: `\\u001B[${style[0]}m`,\n\t\t\t\tclose: `\\u001B[${style[1]}m`,\n\t\t\t};\n\n\t\t\tgroup[styleName] = styles[styleName];\n\n\t\t\tcodes.set(style[0], style[1]);\n\t\t}\n\n\t\tObject.defineProperty(styles, groupName, {\n\t\t\tvalue: group,\n\t\t\tenumerable: false,\n\t\t});\n\t}\n\n\tObject.defineProperty(styles, 'codes', {\n\t\tvalue: codes,\n\t\tenumerable: false,\n\t});\n\n\tstyles.color.close = '\\u001B[39m';\n\tstyles.bgColor.close = '\\u001B[49m';\n\n\tstyles.color.ansi = wrapAnsi16();\n\tstyles.color.ansi256 = wrapAnsi256();\n\tstyles.color.ansi16m = wrapAnsi16m();\n\tstyles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);\n\n\t// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js\n\tObject.defineProperties(styles, {\n\t\trgbToAnsi256: {\n\t\t\tvalue(red, green, blue) {\n\t\t\t\t// We use the extended greyscale palette here, with the exception of\n\t\t\t\t// black and white. normal palette only has 4 greyscale shades.\n\t\t\t\tif (red === green && green === blue) {\n\t\t\t\t\tif (red < 8) {\n\t\t\t\t\t\treturn 16;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (red > 248) {\n\t\t\t\t\t\treturn 231;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Math.round(((red - 8) / 247) * 24) + 232;\n\t\t\t\t}\n\n\t\t\t\treturn 16\n\t\t\t\t\t+ (36 * Math.round(red / 255 * 5))\n\t\t\t\t\t+ (6 * Math.round(green / 255 * 5))\n\t\t\t\t\t+ Math.round(blue / 255 * 5);\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToRgb: {\n\t\t\tvalue(hex) {\n\t\t\t\tconst matches = /[a-f\\d]{6}|[a-f\\d]{3}/i.exec(hex.toString(16));\n\t\t\t\tif (!matches) {\n\t\t\t\t\treturn [0, 0, 0];\n\t\t\t\t}\n\n\t\t\t\tlet [colorString] = matches;\n\n\t\t\t\tif (colorString.length === 3) {\n\t\t\t\t\tcolorString = [...colorString].map(character => character + character).join('');\n\t\t\t\t}\n\n\t\t\t\tconst integer = Number.parseInt(colorString, 16);\n\n\t\t\t\treturn [\n\t\t\t\t\t/* eslint-disable no-bitwise */\n\t\t\t\t\t(integer >> 16) & 0xFF,\n\t\t\t\t\t(integer >> 8) & 0xFF,\n\t\t\t\t\tinteger & 0xFF,\n\t\t\t\t\t/* eslint-enable no-bitwise */\n\t\t\t\t];\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi256: {\n\t\t\tvalue: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t\tansi256ToAnsi: {\n\t\t\tvalue(code) {\n\t\t\t\tif (code < 8) {\n\t\t\t\t\treturn 30 + code;\n\t\t\t\t}\n\n\t\t\t\tif (code < 16) {\n\t\t\t\t\treturn 90 + (code - 8);\n\t\t\t\t}\n\n\t\t\t\tlet red;\n\t\t\t\tlet green;\n\t\t\t\tlet blue;\n\n\t\t\t\tif (code >= 232) {\n\t\t\t\t\tred = (((code - 232) * 10) + 8) / 255;\n\t\t\t\t\tgreen = red;\n\t\t\t\t\tblue = red;\n\t\t\t\t} else {\n\t\t\t\t\tcode -= 16;\n\n\t\t\t\t\tconst remainder = code % 36;\n\n\t\t\t\t\tred = Math.floor(code / 36) / 5;\n\t\t\t\t\tgreen = Math.floor(remainder / 6) / 5;\n\t\t\t\t\tblue = (remainder % 6) / 5;\n\t\t\t\t}\n\n\t\t\t\tconst value = Math.max(red, green, blue) * 2;\n\n\t\t\t\tif (value === 0) {\n\t\t\t\t\treturn 30;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\tlet result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));\n\n\t\t\t\tif (value === 2) {\n\t\t\t\t\tresult += 60;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\trgbToAnsi: {\n\t\t\tvalue: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi: {\n\t\t\tvalue: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t});\n\n\treturn styles;\n}\n\nconst ansiStyles = assembleStyles();\n\nexport default ansiStyles;\n","import process from 'node:process';\nimport os from 'node:os';\nimport tty from 'node:tty';\n\n// From: https://github.com/sindresorhus/has-flag/blob/main/index.js\n/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {\nfunction hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) {\n\tconst prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');\n\tconst position = argv.indexOf(prefix + flag);\n\tconst terminatorPosition = argv.indexOf('--');\n\treturn position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);\n}\n\nconst {env} = process;\n\nlet flagForceColor;\nif (\n\thasFlag('no-color')\n\t|| hasFlag('no-colors')\n\t|| hasFlag('color=false')\n\t|| hasFlag('color=never')\n) {\n\tflagForceColor = 0;\n} else if (\n\thasFlag('color')\n\t|| hasFlag('colors')\n\t|| hasFlag('color=true')\n\t|| hasFlag('color=always')\n) {\n\tflagForceColor = 1;\n}\n\nfunction envForceColor() {\n\tif ('FORCE_COLOR' in env) {\n\t\tif (env.FORCE_COLOR === 'true') {\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (env.FORCE_COLOR === 'false') {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);\n\t}\n}\n\nfunction translateLevel(level) {\n\tif (level === 0) {\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tlevel,\n\t\thasBasic: true,\n\t\thas256: level >= 2,\n\t\thas16m: level >= 3,\n\t};\n}\n\nfunction _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {\n\tconst noFlagForceColor = envForceColor();\n\tif (noFlagForceColor !== undefined) {\n\t\tflagForceColor = noFlagForceColor;\n\t}\n\n\tconst forceColor = sniffFlags ? flagForceColor : noFlagForceColor;\n\n\tif (forceColor === 0) {\n\t\treturn 0;\n\t}\n\n\tif (sniffFlags) {\n\t\tif (hasFlag('color=16m')\n\t\t\t|| hasFlag('color=full')\n\t\t\t|| hasFlag('color=truecolor')) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (hasFlag('color=256')) {\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\t// Check for Azure DevOps pipelines.\n\t// Has to be above the `!streamIsTTY` check.\n\tif ('TF_BUILD' in env && 'AGENT_NAME' in env) {\n\t\treturn 1;\n\t}\n\n\tif (haveStream && !streamIsTTY && forceColor === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst min = forceColor || 0;\n\n\tif (env.TERM === 'dumb') {\n\t\treturn min;\n\t}\n\n\tif (process.platform === 'win32') {\n\t\t// Windows 10 build 10586 is the first Windows release that supports 256 colors.\n\t\t// Windows 10 build 14931 is the first release that supports 16m/TrueColor.\n\t\tconst osRelease = os.release().split('.');\n\t\tif (\n\t\t\tNumber(osRelease[0]) >= 10\n\t\t\t&& Number(osRelease[2]) >= 10_586\n\t\t) {\n\t\t\treturn Number(osRelease[2]) >= 14_931 ? 3 : 2;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tif ('CI' in env) {\n\t\tif (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn min;\n\t}\n\n\tif ('TEAMCITY_VERSION' in env) {\n\t\treturn /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;\n\t}\n\n\tif (env.COLORTERM === 'truecolor') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-kitty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-ghostty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'wezterm') {\n\t\treturn 3;\n\t}\n\n\tif ('TERM_PROGRAM' in env) {\n\t\tconst version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);\n\n\t\tswitch (env.TERM_PROGRAM) {\n\t\t\tcase 'iTerm.app': {\n\t\t\t\treturn version >= 3 ? 3 : 2;\n\t\t\t}\n\n\t\t\tcase 'Apple_Terminal': {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\n\tif (/-256(color)?$/i.test(env.TERM)) {\n\t\treturn 2;\n\t}\n\n\tif (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {\n\t\treturn 1;\n\t}\n\n\tif ('COLORTERM' in env) {\n\t\treturn 1;\n\t}\n\n\treturn min;\n}\n\nexport function createSupportsColor(stream, options = {}) {\n\tconst level = _supportsColor(stream, {\n\t\tstreamIsTTY: stream && stream.isTTY,\n\t\t...options,\n\t});\n\n\treturn translateLevel(level);\n}\n\nconst supportsColor = {\n\tstdout: createSupportsColor({isTTY: tty.isatty(1)}),\n\tstderr: createSupportsColor({isTTY: tty.isatty(2)}),\n};\n\nexport default supportsColor;\n","// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`.\nexport function stringReplaceAll(string, substring, replacer) {\n\tlet index = string.indexOf(substring);\n\tif (index === -1) {\n\t\treturn string;\n\t}\n\n\tconst substringLength = substring.length;\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\treturnValue += string.slice(endIndex, index) + substring + replacer;\n\t\tendIndex = index + substringLength;\n\t\tindex = string.indexOf(substring, endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n\nexport function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\tconst gotCR = string[index - 1] === '\\r';\n\t\treturnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\\r\\n' : '\\n') + postfix;\n\t\tendIndex = index + 1;\n\t\tindex = string.indexOf('\\n', endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n","import ansiStyles from '#ansi-styles';\nimport supportsColor from '#supports-color';\nimport { // eslint-disable-line import/order\n\tstringReplaceAll,\n\tstringEncaseCRLFWithFirstIndex,\n} from './utilities.js';\n\nconst {stdout: stdoutColor, stderr: stderrColor} = supportsColor;\n\nconst GENERATOR = Symbol('GENERATOR');\nconst STYLER = Symbol('STYLER');\nconst IS_EMPTY = Symbol('IS_EMPTY');\n\n// `supportsColor.level` → `ansiStyles.color[name]` mapping\nconst levelMapping = [\n\t'ansi',\n\t'ansi',\n\t'ansi256',\n\t'ansi16m',\n];\n\nconst styles = Object.create(null);\n\nconst applyOptions = (object, options = {}) => {\n\tif (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {\n\t\tthrow new Error('The `level` option should be an integer from 0 to 3');\n\t}\n\n\t// Detect level if not set manually\n\tconst colorLevel = stdoutColor ? stdoutColor.level : 0;\n\tobject.level = options.level === undefined ? colorLevel : options.level;\n};\n\nexport class Chalk {\n\tconstructor(options) {\n\t\t// eslint-disable-next-line no-constructor-return\n\t\treturn chalkFactory(options);\n\t}\n}\n\nconst chalkFactory = options => {\n\tconst chalk = (...strings) => strings.join(' ');\n\tapplyOptions(chalk, options);\n\n\tObject.setPrototypeOf(chalk, createChalk.prototype);\n\n\treturn chalk;\n};\n\nfunction createChalk(options) {\n\treturn chalkFactory(options);\n}\n\nObject.setPrototypeOf(createChalk.prototype, Function.prototype);\n\nfor (const [styleName, style] of Object.entries(ansiStyles)) {\n\tstyles[styleName] = {\n\t\tget() {\n\t\t\tconst builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);\n\t\t\tObject.defineProperty(this, styleName, {value: builder});\n\t\t\treturn builder;\n\t\t},\n\t};\n}\n\nstyles.visible = {\n\tget() {\n\t\tconst builder = createBuilder(this, this[STYLER], true);\n\t\tObject.defineProperty(this, 'visible', {value: builder});\n\t\treturn builder;\n\t},\n};\n\nconst getModelAnsi = (model, level, type, ...arguments_) => {\n\tif (model === 'rgb') {\n\t\tif (level === 'ansi16m') {\n\t\t\treturn ansiStyles[type].ansi16m(...arguments_);\n\t\t}\n\n\t\tif (level === 'ansi256') {\n\t\t\treturn ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));\n\t\t}\n\n\t\treturn ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));\n\t}\n\n\tif (model === 'hex') {\n\t\treturn getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_));\n\t}\n\n\treturn ansiStyles[type][model](...arguments_);\n};\n\nconst usedModels = ['rgb', 'hex', 'ansi256'];\n\nfor (const model of usedModels) {\n\tstyles[model] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n\n\tconst bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);\n\tstyles[bgModel] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n}\n\nconst proto = Object.defineProperties(() => {}, {\n\t...styles,\n\tlevel: {\n\t\tenumerable: true,\n\t\tget() {\n\t\t\treturn this[GENERATOR].level;\n\t\t},\n\t\tset(level) {\n\t\t\tthis[GENERATOR].level = level;\n\t\t},\n\t},\n});\n\nconst createStyler = (open, close, parent) => {\n\tlet openAll;\n\tlet closeAll;\n\tif (parent === undefined) {\n\t\topenAll = open;\n\t\tcloseAll = close;\n\t} else {\n\t\topenAll = parent.openAll + open;\n\t\tcloseAll = close + parent.closeAll;\n\t}\n\n\treturn {\n\t\topen,\n\t\tclose,\n\t\topenAll,\n\t\tcloseAll,\n\t\tparent,\n\t};\n};\n\nconst createBuilder = (self, _styler, _isEmpty) => {\n\t// Single argument is hot path, implicit coercion is faster than anything\n\t// eslint-disable-next-line no-implicit-coercion\n\tconst builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));\n\n\t// We alter the prototype because we must return a function, but there is\n\t// no way to create a function with a different prototype\n\tObject.setPrototypeOf(builder, proto);\n\n\tbuilder[GENERATOR] = self;\n\tbuilder[STYLER] = _styler;\n\tbuilder[IS_EMPTY] = _isEmpty;\n\n\treturn builder;\n};\n\nconst applyStyle = (self, string) => {\n\tif (self.level <= 0 || !string) {\n\t\treturn self[IS_EMPTY] ? '' : string;\n\t}\n\n\tlet styler = self[STYLER];\n\n\tif (styler === undefined) {\n\t\treturn string;\n\t}\n\n\tconst {openAll, closeAll} = styler;\n\tif (string.includes('\\u001B')) {\n\t\twhile (styler !== undefined) {\n\t\t\t// Replace any instances already present with a re-opening code\n\t\t\t// otherwise only the part of the string until said closing code\n\t\t\t// will be colored, and the rest will simply be 'plain'.\n\t\t\tstring = stringReplaceAll(string, styler.close, styler.open);\n\n\t\t\tstyler = styler.parent;\n\t\t}\n\t}\n\n\t// We can move both next actions out of loop, because remaining actions in loop won't have\n\t// any/visible effect on parts we add here. Close the styling before a linebreak and reopen\n\t// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92\n\tconst lfIndex = string.indexOf('\\n');\n\tif (lfIndex !== -1) {\n\t\tstring = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);\n\t}\n\n\treturn openAll + string + closeAll;\n};\n\nObject.defineProperties(createChalk.prototype, styles);\n\nconst chalk = createChalk();\nexport const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0});\n\nexport {\n\tmodifierNames,\n\tforegroundColorNames,\n\tbackgroundColorNames,\n\tcolorNames,\n\n\t// TODO: Remove these aliases in the next major version\n\tmodifierNames as modifiers,\n\tforegroundColorNames as foregroundColors,\n\tbackgroundColorNames as backgroundColors,\n\tcolorNames as colors,\n} from './vendor/ansi-styles/index.js';\n\nexport {\n\tstdoutColor as supportsColor,\n\tstderrColor as supportsColorStderr,\n};\n\nexport default chalk;\n","import type { EthernaServiceName } from \"./types\"\n\n/**\n * Canonical startup nodes, mirroring the dependency tree built by today's Vite plugin\n * (`etherna()` in `src/index.ts`). This is intentionally NOT the legacy CLI\n * `SERVICE_DEPENDENCIES` graph (e.g. CLI's `gateway` also depends on `beehive`; the Vite tree's\n * `gateway` only depends on `mongo` + `sso`). The Vite tree is canonical for `@etherna/docker`.\n */\nexport type StartupCode =\n | \"bee-blockchain\"\n | \"bee-nodes\"\n | \"shkeeper\"\n | \"mongo\"\n | \"sso\"\n | \"index\"\n | \"beehive\"\n | \"gateway\"\n | \"credit\"\n | \"elastic\"\n\nexport interface StartupNodeDefinition {\n code: StartupCode\n /** Logical service name this startup node belongs to (drives its default `enabled` flag). */\n service: EthernaServiceName\n dependencies: StartupCode[]\n onFailure: \"stop\"\n}\n\nexport const SERVICE_CATALOG: Record<StartupCode, StartupNodeDefinition> = {\n \"bee-blockchain\": {\n code: \"bee-blockchain\",\n service: \"bee\",\n dependencies: [],\n onFailure: \"stop\",\n },\n \"bee-nodes\": {\n code: \"bee-nodes\",\n service: \"bee\",\n dependencies: [\"bee-blockchain\"],\n onFailure: \"stop\",\n },\n shkeeper: {\n code: \"shkeeper\",\n service: \"shkeeper\",\n dependencies: [],\n onFailure: \"stop\",\n },\n mongo: {\n code: \"mongo\",\n service: \"mongo\",\n dependencies: [],\n onFailure: \"stop\",\n },\n sso: {\n code: \"sso\",\n service: \"sso\",\n dependencies: [\"mongo\"],\n onFailure: \"stop\",\n },\n index: {\n code: \"index\",\n service: \"index\",\n dependencies: [\"mongo\"],\n onFailure: \"stop\",\n },\n beehive: {\n code: \"beehive\",\n service: \"beehive\",\n dependencies: [\"mongo\"],\n onFailure: \"stop\",\n },\n gateway: {\n code: \"gateway\",\n service: \"gateway\",\n dependencies: [\"mongo\", \"sso\"],\n onFailure: \"stop\",\n },\n credit: {\n code: \"credit\",\n service: \"credit\",\n dependencies: [\"mongo\", \"sso\", \"shkeeper\"],\n onFailure: \"stop\",\n },\n elastic: {\n code: \"elastic\",\n service: \"elastic\",\n dependencies: [],\n onFailure: \"stop\",\n },\n}\n\n/** Every logical service name (including opt-in services). */\nexport const ALL_SERVICE_NAMES: readonly EthernaServiceName[] = [\n \"blockchain\",\n \"bee\",\n \"beehive\",\n \"credit\",\n \"elastic\",\n \"gateway\",\n \"index\",\n \"mongo\",\n \"shkeeper\",\n \"sso\",\n]\n\n/** Default `etherna start` / `etherna start all` expansion — shkeeper stays opt-in. */\nexport const DEFAULT_START_SERVICE_NAMES: readonly EthernaServiceName[] =\n ALL_SERVICE_NAMES.filter((name) => name !== \"shkeeper\")\n\n/** Startup codes directly implied by a logical service name, before dependency expansion. */\nfunction codesForServiceName(name: EthernaServiceName): StartupCode[] {\n switch (name) {\n case \"blockchain\":\n return [\"bee-blockchain\"]\n case \"bee\":\n return [\"bee-blockchain\", \"bee-nodes\"]\n default:\n return [name]\n }\n}\n\n/** Transitively expands a set of startup codes to include every code they (recursively) depend on. */\nfunction expandCodes(codes: Iterable<StartupCode>): Set<StartupCode> {\n const out = new Set<StartupCode>()\n\n function visit(code: StartupCode): void {\n if (out.has(code)) {\n return\n }\n out.add(code)\n for (const dep of SERVICE_CATALOG[code].dependencies) {\n visit(dep)\n }\n }\n\n for (const code of codes) {\n visit(code)\n }\n return out\n}\n\n/**\n * True when `service` is covered by `codes`. `bee` reflects the node group itself\n * (`bee-nodes`) — not merely its `bee-blockchain` dependency — so requesting `\"blockchain\"` alone\n * does not report `bee` as enabled, while requesting `\"bee\"` reports both `bee` and `blockchain`\n * (since `bee-nodes` depends on `bee-blockchain`).\n */\nfunction isServiceCoveredByCodes(service: EthernaServiceName, codes: Set<StartupCode>): boolean {\n if (service === \"bee\") {\n return codes.has(\"bee-nodes\")\n }\n if (service === \"blockchain\") {\n return codes.has(\"bee-blockchain\")\n }\n return codes.has(service)\n}\n\n/**\n * Expands requested logical service names into a full enabled map for every\n * {@link EthernaServiceName}, following the canonical Vite-plugin dependency graph\n * ({@link SERVICE_CATALOG}). Dependencies of a requested service are force-enabled even if not\n * explicitly requested (e.g. requesting `\"gateway\"` also enables `\"mongo\"` and `\"sso\"`).\n */\nexport function resolveEnabledFromServices(\n names: EthernaServiceName[],\n): Record<EthernaServiceName, boolean> {\n const requestedCodes = names.flatMap(codesForServiceName)\n const codes = expandCodes(requestedCodes)\n\n const enabled = {} as Record<EthernaServiceName, boolean>\n for (const service of ALL_SERVICE_NAMES) {\n enabled[service] = isServiceCoveredByCodes(service, codes)\n }\n return enabled\n}\n","export type DependencyFailureMode = \"stop\" | \"log\"\n\nexport interface DependencyRunnerServiceDefinition<TCode extends string = string> {\n code: TCode\n dependencies?: TCode[]\n /** When `false`, startup is skipped and dependents treat this node as satisfied. Defaults to `true`. */\n enabled?: boolean\n /** Runs after dependencies settle and before `startupCallback` (only when enabled). */\n beforeStartup?: () => void | Promise<void>\n /** Defaults to `\"stop\"`. */\n onFailure?: DependencyFailureMode\n startupCallback: () => Promise<boolean>\n}\n\nexport interface DependencyRunnerLogger {\n logError: (code: string, message: string) => void\n}\n\nexport type DependencyRunnerServiceStatus = \"started\" | \"failed\" | \"blocked\" | \"skipped\"\n\nexport interface DependencyRunnerServiceResult<TCode extends string = string> {\n code: TCode\n status: DependencyRunnerServiceStatus\n error?: Error\n blockedBy?: TCode[]\n}\n\nexport interface DependencyRunnerResult<TCode extends string = string> {\n shouldStop: boolean\n services: DependencyRunnerServiceResult<TCode>[]\n}\n\nexport class DependencyTreeValidationError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"DependencyTreeValidationError\"\n }\n}\n\nfunction normalizeError(reason: unknown): Error {\n if (reason instanceof Error) {\n return reason\n }\n return new Error(String(reason))\n}\n\nfunction blockedByFromDependencyResults<TCode extends string>(\n dependencyCodes: TCode[],\n depResults: DependencyRunnerServiceResult<TCode>[],\n): TCode[] {\n const out = new Set<TCode>()\n for (let i = 0; i < depResults.length; i++) {\n const r = depResults[i] as DependencyRunnerServiceResult<TCode>\n if (r.status === \"started\" || r.status === \"skipped\") {\n continue\n }\n if (r.status === \"failed\") {\n out.add(r.code)\n } else {\n const inherited = r.blockedBy\n if (inherited && inherited.length > 0) {\n for (const c of inherited) {\n out.add(c)\n }\n } else {\n out.add(dependencyCodes[i] as TCode)\n }\n }\n }\n return [...out]\n}\n\nexport function validateDependencyTree<TCode extends string>(\n services: DependencyRunnerServiceDefinition<TCode>[],\n): void {\n const codes = new Set<TCode>()\n for (const s of services) {\n if (codes.has(s.code)) {\n throw new DependencyTreeValidationError(`Duplicate service code \"${String(s.code)}\".`)\n }\n codes.add(s.code)\n }\n\n for (const s of services) {\n const deps = s.dependencies ?? []\n for (const d of deps) {\n if (d === s.code) {\n throw new DependencyTreeValidationError(\n `Service \"${String(s.code)}\" cannot depend on itself.`,\n )\n }\n if (!codes.has(d)) {\n throw new DependencyTreeValidationError(\n `Service \"${String(s.code)}\" depends on unknown service \"${String(d)}\".`,\n )\n }\n }\n }\n\n const visiting = new Set<TCode>()\n const visited = new Set<TCode>()\n const byCode = new Map(services.map((s) => [s.code, s] as const))\n\n function dfs(code: TCode): void {\n if (visited.has(code)) {\n return\n }\n if (visiting.has(code)) {\n throw new DependencyTreeValidationError(\n `Dependency cycle detected involving service \"${String(code)}\".`,\n )\n }\n visiting.add(code)\n const svc = byCode.get(code)\n if (!svc) {\n return\n }\n for (const d of svc.dependencies ?? []) {\n dfs(d)\n }\n visiting.delete(code)\n visited.add(code)\n }\n\n for (const s of services) {\n dfs(s.code)\n }\n}\n\n/** Runs a service startup dependency tree, resolving each node concurrently once its dependencies settle. */\nexport function createDependencyRunner<TCode extends string>(\n services: DependencyRunnerServiceDefinition<TCode>[],\n logger: DependencyRunnerLogger,\n): {\n start: () => Promise<DependencyRunnerResult<TCode>>\n} {\n validateDependencyTree(services)\n\n const byCode = new Map(services.map((s) => [s.code, s] as const))\n const pending = new Map<TCode, Promise<DependencyRunnerServiceResult<TCode>>>()\n\n function getTask(code: TCode): Promise<DependencyRunnerServiceResult<TCode>> {\n const existing = pending.get(code)\n if (existing) {\n return existing\n }\n\n const svc = byCode.get(code)\n\n if (!svc) {\n throw new DependencyTreeValidationError(`Unknown service code \"${String(code)}\".`)\n }\n\n const task = (async (): Promise<DependencyRunnerServiceResult<TCode>> => {\n const dependencyCodes = svc.dependencies ?? []\n const depResults = await Promise.all(dependencyCodes.map((d) => getTask(d)))\n\n const anyBad = depResults.some(\n (r) => r.status !== \"started\" && r.status !== \"skipped\",\n )\n if (anyBad) {\n return {\n code,\n status: \"blocked\",\n blockedBy: blockedByFromDependencyResults(dependencyCodes, depResults),\n }\n }\n\n if (svc.enabled === false) {\n return { code, status: \"skipped\" }\n }\n\n const mode: DependencyFailureMode = svc.onFailure ?? \"stop\"\n\n try {\n if (svc.beforeStartup) {\n await svc.beforeStartup()\n }\n const ok = await svc.startupCallback()\n if (!ok) {\n const err = new Error(\"Service startup returned false\")\n if (mode === \"log\") {\n logger.logError(String(code), err.message)\n }\n return { code, status: \"failed\", error: err }\n }\n return { code, status: \"started\" }\n } catch (reason: unknown) {\n const err = normalizeError(reason)\n if (mode === \"log\") {\n logger.logError(String(code), err.message)\n }\n return { code, status: \"failed\", error: err }\n }\n })()\n\n pending.set(code, task)\n return task\n }\n\n return {\n start: async () => {\n const serviceResults = await Promise.all(services.map((s) => getTask(s.code)))\n const shouldStop = serviceResults.some(\n (r) => r.status === \"failed\" && (byCode.get(r.code)?.onFailure ?? \"stop\") === \"stop\",\n )\n return { shouldStop, services: serviceResults }\n },\n }\n}\n","export const DEFAULT_CACHE_DIR = \"node_modules/.vite\"\n\nexport const CERTIFICATE_DIR = \".ssl\"\nexport const CERTIFICATE_CERT_NAME = \"etherna.crt\"\nexport const CERTIFICATE_KEY_NAME = \"etherna.key\"\nexport const CERTIFICATE_PFX_NAME = \"etherna.pfx\"\nexport const CERTIFICATE_PASSWORD = \"\"\n\nexport const CONTAINER_CERTS_DIR = \"/usr/local/share/ca-certificates\"\n","import { spawn } from \"node:child_process\"\n\n/** HTTP proxy port used by Portless when running without TLS (see portless docs). */\nexport const PORTLESS_PROXY_PORT = 1355\n\n/** Alias names registered with `portless alias <name> <port>`. */\nexport type PortlessServiceAlias =\n | \"app\"\n | \"sso\"\n | \"index\"\n | \"credit\"\n | \"gateway\"\n | \"beehive\"\n | \"bee\"\n | \"shkeeper\"\n\nexport const PORTLESS_CONTAINER_ALIASES: Record<string, PortlessServiceAlias> = {\n \"etherna-sso\": \"sso\",\n \"etherna-index\": \"index\",\n \"etherna-credit\": \"credit\",\n \"etherna-gateway\": \"gateway\",\n \"etherna-beehive\": \"beehive\",\n}\n\nexport function getPortlessPublicUrl(alias: PortlessServiceAlias): string {\n return `http://${alias}.localhost:${PORTLESS_PROXY_PORT}`\n}\n\n/** Env name set by the Portless CLI when it wraps your dev process (public URL for the app). */\nexport const PORTLESS_URL_ENV = \"PORTLESS_URL\"\n\n/** Normalizes a base URL for OAuth/client env (trim, strip trailing slashes). */\nexport function normalizePortlessAppPublicUrl(url: string): string {\n return url.trim().replace(/\\/+$/, \"\")\n}\n\nexport function portlessProxyStartArgs(): string[] {\n return [\"proxy\", \"start\", \"-p\", String(PORTLESS_PROXY_PORT), \"--no-tls\"]\n}\n\nexport function portlessProxyStopArgs(): string[] {\n return [\"proxy\", \"stop\"]\n}\n\nexport function portlessAliasAddArgs(name: string, port: number, force = false): string[] {\n const args = [\"alias\", name, String(port)]\n if (force) {\n args.push(\"--force\")\n }\n return args\n}\n\nexport function portlessAliasRemoveArgs(name: string): string[] {\n return [\"alias\", \"--remove\", name]\n}\n\nexport async function runPortlessCli(args: string[]): Promise<{\n code: number\n stderr: string\n stdout: string\n}> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"portless\", args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] })\n let stdout = \"\"\n let stderr = \"\"\n proc.stdout?.on(\"data\", (d) => {\n stdout += String(d)\n })\n proc.stderr?.on(\"data\", (d) => {\n stderr += String(d)\n })\n proc.on(\"error\", reject)\n proc.on(\"exit\", (code) => {\n resolve({ code: code ?? 1, stderr, stdout })\n })\n })\n}\n\n/** True when the `portless` CLI is on PATH and runs. */\nexport async function isPortlessCliAvailable(): Promise<boolean> {\n try {\n const r = await runPortlessCli([\"--version\"])\n return r.code === 0\n } catch {\n return false\n }\n}\n\n/**\n * Starts the Portless HTTP proxy on {@link PORTLESS_PROXY_PORT}. If the proxy is already\n * running, returns `startedByUs: false` without failing.\n */\nexport async function ensurePortlessProxy(): Promise<{ startedByUs: boolean }> {\n const r = await runPortlessCli(portlessProxyStartArgs())\n if (r.code === 0) {\n return { startedByUs: true }\n }\n const combined = `${r.stderr}\\n${r.stdout}`\n if (/already|in use|running|listen/i.test(combined)) {\n return { startedByUs: false }\n }\n throw new Error(\n `portless proxy start failed (exit ${r.code}): ${combined.trim() || \"(no output)\"}`,\n )\n}\n\n/** Parses a port from env strings, URL fragments, or numbers for Portless CLI registration. */\nexport function parsePortlessPort(value: unknown): number {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value\n }\n const s = String(value).trim()\n if (s === \"\") {\n throw new Error(\"Port value is empty\")\n }\n const n = Number.parseInt(s, 10)\n if (!Number.isFinite(n)) {\n throw new Error(`Invalid port: ${String(value)}`)\n }\n return n\n}\n\n/** Registers a single alias with the Portless CLI (`portless alias <name> <port> --force`). */\nexport async function addPortlessAlias(name: PortlessServiceAlias, port: unknown): Promise<void> {\n const portNumber = parsePortlessPort(port)\n const r = await runPortlessCli(portlessAliasAddArgs(name, portNumber, true))\n if (r.code !== 0) {\n const combined = `${r.stderr}\\n${r.stdout}`\n throw new Error(`portless alias ${name} ${portNumber} failed: ${combined.trim()}`)\n }\n}\n\nexport async function removePortlessAliases(names: readonly PortlessServiceAlias[]): Promise<void> {\n for (const name of names) {\n await runPortlessCli(portlessAliasRemoveArgs(name))\n }\n}\n\nexport async function stopPortlessProxy(): Promise<void> {\n await runPortlessCli(portlessProxyStopArgs())\n}\n","import { CERTIFICATE_PASSWORD, CERTIFICATE_PFX_NAME, CONTAINER_CERTS_DIR } from \"./consts\"\nimport {\n getPortlessPublicUrl,\n normalizePortlessAppPublicUrl,\n type PortlessServiceAlias,\n} from \"./portless\"\n\nexport const APP_PORT = 5173\nconst APP_HTTPS_PORT = 5371\n\nconst MONGODB_PORT = 27017\nconst BEE_PORT = 1633\nconst BEE_P2P_PORT = 1634\nconst BLOCKCHAIN_PORT = 9545\nconst NETWORK_ID = 4020\n/**\n * Pre-funded Clique signer / etherbase from fdp-play's genesis. Unlocked by geth\n * at startup (see `startBlockchain` in services/bee.ts), so we can sign transactions\n * via `eth_sendTransaction` without managing a private key.\n */\nexport const BLOCKCHAIN_OWNER_ADDRESS = \"0xCEeE442a149784faa65C35e328CCd64d874F9a02\"\n\n/**\n * Default postage stamp price (PLUR per chunk per block). On fdp-play nobody runs\n * the price-updater bot, so the on-chain `lastPrice` stays at 0 and stamps never\n * expire. The plugin syncs this value into `PriceOracle` after Bee starts so\n * stamps actually burn down. Override via `bee: { env: { POSTAGE_PRICE: \"...\" } }`.\n */\nconst DEFAULT_POSTAGE_PRICE = \"24000\"\n\n/**\n * Private key of fdp-play's contract deployer, holder of `DEFAULT_ADMIN_ROLE`\n * on the `PostageStamp` contract (set by the constructor's\n * `_setupRole(DEFAULT_ADMIN_ROLE, msg.sender)`). The plugin uses it to grant\n * itself `PRICE_ORACLE_ROLE` and call `PostageStamp.setPrice` directly,\n * bypassing fdp-play's `PostagePriceOracle` (which is mis-wired to the BZZ\n * token because `deploy.ts` passes one extra constructor arg the Solidity\n * `PriceOracle(_postageStamp)` constructor silently ignores).\n *\n * It's NOT the unlocked Clique signer / etherbase: that account mines blocks\n * but never deployed any contract, so it has no admin role anywhere.\n *\n * Same key as fdp-play's `orchestrator/hardhat.config.ts` (publicly committed,\n * never used outside local dev). Used for client-side EIP-155 signing in\n * `web3.ts` because geth 1.13+ removed `personal_importRawKey` /\n * `personal_unlockAccount` from the HTTP API.\n */\nexport const POSTAGE_STAMP_ADMIN_PRIVATE_KEY =\n \"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d\"\n\n/**\n * Bee env keys consumed only by the plugin (e.g. post-startup actions). They\n * must be stripped before forwarding to bee/blockchain containers as `-e`.\n */\nexport const BEE_PLUGIN_INTERNAL_ENV_KEYS = [\"POSTAGE_PRICE\"] as const\n\nconst SSO_HTTP_PORT = 32610\nconst SSO_HTTPS_PORT = 42610\n\nconst INDEX_HTTP_PORT = 32620\nconst INDEX_HTTPS_PORT = 42620\n\nconst CREDIT_HTTP_PORT = 32630\nconst CREDIT_HTTPS_PORT = 42630\n\nconst GATEWAY_HTTP_PORT = 32640\nconst GATEWAY_HTTPS_PORT = 42640\n\nconst BEEHIVE_HTTP_PORT = 12610\nconst SHKEEPER_HTTP_PORT = 32650\nconst ETHEREUM_SHKEEPER_PORT = 6000\n\n/**\n * Shared ShKeeper backend API key used by the shkeeper core, every coin-adapter\n * container (e.g. `ethereum-shkeeper`), and the `etherna-credit` client.\n * All of them must agree on the same value; upstream helm chart defaults it to `\"key\"`.\n */\nconst SHKEEPER_BACKEND_KEY = \"shkeeper\"\n\ntype UnionToIntersection<Union> = (\n Union extends unknown ? (distributedUnion: Union) => void : never\n) extends (mergedIntersection: infer Intersection) => void\n ? Intersection & Union\n : never\n\ntype StringEnvOverride<T extends Record<string, string | number>> = Partial<Record<keyof T, string>>\n\n/** Runtime context for building service envs (bind URLs vs public Portless URLs). */\nexport interface ServiceEnvBuildContext {\n mode: \"http\" | \"https\"\n portless: boolean\n /** Actual Vite dev server port (may differ from {@link APP_PORT}). */\n appPort: number\n /**\n * When set (e.g. `PORTLESS_URL` from the Portless CLI), used as the browser-facing dapp base URL\n * instead of `http://app.localhost:1355`. The plugin skips registering the `app` Portless alias.\n */\n portlessAppPublicUrl?: string\n}\n\nexport function buildServiceEnvs(context: ServiceEnvBuildContext) {\n const { mode, portless, appPort, portlessAppPublicUrl } = context\n\n const ssoPort = mode === \"http\" ? SSO_HTTP_PORT : SSO_HTTPS_PORT\n const indexPort = mode === \"http\" ? INDEX_HTTP_PORT : INDEX_HTTPS_PORT\n const creditPort = mode === \"http\" ? CREDIT_HTTP_PORT : CREDIT_HTTPS_PORT\n const gatewayPort = mode === \"http\" ? GATEWAY_HTTP_PORT : GATEWAY_HTTPS_PORT\n const beehivePort = BEEHIVE_HTTP_PORT\n\n const mongodbUrl = `mongodb://localhost:${MONGODB_PORT}`\n const ssoBindUrl = bindUrl(mode, ssoPort)\n const indexBindUrl = bindUrl(mode, indexPort)\n const creditBindUrl = bindUrl(mode, creditPort)\n const gatewayBindUrl = bindUrl(mode, gatewayPort)\n const beehiveBindUrl = bindUrl(mode, beehivePort)\n /** Direct Bee API URL for container-to-container calls (always `localhost`; `*.localhost` Portless hosts often do not resolve inside Docker). */\n const beeApiBindUrl = `http://localhost:${BEE_PORT}`\n\n const appPublicUrl =\n portless && portlessAppPublicUrl\n ? normalizePortlessAppPublicUrl(portlessAppPublicUrl)\n : publicHttpUrl(mode, appPort, portless, \"app\")\n // const indexPublicUrl = publicHttpUrl(mode, indexPort, portless, \"index\")\n // const creditPublicUrl = publicHttpUrl(mode, creditPort, portless, \"credit\")\n // const gatewayPublicUrl = publicHttpUrl(mode, gatewayPort, portless, \"gateway\")\n\n const baseAspEnv = {\n ASPNETCORE_ENVIRONMENT: \"Development\",\n \"Elastic:Urls:0\": \"http://localhost:9200\",\n ...(mode === \"https\"\n ? {\n ASPNETCORE_Kestrel__Certificates__Default__Path: `${CONTAINER_CERTS_DIR}/${CERTIFICATE_PFX_NAME}`,\n ASPNETCORE_Kestrel__Certificates__Default__Password: CERTIFICATE_PASSWORD,\n }\n : {}),\n }\n\n const envs = {\n app: {\n port: appPort,\n },\n shkeeper: {\n port: SHKEEPER_HTTP_PORT,\n },\n \"shkeeper-core\": {\n DEV_MODE: \"1\",\n BTC_WALLET: \"disabled\",\n LTC_WALLET: \"disabled\",\n DOGE_WALLET: \"disabled\",\n ETH_WALLET: \"enabled\",\n ETH_USERNAME: \"shkeeper\",\n ETH_PASSWORD: \"shkeeper\",\n ETHEREUM_API_SERVER_HOST: \"localhost\",\n ETHEREUM_SERVER_PORT: String(ETHEREUM_SHKEEPER_PORT),\n SHKEEPER_BACKEND_KEY: SHKEEPER_BACKEND_KEY,\n SHKEEPER_BTC_BACKEND_KEY: SHKEEPER_BACKEND_KEY,\n },\n \"ethereum-shkeeper\": {\n FULLNODE_URL: `http://localhost:${BLOCKCHAIN_PORT}`,\n FULLNODE_TIMEOUT: \"60\",\n CURRENT_ETH_NETWORK: \"custom\",\n WEB3_ENABLE_POA_MIDDLEWARE: \"1\",\n BLOCK_SCANNER_MAX_CATCHUP_BLOCKS: \"64\",\n ETH_USERNAME: \"shkeeper\",\n ETH_PASSWORD: \"shkeeper\",\n SHKEEPER_BACKEND_KEY: SHKEEPER_BACKEND_KEY,\n SHKEEPER_HOST: `localhost:${SHKEEPER_HTTP_PORT}`,\n REDIS_HOST: \"localhost\",\n SQLALCHEMY_DATABASE_URI:\n \"mariadb+pymysql://root:shkeeper@localhost:3306/ethereum-shkeeper?charset=utf8mb4\",\n LAST_BLOCK_LOCKED: \"FALSE\",\n },\n elastic: {\n \"discovery.type\": \"single-node\",\n \"xpack.security.enabled\": \"false\",\n ES_JAVA_OPTS: \"-Xms512m -Xmx512m\",\n },\n \"etherna-mongodb\": {},\n \"etherna-sso\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: ssoBindUrl,\n /** Issuer/authority for discovery; keep bind URL so services and DNS inside containers resolve it. */\n \"IdServer:SsoServer:BaseUrl\": ssoBindUrl,\n \"IdServer:SsoServer:AllowUnsafeConnection\": \"true\",\n \"IdServer:Clients:EthernaCredit:BaseUrl\": creditBindUrl,\n \"IdServer:Clients:EthernaGateway:BaseUrls:0\": gatewayBindUrl,\n \"IdServer:Clients:EthernaIndex:BaseUrl\": indexBindUrl,\n \"IdServer:Clients:EthernaDapp:BaseUrl\": appPublicUrl,\n \"DbSeed:Clients:0:RedirectUris:0\": `${appPublicUrl}/callback`,\n \"DbSeed:Clients:0:PostLogoutRedirectUris:0\": appPublicUrl,\n \"DbSeed:Clients:0:AllowedCorsOrigins:0\": appPublicUrl,\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSSODataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaSSOHangfireDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n \"ConnectionStrings:SSOServerDb\": `${mongodbUrl}/ethernaSSODev`,\n },\n \"etherna-index\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: indexBindUrl,\n \"Swarm:GatewayUrl\": gatewayBindUrl,\n /** Server-side HTTP to SSO/Gateway must use bind URLs; `*.localhost` Portless names often fail in containers. */\n \"SsoServer:BaseUrl\": ssoBindUrl,\n \"SsoServer:AllowUnsafeConnection\": \"true\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSharedDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaIndexHangfireDev`,\n \"ConnectionStrings:IndexDb\": `${mongodbUrl}/ethernaIndexDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n },\n \"etherna-credit\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: creditBindUrl,\n \"SsoServer:BaseUrl\": ssoBindUrl,\n \"SsoServer:AllowUnsafeConnection\": \"true\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSharedDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaCreditHangfireDev`,\n \"ConnectionStrings:CreditDb\": `${mongodbUrl}/ethernaCreditDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n DisableHttpsRedirection: \"true\",\n \"Payments:ShKeeper:Url\": `http://localhost:${SHKEEPER_HTTP_PORT}`,\n \"Payments:ShKeeper:ApiKey\": SHKEEPER_BACKEND_KEY,\n \"Payments:ShKeeper:CustomCallbackBaseUrl\": creditBindUrl,\n },\n \"etherna-gateway\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: gatewayBindUrl,\n \"ForwardedHeaders:KnownNetworks:0\": \"0.0.0.0/0\",\n \"SsoServer:BaseUrl\": ssoBindUrl,\n \"SsoServer:Clients:Credit:BaseUrl\": creditBindUrl,\n \"SsoServer:Clients:Credit:Secret\": \"ethernaGatewayCreditClientSecret\",\n \"SsoServer:Clients:Webapp:Secret\": \"ethernaGatewayWebappClientSecret\",\n \"SsoServer:AllowUnsafeConnection\": \"true\",\n \"Bee:CachedUrl\": beehiveBindUrl,\n \"Bee:DirectUrl\": beehiveBindUrl,\n \"Features:GarbageCollectPins\": \"false\",\n ForwardedAllowedHosts: \"*\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSharedDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaGatewayHangfireDev`,\n \"ConnectionStrings:GatewayDb\": `${mongodbUrl}/ethernaGatewayDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n },\n \"etherna-beehive\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: beehiveBindUrl,\n \"SeedDb:BeeNodes:0:Hostname\": \"localhost\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/beehiveDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/beehiveHangfireDev`,\n \"ConnectionStrings:BeehiveDb\": `${mongodbUrl}/beehiveDev`,\n \"SeedDb:BeeNodes:0:ConnectionString\": beeApiBindUrl,\n \"SeedDb:BeeNodes:0:EnableBatchCreation\": \"true\",\n },\n \"etherna-blockchain\": {\n BLOCKCHAIN_PORT,\n NETWORK_ID,\n },\n \"etherna-bee\": {\n POSTAGE_PRICE: DEFAULT_POSTAGE_PRICE,\n BEE_WARMUP_TIME: \"10s\",\n BEE_DEBUG_API_ENABLE: \"true\",\n BEE_VERBOSITY: \"4\",\n BEE_SWAP_ENABLE: \"true\",\n BEE_MAINNET: \"false\",\n BEE_SWAP_ENDPOINT: `http://etherna-blockchain:${BLOCKCHAIN_PORT}`,\n BEE_BLOCKCHAIN_RPC_ENDPOINT: `http://etherna-blockchain:${BLOCKCHAIN_PORT}`,\n BEE_PASSWORD: \"password\",\n BEE_SWAP_FACTORY_ADDRESS: \"0xCfEB869F69431e42cdB54A4F4f105C19C080A601\",\n BEE_POSTAGE_STAMP_ADDRESS: \"0x254dffcd3277C0b1660F6d42EFbB754edaBAbC2B\",\n BEE_PRICE_ORACLE_ADDRESS: \"0x5b1869D9A4C187F2EAa108f3062412ecf0526b24\",\n BEE_REDISTRIBUTION_ADDRESS: \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n BEE_STAKING_ADDRESS: \"0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb\",\n BEE_POSTAGE_STAMP_START_BLOCK: \"1\",\n BEE_NETWORK_ID: NETWORK_ID,\n BEE_FULL_NODE: \"true\",\n BEE_PORT,\n BEE_P2P_PORT,\n BEE_API_ADDR: `0.0.0.0:${BEE_PORT}`,\n BEE_P2P_ADDR: `0.0.0.0:${BEE_P2P_PORT}`,\n BEE_CORS_ALLOWED_ORIGINS: \"*\",\n BEE_ALLOW_PRIVATE_CIDRS: \"true\",\n BEE_BOOTNODE_MODE: \"\",\n BEE_BOOTNODE: \"\",\n },\n } satisfies Record<string, Record<string, string | number>>\n\n return envs\n}\n\nexport function defaultServiceEnvBuildContext(mode: \"http\" | \"https\"): ServiceEnvBuildContext {\n return {\n mode,\n portless: false,\n appPort: mode === \"http\" ? APP_PORT : APP_HTTPS_PORT,\n }\n}\n\n/** Parses the listen port from `ASPNETCORE_URLS` (first URL if semicolon-separated). */\nexport function parsePortFromAspNetCoreUrls(bindUrls: string): string {\n const first = bindUrls.split(\";\")[0]?.trim() ?? \"\"\n try {\n const u = new URL(first)\n if (u.port) {\n return u.port\n }\n return u.protocol === \"https:\" ? \"443\" : \"80\"\n } catch {\n return first.split(\":\")[2] ?? \"80\"\n }\n}\n\nfunction bindUrl(mode: \"http\" | \"https\", port: number): string {\n return `${mode}://localhost:${port}`\n}\n\nfunction publicHttpUrl(\n mode: \"http\" | \"https\",\n port: number,\n portless: boolean,\n alias: PortlessServiceAlias,\n): string {\n if (portless) {\n return getPortlessPublicUrl(alias)\n }\n return bindUrl(mode, port)\n}\n\nexport const getEnv = <T extends string>(name: T, context: ServiceEnvBuildContext) => {\n const envs = buildServiceEnvs(context)\n type Env = typeof envs\n type AnyEnv = UnionToIntersection<Env[keyof Env]>\n type AnyEnvKey = keyof AnyEnv\n\n return ((envs as Record<string, unknown>)[name] ?? null) as T extends keyof Env\n ? Env[T]\n : Partial<Record<AnyEnvKey, string>> | null\n}\n\n/** Returns a copy of `env` with {@link BEE_PLUGIN_INTERNAL_ENV_KEYS} removed. */\nexport function stripPluginInternalEnvKeys<T extends Record<string, unknown>>(env: T): T {\n const internal = new Set<string>(BEE_PLUGIN_INTERNAL_ENV_KEYS)\n return Object.fromEntries(Object.entries(env).filter(([key]) => !internal.has(key))) as T\n}\n\nexport type BuiltServiceEnvs = ReturnType<typeof buildServiceEnvs>\n\nexport type ElasticEnv = StringEnvOverride<BuiltServiceEnvs[\"elastic\"]>\nexport type MongoEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-mongodb\"]>\nexport type BeeEnv = StringEnvOverride<\n BuiltServiceEnvs[\"etherna-blockchain\"] & BuiltServiceEnvs[\"etherna-bee\"]\n>\nexport type SsoEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-sso\"]>\nexport type IndexEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-index\"]>\nexport type GatewayEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-gateway\"]>\nexport type CreditEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-credit\"]>\nexport type BeehiveEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-beehive\"]>\nexport type ShkeeperEnv = StringEnvOverride<BuiltServiceEnvs[\"shkeeper-core\"]>\nexport type ShkeeperEthereumEnv = StringEnvOverride<BuiltServiceEnvs[\"ethereum-shkeeper\"]>\n\n/** Union of env overrides accepted by ASP.NET Etherna containers (SSO, Index, Gateway, Credit, Beehive). */\nexport type AspServiceEnv = SsoEnv | IndexEnv | GatewayEnv | CreditEnv | BeehiveEnv\n","import type { EthernaServiceName, ServiceConfig, StartOptions } from \"./types\"\n\nexport const ETHERNA_DETACHED_ENV = \"ETHERNA_DETACHED\"\n\n/**\n * Resolves detached mode: explicit `options.detached` wins, then `ETHERNA_DETACHED` env, then `false`.\n * Env is truthy for `1`, `true`, `yes` (case-insensitive); falsy for `0`, `false`, `no`, or unset.\n * Ported from `src/plugin-define.ts`.\n */\nexport function resolveDetachedMode(options: Pick<StartOptions, \"detached\">): boolean {\n if (typeof options.detached === \"boolean\") {\n return options.detached\n }\n const raw = process.env[ETHERNA_DETACHED_ENV]?.trim().toLowerCase()\n return raw === \"1\" || raw === \"true\" || raw === \"yes\"\n}\n\n/** `StartOptions` keys that toggle a logical service on/off (excludes `blockchain`, which has no independent toggle). */\ntype ConfigurableServiceName = Extract<EthernaServiceName, keyof StartOptions>\n\nconst CONFIGURABLE_SERVICE_NAMES: readonly ConfigurableServiceName[] = [\n \"elastic\",\n \"mongo\",\n \"bee\",\n \"sso\",\n \"index\",\n \"gateway\",\n \"credit\",\n \"beehive\",\n \"shkeeper\",\n]\n\n/**\n * Mirrors `harnessEthernaPlugin`'s `isServiceEnabled` from `src/plugin-define.ts`: a service is\n * enabled unless explicitly set to `false` (as a boolean or via `{ enabled: false }`).\n */\nfunction isServiceOptionEnabled(value: boolean | ServiceConfig<unknown> | undefined): boolean {\n if (typeof value === \"object\" && value !== null) {\n return value.enabled !== false\n }\n return value !== false\n}\n\n/**\n * Mirrors `harnessEthernaPlugin`'s `isShkeeperEnabled` from `src/plugin-define.ts`: shkeeper is\n * opt-in — enabled only when set to `true` or a config object (unless `{ enabled: false }`).\n */\nfunction isShkeeperOptionEnabled(value: boolean | ServiceConfig<unknown> | undefined): boolean {\n if (value === true) {\n return true\n }\n return typeof value === \"object\" && value !== null ? value.enabled !== false : false\n}\n\nexport interface StartPlan {\n /**\n * Per-service enabled flags, one per {@link EthernaServiceName}. Reflects only the caller's\n * options and their defaults — dependency expansion (e.g. enabling `gateway` implying `mongo`\n * and `sso`) is `resolveEnabledFromServices`'s responsibility and is applied by the startup\n * orchestrator, not here.\n */\n enabled: Record<EthernaServiceName, boolean>\n detached: boolean\n portless: boolean\n appPort?: number\n mode: \"http\" | \"https\"\n installSignalHandlers: boolean\n}\n\n/** Resolves a `StartOptions` object into a plan describing which services to run and how. */\nexport function resolveStartPlan(options: StartOptions): StartPlan {\n const enabled = {} as Record<EthernaServiceName, boolean>\n for (const service of CONFIGURABLE_SERVICE_NAMES) {\n enabled[service] =\n service === \"shkeeper\"\n ? isShkeeperOptionEnabled(options[service])\n : isServiceOptionEnabled(options[service])\n }\n // `blockchain` has no independent StartOptions toggle; it always mirrors `bee`.\n enabled.blockchain = enabled.bee\n\n const plan: StartPlan = {\n enabled,\n detached: resolveDetachedMode(options),\n portless: options.portless ?? false,\n mode: options.mode ?? \"http\",\n installSignalHandlers: options.installSignalHandlers ?? true,\n }\n if (options.appPort !== undefined) {\n plan.appPort = options.appPort\n }\n return plan\n}\n","import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport chalk from \"chalk\"\n\nimport { DEFAULT_CACHE_DIR } from \"./consts\"\n\nimport type { SpawnOptionsWithoutStdio } from \"node:child_process\"\n\n/** ShKeeper core container name (see `startShkeeperCoreContainer` in services/shkeeper.ts). */\nconst SHKEEPER_CORE_CONTAINER_NAME = \"shkeeper\"\n\n/** SQLite DB path inside the ShKeeper core container. */\nconst SHKEEPER_INSTANCE_SQLITE_PATH = \"/shkeeper.io/instance/shkeeper.sqlite\"\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\nexport interface FetchFirstShkeeperWalletApiKeyOptions {\n /** Docker container running ShKeeper core (default: `shkeeper`). */\n containerName?: string\n /** Path to `shkeeper.sqlite` inside that container. */\n sqlitePath?: string\n /** Max polling attempts when the DB or row is not ready yet (default: 120). */\n maxAttempts?: number\n /** Delay between attempts in ms (default: 1000). */\n intervalMs?: number\n}\n\n/**\n * Reads the first non-empty `apikey` from ShKeeper's instance SQLite (`wallet` table).\n * Uses `docker exec` + `sqlite3` in the running core container — no extra npm deps.\n * Polls until a row exists or attempts are exhausted (ShKeeper may populate the DB after startup).\n */\nexport async function fetchFirstShkeeperWalletApiKey(\n options?: FetchFirstShkeeperWalletApiKeyOptions,\n): Promise<string | null> {\n const containerName = options?.containerName ?? SHKEEPER_CORE_CONTAINER_NAME\n const sqlitePath = options?.sqlitePath ?? SHKEEPER_INSTANCE_SQLITE_PATH\n const maxAttempts = options?.maxAttempts ?? 120\n const intervalMs = options?.intervalMs ?? 1000\n\n const sql =\n \"SELECT apikey FROM wallet WHERE apikey IS NOT NULL AND TRIM(COALESCE(apikey, '')) != '' LIMIT 1\"\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const value = await runDockerSqliteScalar(containerName, sqlitePath, sql)\n if (value) {\n return value\n }\n if (attempt < maxAttempts - 1) {\n await sleep(intervalMs)\n }\n }\n\n return null\n}\n\nfunction runDockerSqliteScalar(\n containerName: string,\n sqlitePath: string,\n sql: string,\n): Promise<string | null> {\n return new Promise((resolve) => {\n const proc = spawn(\"docker\", [\"exec\", containerName, \"sqlite3\", sqlitePath, sql])\n\n let stdout = \"\"\n proc.stdout?.on(\"data\", (chunk: Buffer | string) => {\n stdout += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\")\n })\n proc.on(\"error\", () => {\n resolve(null)\n })\n proc.on(\"close\", (code: number | null) => {\n if (code !== 0) {\n resolve(null)\n return\n }\n const trimmed = stdout.trim()\n resolve(trimmed.length > 0 ? trimmed : null)\n })\n })\n}\n\n/**\n * Reads an env variable from both `process.env` and `import.meta.env`.\n *\n * `process.env` takes precedence (shell-set vars and CI environments win over\n * Vite's `.env` files). The `etherna` plugin's `config` hook already merges\n * `.env` values into `process.env` via Vite's `loadEnv`, so the\n * `import.meta.env` branch is mainly a safety net for callers that import\n * helpers from this package outside of the plugin's lifecycle.\n */\nexport function getEnvVar(key: string): string | undefined {\n const fromProcess = typeof process !== \"undefined\" ? process.env?.[key] : undefined\n if (fromProcess !== undefined) {\n return fromProcess\n }\n\n try {\n const meta = (import.meta as ImportMeta & { env?: Record<string, unknown> }).env\n const value = meta?.[key]\n return typeof value === \"string\" ? value : undefined\n } catch {\n return undefined\n }\n}\n\nexport function resolvePath(...paths: string[]) {\n return path.resolve(DEFAULT_CACHE_DIR, ...paths)\n}\n\nexport function resolvePathEscape(...paths: string[]) {\n const resolved = resolvePath(...paths)\n if (process.platform === \"win32\") {\n return resolved.replace(/\\\\/g, \"/\")\n }\n return resolved\n}\n\nexport function logSuccess(\n containerName: string,\n protocol: string,\n port: string,\n options?: { portlessUrl?: string },\n) {\n if (options?.portlessUrl) {\n const friendly = `${options.portlessUrl.replace(/\\/$/, \"\")}/`\n const raw = `${protocol}://localhost:${port}/`\n console.log(\n ` ${chalk.green(\"➜\")} ${chalk.bold(containerName)}: ${chalk.cyan(friendly)} ${chalk.gray(`(${raw})`)}`,\n )\n return\n }\n const url = `${protocol}://localhost:${chalk.bold.cyanBright(port)}/`\n console.log(` ${chalk.green(\"➜\")} ${chalk.bold(containerName)}: ${chalk.cyan(url)}`)\n}\n\nexport function logLoading(containerName: string) {\n console.log(\n ` ${chalk.gray(\"➜\")} ${chalk.bold(containerName)}: ${chalk.yellow(\"Downloading image...\")}`,\n )\n}\n\nexport function logError(containerName: string, reason: string) {\n console.log(` ${chalk.red(\"x\")} ${chalk.bold(containerName)}: ${chalk.red(reason)}`)\n}\n\nexport async function runCommand(cmd: string, args?: string[], options?: SpawnOptionsWithoutStdio) {\n const proc = spawn(cmd, args, options)\n\n return new Promise<void>((res, rej) => {\n proc.on(\"error\", (err) => {\n rej(err)\n })\n proc.on(\"exit\", () => {\n res()\n })\n })\n}\n\nexport async function getBeeUnderlayAddress(url: string) {\n const resp = await fetch(`${url}/addresses`)\n if (!resp.ok) {\n throw new Error(`Failed to fetch addresses from ${url}: ${resp.statusText}`)\n }\n const data = (await resp.json()) as {\n underlay: string[] | undefined\n }\n const underlay = Array.isArray(data.underlay) ? data.underlay : []\n\n if (underlay.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, 500))\n return getBeeUnderlayAddress(url)\n }\n\n const address = underlay.find((url) => !url.includes(\"127.0.0.1\"))\n\n if (!address) {\n throw new Error(`No valid underlay address found in response from ${url}`)\n }\n return address\n}\n","import { spawn } from \"node:child_process\"\nimport fs from \"node:fs\"\nimport chalk from \"chalk\"\n\nimport { logError, logLoading } from \"../utils\"\n\nimport type { ChildProcess } from \"node:child_process\"\n\nconst ETHERNA_CONTAINER_PREFIX = \"etherna-\"\n\n/** Prefixes `name` with `etherna-` unless it already carries the prefix. */\nexport function resolveEthernaContainerName(name: string): string {\n return name.startsWith(ETHERNA_CONTAINER_PREFIX) ? name : `${ETHERNA_CONTAINER_PREFIX}${name}`\n}\n\nconst DOCKER_GET_STARTED_URL = \"https://docs.docker.com/get-docker/\"\nconst DOCKER_DAEMON_WAIT_MS = 30_000\nconst DOCKER_DAEMON_POLL_MS = 2_000\n\nfunction spawnDetached(command: string, args: string[]) {\n const proc = spawn(command, args, { detached: true, stdio: \"ignore\" })\n proc.unref()\n}\n\n/** Resolves when `docker info` succeeds (daemon reachable). */\nfunction isDockerDaemonRunning(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"docker\", [\"info\"], { stdio: \"ignore\" })\n proc.on(\"error\", () => resolve(false))\n proc.on(\"exit\", (code) => resolve(code === 0))\n })\n}\n\n/** True when the Docker CLI is on PATH and runs. */\nfunction isDockerCliInstalled(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"docker\", [\"--version\"], { stdio: \"ignore\" })\n proc.on(\"error\", () => resolve(false))\n proc.on(\"exit\", (code) => resolve(code === 0))\n })\n}\n\nfunction tryStartDockerDaemon() {\n const { platform } = process\n\n if (platform === \"darwin\") {\n spawnDetached(\"open\", [\"-a\", \"Docker\"])\n return\n }\n\n if (platform === \"win32\") {\n const exe = \"C:\\\\Program Files\\\\Docker\\\\Docker\\\\Docker Desktop.exe\"\n if (fs.existsSync(exe)) {\n spawnDetached(exe, [])\n return\n }\n spawnDetached(\"cmd\", [\"/c\", \"start\", \"\", \"Docker Desktop\"])\n return\n }\n\n if (platform === \"linux\") {\n spawnDetached(\"systemctl\", [\"--user\", \"start\", \"docker-desktop\"])\n }\n}\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Verifies Docker CLI is installed, starts the daemon when possible, and waits until it responds.\n * Exits the process on unrecoverable errors.\n */\nexport async function ensureDockerReady() {\n const cliOk = await isDockerCliInstalled()\n if (!cliOk) {\n console.error(\n ` ${chalk.red(\"x\")} ${chalk.bold(\"docker\")}: ${chalk.red(\"Docker is not installed or not on your PATH.\")}`,\n )\n console.error(\n ` Install Docker and try again: ${chalk.cyan.underline(DOCKER_GET_STARTED_URL)}`,\n )\n process.exit(1)\n }\n\n if (await isDockerDaemonRunning()) {\n return\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(\"docker\")}: ${chalk.yellow(\"Docker daemon is not running. Starting it…\")}`,\n )\n tryStartDockerDaemon()\n\n const deadline = Date.now() + DOCKER_DAEMON_WAIT_MS\n while (Date.now() < deadline) {\n await sleep(DOCKER_DAEMON_POLL_MS)\n if (await isDockerDaemonRunning()) {\n console.log(\n ` ${chalk.green(\"➜\")} ${chalk.bold(\"docker\")}: ${chalk.green(\"Docker is ready.\")}`,\n )\n return\n }\n }\n\n console.error(\n ` ${chalk.red(\"x\")} ${chalk.bold(\"docker\")}: ${chalk.red(\n `Docker did not become ready within ${DOCKER_DAEMON_WAIT_MS / 1000}s. Start Docker manually and run the dev server again.`,\n )}`,\n )\n console.error(` Install or troubleshoot: ${chalk.cyan.underline(DOCKER_GET_STARTED_URL)}`)\n process.exit(1)\n}\n\nexport async function startDockerContainer({\n containerName,\n imageName,\n args = [],\n cmd = [],\n detached = false,\n}: {\n containerName: string\n imageName: string\n args?: string[]\n cmd?: string[]\n /** When true, skip start if the container is already running; remove a non-running name conflict before `docker run`. */\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const dockerContainerName = resolveEthernaContainerName(containerName)\n\n if (!detached) {\n if (await isContainerNameInUse(dockerContainerName)) {\n await stopContainer(dockerContainerName)\n }\n } else {\n if (await isContainerRunning(dockerContainerName)) {\n return null\n }\n if (await isContainerNameInUse(dockerContainerName)) {\n await removeContainerForce(dockerContainerName)\n }\n }\n\n // When the plugin runs in detached mode, put `docker run` in its own session so terminal Ctrl+C\n // (SIGINT to the foreground process group) does not stop the CLI and tear down `--rm` containers.\n const runArgs = [\n \"run\",\n \"--rm\",\n \"--name\",\n dockerContainerName,\n ...args,\n imageName,\n ...cmd,\n ] as const\n const proc = (\n detached\n ? spawn(\"docker\", [...runArgs], {\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n })\n : spawn(\"docker\", [...runArgs])\n ) as ChildProcess\n proc.stdout?.on(\"data\", (data) => {\n const text = String(data)\n\n if (/Pulling from/gm.test(text)) {\n logLoading(dockerContainerName)\n }\n if (/Error response from daemon/gm.test(text)) {\n logError(dockerContainerName, text)\n }\n })\n if (detached) {\n proc.unref()\n }\n\n return proc\n}\n\nasync function isContainerNameInUse(name: string) {\n const proc = spawn(\"docker\", [\n \"ps\",\n \"-a\",\n \"--filter\",\n `name=${resolveEthernaContainerName(name)}`,\n ])\n const result = await new Promise<string>((res) => {\n let data = \"\"\n proc.stdout?.on(\"data\", (d) => {\n data += String(d)\n })\n proc.on(\"close\", () => {\n res(data)\n })\n })\n const lines = result.split(\"\\n\")\n const isInUse = lines.length > 1\n return isInUse\n}\n\n/** Stops the named container (`docker stop`), prefixing the name with `etherna-` when needed. */\nexport async function stopContainer(name: string) {\n const proc = spawn(\"docker\", [\"stop\", resolveEthernaContainerName(name)])\n await new Promise<void>((res) => {\n proc.on(\"close\", () => {\n res()\n })\n })\n}\n\n/** True when a container with this exact name exists and is running. */\nexport async function isContainerRunning(name: string): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\n \"docker\",\n [\"inspect\", \"-f\", \"{{.State.Running}}\", resolveEthernaContainerName(name)],\n {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n },\n )\n let out = \"\"\n proc.stdout?.on(\"data\", (d) => {\n out += String(d)\n })\n proc.on(\"error\", () => resolve(false))\n proc.on(\"close\", (code) => {\n if (code !== 0) {\n resolve(false)\n return\n }\n resolve(out.trim().toLowerCase() === \"true\")\n })\n })\n}\n\nasync function removeContainerForce(name: string) {\n await new Promise<void>((res) => {\n const proc = spawn(\"docker\", [\"rm\", \"-f\", resolveEthernaContainerName(name)], {\n stdio: \"ignore\",\n })\n proc.on(\"error\", () => res())\n proc.on(\"close\", () => res())\n })\n}\n\nexport async function createContainerVolume(volumeName: string) {\n const proc = spawn(\"docker\", [\"volume\", \"create\", volumeName])\n\n await new Promise<void>((res) => {\n proc.on(\"close\", () => {\n res()\n })\n })\n}\n\nexport async function createNetwork(networkName: string) {\n const proc = spawn(\"docker\", [\"network\", \"create\", networkName])\n\n await new Promise<void>((res) => {\n proc.on(\"close\", () => {\n res()\n })\n })\n}\n","import { stopContainer } from \"./docker\"\n\nimport type { EnabledServiceMap } from \"../session\"\nimport type { EthernaServiceName } from \"../types\"\n\n/**\n * Docker container names that make up each logical service's group. Multi-container services\n * stop as a whole group (see design doc \"Multi-container services\"): `bee` includes the\n * blockchain container (matches today's `stopEnabledEthernaContainers` when `bee: true`), while\n * `blockchain` alone stops only the blockchain container.\n */\nconst CONTAINER_GROUPS: Record<EthernaServiceName, string[]> = {\n blockchain: [\"etherna-blockchain\"],\n bee: [\"etherna-blockchain\", \"etherna-bee\", \"etherna-bee_worker_1\"],\n beehive: [\"etherna-beehive\"],\n credit: [\"etherna-credit\"],\n elastic: [\"etherna-elastic\"],\n gateway: [\"etherna-gateway\"],\n index: [\"etherna-index\"],\n mongo: [\"etherna-mongodb\"],\n shkeeper: [\n \"ethereum-shkeeper-mariadb\",\n \"ethereum-shkeeper-redis\",\n \"ethereum-shkeeper\",\n \"ethereum-tasks\",\n \"shkeeper\",\n ],\n sso: [\"etherna-sso\"],\n}\n\n/** Returns the Docker container names belonging to a logical service's group. */\nexport function containerNamesFor(service: EthernaServiceName): string[] {\n return CONTAINER_GROUPS[service]\n}\n\n/** Stops the container groups for each named logical service (de-duplicated across overlapping groups). */\nexport async function stopLogicalServices(names: EthernaServiceName[]): Promise<void> {\n const containerNames = [...new Set(names.flatMap(containerNamesFor))]\n await Promise.all(containerNames.map((name) => stopContainer(name)))\n}\n\n/**\n * Stops the container groups for every service flagged `true` in `enabled`. Replaces the old\n * `stopEnabledEthernaContainers` (used after a startup failure with `onFailure: \"stop\"`).\n */\nexport async function stopEnabled(enabled: EnabledServiceMap): Promise<void> {\n const names = (Object.keys(enabled) as EthernaServiceName[]).filter((name) => enabled[name])\n await stopLogicalServices(names)\n}\n","import chalk from \"chalk\"\n\nimport { runCommand } from \"./utils\"\n\n/**\n * Runs `update-ca-certificates` inside a running container so it trusts the\n * dev certificate we bind-mounted into it. Used by HTTPS ASP.NET services.\n */\nexport async function trustContainerCertificate(containerName: string) {\n await runCommand(\"docker\", [\"exec\", containerName, \"update-ca-certificates\"]).catch(\n (err: unknown) => {\n console.error(\n chalk.red(\n `‼️ Error trusting certificate in container '${containerName}': ${(err as Error).message}`,\n ),\n )\n },\n )\n}\n","import { CERTIFICATE_DIR, CONTAINER_CERTS_DIR } from \"../consts\"\nimport { getEnv } from \"../env\"\nimport { getPortlessPublicUrl, PORTLESS_CONTAINER_ALIASES } from \"../portless\"\nimport { startDockerContainer } from \"../runtime/docker\"\nimport { trustContainerCertificate } from \"../ssl-trust\"\nimport { logError, logSuccess, resolvePathEscape } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { AspServiceEnv } from \"../env\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/**\n * Starts an ASP.NET Etherna service container (sso/index/gateway/credit/beehive). Resolves once the\n * app logs \"Now listening on …\" (unless reused while detached). `envs` are the caller's per-service\n * overrides (the manager passes `ctx.getServiceEnv(<key>)`).\n */\nexport async function startAspContainer(\n ctx: ServiceStartContext,\n name: string,\n image: string,\n envs?: AspServiceEnv,\n): Promise<ChildProcess | null> {\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n let lastLog: string | undefined = undefined\n\n const { mode } = ctx.serviceCtx\n const env = {\n ...(getEnv(name as \"etherna-sso\", ctx.serviceCtx) ?? {}),\n ...envs,\n }\n const port = env.ASPNETCORE_URLS.split(\";\")[0]?.split(\":\")[2] ?? \"80\"\n\n const alias = PORTLESS_CONTAINER_ALIASES[name]\n const portlessUrl = ctx.serviceCtx.portless && alias ? getPortlessPublicUrl(alias) : undefined\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: image,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n ...(mode === \"https\"\n ? [\n \"--mount\",\n `type=bind,source=${resolvePathEscape(CERTIFICATE_DIR)},target=${CONTAINER_CERTS_DIR}/`,\n ]\n : []),\n \"--network\",\n \"host\",\n ],\n detached: ctx.detached,\n })\n\n if (!proc) {\n logSuccess(name, mode, port, { portlessUrl })\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = async (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n\n if (/Now listening on: https?:\\/\\/(localhost|\\[::\\]):\\d+/gm.test(text)) {\n if (mode === \"https\") {\n await trustContainerCertificate(name)\n }\n logSuccess(name, mode, port, { portlessUrl })\n endPromise?.()\n }\n\n const excludedErrorRegexes = [\n /Current db does not support change stream/gm,\n /is only supported on replica sets./gm,\n /Failed to process the job/gm,\n ]\n // Etherna ASP.NET apps use Serilog; default format: [HH:mm:ss INF] message\n // Require explicit error level - logs can arrive in chunks, so a chunk with\n // Exception but no level may be the continuation of a [WRN] log\n const errorLogLevelRegexes = [\n /\\[(ERR|FTL)\\]/gm, // Serilog {Level:u3}\n /\"LogLevel\"\\s*:\\s*\"(Error|Critical)\"/gm, // Microsoft JSON\n /\\b(fail|crit):/gm, // Microsoft Simple\n /<(2|3)>/gm, // Microsoft Systemd: <2>=Critical, <3>=Error\n ]\n const hasErrorLevel = errorLogLevelRegexes.some((regex) => regex.test(text))\n const hasNonErrorLevel = /\\[(INF|WRN|DBG|VRB)\\]/gm.test(text)\n if (\n hasErrorLevel &&\n !hasNonErrorLevel &&\n /Exception:.+/gm.test(text) &&\n !excludedErrorRegexes.some((regex) => regex.test(text))\n ) {\n logError(name, text)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","/**\n * Minimal Ethereum JSON-RPC + tx-signing helpers used by the plugin to talk to\n * the dev-chain geth container without pulling in a full web3/ethers/viem\n * dependency.\n *\n * All RPC helpers are stateless and take an `rpcUrl`. They throw on transport\n * or RPC-level errors so callers can decide how to surface them.\n *\n * The signing helpers implement just enough RLP + EIP-155 to sign and broadcast\n * a single legacy transaction. We sign client-side because geth 1.13+ removed\n * `personal_importRawKey` / `personal_unlockAccount` from the HTTP API, so we\n * cannot rely on geth-managed signing for any account other than the Clique\n * signer that geth itself keeps unlocked.\n *\n * The implementation intentionally does NOT support EIP-1559 / 2930 envelopes;\n * the Clique dev chain accepts legacy txs and that keeps the code small.\n */\n\nimport { secp256k1 } from \"@noble/curves/secp256k1.js\"\nimport { keccak_256 } from \"@noble/hashes/sha3.js\"\n\nconst DEFAULT_TX_RECEIPT_POLL_MS = 500\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/** Performs a JSON-RPC POST and unwraps `result`/`error` for the caller. */\nexport async function ethJsonRpc<T = unknown>(\n rpcUrl: string,\n method: string,\n params: unknown[],\n): Promise<T> {\n const resp = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ jsonrpc: \"2.0\", id: 1, method, params }),\n })\n if (!resp.ok) {\n throw new Error(`RPC ${method} failed: ${resp.status} ${resp.statusText}`)\n }\n const data = (await resp.json()) as {\n error?: { message?: string }\n result?: T\n }\n if (data.error?.message) {\n throw new Error(`RPC ${method} error: ${data.error.message}`)\n }\n return data.result as T\n}\n\n/** Resolves the 4-byte function selector for `signature` via geth's `web3_sha3`. */\nexport async function getFunctionSelector(rpcUrl: string, signature: string): Promise<string> {\n const hex = \"0x\" + Buffer.from(signature, \"utf-8\").toString(\"hex\")\n const digest = await ethJsonRpc<string>(rpcUrl, \"web3_sha3\", [hex])\n return digest.slice(0, 10)\n}\n\n/** ABI-encodes a single uint up to 256 bits as a 32-byte big-endian word (no `0x` prefix). */\nexport function encodeUintParam(value: bigint): string {\n if (value < 0n) {\n throw new Error(`Cannot encode negative uint param: ${value}`)\n }\n return value.toString(16).padStart(64, \"0\")\n}\n\n/** ABI-encodes a 20-byte address as a 32-byte left-padded big-endian word (no `0x` prefix). */\nexport function encodeAddressParam(address: string): string {\n const trimmed = address.toLowerCase().startsWith(\"0x\") ? address.slice(2) : address\n if (trimmed.length !== 40) {\n throw new Error(`Invalid address (expected 20 bytes / 40 hex chars): ${address}`)\n }\n return trimmed.toLowerCase().padStart(64, \"0\")\n}\n\n/** ABI-encodes a 32-byte hash as-is (no `0x` prefix). */\nexport function encodeBytes32Param(hash: string): string {\n const trimmed = hash.startsWith(\"0x\") ? hash.slice(2) : hash\n if (trimmed.length !== 64) {\n throw new Error(`Invalid bytes32 (expected 32 bytes / 64 hex chars): ${hash}`)\n }\n return trimmed.toLowerCase()\n}\n\n/** Decodes a hex-encoded uint (with or without `0x` prefix) into a `bigint`. */\nexport function decodeUint(hex: string): bigint {\n const trimmed = hex.startsWith(\"0x\") ? hex.slice(2) : hex\n if (trimmed.length === 0) {\n return 0n\n }\n return BigInt(\"0x\" + trimmed)\n}\n\n/** Polls `eth_getTransactionReceipt` until `txHash` is mined or `timeoutMs` elapses. */\nexport async function waitForTxReceipt(\n rpcUrl: string,\n txHash: string,\n timeoutMs: number,\n pollMs: number = DEFAULT_TX_RECEIPT_POLL_MS,\n): Promise<{ status: string; blockNumber?: string }> {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const receipt = await ethJsonRpc<{ status?: string; blockNumber?: string } | null>(\n rpcUrl,\n \"eth_getTransactionReceipt\",\n [txHash],\n )\n if (receipt?.status) {\n return { status: receipt.status, blockNumber: receipt.blockNumber }\n }\n await sleep(pollMs)\n }\n throw new Error(`Transaction ${txHash} was not mined within ${timeoutMs}ms`)\n}\n\n/** Returns the deployed bytecode at `address` as a hex string (`\"0x\"` if undeployed). */\nexport async function getEthereumCode(rpcUrl: string, address: string): Promise<string> {\n return await ethJsonRpc<string>(rpcUrl, \"eth_getCode\", [address, \"latest\"]).then(\n (result) => result ?? \"0x\",\n )\n}\n\n/** Returns the current chain head height as a number. */\nexport async function getEthereumBlockNumber(rpcUrl: string): Promise<number> {\n const result = await ethJsonRpc<string>(rpcUrl, \"eth_blockNumber\", [])\n return Number.parseInt(result ?? \"0x0\", 16)\n}\n\n/** True when `code` is non-empty bytecode (i.e. a contract is deployed at the address). */\nexport function isEthereumCodeDeployed(code: string): boolean {\n return code !== \"0x\" && code.length > 2\n}\n\n/** Returns the pending transaction count (next nonce) for `address`. */\nexport async function getEthereumTransactionCount(\n rpcUrl: string,\n address: string,\n block: \"latest\" | \"pending\" = \"pending\",\n): Promise<bigint> {\n const result = await ethJsonRpc<string>(rpcUrl, \"eth_getTransactionCount\", [address, block])\n return decodeUint(result)\n}\n\n/** Returns the suggested gas price reported by the node. */\nexport async function getEthereumGasPrice(rpcUrl: string): Promise<bigint> {\n const result = await ethJsonRpc<string>(rpcUrl, \"eth_gasPrice\", [])\n return decodeUint(result)\n}\n\n// ----------------------------------------------------------------------------\n// Hex / bytes utilities\n// ----------------------------------------------------------------------------\n\nfunction hexToBytes(hex: string): Uint8Array {\n const trimmed = hex.startsWith(\"0x\") ? hex.slice(2) : hex\n const padded = trimmed.length % 2 === 0 ? trimmed : \"0\" + trimmed\n return Uint8Array.from(Buffer.from(padded, \"hex\"))\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString(\"hex\")\n}\n\n/** Converts a non-negative bigint to its minimal big-endian byte representation (0n -> empty). */\nfunction bigintToMinimalBytes(value: bigint): Uint8Array {\n if (value < 0n) {\n throw new Error(`Cannot encode negative bigint: ${value}`)\n }\n if (value === 0n) {\n return new Uint8Array(0)\n }\n let hex = value.toString(16)\n if (hex.length % 2 !== 0) {\n hex = \"0\" + hex\n }\n return hexToBytes(hex)\n}\n\n// ----------------------------------------------------------------------------\n// Minimal RLP encoder\n// ----------------------------------------------------------------------------\n\ntype RlpInput = Uint8Array | RlpInput[]\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((sum, part) => sum + part.length, 0)\n const out = new Uint8Array(total)\n let offset = 0\n for (const part of parts) {\n out.set(part, offset)\n offset += part.length\n }\n return out\n}\n\nfunction rlpEncodeLength(length: number, offset: number): Uint8Array {\n if (length < 56) {\n return Uint8Array.of(offset + length)\n }\n const lenBytes = bigintToMinimalBytes(BigInt(length))\n return concat(Uint8Array.of(offset + 55 + lenBytes.length), lenBytes)\n}\n\nfunction rlpEncode(input: RlpInput): Uint8Array {\n if (input instanceof Uint8Array) {\n if (input.length === 1 && input[0]! < 0x80) {\n return input\n }\n return concat(rlpEncodeLength(input.length, 0x80), input)\n }\n const encoded = input.map(rlpEncode)\n const payload = concat(...encoded)\n return concat(rlpEncodeLength(payload.length, 0xc0), payload)\n}\n\n// ----------------------------------------------------------------------------\n// Keccak256 / address derivation / EIP-155 signing\n// ----------------------------------------------------------------------------\n\n/** Keccak-256 (NOT SHA3-256) hash of `data`. */\nexport function keccak256(data: Uint8Array): Uint8Array {\n return keccak_256(data)\n}\n\n/** Derives the 20-byte Ethereum address from a hex private key (with or without `0x`). */\nexport function privateKeyToAddress(privateKey: string): string {\n const pkBytes = hexToBytes(privateKey)\n if (pkBytes.length !== 32) {\n throw new Error(`Invalid private key length: expected 32 bytes, got ${pkBytes.length}`)\n }\n const pubUncompressed = secp256k1.getPublicKey(pkBytes, false)\n // Strip the leading 0x04 (uncompressed-format tag) before hashing.\n const hash = keccak_256(pubUncompressed.slice(1))\n return \"0x\" + bytesToHex(hash.slice(-20))\n}\n\nexport interface LegacyTx {\n /** EIP-155 chain id. */\n chainId: bigint\n nonce: bigint\n gasPrice: bigint\n gasLimit: bigint\n /** 20-byte hex (`0x…`). */\n to: string\n value: bigint\n /** Hex calldata (`0x…`), may be `\"0x\"` for plain transfers. */\n data: string\n}\n\n/**\n * Signs `tx` as an EIP-155 legacy transaction with `privateKey` and returns the\n * raw RLP payload ready for `eth_sendRawTransaction` plus its tx hash.\n *\n * IMPORTANT: we pass `prehash: false` because the input we feed to ECDSA is\n * already keccak256'd (per yellow paper / EIP-155). Without it, noble's\n * default `prehash: true` would re-hash with sha256 and yield a non-Ethereum\n * signature.\n */\nexport function signLegacyTransaction(\n tx: LegacyTx,\n privateKey: string,\n): { rawTx: string; hash: string } {\n if (!tx.to.startsWith(\"0x\") || tx.to.length !== 42) {\n throw new Error(`Invalid 'to' address: ${tx.to}`)\n }\n\n const fields: Uint8Array[] = [\n bigintToMinimalBytes(tx.nonce),\n bigintToMinimalBytes(tx.gasPrice),\n bigintToMinimalBytes(tx.gasLimit),\n hexToBytes(tx.to),\n bigintToMinimalBytes(tx.value),\n hexToBytes(tx.data),\n ]\n\n const sigHashRlp = rlpEncode([\n ...fields,\n bigintToMinimalBytes(tx.chainId),\n new Uint8Array(0),\n new Uint8Array(0),\n ])\n const sigHash = keccak_256(sigHashRlp)\n\n const pkBytes = hexToBytes(privateKey)\n const sigBytes = secp256k1.sign(sigHash, pkBytes, {\n format: \"recovered\",\n lowS: true,\n prehash: false,\n })\n // `format: \"recovered\"` returns 65 bytes: recoveryId (1) ‖ r (32) ‖ s (32).\n const recoveryId = sigBytes[0]!\n const r = decodeUint(bytesToHex(sigBytes.subarray(1, 33)))\n const s = decodeUint(bytesToHex(sigBytes.subarray(33, 65)))\n const v = BigInt(recoveryId) + 35n + tx.chainId * 2n\n\n const signedRlp = rlpEncode([\n ...fields,\n bigintToMinimalBytes(v),\n bigintToMinimalBytes(r),\n bigintToMinimalBytes(s),\n ])\n\n return {\n rawTx: \"0x\" + bytesToHex(signedRlp),\n hash: \"0x\" + bytesToHex(keccak_256(signedRlp)),\n }\n}\n\n/**\n * Builds, signs (EIP-155 legacy), broadcasts and waits for a single tx from\n * `privateKey`. Fetches `chainId`, pending nonce and `gasPrice` from the node;\n * bumps a `0` gas-price to `1` wei because geth's gas-price oracle returns 0\n * on a freshly-booted dev chain.\n *\n * Throws if the receipt status is not `0x1` (use `onRevert` to customize the\n * error message).\n */\nexport async function sendSignedTransaction(\n rpcUrl: string,\n privateKey: string,\n call: { to: string; data: string; gasLimit: bigint; value?: bigint },\n options: {\n timeoutMs: number\n pollMs?: number\n onRevert?: (txHash: string) => string\n },\n): Promise<string> {\n const from = privateKeyToAddress(privateKey)\n const [chainIdHex, nonce, gasPrice] = await Promise.all([\n ethJsonRpc<string>(rpcUrl, \"eth_chainId\", []),\n getEthereumTransactionCount(rpcUrl, from, \"pending\"),\n getEthereumGasPrice(rpcUrl),\n ])\n const chainId = decodeUint(chainIdHex)\n const { rawTx, hash } = signLegacyTransaction(\n {\n chainId,\n nonce,\n gasPrice: gasPrice === 0n ? 1n : gasPrice,\n gasLimit: call.gasLimit,\n to: call.to,\n value: call.value ?? 0n,\n data: call.data,\n },\n privateKey,\n )\n await ethJsonRpc<string>(rpcUrl, \"eth_sendRawTransaction\", [rawTx])\n const receipt = await waitForTxReceipt(rpcUrl, hash, options.timeoutMs, options.pollMs)\n if (receipt.status !== \"0x1\") {\n throw new Error(options.onRevert?.(hash) ?? `Transaction ${hash} reverted (status ${receipt.status}).`)\n }\n return hash\n}\n","import fs from \"node:fs\"\nimport chalk from \"chalk\"\n\nimport {\n BLOCKCHAIN_OWNER_ADDRESS,\n getEnv,\n POSTAGE_STAMP_ADMIN_PRIVATE_KEY,\n stripPluginInternalEnvKeys,\n} from \"../env\"\nimport { getPortlessPublicUrl } from \"../portless\"\nimport {\n createContainerVolume,\n createNetwork,\n isContainerRunning,\n startDockerContainer,\n stopContainer,\n} from \"../runtime/docker\"\nimport {\n getBeeUnderlayAddress,\n logError,\n logSuccess,\n resolvePath,\n resolvePathEscape,\n} from \"../utils\"\nimport {\n decodeUint,\n encodeAddressParam,\n encodeBytes32Param,\n encodeUintParam,\n ethJsonRpc,\n getEthereumBlockNumber,\n getEthereumCode,\n getFunctionSelector,\n isEthereumCodeDeployed,\n privateKeyToAddress,\n sendSignedTransaction,\n} from \"../web3\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ChildProcess } from \"node:child_process\"\n\nconst BEE_NETWORK_NAME = \"etherna_bee_network\"\n\nconst BEE_CONTRACT_DEPLOY_WAIT_MS = 30_000\nconst BEE_CONTRACT_DEPLOY_POLL_MS = 1_000\nconst BEE_CORRUPTED_CHAIN_BLOCK_THRESHOLD = 10\nconst BEE_CORRUPTED_CHAIN_PROGRESS_BLOCKS = 2\n\nconst BEE_REQUIRED_CONTRACT_ENV_KEYS = [\n \"BEE_SWAP_FACTORY_ADDRESS\",\n \"BEE_POSTAGE_STAMP_ADDRESS\",\n \"BEE_PRICE_ORACLE_ADDRESS\",\n \"BEE_REDISTRIBUTION_ADDRESS\",\n \"BEE_STAKING_ADDRESS\",\n] as const\n\nconst POSTAGE_PRICE_SYNC_TIMEOUT_MS = 30_000\nconst POSTAGE_PRICE_SYNC_POLL_MS = 500\nconst POSTAGE_PRICE_SYNC_GAS_LIMIT = 200_000\n\nlet blockchainBootstrapInProgress = false\nlet resolveBlockchainBootstrapSettle = undefined as undefined | (() => void)\nlet blockchainBootstrapSettlePromise = Promise.resolve()\n\nfunction beginBlockchainBootstrap() {\n blockchainBootstrapInProgress = true\n blockchainBootstrapSettlePromise = new Promise<void>((resolve) => {\n resolveBlockchainBootstrapSettle = resolve\n })\n}\n\nfunction settleBlockchainBootstrap() {\n if (!blockchainBootstrapInProgress) {\n return\n }\n\n blockchainBootstrapInProgress = false\n resolveBlockchainBootstrapSettle?.()\n resolveBlockchainBootstrapSettle = undefined\n}\n\nexport function isBlockchainBootstrapInProgress() {\n return blockchainBootstrapInProgress\n}\n\nexport function waitForBlockchainBootstrapToSettle() {\n return blockchainBootstrapSettlePromise\n}\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Reads `PostageStamp.lastPrice()` (the value Bee uses for stamp accounting)\n * and, if it differs from `desiredPrice`, writes the new price by calling\n * `PostageStamp.setPrice(uint256)` directly from the deployer key — bypassing\n * the broken `PostagePriceOracle` shipped by fdp-play.\n *\n * Why we bypass `PostagePriceOracle`:\n * fdp-play's `deploy.ts` calls `getPostagePriceOracleBin(erc20Address, adminAddress)`\n * which appends BOTH addresses to the constructor calldata, but the actual\n * `PriceOracle` constructor only takes one arg (`address _postageStamp`).\n * Solidity silently ignores the trailing word, so the deployed oracle's\n * `postageStamp` field ends up pointing at the BZZ token contract, not the\n * real `PostageStamp`. Every `oracle.setPrice(...)` then internally calls\n * `bzzToken.setPrice(...)`, which doesn't exist — depending on the exact\n * deployed bytecode the outer tx either reverts or quietly succeeds while\n * `PostageStamp.lastPrice` stays at 0. Either way, no role grant on the\n * oracle can fix it.\n *\n * Direct `PostageStamp.setPrice(uint256)` call requires `PRICE_ORACLE_ROLE`.\n * We grant it to the deployer first (deployer holds `DEFAULT_ADMIN_ROLE` on\n * `PostageStamp`, set by its constructor's `_setupRole(DEFAULT_ADMIN_ROLE,\n * msg.sender)`). The role hash is read from the contract itself\n * (`PRICE_ORACLE_ROLE()` getter) so we transparently support both v0.5.x\n * (`keccak256(\"PRICE_ORACLE\")`) and v0.6.x (`keccak256(\"PRICE_ORACLE_ROLE\")`)\n * bytecodes.\n *\n * `ownerPrivateKey` MUST be the key that originally deployed `PostageStamp`\n * (matching fdp-play's `hardhat.config.ts`). The unlocked Clique signer never\n * deployed any contract and therefore lacks `DEFAULT_ADMIN_ROLE` everywhere.\n * We can't go through geth's `personal_*` API either (removed from the HTTP\n * namespace in geth ≥ 1.12), so txs are signed locally with EIP-155 and\n * broadcast via `eth_sendRawTransaction`.\n */\nasync function ensurePostagePrice({\n rpcUrl,\n postageStampAddress,\n ownerPrivateKey,\n desiredPrice,\n}: {\n rpcUrl: string\n postageStampAddress: string\n ownerPrivateKey: string\n desiredPrice: bigint\n}): Promise<void> {\n const name = \"etherna-bee\"\n // PostageStamp stores `lastPrice` as uint64.\n const maxPrice = (1n << 64n) - 1n\n if (desiredPrice < 0n || desiredPrice > maxPrice) {\n throw new Error(`POSTAGE_PRICE ${desiredPrice} is out of range for uint64 (0..${maxPrice}).`)\n }\n\n const [\n lastPriceSelector,\n setPriceSelector,\n hasRoleSelector,\n grantRoleSelector,\n priceOracleRoleSelector,\n ] = await Promise.all([\n getFunctionSelector(rpcUrl, \"lastPrice()\"),\n getFunctionSelector(rpcUrl, \"setPrice(uint256)\"),\n getFunctionSelector(rpcUrl, \"hasRole(bytes32,address)\"),\n getFunctionSelector(rpcUrl, \"grantRole(bytes32,address)\"),\n getFunctionSelector(rpcUrl, \"PRICE_ORACLE_ROLE()\"),\n ])\n\n const readLastPrice = async () => {\n const raw = await ethJsonRpc<string>(rpcUrl, \"eth_call\", [\n { to: postageStampAddress, data: lastPriceSelector },\n \"latest\",\n ])\n return decodeUint(raw)\n }\n\n const currentPrice = await readLastPrice()\n\n if (currentPrice === desiredPrice) {\n return\n }\n\n const ownerAddress = privateKeyToAddress(ownerPrivateKey)\n\n const roleHashRaw = await ethJsonRpc<string>(rpcUrl, \"eth_call\", [\n { to: postageStampAddress, data: priceOracleRoleSelector },\n \"latest\",\n ])\n if (!roleHashRaw || roleHashRaw === \"0x\") {\n throw new Error(\n `PostageStamp.PRICE_ORACLE_ROLE() returned no data; ${postageStampAddress} may not be a PostageStamp contract.`,\n )\n }\n const roleHashEncoded = encodeBytes32Param(roleHashRaw)\n const ownerAddressEncoded = encodeAddressParam(ownerAddress)\n\n const hasRoleRaw = await ethJsonRpc<string>(rpcUrl, \"eth_call\", [\n {\n to: postageStampAddress,\n data: hasRoleSelector + roleHashEncoded + ownerAddressEncoded,\n },\n \"latest\",\n ])\n const ownerHasRole = decodeUint(hasRoleRaw) !== 0n\n\n if (!ownerHasRole) {\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(\n name,\n )}: granting PRICE_ORACLE_ROLE on PostageStamp to ${chalk.gray(ownerAddress)}`,\n )\n const grantTxHash = await sendSignedTransaction(\n rpcUrl,\n ownerPrivateKey,\n {\n to: postageStampAddress,\n data: grantRoleSelector + roleHashEncoded + ownerAddressEncoded,\n gasLimit: BigInt(POSTAGE_PRICE_SYNC_GAS_LIMIT),\n },\n {\n timeoutMs: POSTAGE_PRICE_SYNC_TIMEOUT_MS,\n pollMs: POSTAGE_PRICE_SYNC_POLL_MS,\n onRevert: (hash) =>\n `PostageStamp.grantRole(PRICE_ORACLE_ROLE, ${ownerAddress}) reverted (tx ${hash}). The owner likely lacks DEFAULT_ADMIN_ROLE on PostageStamp ${postageStampAddress}.`,\n },\n )\n console.log(` ${chalk.gray(` granted (tx ${grantTxHash})`)}`)\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(name)}: updating postage price ${chalk.gray(\n String(currentPrice),\n )} → ${chalk.cyan(String(desiredPrice))} PLUR`,\n )\n\n const txHash = await sendSignedTransaction(\n rpcUrl,\n ownerPrivateKey,\n {\n to: postageStampAddress,\n data: setPriceSelector + encodeUintParam(desiredPrice),\n gasLimit: BigInt(POSTAGE_PRICE_SYNC_GAS_LIMIT),\n },\n {\n timeoutMs: POSTAGE_PRICE_SYNC_TIMEOUT_MS,\n pollMs: POSTAGE_PRICE_SYNC_POLL_MS,\n onRevert: (hash) =>\n `PostageStamp.setPrice(${desiredPrice}) reverted (tx ${hash}). The owner ${ownerAddress} may lack PRICE_ORACLE_ROLE on PostageStamp ${postageStampAddress}.`,\n },\n )\n\n const newPrice = await readLastPrice()\n if (newPrice !== desiredPrice) {\n throw new Error(\n `PostageStamp.setPrice(${desiredPrice}) succeeded (tx ${txHash}) but PostageStamp.lastPrice is ${newPrice}.`,\n )\n }\n\n console.log(\n ` ${chalk.green(\"➜\")} ${chalk.bold(name)}: postage price set to ${chalk.cyan(\n String(desiredPrice),\n )} PLUR ${chalk.gray(`(tx ${txHash})`)}`,\n )\n}\n\nfunction createCorruptedBlockchainError(volumeName: string) {\n return new Error(\n [\n \"Detected a stale or corrupted local blockchain state: Bee contracts are still missing even though the chain has already advanced.\",\n \"Fix it by stopping the dev server, removing the persisted blockchain volume, and starting again:\",\n `1. Stop the dev server`,\n `2. Run: docker volume rm ${volumeName}`,\n `3. Run: pnpm dev`,\n ].join(\"\\n\"),\n )\n}\n\nasync function waitForBeeContracts(rpcUrl: string, addresses: string[], volumeName: string) {\n const deadline = Date.now() + BEE_CONTRACT_DEPLOY_WAIT_MS\n let firstObservedBlock: number | null = null\n\n while (Date.now() < deadline) {\n const [blockNumber, codes] = await Promise.all([\n getEthereumBlockNumber(rpcUrl).catch(() => null),\n Promise.all(addresses.map((address) => getEthereumCode(rpcUrl, address).catch(() => null))),\n ])\n\n if (blockNumber != null && codes.every((code) => code != null)) {\n if (firstObservedBlock === null) {\n firstObservedBlock = blockNumber\n }\n\n if (codes.every((code) => isEthereumCodeDeployed(code))) {\n return\n }\n\n const blockchainLooksCorrupted =\n blockNumber >= BEE_CORRUPTED_CHAIN_BLOCK_THRESHOLD ||\n blockNumber - firstObservedBlock >= BEE_CORRUPTED_CHAIN_PROGRESS_BLOCKS\n\n if (blockchainLooksCorrupted) {\n throw createCorruptedBlockchainError(volumeName)\n }\n }\n\n await sleep(BEE_CONTRACT_DEPLOY_POLL_MS)\n }\n\n throw new Error(\n `Bee contracts were not deployed before the startup timeout elapsed. If this keeps happening, stop the dev server, run \\`docker volume rm ${volumeName}\\`, and start again.`,\n )\n}\n\nexport async function startBlockchain(ctx: ServiceStartContext): Promise<ChildProcess | null> {\n const context = ctx.serviceCtx\n const envs = ctx.getServiceEnv(\"bee\")\n const name = \"etherna-blockchain\"\n const volumeName = \"etherna_blockchain-volume\"\n const detached = ctx.detached\n\n const envEarly = stripPluginInternalEnvKeys({\n ...(getEnv(name, context) ?? {}),\n ...envs,\n })\n const blockchainPortEarly = Number(envEarly.BLOCKCHAIN_PORT)\n\n if (detached && (await isContainerRunning(name))) {\n logSuccess(name, \"http\", String(blockchainPortEarly))\n return null\n }\n\n beginBlockchainBootstrap()\n await createNetwork(BEE_NETWORK_NAME)\n await createContainerVolume(volumeName)\n\n let lastLog: string | undefined = undefined\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n let readinessCheckStarted = false\n let startupSettled = false\n\n if (!fs.existsSync(resolvePath(\".ethereum\"))) {\n fs.mkdirSync(resolvePath(\".ethereum\"), { recursive: true, mode: 0o777 })\n }\n if (!fs.existsSync(resolvePath(\".ethereum\", \"password\"))) {\n fs.writeFileSync(resolvePath(\".ethereum\", \"password\"), \"toTheSun\", {\n encoding: \"utf-8\",\n mode: 0o644,\n })\n }\n\n const env = stripPluginInternalEnvKeys({\n ...(getEnv(name, context) ?? {}),\n ...envs,\n })\n const beeEnv = {\n ...(getEnv(\"etherna-bee\", context) ?? {}),\n ...envs,\n }\n\n const blockchainPort = Number(env.BLOCKCHAIN_PORT)\n const beeContractAddresses = BEE_REQUIRED_CONTRACT_ENV_KEYS.map((key) => String(beeEnv[key]))\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"fairdatasociety/fdp-play-blockchain:latest\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--network\",\n BEE_NETWORK_NAME,\n \"-p\",\n `${blockchainPort}:${blockchainPort}`,\n \"-p\",\n `${blockchainPort + 1}:${blockchainPort + 1}`,\n \"--mount\",\n `type=volume,source=${volumeName},target=/root/.ethereum`,\n \"--mount\",\n `type=bind,source=${resolvePathEscape(\".ethereum\")},target=/root/extra`,\n ],\n detached,\n cmd: [\n \"--allow-insecure-unlock\",\n `--unlock=${BLOCKCHAIN_OWNER_ADDRESS}`,\n \"--password=/root/extra/password\",\n \"--mine\",\n `--miner.etherbase=${BLOCKCHAIN_OWNER_ADDRESS}`,\n \"--http\",\n '--http.api=\"debug,web3,eth,txpool,net,personal\"',\n \"--http.corsdomain=*\",\n `--http.port=${blockchainPort}`,\n \"--http.addr=0.0.0.0\",\n \"--http.vhosts=*\",\n \"--ws\",\n '--ws.api=\"debug,web3,eth,txpool,net,personal\"',\n `--ws.port=${blockchainPort + 1}`,\n \"--ws.origins=*\",\n \"--maxpeers=0\",\n `--networkid=${env.NETWORK_ID}`,\n \"--authrpc.vhosts=*\",\n \"--authrpc.addr=0.0.0.0\",\n ],\n })\n\n if (!proc) {\n settleBlockchainBootstrap()\n logSuccess(name, \"http\", String(blockchainPort))\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (!readinessCheckStarted && /HTTP server started/gm.test(text)) {\n readinessCheckStarted = true\n void waitForBeeContracts(\n `http://127.0.0.1:${blockchainPort}`,\n beeContractAddresses,\n volumeName,\n )\n .then(() => {\n startupSettled = true\n settleBlockchainBootstrap()\n endPromise?.()\n })\n .catch((error: unknown) => {\n startupSettled = true\n settleBlockchainBootstrap()\n const message = error instanceof Error ? error.message : String(error)\n logError(name, message)\n void stopContainer(name).finally(() => {\n rejectPromise?.(error)\n })\n })\n }\n\n if (/Error:.+/gm.test(text)) {\n logError(name, text)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n settleBlockchainBootstrap()\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n settleBlockchainBootstrap()\n if (!startupSettled) {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startBeeNodes(ctx: ServiceStartContext): Promise<(ChildProcess | null)[]> {\n const context = ctx.serviceCtx\n const envs = ctx.getServiceEnv(\"bee\")\n const name = \"etherna-bee\"\n\n const queenProc = await startBeeNode(ctx, name)\n\n const bootnode = await getBeeUnderlayAddress(\n `http://localhost:${getEnv(\"etherna-bee\", context)?.BEE_PORT ?? \"1633\"}`,\n )\n\n const [worker1Proc] = await Promise.all([\n startBeeNode(ctx, name, 1, bootnode),\n // startBeeNode(ctx, name, 2, bootnode),\n // startBeeNode(ctx, name, 3, bootnode),\n // startBeeNode(ctx, name, 4, bootnode),\n ])\n\n try {\n const beeEnv = { ...(getEnv(\"etherna-bee\", context) ?? {}), ...envs }\n const blockchainEnv = {\n ...(getEnv(\"etherna-blockchain\", context) ?? {}),\n ...envs,\n }\n await ensurePostagePrice({\n rpcUrl: `http://127.0.0.1:${blockchainEnv.BLOCKCHAIN_PORT}`,\n postageStampAddress: String(beeEnv.BEE_POSTAGE_STAMP_ADDRESS),\n ownerPrivateKey: POSTAGE_STAMP_ADMIN_PRIVATE_KEY,\n desiredPrice: BigInt(String(beeEnv.POSTAGE_PRICE ?? \"24000\")),\n })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n logError(name, `Failed to sync postage price: ${message}`)\n }\n\n return [queenProc, worker1Proc]\n}\n\nasync function startBeeNode(\n ctx: ServiceStartContext,\n name: string,\n worker?: 1 | 2 | 3 | 4,\n bootnode?: string,\n): Promise<ChildProcess | null> {\n const context = ctx.serviceCtx\n const envs = ctx.getServiceEnv(\"bee\")\n const volumeName = worker ? `etherna_bee_worker_${worker}-volume` : \"etherna_bee-volume\"\n await createContainerVolume(volumeName)\n\n let lastLog: string | undefined = undefined\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const { mode } = context\n const env = stripPluginInternalEnvKeys({\n ...(getEnv(name, context) ?? {}),\n ...envs,\n })\n\n if (!worker) {\n delete env.BEE_BOOTNODE\n env.BEE_BOOTNODE_MODE = \"false\"\n } else {\n delete env.BEE_BOOTNODE_MODE\n env.BEE_BOOTNODE = bootnode\n }\n\n if (worker) {\n name = `${name}_worker_${worker}`\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: worker\n ? `fairdatasociety/fdp-play-worker-${worker}`\n : \"fairdatasociety/fdp-play-queen:latest\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${volumeName},target=/home/bee/.bee`,\n \"--network\",\n BEE_NETWORK_NAME,\n \"-p\",\n `${worker ? parseInt(env.BEE_PORT ?? \"1633\") + worker * 10000 : env.BEE_PORT}:${env.BEE_PORT}`,\n \"-p\",\n `${worker ? parseInt(env.BEE_P2P_PORT ?? \"1634\") + worker * 10000 : env.BEE_P2P_PORT}:${env.BEE_P2P_PORT}`,\n ],\n cmd: [\"start\"],\n detached: ctx.detached,\n })\n\n if (!proc) {\n if (!worker) {\n const portlessUrl = context.portless ? getPortlessPublicUrl(\"bee\") : undefined\n logSuccess(name, mode, String(env.BEE_PORT ?? \"1633\"), { portlessUrl })\n }\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/\"address\"=\"\\[::\\]:\\d+\"/gm.test(text)) {\n if (!worker) {\n const portlessUrl = context.portless ? getPortlessPublicUrl(\"bee\") : undefined\n logSuccess(name, mode, String(env.BEE_PORT ?? \"1633\"), { portlessUrl })\n }\n endPromise?.()\n }\n\n const excludedErrorRegexes = [/\"logger\"=\"node\\/storageincentives\"/gm]\n // Bee uses \"level\"=\"error\" format; filter to only error/critical lines (chunks can mix levels)\n const errorLines = text.split(\"\\n\").filter((line) => /\"level\"=\"(error|critical)\"/.test(line))\n const errorText = errorLines.join(\"\\n\")\n if (errorText && !excludedErrorRegexes.some((regex) => regex.test(text))) {\n logError(name, errorText)\n endPromise?.()\n lastLog = errorText\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startInterceptor(\n ctx: ServiceStartContext,\n name: string,\n): Promise<ChildProcess | null> {\n const context = ctx.serviceCtx\n let lastLog: string | undefined = undefined\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const env = getEnv(name, context) ?? {}\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"etherna/etherna-gateway-interceptor:latest\",\n args: [...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`])],\n detached: ctx.detached,\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/starting in full mode/gm.test(text)) {\n endPromise?.()\n }\n\n if (/\"level\"=\"error\"/gm.test(text)) {\n logError(name, text)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","import type {\n BeeEnv,\n BeehiveEnv,\n CreditEnv,\n ElasticEnv,\n GatewayEnv,\n IndexEnv,\n MongoEnv,\n ServiceEnvBuildContext,\n SsoEnv,\n} from \"../env\"\nimport type { ShkeeperConfig } from \"../types\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/** Maps each configurable logical service to the env-override shape callers may pass for it. */\nexport interface ServiceEnvByKey {\n elastic: ElasticEnv\n mongo: MongoEnv\n bee: BeeEnv\n sso: SsoEnv\n index: IndexEnv\n gateway: GatewayEnv\n credit: CreditEnv\n beehive: BeehiveEnv\n}\n\nexport type ServiceKey = keyof ServiceEnvByKey\n\n/**\n * Everything a service starter needs from the run's session/config, bundled into one object so the\n * manager can wire it once and pass it to every starter. Replaces the per-function\n * `(context, envs, opts)` signatures the starters used before the package split.\n */\nexport interface ServiceStartContext {\n /** When true, reuse already-running containers and leave them running on shutdown. */\n detached: boolean\n /** Context used to build default service envs (bind URLs vs Portless URLs). */\n serviceCtx: ServiceEnvBuildContext\n /** User-supplied env overrides for a logical service (defaults are merged in by each starter). */\n getServiceEnv: <K extends ServiceKey>(k: K) => ServiceEnvByKey[K]\n /** Tracks spawned child processes so the session can kill them on shutdown (nullish entries ignored). */\n pushSpawn: (...procs: (ChildProcess | null | undefined)[]) => void\n /** True once shutdown has been requested; starters use it to bail out gracefully. */\n isShutdownRequested: () => boolean\n /** Resolved ShKeeper configuration (env, ethereum sidecar, build overrides). */\n getShkeeperConfig: () => ShkeeperConfig\n /** Resolved ShKeeper build source (custom GitHub repo/branch, if any). */\n getShkeeperBuild: () => { githubRepo?: string; githubBranch?: string }\n}\n\n/**\n * Builds a {@link ServiceStartContext} from a required `serviceCtx` plus optional overrides. Handy for\n * tests and for the manager, which supplies real `pushSpawn` / config accessors.\n */\nexport function createServiceStartContext(\n options: Partial<ServiceStartContext> & { serviceCtx: ServiceEnvBuildContext },\n): ServiceStartContext {\n return {\n detached: options.detached ?? false,\n serviceCtx: options.serviceCtx,\n getServiceEnv:\n options.getServiceEnv ?? (<K extends ServiceKey>(_k: K) => ({}) as ServiceEnvByKey[K]),\n pushSpawn: options.pushSpawn ?? (() => {}),\n isShutdownRequested: options.isShutdownRequested ?? (() => false),\n getShkeeperConfig: options.getShkeeperConfig ?? (() => ({})),\n getShkeeperBuild: options.getShkeeperBuild ?? (() => ({})),\n }\n}\n","import { getEnv } from \"../env\"\nimport { createContainerVolume, startDockerContainer } from \"../runtime/docker\"\nimport { logError, logSuccess } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/** Starts the Elasticsearch container and resolves once it reports \"started\" (unless reused while detached). */\nexport async function startElastic(ctx: ServiceStartContext): Promise<ChildProcess | null> {\n const name = \"elastic\"\n const dataVolumeName = `etherna_${name}-data-volume`\n await createContainerVolume(dataVolumeName)\n\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const env = {\n ...(getEnv(name, ctx.serviceCtx) ?? {}),\n ...ctx.getServiceEnv(\"elastic\"),\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"elasticsearch:7.17.24\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${dataVolumeName},target=/usr/share/elasticsearch/data`,\n \"--network\",\n \"host\",\n \"--memory=512m\",\n ],\n cmd: [],\n detached: ctx.detached,\n })\n\n if (!proc) {\n logSuccess(name, \"http\", \"9200\")\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n const text = String(data)\n if (/\"message\": \"started\"/gm.test(text)) {\n logSuccess(name, \"http\", \"9200\")\n endPromise?.()\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","import { getEnv } from \"../env\"\nimport { createContainerVolume, startDockerContainer } from \"../runtime/docker\"\nimport { logError, logSuccess } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/** Starts the MongoDB container and resolves once it reports startup complete (unless reused while detached). */\nexport async function startMongo(ctx: ServiceStartContext): Promise<ChildProcess | null> {\n const name = \"etherna-mongodb\"\n const dbVolumeName = `etherna_${name}-db-volume`\n const configDbVolumeName = `etherna_${name}-configdb-volume`\n await Promise.all([\n createContainerVolume(dbVolumeName),\n createContainerVolume(configDbVolumeName),\n ])\n\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const env = {\n ...(getEnv(name, ctx.serviceCtx) ?? {}),\n ...ctx.getServiceEnv(\"mongo\"),\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"mongo:latest\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${dbVolumeName},target=/data/db`,\n \"--mount\",\n `type=volume,source=${configDbVolumeName},target=/data/configdb`,\n \"--network\",\n \"host\",\n ],\n cmd: [],\n detached: ctx.detached,\n })\n\n if (!proc) {\n logSuccess(name, \"mongodb\", \"27017\")\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n const text = String(data)\n if (/mongod startup complete/gm.test(text)) {\n logSuccess(name, \"mongodb\", \"27017\")\n endPromise?.()\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","import { spawn } from \"node:child_process\"\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport chalk from \"chalk\"\n\nimport { logError, resolvePath } from \"./utils\"\n\n/** Upstream image when not building from a custom GitHub repo. */\nexport const DEFAULT_SHKEEPER_IMAGE = \"vsyshost/shkeeper:2.5.12\"\nexport const DEFAULT_ETHEREUM_SHKEEPER_IMAGE = \"vsyshost/ethereum-shkeeper:1.2.3\"\n\n/** Default source repo for SHKeeper core when `githubRepo` is not set (still tagged as {@link DEFAULT_SHKEEPER_IMAGE}). */\nexport const DEFAULT_SHKEEPER_GITHUB_REPO = \"vsys-host/shkeeper.io\"\n\n/** Branch or tag to clone when `githubRepo` points at a custom fork (default upstream clone still uses the pinned image tag). */\nexport const DEFAULT_GITHUB_BRANCH = \"main\"\n\nconst CUSTOM_IMAGE_REGISTRY_PREFIX = \"etherna\"\n\nconst GITHUB_REPO_PATTERN = /^[\\w.-]+\\/[\\w.-]+$/\n\nexport function assertValidGithubRepo(repo: string) {\n if (!GITHUB_REPO_PATTERN.test(repo)) {\n throw new Error(`Invalid githubRepo \"${repo}\". Expected \"owner/repo\".`)\n }\n}\n\nexport function parseImageRef(image: string): { repository: string; tag: string } {\n const idx = image.lastIndexOf(\":\")\n if (idx === -1 || image.slice(idx + 1).includes(\"/\")) {\n return { repository: image, tag: \"latest\" }\n }\n return { repository: image.slice(0, idx), tag: image.slice(idx + 1) }\n}\n\n/** When `githubRepo` is set, the built image is tagged under `etherna/…` with the same tag as the default upstream image. */\nexport function resolveShkeeperImageName(githubRepo?: string): string {\n const { tag } = parseImageRef(DEFAULT_SHKEEPER_IMAGE)\n if (!githubRepo) {\n return DEFAULT_SHKEEPER_IMAGE\n }\n return `${CUSTOM_IMAGE_REGISTRY_PREFIX}/shkeeper:${tag}`\n}\n\nexport function resolveEthereumShkeeperImageName(githubRepo?: string): string {\n const { tag } = parseImageRef(DEFAULT_ETHEREUM_SHKEEPER_IMAGE)\n if (!githubRepo) {\n return DEFAULT_ETHEREUM_SHKEEPER_IMAGE\n }\n return `${CUSTOM_IMAGE_REGISTRY_PREFIX}/ethereum-shkeeper:${tag}`\n}\n\nasync function isDockerImageAvailable(imageName: string) {\n const proc = spawn(\"docker\", [\"image\", \"inspect\", imageName])\n\n return await new Promise<boolean>((resolve) => {\n proc.on(\"close\", (code) => {\n resolve(code === 0)\n })\n proc.on(\"error\", () => {\n resolve(false)\n })\n })\n}\n\nasync function runCommandStrict(command: string, args: string[]) {\n const proc = spawn(command, args)\n\n await new Promise<void>((resolve, reject) => {\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new Error(`Command failed: ${command} ${args.join(\" \")}`))\n })\n proc.on(\"error\", reject)\n })\n}\n\nfunction makeTempWorkspace(prefix: string, ref: string) {\n const safeRef = ref.replace(/[^a-z0-9._-]+/gi, \"-\")\n return resolvePath(prefix, `${safeRef}-${Date.now()}`)\n}\n\nasync function acquireGitCloneBuildContext(\n githubRepo: string,\n workspacePrefix: string,\n gitRef: string,\n) {\n const workspaceRoot = makeTempWorkspace(workspacePrefix, gitRef)\n fs.mkdirSync(workspaceRoot, { recursive: true })\n const cloneRoot = path.join(workspaceRoot, \"clone\")\n await runCommandStrict(\"git\", [\n \"clone\",\n \"--depth\",\n \"1\",\n \"--branch\",\n gitRef,\n `https://github.com/${githubRepo}.git`,\n cloneRoot,\n ])\n return {\n cleanupPath: workspaceRoot,\n contextPath: cloneRoot,\n dockerfilePath: path.join(cloneRoot, \"Dockerfile\"),\n }\n}\n\n/**\n * Ensures a local image exists by shallow-cloning `sourceRepo` at `gitRef` and running `docker build`.\n */\nexport async function ensureDockerImageFromGitHub(options: {\n logLabel: string\n imageName: string\n sourceRepo: string\n workspacePrefix: string\n /** Git branch or tag to clone. */\n gitRef: string\n}) {\n const { logLabel, imageName, sourceRepo, workspacePrefix, gitRef } = options\n\n if (await isDockerImageAvailable(imageName)) {\n return\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(logLabel)}: ${chalk.yellow(\n `Building Docker image from GitHub (${sourceRepo}@${gitRef}) (first run may take a while)…`,\n )}`,\n )\n\n const buildContext = await acquireGitCloneBuildContext(sourceRepo, workspacePrefix, gitRef)\n\n const proc = spawn(\"docker\", [\n \"build\",\n \"-t\",\n imageName,\n \"-f\",\n buildContext.dockerfilePath,\n buildContext.contextPath,\n ])\n\n try {\n await new Promise<void>((resolve, reject) => {\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new Error(`Failed to build local Docker image ${imageName}`))\n })\n proc.on(\"error\", reject)\n })\n } catch (error) {\n logError(logLabel, `Failed to build Docker image (${imageName}).`)\n if (buildContext.cleanupPath) {\n throw new Error(\n `Failed to build local Docker image ${imageName}. Inspect cloned source at ${buildContext.contextPath}`,\n { cause: error },\n )\n }\n throw error\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(logLabel)}: ${chalk.yellow(\"Finished building Docker image.\")}`,\n )\n\n if (buildContext.cleanupPath) {\n fs.rmSync(buildContext.cleanupPath, { force: true, recursive: true })\n }\n}\n\nfunction resolveGitRefForCustomRepo(githubBranch?: string) {\n const trimmed = githubBranch?.trim()\n return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_GITHUB_BRANCH\n}\n\n/** Builds SHKeeper core from GitHub when the image is missing; uses default upstream repo when `githubRepo` is unset. */\nexport async function ensureShkeeperDockerImage(\n githubRepo?: string,\n githubBranch?: string,\n) {\n const imageName = resolveShkeeperImageName(githubRepo)\n const sourceRepo = githubRepo ?? DEFAULT_SHKEEPER_GITHUB_REPO\n const gitRef = githubRepo\n ? resolveGitRefForCustomRepo(githubBranch)\n : parseImageRef(DEFAULT_SHKEEPER_IMAGE).tag\n await ensureDockerImageFromGitHub({\n logLabel: \"shkeeper\",\n imageName,\n sourceRepo,\n workspacePrefix: \".shkeeper-build\",\n gitRef,\n })\n}\n\n/** When `githubRepo` is set, builds the ethereum adapter from that repo; otherwise relies on pulling the upstream image. */\nexport async function ensureEthereumShkeeperDockerImage(\n githubRepo?: string,\n githubBranch?: string,\n) {\n if (!githubRepo) {\n return\n }\n\n const imageName = resolveEthereumShkeeperImageName(githubRepo)\n const gitRef = resolveGitRefForCustomRepo(githubBranch)\n await ensureDockerImageFromGitHub({\n logLabel: \"ethereum-shkeeper\",\n imageName,\n sourceRepo: githubRepo,\n workspacePrefix: \".ethereum-shkeeper-build\",\n gitRef,\n })\n}\n","import {\n ensureEthereumShkeeperDockerImage,\n ensureShkeeperDockerImage,\n resolveEthereumShkeeperImageName,\n resolveShkeeperImageName,\n} from \"../builder\"\nimport { getEnv } from \"../env\"\nimport { createContainerVolume, startDockerContainer } from \"../runtime/docker\"\nimport { logError, logSuccess } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ServiceEnvBuildContext, ShkeeperEnv, ShkeeperEthereumEnv } from \"../env\"\nimport type { ChildProcess } from \"node:child_process\"\n\nconst SHKEEPER_NETWORK_NAME = \"etherna_shkeeper_network\"\n\nexport async function startShkeeperCoreContainer({\n context,\n envs,\n build,\n networkName,\n detached = false,\n}: {\n context: ServiceEnvBuildContext\n envs?: ShkeeperEnv\n build: {\n imageName: string\n }\n networkName: string\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const name = \"shkeeper\"\n const instanceVolumeName = \"etherna_shkeeper-instance-volume\"\n await createContainerVolume(instanceVolumeName)\n\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const env = {\n ...(getEnv(\"shkeeper-core\", context) ?? {}),\n ...envs,\n }\n const port = String(getEnv(\"shkeeper\", context)?.port ?? \"32650\")\n const useHostNetwork = networkName === \"host\"\n const listenPort = useHostNetwork ? port : \"5000\"\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: build.imageName,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${instanceVolumeName},target=/shkeeper.io/instance`,\n \"--network\",\n networkName,\n ...(useHostNetwork ? [] : [\"-p\", `${port}:5000`]),\n ],\n ...(useHostNetwork\n ? {\n cmd: [\n \"bash\",\n \"-c\",\n `gunicorn --access-logfile=- --workers=1 --threads=16 --timeout=600 --bind=0.0.0.0:${port} 'shkeeper:create_app()'`,\n ],\n }\n : {}),\n detached,\n })\n\n if (!proc) {\n logSuccess(name, \"http\", port)\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (new RegExp(`Listening at: http://.+:${listenPort}`, \"gm\").test(text)) {\n ready = true\n logSuccess(name, \"http\", port)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperEthereumApiContainer({\n context,\n envs,\n networkName,\n imageName,\n detached = false,\n}: {\n context: ServiceEnvBuildContext\n envs?: ShkeeperEthereumEnv\n networkName: string\n imageName: string\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const name = \"ethereum-shkeeper\"\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const env = {\n ...(getEnv(\"ethereum-shkeeper\", context) ?? {}),\n ...envs,\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--network\",\n networkName,\n ],\n cmd: [\n \"bash\",\n \"-c\",\n \"sleep 30 && gunicorn --access-logfile=- --workers=1 --threads=16 --timeout=600 --bind=0.0.0.0:6000 run:server\",\n ],\n detached,\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/Listening at: http:\\/\\/.+:6000/gm.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperMariaDbContainer(\n networkName = SHKEEPER_NETWORK_NAME,\n opts?: { detached?: boolean },\n): Promise<ChildProcess | null> {\n const name = \"ethereum-shkeeper-mariadb\"\n const volumeName = \"etherna_shkeeper-mariadb-volume\"\n await createContainerVolume(volumeName)\n\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"mariadb:10.9.3\",\n args: [\n \"-e\",\n \"MARIADB_ROOT_PASSWORD=shkeeper\",\n \"-e\",\n \"MARIADB_DATABASE=ethereum-shkeeper\",\n \"--mount\",\n `type=volume,source=${volumeName},target=/var/lib/mysql`,\n \"--network\",\n networkName,\n ],\n detached: Boolean(opts?.detached),\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/ready for connections/gim.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperRedisContainer(\n networkName = SHKEEPER_NETWORK_NAME,\n opts?: { detached?: boolean },\n): Promise<ChildProcess | null> {\n const name = \"ethereum-shkeeper-redis\"\n const volumeName = \"etherna_shkeeper-redis-volume\"\n await createContainerVolume(volumeName)\n\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"redis:7\",\n args: [\"--mount\", `type=volume,source=${volumeName},target=/data`, \"--network\", networkName],\n detached: Boolean(opts?.detached),\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/Ready to accept connections/gm.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperEthereumTasksContainer({\n context,\n envs,\n networkName,\n imageName,\n detached = false,\n}: {\n context: ServiceEnvBuildContext\n envs?: ShkeeperEthereumEnv\n networkName: string\n imageName: string\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const name = \"ethereum-tasks\"\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const env = {\n ...(getEnv(\"ethereum-shkeeper\", context) ?? {}),\n ...envs,\n C_FORCE_ROOT: \"1\",\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--network\",\n networkName,\n ],\n cmd: [\"bash\", \"-c\", \"sleep 30 && celery -A celery_worker.celery worker --loglevel=info -B\"],\n detached,\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/ready\\./gim.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\n/**\n * Starts the full ShKeeper stack (mariadb + redis + ethereum adapter API/tasks + shkeeper core) on\n * the host network. Reads build source and env overrides from the shared {@link ServiceStartContext}.\n */\nexport async function startShkeeperStack(\n ctx: ServiceStartContext,\n): Promise<(ChildProcess | null)[]> {\n const context = ctx.serviceCtx\n const detached = ctx.detached\n const config = ctx.getShkeeperConfig()\n const shkeeperBuild = ctx.getShkeeperBuild()\n const build = { imageName: resolveShkeeperImageName(shkeeperBuild.githubRepo) }\n const ethereumGithubRepo = config.ethereum?.githubRepo?.trim() || undefined\n const ethereumGithubBranch = config.ethereum?.githubBranch?.trim() || undefined\n\n const networkName = \"host\"\n const started: (ChildProcess | null)[] = []\n\n try {\n await ensureShkeeperDockerImage(shkeeperBuild.githubRepo, shkeeperBuild.githubBranch)\n await ensureEthereumShkeeperDockerImage(ethereumGithubRepo, ethereumGithubBranch)\n\n const ethereumImageName = resolveEthereumShkeeperImageName(ethereumGithubRepo)\n\n const [mariadb, redis] = await Promise.all([\n startShkeeperMariaDbContainer(networkName, { detached }),\n startShkeeperRedisContainer(networkName, { detached }),\n ])\n started.push(mariadb, redis)\n\n const [ethereumApi, ethereumTasks] = await Promise.all([\n startShkeeperEthereumApiContainer({\n context,\n envs: config.ethereum?.env,\n networkName,\n imageName: ethereumImageName,\n detached,\n }),\n startShkeeperEthereumTasksContainer({\n context,\n envs: config.ethereum?.env,\n networkName,\n imageName: ethereumImageName,\n detached,\n }),\n ])\n started.push(ethereumApi, ethereumTasks)\n\n const shkeeper = await startShkeeperCoreContainer({\n context,\n envs: config.env,\n build,\n networkName,\n detached,\n })\n started.push(shkeeper)\n\n ctx.pushSpawn(...started)\n\n return started\n } catch (error) {\n for (const proc of started) {\n proc?.kill()\n }\n\n throw error\n }\n}\n","import type { EthernaServiceName } from \"./types\"\n\n/** Per-service enabled flags used to decide which containers `stopContainersForEnabled` stops. */\nexport type EnabledServiceMap = Partial<Record<EthernaServiceName, boolean>>\n\n/** Minimal shape session needs from a tracked child process (avoids a `node:child_process` dependency here). */\nexport interface TrackedSpawn {\n kill: () => void\n}\n\nexport interface ShutdownOptions {\n /** Exits the process after shutdown work completes. Defaults to `false`. */\n exitProcess?: boolean\n /** Bypasses the shutdown-in-progress guard and the blockchain-settle wait (used for a forced second Ctrl+C). Defaults to `false`. */\n force?: boolean\n /** Kills tracked spawns. Defaults to `!detached` (i.e. `true` when attached, `false` when detached). */\n killTrackedSpawns?: boolean\n}\n\nexport interface CreateSessionOptions {\n /**\n * When `true`, reuse already-running containers and leave them (and the portless proxy)\n * running on shutdown. Resolve this before calling `createSession` (see `resolveDetachedMode`).\n */\n detached: boolean\n /** Per-service enabled flags, passed through to `stopContainersForEnabled` as-is. */\n enabledServices: EnabledServiceMap\n /** Stops the Docker containers for `enabledServices`. Only called when not detached. */\n stopContainersForEnabled: (enabled: EnabledServiceMap) => Promise<void>\n /** Registers a Portless alias for `name` -> `port`. Defaults to a no-op (wired to `src/portless.ts` by the caller). */\n addPortlessAlias?: (name: string, port: unknown) => Promise<void>\n /** Removes previously-registered Portless aliases. Defaults to a no-op. */\n removePortlessAliases?: (names: string[]) => Promise<void>\n /** Stops the Portless proxy this session started. Defaults to a no-op. */\n stopPortlessProxy?: () => Promise<void>\n /** True while a blockchain bootstrap is in flight; shutdown waits for it to settle first. Defaults to `() => false`. */\n isBlockchainBootstrapInProgress?: () => boolean\n /** Resolves once an in-progress blockchain bootstrap reaches a safe shutdown point. Defaults to a no-op. */\n waitForBlockchainBootstrapToSettle?: () => Promise<void>\n /** Called once, before awaiting `waitForBlockchainBootstrapToSettle`, e.g. to log a warning. Defaults to a no-op. */\n onBlockchainShutdownWait?: () => void\n /** Injectable `process.exit` stand-in, called with `0` when `shutdown({ exitProcess: true })`. Defaults to `process.exit`. */\n exitProcess?: (code: number) => void\n}\n\nexport interface EthernaSession {\n isShutdownRequested: () => boolean\n pushSpawn: (...procs: TrackedSpawn[]) => void\n killSpawns: () => void\n getDetached: () => boolean\n setPortlessProxyStartedByUs: (started: boolean) => void\n recordPortlessAlias: (name: string, port: unknown) => Promise<void>\n cleanupPortless: () => Promise<void>\n shutdown: (opts?: ShutdownOptions) => Promise<void>\n installSignalHandlers: () => void\n}\n\n/**\n * Owns a Vite/CLI run's spawn tracking, Portless bookkeeping, and shutdown/signal-handling logic.\n * Ported from `harnessEthernaPlugin` in `src/plugin-define.ts`, consolidated so `shutdown` also\n * stops enabled containers (the caller no longer needs to do that separately before shutting down).\n */\nexport function createSession(options: CreateSessionOptions): EthernaSession {\n const detached = options.detached\n const spawns: TrackedSpawn[] = []\n let portlessProxyStartedByUs = false\n const portlessAliasesRegistered: string[] = []\n let shutdownRequested = false\n let shutdownInProgress = false\n\n const isBlockchainBootstrapInProgress = options.isBlockchainBootstrapInProgress ?? (() => false)\n const waitForBlockchainBootstrapToSettle =\n options.waitForBlockchainBootstrapToSettle ?? (() => Promise.resolve())\n const onBlockchainShutdownWait = options.onBlockchainShutdownWait ?? (() => {})\n const addPortlessAlias = options.addPortlessAlias ?? (async () => {})\n const removePortlessAliases = options.removePortlessAliases ?? (async () => {})\n const stopPortlessProxy = options.stopPortlessProxy ?? (async () => {})\n const exitProcess = options.exitProcess ?? ((code: number) => process.exit(code))\n\n const getDetached = () => detached\n\n const pushSpawn = (...procs: TrackedSpawn[]) => {\n spawns.push(...procs)\n }\n\n const killSpawns = () => {\n for (const proc of spawns) {\n proc.kill()\n }\n }\n\n const setPortlessProxyStartedByUs = (started: boolean) => {\n portlessProxyStartedByUs = started\n }\n\n const recordPortlessAlias = async (name: string, port: unknown) => {\n await addPortlessAlias(name, port)\n portlessAliasesRegistered.push(name)\n }\n\n const cleanupPortless = async () => {\n if (detached) {\n return\n }\n if (portlessAliasesRegistered.length > 0) {\n await removePortlessAliases([...portlessAliasesRegistered])\n portlessAliasesRegistered.length = 0\n }\n if (portlessProxyStartedByUs) {\n await stopPortlessProxy()\n }\n portlessProxyStartedByUs = false\n }\n\n const shutdown = async (opts?: ShutdownOptions) => {\n shutdownRequested = true\n const force = opts?.force ?? false\n\n if (shutdownInProgress && !force) {\n return\n }\n shutdownInProgress = true\n\n if (!force && isBlockchainBootstrapInProgress()) {\n onBlockchainShutdownWait()\n await waitForBlockchainBootstrapToSettle()\n }\n\n if (!detached) {\n await options.stopContainersForEnabled(options.enabledServices)\n }\n\n await cleanupPortless()\n\n const killTracked = opts?.killTrackedSpawns ?? !detached\n if (killTracked) {\n killSpawns()\n }\n\n if (opts?.exitProcess) {\n exitProcess(0)\n }\n }\n\n const installSignalHandlers = () => {\n process.on(\"SIGINT\", () => {\n process.stdin.resume()\n void (async () => {\n await shutdown({ exitProcess: true, force: shutdownRequested })\n })()\n })\n process.on(\"SIGTERM\", () => {\n void (async () => {\n await shutdown({ force: shutdownRequested })\n })()\n })\n }\n\n return {\n isShutdownRequested: () => shutdownRequested,\n pushSpawn,\n killSpawns,\n getDetached,\n setPortlessProxyStartedByUs,\n recordPortlessAlias,\n cleanupPortless,\n shutdown,\n installSignalHandlers,\n }\n}\n","import chalk from \"chalk\"\n\nimport { ALL_SERVICE_NAMES, SERVICE_CATALOG, type StartupCode } from \"./catalog\"\nimport { createDependencyRunner, type DependencyRunnerServiceDefinition } from \"./dependency-runner\"\nimport {\n buildServiceEnvs,\n defaultServiceEnvBuildContext,\n getEnv,\n parsePortFromAspNetCoreUrls,\n type ServiceEnvBuildContext,\n} from \"./env\"\nimport {\n addPortlessAlias,\n ensurePortlessProxy,\n getPortlessPublicUrl,\n isPortlessCliAvailable,\n normalizePortlessAppPublicUrl,\n PORTLESS_URL_ENV,\n removePortlessAliases,\n stopPortlessProxy,\n type PortlessServiceAlias,\n} from \"./portless\"\nimport { resolveStartPlan } from \"./resolve-options\"\nimport { ensureDockerReady } from \"./runtime/docker\"\nimport { stopEnabled, stopLogicalServices } from \"./runtime/names\"\nimport { startAspContainer } from \"./services/asp\"\nimport {\n isBlockchainBootstrapInProgress,\n startBeeNodes,\n startBlockchain,\n waitForBlockchainBootstrapToSettle,\n} from \"./services/bee\"\nimport {\n createServiceStartContext,\n type ServiceEnvByKey,\n type ServiceKey,\n} from \"./services/context\"\nimport { startElastic } from \"./services/elastic\"\nimport { startMongo } from \"./services/mongo\"\nimport { startShkeeperStack } from \"./services/shkeeper\"\nimport { createSession } from \"./session\"\nimport { fetchFirstShkeeperWalletApiKey, getEnvVar, logError } from \"./utils\"\n\nimport type {\n EthernaServiceName,\n EthernaSessionHandle,\n ShkeeperConfig,\n StartOptions,\n} from \"./types\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/**\n * Stops the Docker container groups for the named logical service(s). Multi-container services stop\n * as a whole group and overlapping groups are de-duplicated (see {@link containerNamesFor}).\n * Throws a `TypeError` (listing valid names) for any unknown service name.\n */\nexport async function stop(services: EthernaServiceName | EthernaServiceName[]): Promise<void> {\n const names = Array.isArray(services) ? services : [services]\n for (const name of names) {\n if (!ALL_SERVICE_NAMES.includes(name)) {\n throw new TypeError(\n `Unknown Etherna service \"${String(name)}\". Valid services: ${ALL_SERVICE_NAMES.join(\", \")}.`,\n )\n }\n }\n await stopLogicalServices(names)\n}\n\n/** Reads per-service env overrides from a `StartOptions` service value (`boolean | { env }`). */\nfunction readServiceEnv<K extends ServiceKey>(value: StartOptions[K]): ServiceEnvByKey[K] {\n return typeof value === \"object\" && value !== null\n ? ((value.env ?? {}) as ServiceEnvByKey[K])\n : ({} as ServiceEnvByKey[K])\n}\n\n/** Resolves the ShKeeper configuration object from `StartOptions.shkeeper` (`true | { … }`). */\nfunction readShkeeperConfig(value: StartOptions[\"shkeeper\"]): ShkeeperConfig {\n if (value === true) {\n return {}\n }\n return typeof value === \"object\" && value !== null ? value : {}\n}\n\n/**\n * Starts the enabled Etherna services following the canonical dependency graph\n * ({@link SERVICE_CATALOG}), wiring a {@link createSession} for spawn tracking, Portless bookkeeping,\n * and shutdown. On a startup failure with `onFailure: \"stop\"`, stops the Docker containers for every\n * enabled service in this run — even when detached — before shutting the session down.\n *\n * Detached mode defaults to `false` unless `options.detached` or `ETHERNA_DETACHED` is set (matches\n * the Vite plugin). The CLI passes `detached: true` by default separately.\n */\nexport async function start(options: StartOptions = {}): Promise<EthernaSessionHandle> {\n const plan = resolveStartPlan(options)\n\n await ensureDockerReady()\n\n const portlessAppPublicUrl = getEnvVar(PORTLESS_URL_ENV)?.trim()\n const appPort = plan.appPort ?? defaultServiceEnvBuildContext(plan.mode).appPort\n const serviceCtx: ServiceEnvBuildContext = {\n mode: plan.mode,\n portless: plan.portless,\n appPort,\n ...(plan.portless && portlessAppPublicUrl\n ? { portlessAppPublicUrl: normalizePortlessAppPublicUrl(portlessAppPublicUrl) }\n : {}),\n }\n\n const session = createSession({\n detached: plan.detached,\n enabledServices: plan.enabled,\n stopContainersForEnabled: stopEnabled,\n addPortlessAlias: (name, port) => addPortlessAlias(name as PortlessServiceAlias, port),\n removePortlessAliases: (names) => removePortlessAliases(names as PortlessServiceAlias[]),\n stopPortlessProxy,\n isBlockchainBootstrapInProgress,\n waitForBlockchainBootstrapToSettle,\n onBlockchainShutdownWait: () => {\n console.log(\n chalk.yellow(\n ` ➜ ${chalk.bold(\"etherna-blockchain\")}: Shutdown requested during blockchain initialization. Waiting for a safe shutdown point. Press Ctrl+C again to force exit.`,\n ),\n )\n },\n })\n\n if (options.installSignalHandlers !== false) {\n session.installSignalHandlers()\n }\n\n if (plan.portless) {\n await setupPortless(session, serviceCtx, portlessAppPublicUrl)\n }\n // Built once for Portless alias port lookups (only needed when portless is on).\n const builtEnvs = plan.portless ? buildServiceEnvs(serviceCtx) : undefined\n\n const getServiceEnv = <K extends ServiceKey>(key: K): ServiceEnvByKey[K] =>\n readServiceEnv<K>(options[key])\n\n const serviceStartCtx = createServiceStartContext({\n detached: plan.detached,\n serviceCtx,\n getServiceEnv,\n pushSpawn: (...procs) => {\n session.pushSpawn(...procs.filter((p): p is ChildProcess => p != null))\n },\n isShutdownRequested: () => session.isShutdownRequested(),\n getShkeeperConfig: () => readShkeeperConfig(options.shkeeper),\n getShkeeperBuild: () => {\n const build = readShkeeperConfig(options.shkeeper).build\n return {\n githubRepo: build?.githubRepo?.trim() || undefined,\n githubBranch: build?.githubBranch?.trim() || undefined,\n }\n },\n })\n\n const runStartup = async (fn: () => Promise<unknown>): Promise<boolean> => {\n try {\n await fn()\n return !session.isShutdownRequested()\n } catch (error) {\n if (session.isShutdownRequested()) {\n return false\n }\n throw error\n }\n }\n\n const startCredit = async () => {\n let creditEnv = getServiceEnv(\"credit\")\n if (plan.enabled.shkeeper) {\n const apiKey = await fetchFirstShkeeperWalletApiKey()\n if (apiKey) {\n creditEnv = { ...creditEnv, \"Payments:ShKeeper:ApiKey\": apiKey }\n }\n }\n await startAspContainer(\n serviceStartCtx,\n \"etherna-credit\",\n \"etherna/etherna-credit:latest\",\n creditEnv,\n )\n }\n\n const startupByCode: Record<StartupCode, () => Promise<boolean>> = {\n \"bee-blockchain\": () => runStartup(() => startBlockchain(serviceStartCtx)),\n \"bee-nodes\": () => runStartup(() => startBeeNodes(serviceStartCtx)),\n shkeeper: () => runStartup(() => startShkeeperStack(serviceStartCtx)),\n mongo: () => runStartup(() => startMongo(serviceStartCtx)),\n sso: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-sso\",\n \"etherna/etherna-sso:latest\",\n getServiceEnv(\"sso\"),\n ),\n ),\n index: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-index\",\n \"etherna/etherna-index:latest\",\n getServiceEnv(\"index\"),\n ),\n ),\n beehive: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-beehive\",\n \"etherna/beehive:latest\",\n getServiceEnv(\"beehive\"),\n ),\n ),\n gateway: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-gateway\",\n \"etherna/etherna-gateway:latest\",\n getServiceEnv(\"gateway\"),\n ),\n ),\n credit: () => runStartup(startCredit),\n elastic: () => runStartup(() => startElastic(serviceStartCtx)),\n }\n\n // Portless alias registration, mirroring the Vite plugin: registered in each node's\n // `beforeStartup` so the alias exists before the container's URL is announced.\n const portlessAliasByCode: Partial<Record<StartupCode, () => Promise<void>>> = plan.portless\n ? {\n \"bee-blockchain\": async () => {\n const beeBase = getEnv(\"etherna-bee\", serviceCtx) ?? {}\n await session.recordPortlessAlias(\n \"bee\",\n { ...beeBase, ...getServiceEnv(\"bee\") }.BEE_PORT ?? 1633,\n )\n },\n shkeeper: async () => {\n await session.recordPortlessAlias(\"shkeeper\", getEnv(\"shkeeper\", serviceCtx).port)\n },\n sso: async () => {\n await session.recordPortlessAlias(\n \"sso\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-sso\"].ASPNETCORE_URLS)),\n )\n },\n index: async () => {\n await session.recordPortlessAlias(\n \"index\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-index\"].ASPNETCORE_URLS)),\n )\n },\n beehive: async () => {\n await session.recordPortlessAlias(\n \"beehive\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-beehive\"].ASPNETCORE_URLS)),\n )\n },\n gateway: async () => {\n await session.recordPortlessAlias(\n \"gateway\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-gateway\"].ASPNETCORE_URLS)),\n )\n },\n credit: async () => {\n await session.recordPortlessAlias(\n \"credit\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-credit\"].ASPNETCORE_URLS)),\n )\n },\n }\n : {}\n\n const codes = Object.keys(SERVICE_CATALOG) as StartupCode[]\n const definitions: DependencyRunnerServiceDefinition<StartupCode>[] = codes.map((code) => {\n const node = SERVICE_CATALOG[code]\n const beforeStartup = portlessAliasByCode[code]\n return {\n code,\n dependencies: node.dependencies,\n enabled: plan.enabled[node.service],\n onFailure: node.onFailure,\n startupCallback: startupByCode[code],\n ...(beforeStartup ? { beforeStartup } : {}),\n }\n })\n\n const runner = createDependencyRunner(definitions, { logError })\n const result = await runner.start()\n\n if (result.shouldStop && !session.isShutdownRequested()) {\n // Stop containers for every enabled service in this run — required even when detached, since\n // `session.shutdown` only stops containers when attached (see design doc / Task 3 note).\n await stopEnabled(plan.enabled)\n await session.shutdown({ killTrackedSpawns: true })\n }\n\n return { shutdown: (opts) => session.shutdown(opts) }\n}\n\n/** Fail-fast Portless bootstrap: verify the CLI, start the proxy, register the app alias. */\nasync function setupPortless(\n session: ReturnType<typeof createSession>,\n serviceCtx: ServiceEnvBuildContext,\n portlessAppPublicUrl: string | undefined,\n): Promise<void> {\n if (!(await isPortlessCliAvailable())) {\n console.error(\n chalk.red(\n ` portless: CLI not found. Install globally (recommended): npm install -g portless`,\n ),\n )\n process.exit(1)\n }\n\n try {\n const { startedByUs } = await ensurePortlessProxy()\n session.setPortlessProxyStartedByUs(startedByUs)\n } catch (e) {\n console.error(\n chalk.red(` portless: failed to start proxy: ${e instanceof Error ? e.message : String(e)}`),\n )\n process.exit(1)\n }\n\n if (!portlessAppPublicUrl) {\n try {\n await session.recordPortlessAlias(\"app\", serviceCtx.appPort)\n } catch (e) {\n console.error(\n chalk.red(\n ` portless: failed to register aliases: ${e instanceof Error ? e.message : String(e)}`,\n ),\n )\n await session.cleanupPortless()\n process.exit(1)\n }\n }\n\n const appUrl =\n portlessAppPublicUrl != null && portlessAppPublicUrl !== \"\"\n ? `${normalizePortlessAppPublicUrl(portlessAppPublicUrl)}/`\n : `${getPortlessPublicUrl(\"app\")}/`\n console.log(chalk.green(` ➜ ${chalk.bold(\"app (portless)\")}: ${chalk.cyan(appUrl)}`))\n}\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"gRAAA,MAEM,GAAc,EAAS,IAAM,GAAQ,UAAU,EAAO,EAAO,GAE7D,GAAe,EAAS,IAAM,GAAQ,UAAU,GAAK,EAAO,KAAK,EAAK,GAEtE,GAAe,EAAS,KAAO,EAAK,EAAO,IAAS,UAAU,GAAK,EAAO,KAAK,EAAI,GAAG,EAAM,GAAG,EAAK,GAEpGA,EAAS,CACd,SAAU,CACT,MAAO,CAAC,EAAG,CAAC,EAEZ,KAAM,CAAC,EAAG,EAAE,EACZ,IAAK,CAAC,EAAG,EAAE,EACX,OAAQ,CAAC,EAAG,EAAE,EACd,UAAW,CAAC,EAAG,EAAE,EACjB,SAAU,CAAC,GAAI,EAAE,EACjB,QAAS,CAAC,EAAG,EAAE,EACf,OAAQ,CAAC,EAAG,EAAE,EACd,cAAe,CAAC,EAAG,EAAE,CACtB,EACA,MAAO,CACN,MAAO,CAAC,GAAI,EAAE,EACd,IAAK,CAAC,GAAI,EAAE,EACZ,MAAO,CAAC,GAAI,EAAE,EACd,OAAQ,CAAC,GAAI,EAAE,EACf,KAAM,CAAC,GAAI,EAAE,EACb,QAAS,CAAC,GAAI,EAAE,EAChB,KAAM,CAAC,GAAI,EAAE,EACb,MAAO,CAAC,GAAI,EAAE,EAGd,YAAa,CAAC,GAAI,EAAE,EACpB,KAAM,CAAC,GAAI,EAAE,EACb,KAAM,CAAC,GAAI,EAAE,EACb,UAAW,CAAC,GAAI,EAAE,EAClB,YAAa,CAAC,GAAI,EAAE,EACpB,aAAc,CAAC,GAAI,EAAE,EACrB,WAAY,CAAC,GAAI,EAAE,EACnB,cAAe,CAAC,GAAI,EAAE,EACtB,WAAY,CAAC,GAAI,EAAE,EACnB,YAAa,CAAC,GAAI,EAAE,CACrB,EACA,QAAS,CACR,QAAS,CAAC,GAAI,EAAE,EAChB,MAAO,CAAC,GAAI,EAAE,EACd,QAAS,CAAC,GAAI,EAAE,EAChB,SAAU,CAAC,GAAI,EAAE,EACjB,OAAQ,CAAC,GAAI,EAAE,EACf,UAAW,CAAC,GAAI,EAAE,EAClB,OAAQ,CAAC,GAAI,EAAE,EACf,QAAS,CAAC,GAAI,EAAE,EAGhB,cAAe,CAAC,IAAK,EAAE,EACvB,OAAQ,CAAC,IAAK,EAAE,EAChB,OAAQ,CAAC,IAAK,EAAE,EAChB,YAAa,CAAC,IAAK,EAAE,EACrB,cAAe,CAAC,IAAK,EAAE,EACvB,eAAgB,CAAC,IAAK,EAAE,EACxB,aAAc,CAAC,IAAK,EAAE,EACtB,gBAAiB,CAAC,IAAK,EAAE,EACzB,aAAc,CAAC,IAAK,EAAE,EACtB,cAAe,CAAC,IAAK,EAAE,CACxB,CACD,EAE6B,OAAO,KAAKA,EAAO,QAAQ,EACxD,MAAa,EAAuB,OAAO,KAAKA,EAAO,KAAK,EAC/C,EAAuB,OAAO,KAAKA,EAAO,OAAO,EACpC,CAAC,GAAG,EAAsB,GAAG,CAAoB,EAE3E,SAAS,GAAiB,CACzB,IAAM,EAAQ,IAAI,IAElB,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQA,CAAM,EAAG,CACxD,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,CAAK,EACpD,EAAO,GAAa,CACnB,KAAM,UAAU,EAAM,GAAG,GACzB,MAAO,UAAU,EAAM,GAAG,EAC3B,EAEA,EAAM,GAAaA,EAAO,GAE1B,EAAM,IAAI,EAAM,GAAI,EAAM,EAAE,EAG7B,OAAO,eAAeA,EAAQ,EAAW,CACxC,MAAO,EACP,WAAY,EACb,CAAC,CACF,CA8HA,OA5HA,OAAO,eAAeA,EAAQ,QAAS,CACtC,MAAO,EACP,WAAY,EACb,CAAC,EAED,EAAO,MAAM,MAAQ,WACrB,EAAO,QAAQ,MAAQ,WAEvB,EAAO,MAAM,KAAO,EAAW,EAC/B,EAAO,MAAM,QAAU,EAAY,EACnC,EAAO,MAAM,QAAU,EAAY,EACnC,EAAO,QAAQ,KAAO,EAAW,EAAsB,EACvD,EAAO,QAAQ,QAAU,EAAY,EAAsB,EAC3D,EAAO,QAAQ,QAAU,EAAY,EAAsB,EAG3D,OAAO,iBAAiBA,EAAQ,CAC/B,aAAc,CACb,MAAM,EAAK,EAAO,EAAM,CAevB,OAZI,IAAQ,GAAS,IAAU,EAC1B,EAAM,EACF,GAGJ,EAAM,IACF,IAGD,KAAK,OAAQ,EAAM,GAAK,IAAO,EAAE,EAAI,IAGtC,GACH,GAAK,KAAK,MAAM,EAAM,IAAM,CAAC,EAC7B,EAAI,KAAK,MAAM,EAAQ,IAAM,CAAC,EAC/B,KAAK,MAAM,EAAO,IAAM,CAAC,CAC7B,EACA,WAAY,EACb,EACA,SAAU,CACT,MAAM,EAAK,CACV,IAAM,EAAU,yBAAyB,KAAK,EAAI,SAAS,EAAE,CAAC,EAC9D,GAAI,CAAC,EACJ,MAAO,CAAC,EAAG,EAAG,CAAC,EAGhB,GAAI,CAAC,GAAe,EAEhB,EAAY,SAAW,IAC1B,EAAc,CAAC,GAAG,CAAW,CAAC,CAAC,IAAI,GAAa,EAAY,CAAS,CAAC,CAAC,KAAK,EAAE,GAG/E,IAAM,EAAU,OAAO,SAAS,EAAa,EAAE,EAE/C,MAAO,CAEL,GAAW,GAAM,IACjB,GAAW,EAAK,IACjB,EAAU,GAEX,CACD,EACA,WAAY,EACb,EACA,aAAc,CACb,MAAO,GAAOA,EAAO,aAAa,GAAGA,EAAO,SAAS,CAAG,CAAC,EACzD,WAAY,EACb,EACA,cAAe,CACd,MAAM,EAAM,CACX,GAAI,EAAO,EACV,MAAO,IAAK,EAGb,GAAI,EAAO,GACV,MAAO,KAAM,EAAO,GAGrB,IAAI,EACA,EACA,EAEJ,GAAI,GAAQ,IACX,IAAS,EAAO,KAAO,GAAM,GAAK,IAClC,EAAQ,EACR,EAAO,MACD,CACN,GAAQ,GAER,IAAM,EAAY,EAAO,GAEzB,EAAM,KAAK,MAAM,EAAO,EAAE,EAAI,EAC9B,EAAQ,KAAK,MAAM,EAAY,CAAC,EAAI,EACpC,EAAQ,EAAY,EAAK,CAC1B,CAEA,IAAM,EAAQ,KAAK,IAAI,EAAK,EAAO,CAAI,EAAI,EAE3C,GAAI,IAAU,EACb,MAAO,IAIR,IAAI,EAAS,IAAO,KAAK,MAAM,CAAI,GAAK,EAAM,KAAK,MAAM,CAAK,GAAK,EAAK,KAAK,MAAM,CAAG,GAMtF,OAJI,IAAU,IACb,GAAU,IAGJ,CACR,EACA,WAAY,EACb,EACA,UAAW,CACV,OAAQ,EAAK,EAAO,IAASA,EAAO,cAAcA,EAAO,aAAa,EAAK,EAAO,CAAI,CAAC,EACvF,WAAY,EACb,EACA,UAAW,CACV,MAAO,GAAOA,EAAO,cAAcA,EAAO,aAAa,CAAG,CAAC,EAC3D,WAAY,EACb,CACD,CAAC,EAEMA,CACR,CAEA,MAAM,EAAa,EAAe,ECtNlC,SAAS,EAAQ,EAAM,EAAO,WAAW,KAAO,WAAW,KAAK,KAAOC,EAAQ,KAAM,CACpF,IAAM,EAAS,EAAK,WAAW,GAAG,EAAI,GAAM,EAAK,SAAW,EAAI,IAAM,KAChE,EAAW,EAAK,QAAQ,EAAS,CAAI,EACrC,EAAqB,EAAK,QAAQ,IAAI,EAC5C,OAAO,IAAa,KAAO,IAAuB,IAAM,EAAW,EACpE,CAEA,KAAM,CAAC,OAAOA,EAEd,IAAI,EAEH,EAAQ,UAAU,GACf,EAAQ,WAAW,GACnB,EAAQ,aAAa,GACrB,EAAQ,aAAa,EAExB,EAAiB,GAEjB,EAAQ,OAAO,GACZ,EAAQ,QAAQ,GAChB,EAAQ,YAAY,GACpB,EAAQ,cAAc,KAEzB,EAAiB,GAGlB,SAAS,GAAgB,CACxB,GAAI,gBAAiB,EASpB,OARI,EAAI,cAAgB,OAChB,EAGJ,EAAI,cAAgB,QAChB,EAGD,EAAI,YAAY,SAAW,EAAI,EAAI,KAAK,IAAI,OAAO,SAAS,EAAI,YAAa,EAAE,EAAG,CAAC,CAE5F,CAEA,SAAS,EAAe,EAAO,CAK9B,OAJI,IAAU,GAIP,CACN,QACA,SAAU,GACV,OAAQ,GAAS,EACjB,OAAQ,GAAS,CAClB,CACD,CAEA,SAAS,GAAe,EAAY,CAAC,cAAa,aAAa,IAAQ,CAAC,EAAG,CAC1E,IAAM,EAAmB,EAAc,EACnC,IAAqB,IAAA,KACxB,EAAiB,GAGlB,IAAM,EAAa,EAAa,EAAiB,EAEjD,GAAI,IAAe,EAClB,MAAO,GAGR,GAAI,EAAY,CACf,GAAI,EAAQ,WAAW,GACnB,EAAQ,YAAY,GACpB,EAAQ,iBAAiB,EAC5B,MAAO,GAGR,GAAI,EAAQ,WAAW,EACtB,MAAO,EAET,CAIA,GAAI,aAAc,GAAO,eAAgB,EACxC,MAAO,GAGR,GAAI,GAAc,CAAC,GAAe,IAAe,IAAA,GAChD,MAAO,GAGR,IAAM,EAAM,GAAc,EAE1B,GAAI,EAAI,OAAS,OAChB,OAAO,EAGR,GAAIA,EAAQ,WAAa,QAAS,CAGjC,IAAM,EAAY,EAAG,QAAQ,CAAC,CAAC,MAAM,GAAG,EAQxC,OANC,OAAO,EAAU,EAAE,GAAK,IACrB,OAAO,EAAU,EAAE,GAAK,MAEpB,OAAO,EAAU,EAAE,GAAK,MAAS,EAAI,EAGtC,CACR,CAEA,GAAI,OAAQ,EASX,MARI,CAAC,iBAAkB,gBAAiB,UAAU,CAAC,CAAC,KAAK,GAAO,KAAO,CAAG,EAClE,EAGJ,CAAC,SAAU,WAAY,YAAa,YAAa,OAAO,CAAC,CAAC,KAAK,GAAQ,KAAQ,CAAG,GAAK,EAAI,UAAY,WACnG,EAGD,EAGR,GAAI,qBAAsB,EACzB,MAAO,mCAAgC,KAAK,EAAI,gBAAgB,EAejE,GAZI,EAAI,YAAc,aAIlB,EAAI,OAAS,eAIb,EAAI,OAAS,iBAIb,EAAI,OAAS,UAChB,MAAO,GAGR,GAAI,iBAAkB,EAAK,CAC1B,IAAM,EAAU,OAAO,UAAU,EAAI,sBAAwB,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,GAAI,EAAE,EAElF,OAAQ,EAAI,aAAZ,CACC,IAAK,YACJ,OAAO,GAAW,EAAI,EAAI,EAG3B,IAAK,iBACJ,MAAO,EAGT,CACD,CAcA,MAZI,iBAAiB,KAAK,EAAI,IAAI,EAC1B,EAGJ,8DAA8D,KAAK,EAAI,IAAI,GAI3E,cAAe,EACX,EAGD,CACR,CAEA,SAAgB,GAAoB,EAAQ,EAAU,CAAC,EAAG,CAMzD,OAAO,EALO,GAAe,EAAQ,CACpC,YAAa,GAAU,EAAO,MAC9B,GAAG,CACJ,CAE0B,CAAC,CAC5B,CAEA,MAAM,GAAgB,CACrB,OAAQ,GAAoB,CAAC,MAAO,EAAI,OAAO,CAAC,CAAC,CAAC,EAClD,OAAQ,GAAoB,CAAC,MAAO,EAAI,OAAO,CAAC,CAAC,CAAC,CACnD,EC1LA,SAAgB,GAAiB,EAAQ,EAAW,EAAU,CAC7D,IAAI,EAAQ,EAAO,QAAQ,CAAS,EACpC,GAAI,IAAU,GACb,OAAO,EAGR,IAAM,EAAkB,EAAU,OAC9B,EAAW,EACX,EAAc,GAClB,EACC,IAAe,EAAO,MAAM,EAAU,CAAK,EAAI,EAAY,EAC3D,EAAW,EAAQ,EACnB,EAAQ,EAAO,QAAQ,EAAW,CAAQ,QAClC,IAAU,IAGnB,MADA,IAAe,EAAO,MAAM,CAAQ,EAC7B,CACR,CAEA,SAAgB,GAA+B,EAAQ,EAAQ,EAAS,EAAO,CAC9E,IAAI,EAAW,EACX,EAAc,GAClB,EAAG,CACF,IAAM,EAAQ,EAAO,EAAQ,KAAO,KACpC,GAAe,EAAO,MAAM,EAAW,EAAQ,EAAQ,EAAI,CAAM,EAAI,GAAU,EAAQ;EAAS;GAAQ,EACxG,EAAW,EAAQ,EACnB,EAAQ,EAAO,QAAQ;EAAM,CAAQ,CACtC,OAAS,IAAU,IAGnB,MADA,IAAe,EAAO,MAAM,CAAQ,EAC7B,CACR,CCzBA,KAAM,CAAC,OAAQ,GAAa,OAAQ,IAAe,GAE7C,GAAY,OAAO,WAAW,EAC9B,EAAS,OAAO,QAAQ,EACxB,EAAW,OAAO,UAAU,EAG5B,GAAe,CACpB,OACA,OACA,UACA,SACD,EAEM,EAAS,OAAO,OAAO,IAAI,EAE3B,IAAgB,EAAQ,EAAU,CAAC,IAAM,CAC9C,GAAI,EAAQ,OAAS,EAAE,OAAO,UAAU,EAAQ,KAAK,GAAK,EAAQ,OAAS,GAAK,EAAQ,OAAS,GAChG,MAAU,MAAM,qDAAqD,EAItE,IAAM,EAAa,GAAc,GAAY,MAAQ,EACrD,EAAO,MAAQ,EAAQ,QAAU,IAAA,GAAY,EAAa,EAAQ,KACnE,EASM,GAAe,GAAW,CAC/B,IAAM,GAAS,GAAG,IAAY,EAAQ,KAAK,GAAG,EAK9C,OAJA,GAAa,EAAO,CAAO,EAE3B,OAAO,eAAe,EAAO,EAAY,SAAS,EAE3C,CACR,EAEA,SAAS,EAAY,EAAS,CAC7B,OAAO,GAAa,CAAO,CAC5B,CAEA,OAAO,eAAe,EAAY,UAAW,SAAS,SAAS,EAE/D,IAAK,GAAM,CAAC,EAAW,KAAU,OAAO,QAAQ,CAAU,EACzD,EAAO,GAAa,CACnB,KAAM,CACL,IAAM,EAAU,EAAc,KAAM,GAAa,EAAM,KAAM,EAAM,MAAO,KAAK,EAAO,EAAG,KAAK,EAAS,EAEvG,OADA,OAAO,eAAe,KAAM,EAAW,CAAC,MAAO,CAAO,CAAC,EAChD,CACR,CACD,EAGD,EAAO,QAAU,CAChB,KAAM,CACL,IAAM,EAAU,EAAc,KAAM,KAAK,GAAS,EAAI,EAEtD,OADA,OAAO,eAAe,KAAM,UAAW,CAAC,MAAO,CAAO,CAAC,EAChD,CACR,CACD,EAEA,MAAM,IAAgB,EAAO,EAAO,EAAM,GAAG,IACxC,IAAU,MACT,IAAU,UACN,EAAW,EAAK,CAAC,QAAQ,GAAG,CAAU,EAG1C,IAAU,UACN,EAAW,EAAK,CAAC,QAAQ,EAAW,aAAa,GAAG,CAAU,CAAC,EAGhE,EAAW,EAAK,CAAC,KAAK,EAAW,UAAU,GAAG,CAAU,CAAC,EAG7D,IAAU,MACN,GAAa,MAAO,EAAO,EAAM,GAAG,EAAW,SAAS,GAAG,CAAU,CAAC,EAGvE,EAAW,EAAK,CAAC,EAAM,CAAC,GAAG,CAAU,EAK7C,IAAK,IAAM,IAAS,CAFA,MAAO,MAAO,SAEL,EAAG,CAC/B,EAAO,GAAS,CACf,KAAM,CACL,GAAM,CAAC,SAAS,KAChB,OAAO,SAAU,GAAG,EAAY,CAC/B,IAAM,EAAS,GAAa,GAAa,EAAO,GAAa,GAAQ,QAAS,GAAG,CAAU,EAAG,EAAW,MAAM,MAAO,KAAK,EAAO,EAClI,OAAO,EAAc,KAAM,EAAQ,KAAK,EAAS,CAClD,CACD,CACD,EAEA,IAAM,EAAU,KAAO,EAAM,EAAE,CAAC,YAAY,EAAI,EAAM,MAAM,CAAC,EAC7D,EAAO,GAAW,CACjB,KAAM,CACL,GAAM,CAAC,SAAS,KAChB,OAAO,SAAU,GAAG,EAAY,CAC/B,IAAM,EAAS,GAAa,GAAa,EAAO,GAAa,GAAQ,UAAW,GAAG,CAAU,EAAG,EAAW,QAAQ,MAAO,KAAK,EAAO,EACtI,OAAO,EAAc,KAAM,EAAQ,KAAK,EAAS,CAClD,CACD,CACD,CACD,CAEA,MAAM,GAAQ,OAAO,qBAAuB,CAAC,EAAG,CAC/C,GAAG,EACH,MAAO,CACN,WAAY,GACZ,KAAM,CACL,OAAO,KAAK,GAAU,CAAC,KACxB,EACA,IAAI,EAAO,CACV,KAAK,GAAU,CAAC,MAAQ,CACzB,CACD,CACD,CAAC,EAEK,IAAgB,EAAM,EAAO,IAAW,CAC7C,IAAI,EACA,EASJ,OARI,IAAW,IAAA,IACd,EAAU,EACV,EAAW,IAEX,EAAU,EAAO,QAAU,EAC3B,EAAW,EAAQ,EAAO,UAGpB,CACN,OACA,QACA,UACA,WACA,QACD,CACD,EAEM,GAAiB,EAAM,EAAS,IAAa,CAGlD,IAAM,GAAW,GAAG,IAAe,GAAW,EAAU,EAAW,SAAW,EAAM,GAAK,EAAW,GAAM,EAAW,KAAK,GAAG,CAAC,EAU9H,OANA,OAAO,eAAe,EAAS,EAAK,EAEpC,EAAQ,IAAa,EACrB,EAAQ,GAAU,EAClB,EAAQ,GAAY,EAEb,CACR,EAEM,IAAc,EAAM,IAAW,CACpC,GAAI,EAAK,OAAS,GAAK,CAAC,EACvB,OAAO,EAAK,GAAY,GAAK,EAG9B,IAAI,EAAS,EAAK,GAElB,GAAI,IAAW,IAAA,GACd,OAAO,EAGR,GAAM,CAAC,UAAS,YAAY,EAC5B,GAAI,EAAO,SAAS,MAAQ,EAC3B,KAAO,IAAW,IAAA,IAIjB,EAAS,GAAiB,EAAQ,EAAO,MAAO,EAAO,IAAI,EAE3D,EAAS,EAAO,OAOlB,IAAM,EAAU,EAAO,QAAQ;CAAI,EAKnC,OAJI,IAAY,KACf,EAAS,GAA+B,EAAQ,EAAU,EAAS,CAAO,GAGpE,EAAU,EAAS,CAC3B,EAEA,OAAO,iBAAiB,EAAY,UAAW,CAAM,EAErD,MAAM,EAAQ,EAAY,EACC,EAAY,CAAC,MAAO,GAAc,GAAY,MAAQ,CAAC,CAAC,EChLnF,MAAa,GAA8D,CACzE,iBAAkB,CAChB,KAAM,iBACN,QAAS,MACT,aAAc,CAAC,EACf,UAAW,MACb,EACA,YAAa,CACX,KAAM,YACN,QAAS,MACT,aAAc,CAAC,gBAAgB,EAC/B,UAAW,MACb,EACA,SAAU,CACR,KAAM,WACN,QAAS,WACT,aAAc,CAAC,EACf,UAAW,MACb,EACA,MAAO,CACL,KAAM,QACN,QAAS,QACT,aAAc,CAAC,EACf,UAAW,MACb,EACA,IAAK,CACH,KAAM,MACN,QAAS,MACT,aAAc,CAAC,OAAO,EACtB,UAAW,MACb,EACA,MAAO,CACL,KAAM,QACN,QAAS,QACT,aAAc,CAAC,OAAO,EACtB,UAAW,MACb,EACA,QAAS,CACP,KAAM,UACN,QAAS,UACT,aAAc,CAAC,OAAO,EACtB,UAAW,MACb,EACA,QAAS,CACP,KAAM,UACN,QAAS,UACT,aAAc,CAAC,QAAS,KAAK,EAC7B,UAAW,MACb,EACA,OAAQ,CACN,KAAM,SACN,QAAS,SACT,aAAc,CAAC,QAAS,MAAO,UAAU,EACzC,UAAW,MACb,EACA,QAAS,CACP,KAAM,UACN,QAAS,UACT,aAAc,CAAC,EACf,UAAW,MACb,CACF,EAGa,GAAmD,CAC9D,aACA,MACA,UACA,SACA,UACA,UACA,QACA,QACA,WACA,KACF,EAIE,GAAkB,OAAQ,GAAS,IAAS,UAAU,EC3ExD,IAAa,EAAb,cAAmD,KAAM,CACvD,YAAY,EAAiB,CAC3B,MAAM,CAAO,EACb,KAAK,KAAO,+BACd,CACF,EAEA,SAAS,GAAe,EAAwB,CAI9C,OAHI,aAAkB,MACb,EAEE,MAAM,OAAO,CAAM,CAAC,CACjC,CAEA,SAAS,GACP,EACA,EACS,CACT,IAAM,EAAM,IAAI,IAChB,IAAK,IAAI,EAAI,EAAG,EAAI,EAAW,OAAQ,IAAK,CAC1C,IAAM,EAAI,EAAW,GACjB,KAAE,SAAW,WAAa,EAAE,SAAW,UAG3C,GAAI,EAAE,SAAW,SACf,EAAI,IAAI,EAAE,IAAI,MACT,CACL,IAAM,EAAY,EAAE,UACpB,GAAI,GAAa,EAAU,OAAS,EAClC,IAAK,IAAM,KAAK,EACd,EAAI,IAAI,CAAC,OAGX,EAAI,IAAI,EAAgB,EAAW,CAEvC,CACF,CACA,MAAO,CAAC,GAAG,CAAG,CAChB,CAEA,SAAgB,GACd,EACM,CACN,IAAM,EAAQ,IAAI,IAClB,IAAK,IAAM,KAAK,EAAU,CACxB,GAAI,EAAM,IAAI,EAAE,IAAI,EAClB,MAAM,IAAI,EAA8B,2BAA2B,OAAO,EAAE,IAAI,EAAE,GAAG,EAEvF,EAAM,IAAI,EAAE,IAAI,CAClB,CAEA,IAAK,IAAM,KAAK,EAAU,CACxB,IAAM,EAAO,EAAE,cAAgB,CAAC,EAChC,IAAK,IAAM,KAAK,EAAM,CACpB,GAAI,IAAM,EAAE,KACV,MAAM,IAAI,EACR,YAAY,OAAO,EAAE,IAAI,EAAE,2BAC7B,EAEF,GAAI,CAAC,EAAM,IAAI,CAAC,EACd,MAAM,IAAI,EACR,YAAY,OAAO,EAAE,IAAI,EAAE,gCAAgC,OAAO,CAAC,EAAE,GACvE,CAEJ,CACF,CAEA,IAAM,EAAW,IAAI,IACf,EAAU,IAAI,IACd,EAAS,IAAI,IAAI,EAAS,IAAK,GAAM,CAAC,EAAE,KAAM,CAAC,CAAU,CAAC,EAEhE,SAAS,EAAI,EAAmB,CAC9B,GAAI,EAAQ,IAAI,CAAI,EAClB,OAEF,GAAI,EAAS,IAAI,CAAI,EACnB,MAAM,IAAI,EACR,gDAAgD,OAAO,CAAI,EAAE,GAC/D,EAEF,EAAS,IAAI,CAAI,EACjB,IAAM,EAAM,EAAO,IAAI,CAAI,EACtB,KAGL,KAAK,IAAM,KAAK,EAAI,cAAgB,CAAC,EACnC,EAAI,CAAC,EAEP,EAAS,OAAO,CAAI,EACpB,EAAQ,IAAI,CAAI,CAHT,CAIT,CAEA,IAAK,IAAM,KAAK,EACd,EAAI,EAAE,IAAI,CAEd,CAGA,SAAgB,GACd,EACA,EAGA,CACA,GAAuB,CAAQ,EAE/B,IAAM,EAAS,IAAI,IAAI,EAAS,IAAK,GAAM,CAAC,EAAE,KAAM,CAAC,CAAU,CAAC,EAC1D,EAAU,IAAI,IAEpB,SAAS,EAAQ,EAA4D,CAC3E,IAAM,EAAW,EAAQ,IAAI,CAAI,EACjC,GAAI,EACF,OAAO,EAGT,IAAM,EAAM,EAAO,IAAI,CAAI,EAE3B,GAAI,CAAC,EACH,MAAM,IAAI,EAA8B,yBAAyB,OAAO,CAAI,EAAE,GAAG,EAGnF,IAAM,GAAQ,SAA2D,CACvE,IAAM,EAAkB,EAAI,cAAgB,CAAC,EACvC,EAAa,MAAM,QAAQ,IAAI,EAAgB,IAAK,GAAM,EAAQ,CAAC,CAAC,CAAC,EAK3E,GAHe,EAAW,KACvB,GAAM,EAAE,SAAW,WAAa,EAAE,SAAW,SAEvC,EACP,MAAO,CACL,OACA,OAAQ,UACR,UAAW,GAA+B,EAAiB,CAAU,CACvE,EAGF,GAAI,EAAI,UAAY,GAClB,MAAO,CAAE,OAAM,OAAQ,SAAU,EAGnC,IAAM,EAA8B,EAAI,WAAa,OAErD,GAAI,CAKF,GAJI,EAAI,eACN,MAAM,EAAI,cAAc,EAGtB,CAAC,MADY,EAAI,gBAAgB,EAC5B,CACP,IAAM,EAAU,MAAM,gCAAgC,EAItD,OAHI,IAAS,OACX,EAAO,SAAS,OAAO,CAAI,EAAG,EAAI,OAAO,EAEpC,CAAE,OAAM,OAAQ,SAAU,MAAO,CAAI,CAC9C,CACA,MAAO,CAAE,OAAM,OAAQ,SAAU,CACnC,OAAS,EAAiB,CACxB,IAAM,EAAM,GAAe,CAAM,EAIjC,OAHI,IAAS,OACX,EAAO,SAAS,OAAO,CAAI,EAAG,EAAI,OAAO,EAEpC,CAAE,OAAM,OAAQ,SAAU,MAAO,CAAI,CAC9C,CACF,EAAA,CAAG,EAGH,OADA,EAAQ,IAAI,EAAM,CAAI,EACf,CACT,CAEA,MAAO,CACL,MAAO,SAAY,CACjB,IAAM,EAAiB,MAAM,QAAQ,IAAI,EAAS,IAAK,GAAM,EAAQ,EAAE,IAAI,CAAC,CAAC,EAI7E,MAAO,CAAE,WAHU,EAAe,KAC/B,GAAM,EAAE,SAAW,WAAa,EAAO,IAAI,EAAE,IAAI,CAAC,EAAE,WAAa,UAAY,MAE9D,EAAG,SAAU,CAAe,CAChD,CACF,CACF,CCjNA,MAQa,GAAsB,mCCQtB,GAAmE,CAC9E,cAAe,MACf,gBAAiB,QACjB,iBAAkB,SAClB,kBAAmB,UACnB,kBAAmB,SACrB,EAEA,SAAgB,EAAqB,EAAqC,CACxE,MAAO,UAAU,EAAM,gBACzB,CAMA,SAAgB,EAA8B,EAAqB,CACjE,OAAO,EAAI,KAAK,CAAC,CAAC,QAAQ,OAAQ,EAAE,CACtC,CAEA,SAAgB,IAAmC,CACjD,MAAO,CAAC,QAAS,QAAS,KAAM,OAA6B,UAAU,CACzE,CAEA,SAAgB,IAAkC,CAChD,MAAO,CAAC,QAAS,MAAM,CACzB,CAEA,SAAgB,GAAqB,EAAc,EAAc,EAAQ,GAAiB,CACxF,IAAM,EAAO,CAAC,QAAS,EAAM,OAAO,CAAI,CAAC,EAIzC,OAHI,GACF,EAAK,KAAK,SAAS,EAEd,CACT,CAEA,SAAgB,GAAwB,EAAwB,CAC9D,MAAO,CAAC,QAAS,WAAY,CAAI,CACnC,CAEA,eAAsB,EAAe,EAIlC,CACD,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAO,EAAM,WAAY,EAAM,CAAE,MAAO,CAAC,SAAU,OAAQ,MAAM,CAAE,CAAC,EACtE,EAAS,GACT,EAAS,GACb,EAAK,QAAQ,GAAG,OAAS,GAAM,CAC7B,GAAU,OAAO,CAAC,CACpB,CAAC,EACD,EAAK,QAAQ,GAAG,OAAS,GAAM,CAC7B,GAAU,OAAO,CAAC,CACpB,CAAC,EACD,EAAK,GAAG,QAAS,CAAM,EACvB,EAAK,GAAG,OAAS,GAAS,CACxB,EAAQ,CAAE,KAAM,GAAQ,EAAG,SAAQ,QAAO,CAAC,CAC7C,CAAC,CACH,CAAC,CACH,CAGA,eAAsB,IAA2C,CAC/D,GAAI,CAEF,OAAO,MADS,EAAe,CAAC,WAAW,CAAC,EAAA,CACnC,OAAS,CACpB,MAAQ,CACN,MAAO,EACT,CACF,CAMA,eAAsB,IAAyD,CAC7E,IAAM,EAAI,MAAM,EAAe,GAAuB,CAAC,EACvD,GAAI,EAAE,OAAS,EACb,MAAO,CAAE,YAAa,EAAK,EAE7B,IAAM,EAAW,GAAG,EAAE,OAAO,IAAI,EAAE,SACnC,GAAI,iCAAiC,KAAK,CAAQ,EAChD,MAAO,CAAE,YAAa,EAAM,EAE9B,MAAU,MACR,qCAAqC,EAAE,KAAK,KAAK,EAAS,KAAK,GAAK,eACtE,CACF,CAGA,SAAgB,GAAkB,EAAwB,CACxD,GAAI,OAAO,GAAU,UAAY,OAAO,SAAS,CAAK,EACpD,OAAO,EAET,IAAM,EAAI,OAAO,CAAK,CAAC,CAAC,KAAK,EAC7B,GAAI,IAAM,GACR,MAAU,MAAM,qBAAqB,EAEvC,IAAM,EAAI,OAAO,SAAS,EAAG,EAAE,EAC/B,GAAI,CAAC,OAAO,SAAS,CAAC,EACpB,MAAU,MAAM,iBAAiB,OAAO,CAAK,GAAG,EAElD,OAAO,CACT,CAGA,eAAsB,GAAiB,EAA4B,EAA8B,CAC/F,IAAM,EAAa,GAAkB,CAAI,EACnC,EAAI,MAAM,EAAe,GAAqB,EAAM,EAAY,EAAI,CAAC,EAC3E,GAAI,EAAE,OAAS,EAAG,CAChB,IAAM,EAAW,GAAG,EAAE,OAAO,IAAI,EAAE,SACnC,MAAU,MAAM,kBAAkB,EAAK,GAAG,EAAW,WAAW,EAAS,KAAK,GAAG,CACnF,CACF,CAEA,eAAsB,GAAsB,EAAuD,CACjG,IAAK,IAAM,KAAQ,EACjB,MAAM,EAAe,GAAwB,CAAI,CAAC,CAEtD,CAEA,eAAsB,IAAmC,CACvD,MAAM,EAAe,GAAsB,CAAC,CAC9C,CCrIA,MAIM,GAAW,KACX,GAAe,KACf,EAAkB,KAClB,GAAa,KAMN,GAA2B,6CAkC3B,GAA+B,CAAC,eAAe,EAetD,GAAqB,MAQrB,EAAuB,WAuB7B,SAAgB,GAAiB,EAAiC,CAChE,GAAM,CAAE,OAAM,WAAU,UAAS,wBAAyB,EAEpD,EAAU,IAAS,OAAS,MAAgB,MAC5C,EAAY,IAAS,OAAS,MAAkB,MAChD,EAAa,IAAS,OAAS,MAAmB,MAClD,EAAc,IAAS,OAAS,MAAoB,MAGpD,EAAa,4BACb,EAAa,EAAQ,EAAM,CAAO,EAClC,EAAe,EAAQ,EAAM,CAAS,EACtC,EAAgB,EAAQ,EAAM,CAAU,EACxC,EAAiB,EAAQ,EAAM,CAAW,EAC1C,EAAiB,EAAQ,EAAM,KAAW,EAE1C,EAAgB,oBAAoB,KAEpC,EACJ,GAAY,EACR,EAA8B,CAAoB,EAClD,GAAc,EAAM,EAAS,EAAU,KAAK,EAK5C,EAAa,CACjB,uBAAwB,cACxB,iBAAkB,wBAClB,GAAI,IAAS,QACT,CACA,gDAAiD,GAAG,GAAoB,cACxE,oDAAA,EACF,EACE,CAAC,CACP,EAoJA,MAAO,CAjJL,IAAK,CACH,KAAM,CACR,EACA,SAAU,CACR,KAAM,EACR,EACA,gBAAiB,CACf,SAAU,IACV,WAAY,WACZ,WAAY,WACZ,YAAa,WACb,WAAY,UACZ,aAAc,WACd,aAAc,WACd,yBAA0B,YAC1B,qBAAsB,OACA,uBACtB,yBAA0B,CAC5B,EACA,oBAAqB,CACnB,aAAc,oBAAoB,IAClC,iBAAkB,KAClB,oBAAqB,SACrB,2BAA4B,IAC5B,iCAAkC,KAClC,aAAc,WACd,aAAc,WACQ,uBACtB,cAAe,aAAa,KAC5B,WAAY,YACZ,wBACE,mFACF,kBAAmB,OACrB,EACA,QAAS,CACP,iBAAkB,cAClB,yBAA0B,QAC1B,aAAc,mBAChB,EACA,kBAAmB,CAAC,EACpB,cAAe,CACb,GAAG,EACH,gBAAiB,EAEjB,6BAA8B,EAC9B,2CAA4C,OAC5C,yCAA0C,EAC1C,6CAA8C,EAC9C,wCAAyC,EACzC,uCAAwC,EACxC,kCAAmC,GAAG,EAAa,WACnD,4CAA6C,EAC7C,wCAAyC,EACzC,qCAAsC,GAAG,EAAW,8BACpD,+BAAgC,GAAG,EAAW,wBAC9C,oCAAqC,GAAG,EAAW,0BACnD,gCAAiC,GAAG,EAAW,eACjD,EACA,gBAAiB,CACf,GAAG,EACH,gBAAiB,EACjB,mBAAoB,EAEpB,oBAAqB,EACrB,kCAAmC,OACnC,qCAAsC,GAAG,EAAW,iCACpD,+BAAgC,GAAG,EAAW,0BAC9C,4BAA6B,GAAG,EAAW,kBAC3C,oCAAqC,GAAG,EAAW,yBACrD,EACA,iBAAkB,CAChB,GAAG,EACH,gBAAiB,EACjB,oBAAqB,EACrB,kCAAmC,OACnC,qCAAsC,GAAG,EAAW,iCACpD,+BAAgC,GAAG,EAAW,2BAC9C,6BAA8B,GAAG,EAAW,mBAC5C,oCAAqC,GAAG,EAAW,0BACnD,wBAAyB,OACzB,wBAAyB,oBAAoB,KAC7C,2BAA4B,EAC5B,0CAA2C,CAC7C,EACA,kBAAmB,CACjB,GAAG,EACH,gBAAiB,EACjB,mCAAoC,YACpC,oBAAqB,EACrB,mCAAoC,EACpC,kCAAmC,mCACnC,kCAAmC,mCACnC,kCAAmC,OACnC,gBAAiB,EACjB,gBAAiB,EACjB,8BAA+B,QAC/B,sBAAuB,IACvB,qCAAsC,GAAG,EAAW,iCACpD,+BAAgC,GAAG,EAAW,4BAC9C,8BAA+B,GAAG,EAAW,oBAC7C,oCAAqC,GAAG,EAAW,yBACrD,EACA,kBAAmB,CACjB,GAAG,EACH,gBAAiB,EACjB,6BAA8B,YAC9B,qCAAsC,GAAG,EAAW,2BACpD,+BAAgC,GAAG,EAAW,qBAC9C,8BAA+B,GAAG,EAAW,aAC7C,qCAAsC,EACtC,wCAAyC,MAC3C,EACA,qBAAsB,CACpB,kBACA,aACF,EACA,cAAe,CACb,cAAe,QACf,gBAAiB,MACjB,qBAAsB,OACtB,cAAe,IACf,gBAAiB,OACjB,YAAa,QACb,kBAAmB,6BAA6B,IAChD,4BAA6B,6BAA6B,IAC1D,aAAc,WACd,yBAA0B,6CAC1B,0BAA2B,6CAC3B,yBAA0B,6CAC1B,2BAA4B,6CAC5B,oBAAqB,6CACrB,8BAA+B,IAC/B,eAAgB,GAChB,cAAe,OACf,YACA,gBACA,aAAc,WAAW,KACzB,aAAc,WAAW,KACzB,yBAA0B,IAC1B,wBAAyB,OACzB,kBAAmB,GACnB,aAAc,EAChB,CAGQ,CACZ,CAEA,SAAgB,GAA8B,EAAgD,CAC5F,MAAO,CACL,OACA,SAAU,GACV,QAAS,IAAS,OAAS,KAAW,IACxC,CACF,CAGA,SAAgB,EAA4B,EAA0B,CACpE,IAAM,EAAQ,EAAS,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,GAAK,GAChD,GAAI,CACF,IAAM,EAAI,IAAI,IAAI,CAAK,EAIvB,OAHI,EAAE,KACG,EAAE,KAEJ,EAAE,WAAa,SAAW,MAAQ,IAC3C,MAAQ,CACN,OAAO,EAAM,MAAM,GAAG,CAAC,CAAC,IAAM,IAChC,CACF,CAEA,SAAS,EAAQ,EAAwB,EAAsB,CAC7D,MAAO,GAAG,EAAK,eAAe,GAChC,CAEA,SAAS,GACP,EACA,EACA,EACA,EACQ,CAIR,OAHI,EACK,EAAqB,CAAK,EAE5B,EAAQ,EAAM,CAAI,CAC3B,CAEA,MAAa,GAA4B,EAAS,IACnC,GAAiB,CAKlB,CAAC,CAA6B,IAAS,KAMrD,SAAgB,GAA8D,EAAW,CACvF,IAAM,EAAW,IAAI,IAAY,EAA4B,EAC7D,OAAO,OAAO,YAAY,OAAO,QAAQ,CAAG,CAAC,CAAC,QAAQ,CAAC,KAAS,CAAC,EAAS,IAAI,CAAG,CAAC,CAAC,CACrF,CCjVA,MAAa,GAAuB,mBAOpC,SAAgB,GAAoB,EAAkD,CACpF,GAAI,OAAO,EAAQ,UAAa,UAC9B,OAAO,EAAQ,SAEjB,IAAM,EAAM,QAAQ,IAAI,GAAqB,EAAE,KAAK,CAAC,CAAC,YAAY,EAClE,OAAO,IAAQ,KAAO,IAAQ,QAAU,IAAQ,KAClD,CAKA,MAAM,GAAiE,CACrE,UACA,QACA,MACA,MACA,QACA,UACA,SACA,UACA,UACF,EAMA,SAAS,GAAuB,EAA8D,CAI5F,OAHI,OAAO,GAAU,UAAY,EACxB,EAAM,UAAY,GAEpB,IAAU,EACnB,CAMA,SAAS,GAAwB,EAA8D,CAI7F,OAHI,IAAU,GACL,GAEF,OAAO,GAAU,UAAY,EAAiB,EAAM,UAAY,GAAQ,EACjF,CAkBA,SAAgB,GAAiB,EAAkC,CACjE,IAAM,EAAU,CAAC,EACjB,IAAK,IAAM,KAAW,GACpB,EAAQ,GACN,IAAY,WACR,GAAwB,EAAQ,EAAQ,EACxC,GAAuB,EAAQ,EAAQ,EAG/C,EAAQ,WAAa,EAAQ,IAE7B,IAAM,EAAkB,CACtB,UACA,SAAU,GAAoB,CAAO,EACrC,SAAU,EAAQ,UAAY,GAC9B,KAAM,EAAQ,MAAQ,OACtB,sBAAuB,EAAQ,uBAAyB,EAC1D,EAIA,OAHI,EAAQ,UAAY,IAAA,KACtB,EAAK,QAAU,EAAQ,SAElB,CACT,CC9EA,SAASC,GAAM,EAAY,CACzB,OAAO,IAAI,QAAe,GAAY,WAAW,EAAS,CAAE,CAAC,CAC/D,CAkBA,eAAsB,GACpB,EACwB,CACxB,IAAM,EAAgB,GAAS,eAAiB,WAC1C,EAAa,GAAS,YAAc,wCACpC,EAAc,GAAS,aAAe,IACtC,EAAa,GAAS,YAAc,IAK1C,IAAK,IAAI,EAAU,EAAG,EAAU,EAAa,IAAW,CACtD,IAAM,EAAQ,MAAM,GAAsB,EAAe,EAAY,iGAAG,EACxE,GAAI,EACF,OAAO,EAEL,EAAU,EAAc,GAC1B,MAAMA,GAAM,CAAU,CAE1B,CAEA,OAAO,IACT,CAEA,SAAS,GACP,EACA,EACA,EACwB,CACxB,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAAO,EAAM,SAAU,CAAC,OAAQ,EAAe,UAAW,EAAY,CAAG,CAAC,EAE5E,EAAS,GACb,EAAK,QAAQ,GAAG,OAAS,GAA2B,CAClD,GAAU,OAAO,GAAU,SAAW,EAAQ,EAAM,SAAS,MAAM,CACrE,CAAC,EACD,EAAK,GAAG,YAAe,CACrB,EAAQ,IAAI,CACd,CAAC,EACD,EAAK,GAAG,QAAU,GAAwB,CACxC,GAAI,IAAS,EAAG,CACd,EAAQ,IAAI,EACZ,MACF,CACA,IAAM,EAAU,EAAO,KAAK,EAC5B,EAAQ,EAAQ,OAAS,EAAI,EAAU,IAAI,CAC7C,CAAC,CACH,CAAC,CACH,CAWA,SAAgB,GAAU,EAAiC,CACzD,IAAM,EAAc,OAAO,QAAY,IAAc,QAAQ,MAAM,GAAO,IAAA,GAC1E,GAAI,IAAgB,IAAA,GAClB,OAAO,EAGT,GAAI,CAEF,IAAM,EADQ,OAAO,KAAwD,MACxD,GACrB,OAAO,OAAO,GAAU,SAAW,EAAQ,IAAA,EAC7C,MAAQ,CACN,MACF,CACF,CAEA,SAAgB,EAAY,GAAG,EAAiB,CAC9C,OAAO,EAAK,QAAQ,qBAAmB,GAAG,CAAK,CACjD,CAEA,SAAgB,GAAkB,GAAG,EAAiB,CACpD,IAAM,EAAW,EAAY,GAAG,CAAK,EAIrC,OAHI,QAAQ,WAAa,QAChB,EAAS,QAAQ,MAAO,GAAG,EAE7B,CACT,CAEA,SAAgB,EACd,EACA,EACA,EACA,EACA,CACA,GAAI,GAAS,YAAa,CACxB,IAAM,EAAW,GAAG,EAAQ,YAAY,QAAQ,MAAO,EAAE,EAAE,GACrD,EAAM,GAAG,EAAS,eAAe,EAAK,GAC5C,QAAQ,IACN,KAAK,EAAM,MAAM,GAAG,EAAE,IAAI,EAAM,KAAK,CAAa,EAAE,MAAM,EAAM,KAAK,CAAQ,EAAE,GAAG,EAAM,KAAK,IAAI,EAAI,EAAE,GACzG,EACA,MACF,CACA,IAAM,EAAM,GAAG,EAAS,eAAe,EAAM,KAAK,WAAW,CAAI,EAAE,GACnE,QAAQ,IAAI,KAAK,EAAM,MAAM,GAAG,EAAE,IAAI,EAAM,KAAK,CAAa,EAAE,MAAM,EAAM,KAAK,CAAG,GAAG,CACzF,CAEA,SAAgB,GAAW,EAAuB,CAChD,QAAQ,IACN,KAAK,EAAM,KAAK,GAAG,EAAE,IAAI,EAAM,KAAK,CAAa,EAAE,MAAM,EAAM,OAAO,sBAAsB,GAC9F,CACF,CAEA,SAAgB,EAAS,EAAuB,EAAgB,CAC9D,QAAQ,IAAI,KAAK,EAAM,IAAI,GAAG,EAAE,IAAI,EAAM,KAAK,CAAa,EAAE,MAAM,EAAM,IAAI,CAAM,GAAG,CACzF,CAEA,eAAsB,GAAW,EAAa,EAAiB,EAAoC,CACjG,IAAM,EAAO,EAAM,EAAK,EAAM,CAAO,EAErC,OAAO,IAAI,SAAe,EAAK,IAAQ,CACrC,EAAK,GAAG,QAAU,GAAQ,CACxB,EAAI,CAAG,CACT,CAAC,EACD,EAAK,GAAG,WAAc,CACpB,EAAI,CACN,CAAC,CACH,CAAC,CACH,CAEA,eAAsB,GAAsB,EAAa,CACvD,IAAM,EAAO,MAAM,MAAM,GAAG,EAAI,WAAW,EAC3C,GAAI,CAAC,EAAK,GACR,MAAU,MAAM,kCAAkC,EAAI,IAAI,EAAK,YAAY,EAE7E,IAAM,EAAQ,MAAM,EAAK,KAAK,EAGxB,EAAW,MAAM,QAAQ,EAAK,QAAQ,EAAI,EAAK,SAAW,CAAC,EAEjE,GAAI,EAAS,SAAW,EAEtB,OADA,MAAM,IAAI,QAAS,GAAY,WAAW,EAAS,GAAG,CAAC,EAChD,GAAsB,CAAG,EAGlC,IAAM,EAAU,EAAS,KAAM,GAAQ,CAAC,EAAI,SAAS,WAAW,CAAC,EAEjE,GAAI,CAAC,EACH,MAAU,MAAM,oDAAoD,GAAK,EAE3E,OAAO,CACT,CC9KA,MAAM,GAA2B,WAGjC,SAAgB,EAA4B,EAAsB,CAChE,OAAO,EAAK,WAAW,EAAwB,EAAI,EAAO,GAAG,KAA2B,GAC1F,CAEA,MAAM,GAAyB,sCACzB,GAAwB,IAG9B,SAAS,EAAc,EAAiB,EAAgB,CAEtD,EADmB,EAAS,EAAM,CAAE,SAAU,GAAM,MAAO,QAAS,CACjE,CAAC,CAAC,MAAM,CACb,CAGA,SAAS,IAA0C,CACjD,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAAO,EAAM,SAAU,CAAC,MAAM,EAAG,CAAE,MAAO,QAAS,CAAC,EAC1D,EAAK,GAAG,YAAe,EAAQ,EAAK,CAAC,EACrC,EAAK,GAAG,OAAS,GAAS,EAAQ,IAAS,CAAC,CAAC,CAC/C,CAAC,CACH,CAGA,SAAS,IAAyC,CAChD,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAAO,EAAM,SAAU,CAAC,WAAW,EAAG,CAAE,MAAO,QAAS,CAAC,EAC/D,EAAK,GAAG,YAAe,EAAQ,EAAK,CAAC,EACrC,EAAK,GAAG,OAAS,GAAS,EAAQ,IAAS,CAAC,CAAC,CAC/C,CAAC,CACH,CAEA,SAAS,IAAuB,CAC9B,GAAM,CAAE,YAAa,QAErB,GAAI,IAAa,SAAU,CACzB,EAAc,OAAQ,CAAC,KAAM,QAAQ,CAAC,EACtC,MACF,CAEA,GAAI,IAAa,QAAS,CACxB,IAAM,EAAM,wDACZ,GAAI,EAAG,WAAW,CAAG,EAAG,CACtB,EAAc,EAAK,CAAC,CAAC,EACrB,MACF,CACA,EAAc,MAAO,CAAC,KAAM,QAAS,GAAI,gBAAgB,CAAC,EAC1D,MACF,CAEI,IAAa,SACf,EAAc,YAAa,CAAC,SAAU,QAAS,gBAAgB,CAAC,CAEpE,CAEA,SAASC,GAAM,EAAY,CACzB,OAAO,IAAI,QAAe,GAAY,WAAW,EAAS,CAAE,CAAC,CAC/D,CAMA,eAAsB,IAAoB,CAYxC,GAVK,MADe,GAAqB,IAEvC,QAAQ,MACN,KAAK,EAAM,IAAI,GAAG,EAAE,IAAI,EAAM,KAAK,QAAQ,EAAE,MAAM,EAAM,IAAI,8CAA8C,GAC7G,EACA,QAAQ,MACN,sCAAsC,EAAM,KAAK,UAAU,EAAsB,GACnF,EACA,QAAQ,KAAK,CAAC,GAGZ,MAAM,GAAsB,EAC9B,OAGF,QAAQ,IACN,KAAK,EAAM,OAAO,GAAG,EAAE,IAAI,EAAM,KAAK,QAAQ,EAAE,MAAM,EAAM,OAAO,4CAA4C,GACjH,EACA,GAAqB,EAErB,IAAM,EAAW,KAAK,IAAI,EAAI,GAC9B,KAAO,KAAK,IAAI,EAAI,GAElB,GADA,MAAMA,GAAM,GAAqB,EAC7B,MAAM,GAAsB,EAAG,CACjC,QAAQ,IACN,KAAK,EAAM,MAAM,GAAG,EAAE,IAAI,EAAM,KAAK,QAAQ,EAAE,MAAM,EAAM,MAAM,kBAAkB,GACrF,EACA,MACF,CAGF,QAAQ,MACN,KAAK,EAAM,IAAI,GAAG,EAAE,IAAI,EAAM,KAAK,QAAQ,EAAE,MAAM,EAAM,IACvD,sCAAsC,GAAwB,IAAK,uDACrE,GACF,EACA,QAAQ,MAAM,iCAAiC,EAAM,KAAK,UAAU,EAAsB,GAAG,EAC7F,QAAQ,KAAK,CAAC,CAChB,CAEA,eAAsB,EAAqB,CACzC,gBACA,YACA,OAAO,CAAC,EACR,MAAM,CAAC,EACP,WAAW,IAQoB,CAC/B,IAAM,EAAsB,EAA4B,CAAa,EAErE,GAAI,CAAC,EACC,MAAM,GAAqB,CAAmB,GAChD,MAAM,GAAc,CAAmB,MAEpC,CACL,GAAI,MAAM,GAAmB,CAAmB,EAC9C,OAAO,KAEL,MAAM,GAAqB,CAAmB,GAChD,MAAM,GAAqB,CAAmB,CAElD,CAIA,IAAM,EAAU,CACd,MACA,OACA,SACA,EACA,GAAG,EACH,EACA,GAAG,CACL,EACM,EACJ,EACI,EAAM,SAAU,CAAC,GAAG,CAAO,EAAG,CAC5B,SAAU,GACV,MAAO,CAAC,SAAU,OAAQ,MAAM,CAClC,CAAC,EACD,EAAM,SAAU,CAAC,GAAG,CAAO,CAAC,EAgBlC,OAdA,EAAK,QAAQ,GAAG,OAAS,GAAS,CAChC,IAAM,EAAO,OAAO,CAAI,EAEpB,iBAAiB,KAAK,CAAI,GAC5B,GAAW,CAAmB,EAE5B,+BAA+B,KAAK,CAAI,GAC1C,EAAS,EAAqB,CAAI,CAEtC,CAAC,EACG,GACF,EAAK,MAAM,EAGN,CACT,CAEA,eAAe,GAAqB,EAAc,CAChD,IAAM,EAAO,EAAM,SAAU,CAC3B,KACA,KACA,WACA,QAAQ,EAA4B,CAAI,GAC1C,CAAC,EAYD,OAFc,MATO,IAAI,QAAiB,GAAQ,CAChD,IAAI,EAAO,GACX,EAAK,QAAQ,GAAG,OAAS,GAAM,CAC7B,GAAQ,OAAO,CAAC,CAClB,CAAC,EACD,EAAK,GAAG,YAAe,CACrB,EAAI,CAAI,CACV,CAAC,CACH,CAAC,EAAA,CACoB,MAAM;CACP,CAAC,CAAC,OAAS,CAEjC,CAGA,eAAsB,GAAc,EAAc,CAChD,IAAM,EAAO,EAAM,SAAU,CAAC,OAAQ,EAA4B,CAAI,CAAC,CAAC,EACxE,MAAM,IAAI,QAAe,GAAQ,CAC/B,EAAK,GAAG,YAAe,CACrB,EAAI,CACN,CAAC,CACH,CAAC,CACH,CAGA,eAAsB,GAAmB,EAAgC,CACvE,OAAO,IAAI,QAAS,GAAY,CAC9B,IAAM,EAAO,EACX,SACA,CAAC,UAAW,KAAM,qBAAsB,EAA4B,CAAI,CAAC,EACzE,CACE,MAAO,CAAC,SAAU,OAAQ,QAAQ,CACpC,CACF,EACI,EAAM,GACV,EAAK,QAAQ,GAAG,OAAS,GAAM,CAC7B,GAAO,OAAO,CAAC,CACjB,CAAC,EACD,EAAK,GAAG,YAAe,EAAQ,EAAK,CAAC,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,GAAI,IAAS,EAAG,CACd,EAAQ,EAAK,EACb,MACF,CACA,EAAQ,EAAI,KAAK,CAAC,CAAC,YAAY,IAAM,MAAM,CAC7C,CAAC,CACH,CAAC,CACH,CAEA,eAAe,GAAqB,EAAc,CAChD,MAAM,IAAI,QAAe,GAAQ,CAC/B,IAAM,EAAO,EAAM,SAAU,CAAC,KAAM,KAAM,EAA4B,CAAI,CAAC,EAAG,CAC5E,MAAO,QACT,CAAC,EACD,EAAK,GAAG,YAAe,EAAI,CAAC,EAC5B,EAAK,GAAG,YAAe,EAAI,CAAC,CAC9B,CAAC,CACH,CAEA,eAAsB,EAAsB,EAAoB,CAC9D,IAAM,EAAO,EAAM,SAAU,CAAC,SAAU,SAAU,CAAU,CAAC,EAE7D,MAAM,IAAI,QAAe,GAAQ,CAC/B,EAAK,GAAG,YAAe,CACrB,EAAI,CACN,CAAC,CACH,CAAC,CACH,CAEA,eAAsB,GAAc,EAAqB,CACvD,IAAM,EAAO,EAAM,SAAU,CAAC,UAAW,SAAU,CAAW,CAAC,EAE/D,MAAM,IAAI,QAAe,GAAQ,CAC/B,EAAK,GAAG,YAAe,CACrB,EAAI,CACN,CAAC,CACH,CAAC,CACH,CC5PA,MAAM,GAAyD,CAC7D,WAAY,CAAC,oBAAoB,EACjC,IAAK,CAAC,qBAAsB,cAAe,sBAAsB,EACjE,QAAS,CAAC,iBAAiB,EAC3B,OAAQ,CAAC,gBAAgB,EACzB,QAAS,CAAC,iBAAiB,EAC3B,QAAS,CAAC,iBAAiB,EAC3B,MAAO,CAAC,eAAe,EACvB,MAAO,CAAC,iBAAiB,EACzB,SAAU,CACR,4BACA,0BACA,oBACA,iBACA,UACF,EACA,IAAK,CAAC,aAAa,CACrB,EAGA,SAAgB,GAAkB,EAAuC,CACvE,OAAO,GAAiB,EAC1B,CAGA,eAAsB,GAAoB,EAA4C,CACpF,IAAM,EAAiB,CAAC,GAAG,IAAI,IAAI,EAAM,QAAQ,EAAiB,CAAC,CAAC,EACpE,MAAM,QAAQ,IAAI,EAAe,IAAK,GAAS,GAAc,CAAI,CAAC,CAAC,CACrE,CAMA,eAAsB,GAAY,EAA2C,CAE3E,MAAM,GADS,OAAO,KAAK,CAAO,CAAC,CAA0B,OAAQ,GAAS,EAAQ,EACxD,CAAC,CACjC,CCxCA,eAAsB,GAA0B,EAAuB,CACrE,MAAM,GAAW,SAAU,CAAC,OAAQ,EAAe,wBAAwB,CAAC,CAAC,CAAC,MAC3E,GAAiB,CAChB,QAAQ,MACN,EAAM,IACJ,+CAA+C,EAAc,KAAM,EAAc,SACnF,CACF,CACF,CACF,CACF,CCFA,eAAsB,EACpB,EACA,EACA,EACA,EAC8B,CAC9B,IAAI,EACE,EAAU,IAAI,QAAe,GAAQ,CACzC,EAAa,CACf,CAAC,EAEG,EAEE,CAAE,QAAS,EAAI,WACf,EAAM,CACV,GAAI,EAAO,EAAuB,EAAI,UAAU,GAAK,CAAC,EACtD,GAAG,CACL,EACM,EAAO,EAAI,gBAAgB,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC,IAAM,KAE3D,EAAQ,GAA2B,GACnC,EAAc,EAAI,WAAW,UAAY,EAAQ,EAAqB,CAAK,EAAI,IAAA,GAE/E,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,EACX,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,GAAI,IAAS,QACT,CACE,UACA,oBAAoB,GAAkB,MAAe,EAAE,UAAU,GAAoB,EACvF,EACA,CAAC,EACL,YACA,MACF,EACA,SAAU,EAAI,QAChB,CAAC,EAED,GAAI,CAAC,EAEH,OADA,EAAW,EAAM,EAAM,EAAM,CAAE,aAAY,CAAC,EACrC,KAET,EAAI,UAAU,CAAI,EAElB,IAAM,EAAgB,KAAO,IAAkB,CAC7C,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EAEpB,wDAAwD,KAAK,CAAI,IAC/D,IAAS,SACX,MAAM,GAA0B,CAAI,EAEtC,EAAW,EAAM,EAAM,EAAM,CAAE,aAAY,CAAC,EAC5C,IAAa,GAGf,IAAM,EAAuB,CAC3B,8CACA,uCACA,6BACF,EAUM,EAAgB,CALpB,kBACA,wCACA,mBACA,WAEuC,CAAC,CAAC,KAAM,GAAU,EAAM,KAAK,CAAI,CAAC,EACrE,EAAmB,0BAA0B,KAAK,CAAI,EAE1D,GACA,CAAC,GACD,iBAAiB,KAAK,CAAI,GAC1B,CAAC,EAAqB,KAAM,GAAU,EAAM,KAAK,CAAI,CAAC,GAEtD,EAAS,EAAM,CAAI,EACnB,IAAa,GAEb,EAAU,CAEd,EAgBA,OAdA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACxC,IAAa,CACf,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EAC9D,IAAa,EACb,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CChGA,SAASC,GAAM,EAA2B,CACxC,OAAO,IAAI,QAAe,GAAY,WAAW,EAAS,CAAE,CAAC,CAC/D,CAGA,eAAsB,EACpB,EACA,EACA,EACY,CACZ,IAAM,EAAO,MAAM,MAAM,EAAQ,CAC/B,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,UAAU,CAAE,QAAS,MAAO,GAAI,EAAG,SAAQ,QAAO,CAAC,CAChE,CAAC,EACD,GAAI,CAAC,EAAK,GACR,MAAU,MAAM,OAAO,EAAO,WAAW,EAAK,OAAO,GAAG,EAAK,YAAY,EAE3E,IAAM,EAAQ,MAAM,EAAK,KAAK,EAI9B,GAAI,EAAK,OAAO,QACd,MAAU,MAAM,OAAO,EAAO,UAAU,EAAK,MAAM,SAAS,EAE9D,OAAO,EAAK,MACd,CAGA,eAAsB,EAAoB,EAAgB,EAAoC,CAG5F,OAAO,MADc,EAAmB,EAAQ,YAAa,CADjD,KAAO,OAAO,KAAK,EAAW,OAAO,CAAC,CAAC,SAAS,KAAK,CACA,CAAC,EAAA,CACpD,MAAM,EAAG,EAAE,CAC3B,CAGA,SAAgB,GAAgB,EAAuB,CACrD,GAAI,EAAQ,GACV,MAAU,MAAM,sCAAsC,GAAO,EAE/D,OAAO,EAAM,SAAS,EAAE,CAAC,CAAC,SAAS,GAAI,GAAG,CAC5C,CAGA,SAAgB,GAAmB,EAAyB,CAC1D,IAAM,EAAU,EAAQ,YAAY,CAAC,CAAC,WAAW,IAAI,EAAI,EAAQ,MAAM,CAAC,EAAI,EAC5E,GAAI,EAAQ,SAAW,GACrB,MAAU,MAAM,uDAAuD,GAAS,EAElF,OAAO,EAAQ,YAAY,CAAC,CAAC,SAAS,GAAI,GAAG,CAC/C,CAGA,SAAgB,GAAmB,EAAsB,CACvD,IAAM,EAAU,EAAK,WAAW,IAAI,EAAI,EAAK,MAAM,CAAC,EAAI,EACxD,GAAI,EAAQ,SAAW,GACrB,MAAU,MAAM,uDAAuD,GAAM,EAE/E,OAAO,EAAQ,YAAY,CAC7B,CAGA,SAAgB,EAAW,EAAqB,CAC9C,IAAM,EAAU,EAAI,WAAW,IAAI,EAAI,EAAI,MAAM,CAAC,EAAI,EAItD,OAHI,EAAQ,SAAW,EACd,GAEF,OAAO,KAAO,CAAO,CAC9B,CAGA,eAAsB,GACpB,EACA,EACA,EACA,EAAiB,IACkC,CACnD,IAAM,EAAW,KAAK,IAAI,EAAI,EAC9B,KAAO,KAAK,IAAI,EAAI,GAAU,CAC5B,IAAM,EAAU,MAAM,EACpB,EACA,4BACA,CAAC,CAAM,CACT,EACA,GAAI,GAAS,OACX,MAAO,CAAE,OAAQ,EAAQ,OAAQ,YAAa,EAAQ,WAAY,EAEpE,MAAMA,GAAM,CAAM,CACpB,CACA,MAAU,MAAM,eAAe,EAAO,wBAAwB,EAAU,GAAG,CAC7E,CAGA,eAAsB,GAAgB,EAAgB,EAAkC,CACtF,OAAO,MAAM,EAAmB,EAAQ,cAAe,CAAC,EAAS,QAAQ,CAAC,CAAC,CAAC,KACzE,GAAW,GAAU,IACxB,CACF,CAGA,eAAsB,GAAuB,EAAiC,CAC5E,IAAM,EAAS,MAAM,EAAmB,EAAQ,kBAAmB,CAAC,CAAC,EACrE,OAAO,OAAO,SAAS,GAAU,MAAO,EAAE,CAC5C,CAGA,SAAgB,GAAuB,EAAuB,CAC5D,OAAO,IAAS,MAAQ,EAAK,OAAS,CACxC,CAGA,eAAsB,GACpB,EACA,EACA,EAA8B,UACb,CAEjB,OAAO,EAAW,MADG,EAAmB,EAAQ,0BAA2B,CAAC,EAAS,CAAK,CAAC,CACnE,CAC1B,CAGA,eAAsB,GAAoB,EAAiC,CAEzE,OAAO,EAAW,MADG,EAAmB,EAAQ,eAAgB,CAAC,CAAC,CAC1C,CAC1B,CAMA,SAAS,EAAW,EAAyB,CAC3C,IAAM,EAAU,EAAI,WAAW,IAAI,EAAI,EAAI,MAAM,CAAC,EAAI,EAChD,EAAS,EAAQ,OAAS,GAAM,EAAI,EAAU,IAAM,EAC1D,OAAO,WAAW,KAAK,OAAO,KAAK,EAAQ,KAAK,CAAC,CACnD,CAEA,SAAS,EAAW,EAA2B,CAC7C,OAAO,OAAO,KAAK,CAAK,CAAC,CAAC,SAAS,KAAK,CAC1C,CAGA,SAAS,EAAqB,EAA2B,CACvD,GAAI,EAAQ,GACV,MAAU,MAAM,kCAAkC,GAAO,EAE3D,GAAI,IAAU,GACZ,OAAO,IAAI,WAEb,IAAI,EAAM,EAAM,SAAS,EAAE,EAI3B,OAHI,EAAI,OAAS,GAAM,IACrB,EAAM,IAAM,GAEP,EAAW,CAAG,CACvB,CAQA,SAAS,EAAO,GAAG,EAAiC,CAClD,IAAM,EAAQ,EAAM,QAAQ,EAAK,IAAS,EAAM,EAAK,OAAQ,CAAC,EACxD,EAAM,IAAI,WAAW,CAAK,EAC5B,EAAS,EACb,IAAK,IAAM,KAAQ,EACjB,EAAI,IAAI,EAAM,CAAM,EACpB,GAAU,EAAK,OAEjB,OAAO,CACT,CAEA,SAAS,GAAgB,EAAgB,EAA4B,CACnE,GAAI,EAAS,GACX,OAAO,WAAW,GAAG,EAAS,CAAM,EAEtC,IAAM,EAAW,EAAqB,OAAO,CAAM,CAAC,EACpD,OAAO,EAAO,WAAW,GAAG,EAAS,GAAK,EAAS,MAAM,EAAG,CAAQ,CACtE,CAEA,SAAS,GAAU,EAA6B,CAC9C,GAAI,aAAiB,WAInB,OAHI,EAAM,SAAW,GAAK,EAAM,GAAM,IAC7B,EAEF,EAAO,GAAgB,EAAM,OAAQ,GAAI,EAAG,CAAK,EAG1D,IAAM,EAAU,EAAO,GADP,EAAM,IAAI,EACM,CAAC,EACjC,OAAO,EAAO,GAAgB,EAAQ,OAAQ,GAAI,EAAG,CAAO,CAC9D,CAYA,SAAgB,GAAoB,EAA4B,CAC9D,IAAM,EAAU,EAAW,CAAU,EACrC,GAAI,EAAQ,SAAW,GACrB,MAAU,MAAM,sDAAsD,EAAQ,QAAQ,EAKxF,MAAO,KAAO,EADD,EAFW,EAAU,aAAa,EAAS,EAElB,CAAC,CAAC,MAAM,CAAC,CACnB,CAAC,CAAC,MAAM,GAAG,CAAC,CAC1C,CAwBA,SAAgB,GACd,EACA,EACiC,CACjC,GAAI,CAAC,EAAG,GAAG,WAAW,IAAI,GAAK,EAAG,GAAG,SAAW,GAC9C,MAAU,MAAM,yBAAyB,EAAG,IAAI,EAGlD,IAAM,EAAuB,CAC3B,EAAqB,EAAG,KAAK,EAC7B,EAAqB,EAAG,QAAQ,EAChC,EAAqB,EAAG,QAAQ,EAChC,EAAW,EAAG,EAAE,EAChB,EAAqB,EAAG,KAAK,EAC7B,EAAW,EAAG,IAAI,CACpB,EAQM,EAAU,EANG,GAAU,CAC3B,GAAG,EACH,EAAqB,EAAG,OAAO,EAC/B,IAAI,WACJ,IAAI,UACN,CACoC,CAAC,EAE/B,EAAU,EAAW,CAAU,EAC/B,EAAW,EAAU,KAAK,EAAS,EAAS,CAChD,OAAQ,YACR,KAAM,GACN,QAAS,EACX,CAAC,EAEK,EAAa,EAAS,GACtB,EAAI,EAAW,EAAW,EAAS,SAAS,EAAG,EAAE,CAAC,CAAC,EACnD,EAAI,EAAW,EAAW,EAAS,SAAS,GAAI,EAAE,CAAC,CAAC,EACpD,EAAI,OAAO,CAAU,EAAI,IAAM,EAAG,QAAU,GAE5C,EAAY,GAAU,CAC1B,GAAG,EACH,EAAqB,CAAC,EACtB,EAAqB,CAAC,EACtB,EAAqB,CAAC,CACxB,CAAC,EAED,MAAO,CACL,MAAO,KAAO,EAAW,CAAS,EAClC,KAAM,KAAO,EAAW,EAAW,CAAS,CAAC,CAC/C,CACF,CAWA,eAAsB,GACpB,EACA,EACA,EACA,EAKiB,CACjB,IAAM,EAAO,GAAoB,CAAU,EACrC,CAAC,EAAY,EAAO,GAAY,MAAM,QAAQ,IAAI,CACtD,EAAmB,EAAQ,cAAe,CAAC,CAAC,EAC5C,GAA4B,EAAQ,EAAM,SAAS,EACnD,GAAoB,CAAM,CAC5B,CAAC,EAEK,CAAE,QAAO,QAAS,GACtB,CACE,QAHY,EAAW,CAGjB,EACN,QACA,SAAU,IAAa,GAAK,GAAK,EACjC,SAAU,EAAK,SACf,GAAI,EAAK,GACT,MAAO,EAAK,OAAS,GACrB,KAAM,EAAK,IACb,EACA,CACF,EACA,MAAM,EAAmB,EAAQ,yBAA0B,CAAC,CAAK,CAAC,EAClE,IAAM,EAAU,MAAM,GAAiB,EAAQ,EAAM,EAAQ,UAAW,EAAQ,MAAM,EACtF,GAAI,EAAQ,SAAW,MACrB,MAAU,MAAM,EAAQ,WAAW,CAAI,GAAK,eAAe,EAAK,oBAAoB,EAAQ,OAAO,GAAG,EAExG,OAAO,CACT,CCvTA,MAAM,GAAmB,sBAOnB,GAAiC,CACrC,2BACA,4BACA,2BACA,6BACA,qBACF,EAEM,GAAgC,IAEhC,GAA+B,IAErC,IAAI,EAAgC,GAChC,GACA,GAAmC,QAAQ,QAAQ,EAEvD,SAAS,IAA2B,CAClC,EAAgC,GAChC,GAAmC,IAAI,QAAe,GAAY,CAChE,GAAmC,CACrC,CAAC,CACH,CAEA,SAAS,GAA4B,CAC9B,IAIL,EAAgC,GAChC,KAAmC,EACnC,GAAmC,IAAA,GACrC,CAEA,SAAgB,IAAkC,CAChD,OAAO,CACT,CAEA,SAAgB,IAAqC,CACnD,OAAO,EACT,CAEA,SAAS,GAAM,EAAY,CACzB,OAAO,IAAI,QAAe,GAAY,WAAW,EAAS,CAAE,CAAC,CAC/D,CAmCA,eAAe,GAAmB,CAChC,SACA,sBACA,kBACA,gBAMgB,CAChB,IAAM,EAAO,cAEP,GAAY,IAAM,KAAO,GAC/B,GAAI,EAAe,IAAM,EAAe,EACtC,MAAU,MAAM,iBAAiB,EAAa,kCAAkC,EAAS,GAAG,EAG9F,GAAM,CACJ,EACA,EACA,EACA,EACA,GACE,MAAM,QAAQ,IAAI,CACpB,EAAoB,EAAQ,aAAa,EACzC,EAAoB,EAAQ,mBAAmB,EAC/C,EAAoB,EAAQ,0BAA0B,EACtD,EAAoB,EAAQ,4BAA4B,EACxD,EAAoB,EAAQ,qBAAqB,CACnD,CAAC,EAEK,EAAgB,SAKb,EAAW,MAJA,EAAmB,EAAQ,WAAY,CACvD,CAAE,GAAI,EAAqB,KAAM,CAAkB,EACnD,QACF,CAAC,CACoB,EAGjB,EAAe,MAAM,EAAc,EAEzC,GAAI,IAAiB,EACnB,OAGF,IAAM,EAAe,GAAoB,CAAe,EAElD,EAAc,MAAM,EAAmB,EAAQ,WAAY,CAC/D,CAAE,GAAI,EAAqB,KAAM,CAAwB,EACzD,QACF,CAAC,EACD,GAAI,CAAC,GAAe,IAAgB,KAClC,MAAU,MACR,sDAAsD,EAAoB,qCAC5E,EAEF,IAAM,EAAkB,GAAmB,CAAW,EAChD,EAAsB,GAAmB,CAAY,EAW3D,GAFqB,EAAW,MAPP,EAAmB,EAAQ,WAAY,CAC9D,CACE,GAAI,EACJ,KAAM,EAAkB,EAAkB,CAC5C,EACA,QACF,CAAC,CACyC,IAAM,GAE7B,CACjB,QAAQ,IACN,KAAK,EAAM,OAAO,GAAG,EAAE,IAAI,EAAM,KAC/B,CACF,EAAE,oDAAoD,EAAM,KAAK,CAAY,GAC/E,EACA,IAAM,EAAc,MAAM,GACxB,EACA,EACA,CACE,GAAI,EACJ,KAAM,EAAoB,EAAkB,EAC5C,SAAU,OAAO,EAA4B,CAC/C,EACA,CACE,UAAW,GACX,OAAQ,IACR,SAAW,GACT,6CAA6C,EAAa,iBAAiB,EAAK,+DAA+D,EAAoB,EACvK,CACF,EACA,QAAQ,IAAI,KAAK,EAAM,KAAK,iBAAiB,EAAY,EAAE,GAAG,CAChE,CAEA,QAAQ,IACN,KAAK,EAAM,OAAO,GAAG,EAAE,IAAI,EAAM,KAAK,CAAI,EAAE,6BAA6B,EAAM,KAC7E,OAAO,CAAY,CACrB,EAAE,KAAK,EAAM,KAAK,OAAO,CAAY,CAAC,EAAE,MAC1C,EAEA,IAAM,EAAS,MAAM,GACnB,EACA,EACA,CACE,GAAI,EACJ,KAAM,EAAmB,GAAgB,CAAY,EACrD,SAAU,OAAO,EAA4B,CAC/C,EACA,CACE,UAAW,GACX,OAAQ,IACR,SAAW,GACT,yBAAyB,EAAa,iBAAiB,EAAK,eAAe,EAAa,8CAA8C,EAAoB,EAC9J,CACF,EAEM,EAAW,MAAM,EAAc,EACrC,GAAI,IAAa,EACf,MAAU,MACR,yBAAyB,EAAa,kBAAkB,EAAO,kCAAkC,EAAS,EAC5G,EAGF,QAAQ,IACN,KAAK,EAAM,MAAM,GAAG,EAAE,IAAI,EAAM,KAAK,CAAI,EAAE,2BAA2B,EAAM,KAC1E,OAAO,CAAY,CACrB,EAAE,QAAQ,EAAM,KAAK,OAAO,EAAO,EAAE,GACvC,CACF,CAEA,SAAS,GAA+B,EAAoB,CAC1D,OAAW,MACT,CACE,oIACA,mGACA,yBACA,4BAA4B,IAC5B,kBACF,CAAC,CAAC,KAAK;CAAI,CACb,CACF,CAEA,eAAe,GAAoB,EAAgB,EAAqB,EAAoB,CAC1F,IAAM,EAAW,KAAK,IAAI,EAAI,IAC1B,EAAoC,KAExC,KAAO,KAAK,IAAI,EAAI,GAAU,CAC5B,GAAM,CAAC,EAAa,GAAS,MAAM,QAAQ,IAAI,CAC7C,GAAuB,CAAM,CAAC,CAAC,UAAY,IAAI,EAC/C,QAAQ,IAAI,EAAU,IAAK,GAAY,GAAgB,EAAQ,CAAO,CAAC,CAAC,UAAY,IAAI,CAAC,CAAC,CAC5F,CAAC,EAED,GAAI,GAAe,MAAQ,EAAM,MAAO,GAAS,GAAQ,IAAI,EAAG,CAK9D,GAJI,IAAuB,OACzB,EAAqB,GAGnB,EAAM,MAAO,GAAS,GAAuB,CAAI,CAAC,EACpD,OAOF,GAHE,GAAe,IACf,EAAc,GAAsB,EAGpC,MAAM,GAA+B,CAAU,CAEnD,CAEA,MAAM,GAAM,GAA2B,CACzC,CAEA,MAAU,MACR,4IAA4I,EAAW,qBACzJ,CACF,CAEA,eAAsB,GAAgB,EAAwD,CAC5F,IAAM,EAAU,EAAI,WACd,EAAO,EAAI,cAAc,KAAK,EAC9B,EAAO,qBACP,EAAa,4BACb,EAAW,EAAI,SAEf,EAAW,GAA2B,CAC1C,GAAI,EAAO,EAAM,CAAO,GAAK,CAAC,EAC9B,GAAG,CACL,CAAC,EACK,EAAsB,OAAO,EAAS,eAAe,EAE3D,GAAI,GAAa,MAAM,GAAmB,CAAI,EAE5C,OADA,EAAW,EAAM,OAAQ,OAAO,CAAmB,CAAC,EAC7C,KAGT,GAAyB,EACzB,MAAM,GAAc,EAAgB,EACpC,MAAM,EAAsB,CAAU,EAEtC,IAAI,EACA,EACA,EACE,EAAU,IAAI,SAAe,EAAK,IAAQ,CAC9C,EAAa,EACb,EAAgB,CAClB,CAAC,EACG,EAAwB,GACxB,EAAiB,GAEhB,EAAG,WAAW,EAAY,WAAW,CAAC,GACzC,EAAG,UAAU,EAAY,WAAW,EAAG,CAAE,UAAW,GAAM,KAAM,GAAM,CAAC,EAEpE,EAAG,WAAW,EAAY,YAAa,UAAU,CAAC,GACrD,EAAG,cAAc,EAAY,YAAa,UAAU,EAAG,WAAY,CACjE,SAAU,QACV,KAAM,GACR,CAAC,EAGH,IAAM,EAAM,GAA2B,CACrC,GAAI,EAAO,EAAM,CAAO,GAAK,CAAC,EAC9B,GAAG,CACL,CAAC,EACK,EAAS,CACb,GAAI,EAAO,cAAe,CAAO,GAAK,CAAC,EACvC,GAAG,CACL,EAEM,EAAiB,OAAO,EAAI,eAAe,EAC3C,EAAuB,GAA+B,IAAK,GAAQ,OAAO,EAAO,EAAI,CAAC,EAEtF,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,6CACX,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,YACA,GACA,KACA,GAAG,EAAe,GAAG,IACrB,KACA,GAAG,EAAiB,EAAE,GAAG,EAAiB,IAC1C,UACA,sBAAsB,EAAW,yBACjC,UACA,oBAAoB,GAAkB,WAAW,EAAE,oBACrD,EACA,WACA,IAAK,CACH,0BACA,YAAY,KACZ,kCACA,SACA,qBAAqB,KACrB,SACA,kDACA,sBACA,eAAe,IACf,sBACA,kBACA,OACA,gDACA,aAAa,EAAiB,IAC9B,iBACA,eACA,eAAe,EAAI,aACnB,qBACA,wBACF,CACF,CAAC,EAED,GAAI,CAAC,EAGH,OAFA,EAA0B,EAC1B,EAAW,EAAM,OAAQ,OAAO,CAAc,CAAC,EACxC,KAET,EAAI,UAAU,CAAI,EAElB,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EACpB,CAAC,GAAyB,wBAAwB,KAAK,CAAI,IAC7D,EAAwB,GACxB,GACE,oBAAoB,IACpB,EACA,CACF,CAAC,CACE,SAAW,CACV,EAAiB,GACjB,EAA0B,EAC1B,IAAa,CACf,CAAC,CAAC,CACD,MAAO,GAAmB,CACzB,EAAiB,GACjB,EAA0B,EAC1B,IAAM,EAAU,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,EACrE,EAAS,EAAM,CAAO,EACtB,GAAmB,CAAI,CAAC,CAAC,YAAc,CACrC,IAAgB,CAAK,CACvB,CAAC,CACH,CAAC,GAGD,aAAa,KAAK,CAAI,GACxB,EAAS,EAAM,CAAI,EACnB,IAAa,GAEb,EAAU,CAEd,EAoBA,OAlBA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAA0B,EAC1B,EAAS,EAAM,UAAY,EAAM,OAAO,EACxC,IAAa,CACf,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAA0B,EACrB,IACH,EAAS,EAAM,GAAW,8BAA8B,GAAM,EAC9D,IAAa,GAEf,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CAEA,eAAsB,GAAc,EAA4D,CAC9F,IAAM,EAAU,EAAI,WACd,EAAO,EAAI,cAAc,KAAK,EAC9B,EAAO,cAEP,EAAY,MAAM,GAAa,EAAK,CAAI,EAExC,EAAW,MAAM,GACrB,oBAAoB,EAAO,cAAe,CAAO,CAAC,EAAE,UAAY,QAClE,EAEM,CAAC,GAAe,MAAM,QAAQ,IAAI,CACtC,GAAa,EAAK,EAAM,EAAG,CAAQ,CAIrC,CAAC,EAED,GAAI,CACF,IAAM,EAAS,CAAE,GAAI,EAAO,cAAe,CAAO,GAAK,CAAC,EAAI,GAAG,CAAK,EAKpE,MAAM,GAAmB,CACvB,OAAQ,oBAAoB,CAJ5B,GAAI,EAAO,qBAAsB,CAAO,GAAK,CAAC,EAC9C,GAAG,CAGqC,EAAE,kBAC1C,oBAAqB,OAAO,EAAO,yBAAyB,EAC5D,gBAAiB,qEACjB,aAAc,OAAO,OAAO,EAAO,eAAiB,OAAO,CAAC,CAC9D,CAAC,CACH,OAAS,EAAO,CAEd,EAAS,EAAM,iCADC,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,GACZ,CAC3D,CAEA,MAAO,CAAC,EAAW,CAAW,CAChC,CAEA,eAAe,GACb,EACA,EACA,EACA,EAC8B,CAC9B,IAAM,EAAU,EAAI,WACd,EAAO,EAAI,cAAc,KAAK,EAC9B,EAAa,EAAS,sBAAsB,EAAO,SAAW,qBACpE,MAAM,EAAsB,CAAU,EAEtC,IAAI,EACA,EACE,EAAU,IAAI,QAAe,GAAQ,CACzC,EAAa,CACf,CAAC,EAEK,CAAE,QAAS,EACX,EAAM,GAA2B,CACrC,GAAI,EAAO,EAAM,CAAO,GAAK,CAAC,EAC9B,GAAG,CACL,CAAC,EAEI,GAIH,OAAO,EAAI,kBACX,EAAI,aAAe,IAJnB,OAAO,EAAI,aACX,EAAI,kBAAoB,SAMtB,IACF,EAAO,GAAG,EAAK,UAAU,KAG3B,IAAM,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,EACP,mCAAmC,IACnC,wCACJ,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,UACA,sBAAsB,EAAW,wBACjC,YACA,GACA,KACA,GAAG,EAAS,SAAS,EAAI,UAAY,MAAM,EAAI,EAAS,IAAQ,EAAI,SAAS,GAAG,EAAI,WACpF,KACA,GAAG,EAAS,SAAS,EAAI,cAAgB,MAAM,EAAI,EAAS,IAAQ,EAAI,aAAa,GAAG,EAAI,cAC9F,EACA,IAAK,CAAC,OAAO,EACb,SAAU,EAAI,QAChB,CAAC,EAED,GAAI,CAAC,EAAM,CACT,GAAI,CAAC,EAAQ,CACX,IAAM,EAAc,EAAQ,SAAW,EAAqB,KAAK,EAAI,IAAA,GACrE,EAAW,EAAM,EAAM,OAAO,EAAI,UAAY,MAAM,EAAG,CAAE,aAAY,CAAC,CACxE,CACA,OAAO,IACT,CACA,EAAI,UAAU,CAAI,EAElB,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EACxB,GAAI,2BAA2B,KAAK,CAAI,EAAG,CACzC,GAAI,CAAC,EAAQ,CACX,IAAM,EAAc,EAAQ,SAAW,EAAqB,KAAK,EAAI,IAAA,GACrE,EAAW,EAAM,EAAM,OAAO,EAAI,UAAY,MAAM,EAAG,CAAE,aAAY,CAAC,CACxE,CACA,IAAa,CACf,CAEA,IAAM,EAAuB,CAAC,sCAAsC,EAG9D,EADa,EAAK,MAAM;CAAI,CAAC,CAAC,OAAQ,GAAS,6BAA6B,KAAK,CAAI,CAChE,CAAC,CAAC,KAAK;CAAI,EAClC,GAAa,CAAC,EAAqB,KAAM,GAAU,EAAM,KAAK,CAAI,CAAC,IACrE,EAAS,EAAM,CAAS,EACxB,IAAa,EACb,EAAU,EAEd,EAgBA,OAdA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACxC,IAAa,CACf,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EAC9D,IAAa,EACb,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CCliBA,SAAgB,GACd,EACqB,CACrB,MAAO,CACL,SAAU,EAAQ,UAAY,GAC9B,WAAY,EAAQ,WACpB,cACE,EAAQ,gBAAyC,IAAW,CAAC,IAC/D,UAAW,EAAQ,gBAAoB,CAAC,GACxC,oBAAqB,EAAQ,0BAA8B,IAC3D,kBAAmB,EAAQ,yBAA6B,CAAC,IACzD,iBAAkB,EAAQ,wBAA4B,CAAC,GACzD,CACF,CC3DA,eAAsB,GAAa,EAAwD,CACzF,IAAM,EAAO,UACP,EAAiB,WAAW,EAAK,cACvC,MAAM,EAAsB,CAAc,EAE1C,IAAI,EACE,EAAU,IAAI,QAAe,GAAQ,CACzC,EAAa,CACf,CAAC,EAEK,EAAM,CACV,GAAI,EAAO,EAAM,EAAI,UAAU,GAAK,CAAC,EACrC,GAAG,EAAI,cAAc,SAAS,CAChC,EAEM,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,wBACX,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,UACA,sBAAsB,EAAe,uCACrC,YACA,OACA,eACF,EACA,IAAK,CAAC,EACN,SAAU,EAAI,QAChB,CAAC,EAED,GAAI,CAAC,EAEH,OADA,EAAW,EAAM,OAAQ,MAAM,EACxB,KAET,EAAI,UAAU,CAAI,EAElB,IAAM,EAAiB,GAAkB,CACvC,IAAM,EAAO,OAAO,CAAI,EACpB,yBAAyB,KAAK,CAAI,IACpC,EAAW,EAAM,OAAQ,MAAM,EAC/B,IAAa,EAEjB,EAgBA,OAdA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACxC,IAAa,CACf,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,8BAA8B,GAAM,EACnD,IAAa,EACb,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CC3DA,eAAsB,GAAW,EAAwD,CACvF,IAAM,EAAO,kBACP,EAAe,WAAW,EAAK,YAC/B,EAAqB,WAAW,EAAK,kBAC3C,MAAM,QAAQ,IAAI,CAChB,EAAsB,CAAY,EAClC,EAAsB,CAAkB,CAC1C,CAAC,EAED,IAAI,EACE,EAAU,IAAI,QAAe,GAAQ,CACzC,EAAa,CACf,CAAC,EAEK,EAAM,CACV,GAAI,EAAO,EAAM,EAAI,UAAU,GAAK,CAAC,EACrC,GAAG,EAAI,cAAc,OAAO,CAC9B,EAEM,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,eACX,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,UACA,sBAAsB,EAAa,kBACnC,UACA,sBAAsB,EAAmB,wBACzC,YACA,MACF,EACA,IAAK,CAAC,EACN,SAAU,EAAI,QAChB,CAAC,EAED,GAAI,CAAC,EAEH,OADA,EAAW,EAAM,UAAW,OAAO,EAC5B,KAET,EAAI,UAAU,CAAI,EAElB,IAAM,EAAiB,GAAkB,CACvC,IAAM,EAAO,OAAO,CAAI,EACpB,4BAA4B,KAAK,CAAI,IACvC,EAAW,EAAM,UAAW,OAAO,EACnC,IAAa,EAEjB,EAgBA,OAdA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACxC,IAAa,CACf,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,8BAA8B,GAAM,EACnD,IAAa,EACb,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CChEA,MAAa,GAAyB,2BACzB,GAAkC,mCAQzC,GAA+B,UAUrC,SAAgB,EAAc,EAAoD,CAChF,IAAM,EAAM,EAAM,YAAY,GAAG,EAIjC,OAHI,IAAQ,IAAM,EAAM,MAAM,EAAM,CAAC,CAAC,CAAC,SAAS,GAAG,EAC1C,CAAE,WAAY,EAAO,IAAK,QAAS,EAErC,CAAE,WAAY,EAAM,MAAM,EAAG,CAAG,EAAG,IAAK,EAAM,MAAM,EAAM,CAAC,CAAE,CACtE,CAGA,SAAgB,GAAyB,EAA6B,CACpE,GAAM,CAAE,OAAQ,EAAc,EAAsB,EAIpD,OAHK,EAGE,GAAG,GAA6B,YAAY,IAF1C,EAGX,CAEA,SAAgB,GAAiC,EAA6B,CAC5E,GAAM,CAAE,OAAQ,EAAc,EAA+B,EAI7D,OAHK,EAGE,GAAG,GAA6B,qBAAqB,IAFnD,EAGX,CAEA,eAAe,GAAuB,EAAmB,CACvD,IAAM,EAAO,EAAM,SAAU,CAAC,QAAS,UAAW,CAAS,CAAC,EAE5D,OAAO,MAAM,IAAI,QAAkB,GAAY,CAC7C,EAAK,GAAG,QAAU,GAAS,CACzB,EAAQ,IAAS,CAAC,CACpB,CAAC,EACD,EAAK,GAAG,YAAe,CACrB,EAAQ,EAAK,CACf,CAAC,CACH,CAAC,CACH,CAEA,eAAe,GAAiB,EAAiB,EAAgB,CAC/D,IAAM,EAAO,EAAM,EAAS,CAAI,EAEhC,MAAM,IAAI,SAAe,EAAS,IAAW,CAC3C,EAAK,GAAG,QAAU,GAAS,CACzB,GAAI,IAAS,EAAG,CACd,EAAQ,EACR,MACF,CAEA,EAAW,MAAM,mBAAmB,EAAQ,GAAG,EAAK,KAAK,GAAG,GAAG,CAAC,CAClE,CAAC,EACD,EAAK,GAAG,QAAS,CAAM,CACzB,CAAC,CACH,CAEA,SAAS,GAAkB,EAAgB,EAAa,CAEtD,OAAO,EAAY,EAAQ,GADX,EAAI,QAAQ,kBAAmB,GACX,EAAE,GAAG,KAAK,IAAI,GAAG,CACvD,CAEA,eAAe,GACb,EACA,EACA,EACA,CACA,IAAM,EAAgB,GAAkB,EAAiB,CAAM,EAC/D,EAAG,UAAU,EAAe,CAAE,UAAW,EAAK,CAAC,EAC/C,IAAM,EAAY,EAAK,KAAK,EAAe,OAAO,EAUlD,OATA,MAAM,GAAiB,MAAO,CAC5B,QACA,UACA,IACA,WACA,EACA,sBAAsB,EAAW,MACjC,CACF,CAAC,EACM,CACL,YAAa,EACb,YAAa,EACb,eAAgB,EAAK,KAAK,EAAW,YAAY,CACnD,CACF,CAKA,eAAsB,GAA4B,EAO/C,CACD,GAAM,CAAE,WAAU,YAAW,aAAY,kBAAiB,UAAW,EAErE,GAAI,MAAM,GAAuB,CAAS,EACxC,OAGF,QAAQ,IACN,KAAK,EAAM,OAAO,GAAG,EAAE,IAAI,EAAM,KAAK,CAAQ,EAAE,MAAM,EAAM,OAC1D,sCAAsC,EAAW,GAAG,EAAO,gCAC7D,GACF,EAEA,IAAM,EAAe,MAAM,GAA4B,EAAY,EAAiB,CAAM,EAEpF,EAAO,EAAM,SAAU,CAC3B,QACA,KACA,EACA,KACA,EAAa,eACb,EAAa,WACf,CAAC,EAED,GAAI,CACF,MAAM,IAAI,SAAe,EAAS,IAAW,CAC3C,EAAK,GAAG,QAAU,GAAS,CACzB,GAAI,IAAS,EAAG,CACd,EAAQ,EACR,MACF,CAEA,EAAW,MAAM,sCAAsC,GAAW,CAAC,CACrE,CAAC,EACD,EAAK,GAAG,QAAS,CAAM,CACzB,CAAC,CACH,OAAS,EAAO,CAQd,MAPA,EAAS,EAAU,iCAAiC,EAAU,GAAG,EAC7D,EAAa,YACL,MACR,sCAAsC,EAAU,6BAA6B,EAAa,cAC1F,CAAE,MAAO,CAAM,CACjB,EAEI,CACR,CAEA,QAAQ,IACN,KAAK,EAAM,OAAO,GAAG,EAAE,IAAI,EAAM,KAAK,CAAQ,EAAE,MAAM,EAAM,OAAO,iCAAiC,GACtG,EAEI,EAAa,aACf,EAAG,OAAO,EAAa,YAAa,CAAE,MAAO,GAAM,UAAW,EAAK,CAAC,CAExE,CAEA,SAAS,GAA2B,EAAuB,CACzD,IAAM,EAAU,GAAc,KAAK,EACnC,OAAO,GAAW,EAAQ,OAAS,EAAI,EAAU,MACnD,CAGA,eAAsB,GACpB,EACA,EACA,CAMA,MAAM,GAA4B,CAChC,SAAU,WACV,UAPgB,GAAyB,CAOjC,EACR,WAPiB,GAAA,wBAQjB,gBAAiB,kBACjB,OARa,EACX,GAA2B,CAAY,EACvC,EAAc,EAAsB,CAAC,CAAC,GAO1C,CAAC,CACH,CAGA,eAAsB,GACpB,EACA,EACA,CACK,GAML,MAAM,GAA4B,CAChC,SAAU,oBACV,UAJgB,GAAiC,CAIzC,EACR,WAAY,EACZ,gBAAiB,2BACjB,OANa,GAA2B,CAMnC,CACP,CAAC,CACH,CC5MA,MAAM,GAAwB,2BAE9B,eAAsB,GAA2B,CAC/C,UACA,OACA,QACA,cACA,WAAW,IASoB,CAC/B,IAAM,EAAO,WACP,EAAqB,mCAC3B,MAAM,EAAsB,CAAkB,EAE9C,IAAI,EACA,EACE,EAAU,IAAI,SAAe,EAAK,IAAQ,CAC9C,EAAa,EACb,EAAgB,CAClB,CAAC,EAEG,EACA,EAAQ,GACN,EAAM,CACV,GAAI,EAAO,gBAAiB,CAAO,GAAK,CAAC,EACzC,GAAG,CACL,EACM,EAAO,OAAO,EAAO,WAAY,CAAO,CAAC,EAAE,MAAQ,OAAO,EAC1D,EAAiB,IAAgB,OACjC,EAAa,EAAiB,EAAO,OAErC,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,EAAM,UACjB,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,UACA,sBAAsB,EAAmB,+BACzC,YACA,EACA,GAAI,EAAiB,CAAC,EAAI,CAAC,KAAM,GAAG,EAAK,MAAM,CACjD,EACA,GAAI,EACA,CACE,IAAK,CACH,OACA,KACA,qFAAqF,EAAK,yBAC5F,CACF,EACA,CAAC,EACL,UACF,CAAC,EAED,GAAI,CAAC,EAGH,OAFA,EAAW,EAAM,OAAQ,CAAI,EAC7B,IAAa,EACN,KAGT,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EAChB,OAAO,2BAA2B,IAAc,IAAI,CAAC,CAAC,KAAK,CAAI,GACrE,EAAQ,GACR,EAAW,EAAM,OAAQ,CAAI,EAC7B,IAAa,GAEb,EAAU,CAEd,EAoBA,OAlBA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACnC,GACH,IAAgB,CAAK,CAEzB,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EACzD,GACH,IAAoB,MAAM,8BAA8B,GAAM,CAAC,EAEjE,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CAEA,eAAsB,GAAkC,CACtD,UACA,OACA,cACA,YACA,WAAW,IAOoB,CAC/B,IAAM,EAAO,oBACT,EACA,EACE,EAAU,IAAI,SAAe,EAAK,IAAQ,CAC9C,EAAa,EACb,EAAgB,CAClB,CAAC,EAEG,EACA,EAAQ,GACN,EAAM,CACV,GAAI,EAAO,oBAAqB,CAAO,GAAK,CAAC,EAC7C,GAAG,CACL,EAEM,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,YACA,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,YACA,CACF,EACA,IAAK,CACH,OACA,KACA,+GACF,EACA,UACF,CAAC,EAED,GAAI,CAAC,EAEH,OADA,IAAa,EACN,KAGT,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EACpB,mCAAmC,KAAK,CAAI,GAC9C,EAAQ,GACR,IAAa,GAEb,EAAU,CAEd,EAoBA,OAlBA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACnC,GACH,IAAgB,CAAK,CAEzB,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EACzD,GACH,IAAoB,MAAM,8BAA8B,GAAM,CAAC,EAEjE,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CAEA,eAAsB,GACpB,EAAc,GACd,EAC8B,CAC9B,IAAM,EAAO,4BACP,EAAa,kCACnB,MAAM,EAAsB,CAAU,EAEtC,IAAI,EACA,EACE,EAAU,IAAI,SAAe,EAAK,IAAQ,CAC9C,EAAa,EACb,EAAgB,CAClB,CAAC,EAEG,EACA,EAAQ,GACN,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,iBACX,KAAM,CACJ,KACA,iCACA,KACA,qCACA,UACA,sBAAsB,EAAW,wBACjC,YACA,CACF,EACA,SAAU,EAAQ,GAAM,QAC1B,CAAC,EAED,GAAI,CAAC,EAEH,OADA,IAAa,EACN,KAGT,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EACpB,2BAA2B,KAAK,CAAI,GACtC,EAAQ,GACR,IAAa,GAEb,EAAU,CAEd,EAoBA,OAlBA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACnC,GACH,IAAgB,CAAK,CAEzB,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EACzD,GACH,IAAoB,MAAM,8BAA8B,GAAM,CAAC,EAEjE,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CAEA,eAAsB,GACpB,EAAc,GACd,EAC8B,CAC9B,IAAM,EAAO,0BACP,EAAa,gCACnB,MAAM,EAAsB,CAAU,EAEtC,IAAI,EACA,EACE,EAAU,IAAI,SAAe,EAAK,IAAQ,CAC9C,EAAa,EACb,EAAgB,CAClB,CAAC,EAEG,EACA,EAAQ,GACN,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,UAAW,UACX,KAAM,CAAC,UAAW,sBAAsB,EAAW,eAAgB,YAAa,CAAW,EAC3F,SAAU,EAAQ,GAAM,QAC1B,CAAC,EAED,GAAI,CAAC,EAEH,OADA,IAAa,EACN,KAGT,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EACpB,gCAAgC,KAAK,CAAI,GAC3C,EAAQ,GACR,IAAa,GAEb,EAAU,CAEd,EAoBA,OAlBA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACnC,GACH,IAAgB,CAAK,CAEzB,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EACzD,GACH,IAAoB,MAAM,8BAA8B,GAAM,CAAC,EAEjE,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CAEA,eAAsB,GAAoC,CACxD,UACA,OACA,cACA,YACA,WAAW,IAOoB,CAC/B,IAAM,EAAO,iBACT,EACA,EACE,EAAU,IAAI,SAAe,EAAK,IAAQ,CAC9C,EAAa,EACb,EAAgB,CAClB,CAAC,EAEG,EACA,EAAQ,GACN,EAAM,CACV,GAAI,EAAO,oBAAqB,CAAO,GAAK,CAAC,EAC7C,GAAG,EACH,aAAc,GAChB,EAEM,EAAO,MAAM,EAAqB,CACtC,cAAe,EACf,YACA,KAAM,CACJ,GAAG,OAAO,QAAQ,CAAG,CAAC,CAAC,SAAS,CAAC,EAAK,KAAW,CAAC,KAAM,GAAG,EAAI,GAAG,OAAO,CAAK,GAAG,CAAC,EAClF,YACA,CACF,EACA,IAAK,CAAC,OAAQ,KAAM,sEAAsE,EAC1F,UACF,CAAC,EAED,GAAI,CAAC,EAEH,OADA,IAAa,EACN,KAGT,IAAM,EAAiB,GAAkB,CACvC,EAAU,IAAA,GAEV,IAAM,EAAO,OAAO,CAAI,EACpB,aAAa,KAAK,CAAI,GACxB,EAAQ,GACR,IAAa,GAEb,EAAU,CAEd,EAoBA,OAlBA,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,QAAQ,GAAG,QAAU,GAAU,CAClC,EAAS,EAAM,UAAY,EAAM,OAAO,EACnC,GACH,IAAgB,CAAK,CAEzB,CAAC,EACD,EAAK,QAAQ,GAAG,OAAQ,CAAa,EACrC,EAAK,GAAG,QAAU,GAAS,CACzB,EAAS,EAAM,GAAW,8BAA8B,GAAM,EACzD,GACH,IAAoB,MAAM,8BAA8B,GAAM,CAAC,EAEjE,EAAK,KAAK,CACZ,CAAC,EAED,MAAM,EAEC,CACT,CAMA,eAAsB,GACpB,EACkC,CAClC,IAAM,EAAU,EAAI,WACd,EAAW,EAAI,SACf,EAAS,EAAI,kBAAkB,EAC/B,EAAgB,EAAI,iBAAiB,EACrC,EAAQ,CAAE,UAAW,GAAyB,EAAc,UAAU,CAAE,EACxE,EAAqB,EAAO,UAAU,YAAY,KAAK,GAAK,IAAA,GAC5D,EAAuB,EAAO,UAAU,cAAc,KAAK,GAAK,IAAA,GAEhE,EAAc,OACd,EAAmC,CAAC,EAE1C,GAAI,CACF,MAAM,GAA0B,EAAc,WAAY,EAAc,YAAY,EACpF,MAAM,GAAkC,EAAoB,CAAoB,EAEhF,IAAM,EAAoB,GAAiC,CAAkB,EAEvE,CAAC,EAAS,GAAS,MAAM,QAAQ,IAAI,CACzC,GAA8B,EAAa,CAAE,UAAS,CAAC,EACvD,GAA4B,EAAa,CAAE,UAAS,CAAC,CACvD,CAAC,EACD,EAAQ,KAAK,EAAS,CAAK,EAE3B,GAAM,CAAC,EAAa,GAAiB,MAAM,QAAQ,IAAI,CACrD,GAAkC,CAChC,UACA,KAAM,EAAO,UAAU,IACvB,cACA,UAAW,EACX,UACF,CAAC,EACD,GAAoC,CAClC,UACA,KAAM,EAAO,UAAU,IACvB,cACA,UAAW,EACX,UACF,CAAC,CACH,CAAC,EACD,EAAQ,KAAK,EAAa,CAAa,EAEvC,IAAM,EAAW,MAAM,GAA2B,CAChD,UACA,KAAM,EAAO,IACb,QACA,cACA,UACF,CAAC,EAKD,OAJA,EAAQ,KAAK,CAAQ,EAErB,EAAI,UAAU,GAAG,CAAO,EAEjB,CACT,OAAS,EAAO,CACd,IAAK,IAAM,KAAQ,EACjB,GAAM,KAAK,EAGb,MAAM,CACR,CACF,CC9ZA,SAAgB,GAAc,EAA+C,CAC3E,IAAM,EAAW,EAAQ,SACnB,EAAyB,CAAC,EAC5B,EAA2B,GACzB,EAAsC,CAAC,EACzC,EAAoB,GACpB,EAAqB,GAEnB,EAAkC,EAAQ,sCAA0C,IACpF,EACJ,EAAQ,yCAA6C,QAAQ,QAAQ,GACjE,EAA2B,EAAQ,+BAAmC,CAAC,GACvE,EAAmB,EAAQ,mBAAqB,SAAY,CAAC,GAC7D,EAAwB,EAAQ,wBAA0B,SAAY,CAAC,GACvE,EAAoB,EAAQ,oBAAsB,SAAY,CAAC,GAC/D,EAAc,EAAQ,cAAiB,GAAiB,QAAQ,KAAK,CAAI,GAEzE,MAAoB,EAEpB,GAAa,GAAG,IAA0B,CAC9C,EAAO,KAAK,GAAG,CAAK,CACtB,EAEM,MAAmB,CACvB,IAAK,IAAM,KAAQ,EACjB,EAAK,KAAK,CAEd,EAEM,EAA+B,GAAqB,CACxD,EAA2B,CAC7B,EAEM,EAAsB,MAAO,EAAc,IAAkB,CACjE,MAAM,EAAiB,EAAM,CAAI,EACjC,EAA0B,KAAK,CAAI,CACrC,EAEM,EAAkB,SAAY,CAC9B,IAGA,EAA0B,OAAS,IACrC,MAAM,EAAsB,CAAC,GAAG,CAAyB,CAAC,EAC1D,EAA0B,OAAS,GAEjC,GACF,MAAM,EAAkB,EAE1B,EAA2B,GAC7B,EAEM,EAAW,KAAO,IAA2B,CACjD,EAAoB,GACpB,IAAM,EAAQ,GAAM,OAAS,GAEzB,GAAsB,CAAC,IAG3B,EAAqB,GAEjB,CAAC,GAAS,EAAgC,IAC5C,EAAyB,EACzB,MAAM,EAAmC,GAGtC,GACH,MAAM,EAAQ,yBAAyB,EAAQ,eAAe,EAGhE,MAAM,EAAgB,GAEF,GAAM,mBAAqB,CAAC,IAE9C,EAAW,EAGT,GAAM,aACR,EAAY,CAAC,EAEjB,EAgBA,MAAO,CACL,wBAA2B,EAC3B,YACA,aACA,cACA,8BACA,sBACA,kBACA,WACA,0BAvBkC,CAClC,QAAQ,GAAG,aAAgB,CACzB,QAAQ,MAAM,OAAO,GACf,SAAY,CAChB,MAAM,EAAS,CAAE,YAAa,GAAM,MAAO,CAAkB,CAAC,CAChE,EAAA,CAAG,CACL,CAAC,EACD,QAAQ,GAAG,cAAiB,EACpB,SAAY,CAChB,MAAM,EAAS,CAAE,MAAO,CAAkB,CAAC,CAC7C,EAAA,CAAG,CACL,CAAC,CACH,CAYA,CACF,CCjHA,eAAsB,GAAK,EAAoE,CAC7F,IAAM,EAAQ,MAAM,QAAQ,CAAQ,EAAI,EAAW,CAAC,CAAQ,EAC5D,IAAK,IAAM,KAAQ,EACjB,GAAI,CAAC,GAAkB,SAAS,CAAI,EAClC,MAAU,UACR,4BAA4B,OAAO,CAAI,EAAE,qBAAqB,GAAkB,KAAK,IAAI,EAAE,EAC7F,EAGJ,MAAM,GAAoB,CAAK,CACjC,CAGA,SAAS,GAAqC,EAA4C,CACxF,OAAO,OAAO,GAAU,UAAY,EAC9B,EAAM,KAAO,CAAC,EACf,CAAC,CACR,CAGA,SAAS,GAAmB,EAAiD,CAI3E,OAHI,IAAU,GACL,CAAC,EAEH,OAAO,GAAU,UAAY,EAAiB,EAAQ,CAAC,CAChE,CAWA,eAAsB,GAAM,EAAwB,CAAC,EAAkC,CACrF,IAAM,EAAO,GAAiB,CAAO,EAErC,MAAM,GAAkB,EAExB,IAAM,EAAuB,GAAU,cAAgB,CAAC,EAAE,KAAK,EACzD,EAAU,EAAK,SAAW,GAA8B,EAAK,IAAI,CAAC,CAAC,QACnE,EAAqC,CACzC,KAAM,EAAK,KACX,SAAU,EAAK,SACf,UACA,GAAI,EAAK,UAAY,EACjB,CAAE,qBAAsB,EAA8B,CAAoB,CAAE,EAC5E,CAAC,CACP,EAEM,EAAU,GAAc,CAC5B,SAAU,EAAK,SACf,gBAAiB,EAAK,QACtB,yBAA0B,GAC1B,kBAAmB,EAAM,IAAS,GAAiB,EAA8B,CAAI,EACrF,sBAAwB,GAAU,GAAsB,CAA+B,EACvF,qBACA,mCACA,sCACA,6BAAgC,CAC9B,QAAQ,IACN,EAAM,OACJ,QAAQ,EAAM,KAAK,oBAAoB,EAAE,8HAC3C,CACF,CACF,CACF,CAAC,EAEG,EAAQ,wBAA0B,IACpC,EAAQ,sBAAsB,EAG5B,EAAK,UACP,MAAM,GAAc,EAAS,EAAY,CAAoB,EAG/D,IAAM,EAAY,EAAK,SAAW,GAAiB,CAAU,EAAI,IAAA,GAE3D,EAAuC,GAC3C,GAAkB,EAAQ,EAAI,EAE1B,EAAkB,GAA0B,CAChD,SAAU,EAAK,SACf,aACA,gBACA,WAAY,GAAG,IAAU,CACvB,EAAQ,UAAU,GAAG,EAAM,OAAQ,GAAyB,GAAK,IAAI,CAAC,CACxE,EACA,wBAA2B,EAAQ,oBAAoB,EACvD,sBAAyB,GAAmB,EAAQ,QAAQ,EAC5D,qBAAwB,CACtB,IAAM,EAAQ,GAAmB,EAAQ,QAAQ,CAAC,CAAC,MACnD,MAAO,CACL,WAAY,GAAO,YAAY,KAAK,GAAK,IAAA,GACzC,aAAc,GAAO,cAAc,KAAK,GAAK,IAAA,EAC/C,CACF,CACF,CAAC,EAEK,EAAa,KAAO,IAAiD,CACzE,GAAI,CAEF,OADA,MAAM,EAAG,EACF,CAAC,EAAQ,oBAAoB,CACtC,OAAS,EAAO,CACd,GAAI,EAAQ,oBAAoB,EAC9B,MAAO,GAET,MAAM,CACR,CACF,EAEM,EAAc,SAAY,CAC9B,IAAI,EAAY,EAAc,QAAQ,EACtC,GAAI,EAAK,QAAQ,SAAU,CACzB,IAAM,EAAS,MAAM,GAA+B,EAChD,IACF,EAAY,CAAE,GAAG,EAAW,2BAA4B,CAAO,EAEnE,CACA,MAAM,EACJ,EACA,iBACA,gCACA,CACF,CACF,EAEM,EAA6D,CACjE,qBAAwB,MAAiB,GAAgB,CAAe,CAAC,EACzE,gBAAmB,MAAiB,GAAc,CAAe,CAAC,EAClE,aAAgB,MAAiB,GAAmB,CAAe,CAAC,EACpE,UAAa,MAAiB,GAAW,CAAe,CAAC,EACzD,QACE,MACE,EACE,EACA,cACA,6BACA,EAAc,KAAK,CACrB,CACF,EACF,UACE,MACE,EACE,EACA,gBACA,+BACA,EAAc,OAAO,CACvB,CACF,EACF,YACE,MACE,EACE,EACA,kBACA,yBACA,EAAc,SAAS,CACzB,CACF,EACF,YACE,MACE,EACE,EACA,kBACA,iCACA,EAAc,SAAS,CACzB,CACF,EACF,WAAc,EAAW,CAAW,EACpC,YAAe,MAAiB,GAAa,CAAe,CAAC,CAC/D,EAIM,EAAyE,EAAK,SAChF,CACE,iBAAkB,SAAY,CAC5B,IAAM,EAAU,EAAO,cAAe,CAAU,GAAK,CAAC,EACtD,MAAM,EAAQ,oBACZ,MACA,CAAE,GAAG,EAAS,GAAG,EAAc,KAAK,CAAE,EAAE,UAAY,IACtD,CACF,EACA,SAAU,SAAY,CACpB,MAAM,EAAQ,oBAAoB,WAAY,EAAO,WAAY,CAAU,CAAC,CAAC,IAAI,CACnF,EACA,IAAK,SAAY,CACf,MAAM,EAAQ,oBACZ,MACA,EAA4B,OAAO,IAAY,cAAc,CAAC,eAAe,CAAC,CAChF,CACF,EACA,MAAO,SAAY,CACjB,MAAM,EAAQ,oBACZ,QACA,EAA4B,OAAO,IAAY,gBAAgB,CAAC,eAAe,CAAC,CAClF,CACF,EACA,QAAS,SAAY,CACnB,MAAM,EAAQ,oBACZ,UACA,EAA4B,OAAO,IAAY,kBAAkB,CAAC,eAAe,CAAC,CACpF,CACF,EACA,QAAS,SAAY,CACnB,MAAM,EAAQ,oBACZ,UACA,EAA4B,OAAO,IAAY,kBAAkB,CAAC,eAAe,CAAC,CACpF,CACF,EACA,OAAQ,SAAY,CAClB,MAAM,EAAQ,oBACZ,SACA,EAA4B,OAAO,IAAY,iBAAiB,CAAC,eAAe,CAAC,CACnF,CACF,CACF,EACA,CAAC,EA0BL,OAPI,MAHW,GAdD,OAAO,KAAK,EACgD,CAAC,CAAC,IAAK,GAAS,CACxF,IAAM,EAAO,GAAgB,GACvB,EAAgB,EAAoB,GAC1C,MAAO,CACL,OACA,aAAc,EAAK,aACnB,QAAS,EAAK,QAAQ,EAAK,SAC3B,UAAW,EAAK,UAChB,gBAAiB,EAAc,GAC/B,GAAI,EAAgB,CAAE,eAAc,EAAI,CAAC,CAC3C,CACF,CAEgD,EAAG,CAAE,UAAS,CACpC,CAAC,CAAC,MAAM,EAAA,CAEvB,YAAc,CAAC,EAAQ,oBAAoB,IAGpD,MAAM,GAAY,EAAK,OAAO,EAC9B,MAAM,EAAQ,SAAS,CAAE,kBAAmB,EAAK,CAAC,GAG7C,CAAE,SAAW,GAAS,EAAQ,SAAS,CAAI,CAAE,CACtD,CAGA,eAAe,GACb,EACA,EACA,EACe,CACT,MAAM,GAAuB,IACjC,QAAQ,MACN,EAAM,IACJ,oFACF,CACF,EACA,QAAQ,KAAK,CAAC,GAGhB,GAAI,CACF,GAAM,CAAE,eAAgB,MAAM,GAAoB,EAClD,EAAQ,4BAA4B,CAAW,CACjD,OAAS,EAAG,CACV,QAAQ,MACN,EAAM,IAAI,sCAAsC,aAAa,MAAQ,EAAE,QAAU,OAAO,CAAC,GAAG,CAC9F,EACA,QAAQ,KAAK,CAAC,CAChB,CAEA,GAAI,CAAC,EACH,GAAI,CACF,MAAM,EAAQ,oBAAoB,MAAO,EAAW,OAAO,CAC7D,OAAS,EAAG,CACV,QAAQ,MACN,EAAM,IACJ,2CAA2C,aAAa,MAAQ,EAAE,QAAU,OAAO,CAAC,GACtF,CACF,EACA,MAAM,EAAQ,gBAAgB,EAC9B,QAAQ,KAAK,CAAC,CAChB,CAGF,IAAM,EACJ,GAAwB,MAAQ,IAAyB,GACrD,GAAG,EAA8B,CAAoB,EAAE,GACvD,GAAG,EAAqB,KAAK,EAAE,GACrC,QAAQ,IAAI,EAAM,MAAM,QAAQ,EAAM,KAAK,gBAAgB,EAAE,MAAM,EAAM,KAAK,CAAM,GAAG,CAAC,CAC1F"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["styles","process","sleep","sleep","sleep"],"sources":["../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js","../../../node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js","../src/catalog.ts","../src/dependency-runner.ts","../src/consts.ts","../src/portless.ts","../src/env.ts","../src/resolve-options.ts","../src/utils.ts","../src/runtime/docker.ts","../src/runtime/names.ts","../src/ssl-trust.ts","../src/services/asp.ts","../src/web3.ts","../src/services/bee.ts","../src/services/context.ts","../src/services/elastic.ts","../src/services/mongo.ts","../src/builder.ts","../src/services/shkeeper.ts","../src/session.ts","../src/manager.ts"],"sourcesContent":["const ANSI_BACKGROUND_OFFSET = 10;\n\nconst wrapAnsi16 = (offset = 0) => code => `\\u001B[${code + offset}m`;\n\nconst wrapAnsi256 = (offset = 0) => code => `\\u001B[${38 + offset};5;${code}m`;\n\nconst wrapAnsi16m = (offset = 0) => (red, green, blue) => `\\u001B[${38 + offset};2;${red};${green};${blue}m`;\n\nconst styles = {\n\tmodifier: {\n\t\treset: [0, 0],\n\t\t// 21 isn't widely supported and 22 does the same thing\n\t\tbold: [1, 22],\n\t\tdim: [2, 22],\n\t\titalic: [3, 23],\n\t\tunderline: [4, 24],\n\t\toverline: [53, 55],\n\t\tinverse: [7, 27],\n\t\thidden: [8, 28],\n\t\tstrikethrough: [9, 29],\n\t},\n\tcolor: {\n\t\tblack: [30, 39],\n\t\tred: [31, 39],\n\t\tgreen: [32, 39],\n\t\tyellow: [33, 39],\n\t\tblue: [34, 39],\n\t\tmagenta: [35, 39],\n\t\tcyan: [36, 39],\n\t\twhite: [37, 39],\n\n\t\t// Bright color\n\t\tblackBright: [90, 39],\n\t\tgray: [90, 39], // Alias of `blackBright`\n\t\tgrey: [90, 39], // Alias of `blackBright`\n\t\tredBright: [91, 39],\n\t\tgreenBright: [92, 39],\n\t\tyellowBright: [93, 39],\n\t\tblueBright: [94, 39],\n\t\tmagentaBright: [95, 39],\n\t\tcyanBright: [96, 39],\n\t\twhiteBright: [97, 39],\n\t},\n\tbgColor: {\n\t\tbgBlack: [40, 49],\n\t\tbgRed: [41, 49],\n\t\tbgGreen: [42, 49],\n\t\tbgYellow: [43, 49],\n\t\tbgBlue: [44, 49],\n\t\tbgMagenta: [45, 49],\n\t\tbgCyan: [46, 49],\n\t\tbgWhite: [47, 49],\n\n\t\t// Bright color\n\t\tbgBlackBright: [100, 49],\n\t\tbgGray: [100, 49], // Alias of `bgBlackBright`\n\t\tbgGrey: [100, 49], // Alias of `bgBlackBright`\n\t\tbgRedBright: [101, 49],\n\t\tbgGreenBright: [102, 49],\n\t\tbgYellowBright: [103, 49],\n\t\tbgBlueBright: [104, 49],\n\t\tbgMagentaBright: [105, 49],\n\t\tbgCyanBright: [106, 49],\n\t\tbgWhiteBright: [107, 49],\n\t},\n};\n\nexport const modifierNames = Object.keys(styles.modifier);\nexport const foregroundColorNames = Object.keys(styles.color);\nexport const backgroundColorNames = Object.keys(styles.bgColor);\nexport const colorNames = [...foregroundColorNames, ...backgroundColorNames];\n\nfunction assembleStyles() {\n\tconst codes = new Map();\n\n\tfor (const [groupName, group] of Object.entries(styles)) {\n\t\tfor (const [styleName, style] of Object.entries(group)) {\n\t\t\tstyles[styleName] = {\n\t\t\t\topen: `\\u001B[${style[0]}m`,\n\t\t\t\tclose: `\\u001B[${style[1]}m`,\n\t\t\t};\n\n\t\t\tgroup[styleName] = styles[styleName];\n\n\t\t\tcodes.set(style[0], style[1]);\n\t\t}\n\n\t\tObject.defineProperty(styles, groupName, {\n\t\t\tvalue: group,\n\t\t\tenumerable: false,\n\t\t});\n\t}\n\n\tObject.defineProperty(styles, 'codes', {\n\t\tvalue: codes,\n\t\tenumerable: false,\n\t});\n\n\tstyles.color.close = '\\u001B[39m';\n\tstyles.bgColor.close = '\\u001B[49m';\n\n\tstyles.color.ansi = wrapAnsi16();\n\tstyles.color.ansi256 = wrapAnsi256();\n\tstyles.color.ansi16m = wrapAnsi16m();\n\tstyles.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);\n\tstyles.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);\n\n\t// From https://github.com/Qix-/color-convert/blob/3f0e0d4e92e235796ccb17f6e85c72094a651f49/conversions.js\n\tObject.defineProperties(styles, {\n\t\trgbToAnsi256: {\n\t\t\tvalue(red, green, blue) {\n\t\t\t\t// We use the extended greyscale palette here, with the exception of\n\t\t\t\t// black and white. normal palette only has 4 greyscale shades.\n\t\t\t\tif (red === green && green === blue) {\n\t\t\t\t\tif (red < 8) {\n\t\t\t\t\t\treturn 16;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (red > 248) {\n\t\t\t\t\t\treturn 231;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn Math.round(((red - 8) / 247) * 24) + 232;\n\t\t\t\t}\n\n\t\t\t\treturn 16\n\t\t\t\t\t+ (36 * Math.round(red / 255 * 5))\n\t\t\t\t\t+ (6 * Math.round(green / 255 * 5))\n\t\t\t\t\t+ Math.round(blue / 255 * 5);\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToRgb: {\n\t\t\tvalue(hex) {\n\t\t\t\tconst matches = /[a-f\\d]{6}|[a-f\\d]{3}/i.exec(hex.toString(16));\n\t\t\t\tif (!matches) {\n\t\t\t\t\treturn [0, 0, 0];\n\t\t\t\t}\n\n\t\t\t\tlet [colorString] = matches;\n\n\t\t\t\tif (colorString.length === 3) {\n\t\t\t\t\tcolorString = [...colorString].map(character => character + character).join('');\n\t\t\t\t}\n\n\t\t\t\tconst integer = Number.parseInt(colorString, 16);\n\n\t\t\t\treturn [\n\t\t\t\t\t/* eslint-disable no-bitwise */\n\t\t\t\t\t(integer >> 16) & 0xFF,\n\t\t\t\t\t(integer >> 8) & 0xFF,\n\t\t\t\t\tinteger & 0xFF,\n\t\t\t\t\t/* eslint-enable no-bitwise */\n\t\t\t\t];\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi256: {\n\t\t\tvalue: hex => styles.rgbToAnsi256(...styles.hexToRgb(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t\tansi256ToAnsi: {\n\t\t\tvalue(code) {\n\t\t\t\tif (code < 8) {\n\t\t\t\t\treturn 30 + code;\n\t\t\t\t}\n\n\t\t\t\tif (code < 16) {\n\t\t\t\t\treturn 90 + (code - 8);\n\t\t\t\t}\n\n\t\t\t\tlet red;\n\t\t\t\tlet green;\n\t\t\t\tlet blue;\n\n\t\t\t\tif (code >= 232) {\n\t\t\t\t\tred = (((code - 232) * 10) + 8) / 255;\n\t\t\t\t\tgreen = red;\n\t\t\t\t\tblue = red;\n\t\t\t\t} else {\n\t\t\t\t\tcode -= 16;\n\n\t\t\t\t\tconst remainder = code % 36;\n\n\t\t\t\t\tred = Math.floor(code / 36) / 5;\n\t\t\t\t\tgreen = Math.floor(remainder / 6) / 5;\n\t\t\t\t\tblue = (remainder % 6) / 5;\n\t\t\t\t}\n\n\t\t\t\tconst value = Math.max(red, green, blue) * 2;\n\n\t\t\t\tif (value === 0) {\n\t\t\t\t\treturn 30;\n\t\t\t\t}\n\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\tlet result = 30 + ((Math.round(blue) << 2) | (Math.round(green) << 1) | Math.round(red));\n\n\t\t\t\tif (value === 2) {\n\t\t\t\t\tresult += 60;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\tenumerable: false,\n\t\t},\n\t\trgbToAnsi: {\n\t\t\tvalue: (red, green, blue) => styles.ansi256ToAnsi(styles.rgbToAnsi256(red, green, blue)),\n\t\t\tenumerable: false,\n\t\t},\n\t\thexToAnsi: {\n\t\t\tvalue: hex => styles.ansi256ToAnsi(styles.hexToAnsi256(hex)),\n\t\t\tenumerable: false,\n\t\t},\n\t});\n\n\treturn styles;\n}\n\nconst ansiStyles = assembleStyles();\n\nexport default ansiStyles;\n","import process from 'node:process';\nimport os from 'node:os';\nimport tty from 'node:tty';\n\n// From: https://github.com/sindresorhus/has-flag/blob/main/index.js\n/// function hasFlag(flag, argv = globalThis.Deno?.args ?? process.argv) {\nfunction hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) {\n\tconst prefix = flag.startsWith('-') ? '' : (flag.length === 1 ? '-' : '--');\n\tconst position = argv.indexOf(prefix + flag);\n\tconst terminatorPosition = argv.indexOf('--');\n\treturn position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);\n}\n\nconst {env} = process;\n\nlet flagForceColor;\nif (\n\thasFlag('no-color')\n\t|| hasFlag('no-colors')\n\t|| hasFlag('color=false')\n\t|| hasFlag('color=never')\n) {\n\tflagForceColor = 0;\n} else if (\n\thasFlag('color')\n\t|| hasFlag('colors')\n\t|| hasFlag('color=true')\n\t|| hasFlag('color=always')\n) {\n\tflagForceColor = 1;\n}\n\nfunction envForceColor() {\n\tif ('FORCE_COLOR' in env) {\n\t\tif (env.FORCE_COLOR === 'true') {\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (env.FORCE_COLOR === 'false') {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn env.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env.FORCE_COLOR, 10), 3);\n\t}\n}\n\nfunction translateLevel(level) {\n\tif (level === 0) {\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tlevel,\n\t\thasBasic: true,\n\t\thas256: level >= 2,\n\t\thas16m: level >= 3,\n\t};\n}\n\nfunction _supportsColor(haveStream, {streamIsTTY, sniffFlags = true} = {}) {\n\tconst noFlagForceColor = envForceColor();\n\tif (noFlagForceColor !== undefined) {\n\t\tflagForceColor = noFlagForceColor;\n\t}\n\n\tconst forceColor = sniffFlags ? flagForceColor : noFlagForceColor;\n\n\tif (forceColor === 0) {\n\t\treturn 0;\n\t}\n\n\tif (sniffFlags) {\n\t\tif (hasFlag('color=16m')\n\t\t\t|| hasFlag('color=full')\n\t\t\t|| hasFlag('color=truecolor')) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (hasFlag('color=256')) {\n\t\t\treturn 2;\n\t\t}\n\t}\n\n\t// Check for Azure DevOps pipelines.\n\t// Has to be above the `!streamIsTTY` check.\n\tif ('TF_BUILD' in env && 'AGENT_NAME' in env) {\n\t\treturn 1;\n\t}\n\n\tif (haveStream && !streamIsTTY && forceColor === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst min = forceColor || 0;\n\n\tif (env.TERM === 'dumb') {\n\t\treturn min;\n\t}\n\n\tif (process.platform === 'win32') {\n\t\t// Windows 10 build 10586 is the first Windows release that supports 256 colors.\n\t\t// Windows 10 build 14931 is the first release that supports 16m/TrueColor.\n\t\tconst osRelease = os.release().split('.');\n\t\tif (\n\t\t\tNumber(osRelease[0]) >= 10\n\t\t\t&& Number(osRelease[2]) >= 10_586\n\t\t) {\n\t\t\treturn Number(osRelease[2]) >= 14_931 ? 3 : 2;\n\t\t}\n\n\t\treturn 1;\n\t}\n\n\tif ('CI' in env) {\n\t\tif (['GITHUB_ACTIONS', 'GITEA_ACTIONS', 'CIRCLECI'].some(key => key in env)) {\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (['TRAVIS', 'APPVEYOR', 'GITLAB_CI', 'BUILDKITE', 'DRONE'].some(sign => sign in env) || env.CI_NAME === 'codeship') {\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn min;\n\t}\n\n\tif ('TEAMCITY_VERSION' in env) {\n\t\treturn /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;\n\t}\n\n\tif (env.COLORTERM === 'truecolor') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-kitty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'xterm-ghostty') {\n\t\treturn 3;\n\t}\n\n\tif (env.TERM === 'wezterm') {\n\t\treturn 3;\n\t}\n\n\tif ('TERM_PROGRAM' in env) {\n\t\tconst version = Number.parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);\n\n\t\tswitch (env.TERM_PROGRAM) {\n\t\t\tcase 'iTerm.app': {\n\t\t\t\treturn version >= 3 ? 3 : 2;\n\t\t\t}\n\n\t\t\tcase 'Apple_Terminal': {\n\t\t\t\treturn 2;\n\t\t\t}\n\t\t\t// No default\n\t\t}\n\t}\n\n\tif (/-256(color)?$/i.test(env.TERM)) {\n\t\treturn 2;\n\t}\n\n\tif (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {\n\t\treturn 1;\n\t}\n\n\tif ('COLORTERM' in env) {\n\t\treturn 1;\n\t}\n\n\treturn min;\n}\n\nexport function createSupportsColor(stream, options = {}) {\n\tconst level = _supportsColor(stream, {\n\t\tstreamIsTTY: stream && stream.isTTY,\n\t\t...options,\n\t});\n\n\treturn translateLevel(level);\n}\n\nconst supportsColor = {\n\tstdout: createSupportsColor({isTTY: tty.isatty(1)}),\n\tstderr: createSupportsColor({isTTY: tty.isatty(2)}),\n};\n\nexport default supportsColor;\n","// TODO: When targeting Node.js 16, use `String.prototype.replaceAll`.\nexport function stringReplaceAll(string, substring, replacer) {\n\tlet index = string.indexOf(substring);\n\tif (index === -1) {\n\t\treturn string;\n\t}\n\n\tconst substringLength = substring.length;\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\treturnValue += string.slice(endIndex, index) + substring + replacer;\n\t\tendIndex = index + substringLength;\n\t\tindex = string.indexOf(substring, endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n\nexport function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {\n\tlet endIndex = 0;\n\tlet returnValue = '';\n\tdo {\n\t\tconst gotCR = string[index - 1] === '\\r';\n\t\treturnValue += string.slice(endIndex, (gotCR ? index - 1 : index)) + prefix + (gotCR ? '\\r\\n' : '\\n') + postfix;\n\t\tendIndex = index + 1;\n\t\tindex = string.indexOf('\\n', endIndex);\n\t} while (index !== -1);\n\n\treturnValue += string.slice(endIndex);\n\treturn returnValue;\n}\n","import ansiStyles from '#ansi-styles';\nimport supportsColor from '#supports-color';\nimport { // eslint-disable-line import/order\n\tstringReplaceAll,\n\tstringEncaseCRLFWithFirstIndex,\n} from './utilities.js';\n\nconst {stdout: stdoutColor, stderr: stderrColor} = supportsColor;\n\nconst GENERATOR = Symbol('GENERATOR');\nconst STYLER = Symbol('STYLER');\nconst IS_EMPTY = Symbol('IS_EMPTY');\n\n// `supportsColor.level` → `ansiStyles.color[name]` mapping\nconst levelMapping = [\n\t'ansi',\n\t'ansi',\n\t'ansi256',\n\t'ansi16m',\n];\n\nconst styles = Object.create(null);\n\nconst applyOptions = (object, options = {}) => {\n\tif (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) {\n\t\tthrow new Error('The `level` option should be an integer from 0 to 3');\n\t}\n\n\t// Detect level if not set manually\n\tconst colorLevel = stdoutColor ? stdoutColor.level : 0;\n\tobject.level = options.level === undefined ? colorLevel : options.level;\n};\n\nexport class Chalk {\n\tconstructor(options) {\n\t\t// eslint-disable-next-line no-constructor-return\n\t\treturn chalkFactory(options);\n\t}\n}\n\nconst chalkFactory = options => {\n\tconst chalk = (...strings) => strings.join(' ');\n\tapplyOptions(chalk, options);\n\n\tObject.setPrototypeOf(chalk, createChalk.prototype);\n\n\treturn chalk;\n};\n\nfunction createChalk(options) {\n\treturn chalkFactory(options);\n}\n\nObject.setPrototypeOf(createChalk.prototype, Function.prototype);\n\nfor (const [styleName, style] of Object.entries(ansiStyles)) {\n\tstyles[styleName] = {\n\t\tget() {\n\t\t\tconst builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);\n\t\t\tObject.defineProperty(this, styleName, {value: builder});\n\t\t\treturn builder;\n\t\t},\n\t};\n}\n\nstyles.visible = {\n\tget() {\n\t\tconst builder = createBuilder(this, this[STYLER], true);\n\t\tObject.defineProperty(this, 'visible', {value: builder});\n\t\treturn builder;\n\t},\n};\n\nconst getModelAnsi = (model, level, type, ...arguments_) => {\n\tif (model === 'rgb') {\n\t\tif (level === 'ansi16m') {\n\t\t\treturn ansiStyles[type].ansi16m(...arguments_);\n\t\t}\n\n\t\tif (level === 'ansi256') {\n\t\t\treturn ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));\n\t\t}\n\n\t\treturn ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));\n\t}\n\n\tif (model === 'hex') {\n\t\treturn getModelAnsi('rgb', level, type, ...ansiStyles.hexToRgb(...arguments_));\n\t}\n\n\treturn ansiStyles[type][model](...arguments_);\n};\n\nconst usedModels = ['rgb', 'hex', 'ansi256'];\n\nfor (const model of usedModels) {\n\tstyles[model] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'color', ...arguments_), ansiStyles.color.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n\n\tconst bgModel = 'bg' + model[0].toUpperCase() + model.slice(1);\n\tstyles[bgModel] = {\n\t\tget() {\n\t\t\tconst {level} = this;\n\t\t\treturn function (...arguments_) {\n\t\t\t\tconst styler = createStyler(getModelAnsi(model, levelMapping[level], 'bgColor', ...arguments_), ansiStyles.bgColor.close, this[STYLER]);\n\t\t\t\treturn createBuilder(this, styler, this[IS_EMPTY]);\n\t\t\t};\n\t\t},\n\t};\n}\n\nconst proto = Object.defineProperties(() => {}, {\n\t...styles,\n\tlevel: {\n\t\tenumerable: true,\n\t\tget() {\n\t\t\treturn this[GENERATOR].level;\n\t\t},\n\t\tset(level) {\n\t\t\tthis[GENERATOR].level = level;\n\t\t},\n\t},\n});\n\nconst createStyler = (open, close, parent) => {\n\tlet openAll;\n\tlet closeAll;\n\tif (parent === undefined) {\n\t\topenAll = open;\n\t\tcloseAll = close;\n\t} else {\n\t\topenAll = parent.openAll + open;\n\t\tcloseAll = close + parent.closeAll;\n\t}\n\n\treturn {\n\t\topen,\n\t\tclose,\n\t\topenAll,\n\t\tcloseAll,\n\t\tparent,\n\t};\n};\n\nconst createBuilder = (self, _styler, _isEmpty) => {\n\t// Single argument is hot path, implicit coercion is faster than anything\n\t// eslint-disable-next-line no-implicit-coercion\n\tconst builder = (...arguments_) => applyStyle(builder, (arguments_.length === 1) ? ('' + arguments_[0]) : arguments_.join(' '));\n\n\t// We alter the prototype because we must return a function, but there is\n\t// no way to create a function with a different prototype\n\tObject.setPrototypeOf(builder, proto);\n\n\tbuilder[GENERATOR] = self;\n\tbuilder[STYLER] = _styler;\n\tbuilder[IS_EMPTY] = _isEmpty;\n\n\treturn builder;\n};\n\nconst applyStyle = (self, string) => {\n\tif (self.level <= 0 || !string) {\n\t\treturn self[IS_EMPTY] ? '' : string;\n\t}\n\n\tlet styler = self[STYLER];\n\n\tif (styler === undefined) {\n\t\treturn string;\n\t}\n\n\tconst {openAll, closeAll} = styler;\n\tif (string.includes('\\u001B')) {\n\t\twhile (styler !== undefined) {\n\t\t\t// Replace any instances already present with a re-opening code\n\t\t\t// otherwise only the part of the string until said closing code\n\t\t\t// will be colored, and the rest will simply be 'plain'.\n\t\t\tstring = stringReplaceAll(string, styler.close, styler.open);\n\n\t\t\tstyler = styler.parent;\n\t\t}\n\t}\n\n\t// We can move both next actions out of loop, because remaining actions in loop won't have\n\t// any/visible effect on parts we add here. Close the styling before a linebreak and reopen\n\t// after next line to fix a bleed issue on macOS: https://github.com/chalk/chalk/pull/92\n\tconst lfIndex = string.indexOf('\\n');\n\tif (lfIndex !== -1) {\n\t\tstring = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);\n\t}\n\n\treturn openAll + string + closeAll;\n};\n\nObject.defineProperties(createChalk.prototype, styles);\n\nconst chalk = createChalk();\nexport const chalkStderr = createChalk({level: stderrColor ? stderrColor.level : 0});\n\nexport {\n\tmodifierNames,\n\tforegroundColorNames,\n\tbackgroundColorNames,\n\tcolorNames,\n\n\t// TODO: Remove these aliases in the next major version\n\tmodifierNames as modifiers,\n\tforegroundColorNames as foregroundColors,\n\tbackgroundColorNames as backgroundColors,\n\tcolorNames as colors,\n} from './vendor/ansi-styles/index.js';\n\nexport {\n\tstdoutColor as supportsColor,\n\tstderrColor as supportsColorStderr,\n};\n\nexport default chalk;\n","import type { EthernaServiceName } from \"./types\"\n\n/**\n * Canonical startup nodes, mirroring the dependency tree built by today's Vite plugin\n * (`etherna()` in `src/index.ts`). This is intentionally NOT the legacy CLI\n * `SERVICE_DEPENDENCIES` graph (e.g. CLI's `gateway` also depends on `beehive`; the Vite tree's\n * `gateway` only depends on `mongo` + `sso`). The Vite tree is canonical for `@etherna/docker`.\n */\nexport type StartupCode =\n | \"bee-blockchain\"\n | \"bee-nodes\"\n | \"shkeeper\"\n | \"mongo\"\n | \"sso\"\n | \"index\"\n | \"beehive\"\n | \"gateway\"\n | \"credit\"\n | \"elastic\"\n\nexport interface StartupNodeDefinition {\n code: StartupCode\n /** Logical service name this startup node belongs to (drives its default `enabled` flag). */\n service: EthernaServiceName\n dependencies: StartupCode[]\n onFailure: \"stop\"\n}\n\nexport const SERVICE_CATALOG: Record<StartupCode, StartupNodeDefinition> = {\n \"bee-blockchain\": {\n code: \"bee-blockchain\",\n service: \"bee\",\n dependencies: [],\n onFailure: \"stop\",\n },\n \"bee-nodes\": {\n code: \"bee-nodes\",\n service: \"bee\",\n dependencies: [\"bee-blockchain\"],\n onFailure: \"stop\",\n },\n shkeeper: {\n code: \"shkeeper\",\n service: \"shkeeper\",\n dependencies: [],\n onFailure: \"stop\",\n },\n mongo: {\n code: \"mongo\",\n service: \"mongo\",\n dependencies: [],\n onFailure: \"stop\",\n },\n sso: {\n code: \"sso\",\n service: \"sso\",\n dependencies: [\"mongo\"],\n onFailure: \"stop\",\n },\n index: {\n code: \"index\",\n service: \"index\",\n dependencies: [\"mongo\"],\n onFailure: \"stop\",\n },\n beehive: {\n code: \"beehive\",\n service: \"beehive\",\n dependencies: [\"mongo\"],\n onFailure: \"stop\",\n },\n gateway: {\n code: \"gateway\",\n service: \"gateway\",\n dependencies: [\"mongo\", \"sso\"],\n onFailure: \"stop\",\n },\n credit: {\n code: \"credit\",\n service: \"credit\",\n dependencies: [\"mongo\", \"sso\", \"shkeeper\"],\n onFailure: \"stop\",\n },\n elastic: {\n code: \"elastic\",\n service: \"elastic\",\n dependencies: [],\n onFailure: \"stop\",\n },\n}\n\n/** Every logical service name (including opt-in services). */\nexport const ALL_SERVICE_NAMES: readonly EthernaServiceName[] = [\n \"blockchain\",\n \"bee\",\n \"beehive\",\n \"credit\",\n \"elastic\",\n \"gateway\",\n \"index\",\n \"mongo\",\n \"shkeeper\",\n \"sso\",\n]\n\n/** Default `etherna start` / `etherna start all` expansion — shkeeper stays opt-in. */\nexport const DEFAULT_START_SERVICE_NAMES: readonly EthernaServiceName[] =\n ALL_SERVICE_NAMES.filter((name) => name !== \"shkeeper\")\n\n/** Startup codes directly implied by a logical service name, before dependency expansion. */\nfunction codesForServiceName(name: EthernaServiceName): StartupCode[] {\n switch (name) {\n case \"blockchain\":\n return [\"bee-blockchain\"]\n case \"bee\":\n return [\"bee-blockchain\", \"bee-nodes\"]\n default:\n return [name]\n }\n}\n\n/** Transitively expands a set of startup codes to include every code they (recursively) depend on. */\nfunction expandCodes(codes: Iterable<StartupCode>): Set<StartupCode> {\n const out = new Set<StartupCode>()\n\n function visit(code: StartupCode): void {\n if (out.has(code)) {\n return\n }\n out.add(code)\n for (const dep of SERVICE_CATALOG[code].dependencies) {\n visit(dep)\n }\n }\n\n for (const code of codes) {\n visit(code)\n }\n return out\n}\n\n/**\n * True when `service` is covered by `codes`. `bee` reflects the node group itself\n * (`bee-nodes`) — not merely its `bee-blockchain` dependency — so requesting `\"blockchain\"` alone\n * does not report `bee` as enabled, while requesting `\"bee\"` reports both `bee` and `blockchain`\n * (since `bee-nodes` depends on `bee-blockchain`).\n */\nfunction isServiceCoveredByCodes(service: EthernaServiceName, codes: Set<StartupCode>): boolean {\n if (service === \"bee\") {\n return codes.has(\"bee-nodes\")\n }\n if (service === \"blockchain\") {\n return codes.has(\"bee-blockchain\")\n }\n return codes.has(service)\n}\n\n/**\n * Expands requested logical service names into a full enabled map for every\n * {@link EthernaServiceName}, following the canonical Vite-plugin dependency graph\n * ({@link SERVICE_CATALOG}). Dependencies of a requested service are force-enabled even if not\n * explicitly requested (e.g. requesting `\"gateway\"` also enables `\"mongo\"` and `\"sso\"`).\n */\nexport function resolveEnabledFromServices(\n names: EthernaServiceName[],\n): Record<EthernaServiceName, boolean> {\n const requestedCodes = names.flatMap(codesForServiceName)\n const codes = expandCodes(requestedCodes)\n\n const enabled = {} as Record<EthernaServiceName, boolean>\n for (const service of ALL_SERVICE_NAMES) {\n enabled[service] = isServiceCoveredByCodes(service, codes)\n }\n return enabled\n}\n","export type DependencyFailureMode = \"stop\" | \"log\"\n\nexport interface DependencyRunnerServiceDefinition<TCode extends string = string> {\n code: TCode\n dependencies?: TCode[]\n /** When `false`, startup is skipped and dependents treat this node as satisfied. Defaults to `true`. */\n enabled?: boolean\n /** Runs after dependencies settle and before `startupCallback` (only when enabled). */\n beforeStartup?: () => void | Promise<void>\n /** Defaults to `\"stop\"`. */\n onFailure?: DependencyFailureMode\n startupCallback: () => Promise<boolean>\n}\n\nexport interface DependencyRunnerLogger {\n logError: (code: string, message: string) => void\n}\n\nexport type DependencyRunnerServiceStatus = \"started\" | \"failed\" | \"blocked\" | \"skipped\"\n\nexport interface DependencyRunnerServiceResult<TCode extends string = string> {\n code: TCode\n status: DependencyRunnerServiceStatus\n error?: Error\n blockedBy?: TCode[]\n}\n\nexport interface DependencyRunnerResult<TCode extends string = string> {\n shouldStop: boolean\n services: DependencyRunnerServiceResult<TCode>[]\n}\n\nexport class DependencyTreeValidationError extends Error {\n constructor(message: string) {\n super(message)\n this.name = \"DependencyTreeValidationError\"\n }\n}\n\nfunction normalizeError(reason: unknown): Error {\n if (reason instanceof Error) {\n return reason\n }\n return new Error(String(reason))\n}\n\nfunction blockedByFromDependencyResults<TCode extends string>(\n dependencyCodes: TCode[],\n depResults: DependencyRunnerServiceResult<TCode>[],\n): TCode[] {\n const out = new Set<TCode>()\n for (let i = 0; i < depResults.length; i++) {\n const r = depResults[i] as DependencyRunnerServiceResult<TCode>\n if (r.status === \"started\" || r.status === \"skipped\") {\n continue\n }\n if (r.status === \"failed\") {\n out.add(r.code)\n } else {\n const inherited = r.blockedBy\n if (inherited && inherited.length > 0) {\n for (const c of inherited) {\n out.add(c)\n }\n } else {\n out.add(dependencyCodes[i] as TCode)\n }\n }\n }\n return [...out]\n}\n\nexport function validateDependencyTree<TCode extends string>(\n services: DependencyRunnerServiceDefinition<TCode>[],\n): void {\n const codes = new Set<TCode>()\n for (const s of services) {\n if (codes.has(s.code)) {\n throw new DependencyTreeValidationError(`Duplicate service code \"${String(s.code)}\".`)\n }\n codes.add(s.code)\n }\n\n for (const s of services) {\n const deps = s.dependencies ?? []\n for (const d of deps) {\n if (d === s.code) {\n throw new DependencyTreeValidationError(\n `Service \"${String(s.code)}\" cannot depend on itself.`,\n )\n }\n if (!codes.has(d)) {\n throw new DependencyTreeValidationError(\n `Service \"${String(s.code)}\" depends on unknown service \"${String(d)}\".`,\n )\n }\n }\n }\n\n const visiting = new Set<TCode>()\n const visited = new Set<TCode>()\n const byCode = new Map(services.map((s) => [s.code, s] as const))\n\n function dfs(code: TCode): void {\n if (visited.has(code)) {\n return\n }\n if (visiting.has(code)) {\n throw new DependencyTreeValidationError(\n `Dependency cycle detected involving service \"${String(code)}\".`,\n )\n }\n visiting.add(code)\n const svc = byCode.get(code)\n if (!svc) {\n return\n }\n for (const d of svc.dependencies ?? []) {\n dfs(d)\n }\n visiting.delete(code)\n visited.add(code)\n }\n\n for (const s of services) {\n dfs(s.code)\n }\n}\n\n/** Runs a service startup dependency tree, resolving each node concurrently once its dependencies settle. */\nexport function createDependencyRunner<TCode extends string>(\n services: DependencyRunnerServiceDefinition<TCode>[],\n logger: DependencyRunnerLogger,\n): {\n start: () => Promise<DependencyRunnerResult<TCode>>\n} {\n validateDependencyTree(services)\n\n const byCode = new Map(services.map((s) => [s.code, s] as const))\n const pending = new Map<TCode, Promise<DependencyRunnerServiceResult<TCode>>>()\n\n function getTask(code: TCode): Promise<DependencyRunnerServiceResult<TCode>> {\n const existing = pending.get(code)\n if (existing) {\n return existing\n }\n\n const svc = byCode.get(code)\n\n if (!svc) {\n throw new DependencyTreeValidationError(`Unknown service code \"${String(code)}\".`)\n }\n\n const task = (async (): Promise<DependencyRunnerServiceResult<TCode>> => {\n const dependencyCodes = svc.dependencies ?? []\n const depResults = await Promise.all(dependencyCodes.map((d) => getTask(d)))\n\n const anyBad = depResults.some(\n (r) => r.status !== \"started\" && r.status !== \"skipped\",\n )\n if (anyBad) {\n return {\n code,\n status: \"blocked\",\n blockedBy: blockedByFromDependencyResults(dependencyCodes, depResults),\n }\n }\n\n if (svc.enabled === false) {\n return { code, status: \"skipped\" }\n }\n\n const mode: DependencyFailureMode = svc.onFailure ?? \"stop\"\n\n try {\n if (svc.beforeStartup) {\n await svc.beforeStartup()\n }\n const ok = await svc.startupCallback()\n if (!ok) {\n const err = new Error(\"Service startup returned false\")\n if (mode === \"log\") {\n logger.logError(String(code), err.message)\n }\n return { code, status: \"failed\", error: err }\n }\n return { code, status: \"started\" }\n } catch (reason: unknown) {\n const err = normalizeError(reason)\n if (mode === \"log\") {\n logger.logError(String(code), err.message)\n }\n return { code, status: \"failed\", error: err }\n }\n })()\n\n pending.set(code, task)\n return task\n }\n\n return {\n start: async () => {\n const serviceResults = await Promise.all(services.map((s) => getTask(s.code)))\n const shouldStop = serviceResults.some(\n (r) => r.status === \"failed\" && (byCode.get(r.code)?.onFailure ?? \"stop\") === \"stop\",\n )\n return { shouldStop, services: serviceResults }\n },\n }\n}\n","export const DEFAULT_CACHE_DIR = \"node_modules/.vite\"\n\nexport const CERTIFICATE_DIR = \".ssl\"\nexport const CERTIFICATE_CERT_NAME = \"etherna.crt\"\nexport const CERTIFICATE_KEY_NAME = \"etherna.key\"\nexport const CERTIFICATE_PFX_NAME = \"etherna.pfx\"\nexport const CERTIFICATE_PASSWORD = \"\"\n\nexport const CONTAINER_CERTS_DIR = \"/usr/local/share/ca-certificates\"\n","import { spawn } from \"node:child_process\"\n\n/** Alias names registered with `portless alias <name> <port>`. */\nexport type PortlessServiceAlias =\n | \"app\"\n | \"sso\"\n | \"index\"\n | \"credit\"\n | \"gateway\"\n | \"beehive\"\n | \"bee\"\n | \"shkeeper\"\n\nexport const PORTLESS_CONTAINER_ALIASES: Record<string, PortlessServiceAlias> = {\n \"etherna-sso\": \"sso\",\n \"etherna-index\": \"index\",\n \"etherna-credit\": \"credit\",\n \"etherna-gateway\": \"gateway\",\n \"etherna-beehive\": \"beehive\",\n}\n\nexport function getPortlessPublicUrl(alias: PortlessServiceAlias): string {\n return `http://${alias}.localhost`\n}\n\n/** Env name set by the Portless CLI when it wraps your dev process (public URL for the app). */\nexport const PORTLESS_URL_ENV = \"PORTLESS_URL\"\n\n/** Normalizes a base URL for OAuth/client env (trim, strip trailing slashes). */\nexport function normalizePortlessAppPublicUrl(url: string): string {\n return url.trim().replace(/\\/+$/, \"\")\n}\n\nexport function portlessProxyStartArgs(): string[] {\n return [\"proxy\", \"start\", \"--no-tls\", \"--unprivileged\"]\n}\n\n/** Env for every `portless` spawn. Unprivileged mode binds HTTP on port 80 without sudo. */\nexport function portlessCliEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEnv {\n return { ...env, PORTLESS_UNPRIVILEGED: \"1\" }\n}\n\nexport function portlessProxyStopArgs(): string[] {\n return [\"proxy\", \"stop\"]\n}\n\nexport function portlessAliasAddArgs(name: string, port: number, force = false): string[] {\n const args = [\"alias\", name, String(port)]\n if (force) {\n args.push(\"--force\")\n }\n return args\n}\n\nexport function portlessAliasRemoveArgs(name: string): string[] {\n return [\"alias\", \"--remove\", name]\n}\n\nexport async function runPortlessCli(args: string[]): Promise<{\n code: number\n stderr: string\n stdout: string\n}> {\n return new Promise((resolve, reject) => {\n const proc = spawn(\"portless\", args, {\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: portlessCliEnv(),\n })\n let stdout = \"\"\n let stderr = \"\"\n proc.stdout?.on(\"data\", (d) => {\n stdout += String(d)\n })\n proc.stderr?.on(\"data\", (d) => {\n stderr += String(d)\n })\n proc.on(\"error\", reject)\n proc.on(\"exit\", (code) => {\n resolve({ code: code ?? 1, stderr, stdout })\n })\n })\n}\n\n/** True when the `portless` CLI is on PATH and runs. */\nexport async function isPortlessCliAvailable(): Promise<boolean> {\n try {\n const r = await runPortlessCli([\"--version\"])\n return r.code === 0\n } catch {\n return false\n }\n}\n\n/**\n * Starts the Portless HTTP proxy in unprivileged mode (plain HTTP on port 80). If the proxy\n * is already running, returns `startedByUs: false` without failing.\n */\nexport async function ensurePortlessProxy(): Promise<{ startedByUs: boolean }> {\n const r = await runPortlessCli(portlessProxyStartArgs())\n if (r.code === 0) {\n return { startedByUs: true }\n }\n const combined = `${r.stderr}\\n${r.stdout}`\n if (/already|in use|running|listen/i.test(combined)) {\n return { startedByUs: false }\n }\n throw new Error(\n `portless proxy start failed (exit ${r.code}): ${combined.trim() || \"(no output)\"}`,\n )\n}\n\n/** Parses a port from env strings, URL fragments, or numbers for Portless CLI registration. */\nexport function parsePortlessPort(value: unknown): number {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value\n }\n const s = String(value).trim()\n if (s === \"\") {\n throw new Error(\"Port value is empty\")\n }\n const n = Number.parseInt(s, 10)\n if (!Number.isFinite(n)) {\n throw new Error(`Invalid port: ${String(value)}`)\n }\n return n\n}\n\n/** Registers a single alias with the Portless CLI (`portless alias <name> <port> --force`). */\nexport async function addPortlessAlias(name: PortlessServiceAlias, port: unknown): Promise<void> {\n const portNumber = parsePortlessPort(port)\n const r = await runPortlessCli(portlessAliasAddArgs(name, portNumber, true))\n if (r.code !== 0) {\n const combined = `${r.stderr}\\n${r.stdout}`\n throw new Error(`portless alias ${name} ${portNumber} failed: ${combined.trim()}`)\n }\n}\n\nexport async function removePortlessAliases(names: readonly PortlessServiceAlias[]): Promise<void> {\n for (const name of names) {\n await runPortlessCli(portlessAliasRemoveArgs(name))\n }\n}\n\nexport async function stopPortlessProxy(): Promise<void> {\n await runPortlessCli(portlessProxyStopArgs())\n}\n","import { CERTIFICATE_PASSWORD, CERTIFICATE_PFX_NAME, CONTAINER_CERTS_DIR } from \"./consts\"\nimport {\n getPortlessPublicUrl,\n normalizePortlessAppPublicUrl,\n type PortlessServiceAlias,\n} from \"./portless\"\n\nexport const APP_PORT = 5173\nconst APP_HTTPS_PORT = 5371\n\nconst MONGODB_PORT = 27017\nconst BEE_PORT = 1633\nconst BEE_P2P_PORT = 1634\nconst BLOCKCHAIN_PORT = 9545\nconst NETWORK_ID = 4020\n/**\n * Pre-funded Clique signer / etherbase from fdp-play's genesis. Unlocked by geth\n * at startup (see `startBlockchain` in services/bee.ts), so we can sign transactions\n * via `eth_sendTransaction` without managing a private key.\n */\nexport const BLOCKCHAIN_OWNER_ADDRESS = \"0xCEeE442a149784faa65C35e328CCd64d874F9a02\"\n\n/**\n * Default postage stamp price (PLUR per chunk per block). On fdp-play nobody runs\n * the price-updater bot, so the on-chain `lastPrice` stays at 0 and stamps never\n * expire. The plugin syncs this value into `PriceOracle` after Bee starts so\n * stamps actually burn down. Override via `bee: { env: { POSTAGE_PRICE: \"...\" } }`.\n */\nconst DEFAULT_POSTAGE_PRICE = \"24000\"\n\n/**\n * Private key of fdp-play's contract deployer, holder of `DEFAULT_ADMIN_ROLE`\n * on the `PostageStamp` contract (set by the constructor's\n * `_setupRole(DEFAULT_ADMIN_ROLE, msg.sender)`). The plugin uses it to grant\n * itself `PRICE_ORACLE_ROLE` and call `PostageStamp.setPrice` directly,\n * bypassing fdp-play's `PostagePriceOracle` (which is mis-wired to the BZZ\n * token because `deploy.ts` passes one extra constructor arg the Solidity\n * `PriceOracle(_postageStamp)` constructor silently ignores).\n *\n * It's NOT the unlocked Clique signer / etherbase: that account mines blocks\n * but never deployed any contract, so it has no admin role anywhere.\n *\n * Same key as fdp-play's `orchestrator/hardhat.config.ts` (publicly committed,\n * never used outside local dev). Used for client-side EIP-155 signing in\n * `web3.ts` because geth 1.13+ removed `personal_importRawKey` /\n * `personal_unlockAccount` from the HTTP API.\n */\nexport const POSTAGE_STAMP_ADMIN_PRIVATE_KEY =\n \"0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d\"\n\n/**\n * Bee env keys consumed only by the plugin (e.g. post-startup actions). They\n * must be stripped before forwarding to bee/blockchain containers as `-e`.\n */\nexport const BEE_PLUGIN_INTERNAL_ENV_KEYS = [\"POSTAGE_PRICE\"] as const\n\nconst SSO_HTTP_PORT = 32610\nconst SSO_HTTPS_PORT = 42610\n\nconst INDEX_HTTP_PORT = 32620\nconst INDEX_HTTPS_PORT = 42620\n\nconst CREDIT_HTTP_PORT = 32630\nconst CREDIT_HTTPS_PORT = 42630\n\nconst GATEWAY_HTTP_PORT = 32640\nconst GATEWAY_HTTPS_PORT = 42640\n\nconst BEEHIVE_HTTP_PORT = 12610\nconst SHKEEPER_HTTP_PORT = 32650\nconst ETHEREUM_SHKEEPER_PORT = 6000\n\n/**\n * Shared ShKeeper backend API key used by the shkeeper core, every coin-adapter\n * container (e.g. `ethereum-shkeeper`), and the `etherna-credit` client.\n * All of them must agree on the same value; upstream helm chart defaults it to `\"key\"`.\n */\nconst SHKEEPER_BACKEND_KEY = \"shkeeper\"\n\ntype UnionToIntersection<Union> = (\n Union extends unknown ? (distributedUnion: Union) => void : never\n) extends (mergedIntersection: infer Intersection) => void\n ? Intersection & Union\n : never\n\ntype StringEnvOverride<T extends Record<string, string | number>> = Partial<Record<keyof T, string>>\n\n/** Runtime context for building service envs (bind URLs vs public Portless URLs). */\nexport interface ServiceEnvBuildContext {\n mode: \"http\" | \"https\"\n portless: boolean\n /** Actual Vite dev server port (may differ from {@link APP_PORT}). */\n appPort: number\n /**\n * When set (e.g. `PORTLESS_URL` from the Portless CLI), used as the browser-facing dapp base URL\n * instead of `http://app.localhost`. The plugin skips registering the `app` Portless alias.\n */\n portlessAppPublicUrl?: string\n}\n\nexport function buildServiceEnvs(context: ServiceEnvBuildContext) {\n const { mode, portless, appPort, portlessAppPublicUrl } = context\n\n const ssoPort = mode === \"http\" ? SSO_HTTP_PORT : SSO_HTTPS_PORT\n const indexPort = mode === \"http\" ? INDEX_HTTP_PORT : INDEX_HTTPS_PORT\n const creditPort = mode === \"http\" ? CREDIT_HTTP_PORT : CREDIT_HTTPS_PORT\n const gatewayPort = mode === \"http\" ? GATEWAY_HTTP_PORT : GATEWAY_HTTPS_PORT\n const beehivePort = BEEHIVE_HTTP_PORT\n\n const mongodbUrl = `mongodb://localhost:${MONGODB_PORT}`\n const ssoBindUrl = bindUrl(mode, ssoPort)\n const indexBindUrl = bindUrl(mode, indexPort)\n const creditBindUrl = bindUrl(mode, creditPort)\n const gatewayBindUrl = bindUrl(mode, gatewayPort)\n const beehiveBindUrl = bindUrl(mode, beehivePort)\n /** Direct Bee API URL for container-to-container calls (always `localhost`; `*.localhost` Portless hosts often do not resolve inside Docker). */\n const beeApiBindUrl = `http://localhost:${BEE_PORT}`\n\n const appPublicUrl =\n portless && portlessAppPublicUrl\n ? normalizePortlessAppPublicUrl(portlessAppPublicUrl)\n : publicHttpUrl(mode, appPort, portless, \"app\")\n // const indexPublicUrl = publicHttpUrl(mode, indexPort, portless, \"index\")\n // const creditPublicUrl = publicHttpUrl(mode, creditPort, portless, \"credit\")\n // const gatewayPublicUrl = publicHttpUrl(mode, gatewayPort, portless, \"gateway\")\n\n const baseAspEnv = {\n ASPNETCORE_ENVIRONMENT: \"Development\",\n \"Elastic:Urls:0\": \"http://localhost:9200\",\n ...(mode === \"https\"\n ? {\n ASPNETCORE_Kestrel__Certificates__Default__Path: `${CONTAINER_CERTS_DIR}/${CERTIFICATE_PFX_NAME}`,\n ASPNETCORE_Kestrel__Certificates__Default__Password: CERTIFICATE_PASSWORD,\n }\n : {}),\n }\n\n const envs = {\n app: {\n port: appPort,\n },\n shkeeper: {\n port: SHKEEPER_HTTP_PORT,\n },\n \"shkeeper-core\": {\n DEV_MODE: \"1\",\n BTC_WALLET: \"disabled\",\n LTC_WALLET: \"disabled\",\n DOGE_WALLET: \"disabled\",\n ETH_WALLET: \"enabled\",\n ETH_USERNAME: \"shkeeper\",\n ETH_PASSWORD: \"shkeeper\",\n ETHEREUM_API_SERVER_HOST: \"localhost\",\n ETHEREUM_SERVER_PORT: String(ETHEREUM_SHKEEPER_PORT),\n SHKEEPER_BACKEND_KEY: SHKEEPER_BACKEND_KEY,\n SHKEEPER_BTC_BACKEND_KEY: SHKEEPER_BACKEND_KEY,\n },\n \"ethereum-shkeeper\": {\n FULLNODE_URL: `http://localhost:${BLOCKCHAIN_PORT}`,\n FULLNODE_TIMEOUT: \"60\",\n CURRENT_ETH_NETWORK: \"custom\",\n WEB3_ENABLE_POA_MIDDLEWARE: \"1\",\n BLOCK_SCANNER_MAX_CATCHUP_BLOCKS: \"64\",\n ETH_USERNAME: \"shkeeper\",\n ETH_PASSWORD: \"shkeeper\",\n SHKEEPER_BACKEND_KEY: SHKEEPER_BACKEND_KEY,\n SHKEEPER_HOST: `localhost:${SHKEEPER_HTTP_PORT}`,\n REDIS_HOST: \"localhost\",\n SQLALCHEMY_DATABASE_URI:\n \"mariadb+pymysql://root:shkeeper@localhost:3306/ethereum-shkeeper?charset=utf8mb4\",\n LAST_BLOCK_LOCKED: \"FALSE\",\n },\n elastic: {\n \"discovery.type\": \"single-node\",\n \"xpack.security.enabled\": \"false\",\n ES_JAVA_OPTS: \"-Xms512m -Xmx512m\",\n },\n \"etherna-mongodb\": {},\n \"etherna-sso\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: ssoBindUrl,\n /** Issuer/authority for discovery; keep bind URL so services and DNS inside containers resolve it. */\n \"IdServer:SsoServer:BaseUrl\": ssoBindUrl,\n \"IdServer:SsoServer:AllowUnsafeConnection\": \"true\",\n \"IdServer:Clients:EthernaCredit:BaseUrl\": creditBindUrl,\n \"IdServer:Clients:EthernaGateway:BaseUrls:0\": gatewayBindUrl,\n \"IdServer:Clients:EthernaIndex:BaseUrl\": indexBindUrl,\n \"IdServer:Clients:EthernaDapp:BaseUrl\": appPublicUrl,\n \"DbSeed:Clients:0:RedirectUris:0\": `${appPublicUrl}/callback`,\n \"DbSeed:Clients:0:PostLogoutRedirectUris:0\": appPublicUrl,\n \"DbSeed:Clients:0:AllowedCorsOrigins:0\": appPublicUrl,\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSSODataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaSSOHangfireDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n \"ConnectionStrings:SSOServerDb\": `${mongodbUrl}/ethernaSSODev`,\n },\n \"etherna-index\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: indexBindUrl,\n \"Swarm:GatewayUrl\": gatewayBindUrl,\n /** Server-side HTTP to SSO/Gateway must use bind URLs; `*.localhost` Portless names often fail in containers. */\n \"SsoServer:BaseUrl\": ssoBindUrl,\n \"SsoServer:AllowUnsafeConnection\": \"true\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSharedDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaIndexHangfireDev`,\n \"ConnectionStrings:IndexDb\": `${mongodbUrl}/ethernaIndexDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n },\n \"etherna-credit\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: creditBindUrl,\n \"SsoServer:BaseUrl\": ssoBindUrl,\n \"SsoServer:AllowUnsafeConnection\": \"true\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSharedDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaCreditHangfireDev`,\n \"ConnectionStrings:CreditDb\": `${mongodbUrl}/ethernaCreditDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n DisableHttpsRedirection: \"true\",\n \"Payments:ShKeeper:Url\": `http://localhost:${SHKEEPER_HTTP_PORT}`,\n \"Payments:ShKeeper:ApiKey\": SHKEEPER_BACKEND_KEY,\n \"Payments:ShKeeper:CustomCallbackBaseUrl\": creditBindUrl,\n },\n \"etherna-gateway\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: gatewayBindUrl,\n \"ForwardedHeaders:KnownNetworks:0\": \"0.0.0.0/0\",\n \"SsoServer:BaseUrl\": ssoBindUrl,\n \"SsoServer:Clients:Credit:BaseUrl\": creditBindUrl,\n \"SsoServer:Clients:Credit:Secret\": \"ethernaGatewayCreditClientSecret\",\n \"SsoServer:Clients:Webapp:Secret\": \"ethernaGatewayWebappClientSecret\",\n \"SsoServer:AllowUnsafeConnection\": \"true\",\n \"Bee:CachedUrl\": beehiveBindUrl,\n \"Bee:DirectUrl\": beehiveBindUrl,\n \"Features:GarbageCollectPins\": \"false\",\n ForwardedAllowedHosts: \"*\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/ethernaSharedDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/ethernaGatewayHangfireDev`,\n \"ConnectionStrings:GatewayDb\": `${mongodbUrl}/ethernaGatewayDev`,\n \"ConnectionStrings:ServiceSharedDb\": `${mongodbUrl}/ethernaServiceSharedDev`,\n },\n \"etherna-beehive\": {\n ...baseAspEnv,\n ASPNETCORE_URLS: beehiveBindUrl,\n \"SeedDb:BeeNodes:0:Hostname\": \"localhost\",\n \"ConnectionStrings:DataProtectionDb\": `${mongodbUrl}/beehiveDataProtectionDev`,\n \"ConnectionStrings:HangfireDb\": `${mongodbUrl}/beehiveHangfireDev`,\n \"ConnectionStrings:BeehiveDb\": `${mongodbUrl}/beehiveDev`,\n \"SeedDb:BeeNodes:0:ConnectionString\": beeApiBindUrl,\n \"SeedDb:BeeNodes:0:EnableBatchCreation\": \"true\",\n },\n \"etherna-blockchain\": {\n BLOCKCHAIN_PORT,\n NETWORK_ID,\n },\n \"etherna-bee\": {\n POSTAGE_PRICE: DEFAULT_POSTAGE_PRICE,\n BEE_WARMUP_TIME: \"10s\",\n BEE_DEBUG_API_ENABLE: \"true\",\n BEE_VERBOSITY: \"4\",\n BEE_SWAP_ENABLE: \"true\",\n BEE_MAINNET: \"false\",\n BEE_SWAP_ENDPOINT: `http://etherna-blockchain:${BLOCKCHAIN_PORT}`,\n BEE_BLOCKCHAIN_RPC_ENDPOINT: `http://etherna-blockchain:${BLOCKCHAIN_PORT}`,\n BEE_PASSWORD: \"password\",\n BEE_SWAP_FACTORY_ADDRESS: \"0xCfEB869F69431e42cdB54A4F4f105C19C080A601\",\n BEE_POSTAGE_STAMP_ADDRESS: \"0x254dffcd3277C0b1660F6d42EFbB754edaBAbC2B\",\n BEE_PRICE_ORACLE_ADDRESS: \"0x5b1869D9A4C187F2EAa108f3062412ecf0526b24\",\n BEE_REDISTRIBUTION_ADDRESS: \"0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7\",\n BEE_STAKING_ADDRESS: \"0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb\",\n BEE_POSTAGE_STAMP_START_BLOCK: \"1\",\n BEE_NETWORK_ID: NETWORK_ID,\n BEE_FULL_NODE: \"true\",\n BEE_PORT,\n BEE_P2P_PORT,\n BEE_API_ADDR: `0.0.0.0:${BEE_PORT}`,\n BEE_P2P_ADDR: `0.0.0.0:${BEE_P2P_PORT}`,\n BEE_CORS_ALLOWED_ORIGINS: \"*\",\n BEE_ALLOW_PRIVATE_CIDRS: \"true\",\n BEE_BOOTNODE_MODE: \"\",\n BEE_BOOTNODE: \"\",\n },\n } satisfies Record<string, Record<string, string | number>>\n\n return envs\n}\n\nexport function defaultServiceEnvBuildContext(mode: \"http\" | \"https\"): ServiceEnvBuildContext {\n return {\n mode,\n portless: false,\n appPort: mode === \"http\" ? APP_PORT : APP_HTTPS_PORT,\n }\n}\n\n/** Parses the listen port from `ASPNETCORE_URLS` (first URL if semicolon-separated). */\nexport function parsePortFromAspNetCoreUrls(bindUrls: string): string {\n const first = bindUrls.split(\";\")[0]?.trim() ?? \"\"\n try {\n const u = new URL(first)\n if (u.port) {\n return u.port\n }\n return u.protocol === \"https:\" ? \"443\" : \"80\"\n } catch {\n return first.split(\":\")[2] ?? \"80\"\n }\n}\n\nfunction bindUrl(mode: \"http\" | \"https\", port: number): string {\n return `${mode}://localhost:${port}`\n}\n\nfunction publicHttpUrl(\n mode: \"http\" | \"https\",\n port: number,\n portless: boolean,\n alias: PortlessServiceAlias,\n): string {\n if (portless) {\n return getPortlessPublicUrl(alias)\n }\n return bindUrl(mode, port)\n}\n\nexport const getEnv = <T extends string>(name: T, context: ServiceEnvBuildContext) => {\n const envs = buildServiceEnvs(context)\n type Env = typeof envs\n type AnyEnv = UnionToIntersection<Env[keyof Env]>\n type AnyEnvKey = keyof AnyEnv\n\n return ((envs as Record<string, unknown>)[name] ?? null) as T extends keyof Env\n ? Env[T]\n : Partial<Record<AnyEnvKey, string>> | null\n}\n\n/** Returns a copy of `env` with {@link BEE_PLUGIN_INTERNAL_ENV_KEYS} removed. */\nexport function stripPluginInternalEnvKeys<T extends Record<string, unknown>>(env: T): T {\n const internal = new Set<string>(BEE_PLUGIN_INTERNAL_ENV_KEYS)\n return Object.fromEntries(Object.entries(env).filter(([key]) => !internal.has(key))) as T\n}\n\nexport type BuiltServiceEnvs = ReturnType<typeof buildServiceEnvs>\n\nexport type ElasticEnv = StringEnvOverride<BuiltServiceEnvs[\"elastic\"]>\nexport type MongoEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-mongodb\"]>\nexport type BeeEnv = StringEnvOverride<\n BuiltServiceEnvs[\"etherna-blockchain\"] & BuiltServiceEnvs[\"etherna-bee\"]\n>\nexport type SsoEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-sso\"]>\nexport type IndexEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-index\"]>\nexport type GatewayEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-gateway\"]>\nexport type CreditEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-credit\"]>\nexport type BeehiveEnv = StringEnvOverride<BuiltServiceEnvs[\"etherna-beehive\"]>\nexport type ShkeeperEnv = StringEnvOverride<BuiltServiceEnvs[\"shkeeper-core\"]>\nexport type ShkeeperEthereumEnv = StringEnvOverride<BuiltServiceEnvs[\"ethereum-shkeeper\"]>\n\n/** Union of env overrides accepted by ASP.NET Etherna containers (SSO, Index, Gateway, Credit, Beehive). */\nexport type AspServiceEnv = SsoEnv | IndexEnv | GatewayEnv | CreditEnv | BeehiveEnv\n","import type { EthernaServiceName, ServiceConfig, StartOptions } from \"./types\"\n\nexport const ETHERNA_DETACHED_ENV = \"ETHERNA_DETACHED\"\n\n/**\n * Resolves detached mode: explicit `options.detached` wins, then `ETHERNA_DETACHED` env, then `false`.\n * Env is truthy for `1`, `true`, `yes` (case-insensitive); falsy for `0`, `false`, `no`, or unset.\n * Ported from `src/plugin-define.ts`.\n */\nexport function resolveDetachedMode(options: Pick<StartOptions, \"detached\">): boolean {\n if (typeof options.detached === \"boolean\") {\n return options.detached\n }\n const raw = process.env[ETHERNA_DETACHED_ENV]?.trim().toLowerCase()\n return raw === \"1\" || raw === \"true\" || raw === \"yes\"\n}\n\n/** `StartOptions` keys that toggle a logical service on/off (excludes `blockchain`, which has no independent toggle). */\ntype ConfigurableServiceName = Extract<EthernaServiceName, keyof StartOptions>\n\nconst CONFIGURABLE_SERVICE_NAMES: readonly ConfigurableServiceName[] = [\n \"elastic\",\n \"mongo\",\n \"bee\",\n \"sso\",\n \"index\",\n \"gateway\",\n \"credit\",\n \"beehive\",\n \"shkeeper\",\n]\n\n/**\n * Mirrors `harnessEthernaPlugin`'s `isServiceEnabled` from `src/plugin-define.ts`: a service is\n * enabled unless explicitly set to `false` (as a boolean or via `{ enabled: false }`).\n */\nfunction isServiceOptionEnabled(value: boolean | ServiceConfig<unknown> | undefined): boolean {\n if (typeof value === \"object\" && value !== null) {\n return value.enabled !== false\n }\n return value !== false\n}\n\n/**\n * Mirrors `harnessEthernaPlugin`'s `isShkeeperEnabled` from `src/plugin-define.ts`: shkeeper is\n * opt-in — enabled only when set to `true` or a config object (unless `{ enabled: false }`).\n */\nfunction isShkeeperOptionEnabled(value: boolean | ServiceConfig<unknown> | undefined): boolean {\n if (value === true) {\n return true\n }\n return typeof value === \"object\" && value !== null ? value.enabled !== false : false\n}\n\nexport interface StartPlan {\n /**\n * Per-service enabled flags, one per {@link EthernaServiceName}. Reflects only the caller's\n * options and their defaults — dependency expansion (e.g. enabling `gateway` implying `mongo`\n * and `sso`) is `resolveEnabledFromServices`'s responsibility and is applied by the startup\n * orchestrator, not here.\n */\n enabled: Record<EthernaServiceName, boolean>\n detached: boolean\n portless: boolean\n appPort?: number\n mode: \"http\" | \"https\"\n installSignalHandlers: boolean\n}\n\n/** Resolves a `StartOptions` object into a plan describing which services to run and how. */\nexport function resolveStartPlan(options: StartOptions): StartPlan {\n const enabled = {} as Record<EthernaServiceName, boolean>\n for (const service of CONFIGURABLE_SERVICE_NAMES) {\n enabled[service] =\n service === \"shkeeper\"\n ? isShkeeperOptionEnabled(options[service])\n : isServiceOptionEnabled(options[service])\n }\n // `blockchain` has no independent StartOptions toggle; it always mirrors `bee`.\n enabled.blockchain = enabled.bee\n\n const plan: StartPlan = {\n enabled,\n detached: resolveDetachedMode(options),\n portless: options.portless ?? false,\n mode: options.mode ?? \"http\",\n installSignalHandlers: options.installSignalHandlers ?? true,\n }\n if (options.appPort !== undefined) {\n plan.appPort = options.appPort\n }\n return plan\n}\n","import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport chalk from \"chalk\"\n\nimport { DEFAULT_CACHE_DIR } from \"./consts\"\n\nimport type { SpawnOptionsWithoutStdio } from \"node:child_process\"\n\n/** ShKeeper core container name (see `startShkeeperCoreContainer` in services/shkeeper.ts). */\nconst SHKEEPER_CORE_CONTAINER_NAME = \"shkeeper\"\n\n/** SQLite DB path inside the ShKeeper core container. */\nconst SHKEEPER_INSTANCE_SQLITE_PATH = \"/shkeeper.io/instance/shkeeper.sqlite\"\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\nexport interface FetchFirstShkeeperWalletApiKeyOptions {\n /** Docker container running ShKeeper core (default: `shkeeper`). */\n containerName?: string\n /** Path to `shkeeper.sqlite` inside that container. */\n sqlitePath?: string\n /** Max polling attempts when the DB or row is not ready yet (default: 120). */\n maxAttempts?: number\n /** Delay between attempts in ms (default: 1000). */\n intervalMs?: number\n}\n\n/**\n * Reads the first non-empty `apikey` from ShKeeper's instance SQLite (`wallet` table).\n * Uses `docker exec` + `sqlite3` in the running core container — no extra npm deps.\n * Polls until a row exists or attempts are exhausted (ShKeeper may populate the DB after startup).\n */\nexport async function fetchFirstShkeeperWalletApiKey(\n options?: FetchFirstShkeeperWalletApiKeyOptions,\n): Promise<string | null> {\n const containerName = options?.containerName ?? SHKEEPER_CORE_CONTAINER_NAME\n const sqlitePath = options?.sqlitePath ?? SHKEEPER_INSTANCE_SQLITE_PATH\n const maxAttempts = options?.maxAttempts ?? 120\n const intervalMs = options?.intervalMs ?? 1000\n\n const sql =\n \"SELECT apikey FROM wallet WHERE apikey IS NOT NULL AND TRIM(COALESCE(apikey, '')) != '' LIMIT 1\"\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n const value = await runDockerSqliteScalar(containerName, sqlitePath, sql)\n if (value) {\n return value\n }\n if (attempt < maxAttempts - 1) {\n await sleep(intervalMs)\n }\n }\n\n return null\n}\n\nfunction runDockerSqliteScalar(\n containerName: string,\n sqlitePath: string,\n sql: string,\n): Promise<string | null> {\n return new Promise((resolve) => {\n const proc = spawn(\"docker\", [\"exec\", containerName, \"sqlite3\", sqlitePath, sql])\n\n let stdout = \"\"\n proc.stdout?.on(\"data\", (chunk: Buffer | string) => {\n stdout += typeof chunk === \"string\" ? chunk : chunk.toString(\"utf8\")\n })\n proc.on(\"error\", () => {\n resolve(null)\n })\n proc.on(\"close\", (code: number | null) => {\n if (code !== 0) {\n resolve(null)\n return\n }\n const trimmed = stdout.trim()\n resolve(trimmed.length > 0 ? trimmed : null)\n })\n })\n}\n\n/**\n * Reads an env variable from both `process.env` and `import.meta.env`.\n *\n * `process.env` takes precedence (shell-set vars and CI environments win over\n * Vite's `.env` files). The `etherna` plugin's `config` hook already merges\n * `.env` values into `process.env` via Vite's `loadEnv`, so the\n * `import.meta.env` branch is mainly a safety net for callers that import\n * helpers from this package outside of the plugin's lifecycle.\n */\nexport function getEnvVar(key: string): string | undefined {\n const fromProcess = typeof process !== \"undefined\" ? process.env?.[key] : undefined\n if (fromProcess !== undefined) {\n return fromProcess\n }\n\n try {\n const meta = (import.meta as ImportMeta & { env?: Record<string, unknown> }).env\n const value = meta?.[key]\n return typeof value === \"string\" ? value : undefined\n } catch {\n return undefined\n }\n}\n\nexport function resolvePath(...paths: string[]) {\n return path.resolve(DEFAULT_CACHE_DIR, ...paths)\n}\n\nexport function resolvePathEscape(...paths: string[]) {\n const resolved = resolvePath(...paths)\n if (process.platform === \"win32\") {\n return resolved.replace(/\\\\/g, \"/\")\n }\n return resolved\n}\n\nexport function logSuccess(\n containerName: string,\n protocol: string,\n port: string,\n options?: { portlessUrl?: string },\n) {\n if (options?.portlessUrl) {\n const friendly = `${options.portlessUrl.replace(/\\/$/, \"\")}/`\n const raw = `${protocol}://localhost:${port}/`\n console.log(\n ` ${chalk.green(\"➜\")} ${chalk.bold(containerName)}: ${chalk.cyan(friendly)} ${chalk.gray(`(${raw})`)}`,\n )\n return\n }\n const url = `${protocol}://localhost:${chalk.bold.cyanBright(port)}/`\n console.log(` ${chalk.green(\"➜\")} ${chalk.bold(containerName)}: ${chalk.cyan(url)}`)\n}\n\nexport function logLoading(containerName: string) {\n console.log(\n ` ${chalk.gray(\"➜\")} ${chalk.bold(containerName)}: ${chalk.yellow(\"Downloading image...\")}`,\n )\n}\n\nexport function logError(containerName: string, reason: string) {\n console.log(` ${chalk.red(\"x\")} ${chalk.bold(containerName)}: ${chalk.red(reason)}`)\n}\n\nexport async function runCommand(cmd: string, args?: string[], options?: SpawnOptionsWithoutStdio) {\n const proc = spawn(cmd, args, options)\n\n return new Promise<void>((res, rej) => {\n proc.on(\"error\", (err) => {\n rej(err)\n })\n proc.on(\"exit\", () => {\n res()\n })\n })\n}\n\nexport async function getBeeUnderlayAddress(url: string) {\n const resp = await fetch(`${url}/addresses`)\n if (!resp.ok) {\n throw new Error(`Failed to fetch addresses from ${url}: ${resp.statusText}`)\n }\n const data = (await resp.json()) as {\n underlay: string[] | undefined\n }\n const underlay = Array.isArray(data.underlay) ? data.underlay : []\n\n if (underlay.length === 0) {\n await new Promise((resolve) => setTimeout(resolve, 500))\n return getBeeUnderlayAddress(url)\n }\n\n const address = underlay.find((url) => !url.includes(\"127.0.0.1\"))\n\n if (!address) {\n throw new Error(`No valid underlay address found in response from ${url}`)\n }\n return address\n}\n","import { spawn } from \"node:child_process\"\nimport fs from \"node:fs\"\nimport chalk from \"chalk\"\n\nimport { logError, logLoading } from \"../utils\"\n\nimport type { ChildProcess } from \"node:child_process\"\n\nconst ETHERNA_CONTAINER_PREFIX = \"etherna-\"\n\n/** Prefixes `name` with `etherna-` unless it already carries the prefix. */\nexport function resolveEthernaContainerName(name: string): string {\n return name.startsWith(ETHERNA_CONTAINER_PREFIX) ? name : `${ETHERNA_CONTAINER_PREFIX}${name}`\n}\n\nconst DOCKER_GET_STARTED_URL = \"https://docs.docker.com/get-docker/\"\nconst DOCKER_DAEMON_WAIT_MS = 30_000\nconst DOCKER_DAEMON_POLL_MS = 2_000\n\nfunction spawnDetached(command: string, args: string[]) {\n const proc = spawn(command, args, { detached: true, stdio: \"ignore\" })\n proc.unref()\n}\n\n/** Resolves when `docker info` succeeds (daemon reachable). */\nfunction isDockerDaemonRunning(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"docker\", [\"info\"], { stdio: \"ignore\" })\n proc.on(\"error\", () => resolve(false))\n proc.on(\"exit\", (code) => resolve(code === 0))\n })\n}\n\n/** True when the Docker CLI is on PATH and runs. */\nfunction isDockerCliInstalled(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"docker\", [\"--version\"], { stdio: \"ignore\" })\n proc.on(\"error\", () => resolve(false))\n proc.on(\"exit\", (code) => resolve(code === 0))\n })\n}\n\nfunction tryStartDockerDaemon() {\n const { platform } = process\n\n if (platform === \"darwin\") {\n spawnDetached(\"open\", [\"-a\", \"Docker\"])\n return\n }\n\n if (platform === \"win32\") {\n const exe = \"C:\\\\Program Files\\\\Docker\\\\Docker\\\\Docker Desktop.exe\"\n if (fs.existsSync(exe)) {\n spawnDetached(exe, [])\n return\n }\n spawnDetached(\"cmd\", [\"/c\", \"start\", \"\", \"Docker Desktop\"])\n return\n }\n\n if (platform === \"linux\") {\n spawnDetached(\"systemctl\", [\"--user\", \"start\", \"docker-desktop\"])\n }\n}\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Verifies Docker CLI is installed, starts the daemon when possible, and waits until it responds.\n * Exits the process on unrecoverable errors.\n */\nexport async function ensureDockerReady() {\n const cliOk = await isDockerCliInstalled()\n if (!cliOk) {\n console.error(\n ` ${chalk.red(\"x\")} ${chalk.bold(\"docker\")}: ${chalk.red(\"Docker is not installed or not on your PATH.\")}`,\n )\n console.error(\n ` Install Docker and try again: ${chalk.cyan.underline(DOCKER_GET_STARTED_URL)}`,\n )\n process.exit(1)\n }\n\n if (await isDockerDaemonRunning()) {\n return\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(\"docker\")}: ${chalk.yellow(\"Docker daemon is not running. Starting it…\")}`,\n )\n tryStartDockerDaemon()\n\n const deadline = Date.now() + DOCKER_DAEMON_WAIT_MS\n while (Date.now() < deadline) {\n await sleep(DOCKER_DAEMON_POLL_MS)\n if (await isDockerDaemonRunning()) {\n console.log(\n ` ${chalk.green(\"➜\")} ${chalk.bold(\"docker\")}: ${chalk.green(\"Docker is ready.\")}`,\n )\n return\n }\n }\n\n console.error(\n ` ${chalk.red(\"x\")} ${chalk.bold(\"docker\")}: ${chalk.red(\n `Docker did not become ready within ${DOCKER_DAEMON_WAIT_MS / 1000}s. Start Docker manually and run the dev server again.`,\n )}`,\n )\n console.error(` Install or troubleshoot: ${chalk.cyan.underline(DOCKER_GET_STARTED_URL)}`)\n process.exit(1)\n}\n\nexport async function startDockerContainer({\n containerName,\n imageName,\n args = [],\n cmd = [],\n detached = false,\n}: {\n containerName: string\n imageName: string\n args?: string[]\n cmd?: string[]\n /** When true, skip start if the container is already running; remove a non-running name conflict before `docker run`. */\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const dockerContainerName = resolveEthernaContainerName(containerName)\n\n if (!detached) {\n if (await isContainerNameInUse(dockerContainerName)) {\n await stopContainer(dockerContainerName)\n }\n } else {\n if (await isContainerRunning(dockerContainerName)) {\n return null\n }\n if (await isContainerNameInUse(dockerContainerName)) {\n await removeContainerForce(dockerContainerName)\n }\n }\n\n // When the plugin runs in detached mode, put `docker run` in its own session so terminal Ctrl+C\n // (SIGINT to the foreground process group) does not stop the CLI and tear down `--rm` containers.\n const runArgs = [\n \"run\",\n \"--rm\",\n \"--name\",\n dockerContainerName,\n ...args,\n imageName,\n ...cmd,\n ] as const\n const proc = (\n detached\n ? spawn(\"docker\", [...runArgs], {\n detached: true,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n })\n : spawn(\"docker\", [...runArgs])\n ) as ChildProcess\n proc.stdout?.on(\"data\", (data) => {\n const text = String(data)\n\n if (/Pulling from/gm.test(text)) {\n logLoading(dockerContainerName)\n }\n if (/Error response from daemon/gm.test(text)) {\n logError(dockerContainerName, text)\n }\n })\n if (detached) {\n proc.unref()\n }\n\n return proc\n}\n\nasync function isContainerNameInUse(name: string) {\n const proc = spawn(\"docker\", [\n \"ps\",\n \"-a\",\n \"--filter\",\n `name=${resolveEthernaContainerName(name)}`,\n ])\n const result = await new Promise<string>((res) => {\n let data = \"\"\n proc.stdout?.on(\"data\", (d) => {\n data += String(d)\n })\n proc.on(\"close\", () => {\n res(data)\n })\n })\n const lines = result.split(\"\\n\")\n const isInUse = lines.length > 1\n return isInUse\n}\n\n/** Stops the named container (`docker stop`), prefixing the name with `etherna-` when needed. */\nexport async function stopContainer(name: string) {\n const proc = spawn(\"docker\", [\"stop\", resolveEthernaContainerName(name)])\n await new Promise<void>((res) => {\n proc.on(\"close\", () => {\n res()\n })\n })\n}\n\n/** True when a container with this exact name exists and is running. */\nexport async function isContainerRunning(name: string): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\n \"docker\",\n [\"inspect\", \"-f\", \"{{.State.Running}}\", resolveEthernaContainerName(name)],\n {\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n },\n )\n let out = \"\"\n proc.stdout?.on(\"data\", (d) => {\n out += String(d)\n })\n proc.on(\"error\", () => resolve(false))\n proc.on(\"close\", (code) => {\n if (code !== 0) {\n resolve(false)\n return\n }\n resolve(out.trim().toLowerCase() === \"true\")\n })\n })\n}\n\nasync function removeContainerForce(name: string) {\n await new Promise<void>((res) => {\n const proc = spawn(\"docker\", [\"rm\", \"-f\", resolveEthernaContainerName(name)], {\n stdio: \"ignore\",\n })\n proc.on(\"error\", () => res())\n proc.on(\"close\", () => res())\n })\n}\n\nexport async function createContainerVolume(volumeName: string) {\n const proc = spawn(\"docker\", [\"volume\", \"create\", volumeName])\n\n await new Promise<void>((res) => {\n proc.on(\"close\", () => {\n res()\n })\n })\n}\n\nexport async function createNetwork(networkName: string) {\n const proc = spawn(\"docker\", [\"network\", \"create\", networkName])\n\n await new Promise<void>((res) => {\n proc.on(\"close\", () => {\n res()\n })\n })\n}\n","import { stopContainer } from \"./docker\"\n\nimport type { EnabledServiceMap } from \"../session\"\nimport type { EthernaServiceName } from \"../types\"\n\n/**\n * Docker container names that make up each logical service's group. Multi-container services\n * stop as a whole group (see design doc \"Multi-container services\"): `bee` includes the\n * blockchain container (matches today's `stopEnabledEthernaContainers` when `bee: true`), while\n * `blockchain` alone stops only the blockchain container.\n */\nconst CONTAINER_GROUPS: Record<EthernaServiceName, string[]> = {\n blockchain: [\"etherna-blockchain\"],\n bee: [\"etherna-blockchain\", \"etherna-bee\", \"etherna-bee_worker_1\"],\n beehive: [\"etherna-beehive\"],\n credit: [\"etherna-credit\"],\n elastic: [\"etherna-elastic\"],\n gateway: [\"etherna-gateway\"],\n index: [\"etherna-index\"],\n mongo: [\"etherna-mongodb\"],\n shkeeper: [\n \"ethereum-shkeeper-mariadb\",\n \"ethereum-shkeeper-redis\",\n \"ethereum-shkeeper\",\n \"ethereum-tasks\",\n \"shkeeper\",\n ],\n sso: [\"etherna-sso\"],\n}\n\n/** Returns the Docker container names belonging to a logical service's group. */\nexport function containerNamesFor(service: EthernaServiceName): string[] {\n return CONTAINER_GROUPS[service]\n}\n\n/** Stops the container groups for each named logical service (de-duplicated across overlapping groups). */\nexport async function stopLogicalServices(names: EthernaServiceName[]): Promise<void> {\n const containerNames = [...new Set(names.flatMap(containerNamesFor))]\n await Promise.all(containerNames.map((name) => stopContainer(name)))\n}\n\n/**\n * Stops the container groups for every service flagged `true` in `enabled`. Replaces the old\n * `stopEnabledEthernaContainers` (used after a startup failure with `onFailure: \"stop\"`).\n */\nexport async function stopEnabled(enabled: EnabledServiceMap): Promise<void> {\n const names = (Object.keys(enabled) as EthernaServiceName[]).filter((name) => enabled[name])\n await stopLogicalServices(names)\n}\n","import chalk from \"chalk\"\n\nimport { runCommand } from \"./utils\"\n\n/**\n * Runs `update-ca-certificates` inside a running container so it trusts the\n * dev certificate we bind-mounted into it. Used by HTTPS ASP.NET services.\n */\nexport async function trustContainerCertificate(containerName: string) {\n await runCommand(\"docker\", [\"exec\", containerName, \"update-ca-certificates\"]).catch(\n (err: unknown) => {\n console.error(\n chalk.red(\n `‼️ Error trusting certificate in container '${containerName}': ${(err as Error).message}`,\n ),\n )\n },\n )\n}\n","import { CERTIFICATE_DIR, CONTAINER_CERTS_DIR } from \"../consts\"\nimport { getEnv } from \"../env\"\nimport { getPortlessPublicUrl, PORTLESS_CONTAINER_ALIASES } from \"../portless\"\nimport { startDockerContainer } from \"../runtime/docker\"\nimport { trustContainerCertificate } from \"../ssl-trust\"\nimport { logError, logSuccess, resolvePathEscape } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { AspServiceEnv } from \"../env\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/**\n * Starts an ASP.NET Etherna service container (sso/index/gateway/credit/beehive). Resolves once the\n * app logs \"Now listening on …\" (unless reused while detached). `envs` are the caller's per-service\n * overrides (the manager passes `ctx.getServiceEnv(<key>)`).\n */\nexport async function startAspContainer(\n ctx: ServiceStartContext,\n name: string,\n image: string,\n envs?: AspServiceEnv,\n): Promise<ChildProcess | null> {\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n let lastLog: string | undefined = undefined\n\n const { mode } = ctx.serviceCtx\n const env = {\n ...(getEnv(name as \"etherna-sso\", ctx.serviceCtx) ?? {}),\n ...envs,\n }\n const port = env.ASPNETCORE_URLS.split(\";\")[0]?.split(\":\")[2] ?? \"80\"\n\n const alias = PORTLESS_CONTAINER_ALIASES[name]\n const portlessUrl = ctx.serviceCtx.portless && alias ? getPortlessPublicUrl(alias) : undefined\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: image,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n ...(mode === \"https\"\n ? [\n \"--mount\",\n `type=bind,source=${resolvePathEscape(CERTIFICATE_DIR)},target=${CONTAINER_CERTS_DIR}/`,\n ]\n : []),\n \"--network\",\n \"host\",\n ],\n detached: ctx.detached,\n })\n\n if (!proc) {\n logSuccess(name, mode, port, { portlessUrl })\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = async (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n\n if (/Now listening on: https?:\\/\\/(localhost|\\[::\\]):\\d+/gm.test(text)) {\n if (mode === \"https\") {\n await trustContainerCertificate(name)\n }\n logSuccess(name, mode, port, { portlessUrl })\n endPromise?.()\n }\n\n const excludedErrorRegexes = [\n /Current db does not support change stream/gm,\n /is only supported on replica sets./gm,\n /Failed to process the job/gm,\n ]\n // Etherna ASP.NET apps use Serilog; default format: [HH:mm:ss INF] message\n // Require explicit error level - logs can arrive in chunks, so a chunk with\n // Exception but no level may be the continuation of a [WRN] log\n const errorLogLevelRegexes = [\n /\\[(ERR|FTL)\\]/gm, // Serilog {Level:u3}\n /\"LogLevel\"\\s*:\\s*\"(Error|Critical)\"/gm, // Microsoft JSON\n /\\b(fail|crit):/gm, // Microsoft Simple\n /<(2|3)>/gm, // Microsoft Systemd: <2>=Critical, <3>=Error\n ]\n const hasErrorLevel = errorLogLevelRegexes.some((regex) => regex.test(text))\n const hasNonErrorLevel = /\\[(INF|WRN|DBG|VRB)\\]/gm.test(text)\n if (\n hasErrorLevel &&\n !hasNonErrorLevel &&\n /Exception:.+/gm.test(text) &&\n !excludedErrorRegexes.some((regex) => regex.test(text))\n ) {\n logError(name, text)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","/**\n * Minimal Ethereum JSON-RPC + tx-signing helpers used by the plugin to talk to\n * the dev-chain geth container without pulling in a full web3/ethers/viem\n * dependency.\n *\n * All RPC helpers are stateless and take an `rpcUrl`. They throw on transport\n * or RPC-level errors so callers can decide how to surface them.\n *\n * The signing helpers implement just enough RLP + EIP-155 to sign and broadcast\n * a single legacy transaction. We sign client-side because geth 1.13+ removed\n * `personal_importRawKey` / `personal_unlockAccount` from the HTTP API, so we\n * cannot rely on geth-managed signing for any account other than the Clique\n * signer that geth itself keeps unlocked.\n *\n * The implementation intentionally does NOT support EIP-1559 / 2930 envelopes;\n * the Clique dev chain accepts legacy txs and that keeps the code small.\n */\n\nimport { secp256k1 } from \"@noble/curves/secp256k1.js\"\nimport { keccak_256 } from \"@noble/hashes/sha3.js\"\n\nconst DEFAULT_TX_RECEIPT_POLL_MS = 500\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/** Performs a JSON-RPC POST and unwraps `result`/`error` for the caller. */\nexport async function ethJsonRpc<T = unknown>(\n rpcUrl: string,\n method: string,\n params: unknown[],\n): Promise<T> {\n const resp = await fetch(rpcUrl, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ jsonrpc: \"2.0\", id: 1, method, params }),\n })\n if (!resp.ok) {\n throw new Error(`RPC ${method} failed: ${resp.status} ${resp.statusText}`)\n }\n const data = (await resp.json()) as {\n error?: { message?: string }\n result?: T\n }\n if (data.error?.message) {\n throw new Error(`RPC ${method} error: ${data.error.message}`)\n }\n return data.result as T\n}\n\n/** Resolves the 4-byte function selector for `signature` via geth's `web3_sha3`. */\nexport async function getFunctionSelector(rpcUrl: string, signature: string): Promise<string> {\n const hex = \"0x\" + Buffer.from(signature, \"utf-8\").toString(\"hex\")\n const digest = await ethJsonRpc<string>(rpcUrl, \"web3_sha3\", [hex])\n return digest.slice(0, 10)\n}\n\n/** ABI-encodes a single uint up to 256 bits as a 32-byte big-endian word (no `0x` prefix). */\nexport function encodeUintParam(value: bigint): string {\n if (value < 0n) {\n throw new Error(`Cannot encode negative uint param: ${value}`)\n }\n return value.toString(16).padStart(64, \"0\")\n}\n\n/** ABI-encodes a 20-byte address as a 32-byte left-padded big-endian word (no `0x` prefix). */\nexport function encodeAddressParam(address: string): string {\n const trimmed = address.toLowerCase().startsWith(\"0x\") ? address.slice(2) : address\n if (trimmed.length !== 40) {\n throw new Error(`Invalid address (expected 20 bytes / 40 hex chars): ${address}`)\n }\n return trimmed.toLowerCase().padStart(64, \"0\")\n}\n\n/** ABI-encodes a 32-byte hash as-is (no `0x` prefix). */\nexport function encodeBytes32Param(hash: string): string {\n const trimmed = hash.startsWith(\"0x\") ? hash.slice(2) : hash\n if (trimmed.length !== 64) {\n throw new Error(`Invalid bytes32 (expected 32 bytes / 64 hex chars): ${hash}`)\n }\n return trimmed.toLowerCase()\n}\n\n/** Decodes a hex-encoded uint (with or without `0x` prefix) into a `bigint`. */\nexport function decodeUint(hex: string): bigint {\n const trimmed = hex.startsWith(\"0x\") ? hex.slice(2) : hex\n if (trimmed.length === 0) {\n return 0n\n }\n return BigInt(\"0x\" + trimmed)\n}\n\n/** Polls `eth_getTransactionReceipt` until `txHash` is mined or `timeoutMs` elapses. */\nexport async function waitForTxReceipt(\n rpcUrl: string,\n txHash: string,\n timeoutMs: number,\n pollMs: number = DEFAULT_TX_RECEIPT_POLL_MS,\n): Promise<{ status: string; blockNumber?: string }> {\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const receipt = await ethJsonRpc<{ status?: string; blockNumber?: string } | null>(\n rpcUrl,\n \"eth_getTransactionReceipt\",\n [txHash],\n )\n if (receipt?.status) {\n return { status: receipt.status, blockNumber: receipt.blockNumber }\n }\n await sleep(pollMs)\n }\n throw new Error(`Transaction ${txHash} was not mined within ${timeoutMs}ms`)\n}\n\n/** Returns the deployed bytecode at `address` as a hex string (`\"0x\"` if undeployed). */\nexport async function getEthereumCode(rpcUrl: string, address: string): Promise<string> {\n return await ethJsonRpc<string>(rpcUrl, \"eth_getCode\", [address, \"latest\"]).then(\n (result) => result ?? \"0x\",\n )\n}\n\n/** Returns the current chain head height as a number. */\nexport async function getEthereumBlockNumber(rpcUrl: string): Promise<number> {\n const result = await ethJsonRpc<string>(rpcUrl, \"eth_blockNumber\", [])\n return Number.parseInt(result ?? \"0x0\", 16)\n}\n\n/** True when `code` is non-empty bytecode (i.e. a contract is deployed at the address). */\nexport function isEthereumCodeDeployed(code: string): boolean {\n return code !== \"0x\" && code.length > 2\n}\n\n/** Returns the pending transaction count (next nonce) for `address`. */\nexport async function getEthereumTransactionCount(\n rpcUrl: string,\n address: string,\n block: \"latest\" | \"pending\" = \"pending\",\n): Promise<bigint> {\n const result = await ethJsonRpc<string>(rpcUrl, \"eth_getTransactionCount\", [address, block])\n return decodeUint(result)\n}\n\n/** Returns the suggested gas price reported by the node. */\nexport async function getEthereumGasPrice(rpcUrl: string): Promise<bigint> {\n const result = await ethJsonRpc<string>(rpcUrl, \"eth_gasPrice\", [])\n return decodeUint(result)\n}\n\n// ----------------------------------------------------------------------------\n// Hex / bytes utilities\n// ----------------------------------------------------------------------------\n\nfunction hexToBytes(hex: string): Uint8Array {\n const trimmed = hex.startsWith(\"0x\") ? hex.slice(2) : hex\n const padded = trimmed.length % 2 === 0 ? trimmed : \"0\" + trimmed\n return Uint8Array.from(Buffer.from(padded, \"hex\"))\n}\n\nfunction bytesToHex(bytes: Uint8Array): string {\n return Buffer.from(bytes).toString(\"hex\")\n}\n\n/** Converts a non-negative bigint to its minimal big-endian byte representation (0n -> empty). */\nfunction bigintToMinimalBytes(value: bigint): Uint8Array {\n if (value < 0n) {\n throw new Error(`Cannot encode negative bigint: ${value}`)\n }\n if (value === 0n) {\n return new Uint8Array(0)\n }\n let hex = value.toString(16)\n if (hex.length % 2 !== 0) {\n hex = \"0\" + hex\n }\n return hexToBytes(hex)\n}\n\n// ----------------------------------------------------------------------------\n// Minimal RLP encoder\n// ----------------------------------------------------------------------------\n\ntype RlpInput = Uint8Array | RlpInput[]\n\nfunction concat(...parts: Uint8Array[]): Uint8Array {\n const total = parts.reduce((sum, part) => sum + part.length, 0)\n const out = new Uint8Array(total)\n let offset = 0\n for (const part of parts) {\n out.set(part, offset)\n offset += part.length\n }\n return out\n}\n\nfunction rlpEncodeLength(length: number, offset: number): Uint8Array {\n if (length < 56) {\n return Uint8Array.of(offset + length)\n }\n const lenBytes = bigintToMinimalBytes(BigInt(length))\n return concat(Uint8Array.of(offset + 55 + lenBytes.length), lenBytes)\n}\n\nfunction rlpEncode(input: RlpInput): Uint8Array {\n if (input instanceof Uint8Array) {\n if (input.length === 1 && input[0]! < 0x80) {\n return input\n }\n return concat(rlpEncodeLength(input.length, 0x80), input)\n }\n const encoded = input.map(rlpEncode)\n const payload = concat(...encoded)\n return concat(rlpEncodeLength(payload.length, 0xc0), payload)\n}\n\n// ----------------------------------------------------------------------------\n// Keccak256 / address derivation / EIP-155 signing\n// ----------------------------------------------------------------------------\n\n/** Keccak-256 (NOT SHA3-256) hash of `data`. */\nexport function keccak256(data: Uint8Array): Uint8Array {\n return keccak_256(data)\n}\n\n/** Derives the 20-byte Ethereum address from a hex private key (with or without `0x`). */\nexport function privateKeyToAddress(privateKey: string): string {\n const pkBytes = hexToBytes(privateKey)\n if (pkBytes.length !== 32) {\n throw new Error(`Invalid private key length: expected 32 bytes, got ${pkBytes.length}`)\n }\n const pubUncompressed = secp256k1.getPublicKey(pkBytes, false)\n // Strip the leading 0x04 (uncompressed-format tag) before hashing.\n const hash = keccak_256(pubUncompressed.slice(1))\n return \"0x\" + bytesToHex(hash.slice(-20))\n}\n\nexport interface LegacyTx {\n /** EIP-155 chain id. */\n chainId: bigint\n nonce: bigint\n gasPrice: bigint\n gasLimit: bigint\n /** 20-byte hex (`0x…`). */\n to: string\n value: bigint\n /** Hex calldata (`0x…`), may be `\"0x\"` for plain transfers. */\n data: string\n}\n\n/**\n * Signs `tx` as an EIP-155 legacy transaction with `privateKey` and returns the\n * raw RLP payload ready for `eth_sendRawTransaction` plus its tx hash.\n *\n * IMPORTANT: we pass `prehash: false` because the input we feed to ECDSA is\n * already keccak256'd (per yellow paper / EIP-155). Without it, noble's\n * default `prehash: true` would re-hash with sha256 and yield a non-Ethereum\n * signature.\n */\nexport function signLegacyTransaction(\n tx: LegacyTx,\n privateKey: string,\n): { rawTx: string; hash: string } {\n if (!tx.to.startsWith(\"0x\") || tx.to.length !== 42) {\n throw new Error(`Invalid 'to' address: ${tx.to}`)\n }\n\n const fields: Uint8Array[] = [\n bigintToMinimalBytes(tx.nonce),\n bigintToMinimalBytes(tx.gasPrice),\n bigintToMinimalBytes(tx.gasLimit),\n hexToBytes(tx.to),\n bigintToMinimalBytes(tx.value),\n hexToBytes(tx.data),\n ]\n\n const sigHashRlp = rlpEncode([\n ...fields,\n bigintToMinimalBytes(tx.chainId),\n new Uint8Array(0),\n new Uint8Array(0),\n ])\n const sigHash = keccak_256(sigHashRlp)\n\n const pkBytes = hexToBytes(privateKey)\n const sigBytes = secp256k1.sign(sigHash, pkBytes, {\n format: \"recovered\",\n lowS: true,\n prehash: false,\n })\n // `format: \"recovered\"` returns 65 bytes: recoveryId (1) ‖ r (32) ‖ s (32).\n const recoveryId = sigBytes[0]!\n const r = decodeUint(bytesToHex(sigBytes.subarray(1, 33)))\n const s = decodeUint(bytesToHex(sigBytes.subarray(33, 65)))\n const v = BigInt(recoveryId) + 35n + tx.chainId * 2n\n\n const signedRlp = rlpEncode([\n ...fields,\n bigintToMinimalBytes(v),\n bigintToMinimalBytes(r),\n bigintToMinimalBytes(s),\n ])\n\n return {\n rawTx: \"0x\" + bytesToHex(signedRlp),\n hash: \"0x\" + bytesToHex(keccak_256(signedRlp)),\n }\n}\n\n/**\n * Builds, signs (EIP-155 legacy), broadcasts and waits for a single tx from\n * `privateKey`. Fetches `chainId`, pending nonce and `gasPrice` from the node;\n * bumps a `0` gas-price to `1` wei because geth's gas-price oracle returns 0\n * on a freshly-booted dev chain.\n *\n * Throws if the receipt status is not `0x1` (use `onRevert` to customize the\n * error message).\n */\nexport async function sendSignedTransaction(\n rpcUrl: string,\n privateKey: string,\n call: { to: string; data: string; gasLimit: bigint; value?: bigint },\n options: {\n timeoutMs: number\n pollMs?: number\n onRevert?: (txHash: string) => string\n },\n): Promise<string> {\n const from = privateKeyToAddress(privateKey)\n const [chainIdHex, nonce, gasPrice] = await Promise.all([\n ethJsonRpc<string>(rpcUrl, \"eth_chainId\", []),\n getEthereumTransactionCount(rpcUrl, from, \"pending\"),\n getEthereumGasPrice(rpcUrl),\n ])\n const chainId = decodeUint(chainIdHex)\n const { rawTx, hash } = signLegacyTransaction(\n {\n chainId,\n nonce,\n gasPrice: gasPrice === 0n ? 1n : gasPrice,\n gasLimit: call.gasLimit,\n to: call.to,\n value: call.value ?? 0n,\n data: call.data,\n },\n privateKey,\n )\n await ethJsonRpc<string>(rpcUrl, \"eth_sendRawTransaction\", [rawTx])\n const receipt = await waitForTxReceipt(rpcUrl, hash, options.timeoutMs, options.pollMs)\n if (receipt.status !== \"0x1\") {\n throw new Error(options.onRevert?.(hash) ?? `Transaction ${hash} reverted (status ${receipt.status}).`)\n }\n return hash\n}\n","import fs from \"node:fs\"\nimport chalk from \"chalk\"\n\nimport {\n BLOCKCHAIN_OWNER_ADDRESS,\n getEnv,\n POSTAGE_STAMP_ADMIN_PRIVATE_KEY,\n stripPluginInternalEnvKeys,\n} from \"../env\"\nimport { getPortlessPublicUrl } from \"../portless\"\nimport {\n createContainerVolume,\n createNetwork,\n isContainerRunning,\n startDockerContainer,\n stopContainer,\n} from \"../runtime/docker\"\nimport {\n getBeeUnderlayAddress,\n logError,\n logSuccess,\n resolvePath,\n resolvePathEscape,\n} from \"../utils\"\nimport {\n decodeUint,\n encodeAddressParam,\n encodeBytes32Param,\n encodeUintParam,\n ethJsonRpc,\n getEthereumBlockNumber,\n getEthereumCode,\n getFunctionSelector,\n isEthereumCodeDeployed,\n privateKeyToAddress,\n sendSignedTransaction,\n} from \"../web3\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ChildProcess } from \"node:child_process\"\n\nconst BEE_NETWORK_NAME = \"etherna_bee_network\"\n\nconst BEE_CONTRACT_DEPLOY_WAIT_MS = 30_000\nconst BEE_CONTRACT_DEPLOY_POLL_MS = 1_000\nconst BEE_CORRUPTED_CHAIN_BLOCK_THRESHOLD = 10\nconst BEE_CORRUPTED_CHAIN_PROGRESS_BLOCKS = 2\n\nconst BEE_REQUIRED_CONTRACT_ENV_KEYS = [\n \"BEE_SWAP_FACTORY_ADDRESS\",\n \"BEE_POSTAGE_STAMP_ADDRESS\",\n \"BEE_PRICE_ORACLE_ADDRESS\",\n \"BEE_REDISTRIBUTION_ADDRESS\",\n \"BEE_STAKING_ADDRESS\",\n] as const\n\nconst POSTAGE_PRICE_SYNC_TIMEOUT_MS = 30_000\nconst POSTAGE_PRICE_SYNC_POLL_MS = 500\nconst POSTAGE_PRICE_SYNC_GAS_LIMIT = 200_000\n\nlet blockchainBootstrapInProgress = false\nlet resolveBlockchainBootstrapSettle = undefined as undefined | (() => void)\nlet blockchainBootstrapSettlePromise = Promise.resolve()\n\nfunction beginBlockchainBootstrap() {\n blockchainBootstrapInProgress = true\n blockchainBootstrapSettlePromise = new Promise<void>((resolve) => {\n resolveBlockchainBootstrapSettle = resolve\n })\n}\n\nfunction settleBlockchainBootstrap() {\n if (!blockchainBootstrapInProgress) {\n return\n }\n\n blockchainBootstrapInProgress = false\n resolveBlockchainBootstrapSettle?.()\n resolveBlockchainBootstrapSettle = undefined\n}\n\nexport function isBlockchainBootstrapInProgress() {\n return blockchainBootstrapInProgress\n}\n\nexport function waitForBlockchainBootstrapToSettle() {\n return blockchainBootstrapSettlePromise\n}\n\nfunction sleep(ms: number) {\n return new Promise<void>((resolve) => setTimeout(resolve, ms))\n}\n\n/**\n * Reads `PostageStamp.lastPrice()` (the value Bee uses for stamp accounting)\n * and, if it differs from `desiredPrice`, writes the new price by calling\n * `PostageStamp.setPrice(uint256)` directly from the deployer key — bypassing\n * the broken `PostagePriceOracle` shipped by fdp-play.\n *\n * Why we bypass `PostagePriceOracle`:\n * fdp-play's `deploy.ts` calls `getPostagePriceOracleBin(erc20Address, adminAddress)`\n * which appends BOTH addresses to the constructor calldata, but the actual\n * `PriceOracle` constructor only takes one arg (`address _postageStamp`).\n * Solidity silently ignores the trailing word, so the deployed oracle's\n * `postageStamp` field ends up pointing at the BZZ token contract, not the\n * real `PostageStamp`. Every `oracle.setPrice(...)` then internally calls\n * `bzzToken.setPrice(...)`, which doesn't exist — depending on the exact\n * deployed bytecode the outer tx either reverts or quietly succeeds while\n * `PostageStamp.lastPrice` stays at 0. Either way, no role grant on the\n * oracle can fix it.\n *\n * Direct `PostageStamp.setPrice(uint256)` call requires `PRICE_ORACLE_ROLE`.\n * We grant it to the deployer first (deployer holds `DEFAULT_ADMIN_ROLE` on\n * `PostageStamp`, set by its constructor's `_setupRole(DEFAULT_ADMIN_ROLE,\n * msg.sender)`). The role hash is read from the contract itself\n * (`PRICE_ORACLE_ROLE()` getter) so we transparently support both v0.5.x\n * (`keccak256(\"PRICE_ORACLE\")`) and v0.6.x (`keccak256(\"PRICE_ORACLE_ROLE\")`)\n * bytecodes.\n *\n * `ownerPrivateKey` MUST be the key that originally deployed `PostageStamp`\n * (matching fdp-play's `hardhat.config.ts`). The unlocked Clique signer never\n * deployed any contract and therefore lacks `DEFAULT_ADMIN_ROLE` everywhere.\n * We can't go through geth's `personal_*` API either (removed from the HTTP\n * namespace in geth ≥ 1.12), so txs are signed locally with EIP-155 and\n * broadcast via `eth_sendRawTransaction`.\n */\nasync function ensurePostagePrice({\n rpcUrl,\n postageStampAddress,\n ownerPrivateKey,\n desiredPrice,\n}: {\n rpcUrl: string\n postageStampAddress: string\n ownerPrivateKey: string\n desiredPrice: bigint\n}): Promise<void> {\n const name = \"etherna-bee\"\n // PostageStamp stores `lastPrice` as uint64.\n const maxPrice = (1n << 64n) - 1n\n if (desiredPrice < 0n || desiredPrice > maxPrice) {\n throw new Error(`POSTAGE_PRICE ${desiredPrice} is out of range for uint64 (0..${maxPrice}).`)\n }\n\n const [\n lastPriceSelector,\n setPriceSelector,\n hasRoleSelector,\n grantRoleSelector,\n priceOracleRoleSelector,\n ] = await Promise.all([\n getFunctionSelector(rpcUrl, \"lastPrice()\"),\n getFunctionSelector(rpcUrl, \"setPrice(uint256)\"),\n getFunctionSelector(rpcUrl, \"hasRole(bytes32,address)\"),\n getFunctionSelector(rpcUrl, \"grantRole(bytes32,address)\"),\n getFunctionSelector(rpcUrl, \"PRICE_ORACLE_ROLE()\"),\n ])\n\n const readLastPrice = async () => {\n const raw = await ethJsonRpc<string>(rpcUrl, \"eth_call\", [\n { to: postageStampAddress, data: lastPriceSelector },\n \"latest\",\n ])\n return decodeUint(raw)\n }\n\n const currentPrice = await readLastPrice()\n\n if (currentPrice === desiredPrice) {\n return\n }\n\n const ownerAddress = privateKeyToAddress(ownerPrivateKey)\n\n const roleHashRaw = await ethJsonRpc<string>(rpcUrl, \"eth_call\", [\n { to: postageStampAddress, data: priceOracleRoleSelector },\n \"latest\",\n ])\n if (!roleHashRaw || roleHashRaw === \"0x\") {\n throw new Error(\n `PostageStamp.PRICE_ORACLE_ROLE() returned no data; ${postageStampAddress} may not be a PostageStamp contract.`,\n )\n }\n const roleHashEncoded = encodeBytes32Param(roleHashRaw)\n const ownerAddressEncoded = encodeAddressParam(ownerAddress)\n\n const hasRoleRaw = await ethJsonRpc<string>(rpcUrl, \"eth_call\", [\n {\n to: postageStampAddress,\n data: hasRoleSelector + roleHashEncoded + ownerAddressEncoded,\n },\n \"latest\",\n ])\n const ownerHasRole = decodeUint(hasRoleRaw) !== 0n\n\n if (!ownerHasRole) {\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(\n name,\n )}: granting PRICE_ORACLE_ROLE on PostageStamp to ${chalk.gray(ownerAddress)}`,\n )\n const grantTxHash = await sendSignedTransaction(\n rpcUrl,\n ownerPrivateKey,\n {\n to: postageStampAddress,\n data: grantRoleSelector + roleHashEncoded + ownerAddressEncoded,\n gasLimit: BigInt(POSTAGE_PRICE_SYNC_GAS_LIMIT),\n },\n {\n timeoutMs: POSTAGE_PRICE_SYNC_TIMEOUT_MS,\n pollMs: POSTAGE_PRICE_SYNC_POLL_MS,\n onRevert: (hash) =>\n `PostageStamp.grantRole(PRICE_ORACLE_ROLE, ${ownerAddress}) reverted (tx ${hash}). The owner likely lacks DEFAULT_ADMIN_ROLE on PostageStamp ${postageStampAddress}.`,\n },\n )\n console.log(` ${chalk.gray(` granted (tx ${grantTxHash})`)}`)\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(name)}: updating postage price ${chalk.gray(\n String(currentPrice),\n )} → ${chalk.cyan(String(desiredPrice))} PLUR`,\n )\n\n const txHash = await sendSignedTransaction(\n rpcUrl,\n ownerPrivateKey,\n {\n to: postageStampAddress,\n data: setPriceSelector + encodeUintParam(desiredPrice),\n gasLimit: BigInt(POSTAGE_PRICE_SYNC_GAS_LIMIT),\n },\n {\n timeoutMs: POSTAGE_PRICE_SYNC_TIMEOUT_MS,\n pollMs: POSTAGE_PRICE_SYNC_POLL_MS,\n onRevert: (hash) =>\n `PostageStamp.setPrice(${desiredPrice}) reverted (tx ${hash}). The owner ${ownerAddress} may lack PRICE_ORACLE_ROLE on PostageStamp ${postageStampAddress}.`,\n },\n )\n\n const newPrice = await readLastPrice()\n if (newPrice !== desiredPrice) {\n throw new Error(\n `PostageStamp.setPrice(${desiredPrice}) succeeded (tx ${txHash}) but PostageStamp.lastPrice is ${newPrice}.`,\n )\n }\n\n console.log(\n ` ${chalk.green(\"➜\")} ${chalk.bold(name)}: postage price set to ${chalk.cyan(\n String(desiredPrice),\n )} PLUR ${chalk.gray(`(tx ${txHash})`)}`,\n )\n}\n\nfunction createCorruptedBlockchainError(volumeName: string) {\n return new Error(\n [\n \"Detected a stale or corrupted local blockchain state: Bee contracts are still missing even though the chain has already advanced.\",\n \"Fix it by stopping the dev server, removing the persisted blockchain volume, and starting again:\",\n `1. Stop the dev server`,\n `2. Run: docker volume rm ${volumeName}`,\n `3. Run: pnpm dev`,\n ].join(\"\\n\"),\n )\n}\n\nasync function waitForBeeContracts(rpcUrl: string, addresses: string[], volumeName: string) {\n const deadline = Date.now() + BEE_CONTRACT_DEPLOY_WAIT_MS\n let firstObservedBlock: number | null = null\n\n while (Date.now() < deadline) {\n const [blockNumber, codes] = await Promise.all([\n getEthereumBlockNumber(rpcUrl).catch(() => null),\n Promise.all(addresses.map((address) => getEthereumCode(rpcUrl, address).catch(() => null))),\n ])\n\n if (blockNumber != null && codes.every((code) => code != null)) {\n if (firstObservedBlock === null) {\n firstObservedBlock = blockNumber\n }\n\n if (codes.every((code) => isEthereumCodeDeployed(code))) {\n return\n }\n\n const blockchainLooksCorrupted =\n blockNumber >= BEE_CORRUPTED_CHAIN_BLOCK_THRESHOLD ||\n blockNumber - firstObservedBlock >= BEE_CORRUPTED_CHAIN_PROGRESS_BLOCKS\n\n if (blockchainLooksCorrupted) {\n throw createCorruptedBlockchainError(volumeName)\n }\n }\n\n await sleep(BEE_CONTRACT_DEPLOY_POLL_MS)\n }\n\n throw new Error(\n `Bee contracts were not deployed before the startup timeout elapsed. If this keeps happening, stop the dev server, run \\`docker volume rm ${volumeName}\\`, and start again.`,\n )\n}\n\nexport async function startBlockchain(ctx: ServiceStartContext): Promise<ChildProcess | null> {\n const context = ctx.serviceCtx\n const envs = ctx.getServiceEnv(\"bee\")\n const name = \"etherna-blockchain\"\n const volumeName = \"etherna_blockchain-volume\"\n const detached = ctx.detached\n\n const envEarly = stripPluginInternalEnvKeys({\n ...(getEnv(name, context) ?? {}),\n ...envs,\n })\n const blockchainPortEarly = Number(envEarly.BLOCKCHAIN_PORT)\n\n if (detached && (await isContainerRunning(name))) {\n logSuccess(name, \"http\", String(blockchainPortEarly))\n return null\n }\n\n beginBlockchainBootstrap()\n await createNetwork(BEE_NETWORK_NAME)\n await createContainerVolume(volumeName)\n\n let lastLog: string | undefined = undefined\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n let readinessCheckStarted = false\n let startupSettled = false\n\n if (!fs.existsSync(resolvePath(\".ethereum\"))) {\n fs.mkdirSync(resolvePath(\".ethereum\"), { recursive: true, mode: 0o777 })\n }\n if (!fs.existsSync(resolvePath(\".ethereum\", \"password\"))) {\n fs.writeFileSync(resolvePath(\".ethereum\", \"password\"), \"toTheSun\", {\n encoding: \"utf-8\",\n mode: 0o644,\n })\n }\n\n const env = stripPluginInternalEnvKeys({\n ...(getEnv(name, context) ?? {}),\n ...envs,\n })\n const beeEnv = {\n ...(getEnv(\"etherna-bee\", context) ?? {}),\n ...envs,\n }\n\n const blockchainPort = Number(env.BLOCKCHAIN_PORT)\n const beeContractAddresses = BEE_REQUIRED_CONTRACT_ENV_KEYS.map((key) => String(beeEnv[key]))\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"fairdatasociety/fdp-play-blockchain:latest\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--network\",\n BEE_NETWORK_NAME,\n \"-p\",\n `${blockchainPort}:${blockchainPort}`,\n \"-p\",\n `${blockchainPort + 1}:${blockchainPort + 1}`,\n \"--mount\",\n `type=volume,source=${volumeName},target=/root/.ethereum`,\n \"--mount\",\n `type=bind,source=${resolvePathEscape(\".ethereum\")},target=/root/extra`,\n ],\n detached,\n cmd: [\n \"--allow-insecure-unlock\",\n `--unlock=${BLOCKCHAIN_OWNER_ADDRESS}`,\n \"--password=/root/extra/password\",\n \"--mine\",\n `--miner.etherbase=${BLOCKCHAIN_OWNER_ADDRESS}`,\n \"--http\",\n '--http.api=\"debug,web3,eth,txpool,net,personal\"',\n \"--http.corsdomain=*\",\n `--http.port=${blockchainPort}`,\n \"--http.addr=0.0.0.0\",\n \"--http.vhosts=*\",\n \"--ws\",\n '--ws.api=\"debug,web3,eth,txpool,net,personal\"',\n `--ws.port=${blockchainPort + 1}`,\n \"--ws.origins=*\",\n \"--maxpeers=0\",\n `--networkid=${env.NETWORK_ID}`,\n \"--authrpc.vhosts=*\",\n \"--authrpc.addr=0.0.0.0\",\n ],\n })\n\n if (!proc) {\n settleBlockchainBootstrap()\n logSuccess(name, \"http\", String(blockchainPort))\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (!readinessCheckStarted && /HTTP server started/gm.test(text)) {\n readinessCheckStarted = true\n void waitForBeeContracts(\n `http://127.0.0.1:${blockchainPort}`,\n beeContractAddresses,\n volumeName,\n )\n .then(() => {\n startupSettled = true\n settleBlockchainBootstrap()\n endPromise?.()\n })\n .catch((error: unknown) => {\n startupSettled = true\n settleBlockchainBootstrap()\n const message = error instanceof Error ? error.message : String(error)\n logError(name, message)\n void stopContainer(name).finally(() => {\n rejectPromise?.(error)\n })\n })\n }\n\n if (/Error:.+/gm.test(text)) {\n logError(name, text)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n settleBlockchainBootstrap()\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n settleBlockchainBootstrap()\n if (!startupSettled) {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startBeeNodes(ctx: ServiceStartContext): Promise<(ChildProcess | null)[]> {\n const context = ctx.serviceCtx\n const envs = ctx.getServiceEnv(\"bee\")\n const name = \"etherna-bee\"\n\n const queenProc = await startBeeNode(ctx, name)\n\n const bootnode = await getBeeUnderlayAddress(\n `http://localhost:${getEnv(\"etherna-bee\", context)?.BEE_PORT ?? \"1633\"}`,\n )\n\n const [worker1Proc] = await Promise.all([\n startBeeNode(ctx, name, 1, bootnode),\n // startBeeNode(ctx, name, 2, bootnode),\n // startBeeNode(ctx, name, 3, bootnode),\n // startBeeNode(ctx, name, 4, bootnode),\n ])\n\n try {\n const beeEnv = { ...(getEnv(\"etherna-bee\", context) ?? {}), ...envs }\n const blockchainEnv = {\n ...(getEnv(\"etherna-blockchain\", context) ?? {}),\n ...envs,\n }\n await ensurePostagePrice({\n rpcUrl: `http://127.0.0.1:${blockchainEnv.BLOCKCHAIN_PORT}`,\n postageStampAddress: String(beeEnv.BEE_POSTAGE_STAMP_ADDRESS),\n ownerPrivateKey: POSTAGE_STAMP_ADMIN_PRIVATE_KEY,\n desiredPrice: BigInt(String(beeEnv.POSTAGE_PRICE ?? \"24000\")),\n })\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n logError(name, `Failed to sync postage price: ${message}`)\n }\n\n return [queenProc, worker1Proc]\n}\n\nasync function startBeeNode(\n ctx: ServiceStartContext,\n name: string,\n worker?: 1 | 2 | 3 | 4,\n bootnode?: string,\n): Promise<ChildProcess | null> {\n const context = ctx.serviceCtx\n const envs = ctx.getServiceEnv(\"bee\")\n const volumeName = worker ? `etherna_bee_worker_${worker}-volume` : \"etherna_bee-volume\"\n await createContainerVolume(volumeName)\n\n let lastLog: string | undefined = undefined\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const { mode } = context\n const env = stripPluginInternalEnvKeys({\n ...(getEnv(name, context) ?? {}),\n ...envs,\n })\n\n if (!worker) {\n delete env.BEE_BOOTNODE\n env.BEE_BOOTNODE_MODE = \"false\"\n } else {\n delete env.BEE_BOOTNODE_MODE\n env.BEE_BOOTNODE = bootnode\n }\n\n if (worker) {\n name = `${name}_worker_${worker}`\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: worker\n ? `fairdatasociety/fdp-play-worker-${worker}`\n : \"fairdatasociety/fdp-play-queen:latest\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${volumeName},target=/home/bee/.bee`,\n \"--network\",\n BEE_NETWORK_NAME,\n \"-p\",\n `${worker ? parseInt(env.BEE_PORT ?? \"1633\") + worker * 10000 : env.BEE_PORT}:${env.BEE_PORT}`,\n \"-p\",\n `${worker ? parseInt(env.BEE_P2P_PORT ?? \"1634\") + worker * 10000 : env.BEE_P2P_PORT}:${env.BEE_P2P_PORT}`,\n ],\n cmd: [\"start\"],\n detached: ctx.detached,\n })\n\n if (!proc) {\n if (!worker) {\n const portlessUrl = context.portless ? getPortlessPublicUrl(\"bee\") : undefined\n logSuccess(name, mode, String(env.BEE_PORT ?? \"1633\"), { portlessUrl })\n }\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/\"address\"=\"\\[::\\]:\\d+\"/gm.test(text)) {\n if (!worker) {\n const portlessUrl = context.portless ? getPortlessPublicUrl(\"bee\") : undefined\n logSuccess(name, mode, String(env.BEE_PORT ?? \"1633\"), { portlessUrl })\n }\n endPromise?.()\n }\n\n const excludedErrorRegexes = [/\"logger\"=\"node\\/storageincentives\"/gm]\n // Bee uses \"level\"=\"error\" format; filter to only error/critical lines (chunks can mix levels)\n const errorLines = text.split(\"\\n\").filter((line) => /\"level\"=\"(error|critical)\"/.test(line))\n const errorText = errorLines.join(\"\\n\")\n if (errorText && !excludedErrorRegexes.some((regex) => regex.test(text))) {\n logError(name, errorText)\n endPromise?.()\n lastLog = errorText\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startInterceptor(\n ctx: ServiceStartContext,\n name: string,\n): Promise<ChildProcess | null> {\n const context = ctx.serviceCtx\n let lastLog: string | undefined = undefined\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const env = getEnv(name, context) ?? {}\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"etherna/etherna-gateway-interceptor:latest\",\n args: [...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`])],\n detached: ctx.detached,\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/starting in full mode/gm.test(text)) {\n endPromise?.()\n }\n\n if (/\"level\"=\"error\"/gm.test(text)) {\n logError(name, text)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","import type {\n BeeEnv,\n BeehiveEnv,\n CreditEnv,\n ElasticEnv,\n GatewayEnv,\n IndexEnv,\n MongoEnv,\n ServiceEnvBuildContext,\n SsoEnv,\n} from \"../env\"\nimport type { ShkeeperConfig } from \"../types\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/** Maps each configurable logical service to the env-override shape callers may pass for it. */\nexport interface ServiceEnvByKey {\n elastic: ElasticEnv\n mongo: MongoEnv\n bee: BeeEnv\n sso: SsoEnv\n index: IndexEnv\n gateway: GatewayEnv\n credit: CreditEnv\n beehive: BeehiveEnv\n}\n\nexport type ServiceKey = keyof ServiceEnvByKey\n\n/**\n * Everything a service starter needs from the run's session/config, bundled into one object so the\n * manager can wire it once and pass it to every starter. Replaces the per-function\n * `(context, envs, opts)` signatures the starters used before the package split.\n */\nexport interface ServiceStartContext {\n /** When true, reuse already-running containers and leave them running on shutdown. */\n detached: boolean\n /** Context used to build default service envs (bind URLs vs Portless URLs). */\n serviceCtx: ServiceEnvBuildContext\n /** User-supplied env overrides for a logical service (defaults are merged in by each starter). */\n getServiceEnv: <K extends ServiceKey>(k: K) => ServiceEnvByKey[K]\n /** Tracks spawned child processes so the session can kill them on shutdown (nullish entries ignored). */\n pushSpawn: (...procs: (ChildProcess | null | undefined)[]) => void\n /** True once shutdown has been requested; starters use it to bail out gracefully. */\n isShutdownRequested: () => boolean\n /** Resolved ShKeeper configuration (env, ethereum sidecar, build overrides). */\n getShkeeperConfig: () => ShkeeperConfig\n /** Resolved ShKeeper build source (custom GitHub repo/branch, if any). */\n getShkeeperBuild: () => { githubRepo?: string; githubBranch?: string }\n}\n\n/**\n * Builds a {@link ServiceStartContext} from a required `serviceCtx` plus optional overrides. Handy for\n * tests and for the manager, which supplies real `pushSpawn` / config accessors.\n */\nexport function createServiceStartContext(\n options: Partial<ServiceStartContext> & { serviceCtx: ServiceEnvBuildContext },\n): ServiceStartContext {\n return {\n detached: options.detached ?? false,\n serviceCtx: options.serviceCtx,\n getServiceEnv:\n options.getServiceEnv ?? (<K extends ServiceKey>(_k: K) => ({}) as ServiceEnvByKey[K]),\n pushSpawn: options.pushSpawn ?? (() => {}),\n isShutdownRequested: options.isShutdownRequested ?? (() => false),\n getShkeeperConfig: options.getShkeeperConfig ?? (() => ({})),\n getShkeeperBuild: options.getShkeeperBuild ?? (() => ({})),\n }\n}\n","import { getEnv } from \"../env\"\nimport { createContainerVolume, startDockerContainer } from \"../runtime/docker\"\nimport { logError, logSuccess } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/** Starts the Elasticsearch container and resolves once it reports \"started\" (unless reused while detached). */\nexport async function startElastic(ctx: ServiceStartContext): Promise<ChildProcess | null> {\n const name = \"elastic\"\n const dataVolumeName = `etherna_${name}-data-volume`\n await createContainerVolume(dataVolumeName)\n\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const env = {\n ...(getEnv(name, ctx.serviceCtx) ?? {}),\n ...ctx.getServiceEnv(\"elastic\"),\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"elasticsearch:7.17.24\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${dataVolumeName},target=/usr/share/elasticsearch/data`,\n \"--network\",\n \"host\",\n \"--memory=512m\",\n ],\n cmd: [],\n detached: ctx.detached,\n })\n\n if (!proc) {\n logSuccess(name, \"http\", \"9200\")\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n const text = String(data)\n if (/\"message\": \"started\"/gm.test(text)) {\n logSuccess(name, \"http\", \"9200\")\n endPromise?.()\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","import { getEnv } from \"../env\"\nimport { createContainerVolume, startDockerContainer } from \"../runtime/docker\"\nimport { logError, logSuccess } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/** Starts the MongoDB container and resolves once it reports startup complete (unless reused while detached). */\nexport async function startMongo(ctx: ServiceStartContext): Promise<ChildProcess | null> {\n const name = \"etherna-mongodb\"\n const dbVolumeName = `etherna_${name}-db-volume`\n const configDbVolumeName = `etherna_${name}-configdb-volume`\n await Promise.all([\n createContainerVolume(dbVolumeName),\n createContainerVolume(configDbVolumeName),\n ])\n\n let endPromise = undefined as undefined | (() => void)\n const promise = new Promise<void>((res) => {\n endPromise = res\n })\n\n const env = {\n ...(getEnv(name, ctx.serviceCtx) ?? {}),\n ...ctx.getServiceEnv(\"mongo\"),\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"mongo:latest\",\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${dbVolumeName},target=/data/db`,\n \"--mount\",\n `type=volume,source=${configDbVolumeName},target=/data/configdb`,\n \"--network\",\n \"host\",\n ],\n cmd: [],\n detached: ctx.detached,\n })\n\n if (!proc) {\n logSuccess(name, \"mongodb\", \"27017\")\n return null\n }\n ctx.pushSpawn(proc)\n\n const handleStdData = (data: unknown) => {\n const text = String(data)\n if (/mongod startup complete/gm.test(text)) {\n logSuccess(name, \"mongodb\", \"27017\")\n endPromise?.()\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n endPromise?.()\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, `Container closed with code ${code}`)\n endPromise?.()\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n","import { spawn } from \"node:child_process\"\nimport fs from \"node:fs\"\nimport path from \"node:path\"\nimport chalk from \"chalk\"\n\nimport { logError, resolvePath } from \"./utils\"\n\n/** Upstream image when not building from a custom GitHub repo. */\nexport const DEFAULT_SHKEEPER_IMAGE = \"vsyshost/shkeeper:2.5.12\"\nexport const DEFAULT_ETHEREUM_SHKEEPER_IMAGE = \"vsyshost/ethereum-shkeeper:1.2.3\"\n\n/** Default source repo for SHKeeper core when `githubRepo` is not set (still tagged as {@link DEFAULT_SHKEEPER_IMAGE}). */\nexport const DEFAULT_SHKEEPER_GITHUB_REPO = \"vsys-host/shkeeper.io\"\n\n/** Branch or tag to clone when `githubRepo` points at a custom fork (default upstream clone still uses the pinned image tag). */\nexport const DEFAULT_GITHUB_BRANCH = \"main\"\n\nconst CUSTOM_IMAGE_REGISTRY_PREFIX = \"etherna\"\n\nconst GITHUB_REPO_PATTERN = /^[\\w.-]+\\/[\\w.-]+$/\n\nexport function assertValidGithubRepo(repo: string) {\n if (!GITHUB_REPO_PATTERN.test(repo)) {\n throw new Error(`Invalid githubRepo \"${repo}\". Expected \"owner/repo\".`)\n }\n}\n\nexport function parseImageRef(image: string): { repository: string; tag: string } {\n const idx = image.lastIndexOf(\":\")\n if (idx === -1 || image.slice(idx + 1).includes(\"/\")) {\n return { repository: image, tag: \"latest\" }\n }\n return { repository: image.slice(0, idx), tag: image.slice(idx + 1) }\n}\n\n/** When `githubRepo` is set, the built image is tagged under `etherna/…` with the same tag as the default upstream image. */\nexport function resolveShkeeperImageName(githubRepo?: string): string {\n const { tag } = parseImageRef(DEFAULT_SHKEEPER_IMAGE)\n if (!githubRepo) {\n return DEFAULT_SHKEEPER_IMAGE\n }\n return `${CUSTOM_IMAGE_REGISTRY_PREFIX}/shkeeper:${tag}`\n}\n\nexport function resolveEthereumShkeeperImageName(githubRepo?: string): string {\n const { tag } = parseImageRef(DEFAULT_ETHEREUM_SHKEEPER_IMAGE)\n if (!githubRepo) {\n return DEFAULT_ETHEREUM_SHKEEPER_IMAGE\n }\n return `${CUSTOM_IMAGE_REGISTRY_PREFIX}/ethereum-shkeeper:${tag}`\n}\n\nasync function isDockerImageAvailable(imageName: string) {\n const proc = spawn(\"docker\", [\"image\", \"inspect\", imageName])\n\n return await new Promise<boolean>((resolve) => {\n proc.on(\"close\", (code) => {\n resolve(code === 0)\n })\n proc.on(\"error\", () => {\n resolve(false)\n })\n })\n}\n\nasync function runCommandStrict(command: string, args: string[]) {\n const proc = spawn(command, args)\n\n await new Promise<void>((resolve, reject) => {\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new Error(`Command failed: ${command} ${args.join(\" \")}`))\n })\n proc.on(\"error\", reject)\n })\n}\n\nfunction makeTempWorkspace(prefix: string, ref: string) {\n const safeRef = ref.replace(/[^a-z0-9._-]+/gi, \"-\")\n return resolvePath(prefix, `${safeRef}-${Date.now()}`)\n}\n\nasync function acquireGitCloneBuildContext(\n githubRepo: string,\n workspacePrefix: string,\n gitRef: string,\n) {\n const workspaceRoot = makeTempWorkspace(workspacePrefix, gitRef)\n fs.mkdirSync(workspaceRoot, { recursive: true })\n const cloneRoot = path.join(workspaceRoot, \"clone\")\n await runCommandStrict(\"git\", [\n \"clone\",\n \"--depth\",\n \"1\",\n \"--branch\",\n gitRef,\n `https://github.com/${githubRepo}.git`,\n cloneRoot,\n ])\n return {\n cleanupPath: workspaceRoot,\n contextPath: cloneRoot,\n dockerfilePath: path.join(cloneRoot, \"Dockerfile\"),\n }\n}\n\n/**\n * Ensures a local image exists by shallow-cloning `sourceRepo` at `gitRef` and running `docker build`.\n */\nexport async function ensureDockerImageFromGitHub(options: {\n logLabel: string\n imageName: string\n sourceRepo: string\n workspacePrefix: string\n /** Git branch or tag to clone. */\n gitRef: string\n}) {\n const { logLabel, imageName, sourceRepo, workspacePrefix, gitRef } = options\n\n if (await isDockerImageAvailable(imageName)) {\n return\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(logLabel)}: ${chalk.yellow(\n `Building Docker image from GitHub (${sourceRepo}@${gitRef}) (first run may take a while)…`,\n )}`,\n )\n\n const buildContext = await acquireGitCloneBuildContext(sourceRepo, workspacePrefix, gitRef)\n\n const proc = spawn(\"docker\", [\n \"build\",\n \"-t\",\n imageName,\n \"-f\",\n buildContext.dockerfilePath,\n buildContext.contextPath,\n ])\n\n try {\n await new Promise<void>((resolve, reject) => {\n proc.on(\"close\", (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new Error(`Failed to build local Docker image ${imageName}`))\n })\n proc.on(\"error\", reject)\n })\n } catch (error) {\n logError(logLabel, `Failed to build Docker image (${imageName}).`)\n if (buildContext.cleanupPath) {\n throw new Error(\n `Failed to build local Docker image ${imageName}. Inspect cloned source at ${buildContext.contextPath}`,\n { cause: error },\n )\n }\n throw error\n }\n\n console.log(\n ` ${chalk.yellow(\"➜\")} ${chalk.bold(logLabel)}: ${chalk.yellow(\"Finished building Docker image.\")}`,\n )\n\n if (buildContext.cleanupPath) {\n fs.rmSync(buildContext.cleanupPath, { force: true, recursive: true })\n }\n}\n\nfunction resolveGitRefForCustomRepo(githubBranch?: string) {\n const trimmed = githubBranch?.trim()\n return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_GITHUB_BRANCH\n}\n\n/** Builds SHKeeper core from GitHub when the image is missing; uses default upstream repo when `githubRepo` is unset. */\nexport async function ensureShkeeperDockerImage(\n githubRepo?: string,\n githubBranch?: string,\n) {\n const imageName = resolveShkeeperImageName(githubRepo)\n const sourceRepo = githubRepo ?? DEFAULT_SHKEEPER_GITHUB_REPO\n const gitRef = githubRepo\n ? resolveGitRefForCustomRepo(githubBranch)\n : parseImageRef(DEFAULT_SHKEEPER_IMAGE).tag\n await ensureDockerImageFromGitHub({\n logLabel: \"shkeeper\",\n imageName,\n sourceRepo,\n workspacePrefix: \".shkeeper-build\",\n gitRef,\n })\n}\n\n/** When `githubRepo` is set, builds the ethereum adapter from that repo; otherwise relies on pulling the upstream image. */\nexport async function ensureEthereumShkeeperDockerImage(\n githubRepo?: string,\n githubBranch?: string,\n) {\n if (!githubRepo) {\n return\n }\n\n const imageName = resolveEthereumShkeeperImageName(githubRepo)\n const gitRef = resolveGitRefForCustomRepo(githubBranch)\n await ensureDockerImageFromGitHub({\n logLabel: \"ethereum-shkeeper\",\n imageName,\n sourceRepo: githubRepo,\n workspacePrefix: \".ethereum-shkeeper-build\",\n gitRef,\n })\n}\n","import {\n ensureEthereumShkeeperDockerImage,\n ensureShkeeperDockerImage,\n resolveEthereumShkeeperImageName,\n resolveShkeeperImageName,\n} from \"../builder\"\nimport { getEnv } from \"../env\"\nimport { createContainerVolume, startDockerContainer } from \"../runtime/docker\"\nimport { logError, logSuccess } from \"../utils\"\n\nimport type { ServiceStartContext } from \"./context\"\nimport type { ServiceEnvBuildContext, ShkeeperEnv, ShkeeperEthereumEnv } from \"../env\"\nimport type { ChildProcess } from \"node:child_process\"\n\nconst SHKEEPER_NETWORK_NAME = \"etherna_shkeeper_network\"\n\nexport async function startShkeeperCoreContainer({\n context,\n envs,\n build,\n networkName,\n detached = false,\n}: {\n context: ServiceEnvBuildContext\n envs?: ShkeeperEnv\n build: {\n imageName: string\n }\n networkName: string\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const name = \"shkeeper\"\n const instanceVolumeName = \"etherna_shkeeper-instance-volume\"\n await createContainerVolume(instanceVolumeName)\n\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const env = {\n ...(getEnv(\"shkeeper-core\", context) ?? {}),\n ...envs,\n }\n const port = String(getEnv(\"shkeeper\", context)?.port ?? \"32650\")\n const useHostNetwork = networkName === \"host\"\n const listenPort = useHostNetwork ? port : \"5000\"\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName: build.imageName,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--mount\",\n `type=volume,source=${instanceVolumeName},target=/shkeeper.io/instance`,\n \"--network\",\n networkName,\n ...(useHostNetwork ? [] : [\"-p\", `${port}:5000`]),\n ],\n ...(useHostNetwork\n ? {\n cmd: [\n \"bash\",\n \"-c\",\n `gunicorn --access-logfile=- --workers=1 --threads=16 --timeout=600 --bind=0.0.0.0:${port} 'shkeeper:create_app()'`,\n ],\n }\n : {}),\n detached,\n })\n\n if (!proc) {\n logSuccess(name, \"http\", port)\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (new RegExp(`Listening at: http://.+:${listenPort}`, \"gm\").test(text)) {\n ready = true\n logSuccess(name, \"http\", port)\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperEthereumApiContainer({\n context,\n envs,\n networkName,\n imageName,\n detached = false,\n}: {\n context: ServiceEnvBuildContext\n envs?: ShkeeperEthereumEnv\n networkName: string\n imageName: string\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const name = \"ethereum-shkeeper\"\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const env = {\n ...(getEnv(\"ethereum-shkeeper\", context) ?? {}),\n ...envs,\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--network\",\n networkName,\n ],\n cmd: [\n \"bash\",\n \"-c\",\n \"sleep 30 && gunicorn --access-logfile=- --workers=1 --threads=16 --timeout=600 --bind=0.0.0.0:6000 run:server\",\n ],\n detached,\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/Listening at: http:\\/\\/.+:6000/gm.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperMariaDbContainer(\n networkName = SHKEEPER_NETWORK_NAME,\n opts?: { detached?: boolean },\n): Promise<ChildProcess | null> {\n const name = \"ethereum-shkeeper-mariadb\"\n const volumeName = \"etherna_shkeeper-mariadb-volume\"\n await createContainerVolume(volumeName)\n\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"mariadb:10.9.3\",\n args: [\n \"-e\",\n \"MARIADB_ROOT_PASSWORD=shkeeper\",\n \"-e\",\n \"MARIADB_DATABASE=ethereum-shkeeper\",\n \"--mount\",\n `type=volume,source=${volumeName},target=/var/lib/mysql`,\n \"--network\",\n networkName,\n ],\n detached: Boolean(opts?.detached),\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/ready for connections/gim.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperRedisContainer(\n networkName = SHKEEPER_NETWORK_NAME,\n opts?: { detached?: boolean },\n): Promise<ChildProcess | null> {\n const name = \"ethereum-shkeeper-redis\"\n const volumeName = \"etherna_shkeeper-redis-volume\"\n await createContainerVolume(volumeName)\n\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const proc = await startDockerContainer({\n containerName: name,\n imageName: \"redis:7\",\n args: [\"--mount\", `type=volume,source=${volumeName},target=/data`, \"--network\", networkName],\n detached: Boolean(opts?.detached),\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/Ready to accept connections/gm.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\nexport async function startShkeeperEthereumTasksContainer({\n context,\n envs,\n networkName,\n imageName,\n detached = false,\n}: {\n context: ServiceEnvBuildContext\n envs?: ShkeeperEthereumEnv\n networkName: string\n imageName: string\n detached?: boolean\n}): Promise<ChildProcess | null> {\n const name = \"ethereum-tasks\"\n let endPromise = undefined as undefined | (() => void)\n let rejectPromise = undefined as undefined | ((reason?: unknown) => void)\n const promise = new Promise<void>((res, rej) => {\n endPromise = res\n rejectPromise = rej\n })\n\n let lastLog: string | undefined = undefined\n let ready = false\n const env = {\n ...(getEnv(\"ethereum-shkeeper\", context) ?? {}),\n ...envs,\n C_FORCE_ROOT: \"1\",\n }\n\n const proc = await startDockerContainer({\n containerName: name,\n imageName,\n args: [\n ...Object.entries(env).flatMap(([key, value]) => [`-e`, `${key}=${String(value)}`]),\n \"--network\",\n networkName,\n ],\n cmd: [\"bash\", \"-c\", \"sleep 30 && celery -A celery_worker.celery worker --loglevel=info -B\"],\n detached,\n })\n\n if (!proc) {\n endPromise?.()\n return null\n }\n\n const handleStdData = (data: unknown) => {\n lastLog = undefined\n\n const text = String(data)\n if (/ready\\./gim.test(text)) {\n ready = true\n endPromise?.()\n } else {\n lastLog = text\n }\n }\n\n proc.stdout?.on(\"data\", handleStdData)\n proc.stdout?.on(\"error\", (error) => {\n logError(name, \"FATAL: \" + error.message)\n if (!ready) {\n rejectPromise?.(error)\n }\n })\n proc.stderr?.on(\"data\", handleStdData)\n proc.on(\"close\", (code) => {\n logError(name, lastLog || `Container closed with code ${code}`)\n if (!ready) {\n rejectPromise?.(new Error(`Container closed with code ${code}`))\n }\n proc.kill()\n })\n\n await promise\n\n return proc\n}\n\n/**\n * Starts the full ShKeeper stack (mariadb + redis + ethereum adapter API/tasks + shkeeper core) on\n * the host network. Reads build source and env overrides from the shared {@link ServiceStartContext}.\n */\nexport async function startShkeeperStack(\n ctx: ServiceStartContext,\n): Promise<(ChildProcess | null)[]> {\n const context = ctx.serviceCtx\n const detached = ctx.detached\n const config = ctx.getShkeeperConfig()\n const shkeeperBuild = ctx.getShkeeperBuild()\n const build = { imageName: resolveShkeeperImageName(shkeeperBuild.githubRepo) }\n const ethereumGithubRepo = config.ethereum?.githubRepo?.trim() || undefined\n const ethereumGithubBranch = config.ethereum?.githubBranch?.trim() || undefined\n\n const networkName = \"host\"\n const started: (ChildProcess | null)[] = []\n\n try {\n await ensureShkeeperDockerImage(shkeeperBuild.githubRepo, shkeeperBuild.githubBranch)\n await ensureEthereumShkeeperDockerImage(ethereumGithubRepo, ethereumGithubBranch)\n\n const ethereumImageName = resolveEthereumShkeeperImageName(ethereumGithubRepo)\n\n const [mariadb, redis] = await Promise.all([\n startShkeeperMariaDbContainer(networkName, { detached }),\n startShkeeperRedisContainer(networkName, { detached }),\n ])\n started.push(mariadb, redis)\n\n const [ethereumApi, ethereumTasks] = await Promise.all([\n startShkeeperEthereumApiContainer({\n context,\n envs: config.ethereum?.env,\n networkName,\n imageName: ethereumImageName,\n detached,\n }),\n startShkeeperEthereumTasksContainer({\n context,\n envs: config.ethereum?.env,\n networkName,\n imageName: ethereumImageName,\n detached,\n }),\n ])\n started.push(ethereumApi, ethereumTasks)\n\n const shkeeper = await startShkeeperCoreContainer({\n context,\n envs: config.env,\n build,\n networkName,\n detached,\n })\n started.push(shkeeper)\n\n ctx.pushSpawn(...started)\n\n return started\n } catch (error) {\n for (const proc of started) {\n proc?.kill()\n }\n\n throw error\n }\n}\n","import type { EthernaServiceName } from \"./types\"\n\n/** Per-service enabled flags used to decide which containers `stopContainersForEnabled` stops. */\nexport type EnabledServiceMap = Partial<Record<EthernaServiceName, boolean>>\n\n/** Minimal shape session needs from a tracked child process (avoids a `node:child_process` dependency here). */\nexport interface TrackedSpawn {\n kill: () => void\n}\n\nexport interface ShutdownOptions {\n /** Exits the process after shutdown work completes. Defaults to `false`. */\n exitProcess?: boolean\n /** Bypasses the shutdown-in-progress guard and the blockchain-settle wait (used for a forced second Ctrl+C). Defaults to `false`. */\n force?: boolean\n /** Kills tracked spawns. Defaults to `!detached` (i.e. `true` when attached, `false` when detached). */\n killTrackedSpawns?: boolean\n}\n\nexport interface CreateSessionOptions {\n /**\n * When `true`, reuse already-running containers and leave them (and the portless proxy)\n * running on shutdown. Resolve this before calling `createSession` (see `resolveDetachedMode`).\n */\n detached: boolean\n /** Per-service enabled flags, passed through to `stopContainersForEnabled` as-is. */\n enabledServices: EnabledServiceMap\n /** Stops the Docker containers for `enabledServices`. Only called when not detached. */\n stopContainersForEnabled: (enabled: EnabledServiceMap) => Promise<void>\n /** Registers a Portless alias for `name` -> `port`. Defaults to a no-op (wired to `src/portless.ts` by the caller). */\n addPortlessAlias?: (name: string, port: unknown) => Promise<void>\n /** Removes previously-registered Portless aliases. Defaults to a no-op. */\n removePortlessAliases?: (names: string[]) => Promise<void>\n /** Stops the Portless proxy this session started. Defaults to a no-op. */\n stopPortlessProxy?: () => Promise<void>\n /** True while a blockchain bootstrap is in flight; shutdown waits for it to settle first. Defaults to `() => false`. */\n isBlockchainBootstrapInProgress?: () => boolean\n /** Resolves once an in-progress blockchain bootstrap reaches a safe shutdown point. Defaults to a no-op. */\n waitForBlockchainBootstrapToSettle?: () => Promise<void>\n /** Called once, before awaiting `waitForBlockchainBootstrapToSettle`, e.g. to log a warning. Defaults to a no-op. */\n onBlockchainShutdownWait?: () => void\n /** Injectable `process.exit` stand-in, called with `0` when `shutdown({ exitProcess: true })`. Defaults to `process.exit`. */\n exitProcess?: (code: number) => void\n}\n\nexport interface EthernaSession {\n isShutdownRequested: () => boolean\n pushSpawn: (...procs: TrackedSpawn[]) => void\n killSpawns: () => void\n getDetached: () => boolean\n setPortlessProxyStartedByUs: (started: boolean) => void\n recordPortlessAlias: (name: string, port: unknown) => Promise<void>\n cleanupPortless: () => Promise<void>\n shutdown: (opts?: ShutdownOptions) => Promise<void>\n installSignalHandlers: () => void\n}\n\n/**\n * Owns a Vite/CLI run's spawn tracking, Portless bookkeeping, and shutdown/signal-handling logic.\n * Ported from `harnessEthernaPlugin` in `src/plugin-define.ts`, consolidated so `shutdown` also\n * stops enabled containers (the caller no longer needs to do that separately before shutting down).\n */\nexport function createSession(options: CreateSessionOptions): EthernaSession {\n const detached = options.detached\n const spawns: TrackedSpawn[] = []\n let portlessProxyStartedByUs = false\n const portlessAliasesRegistered: string[] = []\n let shutdownRequested = false\n let shutdownInProgress = false\n\n const isBlockchainBootstrapInProgress = options.isBlockchainBootstrapInProgress ?? (() => false)\n const waitForBlockchainBootstrapToSettle =\n options.waitForBlockchainBootstrapToSettle ?? (() => Promise.resolve())\n const onBlockchainShutdownWait = options.onBlockchainShutdownWait ?? (() => {})\n const addPortlessAlias = options.addPortlessAlias ?? (async () => {})\n const removePortlessAliases = options.removePortlessAliases ?? (async () => {})\n const stopPortlessProxy = options.stopPortlessProxy ?? (async () => {})\n const exitProcess = options.exitProcess ?? ((code: number) => process.exit(code))\n\n const getDetached = () => detached\n\n const pushSpawn = (...procs: TrackedSpawn[]) => {\n spawns.push(...procs)\n }\n\n const killSpawns = () => {\n for (const proc of spawns) {\n proc.kill()\n }\n }\n\n const setPortlessProxyStartedByUs = (started: boolean) => {\n portlessProxyStartedByUs = started\n }\n\n const recordPortlessAlias = async (name: string, port: unknown) => {\n await addPortlessAlias(name, port)\n portlessAliasesRegistered.push(name)\n }\n\n const cleanupPortless = async () => {\n if (detached) {\n return\n }\n if (portlessAliasesRegistered.length > 0) {\n await removePortlessAliases([...portlessAliasesRegistered])\n portlessAliasesRegistered.length = 0\n }\n if (portlessProxyStartedByUs) {\n await stopPortlessProxy()\n }\n portlessProxyStartedByUs = false\n }\n\n const shutdown = async (opts?: ShutdownOptions) => {\n shutdownRequested = true\n const force = opts?.force ?? false\n\n if (shutdownInProgress && !force) {\n return\n }\n shutdownInProgress = true\n\n if (!force && isBlockchainBootstrapInProgress()) {\n onBlockchainShutdownWait()\n await waitForBlockchainBootstrapToSettle()\n }\n\n if (!detached) {\n await options.stopContainersForEnabled(options.enabledServices)\n }\n\n await cleanupPortless()\n\n const killTracked = opts?.killTrackedSpawns ?? !detached\n if (killTracked) {\n killSpawns()\n }\n\n if (opts?.exitProcess) {\n exitProcess(0)\n }\n }\n\n const installSignalHandlers = () => {\n process.on(\"SIGINT\", () => {\n process.stdin.resume()\n void (async () => {\n await shutdown({ exitProcess: true, force: shutdownRequested })\n })()\n })\n process.on(\"SIGTERM\", () => {\n void (async () => {\n await shutdown({ force: shutdownRequested })\n })()\n })\n }\n\n return {\n isShutdownRequested: () => shutdownRequested,\n pushSpawn,\n killSpawns,\n getDetached,\n setPortlessProxyStartedByUs,\n recordPortlessAlias,\n cleanupPortless,\n shutdown,\n installSignalHandlers,\n }\n}\n","import chalk from \"chalk\"\n\nimport { ALL_SERVICE_NAMES, SERVICE_CATALOG, type StartupCode } from \"./catalog\"\nimport { createDependencyRunner, type DependencyRunnerServiceDefinition } from \"./dependency-runner\"\nimport {\n buildServiceEnvs,\n defaultServiceEnvBuildContext,\n getEnv,\n parsePortFromAspNetCoreUrls,\n type ServiceEnvBuildContext,\n} from \"./env\"\nimport {\n addPortlessAlias,\n ensurePortlessProxy,\n getPortlessPublicUrl,\n isPortlessCliAvailable,\n normalizePortlessAppPublicUrl,\n PORTLESS_URL_ENV,\n removePortlessAliases,\n stopPortlessProxy,\n type PortlessServiceAlias,\n} from \"./portless\"\nimport { resolveStartPlan } from \"./resolve-options\"\nimport { ensureDockerReady } from \"./runtime/docker\"\nimport { stopEnabled, stopLogicalServices } from \"./runtime/names\"\nimport { startAspContainer } from \"./services/asp\"\nimport {\n isBlockchainBootstrapInProgress,\n startBeeNodes,\n startBlockchain,\n waitForBlockchainBootstrapToSettle,\n} from \"./services/bee\"\nimport {\n createServiceStartContext,\n type ServiceEnvByKey,\n type ServiceKey,\n} from \"./services/context\"\nimport { startElastic } from \"./services/elastic\"\nimport { startMongo } from \"./services/mongo\"\nimport { startShkeeperStack } from \"./services/shkeeper\"\nimport { createSession } from \"./session\"\nimport { fetchFirstShkeeperWalletApiKey, getEnvVar, logError } from \"./utils\"\n\nimport type {\n EthernaServiceName,\n EthernaSessionHandle,\n ShkeeperConfig,\n StartOptions,\n} from \"./types\"\nimport type { ChildProcess } from \"node:child_process\"\n\n/**\n * Stops the Docker container groups for the named logical service(s). Multi-container services stop\n * as a whole group and overlapping groups are de-duplicated (see {@link containerNamesFor}).\n * Throws a `TypeError` (listing valid names) for any unknown service name.\n */\nexport async function stop(services: EthernaServiceName | EthernaServiceName[]): Promise<void> {\n const names = Array.isArray(services) ? services : [services]\n for (const name of names) {\n if (!ALL_SERVICE_NAMES.includes(name)) {\n throw new TypeError(\n `Unknown Etherna service \"${String(name)}\". Valid services: ${ALL_SERVICE_NAMES.join(\", \")}.`,\n )\n }\n }\n await stopLogicalServices(names)\n}\n\n/** Reads per-service env overrides from a `StartOptions` service value (`boolean | { env }`). */\nfunction readServiceEnv<K extends ServiceKey>(value: StartOptions[K]): ServiceEnvByKey[K] {\n return typeof value === \"object\" && value !== null\n ? ((value.env ?? {}) as ServiceEnvByKey[K])\n : ({} as ServiceEnvByKey[K])\n}\n\n/** Resolves the ShKeeper configuration object from `StartOptions.shkeeper` (`true | { … }`). */\nfunction readShkeeperConfig(value: StartOptions[\"shkeeper\"]): ShkeeperConfig {\n if (value === true) {\n return {}\n }\n return typeof value === \"object\" && value !== null ? value : {}\n}\n\n/**\n * Starts the enabled Etherna services following the canonical dependency graph\n * ({@link SERVICE_CATALOG}), wiring a {@link createSession} for spawn tracking, Portless bookkeeping,\n * and shutdown. On a startup failure with `onFailure: \"stop\"`, stops the Docker containers for every\n * enabled service in this run — even when detached — before shutting the session down.\n *\n * Detached mode defaults to `false` unless `options.detached` or `ETHERNA_DETACHED` is set (matches\n * the Vite plugin). The CLI passes `detached: true` by default separately.\n */\nexport async function start(options: StartOptions = {}): Promise<EthernaSessionHandle> {\n const plan = resolveStartPlan(options)\n\n await ensureDockerReady()\n\n const portlessAppPublicUrl = getEnvVar(PORTLESS_URL_ENV)?.trim()\n const appPort = plan.appPort ?? defaultServiceEnvBuildContext(plan.mode).appPort\n const serviceCtx: ServiceEnvBuildContext = {\n mode: plan.mode,\n portless: plan.portless,\n appPort,\n ...(plan.portless && portlessAppPublicUrl\n ? { portlessAppPublicUrl: normalizePortlessAppPublicUrl(portlessAppPublicUrl) }\n : {}),\n }\n\n const session = createSession({\n detached: plan.detached,\n enabledServices: plan.enabled,\n stopContainersForEnabled: stopEnabled,\n addPortlessAlias: (name, port) => addPortlessAlias(name as PortlessServiceAlias, port),\n removePortlessAliases: (names) => removePortlessAliases(names as PortlessServiceAlias[]),\n stopPortlessProxy,\n isBlockchainBootstrapInProgress,\n waitForBlockchainBootstrapToSettle,\n onBlockchainShutdownWait: () => {\n console.log(\n chalk.yellow(\n ` ➜ ${chalk.bold(\"etherna-blockchain\")}: Shutdown requested during blockchain initialization. Waiting for a safe shutdown point. Press Ctrl+C again to force exit.`,\n ),\n )\n },\n })\n\n if (options.installSignalHandlers !== false) {\n session.installSignalHandlers()\n }\n\n if (plan.portless) {\n await setupPortless(session, serviceCtx, portlessAppPublicUrl)\n }\n // Built once for Portless alias port lookups (only needed when portless is on).\n const builtEnvs = plan.portless ? buildServiceEnvs(serviceCtx) : undefined\n\n const getServiceEnv = <K extends ServiceKey>(key: K): ServiceEnvByKey[K] =>\n readServiceEnv<K>(options[key])\n\n const serviceStartCtx = createServiceStartContext({\n detached: plan.detached,\n serviceCtx,\n getServiceEnv,\n pushSpawn: (...procs) => {\n session.pushSpawn(...procs.filter((p): p is ChildProcess => p != null))\n },\n isShutdownRequested: () => session.isShutdownRequested(),\n getShkeeperConfig: () => readShkeeperConfig(options.shkeeper),\n getShkeeperBuild: () => {\n const build = readShkeeperConfig(options.shkeeper).build\n return {\n githubRepo: build?.githubRepo?.trim() || undefined,\n githubBranch: build?.githubBranch?.trim() || undefined,\n }\n },\n })\n\n const runStartup = async (fn: () => Promise<unknown>): Promise<boolean> => {\n try {\n await fn()\n return !session.isShutdownRequested()\n } catch (error) {\n if (session.isShutdownRequested()) {\n return false\n }\n throw error\n }\n }\n\n const startCredit = async () => {\n let creditEnv = getServiceEnv(\"credit\")\n if (plan.enabled.shkeeper) {\n const apiKey = await fetchFirstShkeeperWalletApiKey()\n if (apiKey) {\n creditEnv = { ...creditEnv, \"Payments:ShKeeper:ApiKey\": apiKey }\n }\n }\n await startAspContainer(\n serviceStartCtx,\n \"etherna-credit\",\n \"etherna/etherna-credit:latest\",\n creditEnv,\n )\n }\n\n const startupByCode: Record<StartupCode, () => Promise<boolean>> = {\n \"bee-blockchain\": () => runStartup(() => startBlockchain(serviceStartCtx)),\n \"bee-nodes\": () => runStartup(() => startBeeNodes(serviceStartCtx)),\n shkeeper: () => runStartup(() => startShkeeperStack(serviceStartCtx)),\n mongo: () => runStartup(() => startMongo(serviceStartCtx)),\n sso: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-sso\",\n \"etherna/etherna-sso:latest\",\n getServiceEnv(\"sso\"),\n ),\n ),\n index: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-index\",\n \"etherna/etherna-index:latest\",\n getServiceEnv(\"index\"),\n ),\n ),\n beehive: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-beehive\",\n \"etherna/beehive:latest\",\n getServiceEnv(\"beehive\"),\n ),\n ),\n gateway: () =>\n runStartup(() =>\n startAspContainer(\n serviceStartCtx,\n \"etherna-gateway\",\n \"etherna/etherna-gateway:latest\",\n getServiceEnv(\"gateway\"),\n ),\n ),\n credit: () => runStartup(startCredit),\n elastic: () => runStartup(() => startElastic(serviceStartCtx)),\n }\n\n // Portless alias registration, mirroring the Vite plugin: registered in each node's\n // `beforeStartup` so the alias exists before the container's URL is announced.\n const portlessAliasByCode: Partial<Record<StartupCode, () => Promise<void>>> = plan.portless\n ? {\n \"bee-blockchain\": async () => {\n const beeBase = getEnv(\"etherna-bee\", serviceCtx) ?? {}\n await session.recordPortlessAlias(\n \"bee\",\n { ...beeBase, ...getServiceEnv(\"bee\") }.BEE_PORT ?? 1633,\n )\n },\n shkeeper: async () => {\n await session.recordPortlessAlias(\"shkeeper\", getEnv(\"shkeeper\", serviceCtx).port)\n },\n sso: async () => {\n await session.recordPortlessAlias(\n \"sso\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-sso\"].ASPNETCORE_URLS)),\n )\n },\n index: async () => {\n await session.recordPortlessAlias(\n \"index\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-index\"].ASPNETCORE_URLS)),\n )\n },\n beehive: async () => {\n await session.recordPortlessAlias(\n \"beehive\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-beehive\"].ASPNETCORE_URLS)),\n )\n },\n gateway: async () => {\n await session.recordPortlessAlias(\n \"gateway\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-gateway\"].ASPNETCORE_URLS)),\n )\n },\n credit: async () => {\n await session.recordPortlessAlias(\n \"credit\",\n parsePortFromAspNetCoreUrls(String(builtEnvs?.[\"etherna-credit\"].ASPNETCORE_URLS)),\n )\n },\n }\n : {}\n\n const codes = Object.keys(SERVICE_CATALOG) as StartupCode[]\n const definitions: DependencyRunnerServiceDefinition<StartupCode>[] = codes.map((code) => {\n const node = SERVICE_CATALOG[code]\n const beforeStartup = portlessAliasByCode[code]\n return {\n code,\n dependencies: node.dependencies,\n enabled: plan.enabled[node.service],\n onFailure: node.onFailure,\n startupCallback: startupByCode[code],\n ...(beforeStartup ? { beforeStartup } : {}),\n }\n })\n\n const runner = createDependencyRunner(definitions, { logError })\n const result = await runner.start()\n\n if (result.shouldStop && !session.isShutdownRequested()) {\n // Stop containers for every enabled service in this run — required even when detached, since\n // `session.shutdown` only stops containers when attached (see design doc / Task 3 note).\n await stopEnabled(plan.enabled)\n await session.shutdown({ killTrackedSpawns: true })\n }\n\n return { shutdown: (opts) => session.shutdown(opts) }\n}\n\n/** Fail-fast Portless bootstrap: verify the CLI, start the proxy, register the app alias. */\nasync function setupPortless(\n session: ReturnType<typeof createSession>,\n serviceCtx: ServiceEnvBuildContext,\n portlessAppPublicUrl: string | undefined,\n): Promise<void> {\n if (!(await isPortlessCliAvailable())) {\n console.error(\n chalk.red(\n ` portless: CLI not found. Install globally (recommended): npm install -g portless`,\n ),\n )\n process.exit(1)\n }\n\n try {\n const { startedByUs } = await ensurePortlessProxy()\n session.setPortlessProxyStartedByUs(startedByUs)\n } catch (e) {\n console.error(\n chalk.red(` portless: failed to start proxy: ${e instanceof Error ? e.message : String(e)}`),\n )\n process.exit(1)\n }\n\n if (!portlessAppPublicUrl) {\n try {\n await session.recordPortlessAlias(\"app\", serviceCtx.appPort)\n } catch (e) {\n console.error(\n chalk.red(\n ` portless: failed to register aliases: ${e instanceof Error ? e.message : String(e)}`,\n ),\n )\n await session.cleanupPortless()\n process.exit(1)\n }\n }\n\n const appUrl =\n portlessAppPublicUrl != null && portlessAppPublicUrl !== \"\"\n ? `${normalizePortlessAppPublicUrl(portlessAppPublicUrl)}/`\n : `${getPortlessPublicUrl(\"app\")}/`\n console.log(chalk.green(` ➜ ${chalk.bold(\"app (portless)\")}: ${chalk.cyan(appUrl)}`))\n}\n"],"x_google_ignoreList":[0,1,2,3],"mappings":"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"}
|