flatsql 0.4.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +116 -6
  2. package/dist/artifacts/builder.d.ts +31 -0
  3. package/dist/artifacts/builder.d.ts.map +1 -0
  4. package/dist/artifacts/builder.js +514 -0
  5. package/dist/artifacts/builder.js.map +1 -0
  6. package/dist/artifacts/demo-extractors.d.ts +15 -0
  7. package/dist/artifacts/demo-extractors.d.ts.map +1 -0
  8. package/dist/artifacts/demo-extractors.js +238 -0
  9. package/dist/artifacts/demo-extractors.js.map +1 -0
  10. package/dist/artifacts/index.d.ts +5 -0
  11. package/dist/artifacts/index.d.ts.map +1 -0
  12. package/dist/artifacts/index.js +5 -0
  13. package/dist/artifacts/index.js.map +1 -0
  14. package/dist/artifacts/standalone-builder.d.ts +62 -0
  15. package/dist/artifacts/standalone-builder.d.ts.map +1 -0
  16. package/dist/artifacts/standalone-builder.js +144 -0
  17. package/dist/artifacts/standalone-builder.js.map +1 -0
  18. package/dist/artifacts/transport.d.ts +5 -0
  19. package/dist/artifacts/transport.d.ts.map +1 -0
  20. package/dist/artifacts/transport.js +45 -0
  21. package/dist/artifacts/transport.js.map +1 -0
  22. package/dist/artifacts/types.d.ts +34 -0
  23. package/dist/artifacts/types.d.ts.map +1 -0
  24. package/dist/artifacts/types.js +2 -0
  25. package/dist/artifacts/types.js.map +1 -0
  26. package/dist/artifacts/worker-client.d.ts +32 -0
  27. package/dist/artifacts/worker-client.d.ts.map +1 -0
  28. package/dist/artifacts/worker-client.js +415 -0
  29. package/dist/artifacts/worker-client.js.map +1 -0
  30. package/dist/btree/btree.d.ts.map +1 -1
  31. package/dist/btree/btree.js +13 -14
  32. package/dist/btree/btree.js.map +1 -1
  33. package/dist/core/database.d.ts +2 -0
  34. package/dist/core/database.d.ts.map +1 -1
  35. package/dist/core/database.js +18 -0
  36. package/dist/core/database.js.map +1 -1
  37. package/dist/core/table-store.d.ts +1 -0
  38. package/dist/core/table-store.d.ts.map +1 -1
  39. package/dist/core/table-store.js +31 -0
  40. package/dist/core/table-store.js.map +1 -1
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +3 -0
  44. package/dist/index.js.map +1 -1
  45. package/dist/response/artifact.d.ts +5 -0
  46. package/dist/response/artifact.d.ts.map +1 -0
  47. package/dist/response/artifact.js +102 -0
  48. package/dist/response/artifact.js.map +1 -0
  49. package/dist/response/cache-key.d.ts +6 -0
  50. package/dist/response/cache-key.d.ts.map +1 -0
  51. package/dist/response/cache-key.js +114 -0
  52. package/dist/response/cache-key.js.map +1 -0
  53. package/dist/response/index.d.ts +5 -0
  54. package/dist/response/index.d.ts.map +1 -0
  55. package/dist/response/index.js +5 -0
  56. package/dist/response/index.js.map +1 -0
  57. package/dist/response/memory-cache.d.ts +17 -0
  58. package/dist/response/memory-cache.d.ts.map +1 -0
  59. package/dist/response/memory-cache.js +76 -0
  60. package/dist/response/memory-cache.js.map +1 -0
  61. package/dist/response/types.d.ts +51 -0
  62. package/dist/response/types.d.ts.map +1 -0
  63. package/dist/response/types.js +2 -0
  64. package/dist/response/types.js.map +1 -0
  65. package/dist/standalone/index.d.ts +3 -0
  66. package/dist/standalone/index.d.ts.map +1 -0
  67. package/dist/standalone/index.js +3 -0
  68. package/dist/standalone/index.js.map +1 -0
  69. package/dist/standalone/process-client.d.ts +85 -0
  70. package/dist/standalone/process-client.d.ts.map +1 -0
  71. package/dist/standalone/process-client.js +537 -0
  72. package/dist/standalone/process-client.js.map +1 -0
  73. package/dist/standalone/wasmedge-runner.d.ts +19 -0
  74. package/dist/standalone/wasmedge-runner.d.ts.map +1 -0
  75. package/dist/standalone/wasmedge-runner.js +108 -0
  76. package/dist/standalone/wasmedge-runner.js.map +1 -0
  77. package/dist/stress/aggregate.d.ts +3 -0
  78. package/dist/stress/aggregate.d.ts.map +1 -0
  79. package/dist/stress/aggregate.js +61 -0
  80. package/dist/stress/aggregate.js.map +1 -0
  81. package/dist/stress/docker-compose.d.ts +17 -0
  82. package/dist/stress/docker-compose.d.ts.map +1 -0
  83. package/dist/stress/docker-compose.js +156 -0
  84. package/dist/stress/docker-compose.js.map +1 -0
  85. package/dist/stress/index.d.ts +11 -0
  86. package/dist/stress/index.d.ts.map +1 -0
  87. package/dist/stress/index.js +11 -0
  88. package/dist/stress/index.js.map +1 -0
  89. package/dist/stress/metrics.d.ts +3 -0
  90. package/dist/stress/metrics.d.ts.map +1 -0
  91. package/dist/stress/metrics.js +83 -0
  92. package/dist/stress/metrics.js.map +1 -0
  93. package/dist/stress/native-publish-event-workload.d.ts +3 -0
  94. package/dist/stress/native-publish-event-workload.d.ts.map +1 -0
  95. package/dist/stress/native-publish-event-workload.js +455 -0
  96. package/dist/stress/native-publish-event-workload.js.map +1 -0
  97. package/dist/stress/production-gate.d.ts +4 -0
  98. package/dist/stress/production-gate.d.ts.map +1 -0
  99. package/dist/stress/production-gate.js +12 -0
  100. package/dist/stress/production-gate.js.map +1 -0
  101. package/dist/stress/publish-event-workload.d.ts +3 -0
  102. package/dist/stress/publish-event-workload.d.ts.map +1 -0
  103. package/dist/stress/publish-event-workload.js +467 -0
  104. package/dist/stress/publish-event-workload.js.map +1 -0
  105. package/dist/stress/report.d.ts +3 -0
  106. package/dist/stress/report.d.ts.map +1 -0
  107. package/dist/stress/report.js +174 -0
  108. package/dist/stress/report.js.map +1 -0
  109. package/dist/stress/sds-discovery.d.ts +4 -0
  110. package/dist/stress/sds-discovery.d.ts.map +1 -0
  111. package/dist/stress/sds-discovery.js +40 -0
  112. package/dist/stress/sds-discovery.js.map +1 -0
  113. package/dist/stress/smoke-runner.d.ts +3 -0
  114. package/dist/stress/smoke-runner.d.ts.map +1 -0
  115. package/dist/stress/smoke-runner.js +63 -0
  116. package/dist/stress/smoke-runner.js.map +1 -0
  117. package/dist/stress/types.d.ts +219 -0
  118. package/dist/stress/types.d.ts.map +1 -0
  119. package/dist/stress/types.js +2 -0
  120. package/dist/stress/types.js.map +1 -0
  121. package/dist/stress/workload.d.ts +6 -0
  122. package/dist/stress/workload.d.ts.map +1 -0
  123. package/dist/stress/workload.js +144 -0
  124. package/dist/stress/workload.js.map +1 -0
  125. package/docs/agents/response-artifacts.md +65 -0
  126. package/docs/response-artifacts.md +86 -0
  127. package/package.json +37 -7
  128. package/scripts/stress-docker.sh +279 -0
  129. package/sdm/flatsql-spatial.wasm +0 -0
  130. package/stress/docker/Dockerfile +11 -0
  131. package/stress/docker/docker-compose.yml +51 -0
  132. package/stress/sds/aggregate.mjs +97 -0
  133. package/stress/sds/run.mjs +105 -0
  134. package/stress/sds/write-compose.mjs +96 -0
  135. package/wasm/flatsql-artifact.worker.js +847 -0
  136. package/wasm/flatsql-wasi.wasm +0 -0
  137. package/wasm/flatsql.js +2 -16
  138. package/wasm/flatsql.wasm +0 -0
  139. package/wasm/index.d.ts +127 -2
  140. package/wasm/index.js +459 -61
  141. package/wasm/native/flatsql_wasmedge_runner.cpp +858 -0
  142. package/wasm/standalone.d.ts +91 -0
  143. package/wasm/standalone.js +740 -0
@@ -0,0 +1,11 @@
1
+ FROM node:24-bookworm-slim
2
+
3
+ WORKDIR /workspace
4
+
5
+ COPY package.json package-lock.json ./
6
+ RUN npm ci
7
+
8
+ COPY . .
9
+ RUN npm run build
10
+
11
+ CMD ["node", "stress/sds/run.mjs", "--help"]
@@ -0,0 +1,51 @@
1
+ services:
2
+ controller:
3
+ build:
4
+ context: ../..
5
+ dockerfile: stress/docker/Dockerfile
6
+ environment:
7
+ STRESS_MODE: ${STRESS_MODE:-smoke}
8
+ RUN_ID: ${RUN_ID:-docker-smoke}
9
+ NODE_COUNT: ${NODE_COUNT:-2}
10
+ NODE_STORAGE_GB: ${NODE_STORAGE_GB:-0.01}
11
+ RECORDS_PER_NODE: ${RECORDS_PER_NODE:-25}
12
+ BATCH_BYTES: ${BATCH_BYTES:-1048576}
13
+ QUERY_CONCURRENCY: ${QUERY_CONCURRENCY:-4}
14
+ HOT_QUERY_RATIO: ${HOT_QUERY_RATIO:-0.9}
15
+ SDS_SCHEMA_ROOT: /sds/schema
16
+ OUTPUT_DIR: /stress-results
17
+ RUNTIME: ${RUNTIME:-standalone}
18
+ NODE_ISOLATION: ${NODE_ISOLATION:-logical}
19
+ STRESS_TRANSPORT: docker-compose
20
+ volumes:
21
+ - ${SDS_SCHEMA_ROOT_HOST:-../../spacedatastandards.org/schema}:/sds/schema:ro
22
+ - ${OUTPUT_DIR_HOST:-../results/docker-smoke}:/stress-results
23
+ command:
24
+ - node
25
+ - stress/sds/run.mjs
26
+ - --mode
27
+ - ${STRESS_MODE:-smoke}
28
+ - --schema-root
29
+ - /sds/schema
30
+ - --output-dir
31
+ - /stress-results
32
+ - --nodes
33
+ - ${NODE_COUNT:-2}
34
+ - --storage-gb
35
+ - ${NODE_STORAGE_GB:-0.01}
36
+ - --records-per-node
37
+ - ${RECORDS_PER_NODE:-25}
38
+ - --batch-bytes
39
+ - ${BATCH_BYTES:-1048576}
40
+ - --query-concurrency
41
+ - ${QUERY_CONCURRENCY:-4}
42
+ - --hot-query-ratio
43
+ - ${HOT_QUERY_RATIO:-0.9}
44
+ - --run-id
45
+ - ${RUN_ID:-docker-smoke}
46
+ - --runtime
47
+ - ${RUNTIME:-standalone}
48
+ - --node-isolation
49
+ - ${NODE_ISOLATION:-logical}
50
+ - --transport
51
+ - docker-compose
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readdir } from 'node:fs/promises';
4
+ import { join, resolve } from 'node:path';
5
+ import { aggregateStressRunArtifacts, assertProductionReadiness } from '../../dist/stress/index.js';
6
+
7
+ function readOption(argv, name, defaultValue = undefined) {
8
+ const prefix = `--${name}=`;
9
+ let value = defaultValue;
10
+ for (let index = 0; index < argv.length; index++) {
11
+ const arg = argv[index];
12
+ if (arg === `--${name}`) {
13
+ value = argv[index + 1];
14
+ index++;
15
+ } else if (arg.startsWith(prefix)) {
16
+ value = arg.slice(prefix.length);
17
+ }
18
+ }
19
+ return value;
20
+ }
21
+
22
+ function readNumber(argv, name, defaultValue = undefined) {
23
+ const value = readOption(argv, name, defaultValue === undefined ? undefined : String(defaultValue));
24
+ if (value === undefined) {
25
+ return undefined;
26
+ }
27
+ const parsed = Number(value);
28
+ if (!Number.isFinite(parsed)) {
29
+ throw new Error(`Invalid numeric value for --${name}: ${value}`);
30
+ }
31
+ return parsed;
32
+ }
33
+
34
+ function printHelp() {
35
+ console.log(`Usage: node stress/sds/aggregate.mjs [options]
36
+
37
+ Options:
38
+ --input-dir <path> Directory containing node result subdirectories
39
+ --output-dir <path> Directory for aggregate result artifacts
40
+ --run-id <id>
41
+ --mode smoke|full
42
+ --node-storage-gb <gb>
43
+ --records-per-node <count>
44
+ --transport in-process|docker-compose
45
+ --node-isolation logical|container
46
+ `);
47
+ }
48
+
49
+ async function listInputDirs(inputRoot) {
50
+ const entries = await readdir(inputRoot, { withFileTypes: true });
51
+ return entries
52
+ .filter((entry) => entry.isDirectory())
53
+ .map((entry) => join(inputRoot, entry.name))
54
+ .sort();
55
+ }
56
+
57
+ async function main() {
58
+ const argv = process.argv.slice(2);
59
+ if (argv.includes('--help') || argv.includes('-h')) {
60
+ printHelp();
61
+ return;
62
+ }
63
+
64
+ const inputRoot = resolve(readOption(argv, 'input-dir', 'stress/results/nodes'));
65
+ const outputDir = resolve(readOption(argv, 'output-dir', 'stress/results/aggregate'));
66
+ const runId = readOption(argv, 'run-id', process.env.RUN_ID ?? `sds-aggregate-${Date.now()}`);
67
+ const mode = readOption(argv, 'mode', process.env.STRESS_MODE ?? 'smoke');
68
+ const inputDirs = await listInputDirs(inputRoot);
69
+
70
+ const result = await aggregateStressRunArtifacts({
71
+ inputDirs,
72
+ outputDir,
73
+ runId,
74
+ mode,
75
+ nodeStorageGb: readNumber(argv, 'node-storage-gb', process.env.NODE_STORAGE_GB) ?? 1,
76
+ recordsPerNode: readNumber(argv, 'records-per-node', process.env.RECORDS_PER_NODE) ?? 0,
77
+ transport: readOption(argv, 'transport', process.env.STRESS_TRANSPORT ?? 'docker-compose'),
78
+ nodeIsolation: readOption(argv, 'node-isolation', process.env.NODE_ISOLATION ?? 'container'),
79
+ });
80
+
81
+ console.log(`FlatSQL SDS aggregate ${result.manifest.mode} run: ${result.manifest.runId}`);
82
+ console.log(`Nodes: ${result.summary.nodes.length}`);
83
+ console.log(`Result directory: ${outputDir}`);
84
+ console.log(`Events: ${result.summary.eventCount}`);
85
+ console.log(`Request bytes: ${result.summary.totalRequestBytes}`);
86
+ console.log(`Response bytes: ${result.summary.totalResponseBytes}`);
87
+ console.log(`Cache hits/misses: ${result.summary.totalCacheHits}/${result.summary.totalCacheMisses}`);
88
+
89
+ if (result.manifest.mode === 'full') {
90
+ assertProductionReadiness(result.report);
91
+ }
92
+ }
93
+
94
+ main().catch((error) => {
95
+ console.error(error instanceof Error ? error.message : String(error));
96
+ process.exitCode = 1;
97
+ });
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { resolve } from 'node:path';
4
+ import { assertProductionReadiness, runSmokeHarness } from '../../dist/stress/index.js';
5
+
6
+ function readOption(argv, name, defaultValue = undefined) {
7
+ const prefix = `--${name}=`;
8
+ let value = defaultValue;
9
+ for (let index = 0; index < argv.length; index++) {
10
+ const arg = argv[index];
11
+ if (arg === `--${name}`) {
12
+ value = argv[index + 1];
13
+ index++;
14
+ } else if (arg.startsWith(prefix)) {
15
+ value = arg.slice(prefix.length);
16
+ }
17
+ }
18
+ return value;
19
+ }
20
+
21
+ function readNumber(argv, name, defaultValue = undefined) {
22
+ const value = readOption(argv, name, defaultValue === undefined ? undefined : String(defaultValue));
23
+ if (value === undefined) {
24
+ return undefined;
25
+ }
26
+ const parsed = Number(value);
27
+ if (!Number.isFinite(parsed)) {
28
+ throw new Error(`Invalid numeric value for --${name}: ${value}`);
29
+ }
30
+ return parsed;
31
+ }
32
+
33
+ function printHelp() {
34
+ console.log(`Usage: node stress/sds/run.mjs [options]
35
+
36
+ Options:
37
+ --mode smoke|full
38
+ --schema-root <path>
39
+ --output-dir <path>
40
+ --nodes <count>
41
+ --node-id-offset <count>
42
+ --storage-gb <gb>
43
+ --records-per-node <count>
44
+ --batch-bytes <bytes>
45
+ --query-concurrency <count>
46
+ --hot-query-ratio <ratio>
47
+ --runtime standalone|wasmedge|native
48
+ --transport in-process|docker-compose
49
+ --node-isolation logical|container
50
+ --skip-production-gate
51
+ --run-id <id>
52
+ `);
53
+ }
54
+
55
+ async function main() {
56
+ const argv = process.argv.slice(2);
57
+ if (argv.includes('--help') || argv.includes('-h')) {
58
+ printHelp();
59
+ return;
60
+ }
61
+
62
+ const mode = readOption(argv, 'mode', process.env.STRESS_MODE ?? 'smoke');
63
+ const runId = readOption(argv, 'run-id', process.env.RUN_ID ?? `sds-${mode}-${Date.now()}`);
64
+ const schemaRoot = resolve(
65
+ readOption(argv, 'schema-root', process.env.SDS_SCHEMA_ROOT ?? '../spacedatastandards.org/schema')
66
+ );
67
+ const outputDir = resolve(
68
+ readOption(argv, 'output-dir', process.env.OUTPUT_DIR ?? `stress/results/${runId}`)
69
+ );
70
+
71
+ const result = await runSmokeHarness({
72
+ mode,
73
+ runId,
74
+ schemaRoot,
75
+ outputDir,
76
+ nodeCount: readNumber(argv, 'nodes', process.env.NODE_COUNT),
77
+ nodeIdOffset: readNumber(argv, 'node-id-offset', process.env.NODE_ID_OFFSET),
78
+ nodeStorageGb: readNumber(argv, 'storage-gb', process.env.NODE_STORAGE_GB),
79
+ recordsPerNode: readNumber(argv, 'records-per-node', process.env.RECORDS_PER_NODE),
80
+ batchBytes: readNumber(argv, 'batch-bytes', process.env.BATCH_BYTES),
81
+ queryConcurrency: readNumber(argv, 'query-concurrency', process.env.QUERY_CONCURRENCY),
82
+ hotQueryRatio: readNumber(argv, 'hot-query-ratio', process.env.HOT_QUERY_RATIO),
83
+ runtime: readOption(argv, 'runtime', process.env.RUNTIME),
84
+ transport: readOption(argv, 'transport', process.env.STRESS_TRANSPORT),
85
+ nodeIsolation: readOption(argv, 'node-isolation', process.env.NODE_ISOLATION),
86
+ });
87
+
88
+ console.log(`FlatSQL SDS stress ${result.manifest.mode} run: ${result.manifest.runId}`);
89
+ console.log(`Schemas: ${result.manifest.schemaCount}`);
90
+ console.log(`Nodes: ${result.manifest.nodeCount}`);
91
+ console.log(`Result directory: ${outputDir}`);
92
+ console.log(`Events: ${result.summary.eventCount}`);
93
+ console.log(`Request bytes: ${result.summary.totalRequestBytes}`);
94
+ console.log(`Response bytes: ${result.summary.totalResponseBytes}`);
95
+ console.log(`Cache hits/misses: ${result.summary.totalCacheHits}/${result.summary.totalCacheMisses}`);
96
+
97
+ if (result.manifest.mode === 'full' && !argv.includes('--skip-production-gate')) {
98
+ assertProductionReadiness(result.report);
99
+ }
100
+ }
101
+
102
+ main().catch((error) => {
103
+ console.error(error instanceof Error ? error.message : String(error));
104
+ process.exitCode = 1;
105
+ });
@@ -0,0 +1,96 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { mkdir, writeFile } from 'node:fs/promises';
4
+ import { dirname, resolve } from 'node:path';
5
+ import { buildFullStressDockerCompose } from '../../dist/stress/index.js';
6
+
7
+ function readOption(argv, name, defaultValue = undefined) {
8
+ const prefix = `--${name}=`;
9
+ let value = defaultValue;
10
+ for (let index = 0; index < argv.length; index++) {
11
+ const arg = argv[index];
12
+ if (arg === `--${name}`) {
13
+ value = argv[index + 1];
14
+ index++;
15
+ } else if (arg.startsWith(prefix)) {
16
+ value = arg.slice(prefix.length);
17
+ }
18
+ }
19
+ return value;
20
+ }
21
+
22
+ function readNumber(argv, name, defaultValue = undefined) {
23
+ const value = readOption(argv, name, defaultValue === undefined ? undefined : String(defaultValue));
24
+ if (value === undefined) {
25
+ return undefined;
26
+ }
27
+ const parsed = Number(value);
28
+ if (!Number.isFinite(parsed)) {
29
+ throw new Error(`Invalid numeric value for --${name}: ${value}`);
30
+ }
31
+ return parsed;
32
+ }
33
+
34
+ function printHelp() {
35
+ console.log(`Usage: node stress/sds/write-compose.mjs [options]
36
+
37
+ Options:
38
+ --output-file <path>
39
+ --project-root <path>
40
+ --schema-root-host <path>
41
+ --output-dir-host <path>
42
+ --run-id <id>
43
+ --mode smoke|full
44
+ --nodes <count>
45
+ --storage-gb <gb>
46
+ --records-per-node <count>
47
+ --batch-bytes <bytes>
48
+ --query-concurrency <count>
49
+ --hot-query-ratio <ratio>
50
+ --runtime standalone|wasmedge|native
51
+ `);
52
+ }
53
+
54
+ async function main() {
55
+ const argv = process.argv.slice(2);
56
+ if (argv.includes('--help') || argv.includes('-h')) {
57
+ printHelp();
58
+ return;
59
+ }
60
+
61
+ const outputFile = resolve(readOption(argv, 'output-file', 'stress/results/docker-compose.full.yml'));
62
+ const projectRoot = resolve(readOption(argv, 'project-root', process.cwd()));
63
+ const schemaRootHost = resolve(readOption(argv, 'schema-root-host', '../spacedatastandards.org/schema'));
64
+ const outputDirHost = resolve(readOption(argv, 'output-dir-host', 'stress/results/full'));
65
+ const nodeCount = readNumber(argv, 'nodes', process.env.NODE_COUNT) ?? 100;
66
+
67
+ const compose = buildFullStressDockerCompose({
68
+ projectRoot,
69
+ schemaRootHost,
70
+ outputDirHost,
71
+ runId: readOption(argv, 'run-id', process.env.RUN_ID ?? `sds-full-${Date.now()}`),
72
+ mode: readOption(argv, 'mode', process.env.STRESS_MODE ?? 'full'),
73
+ nodeCount,
74
+ nodeStorageGb: readNumber(argv, 'storage-gb', process.env.NODE_STORAGE_GB) ?? 1,
75
+ recordsPerNode: readNumber(argv, 'records-per-node', process.env.RECORDS_PER_NODE) ?? 2900000,
76
+ batchBytes: readNumber(argv, 'batch-bytes', process.env.BATCH_BYTES) ?? 1048576,
77
+ queryConcurrency: readNumber(argv, 'query-concurrency', process.env.QUERY_CONCURRENCY) ?? 64,
78
+ hotQueryRatio: readNumber(argv, 'hot-query-ratio', process.env.HOT_QUERY_RATIO) ?? 0.01,
79
+ runtime: readOption(argv, 'runtime', process.env.RUNTIME ?? 'standalone'),
80
+ });
81
+
82
+ await mkdir(dirname(outputFile), { recursive: true });
83
+ await mkdir(outputDirHost, { recursive: true });
84
+ await mkdir(`${outputDirHost}/nodes`, { recursive: true });
85
+ await mkdir(`${outputDirHost}/aggregate`, { recursive: true });
86
+ await Promise.all(
87
+ Array.from({ length: nodeCount }, (_, nodeId) => mkdir(`${outputDirHost}/nodes/node-${nodeId}`, { recursive: true }))
88
+ );
89
+ await writeFile(outputFile, compose);
90
+ console.log(outputFile);
91
+ }
92
+
93
+ main().catch((error) => {
94
+ console.error(error instanceof Error ? error.message : String(error));
95
+ process.exitCode = 1;
96
+ });