prool 0.0.12 → 0.0.13

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/_lib/utils.d.ts CHANGED
@@ -16,21 +16,17 @@ export declare function extractPath(request: string): ExtractPathReturnType;
16
16
  * @returns The stripped string.
17
17
  */
18
18
  export declare function stripColors(message: string): string;
19
- export type ToArgsParameters = {
20
- [key: string]: Record<string, string> | string | readonly string[] | boolean | number | bigint | undefined;
21
- };
22
19
  /**
23
20
  * Converts an object of options to an array of command line arguments.
24
21
  *
25
22
  * @param options The options object.
26
23
  * @returns The command line arguments.
27
24
  */
28
- export declare function toArgs(parameters: ToArgsParameters): string[];
29
- /**
30
- * Converts a camelCase string to a flag case string.
31
- *
32
- * @param key The camelCase string.
33
- * @returns The flag case string.
34
- */
35
- export declare function toFlagCase(key: string): string;
25
+ export declare function toArgs(obj: {
26
+ [key: string]: Record<string, any> | string | readonly string[] | boolean | number | bigint | undefined;
27
+ }, options?: {
28
+ casing: 'kebab' | 'snake';
29
+ }): any[];
30
+ /** Converts to a --flag-case string. */
31
+ export declare function toFlagCase(str: string, separator?: string): string;
36
32
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAkBlE;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,UAE1C;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,CAAC,GAAG,EAAE,MAAM,GACR,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACtB,MAAM,GACN,SAAS,MAAM,EAAE,GACjB,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,CAAA;CACd,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,UAAU,EAAE,gBAAgB,YAwBlD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,UAErC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG;IAClC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAkBlE;AAMD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,UAE1C;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,GAAG,EAAE;IACH,CAAC,GAAG,EAAE,MAAM,GACR,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACnB,MAAM,GACN,SAAS,MAAM,EAAE,GACjB,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,CAAA;CACd,EACD,OAAO,GAAE;IAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAA;CAAwB,SA6B7D;AAED,wCAAwC;AACxC,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAM,UAatD"}
package/_lib/utils.js CHANGED
@@ -36,21 +36,22 @@ export function stripColors(message) {
36
36
  * @param options The options object.
37
37
  * @returns The command line arguments.
38
38
  */
39
- export function toArgs(parameters) {
40
- return Object.entries(parameters).flatMap(([key, value]) => {
39
+ export function toArgs(obj, options = { casing: 'kebab' }) {
40
+ const { casing } = options;
41
+ return Object.entries(obj).flatMap(([key, value]) => {
41
42
  if (value === undefined)
42
43
  return [];
43
44
  if (Array.isArray(value))
44
45
  return [toFlagCase(key), value.join(',')];
45
- if (typeof value === 'object' && value !== null)
46
+ if (typeof value === 'object' && value !== null) {
46
47
  return Object.entries(value).flatMap(([subKey, subValue]) => {
47
48
  if (subValue === undefined)
48
49
  return [];
49
- const flag = toFlagCase(key);
50
- const value = `${subKey}: ${subValue}`;
51
- return [flag, value];
50
+ const flag = toFlagCase(`${key}.${subKey}`, casing === 'kebab' ? '-' : '_');
51
+ return [flag, subValue];
52
52
  });
53
- const flag = toFlagCase(key);
53
+ }
54
+ const flag = toFlagCase(key, casing === 'kebab' ? '-' : '_');
54
55
  if (value === false)
55
56
  return [flag, 'false'];
56
57
  if (value === true)
@@ -61,13 +62,18 @@ export function toArgs(parameters) {
61
62
  return [flag, stringified];
62
63
  });
63
64
  }
64
- /**
65
- * Converts a camelCase string to a flag case string.
66
- *
67
- * @param key The camelCase string.
68
- * @returns The flag case string.
69
- */
70
- export function toFlagCase(key) {
71
- return `--${key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`)}`;
65
+ /** Converts to a --flag-case string. */
66
+ export function toFlagCase(str, separator = '-') {
67
+ const keys = [];
68
+ for (let i = 0; i < str.split('.').length; i++) {
69
+ const key = str.split('.')[i];
70
+ if (!key)
71
+ continue;
72
+ keys.push(key
73
+ .replace(/\s+/g, separator)
74
+ .replace(/([a-z])([A-Z])/g, `$1${separator}$2`)
75
+ .toLowerCase());
76
+ }
77
+ return `--${keys.join('.')}`;
72
78
  }
73
79
  //# sourceMappingURL=utils.js.map
package/_lib/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../utils.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ test('exports', () => {
6
6
  [
7
7
  "alto",
8
8
  "anvil",
9
+ "rundler",
9
10
  "stackup",
10
11
  ]
11
12
  `)
@@ -1,3 +1,4 @@
1
- export { type AltoParameters, alto } from '../instances/alto.js'
2
- export { type AnvilParameters, anvil } from '../instances/anvil.js'
3
- export { type StackupParameters, stackup } from '../instances/stackup.js'
1
+ export { alto, type AltoParameters } from '../instances/alto.js'
2
+ export { anvil, type AnvilParameters } from '../instances/anvil.js'
3
+ export { rundler, type RundlerParameters } from '../instances/rundler.js'
4
+ export { stackup, type StackupParameters } from '../instances/stackup.js'
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "module",
3
+ "types": "../_lib/exports/instances/index.d.ts",
4
+ "module": "../_lib/exports/instances/index.js"
5
+ }
@@ -0,0 +1,115 @@
1
+ import { afterEach, expect, test } from 'vitest'
2
+ import type { Instance } from '../instance.js'
3
+ import { type RundlerParameters, rundler } from './rundler.js'
4
+
5
+ const instances: Instance[] = []
6
+
7
+ const defineInstance = (parameters: RundlerParameters = {}) => {
8
+ const instance = rundler(parameters)
9
+ instances.push(instance)
10
+ return instance
11
+ }
12
+
13
+ afterEach(async () => {
14
+ for (const instance of instances) await instance.stop()
15
+ })
16
+
17
+ test('default', async () => {
18
+ const messages: string[] = []
19
+ const stdouts: string[] = []
20
+
21
+ const instance = defineInstance()
22
+
23
+ instance.on('message', (m) => messages.push(m))
24
+ instance.on('stdout', (m) => stdouts.push(m))
25
+
26
+ expect(instance.messages.get()).toMatchInlineSnapshot('[]')
27
+
28
+ await instance.start()
29
+ expect(instance.status).toEqual('started')
30
+
31
+ expect(messages.join('')).toBeDefined()
32
+ expect(stdouts.join('')).toBeDefined()
33
+ expect(instance.messages.get().join('')).toBeDefined()
34
+
35
+ await instance.stop()
36
+ expect(instance.status).toEqual('stopped')
37
+
38
+ expect(messages.join('')).toBeDefined()
39
+ expect(stdouts.join('')).toBeDefined()
40
+ expect(instance.messages.get()).toMatchInlineSnapshot('[]')
41
+ })
42
+
43
+ test('behavior: instance errored (duplicate ports)', async () => {
44
+ const instance_1 = defineInstance({
45
+ rpc: {
46
+ port: 1337,
47
+ },
48
+ })
49
+ const instance_2 = defineInstance({
50
+ rpc: {
51
+ port: 1337,
52
+ },
53
+ })
54
+
55
+ await instance_1.start()
56
+ await expect(() =>
57
+ instance_2.start(),
58
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
59
+ `[Error: Failed to start process "rundler": exited]`,
60
+ )
61
+ })
62
+
63
+ test('behavior: start and stop multiple times', async () => {
64
+ const instance = defineInstance()
65
+
66
+ await instance.start()
67
+ await instance.stop()
68
+ await instance.start()
69
+ await instance.stop()
70
+ await instance.start()
71
+ await instance.stop()
72
+ await instance.start()
73
+ await instance.stop()
74
+ })
75
+
76
+ test('behavior: can subscribe to stderr', async () => {
77
+ const messages: string[] = []
78
+
79
+ const instance_1 = defineInstance({
80
+ rpc: {
81
+ port: 1338,
82
+ },
83
+ })
84
+ const instance_2 = defineInstance({
85
+ rpc: {
86
+ port: 1338,
87
+ },
88
+ })
89
+
90
+ await instance_1.start()
91
+ instance_2.on('stderr', (message) => messages.push(message))
92
+ await expect(() =>
93
+ instance_2.start(),
94
+ ).rejects.toThrowErrorMatchingInlineSnapshot(
95
+ `[Error: Failed to start process "rundler": exited]`,
96
+ )
97
+ })
98
+
99
+ test('behavior: exit', async () => {
100
+ const instance = defineInstance()
101
+
102
+ let exitCode: number | null | undefined = undefined
103
+ instance.on('exit', (code) => {
104
+ exitCode = code
105
+ })
106
+
107
+ await instance.start()
108
+ expect(instance.status).toEqual('started')
109
+
110
+ instance._internal.process.kill()
111
+
112
+ await new Promise<void>((res) => setTimeout(res, 100))
113
+ expect(instance.status).toEqual('stopped')
114
+ expect(typeof exitCode !== 'undefined').toBeTruthy()
115
+ })
@@ -0,0 +1,451 @@
1
+ import getPort from 'get-port'
2
+
3
+ import { defineInstance } from '../instance.js'
4
+ import { execa } from '../processes/execa.js'
5
+ import { toArgs } from '../utils.js'
6
+
7
+ export type RundlerParameters = {
8
+ /**
9
+ * The path to the rundler binary
10
+ *
11
+ * @default rundler
12
+ */
13
+ binary?: string
14
+
15
+ /**
16
+ * The version of the entrypoint to use
17
+ *
18
+ * @default 0.6.0
19
+ */
20
+ entryPointVersion?: '0.6.0' | '0.7.0'
21
+
22
+ /**
23
+ * Network to look up a hardcoded chain spec.
24
+ * @default dev
25
+ */
26
+ network?: string
27
+
28
+ /**
29
+ * Path to a chain spec TOML file.
30
+ */
31
+ chainSpec?: string
32
+
33
+ /**
34
+ * EVM Node HTTP URL to use.
35
+ *
36
+ * @default http://localhost:8545
37
+ */
38
+ nodeHttp?: string
39
+
40
+ /**
41
+ * Maximum verification gas.
42
+ * @default 5000000
43
+ */
44
+ maxVerificationGas?: number
45
+
46
+ /**
47
+ * Maximum bundle gas.
48
+ * @default 25000000
49
+ */
50
+ maxBundleGas?: number
51
+
52
+ /**
53
+ * Minimum stake value.
54
+ * @default 1000000000000000000
55
+ */
56
+ minStakeValue?: number
57
+
58
+ /**
59
+ * Minimum unstake delay.
60
+ * @default 84600
61
+ */
62
+ minUnstakeDelay?: number
63
+
64
+ /**
65
+ * Number of blocks to search when calling eth_getUserOperationByHash.
66
+ * @default 100
67
+ */
68
+ userOperationEventBlockDistance?: number
69
+
70
+ /**
71
+ * Maximum gas for simulating handle operations.
72
+ * @default 20000000
73
+ */
74
+ maxSimulateHandleOpsGas?: number
75
+
76
+ /**
77
+ * The gas fee to use during verification estimation.
78
+ * @default 1000000000000 10K gwei
79
+ */
80
+ verificationEstimationGasFee?: number
81
+
82
+ /**
83
+ * Bundle transaction priority fee overhead over network value.
84
+ * @default 0
85
+ */
86
+ bundlePriorityFeeOverheadPercent?: number
87
+
88
+ /**
89
+ * Priority fee mode kind.
90
+ * Possible values are base_fee_percent and priority_fee_increase_percent.
91
+ * @default priority_fee_increase_percent
92
+ */
93
+ priorityFeeModeKind?: 'base_fee_percent' | 'priority_fee_increase_percent'
94
+
95
+ /**
96
+ * Priority fee mode value.
97
+ * @default 0
98
+ */
99
+ priorityFeeModeValue?: number
100
+
101
+ /**
102
+ * Percentage of the current network fees a user operation must have in order to be accepted into the mempool.
103
+ * @default 100
104
+ */
105
+ baseFeeAcceptPercent?: number
106
+
107
+ /**
108
+ * AWS region.
109
+ * @default us-east-1
110
+ */
111
+ awsRegion?: string
112
+
113
+ /**
114
+ * Interval at which the builder polls an RPC node for new blocks and mined transactions.
115
+ * @default 100
116
+ */
117
+ ethPollIntervalMillis?: number
118
+
119
+ /**
120
+ * Flag for unsafe bundling mode. When set Rundler will skip checking simulation rules (and any debug_traceCall).
121
+ *
122
+ * @default true
123
+ */
124
+ unsafe?: boolean
125
+
126
+ /**
127
+ * Path to the mempool configuration file.
128
+ * This path can either be a local file path or an S3 url.
129
+ */
130
+ mempoolConfigPath?: string
131
+
132
+ metrics?: {
133
+ /**
134
+ * Port to listen on for metrics requests.
135
+ * @default 8080
136
+ */
137
+ port?: number
138
+
139
+ /**
140
+ * Host to listen on for metrics requests.
141
+ * @default 0.0.0.0
142
+ */
143
+ host?: string
144
+
145
+ /**
146
+ * Tags for metrics in the format key1=value1,key2=value2,...
147
+ */
148
+ tags?: string
149
+
150
+ /**
151
+ * Sample interval to use for sampling metrics.
152
+ * @default 1000
153
+ */
154
+ sampleIntervalMillis?: number
155
+ }
156
+
157
+ logging?: {
158
+ /**
159
+ * Log file. If not provided, logs will be written to stdout.
160
+ */
161
+ file?: string
162
+
163
+ /**
164
+ * If set, logs will be written in JSON format.
165
+ */
166
+ json?: boolean
167
+ }
168
+
169
+ rpc?: {
170
+ /**
171
+ * Port to listen on for JSON-RPC requests.
172
+ * @default 3000
173
+ */
174
+ port?: number
175
+
176
+ /**
177
+ * Host to listen on for JSON-RPC requests.
178
+ * @default 127.0.0.1
179
+ */
180
+ host?: string
181
+
182
+ /**
183
+ * Which APIs to expose over the RPC interface.
184
+ * @default eth,rundler
185
+ */
186
+ api?: string
187
+
188
+ /**
189
+ * Timeout for RPC requests.
190
+ * @default 20
191
+ */
192
+ timeoutSeconds?: number
193
+
194
+ /**
195
+ * Maximum number of concurrent connections.
196
+ * @default 100
197
+ */
198
+ maxConnections?: number
199
+ }
200
+
201
+ pool?: {
202
+ /**
203
+ * Maximum size in bytes for the pool.
204
+ * @default 500000000, 0.5 GB
205
+ */
206
+ maxSizeInBytes?: number
207
+
208
+ /**
209
+ * Maximum number of user operations for an unstaked sender.
210
+ * @default 4
211
+ */
212
+ sameSenderMempoolCount?: number
213
+
214
+ /**
215
+ * Minimum replacement fee increase percentage.
216
+ * @default 10
217
+ */
218
+ minReplacementFeeIncreasePercentage?: number
219
+
220
+ /**
221
+ * Path to a blocklist file.
222
+ * This path can either be a local file path or an S3 url.
223
+ */
224
+ blocklistPath?: string
225
+
226
+ /**
227
+ * Path to an allowlist file.
228
+ * This path can either be a local file path or an S3 url.
229
+ */
230
+ allowlistPath?: string
231
+
232
+ /**
233
+ * Size of the chain history.
234
+ */
235
+ chainHistorySize?: number
236
+
237
+ /**
238
+ * Boolean field that sets whether the pool server starts with paymaster tracking enabled.
239
+ * @default true
240
+ */
241
+ paymasterTrackingEnabled?: boolean
242
+
243
+ /**
244
+ * Length of the paymaster cache.
245
+ * @default 10_000
246
+ */
247
+ paymasterCacheLength?: number
248
+
249
+ /**
250
+ * Boolean field that sets whether the pool server starts with reputation tracking enabled.
251
+ * @default true
252
+ */
253
+ reputationTrackingEnabled?: boolean
254
+
255
+ /**
256
+ * The minimum number of blocks that a UO must stay in the mempool before it can be requested to be dropped by the user.
257
+ * @default 10
258
+ */
259
+ dropMinNumBlocks?: number
260
+ }
261
+
262
+ builder?: {
263
+ /**
264
+ * Private key to use for signing transactions.
265
+ * If used with awsKmsKeyIds, then explicitly pass in `null` here.
266
+ *
267
+ * @default 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
268
+ */
269
+ privateKey?: string
270
+
271
+ /**
272
+ * AWS KMS key IDs to use for signing transactions (comma-separated).
273
+ * Only required if privateKey is not provided.
274
+ */
275
+ awsKmsKeyIds?: string
276
+
277
+ /**
278
+ * Redis URI to use for KMS leasing.
279
+ * Only required when awsKmsKeyIds are provided.
280
+ *
281
+ * @default ""
282
+ */
283
+ redisUri?: string
284
+
285
+ /**
286
+ * Redis lock TTL in milliseconds.
287
+ * Only required when awsKmsKeyIds are provided.
288
+ * @default 60000
289
+ */
290
+ redisLockTtlMillis?: number
291
+
292
+ /**
293
+ * Maximum number of ops to include in one bundle.
294
+ * @default 128
295
+ */
296
+ maxBundleSize?: number
297
+
298
+ /**
299
+ * If present, the URL of the ETH provider that will be used to send transactions.
300
+ * Defaults to the value of nodeHttp.
301
+ */
302
+ submitUrl?: string
303
+
304
+ /**
305
+ * Choice of what sender type to use for transaction submission.
306
+ * @default raw
307
+ * options: raw, conditional, flashbots, polygon_bloxroute
308
+ */
309
+ sender?: 'raw' | 'conditional' | 'flashbots' | 'polygonBloxroute'
310
+
311
+ /**
312
+ * After submitting a bundle transaction, the maximum number of blocks to wait for that transaction to mine before trying to resend with higher gas fees.
313
+ * @default 2
314
+ */
315
+ maxBlocksToWaitForMine?: number
316
+
317
+ /**
318
+ * Percentage amount to increase gas fees when retrying a transaction after it failed to mine.
319
+ * @default 10
320
+ */
321
+ replacementFeePercentIncrease?: number
322
+
323
+ /**
324
+ * Maximum number of fee increases to attempt.
325
+ * Seven increases of 10% is roughly 2x the initial fees.
326
+ * @default 7
327
+ */
328
+ maxFeeIncreases?: number
329
+
330
+ /**
331
+ * Additional builders to send bundles to through the Flashbots relay RPC (comma-separated).
332
+ * List of builders that the Flashbots RPC supports can be found here.
333
+ * @default flashbots
334
+ */
335
+ flashbotsRelayBuilders?: string
336
+
337
+ /**
338
+ * Authorization key to use with the Flashbots relay.
339
+ * See here for more info.
340
+ * @default None
341
+ */
342
+ flashbotsRelayAuthKey?: string
343
+
344
+ /**
345
+ * If using the bloxroute transaction sender on Polygon, this is the auth header to supply with the requests.
346
+ * @default None
347
+ */
348
+ bloxrouteAuthHeader?: string
349
+
350
+ /**
351
+ * If running multiple builder processes, this is the index offset to assign unique indexes to each bundle sender.
352
+ * @default 0
353
+ */
354
+ indexOffset?: number
355
+ }
356
+ }
357
+
358
+ /**
359
+ * Defines a Rundler instance.
360
+ *
361
+ * @example
362
+ * ```ts
363
+ * const instance = rundler({
364
+ * nodeHttp: 'http://localhost:8545',
365
+ * });
366
+ *
367
+ * await instance.start()
368
+ * // ...
369
+ * await instance.stop()
370
+ * ```
371
+ */
372
+ export const rundler = defineInstance((parameters?: RundlerParameters) => {
373
+ const { binary = 'rundler', ...args } = (parameters ??
374
+ {}) as RundlerParameters
375
+
376
+ const host = '127.0.0.1'
377
+ const name = 'rundler'
378
+ const process = execa({ name })
379
+
380
+ return {
381
+ _internal: {
382
+ args,
383
+ get process() {
384
+ return process._internal.process
385
+ },
386
+ },
387
+ host,
388
+ port: args.rpc?.port ?? 3000,
389
+ name,
390
+ async start({ port = args.rpc?.port ?? 3000 }, options) {
391
+ const args_ = {
392
+ ...args,
393
+ builder: {
394
+ ...args.builder,
395
+ privateKey:
396
+ args.builder?.privateKey ??
397
+ '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
398
+ },
399
+ entryPointVersion: undefined,
400
+ maxVerificationGas: args.maxVerificationGas ?? 10000000,
401
+ network: args.network ?? 'dev',
402
+ nodeHttp: args.nodeHttp ?? 'http://localhost:8545',
403
+ metrics: {
404
+ ...args.metrics,
405
+ port: await getPort(),
406
+ },
407
+ rpc: {
408
+ ...args.rpc,
409
+ port,
410
+ },
411
+ unsafe: args.unsafe ?? true,
412
+ userOperationEventBlockDistance:
413
+ args.userOperationEventBlockDistance ?? 100,
414
+ } satisfies RundlerParameters
415
+
416
+ const entrypointArgs = (() => {
417
+ if (args.entryPointVersion === '0.6.0')
418
+ return ['--disable_entry_point_v0_7']
419
+ return ['--disable_entry_point_v0_6']
420
+ })()
421
+
422
+ return await process.start(
423
+ ($) =>
424
+ $(
425
+ binary,
426
+ ['node', ...toArgs(args_, { casing: 'snake' }), ...entrypointArgs],
427
+ {
428
+ env: {
429
+ RUST_LOG: 'debug',
430
+ },
431
+ },
432
+ ),
433
+ {
434
+ ...options,
435
+ resolver({ process, reject, resolve }) {
436
+ process.stdout.on('data', (data) => {
437
+ const message = data.toString()
438
+ if (message.includes('Started RPC server')) resolve()
439
+ })
440
+ process.stderr.on('data', (data) => {
441
+ reject(data.toString())
442
+ })
443
+ },
444
+ },
445
+ )
446
+ },
447
+ async stop() {
448
+ await process.stop()
449
+ },
450
+ }
451
+ })