@livestore/utils-dev 0.4.0-dev.2 → 0.4.0-dev.20

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 (73) hide show
  1. package/dist/.tsbuildinfo.json +1 -1
  2. package/dist/node/DockerComposeService/DockerComposeService.d.ts +58 -0
  3. package/dist/node/DockerComposeService/DockerComposeService.d.ts.map +1 -0
  4. package/dist/node/DockerComposeService/DockerComposeService.js +144 -0
  5. package/dist/node/DockerComposeService/DockerComposeService.js.map +1 -0
  6. package/dist/node/DockerComposeService/DockerComposeService.test.d.ts +2 -0
  7. package/dist/node/DockerComposeService/DockerComposeService.test.d.ts.map +1 -0
  8. package/dist/node/DockerComposeService/DockerComposeService.test.js +64 -0
  9. package/dist/node/DockerComposeService/DockerComposeService.test.js.map +1 -0
  10. package/dist/node/cmd-log.d.ts +21 -0
  11. package/dist/node/cmd-log.d.ts.map +1 -0
  12. package/dist/node/cmd-log.js +47 -0
  13. package/dist/node/cmd-log.js.map +1 -0
  14. package/dist/node/cmd.d.ts +35 -0
  15. package/dist/node/cmd.d.ts.map +1 -0
  16. package/dist/node/cmd.js +235 -0
  17. package/dist/node/cmd.js.map +1 -0
  18. package/dist/node/cmd.test.d.ts +2 -0
  19. package/dist/node/cmd.test.d.ts.map +1 -0
  20. package/dist/node/cmd.test.js +102 -0
  21. package/dist/node/cmd.test.js.map +1 -0
  22. package/dist/node/mod.d.ts +5 -26
  23. package/dist/node/mod.d.ts.map +1 -1
  24. package/dist/node/mod.js +52 -59
  25. package/dist/node/mod.js.map +1 -1
  26. package/dist/node/workspace.d.ts +22 -0
  27. package/dist/node/workspace.d.ts.map +1 -0
  28. package/dist/node/workspace.js +26 -0
  29. package/dist/node/workspace.js.map +1 -0
  30. package/dist/node-vitest/Vitest.d.ts +41 -7
  31. package/dist/node-vitest/Vitest.d.ts.map +1 -1
  32. package/dist/node-vitest/Vitest.js +82 -5
  33. package/dist/node-vitest/Vitest.js.map +1 -1
  34. package/dist/node-vitest/Vitest.test.d.ts +2 -0
  35. package/dist/node-vitest/Vitest.test.d.ts.map +1 -0
  36. package/dist/node-vitest/Vitest.test.js +70 -0
  37. package/dist/node-vitest/Vitest.test.js.map +1 -0
  38. package/dist/wrangler/WranglerDevServer.d.ts +69 -0
  39. package/dist/wrangler/WranglerDevServer.d.ts.map +1 -0
  40. package/dist/wrangler/WranglerDevServer.js +103 -0
  41. package/dist/wrangler/WranglerDevServer.js.map +1 -0
  42. package/dist/wrangler/WranglerDevServer.test.d.ts +2 -0
  43. package/dist/wrangler/WranglerDevServer.test.d.ts.map +1 -0
  44. package/dist/wrangler/WranglerDevServer.test.js +77 -0
  45. package/dist/wrangler/WranglerDevServer.test.js.map +1 -0
  46. package/dist/wrangler/fixtures/cf-worker.d.ts +8 -0
  47. package/dist/wrangler/fixtures/cf-worker.d.ts.map +1 -0
  48. package/dist/wrangler/fixtures/cf-worker.js +11 -0
  49. package/dist/wrangler/fixtures/cf-worker.js.map +1 -0
  50. package/dist/wrangler/mod.d.ts +2 -0
  51. package/dist/wrangler/mod.d.ts.map +1 -0
  52. package/dist/wrangler/mod.js +2 -0
  53. package/dist/wrangler/mod.js.map +1 -0
  54. package/package.json +11 -10
  55. package/src/node/DockerComposeService/DockerComposeService.test.ts +91 -0
  56. package/src/node/DockerComposeService/DockerComposeService.ts +328 -0
  57. package/src/node/DockerComposeService/test-fixtures/docker-compose.yml +4 -0
  58. package/src/node/cmd-log.ts +87 -0
  59. package/src/node/cmd.test.ts +130 -0
  60. package/src/node/cmd.ts +420 -0
  61. package/src/node/mod.ts +63 -116
  62. package/src/node/workspace.ts +45 -0
  63. package/src/node-vitest/Vitest.test.ts +112 -0
  64. package/src/node-vitest/Vitest.ts +193 -17
  65. package/src/wrangler/WranglerDevServer.test.ts +133 -0
  66. package/src/wrangler/WranglerDevServer.ts +220 -0
  67. package/src/wrangler/fixtures/cf-worker.ts +11 -0
  68. package/src/wrangler/fixtures/wrangler.toml +11 -0
  69. package/src/wrangler/mod.ts +6 -0
  70. package/dist/node-vitest/polyfill.d.ts +0 -2
  71. package/dist/node-vitest/polyfill.d.ts.map +0 -1
  72. package/dist/node-vitest/polyfill.js +0 -3
  73. package/dist/node-vitest/polyfill.js.map +0 -1
@@ -0,0 +1,235 @@
1
+ import fs from 'node:fs';
2
+ import { isNotUndefined } from '@livestore/utils';
3
+ import { Cause, Command, Effect, Fiber, FiberId, FiberRefs, HashMap, identity, List, LogLevel, Schema, Stream, } from '@livestore/utils/effect';
4
+ import { applyLoggingToCommand } from "./cmd-log.js";
5
+ import * as FileLogger from "./FileLogger.js";
6
+ import { CurrentWorkingDirectory } from "./workspace.js";
7
+ // Branded zero value so we can compare exit codes without touching internals.
8
+ const SUCCESS_EXIT_CODE = 0;
9
+ export const cmd = Effect.fn('cmd')(function* (commandInput, options) {
10
+ const cwd = yield* CurrentWorkingDirectory;
11
+ const asArray = Array.isArray(commandInput);
12
+ const parts = asArray ? commandInput.filter(isNotUndefined) : undefined;
13
+ const [command, ...args] = asArray ? parts : commandInput.split(' ');
14
+ const debugEnvStr = Object.entries(options?.env ?? {})
15
+ .map(([key, value]) => `${key}='${value}' `)
16
+ .join('');
17
+ const loggingOpts = {
18
+ ...(options?.logDir ? { logDir: options.logDir } : {}),
19
+ ...(options?.logFileName ? { logFileName: options.logFileName } : {}),
20
+ ...(options?.logRetention ? { logRetention: options.logRetention } : {}),
21
+ };
22
+ const { input: finalInput, subshell: needsShell, logPath } = yield* applyLoggingToCommand(commandInput, loggingOpts);
23
+ const stdoutMode = options?.stdout ?? 'inherit';
24
+ const stderrMode = options?.stderr ?? 'inherit';
25
+ const useShell = (options?.shell ? true : false) || needsShell;
26
+ const commandDebugStr = debugEnvStr + (Array.isArray(finalInput) ? finalInput.join(' ') : finalInput);
27
+ const subshellStr = useShell ? ' (in subshell)' : '';
28
+ yield* Effect.logDebug(`Running '${commandDebugStr}' in '${cwd}'${subshellStr}`);
29
+ yield* Effect.annotateCurrentSpan({
30
+ 'span.label': commandDebugStr,
31
+ cwd,
32
+ command,
33
+ args,
34
+ logDir: options?.logDir,
35
+ });
36
+ const baseArgs = {
37
+ commandInput: finalInput,
38
+ cwd,
39
+ env: options?.env ?? {},
40
+ stdoutMode,
41
+ stderrMode,
42
+ useShell,
43
+ };
44
+ const exitCode = yield* isNotUndefined(logPath)
45
+ ? Effect.gen(function* () {
46
+ yield* Effect.sync(() => console.log(`Logging output to ${logPath}`));
47
+ return yield* runWithLogging({ ...baseArgs, logPath, threadName: commandDebugStr });
48
+ })
49
+ : runWithoutLogging(baseArgs);
50
+ if (exitCode !== SUCCESS_EXIT_CODE) {
51
+ return yield* Effect.fail(CmdError.make({
52
+ command: command,
53
+ args,
54
+ cwd,
55
+ env: options?.env ?? {},
56
+ stderr: stderrMode,
57
+ }));
58
+ }
59
+ return exitCode;
60
+ });
61
+ export const cmdText = Effect.fn('cmdText')(function* (commandInput, options) {
62
+ const cwd = yield* CurrentWorkingDirectory;
63
+ const [command, ...args] = Array.isArray(commandInput)
64
+ ? commandInput.filter(isNotUndefined)
65
+ : commandInput.split(' ');
66
+ const debugEnvStr = Object.entries(options?.env ?? {})
67
+ .map(([key, value]) => `${key}='${value}' `)
68
+ .join('');
69
+ const commandDebugStr = debugEnvStr + [command, ...args].join(' ');
70
+ const subshellStr = options?.runInShell ? ' (in subshell)' : '';
71
+ yield* Effect.logDebug(`Running '${commandDebugStr}' in '${cwd}'${subshellStr}`);
72
+ yield* Effect.annotateCurrentSpan({ 'span.label': commandDebugStr, command, cwd });
73
+ return yield* Command.make(command, ...args).pipe(
74
+ // inherit = Stream stderr to process.stderr, pipe = Stream stderr to process.stdout
75
+ Command.stderr(options?.stderr ?? 'inherit'), Command.workingDirectory(cwd), options?.runInShell ? Command.runInShell(true) : identity, Command.env(options?.env ?? {}), Command.string);
76
+ });
77
+ export class CmdError extends Schema.TaggedError()('CmdError', {
78
+ command: Schema.String,
79
+ args: Schema.Array(Schema.String),
80
+ cwd: Schema.String,
81
+ env: Schema.Record({ key: Schema.String, value: Schema.String.pipe(Schema.UndefinedOr) }),
82
+ stderr: Schema.Literal('inherit', 'pipe'),
83
+ }) {
84
+ }
85
+ const runWithoutLogging = ({ commandInput, cwd, env, stdoutMode, stderrMode, useShell }) => buildCommand(commandInput, useShell).pipe(Command.stdin('inherit'), Command.stdout(stdoutMode), Command.stderr(stderrMode), Command.workingDirectory(cwd), useShell ? Command.runInShell(true) : identity, Command.env(env), Command.exitCode);
86
+ const runWithLogging = ({ commandInput, cwd, env, stdoutMode, stderrMode, useShell, logPath, threadName, }) =>
87
+ // When logging is enabled we have to replace the `2>&1 | tee` pipeline the
88
+ // shell used to give us. We now pipe both streams through Effect so we can
89
+ // mirror to the terminal (only when requested) and append formatted entries
90
+ // into the canonical log ourselves.
91
+ Effect.scoped(Effect.gen(function* () {
92
+ const envWithColor = env.FORCE_COLOR === undefined ? { ...env, FORCE_COLOR: '1' } : env;
93
+ const logFile = yield* Effect.acquireRelease(Effect.sync(() => fs.openSync(logPath, 'a', 0o666)), (fd) => Effect.sync(() => fs.closeSync(fd)));
94
+ const prettyLogger = FileLogger.prettyLoggerTty({
95
+ colors: true,
96
+ stderr: false,
97
+ formatDate: (date) => `${FileLogger.defaultDateFormat(date)} ${threadName}`,
98
+ });
99
+ const appendLog = ({ channel, content }) => Effect.sync(() => {
100
+ const formatted = prettyLogger.log({
101
+ fiberId: FiberId.none,
102
+ logLevel: channel === 'stdout' ? LogLevel.Info : LogLevel.Warning,
103
+ message: [`[${channel}]${content.length > 0 ? ` ${content}` : ''}`],
104
+ cause: Cause.empty,
105
+ context: FiberRefs.empty(),
106
+ spans: List.empty(),
107
+ annotations: HashMap.empty(),
108
+ date: new Date(),
109
+ });
110
+ fs.writeSync(logFile, formatted);
111
+ });
112
+ const command = buildCommand(commandInput, useShell).pipe(Command.stdin('inherit'), Command.stdout('pipe'), Command.stderr('pipe'), Command.workingDirectory(cwd), useShell ? Command.runInShell(true) : identity, Command.env(envWithColor));
113
+ // Acquire/start the command and make sure we kill it on interruption.
114
+ const runningProcess = yield* Effect.acquireRelease(command.pipe(Command.start), (proc) => proc.isRunning.pipe(Effect.flatMap((running) => (running ? proc.kill().pipe(Effect.catchAll(() => Effect.void)) : Effect.void)), Effect.ignore));
115
+ const stdoutHandler = makeStreamHandler({
116
+ channel: 'stdout',
117
+ ...(stdoutMode === 'inherit' ? { mirrorTarget: process.stdout } : {}),
118
+ appendLog,
119
+ });
120
+ const stderrHandler = makeStreamHandler({
121
+ channel: 'stderr',
122
+ ...(stderrMode === 'inherit' ? { mirrorTarget: process.stderr } : {}),
123
+ appendLog,
124
+ });
125
+ const stdoutFiber = yield* runningProcess.stdout.pipe(Stream.decodeText('utf8'), Stream.runForEach((chunk) => stdoutHandler.onChunk(chunk)), Effect.forkScoped);
126
+ const stderrFiber = yield* runningProcess.stderr.pipe(Stream.decodeText('utf8'), Stream.runForEach((chunk) => stderrHandler.onChunk(chunk)), Effect.forkScoped);
127
+ // Dump any buffered data and finish both stream fibers before we return.
128
+ const flushOutputs = Effect.gen(function* () {
129
+ const stillRunning = yield* runningProcess.isRunning.pipe(Effect.catchAll(() => Effect.succeed(false)));
130
+ if (stillRunning) {
131
+ yield* Effect.ignore(runningProcess.kill());
132
+ }
133
+ yield* Effect.ignore(Fiber.join(stdoutFiber));
134
+ yield* Effect.ignore(Fiber.join(stderrFiber));
135
+ yield* stdoutHandler.flush();
136
+ yield* stderrHandler.flush();
137
+ });
138
+ const exitCode = yield* runningProcess.exitCode.pipe(Effect.ensuring(flushOutputs));
139
+ return exitCode;
140
+ }));
141
+ const buildCommand = (input, useShell) => {
142
+ if (Array.isArray(input)) {
143
+ const [c, ...a] = input;
144
+ return Command.make(c, ...a);
145
+ }
146
+ if (useShell) {
147
+ return Command.make(input);
148
+ }
149
+ const [c, ...a] = input.split(' ');
150
+ return Command.make(c, ...a);
151
+ };
152
+ const makeStreamHandler = ({ channel, mirrorTarget, appendLog, }) => {
153
+ let buffer = '';
154
+ // Effect's FileLogger expects line-oriented messages, but the subprocess
155
+ // gives us arbitrary UTF-8 chunks. We keep a tiny line splitter here so the
156
+ // log and console stay readable (and consistent with the previous `tee`
157
+ // behaviour).
158
+ const emit = (content, terminator) => emitSegment({
159
+ channel,
160
+ content,
161
+ terminator,
162
+ ...(mirrorTarget ? { mirrorTarget } : {}),
163
+ appendLog,
164
+ });
165
+ const consumeBuffer = () => {
166
+ if (buffer.length === 0)
167
+ return Effect.void;
168
+ const lastChar = buffer[buffer.length - 1];
169
+ if (lastChar === '\r') {
170
+ const line = buffer.slice(0, -1);
171
+ buffer = '';
172
+ return emit(line, 'carriage-return');
173
+ }
174
+ const line = buffer;
175
+ buffer = '';
176
+ return line.length === 0 ? Effect.void : emit(line, 'none');
177
+ };
178
+ return {
179
+ onChunk: (chunk) => Effect.gen(function* () {
180
+ buffer += chunk;
181
+ while (buffer.length > 0) {
182
+ const newlineIndex = buffer.indexOf('\n');
183
+ const carriageIndex = buffer.indexOf('\r');
184
+ if (newlineIndex === -1 && carriageIndex === -1) {
185
+ break;
186
+ }
187
+ let index;
188
+ let terminator;
189
+ let skip = 1;
190
+ if (carriageIndex !== -1 && (newlineIndex === -1 || carriageIndex < newlineIndex)) {
191
+ index = carriageIndex;
192
+ if (carriageIndex + 1 < buffer.length && buffer[carriageIndex + 1] === '\n') {
193
+ skip = 2;
194
+ terminator = 'newline';
195
+ }
196
+ else {
197
+ terminator = 'carriage-return';
198
+ }
199
+ }
200
+ else {
201
+ index = newlineIndex;
202
+ terminator = 'newline';
203
+ }
204
+ const line = buffer.slice(0, index);
205
+ buffer = buffer.slice(index + skip);
206
+ yield* emit(line, terminator);
207
+ }
208
+ }),
209
+ flush: () => consumeBuffer(),
210
+ };
211
+ };
212
+ const emitSegment = ({ channel, content, terminator, mirrorTarget, appendLog, }) => Effect.gen(function* () {
213
+ if (mirrorTarget) {
214
+ yield* Effect.sync(() => mirrorSegment(mirrorTarget, content, terminator));
215
+ }
216
+ const contentForLog = terminator === 'carriage-return' ? `${content}\r` : content;
217
+ yield* appendLog({ channel, content: contentForLog });
218
+ });
219
+ const mirrorSegment = (target, content, terminator) => {
220
+ switch (terminator) {
221
+ case 'newline': {
222
+ target.write(`${content}\n`);
223
+ break;
224
+ }
225
+ case 'carriage-return': {
226
+ target.write(`${content}\r`);
227
+ break;
228
+ }
229
+ case 'none': {
230
+ target.write(content);
231
+ break;
232
+ }
233
+ }
234
+ };
235
+ //# sourceMappingURL=cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cmd.js","sourceRoot":"","sources":["../../src/node/cmd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cmd.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cmd.test.d.ts","sourceRoot":"","sources":["../../src/node/cmd.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { CommandExecutor, Duration, Effect, Layer } from '@livestore/utils/effect';
4
+ import { PlatformNode } from '@livestore/utils/node';
5
+ import { Vitest } from '@livestore/utils-dev/node-vitest';
6
+ import { expect } from 'vitest';
7
+ import { cmd } from "./cmd.js";
8
+ import { CurrentWorkingDirectory } from "./workspace.js";
9
+ const withNode = Vitest.makeWithTestCtx({
10
+ makeLayer: () => Layer.mergeAll(PlatformNode.NodeContext.layer, CurrentWorkingDirectory.live),
11
+ timeout: 20_000,
12
+ });
13
+ Vitest.describe('cmd helper', () => {
14
+ const ansiRegex = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, 'g');
15
+ Vitest.scopedLive('runs tokenized string without shell', (test) => Effect.gen(function* () {
16
+ const exit = yield* cmd('printf ok');
17
+ expect(exit).toBe(CommandExecutor.ExitCode(0));
18
+ }).pipe(withNode(test)));
19
+ Vitest.scopedLive('runs array input', (test) => Effect.gen(function* () {
20
+ const exit = yield* cmd(['printf', 'ok']);
21
+ expect(exit).toBe(CommandExecutor.ExitCode(0));
22
+ }).pipe(withNode(test)));
23
+ Vitest.scopedLive('supports logging with archive + retention', (test) => Effect.gen(function* () {
24
+ const workspace = process.env.WORKSPACE_ROOT;
25
+ const logsDir = path.join(workspace, 'tmp', 'cmd-tests', String(Date.now()));
26
+ // first run
27
+ const exit1 = yield* cmd('printf first', { logDir: logsDir });
28
+ expect(exit1).toBe(CommandExecutor.ExitCode(0));
29
+ const current = path.join(logsDir, 'dev.log');
30
+ expect(fs.existsSync(current)).toBe(true);
31
+ const firstLog = fs.readFileSync(current, 'utf8');
32
+ const firstStdoutLines = firstLog.split('\n').filter((line) => line.includes('[stdout]'));
33
+ expect(firstStdoutLines.length).toBeGreaterThan(0);
34
+ for (const line of firstStdoutLines) {
35
+ expect(line).toContain('[stdout] first');
36
+ expect(line).toContain('INFO');
37
+ expect(line).toContain('printf first');
38
+ }
39
+ // second run — archives previous
40
+ const exit2 = yield* cmd('printf second', { logDir: logsDir });
41
+ expect(exit2).toBe(CommandExecutor.ExitCode(0));
42
+ const archiveDir = path.join(logsDir, 'archive');
43
+ const archives = fs.readdirSync(archiveDir).filter((f) => f.endsWith('.log'));
44
+ expect(archives.length).toBe(1);
45
+ const archivedPath = path.join(archiveDir, archives[0]);
46
+ const archivedLog = fs.readFileSync(archivedPath, 'utf8');
47
+ const archivedStdoutLines = archivedLog.split('\n').filter((line) => line.includes('[stdout]'));
48
+ expect(archivedStdoutLines.length).toBeGreaterThan(0);
49
+ for (const line of archivedStdoutLines) {
50
+ expect(line).toContain('[stdout] first');
51
+ }
52
+ const secondLog = fs.readFileSync(current, 'utf8');
53
+ const secondStdoutLines = secondLog.split('\n').filter((line) => line.includes('[stdout]'));
54
+ expect(secondStdoutLines.length).toBeGreaterThan(0);
55
+ for (const line of secondStdoutLines) {
56
+ expect(line).toContain('[stdout] second');
57
+ expect(line).toContain('INFO');
58
+ }
59
+ // generate many archives to exercise retention (keep 50)
60
+ for (let i = 0; i < 60; i++) {
61
+ // Use small unique payloads
62
+ yield* cmd(['printf', String(i)], { logDir: logsDir });
63
+ }
64
+ const archivesAfter = fs.readdirSync(archiveDir).filter((f) => f.endsWith('.log'));
65
+ expect(archivesAfter.length).toBeLessThanOrEqual(50);
66
+ }).pipe(withNode(test)));
67
+ Vitest.scopedLive('streams stdout and stderr with logger formatting', (test) => Effect.gen(function* () {
68
+ const workspace = process.env.WORKSPACE_ROOT;
69
+ const logsDir = path.join(workspace, 'tmp', 'cmd-tests', `format-${Date.now()}`);
70
+ const exit = yield* cmd(['node', '-e', "console.log('out'); console.error('err')"], {
71
+ logDir: logsDir,
72
+ });
73
+ expect(exit).toBe(CommandExecutor.ExitCode(0));
74
+ const current = path.join(logsDir, 'dev.log');
75
+ const logContent = fs.readFileSync(current, 'utf8');
76
+ expect(logContent).toMatch(/\[stdout] out/);
77
+ expect(logContent).toMatch(/\[stderr] err/);
78
+ const relevantLines = logContent
79
+ .split('\n')
80
+ .map((line) => line.trim())
81
+ .filter((line) => line.includes('[stdout]') || line.includes('[stderr]'));
82
+ expect(relevantLines.length).toBeGreaterThanOrEqual(2);
83
+ for (const line of relevantLines) {
84
+ const stripped = line.replace(ansiRegex, '');
85
+ expect(stripped.startsWith('[')).toBe(true);
86
+ expect(stripped).toMatch(/(INFO|WARN)/);
87
+ expect(stripped).toMatch(/\[(stdout|stderr)]/);
88
+ }
89
+ }).pipe(withNode(test)));
90
+ Vitest.scopedLive('cleans up logged child process when interrupted', (test) => Effect.gen(function* () {
91
+ const workspace = process.env.WORKSPACE_ROOT;
92
+ const logsDir = path.join(workspace, 'tmp', 'cmd-tests', `timeout-${Date.now()}`);
93
+ const result = yield* cmd(['node', '-e', 'setTimeout(() => {}, 5000)'], {
94
+ logDir: logsDir,
95
+ stdout: 'pipe',
96
+ stderr: 'pipe',
97
+ }).pipe(Effect.timeoutOption(Duration.millis(200)));
98
+ expect(result._tag).toBe('None');
99
+ expect(fs.existsSync(path.join(logsDir, 'dev.log'))).toBe(true);
100
+ }).pipe(withNode(test)));
101
+ });
102
+ //# sourceMappingURL=cmd.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cmd.test.js","sourceRoot":"","sources":["../../src/node/cmd.test.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,12 @@
1
- import type { CommandExecutor, PlatformError, Tracer } from '@livestore/utils/effect';
2
- import { Effect, Layer, OtelTracer, Schema } from '@livestore/utils/effect';
1
+ import type { Tracer } from '@livestore/utils/effect';
2
+ import { Effect, Layer, OtelTracer } from '@livestore/utils/effect';
3
3
  import * as otel from '@opentelemetry/api';
4
4
  export { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
5
5
  export { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
6
+ export * from './cmd.ts';
7
+ export { type DockerComposeArgs, DockerComposeError, type DockerComposeOperations, DockerComposeService, type LogsOptions, type StartOptions, startDockerComposeServicesScoped, } from './DockerComposeService/DockerComposeService.ts';
6
8
  export * as FileLogger from './FileLogger.ts';
9
+ export * from './workspace.ts';
7
10
  export declare const OtelLiveHttp: ({ serviceName, rootSpanName, rootSpanAttributes, parentSpan, skipLogUrl, traceNodeBootstrap, }?: {
8
11
  serviceName?: string;
9
12
  rootSpanName?: string;
@@ -14,28 +17,4 @@ export declare const OtelLiveHttp: ({ serviceName, rootSpanName, rootSpanAttribu
14
17
  }) => Layer.Layer<OtelTracer.OtelTracer | Tracer.ParentSpan, never, never>;
15
18
  export declare const logTraceUiUrlForSpan: (printMsg?: (url: string) => string) => (span: otel.Span) => Effect.Effect<string | undefined, never, never>;
16
19
  export declare const getTracingBackendUrl: (span: otel.Span) => Effect.Effect<string | undefined, never, never>;
17
- export declare const cmd: (commandInput: string | (string | undefined)[], options?: {
18
- cwd?: string;
19
- stderr?: 'inherit' | 'pipe';
20
- stdout?: 'inherit' | 'pipe';
21
- shell?: boolean;
22
- env?: Record<string, string | undefined>;
23
- } | undefined) => Effect.Effect<CommandExecutor.ExitCode, PlatformError.PlatformError | CmdError, CommandExecutor.CommandExecutor>;
24
- export declare const cmdText: (commandInput: string | (string | undefined)[], options?: {
25
- cwd?: string;
26
- stderr?: 'inherit' | 'pipe';
27
- runInShell?: boolean;
28
- env?: Record<string, string | undefined>;
29
- }) => Effect.Effect<string, PlatformError.PlatformError, CommandExecutor.CommandExecutor>;
30
- declare const CmdError_base: Schema.TaggedErrorClass<CmdError, "CmdError", {
31
- readonly _tag: Schema.tag<"CmdError">;
32
- } & {
33
- command: typeof Schema.String;
34
- args: Schema.Array$<typeof Schema.String>;
35
- cwd: typeof Schema.String;
36
- env: Schema.Record$<typeof Schema.String, Schema.UndefinedOr<typeof Schema.String>>;
37
- stderr: Schema.Literal<["inherit", "pipe"]>;
38
- }>;
39
- export declare class CmdError extends CmdError_base {
40
- }
41
20
  //# sourceMappingURL=mod.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/node/mod.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AACrF,OAAO,EAGL,MAAM,EAGN,KAAK,EAEL,UAAU,EACV,MAAM,EACP,MAAM,yBAAyB,CAAA;AAEhC,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAM1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAA;AAE3E,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAE7C,eAAO,MAAM,YAAY,GAAI,iGAO1B;IACD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,OAAO,CAAA;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CACxB,KAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CA0FxC,CAAA;AAEpC,eAAO,MAAM,oBAAoB,GAAI,WAAW,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,MAAM,MAAM,IAAI,CAAC,IAAI,oDAazF,CAAA;AAEH,eAAO,MAAM,oBAAoB,GAAI,MAAM,IAAI,CAAC,IAAI,oDAqBhD,CAAA;AAEJ,eAAO,MAAM,GAAG,EAAE,CAChB,YAAY,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EAC7C,OAAO,CAAC,EACJ;IACE,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IAC3B,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CACzC,GACD,SAAS,KACV,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,GAAG,QAAQ,EAAE,eAAe,CAAC,eAAe,CAyChH,CAAA;AAEJ,eAAO,MAAM,OAAO,EAAE,CACpB,YAAY,EAAE,MAAM,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,EAC7C,OAAO,CAAC,EAAE;IACR,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CACzC,KACE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,aAAa,EAAE,eAAe,CAAC,eAAe,CAyBtF,CAAA;;;;;;;;;;AAED,qBAAa,QAAS,SAAQ,aAM5B;CAAG"}
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../../src/node/mod.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AACrD,OAAO,EAAU,MAAM,EAAY,KAAK,EAAY,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAE/F,OAAO,KAAK,IAAI,MAAM,oBAAoB,CAAA;AAM1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2CAA2C,CAAA;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAA;AAC3E,cAAc,UAAU,CAAA;AACxB,OAAO,EACL,KAAK,iBAAiB,EACtB,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,oBAAoB,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,gCAAgC,GACjC,MAAM,gDAAgD,CAAA;AACvD,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAA;AAC7C,cAAc,gBAAgB,CAAA;AAE9B,eAAO,MAAM,YAAY,GAAI,iGAO1B;IACD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC,OAAO,CAAA;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5C,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,kBAAkB,CAAC,EAAE,OAAO,CAAA;CACxB,KAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,CAuFxC,CAAA;AAEpC,eAAO,MAAM,oBAAoB,GAAI,WAAW,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,MAAM,MAAM,IAAI,CAAC,IAAI,oDAazF,CAAA;AAEH,eAAO,MAAM,oBAAoB,GAAI,MAAM,IAAI,CAAC,IAAI,oDAqBhD,CAAA"}
package/dist/node/mod.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { performance } from 'node:perf_hooks';
2
2
  import * as OtelNodeSdk from '@effect/opentelemetry/NodeSdk';
3
- import { IS_BUN, isNonEmptyString, isNotUndefined, shouldNeverHappen } from '@livestore/utils';
4
- import { Command, Config, Effect, FiberRef, identity, Layer, LogLevel, OtelTracer, Schema, } from '@livestore/utils/effect';
3
+ import { IS_BUN, isNonEmptyString } from '@livestore/utils';
4
+ import { Config, Effect, FiberRef, Layer, LogLevel, OtelTracer } from '@livestore/utils/effect';
5
5
  import { OtelLiveDummy } from '@livestore/utils/node';
6
6
  import * as otel from '@opentelemetry/api';
7
7
  import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
@@ -10,7 +10,10 @@ import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
10
10
  import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
11
11
  export { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
12
12
  export { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
13
+ export * from "./cmd.js";
14
+ export { DockerComposeError, DockerComposeService, startDockerComposeServicesScoped, } from "./DockerComposeService/DockerComposeService.js";
13
15
  export * as FileLogger from "./FileLogger.js";
16
+ export * from "./workspace.js";
14
17
  export const OtelLiveHttp = ({ serviceName, rootSpanName, rootSpanAttributes, parentSpan, skipLogUrl, traceNodeBootstrap, } = {}) => Effect.gen(function* () {
15
18
  const configRes = yield* Config.all({
16
19
  exporterUrl: Config.string('OTEL_EXPORTER_OTLP_ENDPOINT').pipe(Config.validate({ message: 'OTEL_EXPORTER_OTLP_ENDPOINT must be set', validation: isNonEmptyString })),
@@ -60,9 +63,7 @@ export const OtelLiveHttp = ({ serviceName, rootSpanName, rootSpanAttributes, pa
60
63
  yield* Effect.gen(function* () {
61
64
  const tracer = yield* OtelTracer.OtelTracer;
62
65
  const currentSpan = yield* OtelTracer.currentOtelSpan;
63
- const nodeTiming = performance.nodeTiming;
64
- // TODO get rid of this workaround for Bun once Bun properly supports performance.nodeTiming
65
- const startTime = IS_BUN ? nodeTiming.startTime : performance.timeOrigin + nodeTiming.nodeStart;
66
+ const { nodeTiming, endAbs, durationAttr } = computeBootstrapTiming();
66
67
  const bootSpan = tracer.startSpan('node-bootstrap', {
67
68
  startTime: nodeTiming.nodeStart,
68
69
  attributes: {
@@ -70,10 +71,10 @@ export const OtelLiveHttp = ({ serviceName, rootSpanName, rootSpanAttributes, pa
70
71
  'node.timing.environment': nodeTiming.environment,
71
72
  'node.timing.bootstrapComplete': nodeTiming.bootstrapComplete,
72
73
  'node.timing.loopStart': nodeTiming.loopStart,
73
- 'node.timing.duration': nodeTiming.duration,
74
+ 'node.timing.duration': durationAttr,
74
75
  },
75
76
  }, otel.trace.setSpanContext(otel.context.active(), currentSpan.spanContext()));
76
- bootSpan.end(startTime + nodeTiming.duration);
77
+ bootSpan.end(endAbs);
77
78
  }).pipe(Effect.provide(layer), Effect.orDie);
78
79
  }
79
80
  return layer;
@@ -109,56 +110,48 @@ export const getTracingBackendUrl = (span) => Effect.gen(function* () {
109
110
  // TODO make dynamic via env var
110
111
  return `${grafanaEndpoint}/explore?${searchParams.toString()}`;
111
112
  });
112
- export const cmd = Effect.fn('cmd')(function* (commandInput, options) {
113
- const cwd = options?.cwd ?? process.env.WORKSPACE_ROOT ?? shouldNeverHappen('WORKSPACE_ROOT is not set');
114
- const [command, ...args] = Array.isArray(commandInput)
115
- ? commandInput.filter(isNotUndefined)
116
- : commandInput.split(' ');
117
- const debugEnvStr = Object.entries(options?.env ?? {})
118
- .map(([key, value]) => `${key}='${value}' `)
119
- .join('');
120
- const subshellStr = options?.shell ? ' (in subshell)' : '';
121
- const commandDebugStr = debugEnvStr + [command, ...args].join(' ');
122
- yield* Effect.logDebug(`Running '${commandDebugStr}' in '${cwd}'${subshellStr}`);
123
- yield* Effect.annotateCurrentSpan({ 'span.label': commandDebugStr, cwd, command, args });
124
- return yield* Command.make(command, ...args).pipe(
125
- // TODO don't forward abort signal to the command
126
- Command.stdin('inherit'), // Forward stdin to the command
127
- // inherit = Stream stdout to process.stdout, pipe = Stream stdout to process.stderr
128
- Command.stdout(options?.stdout ?? 'inherit'),
129
- // inherit = Stream stderr to process.stderr, pipe = Stream stderr to process.stdout
130
- Command.stderr(options?.stderr ?? 'inherit'), Command.workingDirectory(cwd), options?.shell ? Command.runInShell(true) : identity, Command.env(options?.env ?? {}), Command.exitCode, Effect.tap((exitCode) => exitCode === 0
131
- ? Effect.void
132
- : Effect.fail(CmdError.make({
133
- command: command,
134
- args,
135
- cwd,
136
- env: options?.env ?? {},
137
- stderr: options?.stderr ?? 'inherit',
138
- }))));
139
- });
140
- export const cmdText = Effect.fn('cmdText')(function* (commandInput, options) {
141
- const cwd = options?.cwd ?? process.env.WORKSPACE_ROOT ?? shouldNeverHappen('WORKSPACE_ROOT is not set');
142
- const [command, ...args] = Array.isArray(commandInput)
143
- ? commandInput.filter(isNotUndefined)
144
- : commandInput.split(' ');
145
- const debugEnvStr = Object.entries(options?.env ?? {})
146
- .map(([key, value]) => `${key}='${value}' `)
147
- .join('');
148
- const commandDebugStr = debugEnvStr + [command, ...args].join(' ');
149
- const subshellStr = options?.runInShell ? ' (in subshell)' : '';
150
- yield* Effect.logDebug(`Running '${commandDebugStr}' in '${cwd}'${subshellStr}`);
151
- yield* Effect.annotateCurrentSpan({ 'span.label': commandDebugStr, command, cwd });
152
- return yield* Command.make(command, ...args).pipe(
153
- // inherit = Stream stderr to process.stderr, pipe = Stream stderr to process.stdout
154
- Command.stderr(options?.stderr ?? 'inherit'), Command.workingDirectory(cwd), options?.runInShell ? Command.runInShell(true) : identity, Command.env(options?.env ?? {}), Command.string);
155
- });
156
- export class CmdError extends Schema.TaggedError()('CmdError', {
157
- command: Schema.String,
158
- args: Schema.Array(Schema.String),
159
- cwd: Schema.String,
160
- env: Schema.Record({ key: Schema.String, value: Schema.String.pipe(Schema.UndefinedOr) }),
161
- stderr: Schema.Literal('inherit', 'pipe'),
162
- }) {
163
- }
113
+ /**
114
+ * Compute absolute start/end timestamps for the Node.js bootstrap span in a
115
+ * way that works in both Node and Bun.
116
+ *
117
+ * Context: Bun's perf_hooks PerformanceNodeTiming currently throws when
118
+ * accessing standard PerformanceEntry getters like `startTime` and
119
+ * `duration`, and some fields differ in semantics (e.g. `nodeStart` appears
120
+ * as an epoch timestamp rather than an offset). See:
121
+ * https://github.com/oven-sh/bun/issues/23041
122
+ *
123
+ * We therefore avoid the problematic getters and derive absolute timestamps
124
+ * using fields that exist in both runtimes.
125
+ *
126
+ * TODO: Simplify to a single, non-branching computation once the Bun issue
127
+ * above is fixed and Bun matches Node's semantics for PerformanceNodeTiming.
128
+ */
129
+ const computeBootstrapTiming = () => {
130
+ const nodeTiming = performance.nodeTiming;
131
+ // Absolute start time in ms since epoch.
132
+ const startAbs = IS_BUN
133
+ ? typeof nodeTiming.nodeStart === 'number'
134
+ ? nodeTiming.nodeStart
135
+ : performance.timeOrigin
136
+ : performance.timeOrigin + nodeTiming.nodeStart;
137
+ // Absolute end time.
138
+ const endAbs = IS_BUN
139
+ ? (() => {
140
+ const { loopStart, bootstrapComplete } = nodeTiming;
141
+ if (typeof loopStart === 'number' && loopStart > 0)
142
+ return startAbs + loopStart;
143
+ if (typeof bootstrapComplete === 'number' && bootstrapComplete >= startAbs)
144
+ return bootstrapComplete;
145
+ return startAbs + 1;
146
+ })()
147
+ : startAbs + nodeTiming.duration;
148
+ // Duration attribute value for the span.
149
+ const durationAttr = IS_BUN
150
+ ? (() => {
151
+ const { loopStart } = nodeTiming;
152
+ return typeof loopStart === 'number' && loopStart > 0 ? loopStart : 0;
153
+ })()
154
+ : nodeTiming.duration;
155
+ return { nodeTiming, startAbs, endAbs, durationAttr };
156
+ };
164
157
  //# sourceMappingURL=mod.js.map