devsess 0.3.2 → 0.3.3
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
CHANGED
|
@@ -137,7 +137,7 @@ import { Path as Path2 } from "effect/Path";
|
|
|
137
137
|
import { createConnection } from "net";
|
|
138
138
|
import { StringDecoder } from "string_decoder";
|
|
139
139
|
import { Effect as Effect2, Exit, Schema } from "effect";
|
|
140
|
-
var RESPONSE_TIMEOUT_MS =
|
|
140
|
+
var RESPONSE_TIMEOUT_MS = 5e3;
|
|
141
141
|
var MAX_RESPONSE_BYTES = 1024 * 1024;
|
|
142
142
|
var DaemonResponse = Schema.fromJsonString(
|
|
143
143
|
Schema.Struct({
|
|
@@ -426,4 +426,4 @@ export {
|
|
|
426
426
|
getStickyPort,
|
|
427
427
|
runManagedSubprocess
|
|
428
428
|
};
|
|
429
|
-
//# sourceMappingURL=chunk-
|
|
429
|
+
//# sourceMappingURL=chunk-ULIVG5ID.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dev-sessions.ts","../src/dev/running-signal.ts","../src/dev/daemon-readiness.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';\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 { createConnection } from 'node:net';\nimport { StringDecoder } from 'node:string_decoder';\nimport { Effect, Exit, Schema } from 'effect';\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};\n\nconst sendReadiness = (\n\tidentity: ServiceIdentity,\n\trequest: {\n\t\treadonly version: 1;\n\t\treadonly requestId: string;\n\t\treadonly method: 'publish' | 'unpublish';\n\t\treadonly params: {\n\t\t\treadonly runId: string;\n\t\t\treadonly service: string;\n\t\t\treadonly value?: Schema.Json;\n\t\t};\n\t},\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\tconst decoder = new StringDecoder('utf8');\n\t\t\t\tlet input = '';\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() =>\n\t\t\t\t\t\tfinish(() =>\n\t\t\t\t\t\t\treject(new Error('Daemon readiness request timed out')),\n\t\t\t\t\t\t),\n\t\t\t\t\tRESPONSE_TIMEOUT_MS,\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\tsocket.on('data', (chunk) => {\n\t\t\t\t\tinput += decoder.write(chunk);\n\t\t\t\t\tif (Buffer.byteLength(input) > MAX_RESPONSE_BYTES) {\n\t\t\t\t\t\tfinish(() =>\n\t\t\t\t\t\t\treject(new Error('Daemon readiness response is too large')),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst boundary = input.indexOf('\\n');\n\t\t\t\t\tif (boundary !== -1) finish(() => resolve(input.slice(0, boundary)));\n\t\t\t\t});\n\t\t\t\tsocket.once('error', (cause) => finish(() => reject(cause)));\n\t\t\t\tsocket.once('close', () =>\n\t\t\t\t\tfinish(() =>\n\t\t\t\t\t\treject(new Error('Daemon closed before acknowledging readiness')),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}),\n\t\tcatch: (cause) =>\n\t\t\tnew Error('Could not report readiness 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 readiness')),\n\t\t),\n\t);\n\nexport const publishDaemonReadiness = (value: unknown) =>\n\tEffect.suspend(() => {\n\t\tconst socketPath = process.env.DEVSESS_SOCKET;\n\t\tconst runId = process.env.DEVSESS_RUN_ID;\n\t\tconst service = process.env.DEVSESS_SERVICE;\n\t\tif (\n\t\t\tsocketPath === undefined ||\n\t\t\trunId === undefined ||\n\t\t\tservice === undefined\n\t\t)\n\t\t\treturn Effect.void;\n\t\tconst identity = { socketPath, runId, service };\n\t\treturn Effect.acquireRelease(\n\t\t\tSchema.decodeUnknownEffect(Schema.Json)(value).pipe(\n\t\t\t\tEffect.flatMap((json) =>\n\t\t\t\t\tsendReadiness(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: { runId, service, 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? sendReadiness(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: { runId, service },\n\t\t\t\t\t\t}).pipe(Effect.catch(() => Effect.void))\n\t\t\t\t\t: Effect.void,\n\t\t).pipe(Effect.asVoid);\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 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\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});\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\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\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","Effect","resolve","require","Effect","FileSystem","Path","Data","Effect","FileSystem","Path","SessionState","Effect","S","Effect","Effect"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon-readiness.d.ts","sourceRoot":"","sources":["../../src/dev/daemon-readiness.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAgB,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon-readiness.d.ts","sourceRoot":"","sources":["../../src/dev/daemon-readiness.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAgB,MAAM,QAAQ,CAAC;AAyF9C,eAAO,MAAM,sBAAsB,UAAW,OAAO,6DAkClD,CAAC"}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devsess",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Isolated, managed dev servers — each worktree gets its own session, with its own port and its own database",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/fdarian/devsess#readme",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dev-sessions.ts","../src/dev/running-signal.ts","../src/dev/daemon-readiness.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';\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 { createConnection } from 'node:net';\nimport { StringDecoder } from 'node:string_decoder';\nimport { Effect, Exit, Schema } from 'effect';\n\nconst RESPONSE_TIMEOUT_MS = 200;\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};\n\nconst sendReadiness = (\n\tidentity: ServiceIdentity,\n\trequest: {\n\t\treadonly version: 1;\n\t\treadonly requestId: string;\n\t\treadonly method: 'publish' | 'unpublish';\n\t\treadonly params: {\n\t\t\treadonly runId: string;\n\t\t\treadonly service: string;\n\t\t\treadonly value?: Schema.Json;\n\t\t};\n\t},\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\tconst decoder = new StringDecoder('utf8');\n\t\t\t\tlet input = '';\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() =>\n\t\t\t\t\t\tfinish(() =>\n\t\t\t\t\t\t\treject(new Error('Daemon readiness request timed out')),\n\t\t\t\t\t\t),\n\t\t\t\t\tRESPONSE_TIMEOUT_MS,\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\tsocket.on('data', (chunk) => {\n\t\t\t\t\tinput += decoder.write(chunk);\n\t\t\t\t\tif (Buffer.byteLength(input) > MAX_RESPONSE_BYTES) {\n\t\t\t\t\t\tfinish(() =>\n\t\t\t\t\t\t\treject(new Error('Daemon readiness response is too large')),\n\t\t\t\t\t\t);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst boundary = input.indexOf('\\n');\n\t\t\t\t\tif (boundary !== -1) finish(() => resolve(input.slice(0, boundary)));\n\t\t\t\t});\n\t\t\t\tsocket.once('error', (cause) => finish(() => reject(cause)));\n\t\t\t\tsocket.once('close', () =>\n\t\t\t\t\tfinish(() =>\n\t\t\t\t\t\treject(new Error('Daemon closed before acknowledging readiness')),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}),\n\t\tcatch: (cause) =>\n\t\t\tnew Error('Could not report readiness 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 readiness')),\n\t\t),\n\t);\n\nexport const publishDaemonReadiness = (value: unknown) =>\n\tEffect.suspend(() => {\n\t\tconst socketPath = process.env.DEVSESS_SOCKET;\n\t\tconst runId = process.env.DEVSESS_RUN_ID;\n\t\tconst service = process.env.DEVSESS_SERVICE;\n\t\tif (\n\t\t\tsocketPath === undefined ||\n\t\t\trunId === undefined ||\n\t\t\tservice === undefined\n\t\t)\n\t\t\treturn Effect.void;\n\t\tconst identity = { socketPath, runId, service };\n\t\treturn Effect.acquireRelease(\n\t\t\tSchema.decodeUnknownEffect(Schema.Json)(value).pipe(\n\t\t\t\tEffect.flatMap((json) =>\n\t\t\t\t\tsendReadiness(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: { runId, service, 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? sendReadiness(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: { runId, service },\n\t\t\t\t\t\t}).pipe(Effect.catch(() => Effect.void))\n\t\t\t\t\t: Effect.void,\n\t\t).pipe(Effect.asVoid);\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 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\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});\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\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\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","Effect","resolve","require","Effect","FileSystem","Path","Data","Effect","FileSystem","Path","SessionState","Effect","S","Effect","Effect"]}
|