devsess 0.4.0 → 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/dist/async/index.js +2 -2
- package/dist/{chunk-SX5HBQHG.js → chunk-KG24ZAKO.js} +20 -80
- package/dist/chunk-KG24ZAKO.js.map +1 -0
- package/dist/{chunk-GX4J6JR3.js → chunk-MBPIOYW3.js} +157 -9
- 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-CBRTTFXG.js → chunk-UOIMVHGX.js} +2 -2
- 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-sessions.d.ts +2 -0
- package/dist/dev-sessions.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/lock.d.ts +3 -0
- package/dist/lock.d.ts.map +1 -0
- package/dist/services/container.d.ts.map +1 -1
- package/dist/services/core.d.ts +12 -0
- package/dist/services/core.d.ts.map +1 -1
- package/dist/services/index.d.ts +9 -4
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +119 -52
- package/dist/services/index.js.map +1 -1
- 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 +4 -2
- package/dist/chunk-GX4J6JR3.js.map +0 -1
- package/dist/chunk-SX5HBQHG.js.map +0 -1
- /package/dist/{chunk-CBRTTFXG.js.map → chunk-UOIMVHGX.js.map} +0 -0
package/dist/async/index.js
CHANGED
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
resolveSiblingDir,
|
|
5
5
|
runManagedSubprocess,
|
|
6
6
|
runningSignalPath
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-KG24ZAKO.js";
|
|
8
8
|
import {
|
|
9
9
|
DevSessions,
|
|
10
10
|
SessionState,
|
|
11
11
|
SessionStateError,
|
|
12
12
|
getStickyPort
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-MBPIOYW3.js";
|
|
14
14
|
|
|
15
15
|
// src/async/index.ts
|
|
16
16
|
import { Schema } from "effect";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DevSessions
|
|
3
|
-
|
|
2
|
+
DevSessions,
|
|
3
|
+
readDaemonIdentity,
|
|
4
|
+
sendDaemonRequest
|
|
5
|
+
} from "./chunk-MBPIOYW3.js";
|
|
4
6
|
|
|
5
7
|
// src/dev/running-signal.ts
|
|
6
8
|
import { watch as fsWatch, realpathSync } from "fs";
|
|
@@ -11,97 +13,35 @@ import { FileSystem } from "effect/FileSystem";
|
|
|
11
13
|
import { Path } from "effect/Path";
|
|
12
14
|
|
|
13
15
|
// src/dev/daemon-readiness.ts
|
|
14
|
-
import { createConnection } from "net";
|
|
15
|
-
import { StringDecoder } from "string_decoder";
|
|
16
16
|
import { Effect, Exit, Schema } from "effect";
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
})
|
|
27
|
-
);
|
|
28
|
-
var sendReadiness = (identity, request) => Effect.tryPromise({
|
|
29
|
-
try: () => new Promise((resolve2, reject) => {
|
|
30
|
-
const socket = createConnection(identity.socketPath);
|
|
31
|
-
const decoder = new StringDecoder("utf8");
|
|
32
|
-
let input = "";
|
|
33
|
-
let settled = false;
|
|
34
|
-
const finish = (complete) => {
|
|
35
|
-
if (settled) return;
|
|
36
|
-
settled = true;
|
|
37
|
-
clearTimeout(timer);
|
|
38
|
-
socket.destroy();
|
|
39
|
-
complete();
|
|
40
|
-
};
|
|
41
|
-
const timer = setTimeout(
|
|
42
|
-
() => finish(
|
|
43
|
-
() => reject(new Error("Daemon readiness request timed out"))
|
|
44
|
-
),
|
|
45
|
-
RESPONSE_TIMEOUT_MS
|
|
46
|
-
);
|
|
47
|
-
socket.once(
|
|
48
|
-
"connect",
|
|
49
|
-
() => socket.write(`${JSON.stringify(request)}
|
|
50
|
-
`)
|
|
51
|
-
);
|
|
52
|
-
socket.on("data", (chunk) => {
|
|
53
|
-
input += decoder.write(chunk);
|
|
54
|
-
if (Buffer.byteLength(input) > MAX_RESPONSE_BYTES) {
|
|
55
|
-
finish(
|
|
56
|
-
() => reject(new Error("Daemon readiness response is too large"))
|
|
57
|
-
);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
const boundary = input.indexOf("\n");
|
|
61
|
-
if (boundary !== -1) finish(() => resolve2(input.slice(0, boundary)));
|
|
62
|
-
});
|
|
63
|
-
socket.once("error", (cause) => finish(() => reject(cause)));
|
|
64
|
-
socket.once(
|
|
65
|
-
"close",
|
|
66
|
-
() => finish(
|
|
67
|
-
() => reject(new Error("Daemon closed before acknowledging readiness"))
|
|
68
|
-
)
|
|
69
|
-
);
|
|
70
|
-
}),
|
|
71
|
-
catch: (cause) => new Error("Could not report readiness to daemon", { cause })
|
|
72
|
-
}).pipe(
|
|
73
|
-
Effect.flatMap(Schema.decodeUnknownEffect(DaemonResponse)),
|
|
74
|
-
Effect.flatMap(
|
|
75
|
-
(response) => response.requestId === request.requestId && response.ok ? Effect.void : Effect.fail(new Error("Daemon did not acknowledge readiness"))
|
|
76
|
-
)
|
|
77
|
-
);
|
|
78
|
-
var publishDaemonReadiness = (value) => Effect.suspend(() => {
|
|
79
|
-
const socketPath = process.env.DEVSESS_SOCKET;
|
|
80
|
-
const runId = process.env.DEVSESS_RUN_ID;
|
|
81
|
-
const service = process.env.DEVSESS_SERVICE;
|
|
82
|
-
if (socketPath === void 0 || runId === void 0 || service === void 0)
|
|
83
|
-
return Effect.void;
|
|
84
|
-
const identity = { socketPath, runId, service };
|
|
85
|
-
return Effect.acquireRelease(
|
|
17
|
+
var publishDaemonReadiness = (value) => Effect.gen(function* () {
|
|
18
|
+
const identity = yield* readDaemonIdentity;
|
|
19
|
+
if (identity === void 0) return;
|
|
20
|
+
const params = {
|
|
21
|
+
runId: identity.runId,
|
|
22
|
+
service: identity.service,
|
|
23
|
+
...identity.instanceId === void 0 ? {} : { instanceId: identity.instanceId }
|
|
24
|
+
};
|
|
25
|
+
yield* Effect.acquireRelease(
|
|
86
26
|
Schema.decodeUnknownEffect(Schema.Json)(value).pipe(
|
|
87
27
|
Effect.flatMap(
|
|
88
|
-
(json) =>
|
|
28
|
+
(json) => sendDaemonRequest(identity, {
|
|
89
29
|
version: 1,
|
|
90
30
|
requestId: crypto.randomUUID(),
|
|
91
31
|
method: "publish",
|
|
92
|
-
params: {
|
|
32
|
+
params: { ...params, value: json }
|
|
93
33
|
})
|
|
94
34
|
),
|
|
95
35
|
Effect.exit
|
|
96
36
|
),
|
|
97
|
-
(result) => Exit.isSuccess(result) ?
|
|
37
|
+
(result) => Exit.isSuccess(result) ? sendDaemonRequest(identity, {
|
|
98
38
|
version: 1,
|
|
99
39
|
requestId: crypto.randomUUID(),
|
|
100
40
|
method: "unpublish",
|
|
101
|
-
params
|
|
41
|
+
params
|
|
102
42
|
}).pipe(Effect.catch(() => Effect.void)) : Effect.void
|
|
103
|
-
)
|
|
104
|
-
});
|
|
43
|
+
);
|
|
44
|
+
}).pipe(Effect.catch(() => Effect.void));
|
|
105
45
|
|
|
106
46
|
// src/dev/running-signal.ts
|
|
107
47
|
var RUNNING_SIGNAL_FILE = ".data/running.json";
|
|
@@ -223,4 +163,4 @@ export {
|
|
|
223
163
|
awaitRunning,
|
|
224
164
|
runManagedSubprocess
|
|
225
165
|
};
|
|
226
|
-
//# sourceMappingURL=chunk-
|
|
166
|
+
//# sourceMappingURL=chunk-KG24ZAKO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev/running-signal.ts","../src/dev/daemon-readiness.ts","../src/dev/subprocess.ts"],"sourcesContent":["import { watch as fsWatch, realpathSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join, resolve } from 'node:path';\nimport { Deferred, Effect } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport { DevSessions } from '../dev-sessions';\nimport { publishDaemonReadiness } from './daemon-readiness';\n\nconst RUNNING_SIGNAL_FILE = '.data/running.json';\n\n/** Path to the running-signal file for a dev-session (or sibling package) directory. */\nexport const runningSignalPath = (dir: string) =>\n\tjoin(dir, RUNNING_SIGNAL_FILE);\n\n/**\n * Resolves `spec` to a directory: relative/absolute paths are resolved against\n * `fromDir`, anything else is treated as a package name and resolved via its\n * `package.json`.\n */\nexport const resolveSiblingDir = (spec: string, fromDir: string) => {\n\tif (spec.startsWith('.') || spec.startsWith('/')) {\n\t\treturn resolve(fromDir, spec);\n\t}\n\tconst require = createRequire(join(fromDir, 'package.json'));\n\tconst pkgJsonPath = require.resolve(`${spec}/package.json`);\n\treturn dirname(realpathSync(pkgJsonPath));\n};\n\n/** Atomically writes `value` as JSON to `filePath` and removes it on release. */\nexport const publishRunningSignal = (filePath: string, value: unknown) =>\n\tEffect.acquireRelease(\n\t\tEffect.gen(function* () {\n\t\t\tconst fs = yield* FileSystem;\n\t\t\tconst path = yield* Path;\n\t\t\tconst tmp = `${filePath}.tmp`;\n\t\t\tyield* fs.makeDirectory(path.dirname(filePath), { recursive: true });\n\t\t\t// Write to a temp file then rename atomically so readers never see a partial file.\n\t\t\tyield* fs.writeFileString(tmp, JSON.stringify(value));\n\t\t\tyield* fs.rename(tmp, filePath);\n\t\t}),\n\t\t() =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst fs = yield* FileSystem;\n\t\t\t\tyield* fs.remove(filePath).pipe(Effect.catch(() => Effect.void));\n\t\t\t}),\n\t);\n\n/** Watches parent directory for the signal file and resolves once it can be parsed. */\nexport const awaitRunningSignal = <T>(\n\tfilePath: string,\n\topts: { parse: (raw: string) => T },\n) =>\n\tEffect.scoped(\n\t\tEffect.gen(function* () {\n\t\t\tconst fs = yield* FileSystem;\n\t\t\tconst path = yield* Path;\n\t\t\tconst dir = path.dirname(filePath);\n\t\t\tconst filename = path.basename(filePath);\n\n\t\t\tconst deferred = yield* Deferred.make<T>();\n\n\t\t\tconst tryRead = Effect.gen(function* () {\n\t\t\t\tif (!(yield* fs.exists(filePath))) return false;\n\t\t\t\tconst raw = yield* fs\n\t\t\t\t\t.readFileString(filePath)\n\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed(null)));\n\t\t\t\tif (raw == null) return false;\n\t\t\t\tconst parsed = yield* Effect.try(() => opts.parse(raw)).pipe(\n\t\t\t\t\tEffect.catch(() => Effect.succeed(null)),\n\t\t\t\t);\n\t\t\t\tif (parsed == null) return false;\n\t\t\t\tyield* Deferred.succeed(deferred, parsed);\n\t\t\t\treturn true;\n\t\t\t});\n\n\t\t\t// fsWatch throws synchronously if `dir` doesn't exist yet — e.g. a sibling\n\t\t\t// package's dev script has never run — so ensure it's there first.\n\t\t\tyield* fs.makeDirectory(dir, { recursive: true });\n\n\t\t\tyield* Effect.acquireRelease(\n\t\t\t\tEffect.sync(() =>\n\t\t\t\t\t// Watch parent dir — the file may not exist yet, and watching a missing file errors.\n\t\t\t\t\tfsWatch(dir, { recursive: false }, (eventType, eventFilename) => {\n\t\t\t\t\t\tif (eventFilename !== filename) return;\n\t\t\t\t\t\tif (eventType !== 'rename' && eventType !== 'change') return;\n\t\t\t\t\t\tEffect.runFork(tryRead);\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\t(watcher) => Effect.sync(() => watcher.close()),\n\t\t\t);\n\n\t\t\tyield* tryRead;\n\t\t\treturn yield* Deferred.await(deferred);\n\t\t}),\n\t);\n\n/**\n * Publishes `value` at the project root's running-signal file, so a sibling package's\n * dev script can `awaitRunning` it. Removed when the enclosing scope closes.\n */\nexport const publishRunning = (value: unknown) =>\n\tEffect.gen(function* () {\n\t\tconst sessions = yield* DevSessions;\n\t\tyield* publishRunningSignal(runningSignalPath(sessions.dir), value);\n\t\tyield* publishDaemonReadiness(value);\n\t});\n\n/**\n * Awaits the running-signal file of another package in the workspace (`pkg`, resolved\n * relative to the project root the same way `resolveSiblingDir` resolves any spec).\n */\nexport const awaitRunning = <T>(pkg: string) =>\n\tEffect.gen(function* () {\n\t\tconst sessions = yield* DevSessions;\n\t\treturn yield* awaitRunningSignal<T>(\n\t\t\trunningSignalPath(resolveSiblingDir(pkg, sessions.dir)),\n\t\t\t{ parse: (raw) => JSON.parse(raw) as T },\n\t\t);\n\t});\n","import { Effect, Exit, Schema } from 'effect';\nimport { readDaemonIdentity, sendDaemonRequest } from './daemon-client';\n\nexport const publishDaemonReadiness = (value: unknown) =>\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\t...(identity.instanceId === undefined\n\t\t\t\t? {}\n\t\t\t\t: { instanceId: identity.instanceId }),\n\t\t};\n\t\tyield* Effect.acquireRelease(\n\t\t\tSchema.decodeUnknownEffect(Schema.Json)(value).pipe(\n\t\t\t\tEffect.flatMap((json) =>\n\t\t\t\t\tsendDaemonRequest(identity, {\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\trequestId: crypto.randomUUID(),\n\t\t\t\t\t\tmethod: 'publish',\n\t\t\t\t\t\tparams: { ...params, value: json },\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\tEffect.exit,\n\t\t\t),\n\t\t\t(result) =>\n\t\t\t\tExit.isSuccess(result)\n\t\t\t\t\t? sendDaemonRequest(identity, {\n\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\trequestId: crypto.randomUUID(),\n\t\t\t\t\t\t\tmethod: 'unpublish',\n\t\t\t\t\t\t\tparams,\n\t\t\t\t\t\t}).pipe(Effect.catch(() => Effect.void))\n\t\t\t\t\t: Effect.void,\n\t\t);\n\t}).pipe(Effect.catch(() => Effect.void));\n","import { Effect } from 'effect';\nimport { ChildProcess } from 'effect/process';\n\nexport const runManagedSubprocess = (\n\tcmd: string,\n\targs: string[],\n\topts?: { env?: Record<string, string> },\n) =>\n\tEffect.gen(function* () {\n\t\tconst command = ChildProcess.make(cmd, args, {\n\t\t\t// Keep children in the caller's group so its supervisor can signal them together.\n\t\t\tdetached: false,\n\t\t\tstdin: 'inherit',\n\t\t\tstdout: 'inherit',\n\t\t\tstderr: 'inherit',\n\t\t\tenv: { ...process.env, ...(opts?.env ?? {}) },\n\t\t});\n\n\t\tconst label = [cmd, ...args].join(' ');\n\n\t\t// Registers against the ambient scope, not a scope of its own — the\n\t\t// child must outlive this call (it doesn't resolve until the child\n\t\t// exits) and get killed only when the caller's scope closes.\n\t\tconst child = yield* Effect.acquireRelease(\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst proc = yield* command;\n\t\t\t\tyield* Effect.logInfo(`[dev] started: ${label} (pid=${proc.pid})`);\n\t\t\t\treturn proc;\n\t\t\t}),\n\t\t\t(proc) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tif (!(yield* proc.isRunning.pipe(Effect.orDie))) return;\n\t\t\t\t\tyield* Effect.logInfo(`[dev] stopping: ${label} (pid=${proc.pid})`);\n\t\t\t\t\tyield* proc.kill().pipe(\n\t\t\t\t\t\tEffect.catch((err) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tif (yield* proc.isRunning.pipe(Effect.orDie))\n\t\t\t\t\t\t\t\t\tyield* Effect.logError(\n\t\t\t\t\t\t\t\t\t\t`[dev] failed to stop ${label} (pid=${proc.pid}): ${err}`,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t);\n\n\t\treturn yield* child.exitCode;\n\t});\n"],"mappings":"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","names":["Effect","require","Effect","Effect"]}
|
|
@@ -7,6 +7,7 @@ var DevSession;
|
|
|
7
7
|
((DevSession2) => {
|
|
8
8
|
function make(input) {
|
|
9
9
|
return {
|
|
10
|
+
rootDir: input.rootDir,
|
|
10
11
|
name: input.name,
|
|
11
12
|
lastModifiedAt: input.lastModifiedAt,
|
|
12
13
|
path: (relativePath) => Effect.succeed(input.pathJoin(relativePath)),
|
|
@@ -60,7 +61,7 @@ var findProjectRoot = Effect.gen(function* () {
|
|
|
60
61
|
});
|
|
61
62
|
return yield* walkUp(startDir);
|
|
62
63
|
});
|
|
63
|
-
var buildDevSessionsCore = (sessionsDir) => Effect.gen(function* () {
|
|
64
|
+
var buildDevSessionsCore = (sessionsDir, rootDir) => Effect.gen(function* () {
|
|
64
65
|
const fs = yield* FileSystem;
|
|
65
66
|
const path = yield* Path;
|
|
66
67
|
yield* Effect.logDebug(`DevSessions dir: ${sessionsDir}`);
|
|
@@ -75,7 +76,7 @@ var buildDevSessionsCore = (sessionsDir) => Effect.gen(function* () {
|
|
|
75
76
|
DevSession.make({
|
|
76
77
|
name: entry,
|
|
77
78
|
lastModifiedAt: Option.getOrNull(stat.mtime),
|
|
78
|
-
rootDir
|
|
79
|
+
rootDir,
|
|
79
80
|
pathJoin: (relativePath) => path.join(sessionsDir, entry, relativePath)
|
|
80
81
|
})
|
|
81
82
|
);
|
|
@@ -93,7 +94,7 @@ var buildDevSessionsCore = (sessionsDir) => Effect.gen(function* () {
|
|
|
93
94
|
return DevSession.make({
|
|
94
95
|
name: slug,
|
|
95
96
|
lastModifiedAt: null,
|
|
96
|
-
rootDir
|
|
97
|
+
rootDir,
|
|
97
98
|
pathJoin: (relativePath) => path.join(sessionsDir, slug, relativePath)
|
|
98
99
|
});
|
|
99
100
|
});
|
|
@@ -109,14 +110,25 @@ var buildDevSessionsCore = (sessionsDir) => Effect.gen(function* () {
|
|
|
109
110
|
}
|
|
110
111
|
return yield* createSession;
|
|
111
112
|
});
|
|
112
|
-
|
|
113
|
+
const getOrCreate = (name) => Effect.gen(function* () {
|
|
114
|
+
yield* fs.makeDirectory(path.join(sessionsDir, name), {
|
|
115
|
+
recursive: true
|
|
116
|
+
});
|
|
117
|
+
return DevSession.make({
|
|
118
|
+
name,
|
|
119
|
+
rootDir,
|
|
120
|
+
lastModifiedAt: null,
|
|
121
|
+
pathJoin: (relativePath) => path.join(sessionsDir, name, relativePath)
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
return { getSessions, createSession, getLatestOrCreate, getOrCreate };
|
|
113
125
|
});
|
|
114
126
|
var buildDevSessionsLayer = (rootDir) => Layer.effect(
|
|
115
127
|
DevSessions,
|
|
116
128
|
Effect.gen(function* () {
|
|
117
129
|
const path = yield* Path;
|
|
118
130
|
const sessionsDir = path.join(rootDir, ".data", "sessions");
|
|
119
|
-
const core = yield* buildDevSessionsCore(sessionsDir);
|
|
131
|
+
const core = yield* buildDevSessionsCore(sessionsDir, rootDir);
|
|
120
132
|
return {
|
|
121
133
|
dir: rootDir,
|
|
122
134
|
path: (relativePath) => path.join(rootDir, relativePath),
|
|
@@ -178,9 +190,31 @@ var SessionState;
|
|
|
178
190
|
})(SessionState || (SessionState = {}));
|
|
179
191
|
|
|
180
192
|
// src/dev/sticky-port.ts
|
|
181
|
-
import { Effect as
|
|
193
|
+
import { Effect as Effect4 } from "effect";
|
|
194
|
+
import { FileSystem as FileSystem3 } from "effect/FileSystem";
|
|
195
|
+
import { Path as Path3 } from "effect/Path";
|
|
182
196
|
import * as S2 from "effect/Schema";
|
|
183
197
|
import getPort from "get-port";
|
|
198
|
+
|
|
199
|
+
// src/lock.ts
|
|
200
|
+
import { Effect as Effect3, Schedule } from "effect";
|
|
201
|
+
import lockfile from "proper-lockfile";
|
|
202
|
+
var acquireFileLock = (file, lockPath = `${file}.lock`) => Effect3.tryPromise({
|
|
203
|
+
try: () => lockfile.lock(file, {
|
|
204
|
+
realpath: false,
|
|
205
|
+
lockfilePath: lockPath,
|
|
206
|
+
stale: 6e4,
|
|
207
|
+
retries: 0
|
|
208
|
+
}),
|
|
209
|
+
catch: (cause) => new Error(`Failed to lock ${file}`, { cause })
|
|
210
|
+
}).pipe(
|
|
211
|
+
Effect3.retry({
|
|
212
|
+
while: (error) => typeof error.cause === "object" && error.cause !== null && "code" in error.cause && error.cause.code === "ELOCKED",
|
|
213
|
+
schedule: Schedule.spaced("50 millis")
|
|
214
|
+
})
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
// src/dev/sticky-port.ts
|
|
184
218
|
var DEFAULT_NAME = "default";
|
|
185
219
|
var StickyPorts = SessionState.slot(
|
|
186
220
|
S2.Struct({
|
|
@@ -188,13 +222,28 @@ var StickyPorts = SessionState.slot(
|
|
|
188
222
|
port: S2.optional(S2.Number)
|
|
189
223
|
})
|
|
190
224
|
);
|
|
191
|
-
var getStickyPort = (session, options) =>
|
|
225
|
+
var getStickyPort = (session, options) => Effect4.gen(function* () {
|
|
192
226
|
const name = options?.name ?? DEFAULT_NAME;
|
|
227
|
+
const fs = yield* FileSystem3;
|
|
228
|
+
const path = yield* Path3;
|
|
229
|
+
const statePath = yield* session.path("sess.json");
|
|
230
|
+
yield* fs.makeDirectory(path.dirname(statePath), { recursive: true });
|
|
231
|
+
yield* Effect4.acquireRelease(
|
|
232
|
+
acquireFileLock(statePath).pipe(
|
|
233
|
+
Effect4.mapError(
|
|
234
|
+
(cause) => new SessionStateError({
|
|
235
|
+
message: "Failed to lock sticky ports",
|
|
236
|
+
cause
|
|
237
|
+
})
|
|
238
|
+
)
|
|
239
|
+
),
|
|
240
|
+
(release) => Effect4.promise(() => release())
|
|
241
|
+
);
|
|
193
242
|
const file = yield* StickyPorts.read(session);
|
|
194
243
|
const ports = file?.ports ?? (file?.port !== void 0 ? { [DEFAULT_NAME]: file.port } : {});
|
|
195
244
|
const preferred = ports[name];
|
|
196
245
|
const exclude = Object.entries(ports).filter((entry) => entry[0] !== name).map((entry) => entry[1]);
|
|
197
|
-
const port = yield*
|
|
246
|
+
const port = yield* Effect4.promise(
|
|
198
247
|
async () => getPort({
|
|
199
248
|
port: preferred !== void 0 ? [preferred] : void 0,
|
|
200
249
|
...exclude.length > 0 ? { exclude } : {}
|
|
@@ -202,13 +251,112 @@ var getStickyPort = (session, options) => Effect3.gen(function* () {
|
|
|
202
251
|
);
|
|
203
252
|
yield* StickyPorts.write(session, { ports: { ...ports, [name]: port } });
|
|
204
253
|
return port;
|
|
254
|
+
}).pipe(Effect4.scoped);
|
|
255
|
+
|
|
256
|
+
// src/socket-line.ts
|
|
257
|
+
import { StringDecoder } from "string_decoder";
|
|
258
|
+
var readSocketLine = (socket, maxBytes = 1048576) => new Promise((resolve, reject) => {
|
|
259
|
+
const decoder = new StringDecoder("utf8");
|
|
260
|
+
const state = { input: "", bytes: 0 };
|
|
261
|
+
const cleanup = () => {
|
|
262
|
+
socket.removeListener("data", data);
|
|
263
|
+
socket.removeListener("error", error);
|
|
264
|
+
socket.removeListener("close", closed);
|
|
265
|
+
};
|
|
266
|
+
const error = (cause) => {
|
|
267
|
+
cleanup();
|
|
268
|
+
reject(cause);
|
|
269
|
+
};
|
|
270
|
+
const closed = () => error(new Error("Socket closed before sending a ready line"));
|
|
271
|
+
const data = (chunk) => {
|
|
272
|
+
const boundary = chunk.indexOf(10);
|
|
273
|
+
const part = boundary < 0 ? chunk : chunk.subarray(0, boundary);
|
|
274
|
+
state.bytes += part.length;
|
|
275
|
+
if (state.bytes > maxBytes)
|
|
276
|
+
return error(new Error("Socket line exceeds byte limit"));
|
|
277
|
+
state.input += decoder.write(part);
|
|
278
|
+
if (boundary >= 0) {
|
|
279
|
+
cleanup();
|
|
280
|
+
resolve(state.input + decoder.end());
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
socket.on("data", data);
|
|
284
|
+
socket.once("error", error);
|
|
285
|
+
socket.once("close", closed);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// src/dev/daemon-client.ts
|
|
289
|
+
import { createConnection } from "net";
|
|
290
|
+
import { Config, ConfigProvider, Effect as Effect5, Option as Option2, Schema } from "effect";
|
|
291
|
+
var RESPONSE_TIMEOUT_MS = 5e3;
|
|
292
|
+
var MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
293
|
+
var DaemonResponse = Schema.fromJsonString(
|
|
294
|
+
Schema.Struct({
|
|
295
|
+
version: Schema.Literal(1),
|
|
296
|
+
requestId: Schema.NonEmptyString,
|
|
297
|
+
ok: Schema.Boolean,
|
|
298
|
+
result: Schema.optional(Schema.Unknown),
|
|
299
|
+
error: Schema.optional(Schema.String)
|
|
300
|
+
})
|
|
301
|
+
);
|
|
302
|
+
var readDaemonIdentity = Effect5.gen(function* () {
|
|
303
|
+
const provider = ConfigProvider.fromEnv();
|
|
304
|
+
const read2 = (key) => Config.String(key).pipe(Config.option).parse(provider).pipe(Effect5.map(Option2.getOrUndefined));
|
|
305
|
+
const socketPath = yield* read2("DEVSESS_SOCKET");
|
|
306
|
+
const runId = yield* read2("DEVSESS_RUN_ID");
|
|
307
|
+
const service = yield* read2("DEVSESS_SERVICE");
|
|
308
|
+
const instanceId = yield* read2("DEVSESS_INSTANCE_ID");
|
|
309
|
+
if (socketPath === void 0 || runId === void 0 || service === void 0)
|
|
310
|
+
return void 0;
|
|
311
|
+
return {
|
|
312
|
+
socketPath,
|
|
313
|
+
runId,
|
|
314
|
+
service,
|
|
315
|
+
...instanceId === void 0 ? {} : { instanceId }
|
|
316
|
+
};
|
|
205
317
|
});
|
|
318
|
+
var sendDaemonRequest = (identity, request, timeoutMs = RESPONSE_TIMEOUT_MS) => Effect5.tryPromise({
|
|
319
|
+
try: () => new Promise((resolve, reject) => {
|
|
320
|
+
const socket = createConnection(identity.socketPath);
|
|
321
|
+
let settled = false;
|
|
322
|
+
const finish = (complete) => {
|
|
323
|
+
if (settled) return;
|
|
324
|
+
settled = true;
|
|
325
|
+
clearTimeout(timer);
|
|
326
|
+
socket.destroy();
|
|
327
|
+
complete();
|
|
328
|
+
};
|
|
329
|
+
const timer = setTimeout(
|
|
330
|
+
() => finish(() => reject(new Error("Daemon request timed out"))),
|
|
331
|
+
timeoutMs
|
|
332
|
+
);
|
|
333
|
+
socket.once(
|
|
334
|
+
"connect",
|
|
335
|
+
() => socket.write(`${JSON.stringify(request)}
|
|
336
|
+
`)
|
|
337
|
+
);
|
|
338
|
+
readSocketLine(socket, MAX_RESPONSE_BYTES).then(
|
|
339
|
+
(line) => finish(() => resolve(line)),
|
|
340
|
+
(cause) => finish(() => reject(cause))
|
|
341
|
+
);
|
|
342
|
+
}),
|
|
343
|
+
catch: (cause) => new Error("Could not send request to daemon", { cause })
|
|
344
|
+
}).pipe(
|
|
345
|
+
Effect5.flatMap(Schema.decodeUnknownEffect(DaemonResponse)),
|
|
346
|
+
Effect5.flatMap(
|
|
347
|
+
(response) => response.requestId === request.requestId && response.ok ? Effect5.void : Effect5.fail(new Error("Daemon did not acknowledge request"))
|
|
348
|
+
)
|
|
349
|
+
);
|
|
206
350
|
|
|
207
351
|
export {
|
|
208
352
|
DevSessions,
|
|
209
353
|
ProjectRootNotFoundError,
|
|
354
|
+
readSocketLine,
|
|
355
|
+
readDaemonIdentity,
|
|
356
|
+
sendDaemonRequest,
|
|
210
357
|
SessionStateError,
|
|
211
358
|
SessionState,
|
|
359
|
+
acquireFileLock,
|
|
212
360
|
getStickyPort
|
|
213
361
|
};
|
|
214
|
-
//# sourceMappingURL=chunk-
|
|
362
|
+
//# sourceMappingURL=chunk-MBPIOYW3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev-sessions.ts","../src/dev/session-state.ts","../src/dev/sticky-port.ts","../src/lock.ts","../src/socket-line.ts","../src/dev/daemon-client.ts"],"sourcesContent":["import { Array as A, Context, Data, Effect, Layer, Option } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport type { PlatformError } from 'effect/PlatformError';\nimport { generateSlug } from 'random-word-slugs';\n\nnamespace DevSession {\n\ttype DevSessionInput = {\n\t\tname: string;\n\t\tlastModifiedAt: Date | null;\n\t\trootDir: string;\n\t\tpathJoin: (relativePath: string) => string;\n\t};\n\n\texport function make(input: DevSessionInput) {\n\t\treturn {\n\t\t\trootDir: input.rootDir,\n\t\t\tname: input.name,\n\t\t\tlastModifiedAt: input.lastModifiedAt,\n\t\t\tpath: (relativePath: string) =>\n\t\t\t\tEffect.succeed(input.pathJoin(relativePath)),\n\t\t\ttoString: () => input.name,\n\t\t};\n\t}\n}\n\nexport type DevSession = ReturnType<typeof DevSession.make>;\n\nexport class DevSessions extends Context.Service<\n\tDevSessions,\n\t{\n\t\treadonly dir: string;\n\t\treadonly path: (relativePath: string) => string;\n\t\treadonly getSessions: Effect.Effect<Array<DevSession>, PlatformError>;\n\t\treadonly createSession: Effect.Effect<DevSession, PlatformError>;\n\t\treadonly getLatestOrCreate: Effect.Effect<DevSession, PlatformError>;\n\t\treadonly getOrCreate: (\n\t\t\tname: string,\n\t\t) => Effect.Effect<DevSession, PlatformError>;\n\t}\n>()('devsess/DevSessions') {\n\t/**\n\t * `DevSessions` explicitly rooted at `rootDir`: `dir`/`path` resolve against `rootDir`\n\t * itself (e.g. `sessions.path('drizzle')` reaches a project's real `drizzle/` folder),\n\t * while session directories are namespaced under `<rootDir>/.data/sessions`.\n\t *\n\t * Deliberately does *not* also provide `CurrentSession` — a `Layer`'s build effect\n\t * runs as soon as it's provided, before anything downstream (e.g. `cli.Command.run`'s\n\t * argv parsing) gets a say. Bundling session resolution in here would create a\n\t * session for `--help`/`--version`/a bad flag too, since those never reach a command\n\t * handler at all. Provide `CurrentSession.layer` around the handler itself instead.\n\t */\n\tstatic readonly layerAt = (rootDir: string) => buildDevSessionsLayer(rootDir);\n\n\t/**\n\t * `DevSessions.layerAt` rooted at the auto-detected project root — the nearest\n\t * ancestor of `process.cwd()` containing a `package.json`.\n\t */\n\tstatic readonly layer: Layer.Layer<\n\t\tDevSessions,\n\t\tPlatformError | ProjectRootNotFoundError,\n\t\tFileSystem | Path\n\t> = Layer.unwrap(\n\t\tEffect.suspend(() =>\n\t\t\tEffect.map(findProjectRoot, (rootDir) => DevSessions.layerAt(rootDir)),\n\t\t),\n\t);\n}\n\n/**\n * Raised by `DevSessions.layer` when no ancestor of `searchedFrom` contains a\n * `package.json`. Failing loudly beats silently falling back to `process.cwd()` — a\n * wrong root means dev sessions get written to a surprising place.\n */\nexport class ProjectRootNotFoundError extends Data.TaggedError(\n\t'ProjectRootNotFoundError',\n)<{\n\treadonly searchedFrom: string;\n}> {}\n\n/** Walks up from `process.cwd()` to the nearest ancestor containing a `package.json`. */\nconst findProjectRoot = Effect.gen(function* () {\n\tconst fs = yield* FileSystem;\n\tconst path = yield* Path;\n\tconst startDir = process.cwd();\n\n\tconst walkUp = (\n\t\tdir: string,\n\t): Effect.Effect<string, PlatformError | ProjectRootNotFoundError> =>\n\t\tEffect.gen(function* () {\n\t\t\tif (yield* fs.exists(path.join(dir, 'package.json'))) {\n\t\t\t\treturn dir;\n\t\t\t}\n\t\t\tconst parent = path.dirname(dir);\n\t\t\tif (parent === dir) {\n\t\t\t\treturn yield* Effect.fail(\n\t\t\t\t\tnew ProjectRootNotFoundError({ searchedFrom: startDir }),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn yield* walkUp(parent);\n\t\t});\n\n\treturn yield* walkUp(startDir);\n});\n\n/** The listing/creation logic shared by every `DevSessions` layer, parameterized on the literal directory session subdirs live under. */\nconst buildDevSessionsCore = (sessionsDir: string, rootDir: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\t\tconst path = yield* Path;\n\n\t\tyield* Effect.logDebug(`DevSessions dir: ${sessionsDir}`);\n\n\t\tconst getSessions = Effect.gen(function* () {\n\t\t\tconst entries = yield* fs\n\t\t\t\t.readDirectory(sessionsDir)\n\t\t\t\t.pipe(Effect.catch(() => Effect.succeed([] as Array<string>)));\n\n\t\t\tconst possibleSessions = yield* Effect.all(\n\t\t\t\tentries.map((entry) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst stat = yield* fs.stat(path.join(sessionsDir, entry));\n\t\t\t\t\t\tif (stat.type !== 'Directory') return Option.none();\n\t\t\t\t\t\treturn Option.some(\n\t\t\t\t\t\t\tDevSession.make({\n\t\t\t\t\t\t\t\tname: entry,\n\t\t\t\t\t\t\t\tlastModifiedAt: Option.getOrNull(stat.mtime),\n\t\t\t\t\t\t\t\trootDir,\n\t\t\t\t\t\t\t\tpathJoin: (relativePath: string) =>\n\t\t\t\t\t\t\t\t\tpath.join(sessionsDir, entry, relativePath),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t\t{ concurrency: 'unbounded' },\n\t\t\t);\n\n\t\t\treturn A.getSomes(possibleSessions);\n\t\t});\n\n\t\tconst createSession = Effect.gen(function* () {\n\t\t\tconst slug = generateSlug(1, { partsOfSpeech: ['noun'] });\n\t\t\tyield* fs.makeDirectory(path.join(sessionsDir, slug), {\n\t\t\t\trecursive: true,\n\t\t\t});\n\t\t\treturn DevSession.make({\n\t\t\t\tname: slug,\n\t\t\t\tlastModifiedAt: null,\n\t\t\t\trootDir,\n\t\t\t\tpathJoin: (relativePath: string) =>\n\t\t\t\t\tpath.join(sessionsDir, slug, relativePath),\n\t\t\t});\n\t\t});\n\n\t\tconst getLatestOrCreate = Effect.gen(function* () {\n\t\t\tyield* fs.makeDirectory(sessionsDir, { recursive: true });\n\n\t\t\tconst sessions = yield* getSessions;\n\t\t\tif (sessions.length > 0) {\n\t\t\t\tsessions.sort(\n\t\t\t\t\t(a, b) =>\n\t\t\t\t\t\t(b.lastModifiedAt?.getTime() ?? 0) -\n\t\t\t\t\t\t(a.lastModifiedAt?.getTime() ?? 0),\n\t\t\t\t);\n\t\t\t\tconst latest = sessions[0];\n\t\t\t\treturn latest as DevSession;\n\t\t\t}\n\n\t\t\treturn yield* createSession;\n\t\t});\n\n\t\tconst getOrCreate = (name: string) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tyield* fs.makeDirectory(path.join(sessionsDir, name), {\n\t\t\t\t\trecursive: true,\n\t\t\t\t});\n\t\t\t\treturn DevSession.make({\n\t\t\t\t\tname,\n\t\t\t\t\trootDir,\n\t\t\t\t\tlastModifiedAt: null,\n\t\t\t\t\tpathJoin: (relativePath) =>\n\t\t\t\t\t\tpath.join(sessionsDir, name, relativePath),\n\t\t\t\t});\n\t\t\t});\n\t\treturn { getSessions, createSession, getLatestOrCreate, getOrCreate };\n\t});\n\n/**\n * The one `DevSessions` layer constructor: `dir`/`path` resolve against `rootDir`\n * itself, while session directories are namespaced under `<rootDir>/.data/sessions` —\n * the library owns that layout, so every caller (`DevSessions.layerAt`, the async\n * facade's `createDevSessions`) means the same thing by `rootDir`.\n */\nconst buildDevSessionsLayer = (rootDir: string) =>\n\tLayer.effect(\n\t\tDevSessions,\n\t\tEffect.gen(function* () {\n\t\t\tconst path = yield* Path;\n\t\t\tconst sessionsDir = path.join(rootDir, '.data', 'sessions');\n\t\t\tconst core = yield* buildDevSessionsCore(sessionsDir, rootDir);\n\t\t\treturn {\n\t\t\t\tdir: rootDir,\n\t\t\t\tpath: (relativePath: string) => path.join(rootDir, relativePath),\n\t\t\t\t...core,\n\t\t\t};\n\t\t}),\n\t);\n","import { Data, Effect } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport * as S from 'effect/Schema';\nimport type { DevSession } from '../dev-sessions';\n\nexport class SessionStateError extends Data.TaggedError('SessionStateError')<{\n\tmessage: string;\n\tcause?: unknown;\n}> {}\n\nfunction getPath(session: DevSession) {\n\treturn session.path('sess.json');\n}\n\nfunction read(filePath: string) {\n\treturn Effect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\t\tif (!(yield* fs.exists(filePath))) {\n\t\t\treturn null;\n\t\t}\n\t\treturn yield* fs.readFileString(filePath);\n\t});\n}\n\nexport namespace SessionState {\n\ttype Shape = S.Top;\n\n\texport function slot<T extends Shape>(schema: T) {\n\t\treturn {\n\t\t\tread: (session: DevSession) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst filePath = yield* getPath(session);\n\t\t\t\t\tconst content = yield* read(filePath);\n\t\t\t\t\tif (content == null) return null;\n\t\t\t\t\treturn yield* S.decodeEffect(S.fromJsonString(schema))(content).pipe(\n\t\t\t\t\t\tEffect.catchTag('SchemaError', () => Effect.succeed(null)),\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\twrite: (session: DevSession, data: T['Type']) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst fs = yield* FileSystem;\n\t\t\t\t\tconst path = yield* Path;\n\t\t\t\t\tconst filePath = yield* getPath(session);\n\t\t\t\t\tyield* fs.makeDirectory(path.dirname(filePath), { recursive: true });\n\t\t\t\t\tconst existing = yield* read(filePath);\n\t\t\t\t\tconst parsed = yield* Effect.try({\n\t\t\t\t\t\ttry: () => JSON.parse(existing ?? '{}') as Record<string, unknown>,\n\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\tnew SessionStateError({\n\t\t\t\t\t\t\t\tmessage: `Failed to parse ${filePath} as JSON`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t\tconst merged = { ...parsed, ...(data as Record<string, unknown>) };\n\t\t\t\t\tyield* fs.writeFileString(filePath, JSON.stringify(merged));\n\t\t\t\t}),\n\t\t};\n\t}\n}\n","import { Effect } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport * as S from 'effect/Schema';\nimport getPort from 'get-port';\nimport type { DevSession } from '../dev-sessions';\nimport { acquireFileLock } from '../lock';\nimport { SessionState, SessionStateError } from './session-state';\n\nconst DEFAULT_NAME = 'default';\n\n/**\n * Reads both the current `{ ports: Record<string, number> }` shape and the legacy\n * top-level `{ port: number }` shape, so a session written before named ports existed\n * still yields its remembered port (as `default`). Writes only ever use `ports` —\n * the legacy `port` key is never touched again once the new shape is written.\n */\nconst StickyPorts = SessionState.slot(\n\tS.Struct({\n\t\tports: S.optional(S.Record(S.String, S.Number)),\n\t\tport: S.optional(S.Number),\n\t}),\n);\n\nexport const getStickyPort = (\n\tsession: DevSession,\n\toptions?: { name?: string },\n) =>\n\tEffect.gen(function* () {\n\t\tconst name = options?.name ?? DEFAULT_NAME;\n\t\tconst fs = yield* FileSystem;\n\t\tconst path = yield* Path;\n\t\tconst statePath = yield* session.path('sess.json');\n\t\tyield* fs.makeDirectory(path.dirname(statePath), { recursive: true });\n\t\tyield* Effect.acquireRelease(\n\t\t\tacquireFileLock(statePath).pipe(\n\t\t\t\tEffect.mapError(\n\t\t\t\t\t(cause) =>\n\t\t\t\t\t\tnew SessionStateError({\n\t\t\t\t\t\t\tmessage: 'Failed to lock sticky ports',\n\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t}),\n\t\t\t\t),\n\t\t\t),\n\t\t\t(release) => Effect.promise(() => release()),\n\t\t);\n\n\t\tconst file = yield* StickyPorts.read(session);\n\t\tconst ports =\n\t\t\tfile?.ports ??\n\t\t\t(file?.port !== undefined ? { [DEFAULT_NAME]: file.port } : {});\n\n\t\tconst preferred = ports[name];\n\t\tconst exclude = Object.entries(ports)\n\t\t\t.filter((entry) => entry[0] !== name)\n\t\t\t.map((entry) => entry[1]);\n\n\t\tconst port = yield* Effect.promise(async () =>\n\t\t\tgetPort({\n\t\t\t\tport: preferred !== undefined ? [preferred] : undefined,\n\t\t\t\t...(exclude.length > 0 ? { exclude } : {}),\n\t\t\t}),\n\t\t);\n\n\t\tyield* StickyPorts.write(session, { ports: { ...ports, [name]: port } });\n\n\t\treturn port;\n\t}).pipe(Effect.scoped);\n","import { Effect, Schedule } from 'effect';\nimport lockfile from 'proper-lockfile';\n\nexport const acquireFileLock = (file: string, lockPath = `${file}.lock`) =>\n\tEffect.tryPromise({\n\t\ttry: () =>\n\t\t\tlockfile.lock(file, {\n\t\t\t\trealpath: false,\n\t\t\t\tlockfilePath: lockPath,\n\t\t\t\tstale: 60_000,\n\t\t\t\tretries: 0,\n\t\t\t}),\n\t\tcatch: (cause) => new Error(`Failed to lock ${file}`, { cause }),\n\t}).pipe(\n\t\tEffect.retry({\n\t\t\twhile: (error) =>\n\t\t\t\ttypeof error.cause === 'object' &&\n\t\t\t\terror.cause !== null &&\n\t\t\t\t'code' in error.cause &&\n\t\t\t\terror.cause.code === 'ELOCKED',\n\t\t\tschedule: Schedule.spaced('50 millis'),\n\t\t}),\n\t);\n","import type { Socket } from 'node:net';\nimport { StringDecoder } from 'node:string_decoder';\n\nexport const readSocketLine = (\n\tsocket: Socket,\n\tmaxBytes = 1_048_576,\n): Promise<string> =>\n\tnew Promise((resolve, reject) => {\n\t\tconst decoder = new StringDecoder('utf8');\n\t\tconst state = { input: '', bytes: 0 };\n\t\tconst cleanup = () => {\n\t\t\tsocket.removeListener('data', data);\n\t\t\tsocket.removeListener('error', error);\n\t\t\tsocket.removeListener('close', closed);\n\t\t};\n\t\tconst error = (cause: Error) => {\n\t\t\tcleanup();\n\t\t\treject(cause);\n\t\t};\n\t\tconst closed = () =>\n\t\t\terror(new Error('Socket closed before sending a ready line'));\n\t\tconst data = (chunk: Buffer) => {\n\t\t\tconst boundary = chunk.indexOf(10);\n\t\t\tconst part = boundary < 0 ? chunk : chunk.subarray(0, boundary);\n\t\t\tstate.bytes += part.length;\n\t\t\tif (state.bytes > maxBytes)\n\t\t\t\treturn error(new Error('Socket line exceeds byte limit'));\n\t\t\tstate.input += decoder.write(part);\n\t\t\tif (boundary >= 0) {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(state.input + decoder.end());\n\t\t\t}\n\t\t};\n\t\tsocket.on('data', data);\n\t\tsocket.once('error', error);\n\t\tsocket.once('close', closed);\n\t});\n","import { createConnection } from 'node:net';\nimport { Config, ConfigProvider, Effect, Option, Schema } from 'effect';\nimport { readSocketLine } from '../socket-line';\n\n// The daemon serves requests one at a time, so a readiness report can queue\n// behind slow ones (e.g. `devsess start` polling the run list while it waits).\nconst RESPONSE_TIMEOUT_MS = 5_000;\nconst MAX_RESPONSE_BYTES = 1024 * 1024;\n\nconst DaemonResponse = Schema.fromJsonString(\n\tSchema.Struct({\n\t\tversion: Schema.Literal(1),\n\t\trequestId: Schema.NonEmptyString,\n\t\tok: Schema.Boolean,\n\t\tresult: Schema.optional(Schema.Unknown),\n\t\terror: Schema.optional(Schema.String),\n\t}),\n);\n\ntype ServiceIdentity = {\n\treadonly socketPath: string;\n\treadonly runId: string;\n\treadonly service: string;\n\treadonly instanceId?: string;\n};\n\nexport const readDaemonIdentity = Effect.gen(function* () {\n\tconst provider = ConfigProvider.fromEnv();\n\tconst read = (key: string) =>\n\t\tConfig.String(key)\n\t\t\t.pipe(Config.option)\n\t\t\t.parse(provider)\n\t\t\t.pipe(Effect.map(Option.getOrUndefined));\n\tconst socketPath = yield* read('DEVSESS_SOCKET');\n\tconst runId = yield* read('DEVSESS_RUN_ID');\n\tconst service = yield* read('DEVSESS_SERVICE');\n\tconst instanceId = yield* read('DEVSESS_INSTANCE_ID');\n\tif (socketPath === undefined || runId === undefined || service === undefined)\n\t\treturn undefined;\n\treturn {\n\t\tsocketPath,\n\t\trunId,\n\t\tservice,\n\t\t...(instanceId === undefined ? {} : { instanceId }),\n\t};\n});\n\nexport const sendDaemonRequest = (\n\tidentity: ServiceIdentity,\n\trequest: {\n\t\treadonly version: 1;\n\t\treadonly requestId: string;\n\t\treadonly method: string;\n\t\treadonly params: Readonly<Record<string, unknown>>;\n\t},\n\ttimeoutMs = RESPONSE_TIMEOUT_MS,\n) =>\n\tEffect.tryPromise({\n\t\ttry: () =>\n\t\t\tnew Promise<string>((resolve, reject) => {\n\t\t\t\tconst socket = createConnection(identity.socketPath);\n\t\t\t\tlet settled = false;\n\t\t\t\tconst finish = (complete: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tclearTimeout(timer);\n\t\t\t\t\tsocket.destroy();\n\t\t\t\t\tcomplete();\n\t\t\t\t};\n\t\t\t\tconst timer = setTimeout(\n\t\t\t\t\t() => finish(() => reject(new Error('Daemon request timed out'))),\n\t\t\t\t\ttimeoutMs,\n\t\t\t\t);\n\t\t\t\tsocket.once('connect', () =>\n\t\t\t\t\tsocket.write(`${JSON.stringify(request)}\\n`),\n\t\t\t\t);\n\t\t\t\treadSocketLine(socket, MAX_RESPONSE_BYTES).then(\n\t\t\t\t\t(line) => finish(() => resolve(line)),\n\t\t\t\t\t(cause) => finish(() => reject(cause)),\n\t\t\t\t);\n\t\t\t}),\n\t\tcatch: (cause) => new Error('Could not send request to daemon', { cause }),\n\t}).pipe(\n\t\tEffect.flatMap(Schema.decodeUnknownEffect(DaemonResponse)),\n\t\tEffect.flatMap((response) =>\n\t\t\tresponse.requestId === request.requestId && response.ok\n\t\t\t\t? Effect.void\n\t\t\t\t: Effect.fail(new Error('Daemon did not acknowledge request')),\n\t\t),\n\t);\n"],"mappings":"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","names":["DevSession","Data","Effect","FileSystem","Path","SessionState","Effect","FileSystem","Path","S","Effect","Effect","FileSystem","Path","Effect","Option","Effect","read","Option"]}
|