moonwall 1.0.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +681 -0
- package/README.md +54 -0
- package/config_schema.json +811 -0
- package/dist/api/constants/accounts.d.ts +36 -0
- package/dist/api/constants/accounts.d.ts.map +1 -0
- package/dist/api/constants/accounts.js +67 -0
- package/dist/api/constants/chain.d.ts +134 -0
- package/dist/api/constants/chain.d.ts.map +1 -0
- package/dist/api/constants/chain.js +149 -0
- package/dist/api/constants/index.d.ts +4 -0
- package/dist/api/constants/index.d.ts.map +1 -0
- package/dist/api/constants/index.js +3 -0
- package/dist/api/constants/smartContract.d.ts +29 -0
- package/dist/api/constants/smartContract.d.ts.map +1 -0
- package/dist/api/constants/smartContract.js +118 -0
- package/dist/api/testing/blocks.d.ts +59 -0
- package/dist/api/testing/blocks.d.ts.map +1 -0
- package/dist/api/testing/blocks.js +147 -0
- package/dist/api/testing/contracts.d.ts +5 -0
- package/dist/api/testing/contracts.d.ts.map +1 -0
- package/dist/api/testing/contracts.js +32 -0
- package/dist/api/testing/ethers.d.ts +3 -0
- package/dist/api/testing/ethers.d.ts.map +1 -0
- package/dist/api/testing/ethers.js +38 -0
- package/dist/api/testing/events.d.ts +12 -0
- package/dist/api/testing/events.d.ts.map +1 -0
- package/dist/api/testing/events.js +23 -0
- package/dist/api/testing/extrinsics.d.ts +5 -0
- package/dist/api/testing/extrinsics.d.ts.map +1 -0
- package/dist/api/testing/extrinsics.js +10 -0
- package/dist/api/testing/index.d.ts +9 -0
- package/dist/api/testing/index.d.ts.map +1 -0
- package/dist/api/testing/index.js +8 -0
- package/dist/api/testing/jumping.d.ts +8 -0
- package/dist/api/testing/jumping.d.ts.map +1 -0
- package/dist/api/testing/jumping.js +78 -0
- package/dist/api/testing/providers.d.ts +18 -0
- package/dist/api/testing/providers.d.ts.map +1 -0
- package/dist/api/testing/providers.js +34 -0
- package/dist/api/testing/viem.d.ts +139 -0
- package/dist/api/testing/viem.d.ts.map +1 -0
- package/dist/api/testing/viem.js +247 -0
- package/dist/api/types/config.d.ts +609 -0
- package/dist/api/types/config.d.ts.map +1 -0
- package/dist/api/types/config.js +1 -0
- package/dist/api/types/context.d.ts +125 -0
- package/dist/api/types/context.d.ts.map +1 -0
- package/dist/api/types/context.js +1 -0
- package/dist/api/types/contracts.d.ts +66 -0
- package/dist/api/types/contracts.d.ts.map +1 -0
- package/dist/api/types/contracts.js +1 -0
- package/dist/api/types/eth.d.ts +3 -0
- package/dist/api/types/eth.d.ts.map +1 -0
- package/dist/api/types/eth.js +1 -0
- package/dist/api/types/foundations.d.ts +11 -0
- package/dist/api/types/foundations.d.ts.map +1 -0
- package/dist/api/types/foundations.js +1 -0
- package/dist/api/types/helpers.d.ts +7 -0
- package/dist/api/types/helpers.d.ts.map +1 -0
- package/dist/api/types/helpers.js +1 -0
- package/dist/api/types/index.d.ts +8 -0
- package/dist/api/types/index.d.ts.map +1 -0
- package/dist/api/types/index.js +7 -0
- package/dist/api/types/runner.d.ts +490 -0
- package/dist/api/types/runner.d.ts.map +1 -0
- package/dist/api/types/runner.js +1 -0
- package/dist/cli/cmds/components/LogViewer.d.ts +17 -0
- package/dist/cli/cmds/components/LogViewer.d.ts.map +1 -0
- package/dist/cli/cmds/components/LogViewer.js +171 -0
- package/dist/cli/cmds/entrypoint.d.ts +6 -0
- package/dist/cli/cmds/entrypoint.d.ts.map +1 -0
- package/dist/cli/cmds/entrypoint.js +192 -0
- package/dist/cli/cmds/interactiveCmds/chopsticksIntCmds.d.ts +2 -0
- package/dist/cli/cmds/interactiveCmds/chopsticksIntCmds.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/chopsticksIntCmds.js +117 -0
- package/dist/cli/cmds/interactiveCmds/devIntCmds.d.ts +2 -0
- package/dist/cli/cmds/interactiveCmds/devIntCmds.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/devIntCmds.js +103 -0
- package/dist/cli/cmds/interactiveCmds/index.d.ts +4 -0
- package/dist/cli/cmds/interactiveCmds/index.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/index.js +3 -0
- package/dist/cli/cmds/interactiveCmds/zombieIntCmds.d.ts +2 -0
- package/dist/cli/cmds/interactiveCmds/zombieIntCmds.d.ts.map +1 -0
- package/dist/cli/cmds/interactiveCmds/zombieIntCmds.js +32 -0
- package/dist/cli/cmds/main.d.ts +2 -0
- package/dist/cli/cmds/main.d.ts.map +1 -0
- package/dist/cli/cmds/main.js +336 -0
- package/dist/cli/cmds/runNetwork.d.ts +3 -0
- package/dist/cli/cmds/runNetwork.d.ts.map +1 -0
- package/dist/cli/cmds/runNetwork.js +292 -0
- package/dist/cli/cmds/runTests.d.ts +12 -0
- package/dist/cli/cmds/runTests.d.ts.map +1 -0
- package/dist/cli/cmds/runTests.js +257 -0
- package/dist/cli/internal/cmdFunctions/downloader.d.ts +4 -0
- package/dist/cli/internal/cmdFunctions/downloader.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/downloader.js +49 -0
- package/dist/cli/internal/cmdFunctions/fetchArtifact.d.ts +10 -0
- package/dist/cli/internal/cmdFunctions/fetchArtifact.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/fetchArtifact.js +145 -0
- package/dist/cli/internal/cmdFunctions/index.d.ts +5 -0
- package/dist/cli/internal/cmdFunctions/index.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/index.js +4 -0
- package/dist/cli/internal/cmdFunctions/initialisation.d.ts +20 -0
- package/dist/cli/internal/cmdFunctions/initialisation.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/initialisation.js +150 -0
- package/dist/cli/internal/cmdFunctions/tempLogs.d.ts +3 -0
- package/dist/cli/internal/cmdFunctions/tempLogs.d.ts.map +1 -0
- package/dist/cli/internal/cmdFunctions/tempLogs.js +37 -0
- package/dist/cli/internal/commandParsers.d.ts +59 -0
- package/dist/cli/internal/commandParsers.d.ts.map +1 -0
- package/dist/cli/internal/commandParsers.js +305 -0
- package/dist/cli/internal/deriveTestIds.d.ts +8 -0
- package/dist/cli/internal/deriveTestIds.d.ts.map +1 -0
- package/dist/cli/internal/deriveTestIds.js +123 -0
- package/dist/cli/internal/effect/index.d.ts +6 -0
- package/dist/cli/internal/effect/index.d.ts.map +1 -0
- package/dist/cli/internal/effect/index.js +5 -0
- package/dist/cli/internal/fileCheckers.d.ts +11 -0
- package/dist/cli/internal/fileCheckers.d.ts.map +1 -0
- package/dist/cli/internal/fileCheckers.js +165 -0
- package/dist/cli/internal/foundations/index.d.ts +4 -0
- package/dist/cli/internal/foundations/index.d.ts.map +1 -0
- package/dist/cli/internal/foundations/index.js +4 -0
- package/dist/cli/internal/index.d.ts +12 -0
- package/dist/cli/internal/index.d.ts.map +1 -0
- package/dist/cli/internal/index.js +11 -0
- package/dist/cli/internal/launcherCommon.d.ts +4 -0
- package/dist/cli/internal/launcherCommon.d.ts.map +1 -0
- package/dist/cli/internal/launcherCommon.js +130 -0
- package/dist/cli/internal/localNode.d.ts +16 -0
- package/dist/cli/internal/localNode.d.ts.map +1 -0
- package/dist/cli/internal/localNode.js +362 -0
- package/dist/cli/internal/logging.d.ts +2 -0
- package/dist/cli/internal/logging.d.ts.map +1 -0
- package/dist/cli/internal/logging.js +26 -0
- package/dist/cli/internal/node.d.ts +33 -0
- package/dist/cli/internal/node.d.ts.map +1 -0
- package/dist/cli/internal/node.js +228 -0
- package/dist/cli/internal/processHelpers.d.ts +17 -0
- package/dist/cli/internal/processHelpers.d.ts.map +1 -0
- package/dist/cli/internal/processHelpers.js +56 -0
- package/dist/cli/internal/providerFactories.d.ts +48 -0
- package/dist/cli/internal/providerFactories.d.ts.map +1 -0
- package/dist/cli/internal/providerFactories.js +442 -0
- package/dist/cli/internal/testIdParser.d.ts +34 -0
- package/dist/cli/internal/testIdParser.d.ts.map +1 -0
- package/dist/cli/internal/testIdParser.js +167 -0
- package/dist/cli/lib/binariesHelpers.d.ts +15 -0
- package/dist/cli/lib/binariesHelpers.d.ts.map +1 -0
- package/dist/cli/lib/binariesHelpers.js +99 -0
- package/dist/cli/lib/configReader.d.ts +8 -0
- package/dist/cli/lib/configReader.d.ts.map +1 -0
- package/dist/cli/lib/configReader.js +115 -0
- package/dist/cli/lib/contractFunctions.d.ts +2 -0
- package/dist/cli/lib/contractFunctions.d.ts.map +1 -0
- package/dist/cli/lib/contractFunctions.js +2 -0
- package/dist/cli/lib/globalContext.d.ts +46 -0
- package/dist/cli/lib/globalContext.d.ts.map +1 -0
- package/dist/cli/lib/globalContext.js +710 -0
- package/dist/cli/lib/governanceProcedures.d.ts +27 -0
- package/dist/cli/lib/governanceProcedures.d.ts.map +1 -0
- package/dist/cli/lib/governanceProcedures.js +458 -0
- package/dist/cli/lib/handlers/index.d.ts +5 -0
- package/dist/cli/lib/handlers/index.d.ts.map +1 -0
- package/dist/cli/lib/handlers/index.js +5 -0
- package/dist/cli/lib/repoDefinitions/index.d.ts +6 -0
- package/dist/cli/lib/repoDefinitions/index.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/index.js +21 -0
- package/dist/cli/lib/repoDefinitions/moonbeam.d.ts +4 -0
- package/dist/cli/lib/repoDefinitions/moonbeam.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/moonbeam.js +30 -0
- package/dist/cli/lib/repoDefinitions/polkadot.d.ts +4 -0
- package/dist/cli/lib/repoDefinitions/polkadot.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/polkadot.js +11 -0
- package/dist/cli/lib/repoDefinitions/tanssi.d.ts +4 -0
- package/dist/cli/lib/repoDefinitions/tanssi.d.ts.map +1 -0
- package/dist/cli/lib/repoDefinitions/tanssi.js +14 -0
- package/dist/cli/lib/rpcFunctions.d.ts +2 -0
- package/dist/cli/lib/rpcFunctions.d.ts.map +1 -0
- package/dist/cli/lib/rpcFunctions.js +26 -0
- package/dist/cli/lib/runnerContext.d.ts +32 -0
- package/dist/cli/lib/runnerContext.d.ts.map +1 -0
- package/dist/cli/lib/runnerContext.js +156 -0
- package/dist/cli/lib/shardManager.d.ts +40 -0
- package/dist/cli/lib/shardManager.d.ts.map +1 -0
- package/dist/cli/lib/shardManager.js +80 -0
- package/dist/cli/lib/upgradeProcedures.d.ts +5 -0
- package/dist/cli/lib/upgradeProcedures.d.ts.map +1 -0
- package/dist/cli/lib/upgradeProcedures.js +221 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3 -0
- package/dist/contracts/contractInteraction.d.ts +17 -0
- package/dist/contracts/contractInteraction.d.ts.map +1 -0
- package/dist/contracts/contractInteraction.js +170 -0
- package/dist/contracts/index.d.ts +2 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/foundations/chopsticks/handler.d.ts +3 -0
- package/dist/foundations/chopsticks/handler.d.ts.map +1 -0
- package/dist/foundations/chopsticks/handler.js +93 -0
- package/dist/foundations/chopsticks/helpers.d.ts +27 -0
- package/dist/foundations/chopsticks/helpers.d.ts.map +1 -0
- package/dist/foundations/chopsticks/helpers.js +133 -0
- package/dist/foundations/dev/handler.d.ts +3 -0
- package/dist/foundations/dev/handler.d.ts.map +1 -0
- package/dist/foundations/dev/handler.js +136 -0
- package/dist/foundations/dev/helpers.d.ts +27 -0
- package/dist/foundations/dev/helpers.d.ts.map +1 -0
- package/dist/foundations/dev/helpers.js +161 -0
- package/dist/foundations/read-only/handler.d.ts +3 -0
- package/dist/foundations/read-only/handler.d.ts.map +1 -0
- package/dist/foundations/read-only/handler.js +32 -0
- package/dist/foundations/zombie/handler.d.ts +3 -0
- package/dist/foundations/zombie/handler.d.ts.map +1 -0
- package/dist/foundations/zombie/handler.js +92 -0
- package/dist/foundations/zombie/helpers.d.ts +16 -0
- package/dist/foundations/zombie/helpers.d.ts.map +1 -0
- package/dist/foundations/zombie/helpers.js +97 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47 -0
- package/dist/internal/common.d.ts +3 -0
- package/dist/internal/common.d.ts.map +1 -0
- package/dist/internal/common.js +41 -0
- package/dist/internal/index.d.ts +4 -0
- package/dist/internal/index.d.ts.map +1 -0
- package/dist/internal/index.js +3 -0
- package/dist/internal/logger.d.ts +24 -0
- package/dist/internal/logger.d.ts.map +1 -0
- package/dist/internal/logger.js +66 -0
- package/dist/internal/logging.d.ts +7 -0
- package/dist/internal/logging.d.ts.map +1 -0
- package/dist/internal/logging.js +36 -0
- package/dist/moondebug.d.ts +3 -0
- package/dist/moondebug.d.ts.map +1 -0
- package/dist/moondebug.js +2 -0
- package/dist/services/cache/FileLock.d.ts +11 -0
- package/dist/services/cache/FileLock.d.ts.map +1 -0
- package/dist/services/cache/FileLock.js +68 -0
- package/dist/services/cache/StartupCacheService.d.ts +23 -0
- package/dist/services/cache/StartupCacheService.d.ts.map +1 -0
- package/dist/services/cache/StartupCacheService.js +159 -0
- package/dist/services/cache/index.d.ts +3 -0
- package/dist/services/cache/index.d.ts.map +1 -0
- package/dist/services/cache/index.js +2 -0
- package/dist/services/chopsticks/ChopsticksMultiChain.d.ts +158 -0
- package/dist/services/chopsticks/ChopsticksMultiChain.d.ts.map +1 -0
- package/dist/services/chopsticks/ChopsticksMultiChain.js +282 -0
- package/dist/services/chopsticks/ChopsticksService.d.ts +313 -0
- package/dist/services/chopsticks/ChopsticksService.d.ts.map +1 -0
- package/dist/services/chopsticks/ChopsticksService.js +77 -0
- package/dist/services/chopsticks/chopsticksConfigParser.d.ts +40 -0
- package/dist/services/chopsticks/chopsticksConfigParser.d.ts.map +1 -0
- package/dist/services/chopsticks/chopsticksConfigParser.js +201 -0
- package/dist/services/chopsticks/index.d.ts +5 -0
- package/dist/services/chopsticks/index.d.ts.map +1 -0
- package/dist/services/chopsticks/index.js +4 -0
- package/dist/services/chopsticks/launchChopsticksEffect.d.ts +225 -0
- package/dist/services/chopsticks/launchChopsticksEffect.d.ts.map +1 -0
- package/dist/services/chopsticks/launchChopsticksEffect.js +623 -0
- package/dist/services/config/configAccessors.d.ts +41 -0
- package/dist/services/config/configAccessors.d.ts.map +1 -0
- package/dist/services/config/configAccessors.js +149 -0
- package/dist/services/config/index.d.ts +2 -0
- package/dist/services/config/index.d.ts.map +1 -0
- package/dist/services/config/index.js +1 -0
- package/dist/services/errors.d.ts +72 -0
- package/dist/services/errors.d.ts.map +1 -0
- package/dist/services/errors.js +31 -0
- package/dist/services/index.d.ts +7 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +6 -0
- package/dist/services/network/NodeReadinessService.d.ts +35 -0
- package/dist/services/network/NodeReadinessService.d.ts.map +1 -0
- package/dist/services/network/NodeReadinessService.js +120 -0
- package/dist/services/network/PortDiscoveryService.d.ts +22 -0
- package/dist/services/network/PortDiscoveryService.d.ts.map +1 -0
- package/dist/services/network/PortDiscoveryService.js +77 -0
- package/dist/services/network/RpcPortDiscoveryService.d.ts +25 -0
- package/dist/services/network/RpcPortDiscoveryService.d.ts.map +1 -0
- package/dist/services/network/RpcPortDiscoveryService.js +136 -0
- package/dist/services/network/index.d.ts +4 -0
- package/dist/services/network/index.d.ts.map +1 -0
- package/dist/services/network/index.js +3 -0
- package/dist/services/process/ProcessManagerService.d.ts +49 -0
- package/dist/services/process/ProcessManagerService.d.ts.map +1 -0
- package/dist/services/process/ProcessManagerService.js +162 -0
- package/dist/services/process/index.d.ts +3 -0
- package/dist/services/process/index.d.ts.map +1 -0
- package/dist/services/process/index.js +2 -0
- package/dist/services/process/launchNodeEffect.d.ts +40 -0
- package/dist/services/process/launchNodeEffect.d.ts.map +1 -0
- package/dist/services/process/launchNodeEffect.js +86 -0
- package/dist/util/functions/index.d.ts +3 -0
- package/dist/util/functions/index.d.ts.map +1 -0
- package/dist/util/functions/index.js +4 -0
- package/dist/util/index.d.ts +4 -0
- package/dist/util/index.d.ts.map +1 -0
- package/dist/util/index.js +2 -0
- package/package.json +157 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import JSONC from "jsonc-parser";
|
|
3
|
+
import path, { extname } from "node:path";
|
|
4
|
+
let cachedConfig;
|
|
5
|
+
/**
|
|
6
|
+
* Sets the cached config. Used by async loaders to populate the cache.
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export function setCachedConfig(config) {
|
|
10
|
+
cachedConfig = config;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Gets the cached config if available.
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function getCachedConfig() {
|
|
17
|
+
return cachedConfig;
|
|
18
|
+
}
|
|
19
|
+
function parseConfigSync(filePath) {
|
|
20
|
+
let result;
|
|
21
|
+
const file = readFileSync(filePath, "utf8");
|
|
22
|
+
switch (extname(filePath)) {
|
|
23
|
+
case ".json":
|
|
24
|
+
result = JSON.parse(file);
|
|
25
|
+
break;
|
|
26
|
+
case ".config":
|
|
27
|
+
result = JSONC.parse(file);
|
|
28
|
+
break;
|
|
29
|
+
default:
|
|
30
|
+
result = undefined;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
function replaceEnvVars(value) {
|
|
36
|
+
if (typeof value === "string") {
|
|
37
|
+
return value.replace(/\$\{([^}]+)\}/g, (match, group) => {
|
|
38
|
+
const envVarValue = process.env[group];
|
|
39
|
+
return envVarValue || match;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
return value.map(replaceEnvVars);
|
|
44
|
+
}
|
|
45
|
+
if (typeof value === "object" && value !== null) {
|
|
46
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, replaceEnvVars(v)]));
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Imports the Moonwall config from the path specified in MOON_CONFIG_PATH.
|
|
52
|
+
* Uses a cached version if available.
|
|
53
|
+
*/
|
|
54
|
+
export function importJsonConfig() {
|
|
55
|
+
if (cachedConfig) {
|
|
56
|
+
return cachedConfig;
|
|
57
|
+
}
|
|
58
|
+
const configPath = process.env.MOON_CONFIG_PATH;
|
|
59
|
+
if (!configPath) {
|
|
60
|
+
throw new Error("No moonwall config path set. This is a defect, please raise it.");
|
|
61
|
+
}
|
|
62
|
+
const filePath = path.isAbsolute(configPath) ? configPath : path.join(process.cwd(), configPath);
|
|
63
|
+
try {
|
|
64
|
+
const config = parseConfigSync(filePath);
|
|
65
|
+
const replacedConfig = replaceEnvVars(config);
|
|
66
|
+
cachedConfig = replacedConfig;
|
|
67
|
+
return cachedConfig;
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
console.error(e);
|
|
71
|
+
throw new Error(`Error import config at ${filePath}`, { cause: e });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Caches the config from the MOON_CONFIG_PATH environment variable.
|
|
76
|
+
*/
|
|
77
|
+
export function cacheConfig() {
|
|
78
|
+
const configPath = process.env.MOON_CONFIG_PATH;
|
|
79
|
+
if (!configPath) {
|
|
80
|
+
throw new Error(`Environment ${process.env.MOON_TEST_ENV} not found in config`);
|
|
81
|
+
}
|
|
82
|
+
const filePath = path.isAbsolute(configPath) ? configPath : path.join(process.cwd(), configPath);
|
|
83
|
+
try {
|
|
84
|
+
const config = parseConfigSync(filePath);
|
|
85
|
+
const replacedConfig = replaceEnvVars(config);
|
|
86
|
+
cachedConfig = replacedConfig;
|
|
87
|
+
}
|
|
88
|
+
catch (e) {
|
|
89
|
+
console.error(e);
|
|
90
|
+
throw new Error(`Error import config at ${filePath}`, { cause: e });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Gets the current environment configuration based on MOON_TEST_ENV.
|
|
95
|
+
*/
|
|
96
|
+
export function getEnvironmentFromConfig() {
|
|
97
|
+
const globalConfig = importJsonConfig();
|
|
98
|
+
const config = globalConfig.environments.find(({ name }) => name === process.env.MOON_TEST_ENV);
|
|
99
|
+
if (!config) {
|
|
100
|
+
throw new Error(`Environment ${process.env.MOON_TEST_ENV} not found in config`);
|
|
101
|
+
}
|
|
102
|
+
return config;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Checks if the current environment is an Ethereum-compatible dev config.
|
|
106
|
+
*/
|
|
107
|
+
export function isEthereumDevConfig() {
|
|
108
|
+
const env = getEnvironmentFromConfig();
|
|
109
|
+
return env.foundation.type === "dev" && !env.foundation.launchSpec[0].disableDefaultEthProviders;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Checks if the current environment is an Ethereum-compatible zombie config.
|
|
113
|
+
*/
|
|
114
|
+
export function isEthereumZombieConfig() {
|
|
115
|
+
const env = getEnvironmentFromConfig();
|
|
116
|
+
return env.foundation.type === "zombie" && !env.foundation.zombieSpec.disableDefaultEthProviders;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Checks if a specific option is set in the current environment config.
|
|
120
|
+
*/
|
|
121
|
+
export function isOptionSet(option) {
|
|
122
|
+
const env = getEnvironmentFromConfig();
|
|
123
|
+
const optionValue = traverseConfig(env, option);
|
|
124
|
+
return optionValue !== undefined;
|
|
125
|
+
}
|
|
126
|
+
function traverseConfig(configObj, option) {
|
|
127
|
+
if (typeof configObj !== "object" || !configObj)
|
|
128
|
+
return undefined;
|
|
129
|
+
if (Object.hasOwn(configObj, option)) {
|
|
130
|
+
return configObj[option];
|
|
131
|
+
}
|
|
132
|
+
for (const key in configObj) {
|
|
133
|
+
const result = traverseConfig(configObj[key], option);
|
|
134
|
+
if (result !== undefined) {
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Loads environment variables defined in the current environment config.
|
|
142
|
+
*/
|
|
143
|
+
export function loadEnvVars() {
|
|
144
|
+
const env = getEnvironmentFromConfig();
|
|
145
|
+
for (const envVar of env.envVars || []) {
|
|
146
|
+
const [key, value] = envVar.split("=");
|
|
147
|
+
process.env[key] = value;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/services/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,wBAAwB,EACxB,mBAAmB,EACnB,sBAAsB,EACtB,WAAW,EACX,WAAW,EACX,eAAe,EACf,eAAe,GAChB,6BAA6B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { importJsonConfig, cacheConfig, getEnvironmentFromConfig, isEthereumDevConfig, isEthereumZombieConfig, isOptionSet, loadEnvVars, setCachedConfig, getCachedConfig, } from "./configAccessors.js";
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
declare const PortDiscoveryError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
2
|
+
readonly _tag: "PortDiscoveryError";
|
|
3
|
+
} & Readonly<A>;
|
|
4
|
+
/**
|
|
5
|
+
* Error thrown when port discovery fails
|
|
6
|
+
*/
|
|
7
|
+
export declare class PortDiscoveryError extends PortDiscoveryError_base<{
|
|
8
|
+
readonly cause: unknown;
|
|
9
|
+
readonly pid: number;
|
|
10
|
+
readonly attempts: number;
|
|
11
|
+
}> {
|
|
12
|
+
}
|
|
13
|
+
declare const NodeLaunchError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
14
|
+
readonly _tag: "NodeLaunchError";
|
|
15
|
+
} & Readonly<A>;
|
|
16
|
+
/**
|
|
17
|
+
* Error thrown when node launch fails
|
|
18
|
+
*/
|
|
19
|
+
export declare class NodeLaunchError extends NodeLaunchError_base<{
|
|
20
|
+
readonly cause: unknown;
|
|
21
|
+
readonly command: string;
|
|
22
|
+
readonly args: ReadonlyArray<string>;
|
|
23
|
+
}> {
|
|
24
|
+
}
|
|
25
|
+
declare const NodeReadinessError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
26
|
+
readonly _tag: "NodeReadinessError";
|
|
27
|
+
} & Readonly<A>;
|
|
28
|
+
/**
|
|
29
|
+
* Error thrown when node readiness check fails
|
|
30
|
+
*/
|
|
31
|
+
export declare class NodeReadinessError extends NodeReadinessError_base<{
|
|
32
|
+
readonly cause: unknown;
|
|
33
|
+
readonly port: number;
|
|
34
|
+
readonly attemptsExhausted: number;
|
|
35
|
+
}> {
|
|
36
|
+
}
|
|
37
|
+
declare const ProcessError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
38
|
+
readonly _tag: "ProcessError";
|
|
39
|
+
} & Readonly<A>;
|
|
40
|
+
/**
|
|
41
|
+
* Error thrown when process operations fail
|
|
42
|
+
*/
|
|
43
|
+
export declare class ProcessError extends ProcessError_base<{
|
|
44
|
+
readonly cause: unknown;
|
|
45
|
+
readonly pid?: number;
|
|
46
|
+
readonly operation: "spawn" | "kill" | "check";
|
|
47
|
+
}> {
|
|
48
|
+
}
|
|
49
|
+
declare const StartupCacheError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
50
|
+
readonly _tag: "StartupCacheError";
|
|
51
|
+
} & Readonly<A>;
|
|
52
|
+
/**
|
|
53
|
+
* Error thrown when startup cache operations fail
|
|
54
|
+
*/
|
|
55
|
+
export declare class StartupCacheError extends StartupCacheError_base<{
|
|
56
|
+
readonly cause: unknown;
|
|
57
|
+
readonly operation: "hash" | "precompile" | "cache" | "lock" | "chainspec";
|
|
58
|
+
}> {
|
|
59
|
+
}
|
|
60
|
+
declare const FileLockError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
61
|
+
readonly _tag: "FileLockError";
|
|
62
|
+
} & Readonly<A>;
|
|
63
|
+
/**
|
|
64
|
+
* Error thrown when file lock operations fail
|
|
65
|
+
*/
|
|
66
|
+
export declare class FileLockError extends FileLockError_base<{
|
|
67
|
+
readonly reason: "timeout" | "acquisition_failed";
|
|
68
|
+
readonly lockPath: string;
|
|
69
|
+
}> {
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/services/errors.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC7E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;CAAG;;;;AAEL;;GAEG;AACH,qBAAa,eAAgB,SAAQ,qBAAoC;IACvE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACtC,CAAC;CAAG;;;;AAEL;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC7E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC,CAAC;CAAG;;;;AAEL;;GAEG;AACH,qBAAa,YAAa,SAAQ,kBAAiC;IACjE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;CAChD,CAAC;CAAG;;;;AAEL;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,uBAAsC;IAC3E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;CAC5E,CAAC;CAAG;;;;AAEL;;GAEG;AACH,qBAAa,aAAc,SAAQ,mBAAkC;IACnE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,oBAAoB,CAAC;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B,CAAC;CAAG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Data } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* Error thrown when port discovery fails
|
|
4
|
+
*/
|
|
5
|
+
export class PortDiscoveryError extends Data.TaggedError("PortDiscoveryError") {
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when node launch fails
|
|
9
|
+
*/
|
|
10
|
+
export class NodeLaunchError extends Data.TaggedError("NodeLaunchError") {
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Error thrown when node readiness check fails
|
|
14
|
+
*/
|
|
15
|
+
export class NodeReadinessError extends Data.TaggedError("NodeReadinessError") {
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Error thrown when process operations fail
|
|
19
|
+
*/
|
|
20
|
+
export class ProcessError extends Data.TaggedError("ProcessError") {
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Error thrown when startup cache operations fail
|
|
24
|
+
*/
|
|
25
|
+
export class StartupCacheError extends Data.TaggedError("StartupCacheError") {
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Error thrown when file lock operations fail
|
|
29
|
+
*/
|
|
30
|
+
export class FileLockError extends Data.TaggedError("FileLockError") {
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/services/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,mCAAmC;AACnC,mCAAmC;AACnC,sCAAsC;AACtC,iCAAiC;AACjC,kCAAkC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Socket } from "@effect/platform";
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
|
+
import { NodeReadinessError } from "../errors.js";
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for readiness check
|
|
6
|
+
*/
|
|
7
|
+
export interface ReadinessConfig {
|
|
8
|
+
readonly port: number;
|
|
9
|
+
readonly isEthereumChain: boolean;
|
|
10
|
+
readonly maxAttempts?: number;
|
|
11
|
+
}
|
|
12
|
+
declare const NodeReadinessService_base: Context.TagClass<NodeReadinessService, "NodeReadinessService", {
|
|
13
|
+
/**
|
|
14
|
+
* Check if node is ready to accept connections
|
|
15
|
+
* @param config Readiness check configuration
|
|
16
|
+
* @returns true if node is ready
|
|
17
|
+
*/
|
|
18
|
+
readonly checkReady: (config: ReadinessConfig) => Effect.Effect<boolean, NodeReadinessError>;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Service for checking node readiness via WebSocket JSON-RPC
|
|
22
|
+
*/
|
|
23
|
+
export declare class NodeReadinessService extends NodeReadinessService_base {
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Live implementation of NodeReadinessService
|
|
27
|
+
*/
|
|
28
|
+
export declare const NodeReadinessServiceLive: Layer.Layer<NodeReadinessService, never, never>;
|
|
29
|
+
/**
|
|
30
|
+
* Test implementation that accepts a custom Socket layer
|
|
31
|
+
* Used for testing with mock Sockets
|
|
32
|
+
*/
|
|
33
|
+
export declare const makeNodeReadinessServiceTest: (socketLayer: Layer.Layer<Socket.Socket>) => Layer.Layer<NodeReadinessService>;
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=NodeReadinessService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NodeReadinessService.d.ts","sourceRoot":"","sources":["../../../src/services/network/NodeReadinessService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,OAAO,EAAE,OAAO,EAAY,MAAM,EAAS,KAAK,EAAwB,MAAM,QAAQ,CAAC;AACvF,OAAO,EAAE,kBAAkB,EAAE,qBAAqB;AAKlD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;;IAQG;;;;OAIG;yBACkB,CAAC,MAAM,EAAE,eAAe,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,kBAAkB,CAAC;;AAXhG;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,yBAUvC;CAAG;AAsKN;;GAEG;AACH,eAAO,MAAM,wBAAwB,iDAEnC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACvC,aAAa,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KACtC,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAI/B,CAAC"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { Socket } from "@effect/platform";
|
|
2
|
+
import * as NodeSocket from "@effect/platform-node/NodeSocket";
|
|
3
|
+
import { createLogger } from "../../util/index.js";
|
|
4
|
+
import { Context, Deferred, Effect, Fiber, Layer, Schedule } from "effect";
|
|
5
|
+
import { NodeReadinessError } from "../errors.js";
|
|
6
|
+
const logger = createLogger({ name: "NodeReadinessService" });
|
|
7
|
+
const debug = logger.debug.bind(logger);
|
|
8
|
+
/**
|
|
9
|
+
* Service for checking node readiness via WebSocket JSON-RPC
|
|
10
|
+
*/
|
|
11
|
+
export class NodeReadinessService extends Context.Tag("NodeReadinessService")() {
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Send JSON-RPC request and wait for response using Effect Socket
|
|
15
|
+
*/
|
|
16
|
+
const sendRpcRequest = (method) => Effect.flatMap(Deferred.make(), (responseDeferred) => Effect.flatMap(Socket.Socket, (socket) => Effect.flatMap(socket.writer, (writer) => {
|
|
17
|
+
debug(`Checking method: ${method}`);
|
|
18
|
+
const request = new TextEncoder().encode(JSON.stringify({
|
|
19
|
+
jsonrpc: "2.0",
|
|
20
|
+
id: Math.floor(Math.random() * 10000),
|
|
21
|
+
method,
|
|
22
|
+
params: [],
|
|
23
|
+
}));
|
|
24
|
+
// Set up message handler
|
|
25
|
+
const handleMessages = socket.runRaw((data) => {
|
|
26
|
+
try {
|
|
27
|
+
const message = typeof data === "string" ? data : new TextDecoder().decode(data);
|
|
28
|
+
debug(`Got message for ${method}: ${message.substring(0, 100)}`);
|
|
29
|
+
const response = JSON.parse(message);
|
|
30
|
+
debug(`Parsed response: jsonrpc=${response.jsonrpc}, error=${response.error}`);
|
|
31
|
+
if (response.jsonrpc === "2.0" && !response.error) {
|
|
32
|
+
debug(`Method ${method} succeeded!`);
|
|
33
|
+
return Deferred.succeed(responseDeferred, true);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
debug(`Parse error for ${method}: ${e}`);
|
|
38
|
+
}
|
|
39
|
+
return Effect.void;
|
|
40
|
+
});
|
|
41
|
+
// Send request and wait for response
|
|
42
|
+
return Effect.flatMap(Effect.fork(handleMessages), (messageFiber) => Effect.flatMap(writer(request), () =>
|
|
43
|
+
// Wait for either:
|
|
44
|
+
// 1. Deferred resolving with response (success)
|
|
45
|
+
// 2. Timeout (fails with error)
|
|
46
|
+
// Also check if the message fiber has failed
|
|
47
|
+
Deferred.await(responseDeferred).pipe(Effect.timeoutFail({
|
|
48
|
+
duration: "2 seconds",
|
|
49
|
+
onTimeout: () => new Error("RPC request timed out waiting for response"),
|
|
50
|
+
}),
|
|
51
|
+
// After getting result, check if fiber failed and prefer that error
|
|
52
|
+
Effect.flatMap((result) => Fiber.poll(messageFiber).pipe(Effect.flatMap((pollResult) => {
|
|
53
|
+
if (pollResult._tag === "Some") {
|
|
54
|
+
const exit = pollResult.value;
|
|
55
|
+
if (exit._tag === "Failure") {
|
|
56
|
+
// Fiber failed - propagate that error instead of returning result
|
|
57
|
+
return Effect.failCause(exit.cause);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return Effect.succeed(result);
|
|
61
|
+
}))))).pipe(Effect.ensuring(Fiber.interrupt(messageFiber)), Effect.catchAll((cause) => Effect.fail(new NodeReadinessError({
|
|
62
|
+
cause,
|
|
63
|
+
port: 0, // Will be filled in by caller
|
|
64
|
+
attemptsExhausted: 1,
|
|
65
|
+
})))));
|
|
66
|
+
})));
|
|
67
|
+
/**
|
|
68
|
+
* Attempt single WebSocket readiness check using Effect Socket
|
|
69
|
+
*/
|
|
70
|
+
const attemptReadinessCheck = (config) => Effect.logDebug(`Attempting readiness check on port ${config.port}, isEthereum: ${config.isEthereumChain}`).pipe(Effect.flatMap(() => Effect.scoped(Effect.flatMap(sendRpcRequest("system_chain"), (systemChainOk) => {
|
|
71
|
+
if (systemChainOk) {
|
|
72
|
+
return Effect.succeed(true);
|
|
73
|
+
}
|
|
74
|
+
// If Ethereum chain, also try eth_chainId
|
|
75
|
+
if (config.isEthereumChain) {
|
|
76
|
+
return sendRpcRequest("eth_chainId");
|
|
77
|
+
}
|
|
78
|
+
return Effect.succeed(false);
|
|
79
|
+
})).pipe(Effect.timeoutFail({
|
|
80
|
+
duration: "3 seconds",
|
|
81
|
+
onTimeout: () => new NodeReadinessError({
|
|
82
|
+
cause: new Error("Readiness check timed out"),
|
|
83
|
+
port: config.port,
|
|
84
|
+
attemptsExhausted: 1,
|
|
85
|
+
}),
|
|
86
|
+
}), Effect.catchAll((cause) => Effect.fail(new NodeReadinessError({
|
|
87
|
+
cause,
|
|
88
|
+
port: config.port,
|
|
89
|
+
attemptsExhausted: 1,
|
|
90
|
+
}))))));
|
|
91
|
+
/**
|
|
92
|
+
* Check node readiness with retry (internal, requires Socket.Socket)
|
|
93
|
+
*/
|
|
94
|
+
const checkReadyWithRetryInternal = (config) => {
|
|
95
|
+
const maxAttempts = config.maxAttempts || 200;
|
|
96
|
+
return attemptReadinessCheck(config).pipe(Effect.retry(Schedule.fixed("50 millis").pipe(Schedule.compose(Schedule.recurs(maxAttempts - 1)))), Effect.catchAll((error) => Effect.fail(new NodeReadinessError({
|
|
97
|
+
cause: error,
|
|
98
|
+
port: config.port,
|
|
99
|
+
attemptsExhausted: maxAttempts,
|
|
100
|
+
}))));
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Check node readiness with retry (public, provides real WebSocket layer)
|
|
104
|
+
*/
|
|
105
|
+
const checkReadyWithRetry = (config) => {
|
|
106
|
+
return checkReadyWithRetryInternal(config).pipe(Effect.provide(NodeSocket.layerWebSocket(`ws://localhost:${config.port}`)));
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Live implementation of NodeReadinessService
|
|
110
|
+
*/
|
|
111
|
+
export const NodeReadinessServiceLive = Layer.succeed(NodeReadinessService, {
|
|
112
|
+
checkReady: checkReadyWithRetry,
|
|
113
|
+
});
|
|
114
|
+
/**
|
|
115
|
+
* Test implementation that accepts a custom Socket layer
|
|
116
|
+
* Used for testing with mock Sockets
|
|
117
|
+
*/
|
|
118
|
+
export const makeNodeReadinessServiceTest = (socketLayer) => Layer.succeed(NodeReadinessService, {
|
|
119
|
+
checkReady: (config) => checkReadyWithRetryInternal(config).pipe(Effect.provide(socketLayer)),
|
|
120
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Effect, Context, Layer } from "effect";
|
|
2
|
+
import { PortDiscoveryError } from "../errors.js";
|
|
3
|
+
declare const PortDiscoveryService_base: Context.TagClass<PortDiscoveryService, "PortDiscoveryService", {
|
|
4
|
+
/**
|
|
5
|
+
* Discover ports used by a process ID with automatic retry
|
|
6
|
+
* @param pid Process ID to inspect
|
|
7
|
+
* @param maxAttempts Maximum number of retry attempts (default: 30)
|
|
8
|
+
* @returns First discovered port number
|
|
9
|
+
*/
|
|
10
|
+
readonly discoverPort: (pid: number, maxAttempts?: number) => Effect.Effect<number, PortDiscoveryError>;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Service for discovering ports used by a process
|
|
14
|
+
*/
|
|
15
|
+
export declare class PortDiscoveryService extends PortDiscoveryService_base {
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Live implementation of PortDiscoveryService
|
|
19
|
+
*/
|
|
20
|
+
export declare const PortDiscoveryServiceLive: Layer.Layer<PortDiscoveryService, never, never>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=PortDiscoveryService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PortDiscoveryService.d.ts","sourceRoot":"","sources":["../../../src/services/network/PortDiscoveryService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAY,MAAM,QAAQ,CAAC;AAG1D,OAAO,EAAE,kBAAkB,EAAE,qBAAqB;;IAU9C;;;;;OAKG;2BACoB,CACrB,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,MAAM,KACjB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC;;AAflD;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,yBAcvC;CAAG;AAgGN;;GAEG;AACH,eAAO,MAAM,wBAAwB,iDAEnC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Effect, Context, Layer, Schedule } from "effect";
|
|
2
|
+
import { exec } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { PortDiscoveryError } from "../errors.js";
|
|
5
|
+
const execAsync = promisify(exec);
|
|
6
|
+
/**
|
|
7
|
+
* Service for discovering ports used by a process
|
|
8
|
+
*/
|
|
9
|
+
export class PortDiscoveryService extends Context.Tag("PortDiscoveryService")() {
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse ports from lsof output
|
|
13
|
+
* Example lsof line: "node 97796 user 26u IPv6 0xb6c3e894a2247189 0t0 TCP *:8000 (LISTEN)"
|
|
14
|
+
*/
|
|
15
|
+
const parsePortsFromLsof = (stdout) => {
|
|
16
|
+
const ports = [];
|
|
17
|
+
const lines = stdout.split("\n");
|
|
18
|
+
for (const line of lines) {
|
|
19
|
+
const regex = /(?:.+):(\d+)/;
|
|
20
|
+
const match = line.match(regex);
|
|
21
|
+
if (match) {
|
|
22
|
+
ports.push(Number.parseInt(match[1], 10));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return ports;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Attempt to discover ports for a given PID
|
|
29
|
+
*/
|
|
30
|
+
const attemptPortDiscovery = (pid) => Effect.tryPromise({
|
|
31
|
+
try: () => execAsync(`lsof -p ${pid} -n -P | grep LISTEN`),
|
|
32
|
+
catch: (cause) => new PortDiscoveryError({
|
|
33
|
+
cause,
|
|
34
|
+
pid,
|
|
35
|
+
attempts: 1,
|
|
36
|
+
}),
|
|
37
|
+
}).pipe(Effect.flatMap(({ stdout }) => {
|
|
38
|
+
const ports = parsePortsFromLsof(stdout);
|
|
39
|
+
if (ports.length === 0) {
|
|
40
|
+
return Effect.fail(new PortDiscoveryError({
|
|
41
|
+
cause: new Error("No ports found in lsof output"),
|
|
42
|
+
pid,
|
|
43
|
+
attempts: 1,
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
// Find RPC port with fallback logic:
|
|
47
|
+
// 1. Exclude the p2p port 30333 and metrics port 9615
|
|
48
|
+
// 2. If only one port found, accept it (must be the RPC port)
|
|
49
|
+
// 3. Otherwise fail with informative error
|
|
50
|
+
const rpcPort = ports.find((p) => p !== 30333 && p !== 9615);
|
|
51
|
+
if (!rpcPort) {
|
|
52
|
+
// Fallback: if only one port, it must be the RPC port (e.g., Chopsticks ephemeral ports)
|
|
53
|
+
if (ports.length === 1) {
|
|
54
|
+
return Effect.succeed(ports[0]);
|
|
55
|
+
}
|
|
56
|
+
return Effect.fail(new PortDiscoveryError({
|
|
57
|
+
cause: new Error(`No RPC port found in range 9000-20000 and multiple ports detected (found ports: ${ports.join(", ")})`),
|
|
58
|
+
pid,
|
|
59
|
+
attempts: 1,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
return Effect.succeed(rpcPort);
|
|
63
|
+
}));
|
|
64
|
+
/**
|
|
65
|
+
* Discover port with fixed interval retry
|
|
66
|
+
*/
|
|
67
|
+
const discoverPortWithRetry = (pid, maxAttempts = 1200) => attemptPortDiscovery(pid).pipe(Effect.retry(Schedule.fixed("50 millis").pipe(Schedule.compose(Schedule.recurs(maxAttempts - 1)))), Effect.catchAll((error) => Effect.fail(new PortDiscoveryError({
|
|
68
|
+
cause: error,
|
|
69
|
+
pid,
|
|
70
|
+
attempts: maxAttempts,
|
|
71
|
+
}))));
|
|
72
|
+
/**
|
|
73
|
+
* Live implementation of PortDiscoveryService
|
|
74
|
+
*/
|
|
75
|
+
export const PortDiscoveryServiceLive = Layer.succeed(PortDiscoveryService, {
|
|
76
|
+
discoverPort: discoverPortWithRetry,
|
|
77
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from "effect";
|
|
2
|
+
import { PortDiscoveryError } from "../errors.js";
|
|
3
|
+
declare const RpcPortDiscoveryService_base: Context.TagClass<RpcPortDiscoveryService, "RpcPortDiscoveryService", {
|
|
4
|
+
/**
|
|
5
|
+
* Discover RPC port by testing actual RPC connectivity on all candidate ports
|
|
6
|
+
* @param config Discovery configuration
|
|
7
|
+
* @returns First port that responds to RPC calls
|
|
8
|
+
*/
|
|
9
|
+
readonly discoverRpcPort: (config: {
|
|
10
|
+
pid: number;
|
|
11
|
+
isEthereumChain: boolean;
|
|
12
|
+
maxAttempts?: number;
|
|
13
|
+
}) => Effect.Effect<number, PortDiscoveryError>;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Service for discovering RPC ports by testing actual connectivity
|
|
17
|
+
*/
|
|
18
|
+
export declare class RpcPortDiscoveryService extends RpcPortDiscoveryService_base {
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Live implementation of RpcPortDiscoveryService
|
|
22
|
+
*/
|
|
23
|
+
export declare const RpcPortDiscoveryServiceLive: Layer.Layer<RpcPortDiscoveryService, never, never>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=RpcPortDiscoveryService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RpcPortDiscoveryService.d.ts","sourceRoot":"","sources":["../../../src/services/network/RpcPortDiscoveryService.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAY,MAAM,EAAE,KAAK,EAAgC,MAAM,QAAQ,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,qBAAqB;;IAW9C;;;;OAIG;8BACuB,CAAC,MAAM,EAAE;QACjC,GAAG,EAAE,MAAM,CAAC;QACZ,eAAe,EAAE,OAAO,CAAC;QACzB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC;;AAfnD;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,4BAc1C;CAAG;AAkON;;GAEG;AACH,eAAO,MAAM,2BAA2B,oDAEtC,CAAC"}
|