devsess 0.0.0 → 0.2.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/README.md +122 -0
- package/dist/async/define-cli.d.ts +22 -0
- package/dist/async/define-cli.d.ts.map +1 -0
- package/dist/async/dev-sessions.d.ts +21 -0
- package/dist/async/dev-sessions.d.ts.map +1 -0
- package/dist/async/index.d.ts +9 -0
- package/dist/async/index.d.ts.map +1 -0
- package/dist/async/index.js +141 -0
- package/dist/async/index.js.map +1 -0
- package/dist/async/platform.d.ts +41 -0
- package/dist/async/platform.d.ts.map +1 -0
- package/dist/async/run-dev-cli.d.ts +20 -0
- package/dist/async/run-dev-cli.d.ts.map +1 -0
- package/dist/async/run.d.ts +5 -0
- package/dist/async/run.d.ts.map +1 -0
- package/dist/async/session-state.d.ts +13 -0
- package/dist/async/session-state.d.ts.map +1 -0
- package/dist/async/session.d.ts +16 -0
- package/dist/async/session.d.ts.map +1 -0
- package/dist/chunk-AQGYVNYU.js +321 -0
- package/dist/chunk-AQGYVNYU.js.map +1 -0
- package/dist/current-session.d.ts +29 -0
- package/dist/current-session.d.ts.map +1 -0
- package/dist/dev/running-signal.d.ts +29 -0
- package/dist/dev/running-signal.d.ts.map +1 -0
- package/dist/dev/session-state.d.ts +23 -0
- package/dist/dev/session-state.d.ts.map +1 -0
- package/dist/dev/sticky-port.d.ts +4 -0
- package/dist/dev/sticky-port.d.ts.map +1 -0
- package/dist/dev/subprocess.d.ts +5 -0
- package/dist/dev/subprocess.d.ts.map +1 -0
- package/dist/dev-sessions.d.ts +60 -0
- package/dist/dev-sessions.d.ts.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/pglite/index.d.ts +50 -0
- package/dist/pglite/index.d.ts.map +1 -0
- package/dist/pglite/index.js +218 -0
- package/dist/pglite/index.js.map +1 -0
- package/package.json +86 -1
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
// src/dev-sessions.ts
|
|
2
|
+
import { Array as A, Context, Data, Effect, Layer, Option } from "effect";
|
|
3
|
+
import { FileSystem } from "effect/FileSystem";
|
|
4
|
+
import { Path } from "effect/Path";
|
|
5
|
+
import { generateSlug } from "random-word-slugs";
|
|
6
|
+
var DevSession;
|
|
7
|
+
((DevSession2) => {
|
|
8
|
+
function make(input) {
|
|
9
|
+
return {
|
|
10
|
+
name: input.name,
|
|
11
|
+
lastModifiedAt: input.lastModifiedAt,
|
|
12
|
+
path: (relativePath) => Effect.succeed(input.pathJoin(relativePath)),
|
|
13
|
+
toString: () => input.name
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
DevSession2.make = make;
|
|
17
|
+
})(DevSession || (DevSession = {}));
|
|
18
|
+
var DevSessions = class _DevSessions extends Context.Service()("devsess/DevSessions") {
|
|
19
|
+
/**
|
|
20
|
+
* `DevSessions` explicitly rooted at `rootDir`: `dir`/`path` resolve against `rootDir`
|
|
21
|
+
* itself (e.g. `sessions.path('drizzle')` reaches a project's real `drizzle/` folder),
|
|
22
|
+
* while session directories are namespaced under `<rootDir>/.data/sessions`.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately does *not* also provide `CurrentSession` — a `Layer`'s build effect
|
|
25
|
+
* runs as soon as it's provided, before anything downstream (e.g. `cli.Command.run`'s
|
|
26
|
+
* argv parsing) gets a say. Bundling session resolution in here would create a
|
|
27
|
+
* session for `--help`/`--version`/a bad flag too, since those never reach a command
|
|
28
|
+
* handler at all. Provide `CurrentSession.layer` around the handler itself instead.
|
|
29
|
+
*/
|
|
30
|
+
static layerAt = (rootDir) => buildDevSessionsLayer(rootDir);
|
|
31
|
+
/**
|
|
32
|
+
* `DevSessions.layerAt` rooted at the auto-detected project root — the nearest
|
|
33
|
+
* ancestor of `process.cwd()` containing a `package.json`.
|
|
34
|
+
*/
|
|
35
|
+
static layer = Layer.unwrap(
|
|
36
|
+
Effect.suspend(
|
|
37
|
+
() => Effect.map(findProjectRoot, (rootDir) => _DevSessions.layerAt(rootDir))
|
|
38
|
+
)
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
var ProjectRootNotFoundError = class extends Data.TaggedError(
|
|
42
|
+
"ProjectRootNotFoundError"
|
|
43
|
+
) {
|
|
44
|
+
};
|
|
45
|
+
var findProjectRoot = Effect.gen(function* () {
|
|
46
|
+
const fs = yield* FileSystem;
|
|
47
|
+
const path = yield* Path;
|
|
48
|
+
const startDir = process.cwd();
|
|
49
|
+
const walkUp = (dir) => Effect.gen(function* () {
|
|
50
|
+
if (yield* fs.exists(path.join(dir, "package.json"))) {
|
|
51
|
+
return dir;
|
|
52
|
+
}
|
|
53
|
+
const parent = path.dirname(dir);
|
|
54
|
+
if (parent === dir) {
|
|
55
|
+
return yield* Effect.fail(
|
|
56
|
+
new ProjectRootNotFoundError({ searchedFrom: startDir })
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return yield* walkUp(parent);
|
|
60
|
+
});
|
|
61
|
+
return yield* walkUp(startDir);
|
|
62
|
+
});
|
|
63
|
+
var buildDevSessionsCore = (sessionsDir) => Effect.gen(function* () {
|
|
64
|
+
const fs = yield* FileSystem;
|
|
65
|
+
const path = yield* Path;
|
|
66
|
+
yield* Effect.logDebug(`DevSessions dir: ${sessionsDir}`);
|
|
67
|
+
const getSessions = Effect.gen(function* () {
|
|
68
|
+
const entries = yield* fs.readDirectory(sessionsDir).pipe(Effect.catch(() => Effect.succeed([])));
|
|
69
|
+
const possibleSessions = yield* Effect.all(
|
|
70
|
+
entries.map(
|
|
71
|
+
(entry) => Effect.gen(function* () {
|
|
72
|
+
const stat = yield* fs.stat(path.join(sessionsDir, entry));
|
|
73
|
+
if (stat.type !== "Directory") return Option.none();
|
|
74
|
+
return Option.some(
|
|
75
|
+
DevSession.make({
|
|
76
|
+
name: entry,
|
|
77
|
+
lastModifiedAt: Option.getOrNull(stat.mtime),
|
|
78
|
+
rootDir: sessionsDir,
|
|
79
|
+
pathJoin: (relativePath) => path.join(sessionsDir, entry, relativePath)
|
|
80
|
+
})
|
|
81
|
+
);
|
|
82
|
+
})
|
|
83
|
+
),
|
|
84
|
+
{ concurrency: "unbounded" }
|
|
85
|
+
);
|
|
86
|
+
return A.getSomes(possibleSessions);
|
|
87
|
+
});
|
|
88
|
+
const createSession = Effect.gen(function* () {
|
|
89
|
+
const slug = generateSlug(1, { partsOfSpeech: ["noun"] });
|
|
90
|
+
yield* fs.makeDirectory(path.join(sessionsDir, slug), {
|
|
91
|
+
recursive: true
|
|
92
|
+
});
|
|
93
|
+
return DevSession.make({
|
|
94
|
+
name: slug,
|
|
95
|
+
lastModifiedAt: null,
|
|
96
|
+
rootDir: sessionsDir,
|
|
97
|
+
pathJoin: (relativePath) => path.join(sessionsDir, slug, relativePath)
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
const getLatestOrCreate = Effect.gen(function* () {
|
|
101
|
+
yield* fs.makeDirectory(sessionsDir, { recursive: true });
|
|
102
|
+
const sessions = yield* getSessions;
|
|
103
|
+
if (sessions.length > 0) {
|
|
104
|
+
sessions.sort(
|
|
105
|
+
(a, b) => (b.lastModifiedAt?.getTime() ?? 0) - (a.lastModifiedAt?.getTime() ?? 0)
|
|
106
|
+
);
|
|
107
|
+
const latest = sessions[0];
|
|
108
|
+
return latest;
|
|
109
|
+
}
|
|
110
|
+
return yield* createSession;
|
|
111
|
+
});
|
|
112
|
+
return { getSessions, createSession, getLatestOrCreate };
|
|
113
|
+
});
|
|
114
|
+
var buildDevSessionsLayer = (rootDir) => Layer.effect(
|
|
115
|
+
DevSessions,
|
|
116
|
+
Effect.gen(function* () {
|
|
117
|
+
const path = yield* Path;
|
|
118
|
+
const sessionsDir = path.join(rootDir, ".data", "sessions");
|
|
119
|
+
const core = yield* buildDevSessionsCore(sessionsDir);
|
|
120
|
+
return {
|
|
121
|
+
dir: rootDir,
|
|
122
|
+
path: (relativePath) => path.join(rootDir, relativePath),
|
|
123
|
+
...core
|
|
124
|
+
};
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// src/dev/running-signal.ts
|
|
129
|
+
import { watch as fsWatch, realpathSync } from "fs";
|
|
130
|
+
import { createRequire } from "module";
|
|
131
|
+
import { dirname, join, resolve } from "path";
|
|
132
|
+
import { Deferred, Effect as Effect2 } from "effect";
|
|
133
|
+
import { FileSystem as FileSystem2 } from "effect/FileSystem";
|
|
134
|
+
import { Path as Path2 } from "effect/Path";
|
|
135
|
+
var RUNNING_SIGNAL_FILE = ".data/running.json";
|
|
136
|
+
var runningSignalPath = (dir) => join(dir, RUNNING_SIGNAL_FILE);
|
|
137
|
+
var resolveSiblingDir = (spec, fromDir) => {
|
|
138
|
+
if (spec.startsWith(".") || spec.startsWith("/")) {
|
|
139
|
+
return resolve(fromDir, spec);
|
|
140
|
+
}
|
|
141
|
+
const require2 = createRequire(join(fromDir, "package.json"));
|
|
142
|
+
const pkgJsonPath = require2.resolve(`${spec}/package.json`);
|
|
143
|
+
return dirname(realpathSync(pkgJsonPath));
|
|
144
|
+
};
|
|
145
|
+
var publishRunningSignal = (filePath, value) => Effect2.acquireRelease(
|
|
146
|
+
Effect2.gen(function* () {
|
|
147
|
+
const fs = yield* FileSystem2;
|
|
148
|
+
const path = yield* Path2;
|
|
149
|
+
const tmp = `${filePath}.tmp`;
|
|
150
|
+
yield* fs.makeDirectory(path.dirname(filePath), { recursive: true });
|
|
151
|
+
yield* fs.writeFileString(tmp, JSON.stringify(value));
|
|
152
|
+
yield* fs.rename(tmp, filePath);
|
|
153
|
+
}),
|
|
154
|
+
() => Effect2.gen(function* () {
|
|
155
|
+
const fs = yield* FileSystem2;
|
|
156
|
+
yield* fs.remove(filePath).pipe(Effect2.catch(() => Effect2.void));
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
var awaitRunningSignal = (filePath, opts) => Effect2.scoped(
|
|
160
|
+
Effect2.gen(function* () {
|
|
161
|
+
const fs = yield* FileSystem2;
|
|
162
|
+
const path = yield* Path2;
|
|
163
|
+
const dir = path.dirname(filePath);
|
|
164
|
+
const filename = path.basename(filePath);
|
|
165
|
+
const deferred = yield* Deferred.make();
|
|
166
|
+
const tryRead = Effect2.gen(function* () {
|
|
167
|
+
if (!(yield* fs.exists(filePath))) return false;
|
|
168
|
+
const raw = yield* fs.readFileString(filePath).pipe(Effect2.catch(() => Effect2.succeed(null)));
|
|
169
|
+
if (raw == null) return false;
|
|
170
|
+
const parsed = yield* Effect2.try(() => opts.parse(raw)).pipe(
|
|
171
|
+
Effect2.catch(() => Effect2.succeed(null))
|
|
172
|
+
);
|
|
173
|
+
if (parsed == null) return false;
|
|
174
|
+
yield* Deferred.succeed(deferred, parsed);
|
|
175
|
+
return true;
|
|
176
|
+
});
|
|
177
|
+
yield* fs.makeDirectory(dir, { recursive: true });
|
|
178
|
+
yield* Effect2.acquireRelease(
|
|
179
|
+
Effect2.sync(
|
|
180
|
+
() => (
|
|
181
|
+
// Watch parent dir — the file may not exist yet, and watching a missing file errors.
|
|
182
|
+
fsWatch(dir, { recursive: false }, (eventType, eventFilename) => {
|
|
183
|
+
if (eventFilename !== filename) return;
|
|
184
|
+
if (eventType !== "rename" && eventType !== "change") return;
|
|
185
|
+
Effect2.runFork(tryRead);
|
|
186
|
+
})
|
|
187
|
+
)
|
|
188
|
+
),
|
|
189
|
+
(watcher) => Effect2.sync(() => watcher.close())
|
|
190
|
+
);
|
|
191
|
+
yield* tryRead;
|
|
192
|
+
return yield* Deferred.await(deferred);
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
var publishRunning = (value) => Effect2.gen(function* () {
|
|
196
|
+
const sessions = yield* DevSessions;
|
|
197
|
+
yield* publishRunningSignal(runningSignalPath(sessions.dir), value);
|
|
198
|
+
});
|
|
199
|
+
var awaitRunning = (pkg) => Effect2.gen(function* () {
|
|
200
|
+
const sessions = yield* DevSessions;
|
|
201
|
+
return yield* awaitRunningSignal(
|
|
202
|
+
runningSignalPath(resolveSiblingDir(pkg, sessions.dir)),
|
|
203
|
+
{ parse: (raw) => JSON.parse(raw) }
|
|
204
|
+
);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// src/dev/session-state.ts
|
|
208
|
+
import { Data as Data2, Effect as Effect3 } from "effect";
|
|
209
|
+
import { FileSystem as FileSystem3 } from "effect/FileSystem";
|
|
210
|
+
import { Path as Path3 } from "effect/Path";
|
|
211
|
+
import * as S from "effect/Schema";
|
|
212
|
+
var SessionStateError = class extends Data2.TaggedError("SessionStateError") {
|
|
213
|
+
};
|
|
214
|
+
function getPath(session) {
|
|
215
|
+
return session.path("sess.json");
|
|
216
|
+
}
|
|
217
|
+
function read(filePath) {
|
|
218
|
+
return Effect3.gen(function* () {
|
|
219
|
+
const fs = yield* FileSystem3;
|
|
220
|
+
if (!(yield* fs.exists(filePath))) {
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
return yield* fs.readFileString(filePath);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
var SessionState;
|
|
227
|
+
((SessionState2) => {
|
|
228
|
+
function slot(schema) {
|
|
229
|
+
return {
|
|
230
|
+
read: (session) => Effect3.gen(function* () {
|
|
231
|
+
const filePath = yield* getPath(session);
|
|
232
|
+
const content = yield* read(filePath);
|
|
233
|
+
if (content == null) return null;
|
|
234
|
+
return yield* S.decodeEffect(S.fromJsonString(schema))(content).pipe(
|
|
235
|
+
Effect3.catchTag("SchemaError", () => Effect3.succeed(null))
|
|
236
|
+
);
|
|
237
|
+
}),
|
|
238
|
+
write: (session, data) => Effect3.gen(function* () {
|
|
239
|
+
const fs = yield* FileSystem3;
|
|
240
|
+
const path = yield* Path3;
|
|
241
|
+
const filePath = yield* getPath(session);
|
|
242
|
+
yield* fs.makeDirectory(path.dirname(filePath), { recursive: true });
|
|
243
|
+
const existing = yield* read(filePath);
|
|
244
|
+
const parsed = yield* Effect3.try({
|
|
245
|
+
try: () => JSON.parse(existing ?? "{}"),
|
|
246
|
+
catch: (cause) => new SessionStateError({
|
|
247
|
+
message: `Failed to parse ${filePath} as JSON`,
|
|
248
|
+
cause
|
|
249
|
+
})
|
|
250
|
+
});
|
|
251
|
+
const merged = { ...parsed, ...data };
|
|
252
|
+
yield* fs.writeFileString(filePath, JSON.stringify(merged));
|
|
253
|
+
})
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
SessionState2.slot = slot;
|
|
257
|
+
})(SessionState || (SessionState = {}));
|
|
258
|
+
|
|
259
|
+
// src/dev/sticky-port.ts
|
|
260
|
+
import { Effect as Effect4 } from "effect";
|
|
261
|
+
import * as S2 from "effect/Schema";
|
|
262
|
+
import getPort from "get-port";
|
|
263
|
+
var StickyPort = SessionState.slot(S2.Struct({ port: S2.Number }));
|
|
264
|
+
var getStickyPort = (session) => Effect4.gen(function* () {
|
|
265
|
+
const file = yield* StickyPort.read(session);
|
|
266
|
+
const preferred = file?.port;
|
|
267
|
+
const port = yield* Effect4.promise(
|
|
268
|
+
async () => getPort({
|
|
269
|
+
port: preferred !== void 0 ? [preferred] : void 0
|
|
270
|
+
})
|
|
271
|
+
);
|
|
272
|
+
yield* StickyPort.write(session, { port });
|
|
273
|
+
return port;
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// src/dev/subprocess.ts
|
|
277
|
+
import { Effect as Effect5 } from "effect";
|
|
278
|
+
import { ChildProcess } from "effect/unstable/process";
|
|
279
|
+
var runManagedSubprocess = (cmd, args, opts) => Effect5.gen(function* () {
|
|
280
|
+
const command = ChildProcess.make(cmd, args, {
|
|
281
|
+
stdin: "inherit",
|
|
282
|
+
stdout: "inherit",
|
|
283
|
+
stderr: "inherit",
|
|
284
|
+
env: { ...process.env, ...opts?.env ?? {} }
|
|
285
|
+
});
|
|
286
|
+
const label = [cmd, ...args].join(" ");
|
|
287
|
+
const child = yield* Effect5.acquireRelease(
|
|
288
|
+
Effect5.gen(function* () {
|
|
289
|
+
const proc = yield* command;
|
|
290
|
+
yield* Effect5.logInfo(`[dev] started: ${label} (pid=${proc.pid})`);
|
|
291
|
+
return proc;
|
|
292
|
+
}),
|
|
293
|
+
(proc) => Effect5.gen(function* () {
|
|
294
|
+
yield* Effect5.logInfo(`[dev] stopping: ${label} (pid=${proc.pid})`);
|
|
295
|
+
yield* proc.kill().pipe(
|
|
296
|
+
Effect5.catch(
|
|
297
|
+
(err) => Effect5.logError(
|
|
298
|
+
`[dev] failed to stop ${label} (pid=${proc.pid}): ${err}`
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
);
|
|
302
|
+
})
|
|
303
|
+
);
|
|
304
|
+
return yield* child.exitCode;
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
export {
|
|
308
|
+
DevSessions,
|
|
309
|
+
ProjectRootNotFoundError,
|
|
310
|
+
runningSignalPath,
|
|
311
|
+
resolveSiblingDir,
|
|
312
|
+
publishRunningSignal,
|
|
313
|
+
awaitRunningSignal,
|
|
314
|
+
publishRunning,
|
|
315
|
+
awaitRunning,
|
|
316
|
+
SessionStateError,
|
|
317
|
+
SessionState,
|
|
318
|
+
getStickyPort,
|
|
319
|
+
runManagedSubprocess
|
|
320
|
+
};
|
|
321
|
+
//# sourceMappingURL=chunk-AQGYVNYU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev-sessions.ts","../src/dev/running-signal.ts","../src/dev/session-state.ts","../src/dev/sticky-port.ts","../src/dev/subprocess.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\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}\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) =>\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: sessionsDir,\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: sessionsDir,\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\treturn { getSessions, createSession, getLatestOrCreate };\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);\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 { 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';\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});\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 { 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 * as S from 'effect/Schema';\nimport getPort from 'get-port';\nimport type { DevSession } from '../dev-sessions';\nimport { SessionState } from './session-state';\n\nconst StickyPort = SessionState.slot(S.Struct({ port: S.Number }));\n\nexport const getStickyPort = (session: DevSession) =>\n\tEffect.gen(function* () {\n\t\tconst file = yield* StickyPort.read(session);\n\t\tconst preferred = file?.port;\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}),\n\t\t);\n\n\t\tyield* StickyPort.write(session, { port });\n\n\t\treturn port;\n\t});\n","import { Effect } from 'effect';\nimport { ChildProcess } from 'effect/unstable/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\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\tyield* Effect.logInfo(`[dev] stopping: ${label} (pid=${proc.pid})`);\n\t\t\t\t\tyield* proc\n\t\t\t\t\t\t.kill()\n\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\tEffect.catch((err) =>\n\t\t\t\t\t\t\t\tEffect.logError(\n\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),\n\t\t\t\t\t\t\t),\n\t\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":["DevSession","Effect","FileSystem","Path","require","Effect","FileSystem","Path","Data","Effect","FileSystem","Path","SessionState","Effect","S","Effect","Effect"]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect';
|
|
2
|
+
import type { PlatformError } from 'effect/PlatformError';
|
|
3
|
+
import { type DevSession, DevSessions } from './dev-sessions';
|
|
4
|
+
declare const CurrentSession_base: Context.ServiceClass<CurrentSession, "devsess/CurrentSession", {
|
|
5
|
+
name: string;
|
|
6
|
+
lastModifiedAt: Date | null;
|
|
7
|
+
path: (relativePath: string) => Effect.Effect<string, never, never>;
|
|
8
|
+
toString: () => string;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* The dev session resolved for a single command run. `yield* CurrentSession` always
|
|
12
|
+
* gives a plain `DevSession` — never a wrapper effect to unwrap — so provide whichever
|
|
13
|
+
* layer resolves it (`layer` or the test-only `layerOf(session)`) close to where it's
|
|
14
|
+
* actually used.
|
|
15
|
+
*/
|
|
16
|
+
export declare class CurrentSession extends CurrentSession_base {
|
|
17
|
+
/**
|
|
18
|
+
* Resolves the session via `DevSessions#getLatestOrCreate`. Provide this around a
|
|
19
|
+
* command's own handler effect, not the whole CLI program: a `Layer`'s build effect
|
|
20
|
+
* runs the moment it's provided, regardless of what the effect it wraps ends up
|
|
21
|
+
* doing — wrapping `Command.run` itself would create a session for `--help`,
|
|
22
|
+
* `--version`, or a bad flag too, none of which ever reach a handler.
|
|
23
|
+
*/
|
|
24
|
+
static readonly layer: Layer.Layer<CurrentSession, PlatformError, DevSessions>;
|
|
25
|
+
/** Pins an explicit session instead of resolving one via `DevSessions` — for tests. */
|
|
26
|
+
static readonly layerOf: (session: DevSession) => Layer.Layer<CurrentSession, never, never>;
|
|
27
|
+
}
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=current-session.d.ts.map
|
|
@@ -0,0 +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;;;;;;;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,29 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { FileSystem } from 'effect/FileSystem';
|
|
3
|
+
import { Path } from 'effect/Path';
|
|
4
|
+
import { DevSessions } from '../dev-sessions';
|
|
5
|
+
/** Path to the running-signal file for a dev-session (or sibling package) directory. */
|
|
6
|
+
export declare const runningSignalPath: (dir: string) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves `spec` to a directory: relative/absolute paths are resolved against
|
|
9
|
+
* `fromDir`, anything else is treated as a package name and resolved via its
|
|
10
|
+
* `package.json`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const resolveSiblingDir: (spec: string, fromDir: string) => string;
|
|
13
|
+
/** Atomically writes `value` as JSON to `filePath` and removes it on release. */
|
|
14
|
+
export declare const publishRunningSignal: (filePath: string, value: unknown) => Effect.Effect<void, import("effect/PlatformError").PlatformError, FileSystem | Path | import("effect/Scope").Scope>;
|
|
15
|
+
/** Watches parent directory for the signal file and resolves once it can be parsed. */
|
|
16
|
+
export declare const awaitRunningSignal: <T>(filePath: string, opts: {
|
|
17
|
+
parse: (raw: string) => T;
|
|
18
|
+
}) => Effect.Effect<T, import("effect/PlatformError").PlatformError, FileSystem | Path>;
|
|
19
|
+
/**
|
|
20
|
+
* Publishes `value` at the project root's running-signal file, so a sibling package's
|
|
21
|
+
* dev script can `awaitRunning` it. Removed when the enclosing scope closes.
|
|
22
|
+
*/
|
|
23
|
+
export declare const publishRunning: (value: unknown) => Effect.Effect<void, import("effect/PlatformError").PlatformError, DevSessions | FileSystem | Path | import("effect/Scope").Scope>;
|
|
24
|
+
/**
|
|
25
|
+
* Awaits the running-signal file of another package in the workspace (`pkg`, resolved
|
|
26
|
+
* relative to the project root the same way `resolveSiblingDir` resolves any spec).
|
|
27
|
+
*/
|
|
28
|
+
export declare const awaitRunning: <T>(pkg: string) => Effect.Effect<T, import("effect/PlatformError").PlatformError, DevSessions | FileSystem | Path>;
|
|
29
|
+
//# sourceMappingURL=running-signal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"running-signal.d.ts","sourceRoot":"","sources":["../../src/dev/running-signal.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAI9C,wFAAwF;AACxF,eAAO,MAAM,iBAAiB,QAAS,MAAM,WACd,CAAC;AAEhC;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,WAAW,MAAM,WAO9D,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,oBAAoB,aAAc,MAAM,SAAS,OAAO,wHAgBnE,CAAC;AAEH,uFAAuF;AACvF,eAAO,MAAM,kBAAkB,GAAI,CAAC,YACzB,MAAM,QACV;IAAE,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,CAAC,CAAA;CAAE,sFA4ClC,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc,UAAW,OAAO,sIAI1C,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,CAAC,OAAO,MAAM,oGAOxC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import { FileSystem } from 'effect/FileSystem';
|
|
3
|
+
import { Path } from 'effect/Path';
|
|
4
|
+
import * as S from 'effect/Schema';
|
|
5
|
+
import type { DevSession } from '../dev-sessions';
|
|
6
|
+
declare const SessionStateError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
7
|
+
readonly _tag: "SessionStateError";
|
|
8
|
+
} & Readonly<A>;
|
|
9
|
+
export declare class SessionStateError extends SessionStateError_base<{
|
|
10
|
+
message: string;
|
|
11
|
+
cause?: unknown;
|
|
12
|
+
}> {
|
|
13
|
+
}
|
|
14
|
+
export declare namespace SessionState {
|
|
15
|
+
type Shape = S.Top;
|
|
16
|
+
export function slot<T extends Shape>(schema: T): {
|
|
17
|
+
read: (session: DevSession) => Effect.Effect<T["Type"] | null, import("effect/PlatformError").PlatformError, FileSystem | T["DecodingServices"]>;
|
|
18
|
+
write: (session: DevSession, data: T['Type']) => Effect.Effect<void, import("effect/PlatformError").PlatformError | SessionStateError, FileSystem | Path>;
|
|
19
|
+
};
|
|
20
|
+
export {};
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=session-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-state.d.ts","sourceRoot":"","sources":["../../src/dev/session-state.ts"],"names":[],"mappings":"AAAA,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,CAAC,MAAM,eAAe,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;AAElD,qBAAa,iBAAkB,SAAQ,uBAAsC;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;CAAG;AAgBL,yBAAiB,YAAY,CAAC;IAC7B,KAAK,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC;IAEnB,MAAM,UAAU,IAAI,CAAC,CAAC,SAAS,KAAK,EAAE,MAAM,EAAE,CAAC;QAE7C,IAAI,YAAY,UAAU;QAS1B,KAAK,YAAY,UAAU,QAAQ,CAAC,CAAC,MAAM,CAAC;MAmB7C;;CACD"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
import type { DevSession } from '../dev-sessions';
|
|
3
|
+
export declare const getStickyPort: (session: DevSession) => Effect.Effect<number, import("effect/PlatformError").PlatformError | import("./session-state").SessionStateError, import("effect/FileSystem").FileSystem | import("effect/Path").Path>;
|
|
4
|
+
//# sourceMappingURL=sticky-port.d.ts.map
|
|
@@ -0,0 +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;AAGhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAKlD,eAAO,MAAM,aAAa,YAAa,UAAU,2LAc9C,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Effect } from 'effect';
|
|
2
|
+
export declare const runManagedSubprocess: (cmd: string, args: string[], opts?: {
|
|
3
|
+
env?: Record<string, string>;
|
|
4
|
+
}) => Effect.Effect<import("effect/unstable/process/ChildProcessSpawner").ExitCode, import("effect/PlatformError").PlatformError, import("effect/unstable/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/Scope").Scope>;
|
|
5
|
+
//# sourceMappingURL=subprocess.d.ts.map
|
|
@@ -0,0 +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,0OAqCrC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Context, Effect, Layer } from 'effect';
|
|
2
|
+
import { FileSystem } from 'effect/FileSystem';
|
|
3
|
+
import { Path } from 'effect/Path';
|
|
4
|
+
import type { PlatformError } from 'effect/PlatformError';
|
|
5
|
+
declare namespace DevSession {
|
|
6
|
+
type DevSessionInput = {
|
|
7
|
+
name: string;
|
|
8
|
+
lastModifiedAt: Date | null;
|
|
9
|
+
rootDir: string;
|
|
10
|
+
pathJoin: (relativePath: string) => string;
|
|
11
|
+
};
|
|
12
|
+
export function make(input: DevSessionInput): {
|
|
13
|
+
name: string;
|
|
14
|
+
lastModifiedAt: Date | null;
|
|
15
|
+
path: (relativePath: string) => Effect.Effect<string, never, never>;
|
|
16
|
+
toString: () => string;
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
19
|
+
}
|
|
20
|
+
export type DevSession = ReturnType<typeof DevSession.make>;
|
|
21
|
+
declare const DevSessions_base: Context.ServiceClass<DevSessions, "devsess/DevSessions", {
|
|
22
|
+
readonly dir: string;
|
|
23
|
+
readonly path: (relativePath: string) => string;
|
|
24
|
+
readonly getSessions: Effect.Effect<Array<DevSession>, PlatformError>;
|
|
25
|
+
readonly createSession: Effect.Effect<DevSession, PlatformError>;
|
|
26
|
+
readonly getLatestOrCreate: Effect.Effect<DevSession, PlatformError>;
|
|
27
|
+
}>;
|
|
28
|
+
export declare class DevSessions extends DevSessions_base {
|
|
29
|
+
/**
|
|
30
|
+
* `DevSessions` explicitly rooted at `rootDir`: `dir`/`path` resolve against `rootDir`
|
|
31
|
+
* itself (e.g. `sessions.path('drizzle')` reaches a project's real `drizzle/` folder),
|
|
32
|
+
* while session directories are namespaced under `<rootDir>/.data/sessions`.
|
|
33
|
+
*
|
|
34
|
+
* Deliberately does *not* also provide `CurrentSession` — a `Layer`'s build effect
|
|
35
|
+
* runs as soon as it's provided, before anything downstream (e.g. `cli.Command.run`'s
|
|
36
|
+
* argv parsing) gets a say. Bundling session resolution in here would create a
|
|
37
|
+
* session for `--help`/`--version`/a bad flag too, since those never reach a command
|
|
38
|
+
* handler at all. Provide `CurrentSession.layer` around the handler itself instead.
|
|
39
|
+
*/
|
|
40
|
+
static readonly layerAt: (rootDir: string) => Layer.Layer<DevSessions, never, FileSystem | Path>;
|
|
41
|
+
/**
|
|
42
|
+
* `DevSessions.layerAt` rooted at the auto-detected project root — the nearest
|
|
43
|
+
* ancestor of `process.cwd()` containing a `package.json`.
|
|
44
|
+
*/
|
|
45
|
+
static readonly layer: Layer.Layer<DevSessions, PlatformError | ProjectRootNotFoundError, FileSystem | Path>;
|
|
46
|
+
}
|
|
47
|
+
declare const ProjectRootNotFoundError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
48
|
+
readonly _tag: "ProjectRootNotFoundError";
|
|
49
|
+
} & Readonly<A>;
|
|
50
|
+
/**
|
|
51
|
+
* Raised by `DevSessions.layer` when no ancestor of `searchedFrom` contains a
|
|
52
|
+
* `package.json`. Failing loudly beats silently falling back to `process.cwd()` — a
|
|
53
|
+
* wrong root means dev sessions get written to a surprising place.
|
|
54
|
+
*/
|
|
55
|
+
export declare class ProjectRootNotFoundError extends ProjectRootNotFoundError_base<{
|
|
56
|
+
readonly searchedFrom: string;
|
|
57
|
+
}> {
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=dev-sessions.d.ts.map
|
|
@@ -0,0 +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;;AAPtE,qBAAa,WAAY,SAAQ,gBASP;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.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { CurrentSession } from './current-session';
|
|
2
|
+
export { awaitRunning, publishRunning } from './dev/running-signal';
|
|
3
|
+
export { SessionState, SessionStateError } from './dev/session-state';
|
|
4
|
+
export { getStickyPort } from './dev/sticky-port';
|
|
5
|
+
export { runManagedSubprocess } from './dev/subprocess';
|
|
6
|
+
export { type DevSession, DevSessions, ProjectRootNotFoundError, } from './dev-sessions';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EACN,KAAK,UAAU,EACf,WAAW,EACX,wBAAwB,GACxB,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DevSessions,
|
|
3
|
+
ProjectRootNotFoundError,
|
|
4
|
+
SessionState,
|
|
5
|
+
SessionStateError,
|
|
6
|
+
awaitRunning,
|
|
7
|
+
getStickyPort,
|
|
8
|
+
publishRunning,
|
|
9
|
+
runManagedSubprocess
|
|
10
|
+
} from "./chunk-AQGYVNYU.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
|
+
};
|
|
32
|
+
export {
|
|
33
|
+
CurrentSession,
|
|
34
|
+
DevSessions,
|
|
35
|
+
ProjectRootNotFoundError,
|
|
36
|
+
SessionState,
|
|
37
|
+
SessionStateError,
|
|
38
|
+
awaitRunning,
|
|
39
|
+
getStickyPort,
|
|
40
|
+
publishRunning,
|
|
41
|
+
runManagedSubprocess
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=index.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":[]}
|