@opencode-ai/util 0.0.0-bootstrap.0 → 0.0.0-next-15992
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/dist/cross-spawn-spawner.d.ts +3 -0
- package/dist/cross-spawn-spawner.js +403 -0
- package/dist/effect/app-node-platform.d.ts +6 -0
- package/dist/effect/app-node-platform.js +8 -0
- package/dist/effect/app-node.d.ts +50 -0
- package/dist/effect/app-node.js +8 -0
- package/dist/effect/layer-node.d.ts +79 -0
- package/dist/effect/layer-node.js +181 -0
- package/dist/effect/memo-map.d.ts +2 -0
- package/dist/effect/memo-map.js +2 -0
- package/dist/effect/runtime.d.ts +8 -0
- package/dist/effect/runtime.js +16 -0
- package/dist/effect/service-use.d.ts +7 -0
- package/dist/effect/service-use.js +27 -0
- package/dist/effect-flock.d.ts +31 -0
- package/dist/effect-flock.js +185 -0
- package/dist/flock.d.ts +30 -0
- package/dist/flock.js +273 -0
- package/dist/fs-util.d.ts +139 -0
- package/dist/fs-util.js +224 -0
- package/dist/glob.d.ts +12 -0
- package/dist/glob.js +26 -0
- package/dist/global.d.ts +30 -0
- package/dist/global.js +57 -0
- package/dist/hash.d.ts +4 -0
- package/dist/hash.js +12 -0
- package/dist/npm-config.d.ts +4 -0
- package/dist/npm-config.js +32 -0
- package/dist/npm.d.ts +35 -0
- package/dist/npm.js +207 -0
- package/dist/observability/logging.d.ts +6 -0
- package/dist/observability/logging.js +67 -0
- package/dist/observability/otlp.d.ts +18 -0
- package/dist/observability/otlp.js +73 -0
- package/dist/observability/shared.d.ts +1 -0
- package/dist/observability/shared.js +1 -0
- package/dist/observability.d.ts +13 -0
- package/dist/observability.js +31 -0
- package/dist/patch.d.ts +42 -0
- package/dist/patch.js +206 -0
- package/dist/process.d.ts +54 -0
- package/dist/process.js +162 -0
- package/dist/runtime/import.bun.d.ts +2 -0
- package/dist/runtime/import.bun.js +6 -0
- package/dist/runtime/import.node.d.ts +2 -0
- package/dist/runtime/import.node.js +36 -0
- package/dist/runtime-import.d.ts +1 -0
- package/dist/runtime-import.js +1 -0
- package/package.json +56 -7
- package/index.js +0 -1
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner";
|
|
2
|
+
export declare const node: import("./effect/layer-node.js").Node<ChildProcessSpawner, never, import("./effect/layer-node.js").Tag<"global">>;
|
|
3
|
+
export * as CrossSpawnSpawner from "./cross-spawn-spawner.js";
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { NodeFileSystem, NodePath, NodeSink, NodeStream } from "@effect/platform-node";
|
|
2
|
+
import { Deferred, Effect, Exit, FileSystem, Layer, Path, PlatformError, Predicate, Sink, Stream } from "effect";
|
|
3
|
+
import { ChildProcess } from "effect/unstable/process";
|
|
4
|
+
import { ChildProcessSpawner, ExitCode, make, makeHandle, ProcessId, } from "effect/unstable/process/ChildProcessSpawner";
|
|
5
|
+
// ast-grep-ignore: no-star-import
|
|
6
|
+
import * as NodeChildProcess from "node:child_process";
|
|
7
|
+
import { PassThrough } from "node:stream";
|
|
8
|
+
import launch from "cross-spawn";
|
|
9
|
+
import { makeGlobalNode } from "./effect/app-node.js";
|
|
10
|
+
import { filesystem, path } from "./effect/app-node-platform.js";
|
|
11
|
+
const toError = (err) => (err instanceof globalThis.Error ? err : new globalThis.Error(String(err)));
|
|
12
|
+
const toTag = (err) => {
|
|
13
|
+
switch (err.code) {
|
|
14
|
+
case "ENOENT":
|
|
15
|
+
return "NotFound";
|
|
16
|
+
case "EACCES":
|
|
17
|
+
return "PermissionDenied";
|
|
18
|
+
case "EEXIST":
|
|
19
|
+
return "AlreadyExists";
|
|
20
|
+
case "EISDIR":
|
|
21
|
+
return "BadResource";
|
|
22
|
+
case "ENOTDIR":
|
|
23
|
+
return "BadResource";
|
|
24
|
+
case "EBUSY":
|
|
25
|
+
return "Busy";
|
|
26
|
+
case "ELOOP":
|
|
27
|
+
return "BadResource";
|
|
28
|
+
default:
|
|
29
|
+
return "Unknown";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const flatten = (command) => {
|
|
33
|
+
const commands = [];
|
|
34
|
+
const opts = [];
|
|
35
|
+
const walk = (cmd) => {
|
|
36
|
+
switch (cmd._tag) {
|
|
37
|
+
case "StandardCommand":
|
|
38
|
+
commands.push(cmd);
|
|
39
|
+
return;
|
|
40
|
+
case "PipedCommand":
|
|
41
|
+
walk(cmd.left);
|
|
42
|
+
opts.push(cmd.options);
|
|
43
|
+
walk(cmd.right);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
walk(command);
|
|
48
|
+
if (commands.length === 0)
|
|
49
|
+
throw new Error("flatten produced empty commands array");
|
|
50
|
+
const [head, ...tail] = commands;
|
|
51
|
+
return {
|
|
52
|
+
commands: [head, ...tail],
|
|
53
|
+
opts,
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const toPlatformError = (method, err, command) => {
|
|
57
|
+
const cmd = flatten(command)
|
|
58
|
+
.commands.map((x) => `${x.command} ${x.args.join(" ")}`)
|
|
59
|
+
.join(" | ");
|
|
60
|
+
return PlatformError.systemError({
|
|
61
|
+
_tag: toTag(err),
|
|
62
|
+
module: "ChildProcess",
|
|
63
|
+
method,
|
|
64
|
+
pathOrDescriptor: cmd,
|
|
65
|
+
syscall: err.syscall,
|
|
66
|
+
cause: err,
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const makeCrossSpawnSpawner = Effect.gen(function* () {
|
|
70
|
+
const fs = yield* FileSystem.FileSystem;
|
|
71
|
+
const path = yield* Path.Path;
|
|
72
|
+
const cwd = Effect.fnUntraced(function* (opts) {
|
|
73
|
+
if (Predicate.isUndefined(opts.cwd))
|
|
74
|
+
return undefined;
|
|
75
|
+
yield* fs.access(opts.cwd);
|
|
76
|
+
return path.resolve(opts.cwd);
|
|
77
|
+
});
|
|
78
|
+
const env = (opts) => opts.extendEnv ? { ...globalThis.process.env, ...opts.env } : opts.env;
|
|
79
|
+
const input = (x) => Stream.isStream(x) ? "pipe" : x;
|
|
80
|
+
const output = (x) => Sink.isSink(x) ? "pipe" : x;
|
|
81
|
+
const stdin = (opts) => {
|
|
82
|
+
const cfg = { stream: "pipe", encoding: "utf-8", endOnDone: true };
|
|
83
|
+
if (Predicate.isUndefined(opts.stdin))
|
|
84
|
+
return cfg;
|
|
85
|
+
if (typeof opts.stdin === "string")
|
|
86
|
+
return { ...cfg, stream: opts.stdin };
|
|
87
|
+
if (Stream.isStream(opts.stdin))
|
|
88
|
+
return { ...cfg, stream: opts.stdin };
|
|
89
|
+
return {
|
|
90
|
+
stream: opts.stdin.stream,
|
|
91
|
+
encoding: opts.stdin.encoding ?? cfg.encoding,
|
|
92
|
+
endOnDone: opts.stdin.endOnDone ?? cfg.endOnDone,
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const stdio = (opts, key) => {
|
|
96
|
+
const cfg = opts[key];
|
|
97
|
+
if (Predicate.isUndefined(cfg))
|
|
98
|
+
return { stream: "pipe" };
|
|
99
|
+
if (typeof cfg === "string")
|
|
100
|
+
return { stream: cfg };
|
|
101
|
+
if (Sink.isSink(cfg))
|
|
102
|
+
return { stream: cfg };
|
|
103
|
+
return { stream: cfg.stream };
|
|
104
|
+
};
|
|
105
|
+
const fds = (opts) => {
|
|
106
|
+
if (Predicate.isUndefined(opts.additionalFds))
|
|
107
|
+
return [];
|
|
108
|
+
return Object.entries(opts.additionalFds)
|
|
109
|
+
.flatMap(([name, config]) => {
|
|
110
|
+
const fd = ChildProcess.parseFdName(name);
|
|
111
|
+
return Predicate.isUndefined(fd) ? [] : [{ fd, config }];
|
|
112
|
+
})
|
|
113
|
+
.toSorted((a, b) => a.fd - b.fd);
|
|
114
|
+
};
|
|
115
|
+
const stdios = (sin, sout, serr, extra) => {
|
|
116
|
+
const pipe = (x) => process.platform === "win32" && x === "pipe" ? "overlapped" : x;
|
|
117
|
+
const arr = [
|
|
118
|
+
pipe(input(sin.stream)),
|
|
119
|
+
pipe(output(sout.stream)),
|
|
120
|
+
pipe(output(serr.stream)),
|
|
121
|
+
];
|
|
122
|
+
if (extra.length === 0)
|
|
123
|
+
return arr;
|
|
124
|
+
const max = extra.reduce((acc, x) => Math.max(acc, x.fd), 2);
|
|
125
|
+
for (let i = 3; i <= max; i++)
|
|
126
|
+
arr[i] = "ignore";
|
|
127
|
+
for (const x of extra)
|
|
128
|
+
arr[x.fd] = pipe("pipe");
|
|
129
|
+
return arr;
|
|
130
|
+
};
|
|
131
|
+
const setupFds = Effect.fnUntraced(function* (command, proc, extra) {
|
|
132
|
+
if (extra.length === 0) {
|
|
133
|
+
return {
|
|
134
|
+
getInputFd: () => Sink.drain,
|
|
135
|
+
getOutputFd: () => Stream.empty,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const ins = new Map();
|
|
139
|
+
const outs = new Map();
|
|
140
|
+
for (const x of extra) {
|
|
141
|
+
const node = proc.stdio[x.fd];
|
|
142
|
+
switch (x.config.type) {
|
|
143
|
+
case "input": {
|
|
144
|
+
let sink = Sink.drain;
|
|
145
|
+
if (node && "write" in node) {
|
|
146
|
+
sink = NodeSink.fromWritable({
|
|
147
|
+
evaluate: () => node,
|
|
148
|
+
onError: (err) => toPlatformError(`fromWritable(fd${x.fd})`, toError(err), command),
|
|
149
|
+
endOnDone: true,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
if (x.config.stream)
|
|
153
|
+
yield* Effect.forkScoped(Stream.run(x.config.stream, sink));
|
|
154
|
+
ins.set(x.fd, sink);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case "output": {
|
|
158
|
+
let stream = Stream.empty;
|
|
159
|
+
if (node && "read" in node) {
|
|
160
|
+
const tap = new PassThrough();
|
|
161
|
+
node.on("error", (err) => tap.destroy(toError(err)));
|
|
162
|
+
node.pipe(tap);
|
|
163
|
+
stream = NodeStream.fromReadable({
|
|
164
|
+
evaluate: () => tap,
|
|
165
|
+
onError: (err) => toPlatformError(`fromReadable(fd${x.fd})`, toError(err), command),
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (x.config.sink)
|
|
169
|
+
stream = Stream.transduce(stream, x.config.sink);
|
|
170
|
+
outs.set(x.fd, stream);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return {
|
|
176
|
+
getInputFd: (fd) => ins.get(fd) ?? Sink.drain,
|
|
177
|
+
getOutputFd: (fd) => outs.get(fd) ?? Stream.empty,
|
|
178
|
+
};
|
|
179
|
+
});
|
|
180
|
+
const setupStdin = (command, proc, cfg) => Effect.suspend(() => {
|
|
181
|
+
let sink = Sink.drain;
|
|
182
|
+
if (Predicate.isNotNull(proc.stdin)) {
|
|
183
|
+
sink = NodeSink.fromWritable({
|
|
184
|
+
evaluate: () => proc.stdin,
|
|
185
|
+
onError: (err) => toPlatformError("fromWritable(stdin)", toError(err), command),
|
|
186
|
+
endOnDone: cfg.endOnDone,
|
|
187
|
+
encoding: cfg.encoding,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
if (Stream.isStream(cfg.stream))
|
|
191
|
+
return Effect.as(Effect.forkScoped(Stream.run(cfg.stream, sink)), sink);
|
|
192
|
+
return Effect.succeed(sink);
|
|
193
|
+
});
|
|
194
|
+
const setupOutput = (command, proc, out, err) => {
|
|
195
|
+
let stdout = proc.stdout
|
|
196
|
+
? NodeStream.fromReadable({
|
|
197
|
+
evaluate: () => proc.stdout,
|
|
198
|
+
onError: (cause) => toPlatformError("fromReadable(stdout)", toError(cause), command),
|
|
199
|
+
})
|
|
200
|
+
: Stream.empty;
|
|
201
|
+
let stderr = proc.stderr
|
|
202
|
+
? NodeStream.fromReadable({
|
|
203
|
+
evaluate: () => proc.stderr,
|
|
204
|
+
onError: (cause) => toPlatformError("fromReadable(stderr)", toError(cause), command),
|
|
205
|
+
})
|
|
206
|
+
: Stream.empty;
|
|
207
|
+
if (Sink.isSink(out.stream))
|
|
208
|
+
stdout = Stream.transduce(stdout, out.stream);
|
|
209
|
+
if (Sink.isSink(err.stream))
|
|
210
|
+
stderr = Stream.transduce(stderr, err.stream);
|
|
211
|
+
return { stdout, stderr, all: Stream.merge(stdout, stderr) };
|
|
212
|
+
};
|
|
213
|
+
const spawn = (command, opts) => Effect.callback((resume) => {
|
|
214
|
+
const signal = Deferred.makeUnsafe();
|
|
215
|
+
const proc = launch(command.command, command.args, opts);
|
|
216
|
+
let end = false;
|
|
217
|
+
let exit;
|
|
218
|
+
proc.on("error", (err) => {
|
|
219
|
+
resume(Effect.fail(toPlatformError("spawn", err, command)));
|
|
220
|
+
});
|
|
221
|
+
proc.on("exit", (...args) => {
|
|
222
|
+
exit = args;
|
|
223
|
+
});
|
|
224
|
+
proc.on("close", (...args) => {
|
|
225
|
+
if (end)
|
|
226
|
+
return;
|
|
227
|
+
end = true;
|
|
228
|
+
Deferred.doneUnsafe(signal, Exit.succeed(exit ?? args));
|
|
229
|
+
});
|
|
230
|
+
proc.on("spawn", () => {
|
|
231
|
+
resume(Effect.succeed([proc, signal]));
|
|
232
|
+
});
|
|
233
|
+
return Effect.sync(() => {
|
|
234
|
+
proc.kill("SIGTERM");
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
const killGroup = (command, proc, signal) => {
|
|
238
|
+
if (globalThis.process.platform === "win32") {
|
|
239
|
+
return Effect.callback((resume) => {
|
|
240
|
+
NodeChildProcess.exec(`taskkill /pid ${proc.pid} /T /F`, { windowsHide: true }, (err) => {
|
|
241
|
+
if (err)
|
|
242
|
+
return resume(Effect.fail(toPlatformError("kill", toError(err), command)));
|
|
243
|
+
resume(Effect.void);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
return Effect.try({
|
|
248
|
+
try: () => {
|
|
249
|
+
globalThis.process.kill(-proc.pid, signal);
|
|
250
|
+
},
|
|
251
|
+
catch: (err) => toPlatformError("kill", toError(err), command),
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
const killOne = (command, proc, signal) => Effect.suspend(() => {
|
|
255
|
+
if (proc.kill(signal))
|
|
256
|
+
return Effect.void;
|
|
257
|
+
return Effect.fail(toPlatformError("kill", new Error("Failed to kill child process"), command));
|
|
258
|
+
});
|
|
259
|
+
const timeout = (proc, command, opts) => (f) => {
|
|
260
|
+
const signal = opts?.killSignal ?? "SIGTERM";
|
|
261
|
+
if (Predicate.isUndefined(opts?.forceKillAfter))
|
|
262
|
+
return f(command, proc, signal);
|
|
263
|
+
return Effect.timeoutOrElse(f(command, proc, signal), {
|
|
264
|
+
duration: opts.forceKillAfter,
|
|
265
|
+
orElse: () => f(command, proc, "SIGKILL"),
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
const source = (handle, from) => {
|
|
269
|
+
const opt = from ?? "stdout";
|
|
270
|
+
switch (opt) {
|
|
271
|
+
case "stdout":
|
|
272
|
+
return handle.stdout;
|
|
273
|
+
case "stderr":
|
|
274
|
+
return handle.stderr;
|
|
275
|
+
case "all":
|
|
276
|
+
return handle.all;
|
|
277
|
+
default: {
|
|
278
|
+
const fd = ChildProcess.parseFdName(opt);
|
|
279
|
+
return Predicate.isNotUndefined(fd) ? handle.getOutputFd(fd) : handle.stdout;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const spawnCommand = Effect.fnUntraced(function* (command) {
|
|
284
|
+
switch (command._tag) {
|
|
285
|
+
case "StandardCommand": {
|
|
286
|
+
const sin = stdin(command.options);
|
|
287
|
+
const sout = stdio(command.options, "stdout");
|
|
288
|
+
const serr = stdio(command.options, "stderr");
|
|
289
|
+
const extra = fds(command.options);
|
|
290
|
+
const dir = yield* cwd(command.options);
|
|
291
|
+
const [proc, signal] = yield* Effect.acquireRelease(spawn(command, {
|
|
292
|
+
cwd: dir,
|
|
293
|
+
env: env(command.options),
|
|
294
|
+
stdio: stdios(sin, sout, serr, extra),
|
|
295
|
+
detached: command.options.detached ?? process.platform !== "win32",
|
|
296
|
+
shell: command.options.shell,
|
|
297
|
+
windowsHide: process.platform === "win32",
|
|
298
|
+
}), Effect.fnUntraced(function* ([proc, signal]) {
|
|
299
|
+
const done = yield* Deferred.isDone(signal);
|
|
300
|
+
const kill = timeout(proc, command, command.options);
|
|
301
|
+
if (done) {
|
|
302
|
+
const [code] = yield* Deferred.await(signal);
|
|
303
|
+
if (process.platform === "win32")
|
|
304
|
+
return yield* Effect.void;
|
|
305
|
+
if (code !== 0 && Predicate.isNotNull(code))
|
|
306
|
+
return yield* Effect.ignore(kill(killGroup));
|
|
307
|
+
return yield* Effect.void;
|
|
308
|
+
}
|
|
309
|
+
const send = (s) => Effect.catch(killGroup(command, proc, s), () => killOne(command, proc, s));
|
|
310
|
+
const sig = command.options.killSignal ?? "SIGTERM";
|
|
311
|
+
const attempt = send(sig).pipe(Effect.andThen(Deferred.await(signal)), Effect.asVoid);
|
|
312
|
+
const escalated = command.options.forceKillAfter
|
|
313
|
+
? Effect.timeoutOrElse(attempt, {
|
|
314
|
+
duration: command.options.forceKillAfter,
|
|
315
|
+
orElse: () => send("SIGKILL").pipe(Effect.andThen(Deferred.await(signal)), Effect.asVoid),
|
|
316
|
+
})
|
|
317
|
+
: attempt;
|
|
318
|
+
return yield* Effect.ignore(escalated);
|
|
319
|
+
}));
|
|
320
|
+
const fd = yield* setupFds(command, proc, extra);
|
|
321
|
+
const out = setupOutput(command, proc, sout, serr);
|
|
322
|
+
let ref = true;
|
|
323
|
+
return makeHandle({
|
|
324
|
+
pid: ProcessId(proc.pid),
|
|
325
|
+
stdin: yield* setupStdin(command, proc, sin),
|
|
326
|
+
stdout: out.stdout,
|
|
327
|
+
stderr: out.stderr,
|
|
328
|
+
all: out.all,
|
|
329
|
+
getInputFd: fd.getInputFd,
|
|
330
|
+
getOutputFd: fd.getOutputFd,
|
|
331
|
+
isRunning: Effect.map(Deferred.isDone(signal), (done) => !done),
|
|
332
|
+
exitCode: Effect.flatMap(Deferred.await(signal), ([code, signal]) => {
|
|
333
|
+
if (Predicate.isNotNull(code))
|
|
334
|
+
return Effect.succeed(ExitCode(code));
|
|
335
|
+
return Effect.fail(toPlatformError("exitCode", new Error(`Process interrupted due to receipt of signal: '${signal}'`), command));
|
|
336
|
+
}),
|
|
337
|
+
kill: (opts) => {
|
|
338
|
+
const sig = opts?.killSignal ?? "SIGTERM";
|
|
339
|
+
const send = (s) => Effect.catch(killGroup(command, proc, s), () => killOne(command, proc, s));
|
|
340
|
+
const attempt = send(sig).pipe(Effect.andThen(Deferred.await(signal)), Effect.asVoid);
|
|
341
|
+
if (!opts?.forceKillAfter)
|
|
342
|
+
return attempt;
|
|
343
|
+
return Effect.timeoutOrElse(attempt, {
|
|
344
|
+
duration: opts.forceKillAfter,
|
|
345
|
+
orElse: () => send("SIGKILL").pipe(Effect.andThen(Deferred.await(signal)), Effect.asVoid),
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
unref: Effect.sync(() => {
|
|
349
|
+
if (ref) {
|
|
350
|
+
proc.unref();
|
|
351
|
+
ref = false;
|
|
352
|
+
}
|
|
353
|
+
return Effect.sync(() => {
|
|
354
|
+
if (!ref) {
|
|
355
|
+
proc.ref();
|
|
356
|
+
ref = true;
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}),
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
case "PipedCommand": {
|
|
363
|
+
const flat = flatten(command);
|
|
364
|
+
const [head, ...tail] = flat.commands;
|
|
365
|
+
let handle = spawnCommand(head);
|
|
366
|
+
for (let i = 0; i < tail.length; i++) {
|
|
367
|
+
const next = tail[i];
|
|
368
|
+
const opts = flat.opts[i] ?? {};
|
|
369
|
+
const sin = stdin(next.options);
|
|
370
|
+
const stream = Stream.unwrap(Effect.map(handle, (x) => source(x, opts.from)));
|
|
371
|
+
const to = opts.to ?? "stdin";
|
|
372
|
+
if (to === "stdin") {
|
|
373
|
+
handle = spawnCommand(ChildProcess.make(next.command, next.args, {
|
|
374
|
+
...next.options,
|
|
375
|
+
stdin: { ...sin, stream },
|
|
376
|
+
}));
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
const fd = ChildProcess.parseFdName(to);
|
|
380
|
+
if (Predicate.isUndefined(fd)) {
|
|
381
|
+
handle = spawnCommand(ChildProcess.make(next.command, next.args, {
|
|
382
|
+
...next.options,
|
|
383
|
+
stdin: { ...sin, stream },
|
|
384
|
+
}));
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
handle = spawnCommand(ChildProcess.make(next.command, next.args, {
|
|
388
|
+
...next.options,
|
|
389
|
+
additionalFds: {
|
|
390
|
+
...next.options.additionalFds,
|
|
391
|
+
[ChildProcess.fdName(fd)]: { type: "input", stream },
|
|
392
|
+
},
|
|
393
|
+
}));
|
|
394
|
+
}
|
|
395
|
+
return yield* handle;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
return make(spawnCommand);
|
|
400
|
+
});
|
|
401
|
+
const layer = Layer.effect(ChildProcessSpawner, makeCrossSpawnSpawner);
|
|
402
|
+
export const node = makeGlobalNode({ service: ChildProcessSpawner, layer, deps: [filesystem, path] });
|
|
403
|
+
export * as CrossSpawnSpawner from "./cross-spawn-spawner.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { FileSystem, Path } from "effect";
|
|
2
|
+
import { HttpClient } from "effect/unstable/http";
|
|
3
|
+
export declare const filesystem: import("./layer-node.js").Node<FileSystem.FileSystem, never, import("./layer-node.js").Tag<"global">>;
|
|
4
|
+
export declare const path: import("./layer-node.js").Node<Path.Path, never, import("./layer-node.js").Tag<"global">>;
|
|
5
|
+
export declare const httpClient: import("./layer-node.js").Node<HttpClient.HttpClient, never, import("./layer-node.js").Tag<"global">>;
|
|
6
|
+
export * as LayerNodePlatform from "./app-node-platform.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { NodeFileSystem, NodePath } from "@effect/platform-node";
|
|
2
|
+
import { FileSystem, Path } from "effect";
|
|
3
|
+
import { FetchHttpClient, HttpClient } from "effect/unstable/http";
|
|
4
|
+
import { makeGlobalNode } from "./app-node.js";
|
|
5
|
+
export const filesystem = makeGlobalNode({ service: FileSystem.FileSystem, layer: NodeFileSystem.layer, deps: [] });
|
|
6
|
+
export const path = makeGlobalNode({ service: Path.Path, layer: NodePath.layer, deps: [] });
|
|
7
|
+
export const httpClient = makeGlobalNode({ service: HttpClient.HttpClient, layer: FetchHttpClient.layer, deps: [] });
|
|
8
|
+
export * as LayerNodePlatform from "./app-node-platform.js";
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { LayerNode } from "./layer-node.js";
|
|
2
|
+
export declare const tags: LayerNode.Tags<{
|
|
3
|
+
readonly location: readonly ["global"];
|
|
4
|
+
readonly global: readonly [];
|
|
5
|
+
}>;
|
|
6
|
+
export type GlobalNode<A, E = never> = LayerNode.Node<A, E, (typeof tags.values)["global"]>;
|
|
7
|
+
export type LocationNode<A, E = never> = LayerNode.Node<A, E, (typeof tags.values)["location"]>;
|
|
8
|
+
export declare const makeGlobalNode: <const Implementation extends import("effect/Layer").Any, const Items extends readonly [] | readonly [LayerNode.Node<unknown, unknown, any>, ...LayerNode.Node<unknown, unknown, any>[]]>(input: (Omit<{
|
|
9
|
+
readonly service: import("effect/Context").Service.Any;
|
|
10
|
+
readonly name?: never;
|
|
11
|
+
} & {
|
|
12
|
+
readonly layer: Implementation;
|
|
13
|
+
readonly deps: Items & ([Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>] extends [never] ? unknown : {
|
|
14
|
+
readonly "Missing dependencies": Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>;
|
|
15
|
+
});
|
|
16
|
+
readonly tag?: LayerNode.Tag<"global"> | undefined;
|
|
17
|
+
}, "tag"> | Omit<{
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly service?: never;
|
|
20
|
+
} & {
|
|
21
|
+
readonly layer: Implementation;
|
|
22
|
+
readonly deps: Items & ([Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>] extends [never] ? unknown : {
|
|
23
|
+
readonly "Missing dependencies": Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>;
|
|
24
|
+
});
|
|
25
|
+
readonly tag?: LayerNode.Tag<"global"> | undefined;
|
|
26
|
+
}, "tag">) & ([Exclude<Items[number], LayerNode.Node<unknown, unknown, LayerNode.Tag<"global"> | undefined>>] extends [never] ? unknown : {
|
|
27
|
+
readonly "Invalid tag dependencies": Exclude<Items[number], LayerNode.Node<unknown, unknown, LayerNode.Tag<"global"> | undefined>>;
|
|
28
|
+
})) => LayerNode.Node<import("effect/Layer").Success<Implementation>, import("effect/Layer").Error<Implementation> | LayerNode.Error<Items[number]>, LayerNode.Tag<"global">>;
|
|
29
|
+
export declare const makeLocationNode: <const Implementation extends import("effect/Layer").Any, const Items extends readonly [] | readonly [LayerNode.Node<unknown, unknown, any>, ...LayerNode.Node<unknown, unknown, any>[]]>(input: (Omit<{
|
|
30
|
+
readonly service: import("effect/Context").Service.Any;
|
|
31
|
+
readonly name?: never;
|
|
32
|
+
} & {
|
|
33
|
+
readonly layer: Implementation;
|
|
34
|
+
readonly deps: Items & ([Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>] extends [never] ? unknown : {
|
|
35
|
+
readonly "Missing dependencies": Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>;
|
|
36
|
+
});
|
|
37
|
+
readonly tag?: LayerNode.Tag<"location"> | undefined;
|
|
38
|
+
}, "tag"> | Omit<{
|
|
39
|
+
readonly name: string;
|
|
40
|
+
readonly service?: never;
|
|
41
|
+
} & {
|
|
42
|
+
readonly layer: Implementation;
|
|
43
|
+
readonly deps: Items & ([Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>] extends [never] ? unknown : {
|
|
44
|
+
readonly "Missing dependencies": Exclude<import("effect/Layer").Services<Implementation>, LayerNode.Output<NoInfer<Items>[number]>>;
|
|
45
|
+
});
|
|
46
|
+
readonly tag?: LayerNode.Tag<"location"> | undefined;
|
|
47
|
+
}, "tag">) & ([Exclude<Items[number], LayerNode.Node<unknown, unknown, LayerNode.Tag<"location" | "global"> | undefined>>] extends [never] ? unknown : {
|
|
48
|
+
readonly "Invalid tag dependencies": Exclude<Items[number], LayerNode.Node<unknown, unknown, LayerNode.Tag<"location" | "global"> | undefined>>;
|
|
49
|
+
})) => LayerNode.Node<import("effect/Layer").Success<Implementation>, import("effect/Layer").Error<Implementation> | LayerNode.Error<Items[number]>, LayerNode.Tag<"location">>;
|
|
50
|
+
export * as Node from "./app-node.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { LayerNode } from "./layer-node.js";
|
|
2
|
+
export const tags = LayerNode.tags({
|
|
3
|
+
location: ["global"],
|
|
4
|
+
global: [],
|
|
5
|
+
});
|
|
6
|
+
export const makeGlobalNode = tags.make("global");
|
|
7
|
+
export const makeLocationNode = tags.make("location");
|
|
8
|
+
export * as Node from "./app-node.js";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Brand, Context, Layer } from "effect";
|
|
2
|
+
type AnyNode = Node<unknown, unknown, any>;
|
|
3
|
+
type NodeList<Item extends AnyNode = AnyNode> = readonly [] | readonly [Item, ...Item[]];
|
|
4
|
+
export type Output<Item> = [Item] extends [never] ? never : Item extends Node<infer A, unknown, any> ? A : never;
|
|
5
|
+
export type Error<Item> = [Item] extends [never] ? never : Item extends Node<unknown, infer E, any> ? E : never;
|
|
6
|
+
type NodeTag<Item> = [Item] extends [never] ? undefined : Item extends Node<unknown, unknown, infer T> ? T : never;
|
|
7
|
+
type Missing<Required, Dependencies extends NodeList> = Exclude<Required, Output<Dependencies[number]>>;
|
|
8
|
+
type CheckDependencies<Implementation extends Layer.Any, Dependencies extends NodeList> = [
|
|
9
|
+
Missing<Layer.Services<Implementation>, Dependencies>
|
|
10
|
+
] extends [never] ? unknown : {
|
|
11
|
+
readonly "Missing dependencies": Missing<Layer.Services<Implementation>, Dependencies>;
|
|
12
|
+
};
|
|
13
|
+
declare const $OutputType: unique symbol;
|
|
14
|
+
declare const $ErrorType: unique symbol;
|
|
15
|
+
export type Tag<Name extends string = string> = Name & Brand.Brand<"LayerNode.Tag">;
|
|
16
|
+
export interface Node<A, E = never, T extends Tag | undefined = undefined> {
|
|
17
|
+
readonly kind: "layer" | "unbound" | "group";
|
|
18
|
+
readonly name: string;
|
|
19
|
+
readonly service?: Context.Service.Any;
|
|
20
|
+
readonly implementation?: Layer.Any;
|
|
21
|
+
readonly dependencies: readonly AnyNode[];
|
|
22
|
+
readonly tag?: T;
|
|
23
|
+
readonly [$OutputType]?: () => A;
|
|
24
|
+
readonly [$ErrorType]?: () => E;
|
|
25
|
+
}
|
|
26
|
+
type NodeIdentity = {
|
|
27
|
+
readonly service: Context.Service.Any;
|
|
28
|
+
readonly name?: never;
|
|
29
|
+
} | {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly service?: never;
|
|
32
|
+
};
|
|
33
|
+
type DistributiveOmit<A, K extends PropertyKey> = A extends unknown ? Omit<A, K> : never;
|
|
34
|
+
export type TagConfig = Readonly<Record<string, readonly string[]>>;
|
|
35
|
+
type TagNames<Config extends TagConfig> = keyof Config & string;
|
|
36
|
+
type NodeInTags<Names extends string> = Node<unknown, unknown, Tag<Names> | undefined>;
|
|
37
|
+
type CheckTags<Items extends NodeList, Names extends string> = [Exclude<Items[number], NodeInTags<Names>>] extends [
|
|
38
|
+
never
|
|
39
|
+
] ? unknown : {
|
|
40
|
+
readonly "Invalid tag dependencies": Exclude<Items[number], NodeInTags<Names>>;
|
|
41
|
+
};
|
|
42
|
+
export interface Tags<Config extends TagConfig> {
|
|
43
|
+
readonly values: {
|
|
44
|
+
readonly [Name in TagNames<Config>]: Tag<Name>;
|
|
45
|
+
};
|
|
46
|
+
readonly make: <Name extends TagNames<Config>>(name: Name) => <const Implementation extends Layer.Any, const Items extends NodeList>(input: DistributiveOmit<MakeInput<Implementation, Items, Tag<Name>>, "tag"> & CheckTags<Items, Name | Extract<Config[Name][number], string>>) => Node<Layer.Success<Implementation>, Layer.Error<Implementation> | Error<Items[number]>, Tag<Name>>;
|
|
47
|
+
}
|
|
48
|
+
export declare function tags<const Config extends {
|
|
49
|
+
readonly [Name in keyof Config]: readonly (keyof Config & string)[];
|
|
50
|
+
}>(config: Config): Tags<Config>;
|
|
51
|
+
type MakeInput<Implementation extends Layer.Any, Items extends NodeList, T extends Tag | undefined = undefined> = NodeIdentity & {
|
|
52
|
+
readonly layer: Implementation;
|
|
53
|
+
readonly deps: Items & CheckDependencies<Implementation, NoInfer<Items>>;
|
|
54
|
+
readonly tag?: T;
|
|
55
|
+
};
|
|
56
|
+
export declare function make<const Implementation extends Layer.Any, const Items extends NodeList, const T extends Tag | undefined = undefined>(input: MakeInput<Implementation, Items, T>): Node<Layer.Success<Implementation>, Layer.Error<Implementation> | Error<Items[number]>, T>;
|
|
57
|
+
export declare function unbound<R, Shape, const T extends Tag>(service: Context.Key<R, Shape>, tag: T): Node<R, never, T>;
|
|
58
|
+
export declare function group<const Items extends readonly AnyNode[]>(dependencies: Items): Node<Output<Items[number]>, Error<Items[number]>, NodeTag<Items[number]>>;
|
|
59
|
+
export type Replacement = readonly [source: AnyNode, replacement: AnyNode | Layer.Any];
|
|
60
|
+
export type Replacements = readonly Replacement[];
|
|
61
|
+
type CheckReplacementErrors<SourceError, ReplacementError> = [Exclude<ReplacementError, SourceError>] extends [never] ? unknown : {
|
|
62
|
+
readonly "New replacement errors": Exclude<ReplacementError, SourceError>;
|
|
63
|
+
};
|
|
64
|
+
type CheckReplacement<Item> = Item extends readonly [Node<infer A, infer E, infer T>, infer Replacement] ? Replacement extends Node<NoInfer<A>, infer E2, T> ? CheckReplacementErrors<E, NoInfer<E2>> : Replacement extends Layer.Layer<NoInfer<A>, infer E2, never> ? CheckReplacementErrors<E, NoInfer<E2>> : {
|
|
65
|
+
readonly "Invalid replacement": Replacement;
|
|
66
|
+
} : {
|
|
67
|
+
readonly "Invalid replacement": Item;
|
|
68
|
+
};
|
|
69
|
+
type CheckReplacements<Items extends Replacements> = {
|
|
70
|
+
readonly [K in keyof Items]: CheckReplacement<Items[K]>;
|
|
71
|
+
};
|
|
72
|
+
type ValidReplacements<Items extends Replacements> = Items & CheckReplacements<Items>;
|
|
73
|
+
export declare function hoist<A, E, T extends Tag, const Items extends Replacements = readonly []>(root: Node<A, E, any>, tag: T, replacements?: ValidReplacements<Items>): {
|
|
74
|
+
readonly node: Node<A, E>;
|
|
75
|
+
readonly hoisted: Node<unknown, E>;
|
|
76
|
+
};
|
|
77
|
+
export declare function compile<A, E, const Items extends Replacements = readonly []>(root: Node<A, E, any>, replacements?: ValidReplacements<Items>): Layer.Layer<A, E>;
|
|
78
|
+
export declare function hasUnbound(root: Node<unknown, unknown, any>, source: AnyNode): boolean;
|
|
79
|
+
export * as LayerNode from "./layer-node.js";
|