@etherna/docker 0.0.0-stage → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -2
- package/dist/bin.cjs +29 -0
- package/dist/bin.cjs.map +1 -0
- package/dist/index.cjs +10 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +242 -0
- package/dist/index.d.mts +242 -0
- package/dist/index.mjs +10 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +60 -3
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Logical Etherna service names. Matches today's CLI vocabulary (excluding `all`).
|
|
4
|
+
* `blockchain` has no independent `StartOptions` toggle — it always mirrors `bee` — but is kept
|
|
5
|
+
* as its own name because `stop("blockchain")` stops only the blockchain container while
|
|
6
|
+
* `stop("bee")` stops the whole bee node group (see `containerNamesFor`).
|
|
7
|
+
*/
|
|
8
|
+
type EthernaServiceName = "blockchain" | "bee" | "beehive" | "credit" | "elastic" | "gateway" | "index" | "mongo" | "shkeeper" | "sso";
|
|
9
|
+
interface ServiceConfig<TEnv> {
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
env?: TEnv;
|
|
12
|
+
}
|
|
13
|
+
/** Turns a service's typed env shape into a partial map of string overrides (as passed via `-e` flags). */
|
|
14
|
+
type StringEnvOverride<T extends Record<string, string | number>> = Partial<Record<keyof T, string>>;
|
|
15
|
+
/** ASP.NET-based Etherna services (sso/index/credit/gateway/beehive) share these base keys. */
|
|
16
|
+
type BaseAspEnvShape = {
|
|
17
|
+
ASPNETCORE_ENVIRONMENT: string;
|
|
18
|
+
"Elastic:Urls:0": string;
|
|
19
|
+
ASPNETCORE_Kestrel__Certificates__Default__Path?: string;
|
|
20
|
+
ASPNETCORE_Kestrel__Certificates__Default__Password?: string;
|
|
21
|
+
};
|
|
22
|
+
type ElasticEnvShape = {
|
|
23
|
+
"discovery.type": string;
|
|
24
|
+
"xpack.security.enabled": string;
|
|
25
|
+
ES_JAVA_OPTS: string;
|
|
26
|
+
};
|
|
27
|
+
type BlockchainEnvShape = {
|
|
28
|
+
BLOCKCHAIN_PORT: number;
|
|
29
|
+
NETWORK_ID: number;
|
|
30
|
+
};
|
|
31
|
+
type BeeEnvShape = {
|
|
32
|
+
POSTAGE_PRICE: string;
|
|
33
|
+
BEE_WARMUP_TIME: string;
|
|
34
|
+
BEE_DEBUG_API_ENABLE: string;
|
|
35
|
+
BEE_VERBOSITY: string;
|
|
36
|
+
BEE_SWAP_ENABLE: string;
|
|
37
|
+
BEE_MAINNET: string;
|
|
38
|
+
BEE_SWAP_ENDPOINT: string;
|
|
39
|
+
BEE_BLOCKCHAIN_RPC_ENDPOINT: string;
|
|
40
|
+
BEE_PASSWORD: string;
|
|
41
|
+
BEE_SWAP_FACTORY_ADDRESS: string;
|
|
42
|
+
BEE_POSTAGE_STAMP_ADDRESS: string;
|
|
43
|
+
BEE_PRICE_ORACLE_ADDRESS: string;
|
|
44
|
+
BEE_REDISTRIBUTION_ADDRESS: string;
|
|
45
|
+
BEE_STAKING_ADDRESS: string;
|
|
46
|
+
BEE_POSTAGE_STAMP_START_BLOCK: string;
|
|
47
|
+
BEE_NETWORK_ID: number;
|
|
48
|
+
BEE_FULL_NODE: string;
|
|
49
|
+
BEE_PORT: number;
|
|
50
|
+
BEE_P2P_PORT: number;
|
|
51
|
+
BEE_API_ADDR: string;
|
|
52
|
+
BEE_P2P_ADDR: string;
|
|
53
|
+
BEE_CORS_ALLOWED_ORIGINS: string;
|
|
54
|
+
BEE_ALLOW_PRIVATE_CIDRS: string;
|
|
55
|
+
BEE_BOOTNODE_MODE: string;
|
|
56
|
+
BEE_BOOTNODE: string;
|
|
57
|
+
};
|
|
58
|
+
type SsoEnvShape = BaseAspEnvShape & {
|
|
59
|
+
ASPNETCORE_URLS: string;
|
|
60
|
+
"IdServer:SsoServer:BaseUrl": string;
|
|
61
|
+
"IdServer:SsoServer:AllowUnsafeConnection": string;
|
|
62
|
+
"IdServer:Clients:EthernaCredit:BaseUrl": string;
|
|
63
|
+
"IdServer:Clients:EthernaGateway:BaseUrls:0": string;
|
|
64
|
+
"IdServer:Clients:EthernaIndex:BaseUrl": string;
|
|
65
|
+
"IdServer:Clients:EthernaDapp:BaseUrl": string;
|
|
66
|
+
"DbSeed:Clients:0:RedirectUris:0": string;
|
|
67
|
+
"DbSeed:Clients:0:PostLogoutRedirectUris:0": string;
|
|
68
|
+
"DbSeed:Clients:0:AllowedCorsOrigins:0": string;
|
|
69
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
70
|
+
"ConnectionStrings:HangfireDb": string;
|
|
71
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
72
|
+
"ConnectionStrings:SSOServerDb": string;
|
|
73
|
+
};
|
|
74
|
+
type IndexEnvShape = BaseAspEnvShape & {
|
|
75
|
+
ASPNETCORE_URLS: string;
|
|
76
|
+
"Swarm:GatewayUrl": string;
|
|
77
|
+
"SsoServer:BaseUrl": string;
|
|
78
|
+
"SsoServer:AllowUnsafeConnection": string;
|
|
79
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
80
|
+
"ConnectionStrings:HangfireDb": string;
|
|
81
|
+
"ConnectionStrings:IndexDb": string;
|
|
82
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
83
|
+
};
|
|
84
|
+
type CreditEnvShape = BaseAspEnvShape & {
|
|
85
|
+
ASPNETCORE_URLS: string;
|
|
86
|
+
"SsoServer:BaseUrl": string;
|
|
87
|
+
"SsoServer:AllowUnsafeConnection": string;
|
|
88
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
89
|
+
"ConnectionStrings:HangfireDb": string;
|
|
90
|
+
"ConnectionStrings:CreditDb": string;
|
|
91
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
92
|
+
DisableHttpsRedirection: string;
|
|
93
|
+
"Payments:ShKeeper:Url": string;
|
|
94
|
+
"Payments:ShKeeper:ApiKey": string;
|
|
95
|
+
"Payments:ShKeeper:CustomCallbackBaseUrl": string;
|
|
96
|
+
};
|
|
97
|
+
type GatewayEnvShape = BaseAspEnvShape & {
|
|
98
|
+
ASPNETCORE_URLS: string;
|
|
99
|
+
"ForwardedHeaders:KnownNetworks:0": string;
|
|
100
|
+
"SsoServer:BaseUrl": string;
|
|
101
|
+
"SsoServer:Clients:Credit:BaseUrl": string;
|
|
102
|
+
"SsoServer:Clients:Credit:Secret": string;
|
|
103
|
+
"SsoServer:Clients:Webapp:Secret": string;
|
|
104
|
+
"SsoServer:AllowUnsafeConnection": string;
|
|
105
|
+
"Bee:CachedUrl": string;
|
|
106
|
+
"Bee:DirectUrl": string;
|
|
107
|
+
"Features:GarbageCollectPins": string;
|
|
108
|
+
ForwardedAllowedHosts: string;
|
|
109
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
110
|
+
"ConnectionStrings:HangfireDb": string;
|
|
111
|
+
"ConnectionStrings:GatewayDb": string;
|
|
112
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
113
|
+
};
|
|
114
|
+
type BeehiveEnvShape = BaseAspEnvShape & {
|
|
115
|
+
ASPNETCORE_URLS: string;
|
|
116
|
+
"SeedDb:BeeNodes:0:Hostname": string;
|
|
117
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
118
|
+
"ConnectionStrings:HangfireDb": string;
|
|
119
|
+
"ConnectionStrings:BeehiveDb": string;
|
|
120
|
+
"SeedDb:BeeNodes:0:ConnectionString": string;
|
|
121
|
+
"SeedDb:BeeNodes:0:EnableBatchCreation": string;
|
|
122
|
+
};
|
|
123
|
+
type ShkeeperCoreEnvShape = {
|
|
124
|
+
DEV_MODE: string;
|
|
125
|
+
BTC_WALLET: string;
|
|
126
|
+
LTC_WALLET: string;
|
|
127
|
+
DOGE_WALLET: string;
|
|
128
|
+
ETH_WALLET: string;
|
|
129
|
+
ETH_USERNAME: string;
|
|
130
|
+
ETH_PASSWORD: string;
|
|
131
|
+
ETHEREUM_API_SERVER_HOST: string;
|
|
132
|
+
ETHEREUM_SERVER_PORT: string;
|
|
133
|
+
SHKEEPER_BACKEND_KEY: string;
|
|
134
|
+
SHKEEPER_BTC_BACKEND_KEY: string;
|
|
135
|
+
};
|
|
136
|
+
type ShkeeperEthereumEnvShape = {
|
|
137
|
+
FULLNODE_URL: string;
|
|
138
|
+
FULLNODE_TIMEOUT: string;
|
|
139
|
+
CURRENT_ETH_NETWORK: string;
|
|
140
|
+
WEB3_ENABLE_POA_MIDDLEWARE: string;
|
|
141
|
+
BLOCK_SCANNER_MAX_CATCHUP_BLOCKS: string;
|
|
142
|
+
ETH_USERNAME: string;
|
|
143
|
+
ETH_PASSWORD: string;
|
|
144
|
+
SHKEEPER_BACKEND_KEY: string;
|
|
145
|
+
SHKEEPER_HOST: string;
|
|
146
|
+
REDIS_HOST: string;
|
|
147
|
+
SQLALCHEMY_DATABASE_URI: string;
|
|
148
|
+
LAST_BLOCK_LOCKED: string;
|
|
149
|
+
};
|
|
150
|
+
type ElasticEnv = StringEnvOverride<ElasticEnvShape>;
|
|
151
|
+
/** Mongo has no fixed env keys today; accepts arbitrary string overrides. */
|
|
152
|
+
type MongoEnv = Partial<Record<string, string>>;
|
|
153
|
+
/** Combines blockchain + bee container env keys, matching how the plugin builds bee's env today. */
|
|
154
|
+
type BeeEnv = StringEnvOverride<BlockchainEnvShape & BeeEnvShape>;
|
|
155
|
+
type SsoEnv = StringEnvOverride<SsoEnvShape>;
|
|
156
|
+
type IndexEnv = StringEnvOverride<IndexEnvShape>;
|
|
157
|
+
type GatewayEnv = StringEnvOverride<GatewayEnvShape>;
|
|
158
|
+
type CreditEnv = StringEnvOverride<CreditEnvShape>;
|
|
159
|
+
type BeehiveEnv = StringEnvOverride<BeehiveEnvShape>;
|
|
160
|
+
type ShkeeperEnv = StringEnvOverride<ShkeeperCoreEnvShape>;
|
|
161
|
+
type ShkeeperEthereumEnv = StringEnvOverride<ShkeeperEthereumEnvShape>;
|
|
162
|
+
/** Union of env overrides accepted by ASP.NET Etherna containers (SSO, Index, Gateway, Credit, Beehive). */
|
|
163
|
+
type AspServiceEnv = SsoEnv | IndexEnv | GatewayEnv | CreditEnv | BeehiveEnv;
|
|
164
|
+
/**
|
|
165
|
+
* When `githubRepo` is set (`owner/repo`), builds SHKeeper core from that repository and tags the
|
|
166
|
+
* image as `etherna/shkeeper:…` (same version tag as the default upstream image).
|
|
167
|
+
*/
|
|
168
|
+
interface ShkeeperBuildConfig {
|
|
169
|
+
githubRepo?: string;
|
|
170
|
+
/** Branch or tag to clone when `githubRepo` is set (defaults to `main`). Ignored for the default upstream build. */
|
|
171
|
+
githubBranch?: string;
|
|
172
|
+
}
|
|
173
|
+
interface ShkeeperEthereumConfig {
|
|
174
|
+
env?: ShkeeperEthereumEnv;
|
|
175
|
+
/** When set, build the adapter from this repo and run `etherna/ethereum-shkeeper:…` instead of the upstream image. */
|
|
176
|
+
githubRepo?: string;
|
|
177
|
+
/** Branch or tag to clone when `githubRepo` is set (defaults to `main`). */
|
|
178
|
+
githubBranch?: string;
|
|
179
|
+
}
|
|
180
|
+
interface ShkeeperConfig extends ServiceConfig<ShkeeperEnv> {
|
|
181
|
+
build?: ShkeeperBuildConfig;
|
|
182
|
+
ethereum?: ShkeeperEthereumConfig;
|
|
183
|
+
}
|
|
184
|
+
/** Handle returned by `start`, used to tear the run down (mirrors `EthernaSession.shutdown`). */
|
|
185
|
+
interface EthernaSessionHandle {
|
|
186
|
+
shutdown: (opts?: {
|
|
187
|
+
killTrackedSpawns?: boolean;
|
|
188
|
+
}) => Promise<void>;
|
|
189
|
+
}
|
|
190
|
+
interface StartOptions {
|
|
191
|
+
/**
|
|
192
|
+
* When true, reuse already-running service containers, start only missing ones, and do not stop
|
|
193
|
+
* containers on shutdown. Defaults from `ETHERNA_DETACHED` when unset (see `resolveDetachedMode`).
|
|
194
|
+
*/
|
|
195
|
+
detached?: boolean;
|
|
196
|
+
/** When true, starts Portless and registers friendly `*.localhost` URLs for the app and enabled HTTP services. */
|
|
197
|
+
portless?: boolean;
|
|
198
|
+
/** Actual dev-server / app port; CLI and Vite supply this when known. */
|
|
199
|
+
appPort?: number;
|
|
200
|
+
/** Installs SIGINT/SIGTERM handlers by default; disable in tests or when the caller manages its own signals. */
|
|
201
|
+
installSignalHandlers?: boolean;
|
|
202
|
+
mode?: "http" | "https";
|
|
203
|
+
elastic?: boolean | ServiceConfig<ElasticEnv>;
|
|
204
|
+
mongo?: boolean | ServiceConfig<MongoEnv>;
|
|
205
|
+
bee?: boolean | ServiceConfig<BeeEnv>;
|
|
206
|
+
sso?: boolean | ServiceConfig<SsoEnv>;
|
|
207
|
+
index?: boolean | ServiceConfig<IndexEnv>;
|
|
208
|
+
gateway?: boolean | ServiceConfig<GatewayEnv>;
|
|
209
|
+
credit?: boolean | ServiceConfig<CreditEnv>;
|
|
210
|
+
beehive?: boolean | ServiceConfig<BeehiveEnv>;
|
|
211
|
+
shkeeper?: boolean | ShkeeperConfig;
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/manager.d.ts
|
|
215
|
+
/**
|
|
216
|
+
* Stops the Docker container groups for the named logical service(s). Multi-container services stop
|
|
217
|
+
* as a whole group and overlapping groups are de-duplicated (see {@link containerNamesFor}).
|
|
218
|
+
* Throws a `TypeError` (listing valid names) for any unknown service name.
|
|
219
|
+
*/
|
|
220
|
+
declare function stop(services: EthernaServiceName | EthernaServiceName[]): Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* Starts the enabled Etherna services following the canonical dependency graph
|
|
223
|
+
* ({@link SERVICE_CATALOG}), wiring a {@link createSession} for spawn tracking, Portless bookkeeping,
|
|
224
|
+
* and shutdown. On a startup failure with `onFailure: "stop"`, stops the Docker containers for every
|
|
225
|
+
* enabled service in this run — even when detached — before shutting the session down.
|
|
226
|
+
*
|
|
227
|
+
* Detached mode defaults to `false` unless `options.detached` or `ETHERNA_DETACHED` is set (matches
|
|
228
|
+
* the Vite plugin). The CLI passes `detached: true` by default separately.
|
|
229
|
+
*/
|
|
230
|
+
declare function start(options?: StartOptions): Promise<EthernaSessionHandle>;
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/resolve-options.d.ts
|
|
233
|
+
declare const ETHERNA_DETACHED_ENV = "ETHERNA_DETACHED";
|
|
234
|
+
/**
|
|
235
|
+
* Resolves detached mode: explicit `options.detached` wins, then `ETHERNA_DETACHED` env, then `false`.
|
|
236
|
+
* Env is truthy for `1`, `true`, `yes` (case-insensitive); falsy for `0`, `false`, `no`, or unset.
|
|
237
|
+
* Ported from `src/plugin-define.ts`.
|
|
238
|
+
*/
|
|
239
|
+
declare function resolveDetachedMode(options: Pick<StartOptions, "detached">): boolean;
|
|
240
|
+
//#endregion
|
|
241
|
+
export { type AspServiceEnv, type BeeEnv, type BeehiveEnv, type CreditEnv, ETHERNA_DETACHED_ENV, type ElasticEnv, type EthernaServiceName, type EthernaSessionHandle, type GatewayEnv, type IndexEnv, type MongoEnv, type ServiceConfig, type ShkeeperBuildConfig, type ShkeeperConfig, type ShkeeperEnv, type ShkeeperEthereumConfig, type ShkeeperEthereumEnv, type SsoEnv, type StartOptions, resolveDetachedMode, start, stop };
|
|
242
|
+
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Logical Etherna service names. Matches today's CLI vocabulary (excluding `all`).
|
|
4
|
+
* `blockchain` has no independent `StartOptions` toggle — it always mirrors `bee` — but is kept
|
|
5
|
+
* as its own name because `stop("blockchain")` stops only the blockchain container while
|
|
6
|
+
* `stop("bee")` stops the whole bee node group (see `containerNamesFor`).
|
|
7
|
+
*/
|
|
8
|
+
type EthernaServiceName = "blockchain" | "bee" | "beehive" | "credit" | "elastic" | "gateway" | "index" | "mongo" | "shkeeper" | "sso";
|
|
9
|
+
interface ServiceConfig<TEnv> {
|
|
10
|
+
enabled?: boolean;
|
|
11
|
+
env?: TEnv;
|
|
12
|
+
}
|
|
13
|
+
/** Turns a service's typed env shape into a partial map of string overrides (as passed via `-e` flags). */
|
|
14
|
+
type StringEnvOverride<T extends Record<string, string | number>> = Partial<Record<keyof T, string>>;
|
|
15
|
+
/** ASP.NET-based Etherna services (sso/index/credit/gateway/beehive) share these base keys. */
|
|
16
|
+
type BaseAspEnvShape = {
|
|
17
|
+
ASPNETCORE_ENVIRONMENT: string;
|
|
18
|
+
"Elastic:Urls:0": string;
|
|
19
|
+
ASPNETCORE_Kestrel__Certificates__Default__Path?: string;
|
|
20
|
+
ASPNETCORE_Kestrel__Certificates__Default__Password?: string;
|
|
21
|
+
};
|
|
22
|
+
type ElasticEnvShape = {
|
|
23
|
+
"discovery.type": string;
|
|
24
|
+
"xpack.security.enabled": string;
|
|
25
|
+
ES_JAVA_OPTS: string;
|
|
26
|
+
};
|
|
27
|
+
type BlockchainEnvShape = {
|
|
28
|
+
BLOCKCHAIN_PORT: number;
|
|
29
|
+
NETWORK_ID: number;
|
|
30
|
+
};
|
|
31
|
+
type BeeEnvShape = {
|
|
32
|
+
POSTAGE_PRICE: string;
|
|
33
|
+
BEE_WARMUP_TIME: string;
|
|
34
|
+
BEE_DEBUG_API_ENABLE: string;
|
|
35
|
+
BEE_VERBOSITY: string;
|
|
36
|
+
BEE_SWAP_ENABLE: string;
|
|
37
|
+
BEE_MAINNET: string;
|
|
38
|
+
BEE_SWAP_ENDPOINT: string;
|
|
39
|
+
BEE_BLOCKCHAIN_RPC_ENDPOINT: string;
|
|
40
|
+
BEE_PASSWORD: string;
|
|
41
|
+
BEE_SWAP_FACTORY_ADDRESS: string;
|
|
42
|
+
BEE_POSTAGE_STAMP_ADDRESS: string;
|
|
43
|
+
BEE_PRICE_ORACLE_ADDRESS: string;
|
|
44
|
+
BEE_REDISTRIBUTION_ADDRESS: string;
|
|
45
|
+
BEE_STAKING_ADDRESS: string;
|
|
46
|
+
BEE_POSTAGE_STAMP_START_BLOCK: string;
|
|
47
|
+
BEE_NETWORK_ID: number;
|
|
48
|
+
BEE_FULL_NODE: string;
|
|
49
|
+
BEE_PORT: number;
|
|
50
|
+
BEE_P2P_PORT: number;
|
|
51
|
+
BEE_API_ADDR: string;
|
|
52
|
+
BEE_P2P_ADDR: string;
|
|
53
|
+
BEE_CORS_ALLOWED_ORIGINS: string;
|
|
54
|
+
BEE_ALLOW_PRIVATE_CIDRS: string;
|
|
55
|
+
BEE_BOOTNODE_MODE: string;
|
|
56
|
+
BEE_BOOTNODE: string;
|
|
57
|
+
};
|
|
58
|
+
type SsoEnvShape = BaseAspEnvShape & {
|
|
59
|
+
ASPNETCORE_URLS: string;
|
|
60
|
+
"IdServer:SsoServer:BaseUrl": string;
|
|
61
|
+
"IdServer:SsoServer:AllowUnsafeConnection": string;
|
|
62
|
+
"IdServer:Clients:EthernaCredit:BaseUrl": string;
|
|
63
|
+
"IdServer:Clients:EthernaGateway:BaseUrls:0": string;
|
|
64
|
+
"IdServer:Clients:EthernaIndex:BaseUrl": string;
|
|
65
|
+
"IdServer:Clients:EthernaDapp:BaseUrl": string;
|
|
66
|
+
"DbSeed:Clients:0:RedirectUris:0": string;
|
|
67
|
+
"DbSeed:Clients:0:PostLogoutRedirectUris:0": string;
|
|
68
|
+
"DbSeed:Clients:0:AllowedCorsOrigins:0": string;
|
|
69
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
70
|
+
"ConnectionStrings:HangfireDb": string;
|
|
71
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
72
|
+
"ConnectionStrings:SSOServerDb": string;
|
|
73
|
+
};
|
|
74
|
+
type IndexEnvShape = BaseAspEnvShape & {
|
|
75
|
+
ASPNETCORE_URLS: string;
|
|
76
|
+
"Swarm:GatewayUrl": string;
|
|
77
|
+
"SsoServer:BaseUrl": string;
|
|
78
|
+
"SsoServer:AllowUnsafeConnection": string;
|
|
79
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
80
|
+
"ConnectionStrings:HangfireDb": string;
|
|
81
|
+
"ConnectionStrings:IndexDb": string;
|
|
82
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
83
|
+
};
|
|
84
|
+
type CreditEnvShape = BaseAspEnvShape & {
|
|
85
|
+
ASPNETCORE_URLS: string;
|
|
86
|
+
"SsoServer:BaseUrl": string;
|
|
87
|
+
"SsoServer:AllowUnsafeConnection": string;
|
|
88
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
89
|
+
"ConnectionStrings:HangfireDb": string;
|
|
90
|
+
"ConnectionStrings:CreditDb": string;
|
|
91
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
92
|
+
DisableHttpsRedirection: string;
|
|
93
|
+
"Payments:ShKeeper:Url": string;
|
|
94
|
+
"Payments:ShKeeper:ApiKey": string;
|
|
95
|
+
"Payments:ShKeeper:CustomCallbackBaseUrl": string;
|
|
96
|
+
};
|
|
97
|
+
type GatewayEnvShape = BaseAspEnvShape & {
|
|
98
|
+
ASPNETCORE_URLS: string;
|
|
99
|
+
"ForwardedHeaders:KnownNetworks:0": string;
|
|
100
|
+
"SsoServer:BaseUrl": string;
|
|
101
|
+
"SsoServer:Clients:Credit:BaseUrl": string;
|
|
102
|
+
"SsoServer:Clients:Credit:Secret": string;
|
|
103
|
+
"SsoServer:Clients:Webapp:Secret": string;
|
|
104
|
+
"SsoServer:AllowUnsafeConnection": string;
|
|
105
|
+
"Bee:CachedUrl": string;
|
|
106
|
+
"Bee:DirectUrl": string;
|
|
107
|
+
"Features:GarbageCollectPins": string;
|
|
108
|
+
ForwardedAllowedHosts: string;
|
|
109
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
110
|
+
"ConnectionStrings:HangfireDb": string;
|
|
111
|
+
"ConnectionStrings:GatewayDb": string;
|
|
112
|
+
"ConnectionStrings:ServiceSharedDb": string;
|
|
113
|
+
};
|
|
114
|
+
type BeehiveEnvShape = BaseAspEnvShape & {
|
|
115
|
+
ASPNETCORE_URLS: string;
|
|
116
|
+
"SeedDb:BeeNodes:0:Hostname": string;
|
|
117
|
+
"ConnectionStrings:DataProtectionDb": string;
|
|
118
|
+
"ConnectionStrings:HangfireDb": string;
|
|
119
|
+
"ConnectionStrings:BeehiveDb": string;
|
|
120
|
+
"SeedDb:BeeNodes:0:ConnectionString": string;
|
|
121
|
+
"SeedDb:BeeNodes:0:EnableBatchCreation": string;
|
|
122
|
+
};
|
|
123
|
+
type ShkeeperCoreEnvShape = {
|
|
124
|
+
DEV_MODE: string;
|
|
125
|
+
BTC_WALLET: string;
|
|
126
|
+
LTC_WALLET: string;
|
|
127
|
+
DOGE_WALLET: string;
|
|
128
|
+
ETH_WALLET: string;
|
|
129
|
+
ETH_USERNAME: string;
|
|
130
|
+
ETH_PASSWORD: string;
|
|
131
|
+
ETHEREUM_API_SERVER_HOST: string;
|
|
132
|
+
ETHEREUM_SERVER_PORT: string;
|
|
133
|
+
SHKEEPER_BACKEND_KEY: string;
|
|
134
|
+
SHKEEPER_BTC_BACKEND_KEY: string;
|
|
135
|
+
};
|
|
136
|
+
type ShkeeperEthereumEnvShape = {
|
|
137
|
+
FULLNODE_URL: string;
|
|
138
|
+
FULLNODE_TIMEOUT: string;
|
|
139
|
+
CURRENT_ETH_NETWORK: string;
|
|
140
|
+
WEB3_ENABLE_POA_MIDDLEWARE: string;
|
|
141
|
+
BLOCK_SCANNER_MAX_CATCHUP_BLOCKS: string;
|
|
142
|
+
ETH_USERNAME: string;
|
|
143
|
+
ETH_PASSWORD: string;
|
|
144
|
+
SHKEEPER_BACKEND_KEY: string;
|
|
145
|
+
SHKEEPER_HOST: string;
|
|
146
|
+
REDIS_HOST: string;
|
|
147
|
+
SQLALCHEMY_DATABASE_URI: string;
|
|
148
|
+
LAST_BLOCK_LOCKED: string;
|
|
149
|
+
};
|
|
150
|
+
type ElasticEnv = StringEnvOverride<ElasticEnvShape>;
|
|
151
|
+
/** Mongo has no fixed env keys today; accepts arbitrary string overrides. */
|
|
152
|
+
type MongoEnv = Partial<Record<string, string>>;
|
|
153
|
+
/** Combines blockchain + bee container env keys, matching how the plugin builds bee's env today. */
|
|
154
|
+
type BeeEnv = StringEnvOverride<BlockchainEnvShape & BeeEnvShape>;
|
|
155
|
+
type SsoEnv = StringEnvOverride<SsoEnvShape>;
|
|
156
|
+
type IndexEnv = StringEnvOverride<IndexEnvShape>;
|
|
157
|
+
type GatewayEnv = StringEnvOverride<GatewayEnvShape>;
|
|
158
|
+
type CreditEnv = StringEnvOverride<CreditEnvShape>;
|
|
159
|
+
type BeehiveEnv = StringEnvOverride<BeehiveEnvShape>;
|
|
160
|
+
type ShkeeperEnv = StringEnvOverride<ShkeeperCoreEnvShape>;
|
|
161
|
+
type ShkeeperEthereumEnv = StringEnvOverride<ShkeeperEthereumEnvShape>;
|
|
162
|
+
/** Union of env overrides accepted by ASP.NET Etherna containers (SSO, Index, Gateway, Credit, Beehive). */
|
|
163
|
+
type AspServiceEnv = SsoEnv | IndexEnv | GatewayEnv | CreditEnv | BeehiveEnv;
|
|
164
|
+
/**
|
|
165
|
+
* When `githubRepo` is set (`owner/repo`), builds SHKeeper core from that repository and tags the
|
|
166
|
+
* image as `etherna/shkeeper:…` (same version tag as the default upstream image).
|
|
167
|
+
*/
|
|
168
|
+
interface ShkeeperBuildConfig {
|
|
169
|
+
githubRepo?: string;
|
|
170
|
+
/** Branch or tag to clone when `githubRepo` is set (defaults to `main`). Ignored for the default upstream build. */
|
|
171
|
+
githubBranch?: string;
|
|
172
|
+
}
|
|
173
|
+
interface ShkeeperEthereumConfig {
|
|
174
|
+
env?: ShkeeperEthereumEnv;
|
|
175
|
+
/** When set, build the adapter from this repo and run `etherna/ethereum-shkeeper:…` instead of the upstream image. */
|
|
176
|
+
githubRepo?: string;
|
|
177
|
+
/** Branch or tag to clone when `githubRepo` is set (defaults to `main`). */
|
|
178
|
+
githubBranch?: string;
|
|
179
|
+
}
|
|
180
|
+
interface ShkeeperConfig extends ServiceConfig<ShkeeperEnv> {
|
|
181
|
+
build?: ShkeeperBuildConfig;
|
|
182
|
+
ethereum?: ShkeeperEthereumConfig;
|
|
183
|
+
}
|
|
184
|
+
/** Handle returned by `start`, used to tear the run down (mirrors `EthernaSession.shutdown`). */
|
|
185
|
+
interface EthernaSessionHandle {
|
|
186
|
+
shutdown: (opts?: {
|
|
187
|
+
killTrackedSpawns?: boolean;
|
|
188
|
+
}) => Promise<void>;
|
|
189
|
+
}
|
|
190
|
+
interface StartOptions {
|
|
191
|
+
/**
|
|
192
|
+
* When true, reuse already-running service containers, start only missing ones, and do not stop
|
|
193
|
+
* containers on shutdown. Defaults from `ETHERNA_DETACHED` when unset (see `resolveDetachedMode`).
|
|
194
|
+
*/
|
|
195
|
+
detached?: boolean;
|
|
196
|
+
/** When true, starts Portless and registers friendly `*.localhost` URLs for the app and enabled HTTP services. */
|
|
197
|
+
portless?: boolean;
|
|
198
|
+
/** Actual dev-server / app port; CLI and Vite supply this when known. */
|
|
199
|
+
appPort?: number;
|
|
200
|
+
/** Installs SIGINT/SIGTERM handlers by default; disable in tests or when the caller manages its own signals. */
|
|
201
|
+
installSignalHandlers?: boolean;
|
|
202
|
+
mode?: "http" | "https";
|
|
203
|
+
elastic?: boolean | ServiceConfig<ElasticEnv>;
|
|
204
|
+
mongo?: boolean | ServiceConfig<MongoEnv>;
|
|
205
|
+
bee?: boolean | ServiceConfig<BeeEnv>;
|
|
206
|
+
sso?: boolean | ServiceConfig<SsoEnv>;
|
|
207
|
+
index?: boolean | ServiceConfig<IndexEnv>;
|
|
208
|
+
gateway?: boolean | ServiceConfig<GatewayEnv>;
|
|
209
|
+
credit?: boolean | ServiceConfig<CreditEnv>;
|
|
210
|
+
beehive?: boolean | ServiceConfig<BeehiveEnv>;
|
|
211
|
+
shkeeper?: boolean | ShkeeperConfig;
|
|
212
|
+
}
|
|
213
|
+
//#endregion
|
|
214
|
+
//#region src/manager.d.ts
|
|
215
|
+
/**
|
|
216
|
+
* Stops the Docker container groups for the named logical service(s). Multi-container services stop
|
|
217
|
+
* as a whole group and overlapping groups are de-duplicated (see {@link containerNamesFor}).
|
|
218
|
+
* Throws a `TypeError` (listing valid names) for any unknown service name.
|
|
219
|
+
*/
|
|
220
|
+
declare function stop(services: EthernaServiceName | EthernaServiceName[]): Promise<void>;
|
|
221
|
+
/**
|
|
222
|
+
* Starts the enabled Etherna services following the canonical dependency graph
|
|
223
|
+
* ({@link SERVICE_CATALOG}), wiring a {@link createSession} for spawn tracking, Portless bookkeeping,
|
|
224
|
+
* and shutdown. On a startup failure with `onFailure: "stop"`, stops the Docker containers for every
|
|
225
|
+
* enabled service in this run — even when detached — before shutting the session down.
|
|
226
|
+
*
|
|
227
|
+
* Detached mode defaults to `false` unless `options.detached` or `ETHERNA_DETACHED` is set (matches
|
|
228
|
+
* the Vite plugin). The CLI passes `detached: true` by default separately.
|
|
229
|
+
*/
|
|
230
|
+
declare function start(options?: StartOptions): Promise<EthernaSessionHandle>;
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region src/resolve-options.d.ts
|
|
233
|
+
declare const ETHERNA_DETACHED_ENV = "ETHERNA_DETACHED";
|
|
234
|
+
/**
|
|
235
|
+
* Resolves detached mode: explicit `options.detached` wins, then `ETHERNA_DETACHED` env, then `false`.
|
|
236
|
+
* Env is truthy for `1`, `true`, `yes` (case-insensitive); falsy for `0`, `false`, `no`, or unset.
|
|
237
|
+
* Ported from `src/plugin-define.ts`.
|
|
238
|
+
*/
|
|
239
|
+
declare function resolveDetachedMode(options: Pick<StartOptions, "detached">): boolean;
|
|
240
|
+
//#endregion
|
|
241
|
+
export { type AspServiceEnv, type BeeEnv, type BeehiveEnv, type CreditEnv, ETHERNA_DETACHED_ENV, type ElasticEnv, type EthernaServiceName, type EthernaSessionHandle, type GatewayEnv, type IndexEnv, type MongoEnv, type ServiceConfig, type ShkeeperBuildConfig, type ShkeeperConfig, type ShkeeperEnv, type ShkeeperEthereumConfig, type ShkeeperEthereumEnv, type SsoEnv, type StartOptions, resolveDetachedMode, start, stop };
|
|
242
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import e from"node:process";import t from"node:os";import n from"node:tty";import{spawn as r}from"node:child_process";import i from"node:fs";import a from"node:path";import{secp256k1 as o}from"@noble/curves/secp256k1.js";import{keccak_256 as s}from"@noble/hashes/sha3.js";const c=(e=0)=>t=>`\u001B[${t+e}m`,l=(e=0)=>t=>`\u001B[${38+e};5;${t}m`,u=(e=0)=>(t,n,r)=>`\u001B[${38+e};2;${t};${n};${r}m`,d={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};Object.keys(d.modifier);const f=Object.keys(d.color),p=Object.keys(d.bgColor);[...f,...p];function m(){let e=new Map;for(let[t,n]of Object.entries(d)){for(let[t,r]of Object.entries(n))d[t]={open:`\u001B[${r[0]}m`,close:`\u001B[${r[1]}m`},n[t]=d[t],e.set(r[0],r[1]);Object.defineProperty(d,t,{value:n,enumerable:!1})}return Object.defineProperty(d,"codes",{value:e,enumerable:!1}),d.color.close=`\x1B[39m`,d.bgColor.close=`\x1B[49m`,d.color.ansi=c(),d.color.ansi256=l(),d.color.ansi16m=u(),d.bgColor.ansi=c(10),d.bgColor.ansi256=l(10),d.bgColor.ansi16m=u(10),Object.defineProperties(d,{rgbToAnsi256:{value(e,t,n){return e===t&&t===n?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(t/255*5)+Math.round(n/255*5)},enumerable:!1},hexToRgb:{value(e){let t=/[a-f\d]{6}|[a-f\d]{3}/i.exec(e.toString(16));if(!t)return[0,0,0];let[n]=t;n.length===3&&(n=[...n].map(e=>e+e).join(``));let r=Number.parseInt(n,16);return[r>>16&255,r>>8&255,r&255]},enumerable:!1},hexToAnsi256:{value:e=>d.rgbToAnsi256(...d.hexToRgb(e)),enumerable:!1},ansi256ToAnsi:{value(e){if(e<8)return 30+e;if(e<16)return 90+(e-8);let t,n,r;if(e>=232)t=((e-232)*10+8)/255,n=t,r=t;else{e-=16;let i=e%36;t=Math.floor(e/36)/5,n=Math.floor(i/6)/5,r=i%6/5}let i=Math.max(t,n,r)*2;if(i===0)return 30;let a=30+(Math.round(r)<<2|Math.round(n)<<1|Math.round(t));return i===2&&(a+=60),a},enumerable:!1},rgbToAnsi:{value:(e,t,n)=>d.ansi256ToAnsi(d.rgbToAnsi256(e,t,n)),enumerable:!1},hexToAnsi:{value:e=>d.ansi256ToAnsi(d.hexToAnsi256(e)),enumerable:!1}}),d}const h=m();function g(t,n=globalThis.Deno?globalThis.Deno.args:e.argv){let r=t.startsWith(`-`)?``:t.length===1?`-`:`--`,i=n.indexOf(r+t),a=n.indexOf(`--`);return i!==-1&&(a===-1||i<a)}const{env:_}=e;let v;g(`no-color`)||g(`no-colors`)||g(`color=false`)||g(`color=never`)?v=0:(g(`color`)||g(`colors`)||g(`color=true`)||g(`color=always`))&&(v=1);function y(){if(`FORCE_COLOR`in _)return _.FORCE_COLOR===`true`?1:_.FORCE_COLOR===`false`?0:_.FORCE_COLOR.length===0?1:Math.min(Number.parseInt(_.FORCE_COLOR,10),3)}function b(e){return e!==0&&{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function ee(n,{streamIsTTY:r,sniffFlags:i=!0}={}){let a=y();a!==void 0&&(v=a);let o=i?v:a;if(o===0)return 0;if(i){if(g(`color=16m`)||g(`color=full`)||g(`color=truecolor`))return 3;if(g(`color=256`))return 2}if(`TF_BUILD`in _&&`AGENT_NAME`in _)return 1;if(n&&!r&&o===void 0)return 0;let s=o||0;if(_.TERM===`dumb`)return s;if(e.platform===`win32`){let e=t.release().split(`.`);return Number(e[0])>=10&&Number(e[2])>=10586?Number(e[2])>=14931?3:2:1}if(`CI`in _)return[`GITHUB_ACTIONS`,`GITEA_ACTIONS`,`CIRCLECI`].some(e=>e in _)?3:[`TRAVIS`,`APPVEYOR`,`GITLAB_CI`,`BUILDKITE`,`DRONE`].some(e=>e in _)||_.CI_NAME===`codeship`?1:s;if(`TEAMCITY_VERSION`in _)return+!!/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(_.TEAMCITY_VERSION);if(_.COLORTERM===`truecolor`||_.TERM===`xterm-kitty`||_.TERM===`xterm-ghostty`||_.TERM===`wezterm`)return 3;if(`TERM_PROGRAM`in _){let e=Number.parseInt((_.TERM_PROGRAM_VERSION||``).split(`.`)[0],10);switch(_.TERM_PROGRAM){case`iTerm.app`:return e>=3?3:2;case`Apple_Terminal`:return 2}}return/-256(color)?$/i.test(_.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(_.TERM)||`COLORTERM`in _?1:s}function te(e,t={}){return b(ee(e,{streamIsTTY:e&&e.isTTY,...t}))}const ne={stdout:te({isTTY:n.isatty(1)}),stderr:te({isTTY:n.isatty(2)})};function re(e,t,n){let r=e.indexOf(t);if(r===-1)return e;let i=t.length,a=0,o=``;do o+=e.slice(a,r)+t+n,a=r+i,r=e.indexOf(t,a);while(r!==-1);return o+=e.slice(a),o}function ie(e,t,n,r){let i=0,a=``;do{let o=e[r-1]===`\r`;a+=e.slice(i,o?r-1:r)+t+(o?`\r
|
|
2
|
+
`:`
|
|
3
|
+
`)+n,i=r+1,r=e.indexOf(`
|
|
4
|
+
`,i)}while(r!==-1);return a+=e.slice(i),a}const{stdout:ae,stderr:oe}=ne,se=Symbol(`GENERATOR`),x=Symbol(`STYLER`),S=Symbol(`IS_EMPTY`),ce=[`ansi`,`ansi`,`ansi256`,`ansi16m`],C=Object.create(null),le=(e,t={})=>{if(t.level&&!(Number.isInteger(t.level)&&t.level>=0&&t.level<=3))throw Error("The `level` option should be an integer from 0 to 3");let n=ae?ae.level:0;e.level=t.level===void 0?n:t.level},ue=e=>{let t=(...e)=>e.join(` `);return le(t,e),Object.setPrototypeOf(t,w.prototype),t};function w(e){return ue(e)}Object.setPrototypeOf(w.prototype,Function.prototype);for(let[e,t]of Object.entries(h))C[e]={get(){let n=T(this,pe(t.open,t.close,this[x]),this[S]);return Object.defineProperty(this,e,{value:n}),n}};C.visible={get(){let e=T(this,this[x],!0);return Object.defineProperty(this,"visible",{value:e}),e}};const de=(e,t,n,...r)=>e===`rgb`?t===`ansi16m`?h[n].ansi16m(...r):t===`ansi256`?h[n].ansi256(h.rgbToAnsi256(...r)):h[n].ansi(h.rgbToAnsi(...r)):e===`hex`?de(`rgb`,t,n,...h.hexToRgb(...r)):h[n][e](...r);for(let e of[`rgb`,`hex`,`ansi256`]){C[e]={get(){let{level:t}=this;return function(...n){let r=pe(de(e,ce[t],`color`,...n),h.color.close,this[x]);return T(this,r,this[S])}}};let t=`bg`+e[0].toUpperCase()+e.slice(1);C[t]={get(){let{level:t}=this;return function(...n){let r=pe(de(e,ce[t],`bgColor`,...n),h.bgColor.close,this[x]);return T(this,r,this[S])}}}}const fe=Object.defineProperties(()=>{},{...C,level:{enumerable:!0,get(){return this[se].level},set(e){this[se].level=e}}}),pe=(e,t,n)=>{let r,i;return n===void 0?(r=e,i=t):(r=n.openAll+e,i=t+n.closeAll),{open:e,close:t,openAll:r,closeAll:i,parent:n}},T=(e,t,n)=>{let r=(...e)=>me(r,e.length===1?``+e[0]:e.join(` `));return Object.setPrototypeOf(r,fe),r[se]=e,r[x]=t,r[S]=n,r},me=(e,t)=>{if(e.level<=0||!t)return e[S]?``:t;let n=e[x];if(n===void 0)return t;let{openAll:r,closeAll:i}=n;if(t.includes(`\x1B`))for(;n!==void 0;)t=re(t,n.close,n.open),n=n.parent;let a=t.indexOf(`
|
|
5
|
+
`);return a!==-1&&(t=ie(t,i,r,a)),r+t+i};Object.defineProperties(w.prototype,C);const E=w();w({level:oe?oe.level:0});const he={"bee-blockchain":{code:`bee-blockchain`,service:`bee`,dependencies:[],onFailure:`stop`},"bee-nodes":{code:`bee-nodes`,service:`bee`,dependencies:[`bee-blockchain`],onFailure:`stop`},shkeeper:{code:`shkeeper`,service:`shkeeper`,dependencies:[],onFailure:`stop`},mongo:{code:`mongo`,service:`mongo`,dependencies:[],onFailure:`stop`},sso:{code:`sso`,service:`sso`,dependencies:[`mongo`],onFailure:`stop`},index:{code:`index`,service:`index`,dependencies:[`mongo`],onFailure:`stop`},beehive:{code:`beehive`,service:`beehive`,dependencies:[`mongo`],onFailure:`stop`},gateway:{code:`gateway`,service:`gateway`,dependencies:[`mongo`,`sso`],onFailure:`stop`},credit:{code:`credit`,service:`credit`,dependencies:[`mongo`,`sso`,`shkeeper`],onFailure:`stop`},elastic:{code:`elastic`,service:`elastic`,dependencies:[],onFailure:`stop`}},ge=[`blockchain`,`bee`,`beehive`,`credit`,`elastic`,`gateway`,`index`,`mongo`,`shkeeper`,`sso`];ge.filter(e=>e!==`shkeeper`);var D=class extends Error{constructor(e){super(e),this.name=`DependencyTreeValidationError`}};function _e(e){return e instanceof Error?e:Error(String(e))}function ve(e,t){let n=new Set;for(let r=0;r<t.length;r++){let i=t[r];if(i.status!==`started`&&i.status!==`skipped`)if(i.status===`failed`)n.add(i.code);else{let t=i.blockedBy;if(t&&t.length>0)for(let e of t)n.add(e);else n.add(e[r])}}return[...n]}function ye(e){let t=new Set;for(let n of e){if(t.has(n.code))throw new D(`Duplicate service code "${String(n.code)}".`);t.add(n.code)}for(let n of e){let e=n.dependencies??[];for(let r of e){if(r===n.code)throw new D(`Service "${String(n.code)}" cannot depend on itself.`);if(!t.has(r))throw new D(`Service "${String(n.code)}" depends on unknown service "${String(r)}".`)}}let n=new Set,r=new Set,i=new Map(e.map(e=>[e.code,e]));function a(e){if(r.has(e))return;if(n.has(e))throw new D(`Dependency cycle detected involving service "${String(e)}".`);n.add(e);let t=i.get(e);if(t){for(let e of t.dependencies??[])a(e);n.delete(e),r.add(e)}}for(let t of e)a(t.code)}function be(e,t){ye(e);let n=new Map(e.map(e=>[e.code,e])),r=new Map;function i(e){let a=r.get(e);if(a)return a;let o=n.get(e);if(!o)throw new D(`Unknown service code "${String(e)}".`);let s=(async()=>{let n=o.dependencies??[],r=await Promise.all(n.map(e=>i(e)));if(r.some(e=>e.status!==`started`&&e.status!==`skipped`))return{code:e,status:`blocked`,blockedBy:ve(n,r)};if(o.enabled===!1)return{code:e,status:`skipped`};let a=o.onFailure??`stop`;try{if(o.beforeStartup&&await o.beforeStartup(),!await o.startupCallback()){let n=Error(`Service startup returned false`);return a===`log`&&t.logError(String(e),n.message),{code:e,status:`failed`,error:n}}return{code:e,status:`started`}}catch(n){let r=_e(n);return a===`log`&&t.logError(String(e),r.message),{code:e,status:`failed`,error:r}}})();return r.set(e,s),s}return{start:async()=>{let t=await Promise.all(e.map(e=>i(e.code)));return{shouldStop:t.some(e=>e.status===`failed`&&(n.get(e.code)?.onFailure??`stop`)===`stop`),services:t}}}}const xe=`/usr/local/share/ca-certificates`,Se={"etherna-sso":`sso`,"etherna-index":`index`,"etherna-credit":`credit`,"etherna-gateway":`gateway`,"etherna-beehive":`beehive`};function O(e){return`http://${e}.localhost:1355`}function k(e){return e.trim().replace(/\/+$/,``)}function Ce(){return[`proxy`,`start`,`-p`,`1355`,`--no-tls`]}function we(){return[`proxy`,`stop`]}function Te(e,t,n=!1){let r=[`alias`,e,String(t)];return n&&r.push(`--force`),r}function Ee(e){return[`alias`,`--remove`,e]}async function A(e){return new Promise((t,n)=>{let i=r(`portless`,e,{stdio:[`ignore`,`pipe`,`pipe`]}),a=``,o=``;i.stdout?.on(`data`,e=>{a+=String(e)}),i.stderr?.on(`data`,e=>{o+=String(e)}),i.on(`error`,n),i.on(`exit`,e=>{t({code:e??1,stderr:o,stdout:a})})})}async function De(){try{return(await A([`--version`])).code===0}catch{return!1}}async function Oe(){let e=await A(Ce());if(e.code===0)return{startedByUs:!0};let t=`${e.stderr}\n${e.stdout}`;if(/already|in use|running|listen/i.test(t))return{startedByUs:!1};throw Error(`portless proxy start failed (exit ${e.code}): ${t.trim()||`(no output)`}`)}function ke(e){if(typeof e==`number`&&Number.isFinite(e))return e;let t=String(e).trim();if(t===``)throw Error(`Port value is empty`);let n=Number.parseInt(t,10);if(!Number.isFinite(n))throw Error(`Invalid port: ${String(e)}`);return n}async function Ae(e,t){let n=ke(t),r=await A(Te(e,n,!0));if(r.code!==0){let t=`${r.stderr}\n${r.stdout}`;throw Error(`portless alias ${e} ${n} failed: ${t.trim()}`)}}async function je(e){for(let t of e)await A(Ee(t))}async function Me(){await A(we())}const Ne=1633,Pe=1634,j=9545,Fe=4020,Ie=`0xCEeE442a149784faa65C35e328CCd64d874F9a02`,Le=[`POSTAGE_PRICE`],Re=32650,M=`shkeeper`;function ze(e){let{mode:t,portless:n,appPort:r,portlessAppPublicUrl:i}=e,a=t===`http`?32610:42610,o=t===`http`?32620:42620,s=t===`http`?32630:42630,c=t===`http`?32640:42640,l=`mongodb://localhost:27017`,u=P(t,a),d=P(t,o),f=P(t,s),p=P(t,c),m=P(t,12610),h=`http://localhost:${Ne}`,g=n&&i?k(i):Ve(t,r,n,`app`),_={ASPNETCORE_ENVIRONMENT:`Development`,"Elastic:Urls:0":`http://localhost:9200`,...t===`https`?{ASPNETCORE_Kestrel__Certificates__Default__Path:`${xe}/etherna.pfx`,ASPNETCORE_Kestrel__Certificates__Default__Password:``}:{}};return{app:{port:r},shkeeper:{port:Re},"shkeeper-core":{DEV_MODE:`1`,BTC_WALLET:`disabled`,LTC_WALLET:`disabled`,DOGE_WALLET:`disabled`,ETH_WALLET:`enabled`,ETH_USERNAME:`shkeeper`,ETH_PASSWORD:`shkeeper`,ETHEREUM_API_SERVER_HOST:`localhost`,ETHEREUM_SERVER_PORT:`6000`,SHKEEPER_BACKEND_KEY:M,SHKEEPER_BTC_BACKEND_KEY:M},"ethereum-shkeeper":{FULLNODE_URL:`http://localhost:${j}`,FULLNODE_TIMEOUT:`60`,CURRENT_ETH_NETWORK:`custom`,WEB3_ENABLE_POA_MIDDLEWARE:`1`,BLOCK_SCANNER_MAX_CATCHUP_BLOCKS:`64`,ETH_USERNAME:`shkeeper`,ETH_PASSWORD:`shkeeper`,SHKEEPER_BACKEND_KEY:M,SHKEEPER_HOST:`localhost:${Re}`,REDIS_HOST:`localhost`,SQLALCHEMY_DATABASE_URI:`mariadb+pymysql://root:shkeeper@localhost:3306/ethereum-shkeeper?charset=utf8mb4`,LAST_BLOCK_LOCKED:`FALSE`},elastic:{"discovery.type":`single-node`,"xpack.security.enabled":`false`,ES_JAVA_OPTS:`-Xms512m -Xmx512m`},"etherna-mongodb":{},"etherna-sso":{..._,ASPNETCORE_URLS:u,"IdServer:SsoServer:BaseUrl":u,"IdServer:SsoServer:AllowUnsafeConnection":`true`,"IdServer:Clients:EthernaCredit:BaseUrl":f,"IdServer:Clients:EthernaGateway:BaseUrls:0":p,"IdServer:Clients:EthernaIndex:BaseUrl":d,"IdServer:Clients:EthernaDapp:BaseUrl":g,"DbSeed:Clients:0:RedirectUris:0":`${g}/callback`,"DbSeed:Clients:0:PostLogoutRedirectUris:0":g,"DbSeed:Clients:0:AllowedCorsOrigins:0":g,"ConnectionStrings:DataProtectionDb":`${l}/ethernaSSODataProtectionDev`,"ConnectionStrings:HangfireDb":`${l}/ethernaSSOHangfireDev`,"ConnectionStrings:ServiceSharedDb":`${l}/ethernaServiceSharedDev`,"ConnectionStrings:SSOServerDb":`${l}/ethernaSSODev`},"etherna-index":{..._,ASPNETCORE_URLS:d,"Swarm:GatewayUrl":p,"SsoServer:BaseUrl":u,"SsoServer:AllowUnsafeConnection":`true`,"ConnectionStrings:DataProtectionDb":`${l}/ethernaSharedDataProtectionDev`,"ConnectionStrings:HangfireDb":`${l}/ethernaIndexHangfireDev`,"ConnectionStrings:IndexDb":`${l}/ethernaIndexDev`,"ConnectionStrings:ServiceSharedDb":`${l}/ethernaServiceSharedDev`},"etherna-credit":{..._,ASPNETCORE_URLS:f,"SsoServer:BaseUrl":u,"SsoServer:AllowUnsafeConnection":`true`,"ConnectionStrings:DataProtectionDb":`${l}/ethernaSharedDataProtectionDev`,"ConnectionStrings:HangfireDb":`${l}/ethernaCreditHangfireDev`,"ConnectionStrings:CreditDb":`${l}/ethernaCreditDev`,"ConnectionStrings:ServiceSharedDb":`${l}/ethernaServiceSharedDev`,DisableHttpsRedirection:`true`,"Payments:ShKeeper:Url":`http://localhost:${Re}`,"Payments:ShKeeper:ApiKey":M,"Payments:ShKeeper:CustomCallbackBaseUrl":f},"etherna-gateway":{..._,ASPNETCORE_URLS:p,"ForwardedHeaders:KnownNetworks:0":`0.0.0.0/0`,"SsoServer:BaseUrl":u,"SsoServer:Clients:Credit:BaseUrl":f,"SsoServer:Clients:Credit:Secret":`ethernaGatewayCreditClientSecret`,"SsoServer:Clients:Webapp:Secret":`ethernaGatewayWebappClientSecret`,"SsoServer:AllowUnsafeConnection":`true`,"Bee:CachedUrl":m,"Bee:DirectUrl":m,"Features:GarbageCollectPins":`false`,ForwardedAllowedHosts:`*`,"ConnectionStrings:DataProtectionDb":`${l}/ethernaSharedDataProtectionDev`,"ConnectionStrings:HangfireDb":`${l}/ethernaGatewayHangfireDev`,"ConnectionStrings:GatewayDb":`${l}/ethernaGatewayDev`,"ConnectionStrings:ServiceSharedDb":`${l}/ethernaServiceSharedDev`},"etherna-beehive":{..._,ASPNETCORE_URLS:m,"SeedDb:BeeNodes:0:Hostname":`localhost`,"ConnectionStrings:DataProtectionDb":`${l}/beehiveDataProtectionDev`,"ConnectionStrings:HangfireDb":`${l}/beehiveHangfireDev`,"ConnectionStrings:BeehiveDb":`${l}/beehiveDev`,"SeedDb:BeeNodes:0:ConnectionString":h,"SeedDb:BeeNodes:0:EnableBatchCreation":`true`},"etherna-blockchain":{BLOCKCHAIN_PORT:j,NETWORK_ID:Fe},"etherna-bee":{POSTAGE_PRICE:`24000`,BEE_WARMUP_TIME:`10s`,BEE_DEBUG_API_ENABLE:`true`,BEE_VERBOSITY:`4`,BEE_SWAP_ENABLE:`true`,BEE_MAINNET:`false`,BEE_SWAP_ENDPOINT:`http://etherna-blockchain:${j}`,BEE_BLOCKCHAIN_RPC_ENDPOINT:`http://etherna-blockchain:${j}`,BEE_PASSWORD:`password`,BEE_SWAP_FACTORY_ADDRESS:`0xCfEB869F69431e42cdB54A4F4f105C19C080A601`,BEE_POSTAGE_STAMP_ADDRESS:`0x254dffcd3277C0b1660F6d42EFbB754edaBAbC2B`,BEE_PRICE_ORACLE_ADDRESS:`0x5b1869D9A4C187F2EAa108f3062412ecf0526b24`,BEE_REDISTRIBUTION_ADDRESS:`0x9561C133DD8580860B6b7E504bC5Aa500f0f06a7`,BEE_STAKING_ADDRESS:`0xD833215cBcc3f914bD1C9ece3EE7BF8B14f841bb`,BEE_POSTAGE_STAMP_START_BLOCK:`1`,BEE_NETWORK_ID:Fe,BEE_FULL_NODE:`true`,BEE_PORT:Ne,BEE_P2P_PORT:Pe,BEE_API_ADDR:`0.0.0.0:${Ne}`,BEE_P2P_ADDR:`0.0.0.0:${Pe}`,BEE_CORS_ALLOWED_ORIGINS:`*`,BEE_ALLOW_PRIVATE_CIDRS:`true`,BEE_BOOTNODE_MODE:``,BEE_BOOTNODE:``}}}function Be(e){return{mode:e,portless:!1,appPort:e===`http`?5173:5371}}function N(e){let t=e.split(`;`)[0]?.trim()??``;try{let e=new URL(t);return e.port?e.port:e.protocol===`https:`?`443`:`80`}catch{return t.split(`:`)[2]??`80`}}function P(e,t){return`${e}://localhost:${t}`}function Ve(e,t,n,r){return n?O(r):P(e,t)}const F=(e,t)=>ze(t)[e]??null;function He(e){let t=new Set(Le);return Object.fromEntries(Object.entries(e).filter(([e])=>!t.has(e)))}const Ue=`ETHERNA_DETACHED`;function We(e){if(typeof e.detached==`boolean`)return e.detached;let t=process.env[Ue]?.trim().toLowerCase();return t===`1`||t===`true`||t===`yes`}const Ge=[`elastic`,`mongo`,`bee`,`sso`,`index`,`gateway`,`credit`,`beehive`,`shkeeper`];function Ke(e){return typeof e==`object`&&e?e.enabled!==!1:e!==!1}function qe(e){return e===!0?!0:typeof e==`object`&&e?e.enabled!==!1:!1}function Je(e){let t={};for(let n of Ge)t[n]=n===`shkeeper`?qe(e[n]):Ke(e[n]);t.blockchain=t.bee;let n={enabled:t,detached:We(e),portless:e.portless??!1,mode:e.mode??`http`,installSignalHandlers:e.installSignalHandlers??!0};return e.appPort!==void 0&&(n.appPort=e.appPort),n}function Ye(e){return new Promise(t=>setTimeout(t,e))}async function Xe(e){let t=e?.containerName??`shkeeper`,n=e?.sqlitePath??`/shkeeper.io/instance/shkeeper.sqlite`,r=e?.maxAttempts??120,i=e?.intervalMs??1e3;for(let e=0;e<r;e++){let a=await Ze(t,n,`SELECT apikey FROM wallet WHERE apikey IS NOT NULL AND TRIM(COALESCE(apikey, '')) != '' LIMIT 1`);if(a)return a;e<r-1&&await Ye(i)}return null}function Ze(e,t,n){return new Promise(i=>{let a=r(`docker`,[`exec`,e,`sqlite3`,t,n]),o=``;a.stdout?.on(`data`,e=>{o+=typeof e==`string`?e:e.toString(`utf8`)}),a.on(`error`,()=>{i(null)}),a.on(`close`,e=>{if(e!==0){i(null);return}let t=o.trim();i(t.length>0?t:null)})})}function Qe(e){let t=typeof process<`u`?process.env?.[e]:void 0;if(t!==void 0)return t;try{let t=import.meta.env?.[e];return typeof t==`string`?t:void 0}catch{return}}function I(...e){return a.resolve(`node_modules/.vite`,...e)}function $e(...e){let t=I(...e);return process.platform===`win32`?t.replace(/\\/g,`/`):t}function L(e,t,n,r){if(r?.portlessUrl){let i=`${r.portlessUrl.replace(/\/$/,``)}/`,a=`${t}://localhost:${n}/`;console.log(` ${E.green(`➜`)} ${E.bold(e)}: ${E.cyan(i)} ${E.gray(`(${a})`)}`);return}let i=`${t}://localhost:${E.bold.cyanBright(n)}/`;console.log(` ${E.green(`➜`)} ${E.bold(e)}: ${E.cyan(i)}`)}function et(e){console.log(` ${E.gray(`➜`)} ${E.bold(e)}: ${E.yellow(`Downloading image...`)}`)}function R(e,t){console.log(` ${E.red(`x`)} ${E.bold(e)}: ${E.red(t)}`)}async function tt(e,t,n){let i=r(e,t,n);return new Promise((e,t)=>{i.on(`error`,e=>{t(e)}),i.on(`exit`,()=>{e()})})}async function nt(e){let t=await fetch(`${e}/addresses`);if(!t.ok)throw Error(`Failed to fetch addresses from ${e}: ${t.statusText}`);let n=await t.json(),r=Array.isArray(n.underlay)?n.underlay:[];if(r.length===0)return await new Promise(e=>setTimeout(e,500)),nt(e);let i=r.find(e=>!e.includes(`127.0.0.1`));if(!i)throw Error(`No valid underlay address found in response from ${e}`);return i}const rt=`etherna-`;function z(e){return e.startsWith(rt)?e:`${rt}${e}`}const it=`https://docs.docker.com/get-docker/`,at=3e4;function B(e,t){r(e,t,{detached:!0,stdio:`ignore`}).unref()}function ot(){return new Promise(e=>{let t=r(`docker`,[`info`],{stdio:`ignore`});t.on(`error`,()=>e(!1)),t.on(`exit`,t=>e(t===0))})}function st(){return new Promise(e=>{let t=r(`docker`,[`--version`],{stdio:`ignore`});t.on(`error`,()=>e(!1)),t.on(`exit`,t=>e(t===0))})}function ct(){let{platform:e}=process;if(e===`darwin`){B(`open`,[`-a`,`Docker`]);return}if(e===`win32`){let e=`C:\\Program Files\\Docker\\Docker\\Docker Desktop.exe`;if(i.existsSync(e)){B(e,[]);return}B(`cmd`,[`/c`,`start`,``,`Docker Desktop`]);return}e===`linux`&&B(`systemctl`,[`--user`,`start`,`docker-desktop`])}function lt(e){return new Promise(t=>setTimeout(t,e))}async function ut(){if(await st()||(console.error(` ${E.red(`x`)} ${E.bold(`docker`)}: ${E.red(`Docker is not installed or not on your PATH.`)}`),console.error(` Install Docker and try again: ${E.cyan.underline(it)}`),process.exit(1)),await ot())return;console.log(` ${E.yellow(`➜`)} ${E.bold(`docker`)}: ${E.yellow(`Docker daemon is not running. Starting it…`)}`),ct();let e=Date.now()+at;for(;Date.now()<e;)if(await lt(2e3),await ot()){console.log(` ${E.green(`➜`)} ${E.bold(`docker`)}: ${E.green(`Docker is ready.`)}`);return}console.error(` ${E.red(`x`)} ${E.bold(`docker`)}: ${E.red(`Docker did not become ready within ${at/1e3}s. Start Docker manually and run the dev server again.`)}`),console.error(` Install or troubleshoot: ${E.cyan.underline(it)}`),process.exit(1)}async function V({containerName:e,imageName:t,args:n=[],cmd:i=[],detached:a=!1}){let o=z(e);if(!a)await dt(o)&&await ft(o);else{if(await pt(o))return null;await dt(o)&&await mt(o)}let s=[`run`,`--rm`,`--name`,o,...n,t,...i],c=a?r(`docker`,[...s],{detached:!0,stdio:[`ignore`,`pipe`,`pipe`]}):r(`docker`,[...s]);return c.stdout?.on(`data`,e=>{let t=String(e);/Pulling from/gm.test(t)&&et(o),/Error response from daemon/gm.test(t)&&R(o,t)}),a&&c.unref(),c}async function dt(e){let t=r(`docker`,[`ps`,`-a`,`--filter`,`name=${z(e)}`]);return(await new Promise(e=>{let n=``;t.stdout?.on(`data`,e=>{n+=String(e)}),t.on(`close`,()=>{e(n)})})).split(`
|
|
6
|
+
`).length>1}async function ft(e){let t=r(`docker`,[`stop`,z(e)]);await new Promise(e=>{t.on(`close`,()=>{e()})})}async function pt(e){return new Promise(t=>{let n=r(`docker`,[`inspect`,`-f`,`{{.State.Running}}`,z(e)],{stdio:[`ignore`,`pipe`,`ignore`]}),i=``;n.stdout?.on(`data`,e=>{i+=String(e)}),n.on(`error`,()=>t(!1)),n.on(`close`,e=>{if(e!==0){t(!1);return}t(i.trim().toLowerCase()===`true`)})})}async function mt(e){await new Promise(t=>{let n=r(`docker`,[`rm`,`-f`,z(e)],{stdio:`ignore`});n.on(`error`,()=>t()),n.on(`close`,()=>t())})}async function H(e){let t=r(`docker`,[`volume`,`create`,e]);await new Promise(e=>{t.on(`close`,()=>{e()})})}async function ht(e){let t=r(`docker`,[`network`,`create`,e]);await new Promise(e=>{t.on(`close`,()=>{e()})})}const gt={blockchain:[`etherna-blockchain`],bee:[`etherna-blockchain`,`etherna-bee`,`etherna-bee_worker_1`],beehive:[`etherna-beehive`],credit:[`etherna-credit`],elastic:[`etherna-elastic`],gateway:[`etherna-gateway`],index:[`etherna-index`],mongo:[`etherna-mongodb`],shkeeper:[`ethereum-shkeeper-mariadb`,`ethereum-shkeeper-redis`,`ethereum-shkeeper`,`ethereum-tasks`,`shkeeper`],sso:[`etherna-sso`]};function _t(e){return gt[e]}async function vt(e){let t=[...new Set(e.flatMap(_t))];await Promise.all(t.map(e=>ft(e)))}async function yt(e){await vt(Object.keys(e).filter(t=>e[t]))}async function bt(e){await tt(`docker`,[`exec`,e,`update-ca-certificates`]).catch(t=>{console.error(E.red(`‼️ Error trusting certificate in container '${e}': ${t.message}`))})}async function U(e,t,n,r){let i,a=new Promise(e=>{i=e}),o,{mode:s}=e.serviceCtx,c={...F(t,e.serviceCtx)??{},...r},l=c.ASPNETCORE_URLS.split(`;`)[0]?.split(`:`)[2]??`80`,u=Se[t],d=e.serviceCtx.portless&&u?O(u):void 0,f=await V({containerName:t,imageName:n,args:[...Object.entries(c).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),...s===`https`?[`--mount`,`type=bind,source=${$e(`.ssl`)},target=${xe}/`]:[],`--network`,`host`],detached:e.detached});if(!f)return L(t,s,l,{portlessUrl:d}),null;e.pushSpawn(f);let p=async e=>{o=void 0;let n=String(e);/Now listening on: https?:\/\/(localhost|\[::\]):\d+/gm.test(n)&&(s===`https`&&await bt(t),L(t,s,l,{portlessUrl:d}),i?.());let r=[/Current db does not support change stream/gm,/is only supported on replica sets./gm,/Failed to process the job/gm],a=[/\[(ERR|FTL)\]/gm,/"LogLevel"\s*:\s*"(Error|Critical)"/gm,/\b(fail|crit):/gm,/<(2|3)>/gm].some(e=>e.test(n)),c=/\[(INF|WRN|DBG|VRB)\]/gm.test(n);a&&!c&&/Exception:.+/gm.test(n)&&!r.some(e=>e.test(n))?(R(t,n),i?.()):o=n};return f.stdout?.on(`data`,p),f.stdout?.on(`error`,e=>{R(t,`FATAL: `+e.message),i?.()}),f.stderr?.on(`data`,p),f.on(`close`,e=>{R(t,o||`Container closed with code ${e}`),i?.(),f.kill()}),await a,f}function xt(e){return new Promise(t=>setTimeout(t,e))}async function W(e,t,n){let r=await fetch(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({jsonrpc:`2.0`,id:1,method:t,params:n})});if(!r.ok)throw Error(`RPC ${t} failed: ${r.status} ${r.statusText}`);let i=await r.json();if(i.error?.message)throw Error(`RPC ${t} error: ${i.error.message}`);return i.result}async function G(e,t){return(await W(e,`web3_sha3`,[`0x`+Buffer.from(t,`utf-8`).toString(`hex`)])).slice(0,10)}function St(e){if(e<0n)throw Error(`Cannot encode negative uint param: ${e}`);return e.toString(16).padStart(64,`0`)}function Ct(e){let t=e.toLowerCase().startsWith(`0x`)?e.slice(2):e;if(t.length!==40)throw Error(`Invalid address (expected 20 bytes / 40 hex chars): ${e}`);return t.toLowerCase().padStart(64,`0`)}function wt(e){let t=e.startsWith(`0x`)?e.slice(2):e;if(t.length!==64)throw Error(`Invalid bytes32 (expected 32 bytes / 64 hex chars): ${e}`);return t.toLowerCase()}function K(e){let t=e.startsWith(`0x`)?e.slice(2):e;return t.length===0?0n:BigInt(`0x`+t)}async function Tt(e,t,n,r=500){let i=Date.now()+n;for(;Date.now()<i;){let n=await W(e,`eth_getTransactionReceipt`,[t]);if(n?.status)return{status:n.status,blockNumber:n.blockNumber};await xt(r)}throw Error(`Transaction ${t} was not mined within ${n}ms`)}async function Et(e,t){return await W(e,`eth_getCode`,[t,`latest`]).then(e=>e??`0x`)}async function Dt(e){let t=await W(e,`eth_blockNumber`,[]);return Number.parseInt(t??`0x0`,16)}function Ot(e){return e!==`0x`&&e.length>2}async function kt(e,t,n=`pending`){return K(await W(e,`eth_getTransactionCount`,[t,n]))}async function At(e){return K(await W(e,`eth_gasPrice`,[]))}function q(e){let t=e.startsWith(`0x`)?e.slice(2):e,n=t.length%2==0?t:`0`+t;return Uint8Array.from(Buffer.from(n,`hex`))}function J(e){return Buffer.from(e).toString(`hex`)}function Y(e){if(e<0n)throw Error(`Cannot encode negative bigint: ${e}`);if(e===0n)return new Uint8Array;let t=e.toString(16);return t.length%2!=0&&(t=`0`+t),q(t)}function X(...e){let t=e.reduce((e,t)=>e+t.length,0),n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.length;return n}function jt(e,t){if(e<56)return Uint8Array.of(t+e);let n=Y(BigInt(e));return X(Uint8Array.of(t+55+n.length),n)}function Mt(e){if(e instanceof Uint8Array)return e.length===1&&e[0]<128?e:X(jt(e.length,128),e);let t=X(...e.map(Mt));return X(jt(t.length,192),t)}function Nt(e){let t=q(e);if(t.length!==32)throw Error(`Invalid private key length: expected 32 bytes, got ${t.length}`);return`0x`+J(s(o.getPublicKey(t,!1).slice(1)).slice(-20))}function Pt(e,t){if(!e.to.startsWith(`0x`)||e.to.length!==42)throw Error(`Invalid 'to' address: ${e.to}`);let n=[Y(e.nonce),Y(e.gasPrice),Y(e.gasLimit),q(e.to),Y(e.value),q(e.data)],r=s(Mt([...n,Y(e.chainId),new Uint8Array,new Uint8Array])),i=q(t),a=o.sign(r,i,{format:`recovered`,lowS:!0,prehash:!1}),c=a[0],l=K(J(a.subarray(1,33))),u=K(J(a.subarray(33,65))),d=BigInt(c)+35n+e.chainId*2n,f=Mt([...n,Y(d),Y(l),Y(u)]);return{rawTx:`0x`+J(f),hash:`0x`+J(s(f))}}async function Ft(e,t,n,r){let i=Nt(t),[a,o,s]=await Promise.all([W(e,`eth_chainId`,[]),kt(e,i,`pending`),At(e)]),{rawTx:c,hash:l}=Pt({chainId:K(a),nonce:o,gasPrice:s===0n?1n:s,gasLimit:n.gasLimit,to:n.to,value:n.value??0n,data:n.data},t);await W(e,`eth_sendRawTransaction`,[c]);let u=await Tt(e,l,r.timeoutMs,r.pollMs);if(u.status!==`0x1`)throw Error(r.onRevert?.(l)??`Transaction ${l} reverted (status ${u.status}).`);return l}const It=`etherna_bee_network`,Lt=[`BEE_SWAP_FACTORY_ADDRESS`,`BEE_POSTAGE_STAMP_ADDRESS`,`BEE_PRICE_ORACLE_ADDRESS`,`BEE_REDISTRIBUTION_ADDRESS`,`BEE_STAKING_ADDRESS`],Rt=3e4,zt=2e5;let Z=!1,Bt,Vt=Promise.resolve();function Ht(){Z=!0,Vt=new Promise(e=>{Bt=e})}function Q(){Z&&(Z=!1,Bt?.(),Bt=void 0)}function Ut(){return Z}function Wt(){return Vt}function Gt(e){return new Promise(t=>setTimeout(t,e))}async function Kt({rpcUrl:e,postageStampAddress:t,ownerPrivateKey:n,desiredPrice:r}){let i=`etherna-bee`,a=(1n<<64n)-1n;if(r<0n||r>a)throw Error(`POSTAGE_PRICE ${r} is out of range for uint64 (0..${a}).`);let[o,s,c,l,u]=await Promise.all([G(e,`lastPrice()`),G(e,`setPrice(uint256)`),G(e,`hasRole(bytes32,address)`),G(e,`grantRole(bytes32,address)`),G(e,`PRICE_ORACLE_ROLE()`)]),d=async()=>K(await W(e,`eth_call`,[{to:t,data:o},`latest`])),f=await d();if(f===r)return;let p=Nt(n),m=await W(e,`eth_call`,[{to:t,data:u},`latest`]);if(!m||m===`0x`)throw Error(`PostageStamp.PRICE_ORACLE_ROLE() returned no data; ${t} may not be a PostageStamp contract.`);let h=wt(m),g=Ct(p);if(K(await W(e,`eth_call`,[{to:t,data:c+h+g},`latest`]))===0n){console.log(` ${E.yellow(`➜`)} ${E.bold(i)}: granting PRICE_ORACLE_ROLE on PostageStamp to ${E.gray(p)}`);let r=await Ft(e,n,{to:t,data:l+h+g,gasLimit:BigInt(zt)},{timeoutMs:Rt,pollMs:500,onRevert:e=>`PostageStamp.grantRole(PRICE_ORACLE_ROLE, ${p}) reverted (tx ${e}). The owner likely lacks DEFAULT_ADMIN_ROLE on PostageStamp ${t}.`});console.log(` ${E.gray(` granted (tx ${r})`)}`)}console.log(` ${E.yellow(`➜`)} ${E.bold(i)}: updating postage price ${E.gray(String(f))} → ${E.cyan(String(r))} PLUR`);let _=await Ft(e,n,{to:t,data:s+St(r),gasLimit:BigInt(zt)},{timeoutMs:Rt,pollMs:500,onRevert:e=>`PostageStamp.setPrice(${r}) reverted (tx ${e}). The owner ${p} may lack PRICE_ORACLE_ROLE on PostageStamp ${t}.`}),v=await d();if(v!==r)throw Error(`PostageStamp.setPrice(${r}) succeeded (tx ${_}) but PostageStamp.lastPrice is ${v}.`);console.log(` ${E.green(`➜`)} ${E.bold(i)}: postage price set to ${E.cyan(String(r))} PLUR ${E.gray(`(tx ${_})`)}`)}function qt(e){return Error([`Detected a stale or corrupted local blockchain state: Bee contracts are still missing even though the chain has already advanced.`,`Fix it by stopping the dev server, removing the persisted blockchain volume, and starting again:`,`1. Stop the dev server`,`2. Run: docker volume rm ${e}`,`3. Run: pnpm dev`].join(`
|
|
7
|
+
`))}async function Jt(e,t,n){let r=Date.now()+3e4,i=null;for(;Date.now()<r;){let[r,a]=await Promise.all([Dt(e).catch(()=>null),Promise.all(t.map(t=>Et(e,t).catch(()=>null)))]);if(r!=null&&a.every(e=>e!=null)){if(i===null&&(i=r),a.every(e=>Ot(e)))return;if(r>=10||r-i>=2)throw qt(n)}await Gt(1e3)}throw Error(`Bee contracts were not deployed before the startup timeout elapsed. If this keeps happening, stop the dev server, run \`docker volume rm ${n}\`, and start again.`)}async function Yt(e){let t=e.serviceCtx,n=e.getServiceEnv(`bee`),r=`etherna-blockchain`,a=`etherna_blockchain-volume`,o=e.detached,s=He({...F(r,t)??{},...n}),c=Number(s.BLOCKCHAIN_PORT);if(o&&await pt(r))return L(r,`http`,String(c)),null;Ht(),await ht(It),await H(a);let l,u,d,f=new Promise((e,t)=>{u=e,d=t}),p=!1,m=!1;i.existsSync(I(`.ethereum`))||i.mkdirSync(I(`.ethereum`),{recursive:!0,mode:511}),i.existsSync(I(`.ethereum`,`password`))||i.writeFileSync(I(`.ethereum`,`password`),`toTheSun`,{encoding:`utf-8`,mode:420});let h=He({...F(r,t)??{},...n}),g={...F(`etherna-bee`,t)??{},...n},_=Number(h.BLOCKCHAIN_PORT),v=Lt.map(e=>String(g[e])),y=await V({containerName:r,imageName:`fairdatasociety/fdp-play-blockchain:latest`,args:[...Object.entries(h).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--network`,It,`-p`,`${_}:${_}`,`-p`,`${_+1}:${_+1}`,`--mount`,`type=volume,source=${a},target=/root/.ethereum`,`--mount`,`type=bind,source=${$e(`.ethereum`)},target=/root/extra`],detached:o,cmd:[`--allow-insecure-unlock`,`--unlock=${Ie}`,`--password=/root/extra/password`,`--mine`,`--miner.etherbase=${Ie}`,`--http`,`--http.api="debug,web3,eth,txpool,net,personal"`,`--http.corsdomain=*`,`--http.port=${_}`,`--http.addr=0.0.0.0`,`--http.vhosts=*`,`--ws`,`--ws.api="debug,web3,eth,txpool,net,personal"`,`--ws.port=${_+1}`,`--ws.origins=*`,`--maxpeers=0`,`--networkid=${h.NETWORK_ID}`,`--authrpc.vhosts=*`,`--authrpc.addr=0.0.0.0`]});if(!y)return Q(),L(r,`http`,String(_)),null;e.pushSpawn(y);let b=e=>{l=void 0;let t=String(e);!p&&/HTTP server started/gm.test(t)&&(p=!0,Jt(`http://127.0.0.1:${_}`,v,a).then(()=>{m=!0,Q(),u?.()}).catch(e=>{m=!0,Q();let t=e instanceof Error?e.message:String(e);R(r,t),ft(r).finally(()=>{d?.(e)})})),/Error:.+/gm.test(t)?(R(r,t),u?.()):l=t};return y.stdout?.on(`data`,b),y.stdout?.on(`error`,e=>{Q(),R(r,`FATAL: `+e.message),u?.()}),y.stderr?.on(`data`,b),y.on(`close`,e=>{Q(),m||(R(r,l||`Container closed with code ${e}`),u?.()),y.kill()}),await f,y}async function Xt(e){let t=e.serviceCtx,n=e.getServiceEnv(`bee`),r=`etherna-bee`,i=await Zt(e,r),a=await nt(`http://localhost:${F(`etherna-bee`,t)?.BEE_PORT??`1633`}`),[o]=await Promise.all([Zt(e,r,1,a)]);try{let e={...F(`etherna-bee`,t)??{},...n};await Kt({rpcUrl:`http://127.0.0.1:${{...F(`etherna-blockchain`,t)??{},...n}.BLOCKCHAIN_PORT}`,postageStampAddress:String(e.BEE_POSTAGE_STAMP_ADDRESS),ownerPrivateKey:`0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d`,desiredPrice:BigInt(String(e.POSTAGE_PRICE??`24000`))})}catch(e){R(r,`Failed to sync postage price: ${e instanceof Error?e.message:String(e)}`)}return[i,o]}async function Zt(e,t,n,r){let i=e.serviceCtx,a=e.getServiceEnv(`bee`),o=n?`etherna_bee_worker_${n}-volume`:`etherna_bee-volume`;await H(o);let s,c,l=new Promise(e=>{c=e}),{mode:u}=i,d=He({...F(t,i)??{},...a});n?(delete d.BEE_BOOTNODE_MODE,d.BEE_BOOTNODE=r):(delete d.BEE_BOOTNODE,d.BEE_BOOTNODE_MODE=`false`),n&&(t=`${t}_worker_${n}`);let f=await V({containerName:t,imageName:n?`fairdatasociety/fdp-play-worker-${n}`:`fairdatasociety/fdp-play-queen:latest`,args:[...Object.entries(d).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--mount`,`type=volume,source=${o},target=/home/bee/.bee`,`--network`,It,`-p`,`${n?parseInt(d.BEE_PORT??`1633`)+n*1e4:d.BEE_PORT}:${d.BEE_PORT}`,`-p`,`${n?parseInt(d.BEE_P2P_PORT??`1634`)+n*1e4:d.BEE_P2P_PORT}:${d.BEE_P2P_PORT}`],cmd:[`start`],detached:e.detached});if(!f){if(!n){let e=i.portless?O(`bee`):void 0;L(t,u,String(d.BEE_PORT??`1633`),{portlessUrl:e})}return null}e.pushSpawn(f);let p=e=>{s=void 0;let r=String(e);if(/"address"="\[::\]:\d+"/gm.test(r)){if(!n){let e=i.portless?O(`bee`):void 0;L(t,u,String(d.BEE_PORT??`1633`),{portlessUrl:e})}c?.()}let a=[/"logger"="node\/storageincentives"/gm],o=r.split(`
|
|
8
|
+
`).filter(e=>/"level"="(error|critical)"/.test(e)).join(`
|
|
9
|
+
`);o&&!a.some(e=>e.test(r))&&(R(t,o),c?.(),s=o)};return f.stdout?.on(`data`,p),f.stdout?.on(`error`,e=>{R(t,`FATAL: `+e.message),c?.()}),f.stderr?.on(`data`,p),f.on(`close`,e=>{R(t,s||`Container closed with code ${e}`),c?.(),f.kill()}),await l,f}function Qt(e){return{detached:e.detached??!1,serviceCtx:e.serviceCtx,getServiceEnv:e.getServiceEnv??(e=>({})),pushSpawn:e.pushSpawn??(()=>{}),isShutdownRequested:e.isShutdownRequested??(()=>!1),getShkeeperConfig:e.getShkeeperConfig??(()=>({})),getShkeeperBuild:e.getShkeeperBuild??(()=>({}))}}async function $t(e){let t=`elastic`,n=`etherna_${t}-data-volume`;await H(n);let r,i=new Promise(e=>{r=e}),a={...F(t,e.serviceCtx)??{},...e.getServiceEnv(`elastic`)},o=await V({containerName:t,imageName:`elasticsearch:7.17.24`,args:[...Object.entries(a).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--mount`,`type=volume,source=${n},target=/usr/share/elasticsearch/data`,`--network`,`host`,`--memory=512m`],cmd:[],detached:e.detached});if(!o)return L(t,`http`,`9200`),null;e.pushSpawn(o);let s=e=>{let n=String(e);/"message": "started"/gm.test(n)&&(L(t,`http`,`9200`),r?.())};return o.stdout?.on(`data`,s),o.stdout?.on(`error`,e=>{R(t,`FATAL: `+e.message),r?.()}),o.stderr?.on(`data`,s),o.on(`close`,e=>{R(t,`Container closed with code ${e}`),r?.(),o.kill()}),await i,o}async function en(e){let t=`etherna-mongodb`,n=`etherna_${t}-db-volume`,r=`etherna_${t}-configdb-volume`;await Promise.all([H(n),H(r)]);let i,a=new Promise(e=>{i=e}),o={...F(t,e.serviceCtx)??{},...e.getServiceEnv(`mongo`)},s=await V({containerName:t,imageName:`mongo:latest`,args:[...Object.entries(o).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--mount`,`type=volume,source=${n},target=/data/db`,`--mount`,`type=volume,source=${r},target=/data/configdb`,`--network`,`host`],cmd:[],detached:e.detached});if(!s)return L(t,`mongodb`,`27017`),null;e.pushSpawn(s);let c=e=>{let n=String(e);/mongod startup complete/gm.test(n)&&(L(t,`mongodb`,`27017`),i?.())};return s.stdout?.on(`data`,c),s.stdout?.on(`error`,e=>{R(t,`FATAL: `+e.message),i?.()}),s.stderr?.on(`data`,c),s.on(`close`,e=>{R(t,`Container closed with code ${e}`),i?.(),s.kill()}),await a,s}const tn=`vsyshost/shkeeper:2.5.12`,nn=`vsyshost/ethereum-shkeeper:1.2.3`,rn=`etherna`;function $(e){let t=e.lastIndexOf(`:`);return t===-1||e.slice(t+1).includes(`/`)?{repository:e,tag:`latest`}:{repository:e.slice(0,t),tag:e.slice(t+1)}}function an(e){let{tag:t}=$(tn);return e?`${rn}/shkeeper:${t}`:tn}function on(e){let{tag:t}=$(nn);return e?`${rn}/ethereum-shkeeper:${t}`:nn}async function sn(e){let t=r(`docker`,[`image`,`inspect`,e]);return await new Promise(e=>{t.on(`close`,t=>{e(t===0)}),t.on(`error`,()=>{e(!1)})})}async function cn(e,t){let n=r(e,t);await new Promise((r,i)=>{n.on(`close`,n=>{if(n===0){r();return}i(Error(`Command failed: ${e} ${t.join(` `)}`))}),n.on(`error`,i)})}function ln(e,t){return I(e,`${t.replace(/[^a-z0-9._-]+/gi,`-`)}-${Date.now()}`)}async function un(e,t,n){let r=ln(t,n);i.mkdirSync(r,{recursive:!0});let o=a.join(r,`clone`);return await cn(`git`,[`clone`,`--depth`,`1`,`--branch`,n,`https://github.com/${e}.git`,o]),{cleanupPath:r,contextPath:o,dockerfilePath:a.join(o,`Dockerfile`)}}async function dn(e){let{logLabel:t,imageName:n,sourceRepo:a,workspacePrefix:o,gitRef:s}=e;if(await sn(n))return;console.log(` ${E.yellow(`➜`)} ${E.bold(t)}: ${E.yellow(`Building Docker image from GitHub (${a}@${s}) (first run may take a while)…`)}`);let c=await un(a,o,s),l=r(`docker`,[`build`,`-t`,n,`-f`,c.dockerfilePath,c.contextPath]);try{await new Promise((e,t)=>{l.on(`close`,r=>{if(r===0){e();return}t(Error(`Failed to build local Docker image ${n}`))}),l.on(`error`,t)})}catch(e){throw R(t,`Failed to build Docker image (${n}).`),c.cleanupPath?Error(`Failed to build local Docker image ${n}. Inspect cloned source at ${c.contextPath}`,{cause:e}):e}console.log(` ${E.yellow(`➜`)} ${E.bold(t)}: ${E.yellow(`Finished building Docker image.`)}`),c.cleanupPath&&i.rmSync(c.cleanupPath,{force:!0,recursive:!0})}function fn(e){let t=e?.trim();return t&&t.length>0?t:`main`}async function pn(e,t){await dn({logLabel:`shkeeper`,imageName:an(e),sourceRepo:e??`vsys-host/shkeeper.io`,workspacePrefix:`.shkeeper-build`,gitRef:e?fn(t):$(tn).tag})}async function mn(e,t){e&&await dn({logLabel:`ethereum-shkeeper`,imageName:on(e),sourceRepo:e,workspacePrefix:`.ethereum-shkeeper-build`,gitRef:fn(t)})}const hn=`etherna_shkeeper_network`;async function gn({context:e,envs:t,build:n,networkName:r,detached:i=!1}){let a=`shkeeper`,o=`etherna_shkeeper-instance-volume`;await H(o);let s,c,l=new Promise((e,t)=>{s=e,c=t}),u,d=!1,f={...F(`shkeeper-core`,e)??{},...t},p=String(F(`shkeeper`,e)?.port??`32650`),m=r===`host`,h=m?p:`5000`,g=await V({containerName:a,imageName:n.imageName,args:[...Object.entries(f).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--mount`,`type=volume,source=${o},target=/shkeeper.io/instance`,`--network`,r,...m?[]:[`-p`,`${p}:5000`]],...m?{cmd:[`bash`,`-c`,`gunicorn --access-logfile=- --workers=1 --threads=16 --timeout=600 --bind=0.0.0.0:${p} 'shkeeper:create_app()'`]}:{},detached:i});if(!g)return L(a,`http`,p),s?.(),null;let _=e=>{u=void 0;let t=String(e);RegExp(`Listening at: http://.+:${h}`,`gm`).test(t)?(d=!0,L(a,`http`,p),s?.()):u=t};return g.stdout?.on(`data`,_),g.stdout?.on(`error`,e=>{R(a,`FATAL: `+e.message),d||c?.(e)}),g.stderr?.on(`data`,_),g.on(`close`,e=>{R(a,u||`Container closed with code ${e}`),d||c?.(Error(`Container closed with code ${e}`)),g.kill()}),await l,g}async function _n({context:e,envs:t,networkName:n,imageName:r,detached:i=!1}){let a=`ethereum-shkeeper`,o,s,c=new Promise((e,t)=>{o=e,s=t}),l,u=!1,d={...F(`ethereum-shkeeper`,e)??{},...t},f=await V({containerName:a,imageName:r,args:[...Object.entries(d).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--network`,n],cmd:[`bash`,`-c`,`sleep 30 && gunicorn --access-logfile=- --workers=1 --threads=16 --timeout=600 --bind=0.0.0.0:6000 run:server`],detached:i});if(!f)return o?.(),null;let p=e=>{l=void 0;let t=String(e);/Listening at: http:\/\/.+:6000/gm.test(t)?(u=!0,o?.()):l=t};return f.stdout?.on(`data`,p),f.stdout?.on(`error`,e=>{R(a,`FATAL: `+e.message),u||s?.(e)}),f.stderr?.on(`data`,p),f.on(`close`,e=>{R(a,l||`Container closed with code ${e}`),u||s?.(Error(`Container closed with code ${e}`)),f.kill()}),await c,f}async function vn(e=hn,t){let n=`ethereum-shkeeper-mariadb`,r=`etherna_shkeeper-mariadb-volume`;await H(r);let i,a,o=new Promise((e,t)=>{i=e,a=t}),s,c=!1,l=await V({containerName:n,imageName:`mariadb:10.9.3`,args:[`-e`,`MARIADB_ROOT_PASSWORD=shkeeper`,`-e`,`MARIADB_DATABASE=ethereum-shkeeper`,`--mount`,`type=volume,source=${r},target=/var/lib/mysql`,`--network`,e],detached:!!t?.detached});if(!l)return i?.(),null;let u=e=>{s=void 0;let t=String(e);/ready for connections/gim.test(t)?(c=!0,i?.()):s=t};return l.stdout?.on(`data`,u),l.stdout?.on(`error`,e=>{R(n,`FATAL: `+e.message),c||a?.(e)}),l.stderr?.on(`data`,u),l.on(`close`,e=>{R(n,s||`Container closed with code ${e}`),c||a?.(Error(`Container closed with code ${e}`)),l.kill()}),await o,l}async function yn(e=hn,t){let n=`ethereum-shkeeper-redis`,r=`etherna_shkeeper-redis-volume`;await H(r);let i,a,o=new Promise((e,t)=>{i=e,a=t}),s,c=!1,l=await V({containerName:n,imageName:`redis:7`,args:[`--mount`,`type=volume,source=${r},target=/data`,`--network`,e],detached:!!t?.detached});if(!l)return i?.(),null;let u=e=>{s=void 0;let t=String(e);/Ready to accept connections/gm.test(t)?(c=!0,i?.()):s=t};return l.stdout?.on(`data`,u),l.stdout?.on(`error`,e=>{R(n,`FATAL: `+e.message),c||a?.(e)}),l.stderr?.on(`data`,u),l.on(`close`,e=>{R(n,s||`Container closed with code ${e}`),c||a?.(Error(`Container closed with code ${e}`)),l.kill()}),await o,l}async function bn({context:e,envs:t,networkName:n,imageName:r,detached:i=!1}){let a=`ethereum-tasks`,o,s,c=new Promise((e,t)=>{o=e,s=t}),l,u=!1,d={...F(`ethereum-shkeeper`,e)??{},...t,C_FORCE_ROOT:`1`},f=await V({containerName:a,imageName:r,args:[...Object.entries(d).flatMap(([e,t])=>[`-e`,`${e}=${String(t)}`]),`--network`,n],cmd:[`bash`,`-c`,`sleep 30 && celery -A celery_worker.celery worker --loglevel=info -B`],detached:i});if(!f)return o?.(),null;let p=e=>{l=void 0;let t=String(e);/ready\./gim.test(t)?(u=!0,o?.()):l=t};return f.stdout?.on(`data`,p),f.stdout?.on(`error`,e=>{R(a,`FATAL: `+e.message),u||s?.(e)}),f.stderr?.on(`data`,p),f.on(`close`,e=>{R(a,l||`Container closed with code ${e}`),u||s?.(Error(`Container closed with code ${e}`)),f.kill()}),await c,f}async function xn(e){let t=e.serviceCtx,n=e.detached,r=e.getShkeeperConfig(),i=e.getShkeeperBuild(),a={imageName:an(i.githubRepo)},o=r.ethereum?.githubRepo?.trim()||void 0,s=r.ethereum?.githubBranch?.trim()||void 0,c=`host`,l=[];try{await pn(i.githubRepo,i.githubBranch),await mn(o,s);let u=on(o),[d,f]=await Promise.all([vn(c,{detached:n}),yn(c,{detached:n})]);l.push(d,f);let[p,m]=await Promise.all([_n({context:t,envs:r.ethereum?.env,networkName:c,imageName:u,detached:n}),bn({context:t,envs:r.ethereum?.env,networkName:c,imageName:u,detached:n})]);l.push(p,m);let h=await gn({context:t,envs:r.env,build:a,networkName:c,detached:n});return l.push(h),e.pushSpawn(...l),l}catch(e){for(let e of l)e?.kill();throw e}}function Sn(e){let t=e.detached,n=[],r=!1,i=[],a=!1,o=!1,s=e.isBlockchainBootstrapInProgress??(()=>!1),c=e.waitForBlockchainBootstrapToSettle??(()=>Promise.resolve()),l=e.onBlockchainShutdownWait??(()=>{}),u=e.addPortlessAlias??(async()=>{}),d=e.removePortlessAliases??(async()=>{}),f=e.stopPortlessProxy??(async()=>{}),p=e.exitProcess??(e=>process.exit(e)),m=()=>t,h=(...e)=>{n.push(...e)},g=()=>{for(let e of n)e.kill()},_=e=>{r=e},v=async(e,t)=>{await u(e,t),i.push(e)},y=async()=>{t||(i.length>0&&(await d([...i]),i.length=0),r&&await f(),r=!1)},b=async n=>{a=!0;let r=n?.force??!1;o&&!r||(o=!0,!r&&s()&&(l(),await c()),t||await e.stopContainersForEnabled(e.enabledServices),await y(),(n?.killTrackedSpawns??!t)&&g(),n?.exitProcess&&p(0))};return{isShutdownRequested:()=>a,pushSpawn:h,killSpawns:g,getDetached:m,setPortlessProxyStartedByUs:_,recordPortlessAlias:v,cleanupPortless:y,shutdown:b,installSignalHandlers:()=>{process.on(`SIGINT`,()=>{process.stdin.resume(),(async()=>{await b({exitProcess:!0,force:a})})()}),process.on(`SIGTERM`,()=>{(async()=>{await b({force:a})})()})}}}async function Cn(e){let t=Array.isArray(e)?e:[e];for(let e of t)if(!ge.includes(e))throw TypeError(`Unknown Etherna service "${String(e)}". Valid services: ${ge.join(`, `)}.`);await vt(t)}function wn(e){return typeof e==`object`&&e?e.env??{}:{}}function Tn(e){return e===!0?{}:typeof e==`object`&&e?e:{}}async function En(e={}){let t=Je(e);await ut();let n=Qe(`PORTLESS_URL`)?.trim(),r=t.appPort??Be(t.mode).appPort,i={mode:t.mode,portless:t.portless,appPort:r,...t.portless&&n?{portlessAppPublicUrl:k(n)}:{}},a=Sn({detached:t.detached,enabledServices:t.enabled,stopContainersForEnabled:yt,addPortlessAlias:(e,t)=>Ae(e,t),removePortlessAliases:e=>je(e),stopPortlessProxy:Me,isBlockchainBootstrapInProgress:Ut,waitForBlockchainBootstrapToSettle:Wt,onBlockchainShutdownWait:()=>{console.log(E.yellow(` ➜ ${E.bold(`etherna-blockchain`)}: Shutdown requested during blockchain initialization. Waiting for a safe shutdown point. Press Ctrl+C again to force exit.`))}});e.installSignalHandlers!==!1&&a.installSignalHandlers(),t.portless&&await Dn(a,i,n);let o=t.portless?ze(i):void 0,s=t=>wn(e[t]),c=Qt({detached:t.detached,serviceCtx:i,getServiceEnv:s,pushSpawn:(...e)=>{a.pushSpawn(...e.filter(e=>e!=null))},isShutdownRequested:()=>a.isShutdownRequested(),getShkeeperConfig:()=>Tn(e.shkeeper),getShkeeperBuild:()=>{let t=Tn(e.shkeeper).build;return{githubRepo:t?.githubRepo?.trim()||void 0,githubBranch:t?.githubBranch?.trim()||void 0}}}),l=async e=>{try{return await e(),!a.isShutdownRequested()}catch(e){if(a.isShutdownRequested())return!1;throw e}},u=async()=>{let e=s(`credit`);if(t.enabled.shkeeper){let t=await Xe();t&&(e={...e,"Payments:ShKeeper:ApiKey":t})}await U(c,`etherna-credit`,`etherna/etherna-credit:latest`,e)},d={"bee-blockchain":()=>l(()=>Yt(c)),"bee-nodes":()=>l(()=>Xt(c)),shkeeper:()=>l(()=>xn(c)),mongo:()=>l(()=>en(c)),sso:()=>l(()=>U(c,`etherna-sso`,`etherna/etherna-sso:latest`,s(`sso`))),index:()=>l(()=>U(c,`etherna-index`,`etherna/etherna-index:latest`,s(`index`))),beehive:()=>l(()=>U(c,`etherna-beehive`,`etherna/beehive:latest`,s(`beehive`))),gateway:()=>l(()=>U(c,`etherna-gateway`,`etherna/etherna-gateway:latest`,s(`gateway`))),credit:()=>l(u),elastic:()=>l(()=>$t(c))},f=t.portless?{"bee-blockchain":async()=>{let e=F(`etherna-bee`,i)??{};await a.recordPortlessAlias(`bee`,{...e,...s(`bee`)}.BEE_PORT??1633)},shkeeper:async()=>{await a.recordPortlessAlias(`shkeeper`,F(`shkeeper`,i).port)},sso:async()=>{await a.recordPortlessAlias(`sso`,N(String(o?.[`etherna-sso`].ASPNETCORE_URLS)))},index:async()=>{await a.recordPortlessAlias(`index`,N(String(o?.[`etherna-index`].ASPNETCORE_URLS)))},beehive:async()=>{await a.recordPortlessAlias(`beehive`,N(String(o?.[`etherna-beehive`].ASPNETCORE_URLS)))},gateway:async()=>{await a.recordPortlessAlias(`gateway`,N(String(o?.[`etherna-gateway`].ASPNETCORE_URLS)))},credit:async()=>{await a.recordPortlessAlias(`credit`,N(String(o?.[`etherna-credit`].ASPNETCORE_URLS)))}}:{};return(await be(Object.keys(he).map(e=>{let n=he[e],r=f[e];return{code:e,dependencies:n.dependencies,enabled:t.enabled[n.service],onFailure:n.onFailure,startupCallback:d[e],...r?{beforeStartup:r}:{}}}),{logError:R}).start()).shouldStop&&!a.isShutdownRequested()&&(await yt(t.enabled),await a.shutdown({killTrackedSpawns:!0})),{shutdown:e=>a.shutdown(e)}}async function Dn(e,t,n){await De()||(console.error(E.red(` portless: CLI not found. Install globally (recommended): npm install -g portless`)),process.exit(1));try{let{startedByUs:t}=await Oe();e.setPortlessProxyStartedByUs(t)}catch(e){console.error(E.red(` portless: failed to start proxy: ${e instanceof Error?e.message:String(e)}`)),process.exit(1)}if(!n)try{await e.recordPortlessAlias(`app`,t.appPort)}catch(t){console.error(E.red(` portless: failed to register aliases: ${t instanceof Error?t.message:String(t)}`)),await e.cleanupPortless(),process.exit(1)}let r=n!=null&&n!==``?`${k(n)}/`:`${O(`app`)}/`;console.log(E.green(` ➜ ${E.bold(`app (portless)`)}: ${E.cyan(r)}`))}export{Ue as ETHERNA_DETACHED_ENV,We as resolveDetachedMode,En as start,Cn as stop};
|
|
10
|
+
//# sourceMappingURL=index.mjs.map
|