@effectstream/orchestrator 0.100.9

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/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@effectstream/orchestrator",
3
+ "version": "0.100.9",
4
+ "license": "MIT",
5
+ "homepage": "https://effectstream.github.io/docs/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/PaimaStudios/paima-engine",
9
+ "directory": "packages/build-tools/orchestrator"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/PaimaStudios/paima-engine/issues"
13
+ },
14
+ "exports": {
15
+ "./config": "./src/config.ts",
16
+ "./resolve-package": "./scripts/resolve-package.ts",
17
+ "./launch-pglite": "./scripts/launch-pglite.ts",
18
+ "./launch-evm": "./scripts/launch-evm.ts",
19
+ "./launch-bitcoin": "./scripts/launch-bitcoin.ts",
20
+ "./launch-cardano": "./scripts/launch-cardano.ts",
21
+ "./launch-midnight": "./scripts/launch-midnight.ts",
22
+ "./launch-avail": "./scripts/launch-avail.ts",
23
+ "./launch-near": "./scripts/launch-near.ts",
24
+ "./wait-tcp": "./scripts/wait-tcp.ts",
25
+ "./wait-http": "./scripts/wait-http.ts"
26
+ },
27
+ "bin": {
28
+ "orchestrator": "src/cli.ts"
29
+ },
30
+ "scripts": {
31
+ "start": "bun src/cli.ts start"
32
+ },
33
+ "dependencies": {
34
+ "@effectstream/db": "0.100.9"
35
+ },
36
+ "description": "Multi-chain local development environment for EffectStream"
37
+ }
@@ -0,0 +1,64 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+ import { resolvePackageDir } from "./resolve-package.ts";
3
+
4
+ export const AvailNames = {
5
+ NODE: "avail-node",
6
+ NODE_WAIT: "avail-node-wait",
7
+ LIGHT_CLIENT_DEPLOY: "avail-light-client-deploy",
8
+ LIGHT_CLIENT_WAIT: "avail-light-client-wait",
9
+ } as const;
10
+
11
+ const REQUIRED_SCRIPTS = {
12
+ "avail-node:start": "Start the Avail dev node",
13
+ "avail-node:wait": "Wait for the Avail node RPC to be ready",
14
+ "avail-light-client:deploy": "Create app key and start the Avail light client",
15
+ "avail-light-client:wait": "Wait for the Avail light client to be ready",
16
+ } as const;
17
+
18
+ export function launchAvail(
19
+ packageName: string,
20
+ resolveFrom: string,
21
+ opts?: { nodePorts?: number[]; clientPorts?: number[] },
22
+ ): ProcessConfig[] {
23
+ const cwd = resolvePackageDir("launchAvail", packageName, resolveFrom, REQUIRED_SCRIPTS);
24
+ const nodePorts = opts?.nodePorts ?? [9955, 30334];
25
+ const clientPorts = opts?.clientPorts ?? [7007];
26
+
27
+ return [
28
+ {
29
+ name: AvailNames.NODE,
30
+ description: `Start Avail dev node (${packageName} avail-node:start)`,
31
+ cwd,
32
+ stopProcessAtPort: nodePorts,
33
+ args: ["run", "avail-node:start"],
34
+ waitToExit: false,
35
+ critical: true,
36
+ },
37
+ {
38
+ name: AvailNames.NODE_WAIT,
39
+ description: `Wait for Avail node (${packageName} avail-node:wait)`,
40
+ cwd,
41
+ args: ["run", "avail-node:wait"],
42
+ waitToExit: true,
43
+ dependsOn: [AvailNames.NODE],
44
+ },
45
+ {
46
+ name: AvailNames.LIGHT_CLIENT_DEPLOY,
47
+ description: `Deploy Avail light client (${packageName} avail-light-client:deploy)`,
48
+ cwd,
49
+ stopProcessAtPort: clientPorts,
50
+ args: ["run", "avail-light-client:deploy"],
51
+ waitToExit: false,
52
+ critical: true,
53
+ dependsOn: [AvailNames.NODE_WAIT],
54
+ },
55
+ {
56
+ name: AvailNames.LIGHT_CLIENT_WAIT,
57
+ description: `Wait for Avail light client (${packageName} avail-light-client:wait)`,
58
+ cwd,
59
+ args: ["run", "avail-light-client:wait"],
60
+ waitToExit: true,
61
+ dependsOn: [AvailNames.LIGHT_CLIENT_DEPLOY],
62
+ },
63
+ ];
64
+ }
@@ -0,0 +1,62 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+ import { resolvePackageDir } from "./resolve-package.ts";
3
+
4
+ export const BitcoinNames = {
5
+ BITCOIN_CORE: "bitcoin-core",
6
+ BITCOIN_CORE_WAIT: "bitcoin-core-wait",
7
+ BITCOIN_MINE_BLOCKS: "bitcoin-mine-blocks",
8
+ BITCOIN_WAIT_FOR_BLOCK: "bitcoin-wait-for-block",
9
+ } as const;
10
+
11
+ const REQUIRED_SCRIPTS = {
12
+ "chain:start": "Start Bitcoin Core in regtest mode",
13
+ "chain:wait": "Wait for Bitcoin Core RPC to be ready",
14
+ "generate:blocks": "Continuously generate regtest blocks",
15
+ "wait-for-block": "Wait until block height exceeds a threshold (e.g. > 100)",
16
+ } as const;
17
+
18
+ export function launchBitcoin(
19
+ packageName: string,
20
+ resolveFrom: string,
21
+ opts?: { ports?: number[] },
22
+ ): ProcessConfig[] {
23
+ const cwd = resolvePackageDir("launchBitcoin", packageName, resolveFrom, REQUIRED_SCRIPTS);
24
+ const ports = opts?.ports ?? [18334, 18443];
25
+
26
+ return [
27
+ {
28
+ stopProcessAtPort: ports,
29
+ name: BitcoinNames.BITCOIN_CORE,
30
+ description: `Start Bitcoin Core regtest node (${packageName} chain:start)`,
31
+ cwd,
32
+ args: ["run", "chain:start"],
33
+ waitToExit: false,
34
+ critical: true,
35
+ },
36
+ {
37
+ name: BitcoinNames.BITCOIN_CORE_WAIT,
38
+ description: `Wait for Bitcoin Core RPC (${packageName} chain:wait)`,
39
+ cwd,
40
+ args: ["run", "chain:wait"],
41
+ waitToExit: true,
42
+ dependsOn: [BitcoinNames.BITCOIN_CORE],
43
+ },
44
+ {
45
+ name: BitcoinNames.BITCOIN_MINE_BLOCKS,
46
+ description: `Generate blocks continuously (${packageName} generate:blocks)`,
47
+ cwd,
48
+ args: ["run", "generate:blocks"],
49
+ waitToExit: false,
50
+ type: "system-dependency",
51
+ dependsOn: [BitcoinNames.BITCOIN_CORE_WAIT],
52
+ },
53
+ {
54
+ name: BitcoinNames.BITCOIN_WAIT_FOR_BLOCK,
55
+ description: `Wait for block height > 100 (${packageName} wait-for-block)`,
56
+ cwd,
57
+ args: ["run", "wait-for-block"],
58
+ waitToExit: true,
59
+ dependsOn: [BitcoinNames.BITCOIN_MINE_BLOCKS],
60
+ },
61
+ ];
62
+ }
@@ -0,0 +1,99 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+ import { resolvePackageDir } from "./resolve-package.ts";
3
+
4
+ const waitHttpScript = new URL("./wait-http.ts", import.meta.url).pathname;
5
+
6
+ export const CardanoNames = {
7
+ YACI_DEVKIT: "yaci-devkit",
8
+ YACI_DEVKIT_WAIT: "yaci-devkit-wait",
9
+ DOLOS_FILL_TEMPLATE: "dolos-fill-template",
10
+ DOLOS: "dolos",
11
+ DOLOS_WAIT: "dolos-wait",
12
+ DOLOS_MINIBF_WAIT: "dolos-minibf-wait",
13
+ CARDANO_SUBMIT_TX: "cardano-submit-tx",
14
+ } as const;
15
+
16
+ const REQUIRED_SCRIPTS = {
17
+ "devkit:start": "Start YACI DevKit (Cardano local devnet)",
18
+ "devkit:wait": "Wait for YACI DevKit to be ready",
19
+ "dolos:fill-template": "Generate Dolos config from YACI DevKit state",
20
+ "dolos:start": "Start Dolos relay node",
21
+ "dolos:wait": "Wait for Dolos gRPC to be ready",
22
+ "cardano-submit-tx": "Submit test transactions to the devnet",
23
+ } as const;
24
+
25
+ export function launchCardano(
26
+ packageName: string,
27
+ resolveFrom: string,
28
+ opts?: { ports?: number[] },
29
+ ): ProcessConfig[] {
30
+ const cwd = resolvePackageDir("launchCardano", packageName, resolveFrom, REQUIRED_SCRIPTS);
31
+ const ports = opts?.ports ?? [
32
+ 8090, // CARDANO_SUBMIT_TX: cardano-submit-api
33
+ 10000, // YACI_DEVKIT: admin port
34
+ 3001, // YACI_DEVKIT: cardano-node
35
+ 3000, // DOLOS: minibf (blockfrost API)
36
+ 50051, // DOLOS: gRPC
37
+ ];
38
+
39
+ return [
40
+ {
41
+ stopProcessAtPort: ports,
42
+ name: CardanoNames.YACI_DEVKIT,
43
+ description: `Start YACI DevKit (${packageName} devkit:start)`,
44
+ cwd,
45
+ args: ["run", "devkit:start"],
46
+ waitToExit: false,
47
+ type: "system-dependency",
48
+ },
49
+ {
50
+ name: CardanoNames.YACI_DEVKIT_WAIT,
51
+ description: `Wait for YACI DevKit (${packageName} devkit:wait)`,
52
+ cwd,
53
+ args: ["run", "devkit:wait"],
54
+ waitToExit: true,
55
+ dependsOn: [CardanoNames.YACI_DEVKIT],
56
+ },
57
+ {
58
+ name: CardanoNames.DOLOS_FILL_TEMPLATE,
59
+ description: `Generate Dolos config (${packageName} dolos:fill-template)`,
60
+ cwd,
61
+ args: ["run", "dolos:fill-template"],
62
+ waitToExit: true,
63
+ dependsOn: [CardanoNames.YACI_DEVKIT_WAIT],
64
+ },
65
+ {
66
+ name: CardanoNames.DOLOS,
67
+ description: `Start Dolos relay node (${packageName} dolos:start)`,
68
+ cwd,
69
+ args: ["run", "dolos:start"],
70
+ waitToExit: false,
71
+ type: "system-dependency",
72
+ dependsOn: [CardanoNames.DOLOS_FILL_TEMPLATE],
73
+ },
74
+ {
75
+ name: CardanoNames.DOLOS_WAIT,
76
+ description: `Wait for Dolos gRPC (${packageName} dolos:wait)`,
77
+ cwd,
78
+ args: ["run", "dolos:wait"],
79
+ waitToExit: true,
80
+ dependsOn: [CardanoNames.DOLOS],
81
+ },
82
+ {
83
+ name: CardanoNames.DOLOS_MINIBF_WAIT,
84
+ description: "Wait for Dolos blockfrost API on port 3000",
85
+ args: [waitHttpScript, "--timeout", "60000", "http://localhost:3000/blocks/latest"],
86
+ waitToExit: true,
87
+ dependsOn: [CardanoNames.DOLOS_WAIT],
88
+ },
89
+ {
90
+ name: CardanoNames.CARDANO_SUBMIT_TX,
91
+ description: `Submit test transactions (${packageName} cardano-submit-tx)`,
92
+ cwd,
93
+ args: ["run", "cardano-submit-tx"],
94
+ waitToExit: true,
95
+ critical: true,
96
+ dependsOn: [CardanoNames.YACI_DEVKIT_WAIT],
97
+ },
98
+ ];
99
+ }
@@ -0,0 +1,72 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+ import { resolvePackageDir } from "./resolve-package.ts";
3
+
4
+ export const EvmNames = {
5
+ HARDHAT: "hardhat",
6
+ HARDHAT_WAIT: "hardhat-wait",
7
+ COMPILE: "compile-evm-contracts",
8
+ DEPLOY: "deploy-evm-contracts",
9
+ GENERATE_MOD: "generate-evm-mod",
10
+ } as const;
11
+
12
+ const REQUIRED_SCRIPTS = {
13
+ "chain:start": "Start the Hardhat node (e.g. `bun ./node_modules/.bin/hardhat node`)",
14
+ "chain:wait": "Wait for the Hardhat node to be ready (e.g. `bun ./node_modules/.bin/hardhat node wait`)",
15
+ "build:hardhat": "Compile Solidity contracts with Hardhat (e.g. `hardhat compile`)",
16
+ "deploy": "Deploy compiled contracts to the running chain (e.g. via Hardhat Ignition)",
17
+ } as const;
18
+
19
+ export function launchEvm(
20
+ packageName: string,
21
+ resolveFrom: string,
22
+ opts?: { ports?: number[] },
23
+ ): ProcessConfig[] {
24
+ const cwd = resolvePackageDir("launchEvm", packageName, resolveFrom, REQUIRED_SCRIPTS);
25
+ const ports = opts?.ports ?? [8545, 8546];
26
+
27
+ return [
28
+ {
29
+ stopProcessAtPort: ports,
30
+ name: EvmNames.HARDHAT,
31
+ description: `Start the Hardhat node (${packageName} chain:start)`,
32
+ cwd,
33
+ args: ["run", "chain:start"],
34
+ waitToExit: false,
35
+ critical: true,
36
+ },
37
+ {
38
+ name: EvmNames.HARDHAT_WAIT,
39
+ description: `Wait for the Hardhat node to be ready (${packageName} chain:wait)`,
40
+ cwd,
41
+ args: ["run", "chain:wait"],
42
+ waitToExit: true,
43
+ dependsOn: [EvmNames.HARDHAT],
44
+ },
45
+ {
46
+ name: EvmNames.COMPILE,
47
+ description: `Compile Solidity contracts (${packageName} build:hardhat)`,
48
+ cwd,
49
+ args: ["run", "build:hardhat"],
50
+ waitToExit: true,
51
+ critical: true,
52
+ },
53
+ {
54
+ name: EvmNames.DEPLOY,
55
+ description: `Deploy contracts to the running chain (${packageName} deploy)`,
56
+ cwd,
57
+ args: ["run", "deploy"],
58
+ waitToExit: true,
59
+ critical: true,
60
+ dependsOn: [EvmNames.HARDHAT_WAIT, EvmNames.COMPILE],
61
+ },
62
+ {
63
+ name: EvmNames.GENERATE_MOD,
64
+ description: `Generate TypeScript bindings from deployed contracts (${packageName})`,
65
+ cwd,
66
+ args: ["-e", "const fs=await import('node:fs');await fs.promises.mkdir('./build',{recursive:true});await fs.promises.writeFile('./build/mod.ts','export {};\\n');await import('@effectstream/evm-hardhat/builder')"],
67
+ waitToExit: true,
68
+ critical: true,
69
+ dependsOn: [EvmNames.DEPLOY],
70
+ },
71
+ ];
72
+ }
@@ -0,0 +1,108 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+ import { resolvePackageDir } from "./resolve-package.ts";
3
+
4
+ export const MidnightNames = {
5
+ NODE: "midnight-node",
6
+ NODE_WAIT: "midnight-node-wait",
7
+ INDEXER: "midnight-indexer",
8
+ INDEXER_WAIT: "midnight-indexer-wait",
9
+ PROOF_SERVER: "midnight-proof-server",
10
+ PROOF_SERVER_WAIT: "midnight-proof-server-wait",
11
+ CONTRACT_DEPLOY: "midnight-contract",
12
+ } as const;
13
+
14
+ const REQUIRED_SCRIPTS = {
15
+ "midnight-node:start": "Start the Midnight substrate node",
16
+ "midnight-node:wait": "Wait for the Midnight node RPC (e.g. tcp:9944)",
17
+ "midnight-indexer:start": "Start the Midnight indexer",
18
+ "midnight-indexer:wait": "Wait for the Midnight indexer (e.g. tcp:8088)",
19
+ "midnight-proof-server:start": "Start the Midnight proof server",
20
+ "midnight-proof-server:wait": "Wait for the Midnight proof server (e.g. tcp:6300)",
21
+ "midnight-contract:deploy": "Deploy Midnight contracts (Compact-compiled)",
22
+ } as const;
23
+
24
+ export function launchMidnight(
25
+ packageName: string,
26
+ resolveFrom: string,
27
+ opts?: {
28
+ env?: { MIDNIGHT_STORAGE_PASSWORD?: string };
29
+ dependsOn?: string[];
30
+ },
31
+ ): ProcessConfig[] {
32
+ const cwd = resolvePackageDir("launchMidnight", packageName, resolveFrom, REQUIRED_SCRIPTS);
33
+ const deployEnv: Record<string, string> = {};
34
+ if (opts?.env?.MIDNIGHT_STORAGE_PASSWORD) {
35
+ deployEnv.MIDNIGHT_STORAGE_PASSWORD = opts.env.MIDNIGHT_STORAGE_PASSWORD;
36
+ }
37
+ const extraDeps = opts?.dependsOn ?? [];
38
+
39
+ return [
40
+ {
41
+ name: MidnightNames.NODE,
42
+ description: `Start Midnight node (${packageName} midnight-node:start)`,
43
+ cwd,
44
+ stopProcessAtPort: [9944, 30333],
45
+ args: ["run", "midnight-node:start"],
46
+ waitToExit: false,
47
+ critical: true,
48
+ },
49
+ {
50
+ name: MidnightNames.INDEXER,
51
+ description: `Start Midnight indexer (${packageName} midnight-indexer:start)`,
52
+ cwd,
53
+ stopProcessAtPort: [8088],
54
+ args: ["run", "midnight-indexer:start"],
55
+ waitToExit: false,
56
+ critical: true,
57
+ dependsOn: [MidnightNames.NODE],
58
+ },
59
+ {
60
+ name: MidnightNames.PROOF_SERVER,
61
+ description: `Start Midnight proof server (${packageName} midnight-proof-server:start)`,
62
+ cwd,
63
+ stopProcessAtPort: [6300],
64
+ args: ["run", "midnight-proof-server:start"],
65
+ waitToExit: false,
66
+ critical: true,
67
+ dependsOn: [MidnightNames.NODE],
68
+ },
69
+ {
70
+ name: MidnightNames.NODE_WAIT,
71
+ description: `Wait for Midnight node (${packageName} midnight-node:wait)`,
72
+ cwd,
73
+ args: ["run", "midnight-node:wait"],
74
+ waitToExit: true,
75
+ dependsOn: [MidnightNames.NODE],
76
+ },
77
+ {
78
+ name: MidnightNames.INDEXER_WAIT,
79
+ description: `Wait for Midnight indexer (${packageName} midnight-indexer:wait)`,
80
+ cwd,
81
+ args: ["run", "midnight-indexer:wait"],
82
+ waitToExit: true,
83
+ dependsOn: [MidnightNames.INDEXER],
84
+ },
85
+ {
86
+ name: MidnightNames.PROOF_SERVER_WAIT,
87
+ description: `Wait for Midnight proof server (${packageName} midnight-proof-server:wait)`,
88
+ cwd,
89
+ args: ["run", "midnight-proof-server:wait"],
90
+ waitToExit: true,
91
+ dependsOn: [MidnightNames.PROOF_SERVER],
92
+ },
93
+ {
94
+ name: MidnightNames.CONTRACT_DEPLOY,
95
+ description: `Deploy Midnight contracts (${packageName} midnight-contract:deploy)`,
96
+ cwd,
97
+ args: ["run", "midnight-contract:deploy"],
98
+ ...(Object.keys(deployEnv).length > 0 ? { env: deployEnv } : {}),
99
+ waitToExit: true,
100
+ dependsOn: [
101
+ MidnightNames.NODE_WAIT,
102
+ MidnightNames.INDEXER_WAIT,
103
+ MidnightNames.PROOF_SERVER_WAIT,
104
+ ...extraDeps,
105
+ ],
106
+ },
107
+ ];
108
+ }
@@ -0,0 +1,41 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+ import { resolvePackageDir } from "./resolve-package.ts";
3
+
4
+ export const NearNames = {
5
+ SANDBOX: "near-sandbox",
6
+ SANDBOX_WAIT: "near-sandbox-wait",
7
+ } as const;
8
+
9
+ const REQUIRED_SCRIPTS = {
10
+ "chain:start": "Start the NEAR sandbox node",
11
+ "chain:wait": "Wait for the NEAR sandbox RPC to be ready (e.g. tcp:3030)",
12
+ } as const;
13
+
14
+ export function launchNear(
15
+ packageName: string,
16
+ resolveFrom: string,
17
+ opts?: { ports?: number[] },
18
+ ): ProcessConfig[] {
19
+ const cwd = resolvePackageDir("launchNear", packageName, resolveFrom, REQUIRED_SCRIPTS);
20
+ const ports = opts?.ports ?? [3030];
21
+
22
+ return [
23
+ {
24
+ stopProcessAtPort: ports,
25
+ name: NearNames.SANDBOX,
26
+ description: `Start NEAR sandbox node (${packageName} chain:start)`,
27
+ cwd,
28
+ args: ["run", "chain:start"],
29
+ waitToExit: false,
30
+ critical: true,
31
+ },
32
+ {
33
+ name: NearNames.SANDBOX_WAIT,
34
+ description: `Wait for NEAR sandbox RPC (${packageName} chain:wait)`,
35
+ cwd,
36
+ args: ["run", "chain:wait"],
37
+ waitToExit: true,
38
+ dependsOn: [NearNames.SANDBOX],
39
+ },
40
+ ];
41
+ }
@@ -0,0 +1,30 @@
1
+ import type { ProcessConfig } from "../src/config.ts";
2
+
3
+ const waitTcpScript = new URL("./wait-tcp.ts", import.meta.url).pathname;
4
+ const startPgliteScript = import.meta.resolve("@effectstream/db/start-pglite").replace("file://", "");
5
+
6
+ export const DbNames = {
7
+ PGLITE: "pglite",
8
+ PGLITE_WAIT: "pglite-wait",
9
+ } as const;
10
+
11
+ export function launchPglite(opts?: { port?: number }): ProcessConfig[] {
12
+ const port = opts?.port ?? 5432;
13
+ return [
14
+ {
15
+ name: DbNames.PGLITE,
16
+ description: `PGLite embedded database (port ${port})`,
17
+ args: [startPgliteScript, "--port", String(port)],
18
+ stopProcessAtPort: [port],
19
+ waitToExit: false,
20
+ critical: true,
21
+ },
22
+ {
23
+ name: DbNames.PGLITE_WAIT,
24
+ description: `Wait for PGLite on port ${port}`,
25
+ args: [waitTcpScript, String(port)],
26
+ waitToExit: true,
27
+ dependsOn: [DbNames.PGLITE],
28
+ },
29
+ ];
30
+ }
@@ -0,0 +1,42 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ function resolveEntry(packageName: string, resolveFrom: string): string {
5
+ try {
6
+ return require.resolve(packageName, { paths: [resolveFrom] });
7
+ } catch {
8
+ return require.resolve(`${packageName}/package.json`, { paths: [resolveFrom] });
9
+ }
10
+ }
11
+
12
+ export function resolvePackageDir(
13
+ launcherName: string,
14
+ packageName: string,
15
+ resolveFrom: string,
16
+ requiredScripts: Record<string, string>,
17
+ ): string {
18
+ const resolved = resolveEntry(packageName, resolveFrom);
19
+ let dir = path.dirname(resolved);
20
+ while (dir !== path.dirname(dir)) {
21
+ const pkgJsonPath = path.join(dir, "package.json");
22
+ if (!fs.existsSync(pkgJsonPath)) { dir = path.dirname(dir); continue; }
23
+
24
+ const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
25
+ if (pkg.name !== packageName) { dir = path.dirname(dir); continue; }
26
+
27
+ const scripts = pkg.scripts ?? {};
28
+ const required = Object.keys(requiredScripts);
29
+ const missing = required.filter((s) => !(s in scripts));
30
+ if (missing.length > 0) {
31
+ throw new Error(
32
+ `${launcherName}: package "${packageName}" is missing required scripts: ${missing.join(", ")}\n` +
33
+ ` This launcher expects the following scripts in package.json:\n` +
34
+ missing.map((s) => ` - ${s}: ${requiredScripts[s]}`).join("\n"),
35
+ );
36
+ }
37
+ return dir;
38
+ }
39
+ throw new Error(
40
+ `${launcherName}: could not find package.json for "${packageName}" (resolved to "${resolved}")`,
41
+ );
42
+ }
@@ -0,0 +1,24 @@
1
+ const url = process.argv.at(-1);
2
+ if (!url || !url.startsWith("http")) {
3
+ console.error("Usage: bun wait-http.ts <url>");
4
+ process.exit(1);
5
+ }
6
+
7
+ const timeout = Number(process.argv.includes("--timeout")
8
+ ? process.argv[process.argv.indexOf("--timeout") + 1]
9
+ : 60000);
10
+
11
+ const start = Date.now();
12
+
13
+ while (Date.now() - start < timeout) {
14
+ try {
15
+ const res = await fetch(url);
16
+ if (res.ok) process.exit(0);
17
+ } catch {
18
+ // not ready yet
19
+ }
20
+ await Bun.sleep(500);
21
+ }
22
+
23
+ console.error(`Timed out waiting for ${url}`);
24
+ process.exit(1);
@@ -0,0 +1,30 @@
1
+ const port = Number(process.argv.at(-1));
2
+ if (!port || isNaN(port)) {
3
+ console.error("Usage: bun wait-tcp.ts <port>");
4
+ process.exit(1);
5
+ }
6
+
7
+ for (let i = 0; i < 120; i++) {
8
+ try {
9
+ const connected = await new Promise<boolean>((resolve) => {
10
+ Bun.connect({
11
+ hostname: "127.0.0.1",
12
+ port,
13
+ socket: {
14
+ open(socket) { socket.end(); resolve(true); },
15
+ data() {},
16
+ error() { resolve(false); },
17
+ close() {},
18
+ connectError() { resolve(false); },
19
+ },
20
+ }).catch(() => resolve(false));
21
+ });
22
+ if (connected) process.exit(0);
23
+ } catch {
24
+ // fallthrough to retry
25
+ }
26
+ await Bun.sleep(500);
27
+ }
28
+
29
+ console.error(`Timed out waiting for tcp:${port}`);
30
+ process.exit(1);