devsess 0.3.4 → 0.5.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.
- package/LICENSE +201 -0
- package/README.md +3 -3
- package/dist/async/index.d.ts +1 -1
- package/dist/async/index.d.ts.map +1 -1
- package/dist/async/index.js +9 -7
- package/dist/async/index.js.map +1 -1
- package/dist/async/platform.d.ts +2 -2
- package/dist/async/platform.d.ts.map +1 -1
- package/dist/async/run-dev-cli.d.ts +1 -1
- package/dist/async/run-dev-cli.d.ts.map +1 -1
- package/dist/chunk-KG24ZAKO.js +166 -0
- package/dist/chunk-KG24ZAKO.js.map +1 -0
- package/dist/{chunk-ULIVG5ID.js → chunk-MBPIOYW3.js} +166 -233
- package/dist/chunk-MBPIOYW3.js.map +1 -0
- package/dist/chunk-OODLZZCC.js +287 -0
- package/dist/chunk-OODLZZCC.js.map +1 -0
- package/dist/chunk-UOIMVHGX.js +29 -0
- package/dist/chunk-UOIMVHGX.js.map +1 -0
- package/dist/current-session.d.ts +1 -0
- package/dist/current-session.d.ts.map +1 -1
- package/dist/dev/daemon-client.d.ts +21 -0
- package/dist/dev/daemon-client.d.ts.map +1 -0
- package/dist/dev/daemon-readiness.d.ts.map +1 -1
- package/dist/dev/daemon-services.d.ts +3 -0
- package/dist/dev/daemon-services.d.ts.map +1 -0
- package/dist/dev/sticky-port.d.ts +4 -1
- package/dist/dev/sticky-port.d.ts.map +1 -1
- package/dist/dev/subprocess.d.ts +1 -1
- package/dist/dev/subprocess.d.ts.map +1 -1
- package/dist/dev-sessions.d.ts +2 -0
- package/dist/dev-sessions.d.ts.map +1 -1
- package/dist/index.js +10 -26
- package/dist/index.js.map +1 -1
- package/dist/lock.d.ts +3 -0
- package/dist/lock.d.ts.map +1 -0
- package/dist/pglite/index.d.ts +2 -2
- package/dist/pglite/index.d.ts.map +1 -1
- package/dist/pglite/index.js +20 -30
- package/dist/pglite/index.js.map +1 -1
- package/dist/services/container.d.ts +17 -0
- package/dist/services/container.d.ts.map +1 -0
- package/dist/services/core.d.ts +30 -0
- package/dist/services/core.d.ts.map +1 -0
- package/dist/services/docker-args.d.ts +31 -0
- package/dist/services/docker-args.d.ts.map +1 -0
- package/dist/services/index.d.ts +50 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +379 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/local.d.ts +11 -0
- package/dist/services/local.d.ts.map +1 -0
- package/dist/services/shared/callsite.d.ts +4 -0
- package/dist/services/shared/callsite.d.ts.map +1 -0
- package/dist/services/shared/entry.d.ts +2 -0
- package/dist/services/shared/entry.d.ts.map +1 -0
- package/dist/services/shared/entry.js +137 -0
- package/dist/services/shared/entry.js.map +1 -0
- package/dist/services/shared/host.d.ts +5 -0
- package/dist/services/shared/host.d.ts.map +1 -0
- package/dist/services/shared/index.d.ts +11 -0
- package/dist/services/shared/index.d.ts.map +1 -0
- package/dist/services/shared/protocol.d.ts +39 -0
- package/dist/services/shared/protocol.d.ts.map +1 -0
- package/dist/services/shared/root.d.ts +5 -0
- package/dist/services/shared/root.d.ts.map +1 -0
- package/dist/socket-line.d.ts +3 -0
- package/dist/socket-line.d.ts.map +1 -0
- package/package.json +94 -88
- package/dist/chunk-ULIVG5ID.js.map +0 -1
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import {
|
|
2
|
+
acquireFileLock,
|
|
3
|
+
getStickyPort,
|
|
4
|
+
readDaemonIdentity,
|
|
5
|
+
readSocketLine,
|
|
6
|
+
sendDaemonRequest
|
|
7
|
+
} from "./chunk-MBPIOYW3.js";
|
|
8
|
+
|
|
9
|
+
// src/services/core.ts
|
|
10
|
+
import { Data, Effect } from "effect";
|
|
11
|
+
var serviceBrand = /* @__PURE__ */ Symbol.for("devsess/ServiceDefinition");
|
|
12
|
+
var isServiceDefinition = (value) => typeof value === "object" && value !== null && serviceBrand in value && value[serviceBrand] === true;
|
|
13
|
+
var withServiceError = (message) => Effect.mapError(
|
|
14
|
+
(cause) => cause instanceof ServiceError ? cause : new ServiceError({ message, cause })
|
|
15
|
+
);
|
|
16
|
+
var runningService = (result) => ({
|
|
17
|
+
...typeof result.value === "object" && result.value !== null ? result.value : {},
|
|
18
|
+
ports: result.ports
|
|
19
|
+
});
|
|
20
|
+
var ServiceError = class extends Data.TaggedError("ServiceError") {
|
|
21
|
+
};
|
|
22
|
+
var validName = (name) => /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(name);
|
|
23
|
+
|
|
24
|
+
// src/services/local.ts
|
|
25
|
+
import { Effect as Effect3 } from "effect";
|
|
26
|
+
import { FileSystem } from "effect/FileSystem";
|
|
27
|
+
import { Path } from "effect/Path";
|
|
28
|
+
|
|
29
|
+
// src/dev/daemon-services.ts
|
|
30
|
+
import { Effect as Effect2 } from "effect";
|
|
31
|
+
var reportDaemonService = (name, ports) => Effect2.gen(function* () {
|
|
32
|
+
const identity = yield* readDaemonIdentity;
|
|
33
|
+
if (identity === void 0) return;
|
|
34
|
+
const params = {
|
|
35
|
+
runId: identity.runId,
|
|
36
|
+
service: identity.service,
|
|
37
|
+
name,
|
|
38
|
+
...identity.instanceId === void 0 ? {} : { instanceId: identity.instanceId }
|
|
39
|
+
};
|
|
40
|
+
const send = (method, values) => sendDaemonRequest(
|
|
41
|
+
identity,
|
|
42
|
+
{ version: 1, requestId: crypto.randomUUID(), method, params: values },
|
|
43
|
+
250
|
|
44
|
+
).pipe(Effect2.catch(() => Effect2.void));
|
|
45
|
+
yield* Effect2.acquireRelease(
|
|
46
|
+
send("reportService", {
|
|
47
|
+
...params,
|
|
48
|
+
...Object.keys(ports).length === 0 ? {} : { ports }
|
|
49
|
+
}),
|
|
50
|
+
() => send("retractService", params)
|
|
51
|
+
);
|
|
52
|
+
}).pipe(Effect2.catch(() => Effect2.void));
|
|
53
|
+
|
|
54
|
+
// src/services/local.ts
|
|
55
|
+
var prepareLocal = (session, def) => Effect3.gen(function* () {
|
|
56
|
+
if (!validName(def.name) || !validName(session.name)) {
|
|
57
|
+
return yield* new ServiceError({
|
|
58
|
+
message: "Service and session names must contain only letters, numbers, dots, underscores, or hyphens"
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const fs = yield* FileSystem;
|
|
62
|
+
const path = yield* Path;
|
|
63
|
+
const dataDir = path.join(yield* session.path(""), "services", def.name);
|
|
64
|
+
const ports = {};
|
|
65
|
+
for (const port of def.ports)
|
|
66
|
+
ports[port] = yield* getStickyPort(session, {
|
|
67
|
+
name: `${def.name}:${port}`
|
|
68
|
+
});
|
|
69
|
+
yield* fs.makeDirectory(dataDir, { recursive: true });
|
|
70
|
+
return { ports, dataDir };
|
|
71
|
+
}).pipe(withServiceError(`Failed to prepare service ${def.name}`));
|
|
72
|
+
var runLocal = (session, def) => Effect3.gen(function* () {
|
|
73
|
+
const prepared = yield* prepareLocal(session, def);
|
|
74
|
+
const value = yield* def.start({
|
|
75
|
+
session,
|
|
76
|
+
ports: prepared.ports,
|
|
77
|
+
dataDir: prepared.dataDir
|
|
78
|
+
});
|
|
79
|
+
yield* reportDaemonService(def.name, prepared.ports);
|
|
80
|
+
return { value, ports: prepared.ports };
|
|
81
|
+
}).pipe(Effect3.annotateLogs({ service: def.name }));
|
|
82
|
+
|
|
83
|
+
// src/services/shared/protocol.ts
|
|
84
|
+
import { spawn } from "child_process";
|
|
85
|
+
import { createHash } from "crypto";
|
|
86
|
+
import { mkdir, open, readlink, rm, symlink } from "fs/promises";
|
|
87
|
+
import { connect } from "net";
|
|
88
|
+
import { tmpdir } from "os";
|
|
89
|
+
import { basename, join } from "path";
|
|
90
|
+
import { fileURLToPath } from "url";
|
|
91
|
+
import { Effect as Effect4, Schedule, Schema } from "effect";
|
|
92
|
+
var sharedGraceMs = 5e3;
|
|
93
|
+
var hostPaths = (sessionDir, name) => {
|
|
94
|
+
const dir = join(sessionDir, "hosts", name);
|
|
95
|
+
return {
|
|
96
|
+
dir,
|
|
97
|
+
socket: join(dir, "host.sock"),
|
|
98
|
+
lock: join(dir, "startup.lock"),
|
|
99
|
+
log: join(dir, "service.log")
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
var hostArguments = Schema.fromJsonString(
|
|
103
|
+
Schema.Struct({
|
|
104
|
+
module: Schema.String,
|
|
105
|
+
name: Schema.String,
|
|
106
|
+
root: Schema.String,
|
|
107
|
+
session: Schema.String
|
|
108
|
+
})
|
|
109
|
+
);
|
|
110
|
+
var readyMessage = (output) => Schema.fromJsonString(
|
|
111
|
+
Schema.Struct({
|
|
112
|
+
output,
|
|
113
|
+
ports: Schema.Record(Schema.String, Schema.Number)
|
|
114
|
+
})
|
|
115
|
+
);
|
|
116
|
+
var io = (message, operation) => Effect4.tryPromise({
|
|
117
|
+
try: () => operation(),
|
|
118
|
+
catch: (cause) => new ServiceError({ message, cause })
|
|
119
|
+
});
|
|
120
|
+
var isErrno = (cause, code) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === code;
|
|
121
|
+
var startupLock = (paths) => acquireFileLock(paths.dir, paths.lock).pipe(
|
|
122
|
+
withServiceError("Failed to acquire shared host lock")
|
|
123
|
+
);
|
|
124
|
+
var failWhenHostExits = (lease, name) => Effect4.callback((resume) => {
|
|
125
|
+
const closed = () => resume(
|
|
126
|
+
new ServiceError({
|
|
127
|
+
message: `Shared host ${name} exited while this consumer was active`
|
|
128
|
+
})
|
|
129
|
+
);
|
|
130
|
+
lease.socket.once("close", closed);
|
|
131
|
+
return Effect4.sync(() => lease.socket.removeListener("close", closed));
|
|
132
|
+
});
|
|
133
|
+
var socketPath = async (paths) => {
|
|
134
|
+
if (Buffer.byteLength(paths.socket) < 100) return paths.socket;
|
|
135
|
+
const alias = join(
|
|
136
|
+
tmpdir(),
|
|
137
|
+
`dvs-${createHash("sha256").update(paths.dir).digest("hex").slice(0, 16)}`
|
|
138
|
+
);
|
|
139
|
+
await symlink(paths.dir, alias).catch(async (cause) => {
|
|
140
|
+
if (!isErrno(cause, "EEXIST")) throw cause;
|
|
141
|
+
if (await readlink(alias) !== paths.dir)
|
|
142
|
+
throw new Error(`Unexpected shared socket alias: ${alias}`);
|
|
143
|
+
});
|
|
144
|
+
return join(alias, basename(paths.socket));
|
|
145
|
+
};
|
|
146
|
+
var HostUnavailable = class extends Error {
|
|
147
|
+
};
|
|
148
|
+
var connectHost = async (paths, child) => {
|
|
149
|
+
const socket = connect(await socketPath(paths));
|
|
150
|
+
const exited = () => socket.destroy(new Error("Host exited before readiness"));
|
|
151
|
+
child?.once("exit", exited);
|
|
152
|
+
try {
|
|
153
|
+
if (child !== void 0 && (child.exitCode !== null || child.signalCode !== null))
|
|
154
|
+
exited();
|
|
155
|
+
const line = await readSocketLine(socket);
|
|
156
|
+
socket.on("error", () => socket.destroy());
|
|
157
|
+
return { socket, line };
|
|
158
|
+
} catch (cause) {
|
|
159
|
+
socket.destroy();
|
|
160
|
+
throw new HostUnavailable("Host did not send readiness", { cause });
|
|
161
|
+
} finally {
|
|
162
|
+
child?.removeListener("exit", exited);
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
var unavailable = (cause) => cause instanceof HostUnavailable;
|
|
166
|
+
var logTail = async (paths) => {
|
|
167
|
+
const file = await open(paths.log, "r");
|
|
168
|
+
try {
|
|
169
|
+
const size = (await file.stat()).size;
|
|
170
|
+
const buffer = Buffer.alloc(Math.min(size, 8192));
|
|
171
|
+
const read = await file.read(
|
|
172
|
+
buffer,
|
|
173
|
+
0,
|
|
174
|
+
buffer.length,
|
|
175
|
+
Math.max(0, size - buffer.length)
|
|
176
|
+
);
|
|
177
|
+
return buffer.subarray(0, read.bytesRead).toString("utf8");
|
|
178
|
+
} finally {
|
|
179
|
+
await file.close();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
var startHost = (paths, launch) => Effect4.gen(function* () {
|
|
183
|
+
yield* io(
|
|
184
|
+
"Failed to remove stale host socket",
|
|
185
|
+
() => rm(paths.socket, { force: true })
|
|
186
|
+
);
|
|
187
|
+
const child = yield* io("Failed to launch shared host", launch);
|
|
188
|
+
return yield* Effect4.suspend(() => {
|
|
189
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
190
|
+
return io("Failed to read shared host log", () => logTail(paths)).pipe(
|
|
191
|
+
Effect4.flatMap(
|
|
192
|
+
(log) => new ServiceError({
|
|
193
|
+
message: `Shared host failed to start: ${log}`
|
|
194
|
+
})
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
return io(
|
|
198
|
+
"Failed to read shared host readiness",
|
|
199
|
+
() => connectHost(paths, child)
|
|
200
|
+
);
|
|
201
|
+
}).pipe(
|
|
202
|
+
Effect4.retry({
|
|
203
|
+
while: (error) => unavailable(error.cause),
|
|
204
|
+
schedule: Schedule.spaced("50 millis")
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
var acquireHostUnderLock = (paths, launch) => Effect4.gen(function* () {
|
|
209
|
+
yield* Effect4.acquireRelease(
|
|
210
|
+
startupLock(paths),
|
|
211
|
+
(release) => io("Failed to release shared host lock", release).pipe(Effect4.orDie)
|
|
212
|
+
);
|
|
213
|
+
return yield* io(
|
|
214
|
+
"Failed to connect to shared host",
|
|
215
|
+
() => connectHost(paths)
|
|
216
|
+
).pipe(
|
|
217
|
+
Effect4.catch(
|
|
218
|
+
(error) => unavailable(error.cause) ? startHost(paths, launch) : error
|
|
219
|
+
)
|
|
220
|
+
);
|
|
221
|
+
}).pipe(Effect4.scoped);
|
|
222
|
+
var acquireHost = (paths, launch) => Effect4.gen(function* () {
|
|
223
|
+
yield* io(
|
|
224
|
+
"Failed to create shared host directory",
|
|
225
|
+
() => mkdir(paths.dir, { recursive: true })
|
|
226
|
+
);
|
|
227
|
+
return yield* io(
|
|
228
|
+
"Failed to connect to shared host",
|
|
229
|
+
() => connectHost(paths)
|
|
230
|
+
).pipe(
|
|
231
|
+
Effect4.catch(
|
|
232
|
+
(error) => unavailable(error.cause) ? acquireHostUnderLock(paths, launch) : error
|
|
233
|
+
)
|
|
234
|
+
);
|
|
235
|
+
});
|
|
236
|
+
var launchHost = async (paths, args) => {
|
|
237
|
+
const log = await open(paths.log, "a");
|
|
238
|
+
try {
|
|
239
|
+
const entry = new URL(
|
|
240
|
+
import.meta.url.endsWith(".ts") ? "../../../dist/services/shared/entry.js" : "./services/shared/entry.js",
|
|
241
|
+
import.meta.url
|
|
242
|
+
);
|
|
243
|
+
const child = spawn(
|
|
244
|
+
process.execPath,
|
|
245
|
+
[...process.execArgv, fileURLToPath(entry), JSON.stringify(args)],
|
|
246
|
+
{
|
|
247
|
+
detached: true,
|
|
248
|
+
env: Object.fromEntries(
|
|
249
|
+
Object.entries(process.env).filter(
|
|
250
|
+
(entry2) => !entry2[0].startsWith("DEVSESS_")
|
|
251
|
+
)
|
|
252
|
+
),
|
|
253
|
+
stdio: ["ignore", log.fd, log.fd]
|
|
254
|
+
}
|
|
255
|
+
);
|
|
256
|
+
await new Promise((resolve, reject) => {
|
|
257
|
+
child.once("spawn", resolve);
|
|
258
|
+
child.once("error", reject);
|
|
259
|
+
});
|
|
260
|
+
child.unref();
|
|
261
|
+
return child;
|
|
262
|
+
} finally {
|
|
263
|
+
await log.close();
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
export {
|
|
268
|
+
serviceBrand,
|
|
269
|
+
isServiceDefinition,
|
|
270
|
+
withServiceError,
|
|
271
|
+
runningService,
|
|
272
|
+
ServiceError,
|
|
273
|
+
validName,
|
|
274
|
+
reportDaemonService,
|
|
275
|
+
runLocal,
|
|
276
|
+
sharedGraceMs,
|
|
277
|
+
hostPaths,
|
|
278
|
+
hostArguments,
|
|
279
|
+
readyMessage,
|
|
280
|
+
io,
|
|
281
|
+
startupLock,
|
|
282
|
+
failWhenHostExits,
|
|
283
|
+
socketPath,
|
|
284
|
+
acquireHost,
|
|
285
|
+
launchHost
|
|
286
|
+
};
|
|
287
|
+
//# sourceMappingURL=chunk-OODLZZCC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/services/core.ts","../src/services/local.ts","../src/dev/daemon-services.ts","../src/services/shared/protocol.ts"],"sourcesContent":["import { Data, Effect } from 'effect';\nimport type { FileSystem } from 'effect/FileSystem';\nimport type { Path } from 'effect/Path';\nimport type { Scope } from 'effect/Scope';\nimport type { DevSession } from '../dev-sessions';\nimport type { RunningService, ServiceDefinition } from './index';\n\nexport const serviceBrand = Symbol.for('devsess/ServiceDefinition');\n\nexport const isServiceDefinition = (\n\tvalue: unknown,\n): value is ServiceDefinition<\n\tstring,\n\tstring,\n\tunknown,\n\tunknown,\n\tScope | FileSystem | Path\n> =>\n\ttypeof value === 'object' &&\n\tvalue !== null &&\n\tserviceBrand in value &&\n\tvalue[serviceBrand] === true;\n\nexport const withServiceError = (message: string) =>\n\tEffect.mapError((cause: unknown) =>\n\t\tcause instanceof ServiceError\n\t\t\t? cause\n\t\t\t: new ServiceError({ message, cause }),\n\t);\n\nexport const runningService = <Port extends string, A>(result: {\n\tvalue: A;\n\tports: Readonly<Record<Port, number>>;\n}) =>\n\t({\n\t\t...(typeof result.value === 'object' && result.value !== null\n\t\t\t? result.value\n\t\t\t: {}),\n\t\tports: result.ports,\n\t}) as RunningService<Port, A>;\n\nexport class ServiceError extends Data.TaggedError('ServiceError')<{\n\tmessage: string;\n\tcause?: unknown;\n}> {}\n\nexport type ServiceContext<Port extends string> = {\n\treadonly session: DevSession;\n\treadonly ports: Readonly<Record<Port, number>>;\n\t/** `<session>/services/<service>`, created before `start` runs and kept after it stops. */\n\treadonly dataDir: string;\n};\n\nexport const validName = (name: string) =>\n\t/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(name);\n","import { Effect } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport { reportDaemonService } from '../dev/daemon-services';\nimport { getStickyPort } from '../dev/sticky-port';\nimport type { DevSession } from '../dev-sessions';\nimport { ServiceError, validName, withServiceError } from './core';\nimport type { ServiceDefinition } from './index';\n\nconst prepareLocal = <Name extends string, Port extends string>(\n\tsession: DevSession,\n\tdef: { readonly name: Name; readonly ports: ReadonlyArray<Port> },\n) =>\n\tEffect.gen(function* () {\n\t\tif (!validName(def.name) || !validName(session.name)) {\n\t\t\treturn yield* new ServiceError({\n\t\t\t\tmessage:\n\t\t\t\t\t'Service and session names must contain only letters, numbers, dots, underscores, or hyphens',\n\t\t\t});\n\t\t}\n\t\tconst fs = yield* FileSystem;\n\t\tconst path = yield* Path;\n\t\tconst dataDir = path.join(yield* session.path(''), 'services', def.name);\n\t\tconst ports = {} as Record<Port, number>;\n\t\tfor (const port of def.ports)\n\t\t\tports[port] = yield* getStickyPort(session, {\n\t\t\t\tname: `${def.name}:${port}`,\n\t\t\t});\n\t\tyield* fs.makeDirectory(dataDir, { recursive: true });\n\t\treturn { ports, dataDir };\n\t}).pipe(withServiceError(`Failed to prepare service ${def.name}`));\n\nexport const runLocal = <Name extends string, Port extends string, A, E, R>(\n\tsession: DevSession,\n\tdef: Pick<ServiceDefinition<Name, Port, A, E, R>, 'name' | 'ports' | 'start'>,\n) =>\n\tEffect.gen(function* () {\n\t\tconst prepared = yield* prepareLocal(session, def);\n\t\tconst value = yield* def.start({\n\t\t\tsession,\n\t\t\tports: prepared.ports,\n\t\t\tdataDir: prepared.dataDir,\n\t\t});\n\t\tyield* reportDaemonService(def.name, prepared.ports);\n\t\treturn { value, ports: prepared.ports };\n\t}).pipe(Effect.annotateLogs({ service: def.name }));\n","import { Effect } from 'effect';\nimport { readDaemonIdentity, sendDaemonRequest } from './daemon-client';\n\nexport const reportDaemonService = (\n\tname: string,\n\tports: Readonly<Record<string, number>>,\n) =>\n\tEffect.gen(function* () {\n\t\tconst identity = yield* readDaemonIdentity;\n\t\tif (identity === undefined) return;\n\t\tconst params = {\n\t\t\trunId: identity.runId,\n\t\t\tservice: identity.service,\n\t\t\tname,\n\t\t\t...(identity.instanceId === undefined\n\t\t\t\t? {}\n\t\t\t\t: { instanceId: identity.instanceId }),\n\t\t};\n\t\tconst send = (method: string, values: Readonly<Record<string, unknown>>) =>\n\t\t\tsendDaemonRequest(\n\t\t\t\tidentity,\n\t\t\t\t{ version: 1, requestId: crypto.randomUUID(), method, params: values },\n\t\t\t\t250,\n\t\t\t).pipe(Effect.catch(() => Effect.void));\n\t\tyield* Effect.acquireRelease(\n\t\t\tsend('reportService', {\n\t\t\t\t...params,\n\t\t\t\t...(Object.keys(ports).length === 0 ? {} : { ports }),\n\t\t\t}),\n\t\t\t() => send('retractService', params),\n\t\t);\n\t}).pipe(Effect.catch(() => Effect.void));\n","import { type ChildProcess, spawn } from 'node:child_process';\nimport { createHash } from 'node:crypto';\nimport { mkdir, open, readlink, rm, symlink } from 'node:fs/promises';\nimport { connect, type Socket } from 'node:net';\nimport { tmpdir } from 'node:os';\nimport { basename, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { Effect, Schedule, Schema } from 'effect';\nimport { acquireFileLock } from '../../lock';\nimport { readSocketLine } from '../../socket-line';\nimport { ServiceError, withServiceError } from '../core';\n\nexport const sharedGraceMs = 5_000;\nexport const hostPaths = (sessionDir: string, name: string) => {\n\tconst dir = join(sessionDir, 'hosts', name);\n\treturn {\n\t\tdir,\n\t\tsocket: join(dir, 'host.sock'),\n\t\tlock: join(dir, 'startup.lock'),\n\t\tlog: join(dir, 'service.log'),\n\t};\n};\nexport type HostPaths = ReturnType<typeof hostPaths>;\nexport const hostArguments = Schema.fromJsonString(\n\tSchema.Struct({\n\t\tmodule: Schema.String,\n\t\tname: Schema.String,\n\t\troot: Schema.String,\n\t\tsession: Schema.String,\n\t}),\n);\ntype HostArguments = typeof hostArguments.Type;\nexport const readyMessage = <A>(output: Schema.Codec<A, unknown>) =>\n\tSchema.fromJsonString(\n\t\tSchema.Struct({\n\t\t\toutput,\n\t\t\tports: Schema.Record(Schema.String, Schema.Number),\n\t\t}),\n\t);\n\nexport const io = <A>(message: string, operation: () => Promise<A>) =>\n\tEffect.tryPromise({\n\t\ttry: () => operation(),\n\t\tcatch: (cause) => new ServiceError({ message, cause }),\n\t});\nexport const isErrno = (cause: unknown, code: string) =>\n\ttypeof cause === 'object' &&\n\tcause !== null &&\n\t'code' in cause &&\n\tcause.code === code;\nexport const startupLock = (paths: HostPaths) =>\n\tacquireFileLock(paths.dir, paths.lock).pipe(\n\t\twithServiceError('Failed to acquire shared host lock'),\n\t);\nexport type Lease = { socket: Socket; line: string };\n\nexport const failWhenHostExits = (lease: Lease, name: string) =>\n\tEffect.callback<never, ServiceError>((resume) => {\n\t\tconst closed = () =>\n\t\t\tresume(\n\t\t\t\tnew ServiceError({\n\t\t\t\t\tmessage: `Shared host ${name} exited while this consumer was active`,\n\t\t\t\t}),\n\t\t\t);\n\t\tlease.socket.once('close', closed);\n\t\treturn Effect.sync(() => lease.socket.removeListener('close', closed));\n\t});\n\n/** Unix sockets have tiny pathname limits; a short alias keeps the socket in the host directory. */\nexport const socketPath = async (paths: HostPaths) => {\n\tif (Buffer.byteLength(paths.socket) < 100) return paths.socket;\n\tconst alias = join(\n\t\ttmpdir(),\n\t\t`dvs-${createHash('sha256').update(paths.dir).digest('hex').slice(0, 16)}`,\n\t);\n\tawait symlink(paths.dir, alias).catch(async (cause: unknown) => {\n\t\tif (!isErrno(cause, 'EEXIST')) throw cause;\n\t\tif ((await readlink(alias)) !== paths.dir)\n\t\t\tthrow new Error(`Unexpected shared socket alias: ${alias}`);\n\t});\n\treturn join(alias, basename(paths.socket));\n};\nclass HostUnavailable extends Error {}\nexport const connectHost = async (\n\tpaths: HostPaths,\n\tchild?: ChildProcess,\n): Promise<Lease> => {\n\tconst socket = connect(await socketPath(paths));\n\tconst exited = () =>\n\t\tsocket.destroy(new Error('Host exited before readiness'));\n\tchild?.once('exit', exited);\n\ttry {\n\t\tif (\n\t\t\tchild !== undefined &&\n\t\t\t(child.exitCode !== null || child.signalCode !== null)\n\t\t)\n\t\t\texited();\n\t\tconst line = await readSocketLine(socket);\n\t\tsocket.on('error', () => socket.destroy());\n\t\treturn { socket, line };\n\t} catch (cause) {\n\t\tsocket.destroy();\n\t\tthrow new HostUnavailable('Host did not send readiness', { cause });\n\t} finally {\n\t\tchild?.removeListener('exit', exited);\n\t}\n};\nconst unavailable = (cause: unknown) => cause instanceof HostUnavailable;\nconst logTail = async (paths: HostPaths) => {\n\tconst file = await open(paths.log, 'r');\n\ttry {\n\t\tconst size = (await file.stat()).size;\n\t\tconst buffer = Buffer.alloc(Math.min(size, 8_192));\n\t\tconst read = await file.read(\n\t\t\tbuffer,\n\t\t\t0,\n\t\t\tbuffer.length,\n\t\t\tMath.max(0, size - buffer.length),\n\t\t);\n\t\treturn buffer.subarray(0, read.bytesRead).toString('utf8');\n\t} finally {\n\t\tawait file.close();\n\t}\n};\ntype Launch = () => Promise<ChildProcess>;\nconst startHost = (paths: HostPaths, launch: Launch) =>\n\tEffect.gen(function* () {\n\t\tyield* io('Failed to remove stale host socket', () =>\n\t\t\trm(paths.socket, { force: true }),\n\t\t);\n\t\tconst child = yield* io('Failed to launch shared host', launch);\n\t\treturn yield* Effect.suspend(() => {\n\t\t\tif (child.exitCode !== null || child.signalCode !== null)\n\t\t\t\treturn io('Failed to read shared host log', () => logTail(paths)).pipe(\n\t\t\t\t\tEffect.flatMap(\n\t\t\t\t\t\t(log) =>\n\t\t\t\t\t\t\tnew ServiceError({\n\t\t\t\t\t\t\t\tmessage: `Shared host failed to start: ${log}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\treturn io('Failed to read shared host readiness', () =>\n\t\t\t\tconnectHost(paths, child),\n\t\t\t);\n\t\t}).pipe(\n\t\t\tEffect.retry({\n\t\t\t\twhile: (error) => unavailable(error.cause),\n\t\t\t\tschedule: Schedule.spaced('50 millis'),\n\t\t\t}),\n\t\t);\n\t});\nconst acquireHostUnderLock = (paths: HostPaths, launch: Launch) =>\n\tEffect.gen(function* () {\n\t\tyield* Effect.acquireRelease(startupLock(paths), (release) =>\n\t\t\tio('Failed to release shared host lock', release).pipe(Effect.orDie),\n\t\t);\n\t\treturn yield* io('Failed to connect to shared host', () =>\n\t\t\tconnectHost(paths),\n\t\t).pipe(\n\t\t\tEffect.catch((error) =>\n\t\t\t\tunavailable(error.cause) ? startHost(paths, launch) : error,\n\t\t\t),\n\t\t);\n\t}).pipe(Effect.scoped);\nexport const acquireHost = (paths: HostPaths, launch: Launch) =>\n\tEffect.gen(function* () {\n\t\tyield* io('Failed to create shared host directory', () =>\n\t\t\tmkdir(paths.dir, { recursive: true }),\n\t\t);\n\t\treturn yield* io('Failed to connect to shared host', () =>\n\t\t\tconnectHost(paths),\n\t\t).pipe(\n\t\t\tEffect.catch((error) =>\n\t\t\t\tunavailable(error.cause) ? acquireHostUnderLock(paths, launch) : error,\n\t\t\t),\n\t\t);\n\t});\nexport const launchHost = async (paths: HostPaths, args: HostArguments) => {\n\tconst log = await open(paths.log, 'a');\n\ttry {\n\t\tconst entry = new URL(\n\t\t\timport.meta.url.endsWith('.ts')\n\t\t\t\t? '../../../dist/services/shared/entry.js'\n\t\t\t\t: './services/shared/entry.js',\n\t\t\timport.meta.url,\n\t\t);\n\t\tconst child = spawn(\n\t\t\tprocess.execPath,\n\t\t\t[...process.execArgv, fileURLToPath(entry), JSON.stringify(args)],\n\t\t\t{\n\t\t\t\tdetached: true,\n\t\t\t\tenv: Object.fromEntries(\n\t\t\t\t\tObject.entries(process.env).filter(\n\t\t\t\t\t\t(entry) => !entry[0].startsWith('DEVSESS_'),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t\tstdio: ['ignore', log.fd, log.fd],\n\t\t\t},\n\t\t);\n\t\tawait new Promise<void>((resolve, reject) => {\n\t\t\tchild.once('spawn', resolve);\n\t\t\tchild.once('error', reject);\n\t\t});\n\t\tchild.unref();\n\t\treturn child;\n\t} finally {\n\t\tawait log.close();\n\t}\n};\n"],"mappings":"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","names":["Effect","Effect","Effect","Effect","Effect","Effect","entry"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DevSessions
|
|
3
|
+
} from "./chunk-MBPIOYW3.js";
|
|
4
|
+
|
|
5
|
+
// src/current-session.ts
|
|
6
|
+
import { Context, Effect, Layer } from "effect";
|
|
7
|
+
var CurrentSession = class _CurrentSession extends Context.Service()("devsess/CurrentSession") {
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the session via `DevSessions#getLatestOrCreate`. Provide this around a
|
|
10
|
+
* command's own handler effect, not the whole CLI program: a `Layer`'s build effect
|
|
11
|
+
* runs the moment it's provided, regardless of what the effect it wraps ends up
|
|
12
|
+
* doing — wrapping `Command.run` itself would create a session for `--help`,
|
|
13
|
+
* `--version`, or a bad flag too, none of which ever reach a handler.
|
|
14
|
+
*/
|
|
15
|
+
static layer = Layer.effect(
|
|
16
|
+
_CurrentSession,
|
|
17
|
+
Effect.gen(function* () {
|
|
18
|
+
const sessions = yield* DevSessions;
|
|
19
|
+
return yield* sessions.getLatestOrCreate;
|
|
20
|
+
})
|
|
21
|
+
);
|
|
22
|
+
/** Pins an explicit session instead of resolving one via `DevSessions` — for tests. */
|
|
23
|
+
static layerOf = (session) => Layer.succeed(_CurrentSession, session);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
CurrentSession
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=chunk-UOIMVHGX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/current-session.ts"],"sourcesContent":["import { Context, Effect, Layer } from 'effect';\nimport type { PlatformError } from 'effect/PlatformError';\nimport { type DevSession, DevSessions } from './dev-sessions';\n\n/**\n * The dev session resolved for a single command run. `yield* CurrentSession` always\n * gives a plain `DevSession` — never a wrapper effect to unwrap — so provide whichever\n * layer resolves it (`layer` or the test-only `layerOf(session)`) close to where it's\n * actually used.\n */\nexport class CurrentSession extends Context.Service<\n\tCurrentSession,\n\tDevSession\n>()('devsess/CurrentSession') {\n\t/**\n\t * Resolves the session via `DevSessions#getLatestOrCreate`. Provide this around a\n\t * command's own handler effect, not the whole CLI program: a `Layer`'s build effect\n\t * runs the moment it's provided, regardless of what the effect it wraps ends up\n\t * doing — wrapping `Command.run` itself would create a session for `--help`,\n\t * `--version`, or a bad flag too, none of which ever reach a handler.\n\t */\n\tstatic readonly layer: Layer.Layer<\n\t\tCurrentSession,\n\t\tPlatformError,\n\t\tDevSessions\n\t> = Layer.effect(\n\t\tCurrentSession,\n\t\tEffect.gen(function* () {\n\t\t\tconst sessions = yield* DevSessions;\n\t\t\treturn yield* sessions.getLatestOrCreate;\n\t\t}),\n\t);\n\n\t/** Pins an explicit session instead of resolving one via `DevSessions` — for tests. */\n\tstatic readonly layerOf = (session: DevSession) =>\n\t\tLayer.succeed(CurrentSession, session);\n}\n"],"mappings":";;;;;AAAA,SAAS,SAAS,QAAQ,aAAa;AAUhC,IAAM,iBAAN,MAAM,wBAAuB,QAAQ,QAG1C,EAAE,wBAAwB,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ7B,OAAgB,QAIZ,MAAM;AAAA,IACT;AAAA,IACA,OAAO,IAAI,aAAa;AACvB,YAAM,WAAW,OAAO;AACxB,aAAO,OAAO,SAAS;AAAA,IACxB,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,OAAgB,UAAU,CAAC,YAC1B,MAAM,QAAQ,iBAAgB,OAAO;AACvC;","names":[]}
|
|
@@ -2,6 +2,7 @@ import { Context, Effect, Layer } from 'effect';
|
|
|
2
2
|
import type { PlatformError } from 'effect/PlatformError';
|
|
3
3
|
import { type DevSession, DevSessions } from './dev-sessions';
|
|
4
4
|
declare const CurrentSession_base: Context.ServiceClass<CurrentSession, "devsess/CurrentSession", {
|
|
5
|
+
rootDir: string;
|
|
5
6
|
name: string;
|
|
6
7
|
lastModifiedAt: Date | null;
|
|
7
8
|
path: (relativePath: string) => Effect.Effect<string, never, never>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"current-session.d.ts","sourceRoot":"","sources":["../src/current-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,KAAK,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC
|
|
1
|
+
{"version":3,"file":"current-session.d.ts","sourceRoot":"","sources":["../src/current-session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,KAAK,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;;;;;;;;AAE9D;;;;;GAKG;AACH,qBAAa,cAAe,SAAQ,mBAGP;IAC5B;;;;;;OAMG;IACH,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CACjC,cAAc,EACd,aAAa,EACb,WAAW,CACX,CAMC;IAEF,uFAAuF;IACvF,MAAM,CAAC,QAAQ,CAAC,OAAO,YAAa,UAAU,+CACN;CACxC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Config, Effect, Schema } from 'effect';
|
|
2
|
+
type ServiceIdentity = {
|
|
3
|
+
readonly socketPath: string;
|
|
4
|
+
readonly runId: string;
|
|
5
|
+
readonly service: string;
|
|
6
|
+
readonly instanceId?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const readDaemonIdentity: Effect.Effect<{
|
|
9
|
+
socketPath: string;
|
|
10
|
+
runId: string;
|
|
11
|
+
service: string;
|
|
12
|
+
instanceId?: string | undefined;
|
|
13
|
+
} | undefined, Config.ConfigError, never>;
|
|
14
|
+
export declare const sendDaemonRequest: (identity: ServiceIdentity, request: {
|
|
15
|
+
readonly version: 1;
|
|
16
|
+
readonly requestId: string;
|
|
17
|
+
readonly method: string;
|
|
18
|
+
readonly params: Readonly<Record<string, unknown>>;
|
|
19
|
+
}, timeoutMs?: number) => Effect.Effect<void, Error | Schema.SchemaError, never>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=daemon-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-client.d.ts","sourceRoot":"","sources":["../../src/dev/daemon-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAkB,MAAM,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AAkBxE,KAAK,eAAe,GAAG;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,eAAO,MAAM,kBAAkB;;;;;yCAmB7B,CAAC;AAEH,eAAO,MAAM,iBAAiB,aACnB,eAAe,WAChB;IACR,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACnD,+EAmCA,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon-readiness.d.ts","sourceRoot":"","sources":["../../src/dev/daemon-readiness.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"daemon-readiness.d.ts","sourceRoot":"","sources":["../../src/dev/daemon-readiness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAgB,MAAM,QAAQ,CAAC;AAG9C,eAAO,MAAM,sBAAsB,UAAW,OAAO,6DAiCZ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-services.d.ts","sourceRoot":"","sources":["../../src/dev/daemon-services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,eAAO,MAAM,mBAAmB,SACzB,MAAM,SACL,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,6DA0BC,CAAC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { Effect } from 'effect';
|
|
2
|
+
import { FileSystem } from 'effect/FileSystem';
|
|
3
|
+
import { Path } from 'effect/Path';
|
|
2
4
|
import type { DevSession } from '../dev-sessions';
|
|
5
|
+
import { SessionStateError } from './session-state';
|
|
3
6
|
export declare const getStickyPort: (session: DevSession, options?: {
|
|
4
7
|
name?: string;
|
|
5
|
-
}) => Effect.Effect<number, import("effect/PlatformError").PlatformError |
|
|
8
|
+
}) => Effect.Effect<number, import("effect/PlatformError").PlatformError | SessionStateError, FileSystem | Path>;
|
|
6
9
|
//# sourceMappingURL=sticky-port.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sticky-port.d.ts","sourceRoot":"","sources":["../../src/dev/sticky-port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"sticky-port.d.ts","sourceRoot":"","sources":["../../src/dev/sticky-port.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAGnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAgB,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAiBlE,eAAO,MAAM,aAAa,YAChB,UAAU,YACT;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+GAyCL,CAAC"}
|
package/dist/dev/subprocess.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from 'effect';
|
|
2
2
|
export declare const runManagedSubprocess: (cmd: string, args: string[], opts?: {
|
|
3
3
|
env?: Record<string, string>;
|
|
4
|
-
}) => Effect.Effect<import("effect/
|
|
4
|
+
}) => Effect.Effect<import("effect/process/ChildProcessSpawner").ExitCode, import("effect/PlatformError").PlatformError, import("effect/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/Scope").Scope>;
|
|
5
5
|
//# sourceMappingURL=subprocess.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subprocess.d.ts","sourceRoot":"","sources":["../../src/dev/subprocess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,eAAO,MAAM,oBAAoB,QAC3B,MAAM,QACL,MAAM,EAAE,SACP;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,
|
|
1
|
+
{"version":3,"file":"subprocess.d.ts","sourceRoot":"","sources":["../../src/dev/subprocess.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,eAAO,MAAM,oBAAoB,QAC3B,MAAM,QACL,MAAM,EAAE,SACP;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,wNAyCrC,CAAC"}
|
package/dist/dev-sessions.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ declare namespace DevSession {
|
|
|
10
10
|
pathJoin: (relativePath: string) => string;
|
|
11
11
|
};
|
|
12
12
|
export function make(input: DevSessionInput): {
|
|
13
|
+
rootDir: string;
|
|
13
14
|
name: string;
|
|
14
15
|
lastModifiedAt: Date | null;
|
|
15
16
|
path: (relativePath: string) => Effect.Effect<string, never, never>;
|
|
@@ -24,6 +25,7 @@ declare const DevSessions_base: Context.ServiceClass<DevSessions, "devsess/DevSe
|
|
|
24
25
|
readonly getSessions: Effect.Effect<Array<DevSession>, PlatformError>;
|
|
25
26
|
readonly createSession: Effect.Effect<DevSession, PlatformError>;
|
|
26
27
|
readonly getLatestOrCreate: Effect.Effect<DevSession, PlatformError>;
|
|
28
|
+
readonly getOrCreate: (name: string) => Effect.Effect<DevSession, PlatformError>;
|
|
27
29
|
}>;
|
|
28
30
|
export declare class DevSessions extends DevSessions_base {
|
|
29
31
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev-sessions.d.ts","sourceRoot":"","sources":["../src/dev-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAQ,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,kBAAU,UAAU,CAAC;IACpB,KAAK,eAAe,GAAG;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;KAC3C,CAAC;IAEF,MAAM,UAAU,IAAI,CAAC,KAAK,EAAE,eAAe;QAEzC,IAAI;QACJ,cAAc;QACd,IAAI,iBAAiB,MAAM;QAE3B,QAAQ;MAET;;CACD;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;;kBAK5C,MAAM;mBACL,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM;0BACzB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC;4BAC7C,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC;gCACpC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC;;
|
|
1
|
+
{"version":3,"file":"dev-sessions.d.ts","sourceRoot":"","sources":["../src/dev-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,OAAO,EAAQ,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAG1D,kBAAU,UAAU,CAAC;IACpB,KAAK,eAAe,GAAG;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,IAAI,GAAG,IAAI,CAAC;QAC5B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM,CAAC;KAC3C,CAAC;IAEF,MAAM,UAAU,IAAI,CAAC,KAAK,EAAE,eAAe;QAEzC,OAAO;QACP,IAAI;QACJ,cAAc;QACd,IAAI,iBAAiB,MAAM;QAE3B,QAAQ;MAET;;CACD;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;;kBAK5C,MAAM;mBACL,CAAC,YAAY,EAAE,MAAM,KAAK,MAAM;0BACzB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,aAAa,CAAC;4BAC7C,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC;gCACpC,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC;0BAC9C,CACrB,IAAI,EAAE,MAAM,KACR,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC;;AAV/C,qBAAa,WAAY,SAAQ,gBAYP;IACzB;;;;;;;;;;OAUG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,YAAa,MAAM,wDAAoC;IAE9E;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CACjC,WAAW,EACX,aAAa,GAAG,wBAAwB,EACxC,UAAU,GAAG,IAAI,CACjB,CAIC;CACF;;;;AAED;;;;GAIG;AACH,qBAAa,wBAAyB,SAAQ,8BAE5C;IACD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B,CAAC;CAAG"}
|
package/dist/index.js
CHANGED
|
@@ -1,34 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CurrentSession
|
|
3
|
+
} from "./chunk-UOIMVHGX.js";
|
|
4
|
+
import {
|
|
5
|
+
awaitRunning,
|
|
6
|
+
publishRunning,
|
|
7
|
+
runManagedSubprocess
|
|
8
|
+
} from "./chunk-KG24ZAKO.js";
|
|
1
9
|
import {
|
|
2
10
|
DevSessions,
|
|
3
11
|
ProjectRootNotFoundError,
|
|
4
12
|
SessionState,
|
|
5
13
|
SessionStateError,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
publishRunning,
|
|
9
|
-
runManagedSubprocess
|
|
10
|
-
} from "./chunk-ULIVG5ID.js";
|
|
11
|
-
|
|
12
|
-
// src/current-session.ts
|
|
13
|
-
import { Context, Effect, Layer } from "effect";
|
|
14
|
-
var CurrentSession = class _CurrentSession extends Context.Service()("devsess/CurrentSession") {
|
|
15
|
-
/**
|
|
16
|
-
* Resolves the session via `DevSessions#getLatestOrCreate`. Provide this around a
|
|
17
|
-
* command's own handler effect, not the whole CLI program: a `Layer`'s build effect
|
|
18
|
-
* runs the moment it's provided, regardless of what the effect it wraps ends up
|
|
19
|
-
* doing — wrapping `Command.run` itself would create a session for `--help`,
|
|
20
|
-
* `--version`, or a bad flag too, none of which ever reach a handler.
|
|
21
|
-
*/
|
|
22
|
-
static layer = Layer.effect(
|
|
23
|
-
_CurrentSession,
|
|
24
|
-
Effect.gen(function* () {
|
|
25
|
-
const sessions = yield* DevSessions;
|
|
26
|
-
return yield* sessions.getLatestOrCreate;
|
|
27
|
-
})
|
|
28
|
-
);
|
|
29
|
-
/** Pins an explicit session instead of resolving one via `DevSessions` — for tests. */
|
|
30
|
-
static layerOf = (session) => Layer.succeed(_CurrentSession, session);
|
|
31
|
-
};
|
|
14
|
+
getStickyPort
|
|
15
|
+
} from "./chunk-MBPIOYW3.js";
|
|
32
16
|
export {
|
|
33
17
|
CurrentSession,
|
|
34
18
|
DevSessions,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/lock.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../src/lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,QAAQ,CAAC;AAG1C,eAAO,MAAM,eAAe,SAAU,MAAM,wEAmB1C,CAAC"}
|
package/dist/pglite/index.d.ts
CHANGED
|
@@ -21,9 +21,9 @@ export declare const createPgliteFromDump: (opts: {
|
|
|
21
21
|
dumpPath: string;
|
|
22
22
|
}) => Effect.Effect<PGlite, PgliteError | import("effect/PlatformError").PlatformError, FileSystem>;
|
|
23
23
|
export declare const dumpPgliteToFile: (client: PGlite, dest: string) => Effect.Effect<void, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
|
|
24
|
-
export declare const migratePglite: (client: PGlite, migrations: PgliteMigrations) => Effect.Effect<void, PgliteError, never>;
|
|
24
|
+
export declare const migratePglite: (client: PGlite, migrations: PgliteMigrations) => Effect.Effect<void | import("drizzle-orm/migrator").MigratorInitFailResponse, PgliteError, never>;
|
|
25
25
|
export declare const getDbMigrationCount: (client: PGlite, migrations?: Pick<PgliteMigrations, 'migrationsTable' | 'migrationsSchema'>) => Effect.Effect<number, PgliteError, never>;
|
|
26
|
-
export declare const getExpectedMigrationCount: (migrationsFolder: string) => Effect.Effect<number, PgliteError
|
|
26
|
+
export declare const getExpectedMigrationCount: (migrationsFolder: string) => Effect.Effect<number, PgliteError, never>;
|
|
27
27
|
export declare const buildPgliteDump: (opts: PgliteMigrations & {
|
|
28
28
|
dumpPath: string;
|
|
29
29
|
}) => Effect.Effect<void, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAI9C,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;AAElD,qBAAa,WAAY,SAAQ,iBAAgC;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;CAAG;AAQL,MAAM,MAAM,gBAAgB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAwBF,eAAO,MAAM,oBAAoB,SAAU;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB,kGAsBE,CAAC;AAeJ,eAAO,MAAM,gBAAgB,WAAY,MAAM,QAAQ,MAAM,uGAmC1D,CAAC;AAEJ,eAAO,MAAM,aAAa,WAAY,MAAM,cAAc,gBAAgB,sGAavE,CAAC;AAYJ,eAAO,MAAM,mBAAmB,WACvB,MAAM,eACD,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,8CA4DzE,CAAC;AAEJ,eAAO,MAAM,yBAAyB,qBAAsB,MAAM,8CAQ/D,CAAC;AAEJ,eAAO,MAAM,eAAe,SACrB,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,uGAO3C,CAAC;AAEJ,eAAO,MAAM,gBAAgB,SACtB,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,uGAQ3C,CAAC;AAEJ,eAAO,MAAM,cAAc,SACpB,gBAAgB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,yGAwB5D,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,YACvB,UAAU,QACb,gBAAgB;;;iFAYpB,CAAC"}
|
package/dist/pglite/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/pglite/index.ts
|
|
2
2
|
import { PGlite } from "@electric-sql/pglite";
|
|
3
|
+
import { readMigrationFiles } from "drizzle-orm/migrator";
|
|
3
4
|
import { drizzle } from "drizzle-orm/pglite";
|
|
4
5
|
import { migrate } from "drizzle-orm/pglite/migrator";
|
|
5
6
|
import { Data, Effect } from "effect";
|
|
@@ -62,10 +63,21 @@ var dumpPgliteToFile = (client, dest) => Effect.gen(function* () {
|
|
|
62
63
|
})
|
|
63
64
|
});
|
|
64
65
|
const data = yield* toUint8Array(dump);
|
|
65
|
-
yield*
|
|
66
|
+
const tempName = yield* Effect.sync(
|
|
67
|
+
() => `.${path.basename(dest)}.${crypto.randomUUID()}.tmp`
|
|
68
|
+
);
|
|
69
|
+
const tempPath = path.join(destDir, tempName);
|
|
70
|
+
yield* Effect.gen(function* () {
|
|
71
|
+
yield* fs.writeFile(tempPath, data);
|
|
72
|
+
yield* fs.rename(tempPath, dest);
|
|
73
|
+
}).pipe(
|
|
74
|
+
Effect.onError(
|
|
75
|
+
() => fs.remove(tempPath, { force: true }).pipe(Effect.orDie)
|
|
76
|
+
)
|
|
77
|
+
);
|
|
66
78
|
});
|
|
67
79
|
var migratePglite = (client, migrations) => Effect.tryPromise({
|
|
68
|
-
try: () => migrate(drizzle(client), {
|
|
80
|
+
try: () => migrate(drizzle({ client }), {
|
|
69
81
|
migrationsFolder: migrations.migrationsFolder,
|
|
70
82
|
migrationsTable: migrations.migrationsTable,
|
|
71
83
|
migrationsSchema: migrations.migrationsSchema
|
|
@@ -131,34 +143,12 @@ var getDbMigrationCount = (client, migrations) => Effect.gen(function* () {
|
|
|
131
143
|
}
|
|
132
144
|
return countRow.c;
|
|
133
145
|
});
|
|
134
|
-
var getExpectedMigrationCount = (migrationsFolder) => Effect.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return yield* Effect.fail(
|
|
141
|
-
new PgliteError({
|
|
142
|
-
message: `Migration journal not found at ${journalPath}`
|
|
143
|
-
})
|
|
144
|
-
);
|
|
145
|
-
}
|
|
146
|
-
const content = yield* fs.readFileString(journalPath);
|
|
147
|
-
const journal = yield* Effect.try({
|
|
148
|
-
try: () => JSON.parse(content),
|
|
149
|
-
catch: (cause) => new PgliteError({
|
|
150
|
-
message: `Failed to parse migration journal at ${journalPath}`,
|
|
151
|
-
cause
|
|
152
|
-
})
|
|
153
|
-
});
|
|
154
|
-
if (!Array.isArray(journal.entries)) {
|
|
155
|
-
return yield* Effect.fail(
|
|
156
|
-
new PgliteError({
|
|
157
|
-
message: `Migration journal at ${journalPath} is missing an "entries" array`
|
|
158
|
-
})
|
|
159
|
-
);
|
|
160
|
-
}
|
|
161
|
-
return journal.entries.length;
|
|
146
|
+
var getExpectedMigrationCount = (migrationsFolder) => Effect.try({
|
|
147
|
+
try: () => readMigrationFiles({ migrationsFolder }).length,
|
|
148
|
+
catch: (cause) => new PgliteError({
|
|
149
|
+
message: `Failed to read migrations from ${migrationsFolder}`,
|
|
150
|
+
cause
|
|
151
|
+
})
|
|
162
152
|
});
|
|
163
153
|
var buildPgliteDump = (opts) => Effect.gen(function* () {
|
|
164
154
|
const client = new PGlite(IN_MEMORY_DATA_DIR);
|