devsess 0.0.0 → 0.1.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.
Files changed (40) hide show
  1. package/README.md +109 -0
  2. package/dist/async/define-cli.d.ts +20 -0
  3. package/dist/async/define-cli.d.ts.map +1 -0
  4. package/dist/async/dev-sessions.d.ts +16 -0
  5. package/dist/async/dev-sessions.d.ts.map +1 -0
  6. package/dist/async/index.d.ts +8 -0
  7. package/dist/async/index.d.ts.map +1 -0
  8. package/dist/async/index.js +127 -0
  9. package/dist/async/index.js.map +1 -0
  10. package/dist/async/run.d.ts +5 -0
  11. package/dist/async/run.d.ts.map +1 -0
  12. package/dist/async/session-state.d.ts +11 -0
  13. package/dist/async/session-state.d.ts.map +1 -0
  14. package/dist/async/session.d.ts +16 -0
  15. package/dist/async/session.d.ts.map +1 -0
  16. package/dist/chunk-IEQZ3AJH.js +282 -0
  17. package/dist/chunk-IEQZ3AJH.js.map +1 -0
  18. package/dist/dev/define-cli.d.ts +25 -0
  19. package/dist/dev/define-cli.d.ts.map +1 -0
  20. package/dist/dev/run-dev-cli.d.ts +20 -0
  21. package/dist/dev/run-dev-cli.d.ts.map +1 -0
  22. package/dist/dev/running-signal.d.ts +18 -0
  23. package/dist/dev/running-signal.d.ts.map +1 -0
  24. package/dist/dev/session-state.d.ts +23 -0
  25. package/dist/dev/session-state.d.ts.map +1 -0
  26. package/dist/dev/sticky-port.d.ts +4 -0
  27. package/dist/dev/sticky-port.d.ts.map +1 -0
  28. package/dist/dev/subprocess.d.ts +5 -0
  29. package/dist/dev/subprocess.d.ts.map +1 -0
  30. package/dist/dev-sessions.d.ts +32 -0
  31. package/dist/dev-sessions.d.ts.map +1 -0
  32. package/dist/index.d.ts +5 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +50 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/pglite/index.d.ts +50 -0
  37. package/dist/pglite/index.d.ts.map +1 -0
  38. package/dist/pglite/index.js +218 -0
  39. package/dist/pglite/index.js.map +1 -0
  40. package/package.json +87 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dev-sessions.ts","../src/dev/session-state.ts","../src/dev/run-dev-cli.ts","../src/dev/running-signal.ts","../src/dev/sticky-port.ts","../src/dev/subprocess.ts"],"sourcesContent":["import { Array as A, Context, 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\nexport const makeDevSessionsLayer = (rootDir: string) =>\n\tLayer.effect(\n\t\tDevSessions,\n\t\tEffect.gen(function* () {\n\t\t\tconst fs = yield* FileSystem;\n\t\t\tconst path = yield* Path;\n\n\t\t\tyield* Effect.logDebug(`DevSessions dir: ${rootDir}`);\n\t\t\tconst getPath = (relativePath: string) =>\n\t\t\t\tpath.join(rootDir, relativePath);\n\n\t\t\tconst getSessions = Effect.gen(function* () {\n\t\t\t\tconst entries = yield* fs\n\t\t\t\t\t.readDirectory(rootDir)\n\t\t\t\t\t.pipe(Effect.catch(() => Effect.succeed([] as Array<string>)));\n\n\t\t\t\tconst possibleSessions = yield* Effect.all(\n\t\t\t\t\tentries.map((entry) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst stat = yield* fs.stat(getPath(entry));\n\t\t\t\t\t\t\tif (stat.type !== 'Directory') return Option.none();\n\t\t\t\t\t\t\treturn Option.some(\n\t\t\t\t\t\t\t\tDevSession.make({\n\t\t\t\t\t\t\t\t\tname: entry,\n\t\t\t\t\t\t\t\t\tlastModifiedAt: Option.getOrNull(stat.mtime),\n\t\t\t\t\t\t\t\t\trootDir,\n\t\t\t\t\t\t\t\t\tpathJoin: (relativePath: string) =>\n\t\t\t\t\t\t\t\t\t\tpath.join(rootDir, entry, relativePath),\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\t),\n\t\t\t\t\t{ concurrency: 'unbounded' },\n\t\t\t\t);\n\n\t\t\t\treturn A.getSomes(possibleSessions);\n\t\t\t});\n\n\t\t\tconst createSession = Effect.gen(function* () {\n\t\t\t\tconst slug = generateSlug(1, { partsOfSpeech: ['noun'] });\n\t\t\t\tyield* fs.makeDirectory(getPath(slug), { recursive: true });\n\t\t\t\treturn DevSession.make({\n\t\t\t\t\tname: slug,\n\t\t\t\t\tlastModifiedAt: null,\n\t\t\t\t\trootDir,\n\t\t\t\t\tpathJoin: (relativePath: string) =>\n\t\t\t\t\t\tpath.join(rootDir, slug, relativePath),\n\t\t\t\t});\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tdir: rootDir,\n\t\t\t\tpath: getPath,\n\t\t\t\tgetSessions,\n\t\t\t\tcreateSession,\n\t\t\t\tgetLatestOrCreate: Effect.gen(function* () {\n\t\t\t\t\tyield* fs.makeDirectory(rootDir, { recursive: true });\n\n\t\t\t\t\tconst sessions = yield* getSessions;\n\t\t\t\t\tif (sessions.length > 0) {\n\t\t\t\t\t\tsessions.sort(\n\t\t\t\t\t\t\t(a, b) =>\n\t\t\t\t\t\t\t\t(b.lastModifiedAt?.getTime() ?? 0) -\n\t\t\t\t\t\t\t\t(a.lastModifiedAt?.getTime() ?? 0),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst latest = sessions[0];\n\t\t\t\t\t\treturn latest as DevSession;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn yield* createSession;\n\t\t\t\t}),\n\t\t\t};\n\t\t}),\n\t);\n","import { Data, Effect } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport * as S from 'effect/Schema';\nimport type { DevSession } from '../dev-sessions';\n\nexport class SessionStateError extends Data.TaggedError('SessionStateError')<{\n\tmessage: string;\n\tcause?: unknown;\n}> {}\n\nfunction getPath(session: DevSession) {\n\treturn session.path('sess.json');\n}\n\nfunction read(filePath: string) {\n\treturn Effect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\t\tif (!(yield* fs.exists(filePath))) {\n\t\t\treturn null;\n\t\t}\n\t\treturn yield* fs.readFileString(filePath);\n\t});\n}\n\nexport namespace SessionState {\n\ttype Shape = S.Top;\n\n\texport function slot<T extends Shape>(schema: T) {\n\t\treturn {\n\t\t\tread: (session: DevSession) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst filePath = yield* getPath(session);\n\t\t\t\t\tconst content = yield* read(filePath);\n\t\t\t\t\tif (content == null) return null;\n\t\t\t\t\treturn yield* S.decodeEffect(S.fromJsonString(schema))(content).pipe(\n\t\t\t\t\t\tEffect.catchTag('SchemaError', () => Effect.succeed(null)),\n\t\t\t\t\t);\n\t\t\t\t}),\n\t\t\twrite: (session: DevSession, data: T['Type']) =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst fs = yield* FileSystem;\n\t\t\t\t\tconst path = yield* Path;\n\t\t\t\t\tconst filePath = yield* getPath(session);\n\t\t\t\t\tyield* fs.makeDirectory(path.dirname(filePath), { recursive: true });\n\t\t\t\t\tconst existing = yield* read(filePath);\n\t\t\t\t\tconst parsed = yield* Effect.try({\n\t\t\t\t\t\ttry: () => JSON.parse(existing ?? '{}') as Record<string, unknown>,\n\t\t\t\t\t\tcatch: (cause) =>\n\t\t\t\t\t\t\tnew SessionStateError({\n\t\t\t\t\t\t\t\tmessage: `Failed to parse ${filePath} as JSON`,\n\t\t\t\t\t\t\t\tcause,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t});\n\t\t\t\t\tconst merged = { ...parsed, ...(data as Record<string, unknown>) };\n\t\t\t\t\tyield* fs.writeFileString(filePath, JSON.stringify(merged));\n\t\t\t\t}),\n\t\t};\n\t}\n}\n","import { join } from 'node:path';\nimport { NodeRuntime, NodeServices } from '@effect/platform-node';\nimport { Effect, Layer, type Scope } from 'effect';\nimport * as cli from 'effect/unstable/cli';\nimport { type DevSessions, makeDevSessionsLayer } from '../dev-sessions';\n\nexport type CommandConfig = typeof cli.Command.make extends (\n\tname: string,\n\tconfig: infer C,\n\t...rest: Array<unknown>\n) => unknown\n\t? C\n\t: never;\n\ntype CliHandler = (\n\topts: Record<string, unknown>,\n) => Effect.Effect<\n\tvoid,\n\tunknown,\n\tDevSessions | NodeServices.NodeServices | Scope.Scope\n>;\n\n/**\n * Shared CLI scaffolding used by both `defineDevCli` facades (`src/dev/define-cli.ts`\n * for Effect, `src/async/define-cli.ts` for plain-async): builds the `cli.Command`,\n * wires the per-project `DevSessions` + Node platform services layer, and runs it via\n * `NodeRuntime.runMain`. Only the effectful `makeHandler` differs between the two.\n */\nexport const runDevCli = (config: {\n\tname: string;\n\tdir: string;\n\toptions?: CommandConfig;\n\tmakeHandler: CliHandler;\n}): ((argv: string[]) => void) => {\n\tconst command = cli.Command.make(config.name, config.options ?? {}, (opts) =>\n\t\tconfig.makeHandler(opts as Record<string, unknown>),\n\t);\n\n\treturn (argv) => {\n\t\tconst layer = makeDevSessionsLayer(join(config.dir, '.data/sessions')).pipe(\n\t\t\tLayer.provideMerge(NodeServices.layer),\n\t\t);\n\n\t\tconst program = cli.Command.runWith(command, {\n\t\t\tversion: '0.0.0',\n\t\t})(argv);\n\n\t\tNodeRuntime.runMain(Effect.scoped(Effect.provide(program, layer)));\n\t};\n};\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';\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","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":";AAAA,SAAS,SAAS,GAAG,SAAS,QAAQ,OAAO,cAAc;AAC3D,SAAS,kBAAkB;AAC3B,SAAS,YAAY;AAErB,SAAS,oBAAoB;AAE7B,IAAU;AAAA,CAAV,CAAUA,gBAAV;AAQQ,WAAS,KAAK,OAAwB;AAC5C,WAAO;AAAA,MACN,MAAM,MAAM;AAAA,MACZ,gBAAgB,MAAM;AAAA,MACtB,MAAM,CAAC,iBACN,OAAO,QAAQ,MAAM,SAAS,YAAY,CAAC;AAAA,MAC5C,UAAU,MAAM,MAAM;AAAA,IACvB;AAAA,EACD;AARO,EAAAA,YAAS;AAAA,GARP;AAqBH,IAAM,cAAN,cAA0B,QAAQ,QASvC,EAAE,qBAAqB,EAAE;AAAC;AAErB,IAAM,uBAAuB,CAAC,YACpC,MAAM;AAAA,EACL;AAAA,EACA,OAAO,IAAI,aAAa;AACvB,UAAM,KAAK,OAAO;AAClB,UAAM,OAAO,OAAO;AAEpB,WAAO,OAAO,SAAS,oBAAoB,OAAO,EAAE;AACpD,UAAMC,WAAU,CAAC,iBAChB,KAAK,KAAK,SAAS,YAAY;AAEhC,UAAM,cAAc,OAAO,IAAI,aAAa;AAC3C,YAAM,UAAU,OAAO,GACrB,cAAc,OAAO,EACrB,KAAK,OAAO,MAAM,MAAM,OAAO,QAAQ,CAAC,CAAkB,CAAC,CAAC;AAE9D,YAAM,mBAAmB,OAAO,OAAO;AAAA,QACtC,QAAQ;AAAA,UAAI,CAAC,UACZ,OAAO,IAAI,aAAa;AACvB,kBAAM,OAAO,OAAO,GAAG,KAAKA,SAAQ,KAAK,CAAC;AAC1C,gBAAI,KAAK,SAAS,YAAa,QAAO,OAAO,KAAK;AAClD,mBAAO,OAAO;AAAA,cACb,WAAW,KAAK;AAAA,gBACf,MAAM;AAAA,gBACN,gBAAgB,OAAO,UAAU,KAAK,KAAK;AAAA,gBAC3C;AAAA,gBACA,UAAU,CAAC,iBACV,KAAK,KAAK,SAAS,OAAO,YAAY;AAAA,cACxC,CAAC;AAAA,YACF;AAAA,UACD,CAAC;AAAA,QACF;AAAA,QACA,EAAE,aAAa,YAAY;AAAA,MAC5B;AAEA,aAAO,EAAE,SAAS,gBAAgB;AAAA,IACnC,CAAC;AAED,UAAM,gBAAgB,OAAO,IAAI,aAAa;AAC7C,YAAM,OAAO,aAAa,GAAG,EAAE,eAAe,CAAC,MAAM,EAAE,CAAC;AACxD,aAAO,GAAG,cAAcA,SAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC1D,aAAO,WAAW,KAAK;AAAA,QACtB,MAAM;AAAA,QACN,gBAAgB;AAAA,QAChB;AAAA,QACA,UAAU,CAAC,iBACV,KAAK,KAAK,SAAS,MAAM,YAAY;AAAA,MACvC,CAAC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACN,KAAK;AAAA,MACL,MAAMA;AAAA,MACN;AAAA,MACA;AAAA,MACA,mBAAmB,OAAO,IAAI,aAAa;AAC1C,eAAO,GAAG,cAAc,SAAS,EAAE,WAAW,KAAK,CAAC;AAEpD,cAAM,WAAW,OAAO;AACxB,YAAI,SAAS,SAAS,GAAG;AACxB,mBAAS;AAAA,YACR,CAAC,GAAG,OACF,EAAE,gBAAgB,QAAQ,KAAK,MAC/B,EAAE,gBAAgB,QAAQ,KAAK;AAAA,UAClC;AACA,gBAAM,SAAS,SAAS,CAAC;AACzB,iBAAO;AAAA,QACR;AAEA,eAAO,OAAO;AAAA,MACf,CAAC;AAAA,IACF;AAAA,EACD,CAAC;AACF;;;AC/GD,SAAS,MAAM,UAAAC,eAAc;AAC7B,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AACrB,YAAY,OAAO;AAGZ,IAAM,oBAAN,cAAgC,KAAK,YAAY,mBAAmB,EAGxE;AAAC;AAEJ,SAAS,QAAQ,SAAqB;AACrC,SAAO,QAAQ,KAAK,WAAW;AAChC;AAEA,SAAS,KAAK,UAAkB;AAC/B,SAAOF,QAAO,IAAI,aAAa;AAC9B,UAAM,KAAK,OAAOC;AAClB,QAAI,EAAE,OAAO,GAAG,OAAO,QAAQ,IAAI;AAClC,aAAO;AAAA,IACR;AACA,WAAO,OAAO,GAAG,eAAe,QAAQ;AAAA,EACzC,CAAC;AACF;AAEO,IAAU;AAAA,CAAV,CAAUE,kBAAV;AAGC,WAAS,KAAsB,QAAW;AAChD,WAAO;AAAA,MACN,MAAM,CAAC,YACNH,QAAO,IAAI,aAAa;AACvB,cAAM,WAAW,OAAO,QAAQ,OAAO;AACvC,cAAM,UAAU,OAAO,KAAK,QAAQ;AACpC,YAAI,WAAW,KAAM,QAAO;AAC5B,eAAO,OAAS,eAAe,iBAAe,MAAM,CAAC,EAAE,OAAO,EAAE;AAAA,UAC/DA,QAAO,SAAS,eAAe,MAAMA,QAAO,QAAQ,IAAI,CAAC;AAAA,QAC1D;AAAA,MACD,CAAC;AAAA,MACF,OAAO,CAAC,SAAqB,SAC5BA,QAAO,IAAI,aAAa;AACvB,cAAM,KAAK,OAAOC;AAClB,cAAM,OAAO,OAAOC;AACpB,cAAM,WAAW,OAAO,QAAQ,OAAO;AACvC,eAAO,GAAG,cAAc,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AACnE,cAAM,WAAW,OAAO,KAAK,QAAQ;AACrC,cAAM,SAAS,OAAOF,QAAO,IAAI;AAAA,UAChC,KAAK,MAAM,KAAK,MAAM,YAAY,IAAI;AAAA,UACtC,OAAO,CAAC,UACP,IAAI,kBAAkB;AAAA,YACrB,SAAS,mBAAmB,QAAQ;AAAA,YACpC;AAAA,UACD,CAAC;AAAA,QACH,CAAC;AACD,cAAM,SAAS,EAAE,GAAG,QAAQ,GAAI,KAAiC;AACjE,eAAO,GAAG,gBAAgB,UAAU,KAAK,UAAU,MAAM,CAAC;AAAA,MAC3D,CAAC;AAAA,IACH;AAAA,EACD;AA9BO,EAAAG,cAAS;AAAA,GAHA;;;ACzBjB,SAAS,YAAY;AACrB,SAAS,aAAa,oBAAoB;AAC1C,SAAS,UAAAC,SAAQ,SAAAC,cAAyB;AAC1C,YAAY,SAAS;AAyBd,IAAM,YAAY,CAAC,WAKQ;AACjC,QAAM,UAAc,YAAQ;AAAA,IAAK,OAAO;AAAA,IAAM,OAAO,WAAW,CAAC;AAAA,IAAG,CAAC,SACpE,OAAO,YAAY,IAA+B;AAAA,EACnD;AAEA,SAAO,CAAC,SAAS;AAChB,UAAM,QAAQ,qBAAqB,KAAK,OAAO,KAAK,gBAAgB,CAAC,EAAE;AAAA,MACtEC,OAAM,aAAa,aAAa,KAAK;AAAA,IACtC;AAEA,UAAM,UAAc,YAAQ,QAAQ,SAAS;AAAA,MAC5C,SAAS;AAAA,IACV,CAAC,EAAE,IAAI;AAEP,gBAAY,QAAQC,QAAO,OAAOA,QAAO,QAAQ,SAAS,KAAK,CAAC,CAAC;AAAA,EAClE;AACD;;;ACjDA,SAAS,SAAS,SAAS,oBAAoB;AAC/C,SAAS,qBAAqB;AAC9B,SAAS,SAAS,QAAAC,OAAM,eAAe;AACvC,SAAS,UAAU,UAAAC,eAAc;AACjC,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,QAAAC,aAAY;AAErB,IAAM,sBAAsB;AAGrB,IAAM,oBAAoB,CAAC,QACjCH,MAAK,KAAK,mBAAmB;AAOvB,IAAM,oBAAoB,CAAC,MAAc,YAAoB;AACnE,MAAI,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,GAAG;AACjD,WAAO,QAAQ,SAAS,IAAI;AAAA,EAC7B;AACA,QAAMI,WAAU,cAAcJ,MAAK,SAAS,cAAc,CAAC;AAC3D,QAAM,cAAcI,SAAQ,QAAQ,GAAG,IAAI,eAAe;AAC1D,SAAO,QAAQ,aAAa,WAAW,CAAC;AACzC;AAGO,IAAM,uBAAuB,CAAC,UAAkB,UACtDH,QAAO;AAAA,EACNA,QAAO,IAAI,aAAa;AACvB,UAAM,KAAK,OAAOC;AAClB,UAAM,OAAO,OAAOC;AACpB,UAAM,MAAM,GAAG,QAAQ;AACvB,WAAO,GAAG,cAAc,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAEnE,WAAO,GAAG,gBAAgB,KAAK,KAAK,UAAU,KAAK,CAAC;AACpD,WAAO,GAAG,OAAO,KAAK,QAAQ;AAAA,EAC/B,CAAC;AAAA,EACD,MACCF,QAAO,IAAI,aAAa;AACvB,UAAM,KAAK,OAAOC;AAClB,WAAO,GAAG,OAAO,QAAQ,EAAE,KAAKD,QAAO,MAAM,MAAMA,QAAO,IAAI,CAAC;AAAA,EAChE,CAAC;AACH;AAGM,IAAM,qBAAqB,CACjC,UACA,SAEAA,QAAO;AAAA,EACNA,QAAO,IAAI,aAAa;AACvB,UAAM,KAAK,OAAOC;AAClB,UAAM,OAAO,OAAOC;AACpB,UAAM,MAAM,KAAK,QAAQ,QAAQ;AACjC,UAAM,WAAW,KAAK,SAAS,QAAQ;AAEvC,UAAM,WAAW,OAAO,SAAS,KAAQ;AAEzC,UAAM,UAAUF,QAAO,IAAI,aAAa;AACvC,UAAI,EAAE,OAAO,GAAG,OAAO,QAAQ,GAAI,QAAO;AAC1C,YAAM,MAAM,OAAO,GACjB,eAAe,QAAQ,EACvB,KAAKA,QAAO,MAAM,MAAMA,QAAO,QAAQ,IAAI,CAAC,CAAC;AAC/C,UAAI,OAAO,KAAM,QAAO;AACxB,YAAM,SAAS,OAAOA,QAAO,IAAI,MAAM,KAAK,MAAM,GAAG,CAAC,EAAE;AAAA,QACvDA,QAAO,MAAM,MAAMA,QAAO,QAAQ,IAAI,CAAC;AAAA,MACxC;AACA,UAAI,UAAU,KAAM,QAAO;AAC3B,aAAO,SAAS,QAAQ,UAAU,MAAM;AACxC,aAAO;AAAA,IACR,CAAC;AAID,WAAO,GAAG,cAAc,KAAK,EAAE,WAAW,KAAK,CAAC;AAEhD,WAAOA,QAAO;AAAA,MACbA,QAAO;AAAA,QAAK;AAAA;AAAA,UAEX,QAAQ,KAAK,EAAE,WAAW,MAAM,GAAG,CAAC,WAAW,kBAAkB;AAChE,gBAAI,kBAAkB,SAAU;AAChC,gBAAI,cAAc,YAAY,cAAc,SAAU;AACtD,YAAAA,QAAO,QAAQ,OAAO;AAAA,UACvB,CAAC;AAAA;AAAA,MACF;AAAA,MACA,CAAC,YAAYA,QAAO,KAAK,MAAM,QAAQ,MAAM,CAAC;AAAA,IAC/C;AAEA,WAAO;AACP,WAAO,OAAO,SAAS,MAAM,QAAQ;AAAA,EACtC,CAAC;AACF;;;AC7FD,SAAS,UAAAI,eAAc;AACvB,YAAYC,QAAO;AACnB,OAAO,aAAa;AAIpB,IAAM,aAAa,aAAa,KAAO,UAAO,EAAE,MAAQ,UAAO,CAAC,CAAC;AAE1D,IAAM,gBAAgB,CAAC,YAC7BC,QAAO,IAAI,aAAa;AACvB,QAAM,OAAO,OAAO,WAAW,KAAK,OAAO;AAC3C,QAAM,YAAY,MAAM;AAExB,QAAM,OAAO,OAAOA,QAAO;AAAA,IAAQ,YAClC,QAAQ;AAAA,MACP,MAAM,cAAc,SAAY,CAAC,SAAS,IAAI;AAAA,IAC/C,CAAC;AAAA,EACF;AAEA,SAAO,WAAW,MAAM,SAAS,EAAE,KAAK,CAAC;AAEzC,SAAO;AACR,CAAC;;;ACtBF,SAAS,UAAAC,eAAc;AACvB,SAAS,oBAAoB;AAEtB,IAAM,uBAAuB,CACnC,KACA,MACA,SAEAA,QAAO,IAAI,aAAa;AACvB,QAAM,UAAU,aAAa,KAAK,KAAK,MAAM;AAAA,IAC5C,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,KAAK,EAAE,GAAG,QAAQ,KAAK,GAAI,MAAM,OAAO,CAAC,EAAG;AAAA,EAC7C,CAAC;AAED,QAAM,QAAQ,CAAC,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG;AAKrC,QAAM,QAAQ,OAAOA,QAAO;AAAA,IAC3BA,QAAO,IAAI,aAAa;AACvB,YAAM,OAAO,OAAO;AACpB,aAAOA,QAAO,QAAQ,kBAAkB,KAAK,SAAS,KAAK,GAAG,GAAG;AACjE,aAAO;AAAA,IACR,CAAC;AAAA,IACD,CAAC,SACAA,QAAO,IAAI,aAAa;AACvB,aAAOA,QAAO,QAAQ,mBAAmB,KAAK,SAAS,KAAK,GAAG,GAAG;AAClE,aAAO,KACL,KAAK,EACL;AAAA,QACAA,QAAO;AAAA,UAAM,CAAC,QACbA,QAAO;AAAA,YACN,wBAAwB,KAAK,SAAS,KAAK,GAAG,MAAM,GAAG;AAAA,UACxD;AAAA,QACD;AAAA,MACD;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO,OAAO,MAAM;AACrB,CAAC;","names":["DevSession","getPath","Effect","FileSystem","Path","SessionState","Effect","Layer","Layer","Effect","join","Effect","FileSystem","Path","require","Effect","S","Effect","Effect"]}
@@ -0,0 +1,25 @@
1
+ import type { NodeServices } from '@effect/platform-node';
2
+ import { Effect, type Scope } from 'effect';
3
+ import type { FileSystem } from 'effect/FileSystem';
4
+ import type { Path } from 'effect/Path';
5
+ import type { PlatformError } from 'effect/PlatformError';
6
+ import { type DevSession, DevSessions } from '../dev-sessions';
7
+ import { type CommandConfig } from './run-dev-cli';
8
+ import { getStickyPort } from './sticky-port';
9
+ import { runManagedSubprocess } from './subprocess';
10
+ type RunContext = {
11
+ session: Effect.Effect<DevSession, PlatformError>;
12
+ getStickyPort: () => ReturnType<typeof getStickyPort>;
13
+ runManagedSubprocess: typeof runManagedSubprocess;
14
+ publishRunning: (data: unknown) => Effect.Effect<void, PlatformError, Scope.Scope | FileSystem | Path>;
15
+ awaitRunning: <T>(pkg: string) => Effect.Effect<T, PlatformError, FileSystem | Path>;
16
+ };
17
+ type RunEffect = Effect.Effect<void, unknown, DevSessions | NodeServices.NodeServices | Scope.Scope>;
18
+ export declare const defineDevCli: (config: {
19
+ name: string;
20
+ dir: string;
21
+ options?: CommandConfig;
22
+ run: (ctx: RunContext, opts: Record<string, unknown>) => RunEffect;
23
+ }) => ((argv: string[]) => void);
24
+ export {};
25
+ //# sourceMappingURL=define-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-cli.d.ts","sourceRoot":"","sources":["../../src/dev/define-cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,KAAK,UAAU,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC/D,OAAO,EAAE,KAAK,aAAa,EAAa,MAAM,eAAe,CAAC;AAO9D,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,KAAK,UAAU,GAAG;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAClD,aAAa,EAAE,MAAM,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;IACtD,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD,cAAc,EAAE,CACf,IAAI,EAAE,OAAO,KACT,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,KAAK,GAAG,UAAU,GAAG,IAAI,CAAC,CAAC;IACzE,YAAY,EAAE,CAAC,CAAC,EACf,GAAG,EAAE,MAAM,KACP,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,GAAG,IAAI,CAAC,CAAC;CACxD,CAAC;AAEF,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,CAC7B,IAAI,EACJ,OAAO,EACP,WAAW,GAAG,YAAY,CAAC,YAAY,GAAG,KAAK,CAAC,KAAK,CACrD,CAAC;AAEF,eAAO,MAAM,YAAY,WAAY;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,GAAG,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,CAAC;CACnE,KAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAyB1B,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { NodeServices } from '@effect/platform-node';
2
+ import { Effect, type Scope } from 'effect';
3
+ import * as cli from 'effect/unstable/cli';
4
+ import { type DevSessions } from '../dev-sessions';
5
+ export type CommandConfig = typeof cli.Command.make extends (name: string, config: infer C, ...rest: Array<unknown>) => unknown ? C : never;
6
+ type CliHandler = (opts: Record<string, unknown>) => Effect.Effect<void, unknown, DevSessions | NodeServices.NodeServices | Scope.Scope>;
7
+ /**
8
+ * Shared CLI scaffolding used by both `defineDevCli` facades (`src/dev/define-cli.ts`
9
+ * for Effect, `src/async/define-cli.ts` for plain-async): builds the `cli.Command`,
10
+ * wires the per-project `DevSessions` + Node platform services layer, and runs it via
11
+ * `NodeRuntime.runMain`. Only the effectful `makeHandler` differs between the two.
12
+ */
13
+ export declare const runDevCli: (config: {
14
+ name: string;
15
+ dir: string;
16
+ options?: CommandConfig;
17
+ makeHandler: CliHandler;
18
+ }) => ((argv: string[]) => void);
19
+ export {};
20
+ //# sourceMappingURL=run-dev-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-dev-cli.d.ts","sourceRoot":"","sources":["../../src/dev/run-dev-cli.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAS,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,KAAK,WAAW,EAAwB,MAAM,iBAAiB,CAAC;AAEzE,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,SAAS,CAC3D,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,EACf,GAAG,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,KACnB,OAAO,GACT,CAAC,GACD,KAAK,CAAC;AAET,KAAK,UAAU,GAAG,CACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACzB,MAAM,CAAC,MAAM,CACjB,IAAI,EACJ,OAAO,EACP,WAAW,GAAG,YAAY,CAAC,YAAY,GAAG,KAAK,CAAC,KAAK,CACrD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,WAAY;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,UAAU,CAAC;CACxB,KAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAgB5B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { Effect } from 'effect';
2
+ import { FileSystem } from 'effect/FileSystem';
3
+ import { Path } from 'effect/Path';
4
+ /** Path to the running-signal file for a dev-session (or sibling package) directory. */
5
+ export declare const runningSignalPath: (dir: string) => string;
6
+ /**
7
+ * Resolves `spec` to a directory: relative/absolute paths are resolved against
8
+ * `fromDir`, anything else is treated as a package name and resolved via its
9
+ * `package.json`.
10
+ */
11
+ export declare const resolveSiblingDir: (spec: string, fromDir: string) => string;
12
+ /** Atomically writes `value` as JSON to `filePath` and removes it on release. */
13
+ export declare const publishRunningSignal: (filePath: string, value: unknown) => Effect.Effect<void, import("effect/PlatformError").PlatformError, FileSystem | Path | import("effect/Scope").Scope>;
14
+ /** Watches parent directory for the signal file and resolves once it can be parsed. */
15
+ export declare const awaitRunningSignal: <T>(filePath: string, opts: {
16
+ parse: (raw: string) => T;
17
+ }) => Effect.Effect<T, import("effect/PlatformError").PlatformError, FileSystem | Path>;
18
+ //# 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;AAInC,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"}
@@ -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,32 @@
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
+ export declare const makeDevSessionsLayer: (rootDir: string) => Layer.Layer<DevSessions, never, FileSystem | Path>;
31
+ export {};
32
+ //# 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,EAAE,MAAM,EAAE,KAAK,EAAU,MAAM,QAAQ,CAAC;AACpE,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;CAAG;AAE7B,eAAO,MAAM,oBAAoB,YAAa,MAAM,uDAyElD,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * as cli from 'effect/unstable/cli';
2
+ export { defineDevCli } from './dev/define-cli';
3
+ export { SessionState, SessionStateError } from './dev/session-state';
4
+ export { type DevSession, DevSessions, makeDevSessionsLayer, } from './dev-sessions';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,GAAG,MAAM,qBAAqB,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EACN,KAAK,UAAU,EACf,WAAW,EACX,oBAAoB,GACpB,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ import {
2
+ DevSessions,
3
+ SessionState,
4
+ SessionStateError,
5
+ awaitRunningSignal,
6
+ getStickyPort,
7
+ makeDevSessionsLayer,
8
+ publishRunningSignal,
9
+ resolveSiblingDir,
10
+ runDevCli,
11
+ runManagedSubprocess,
12
+ runningSignalPath
13
+ } from "./chunk-IEQZ3AJH.js";
14
+
15
+ // src/index.ts
16
+ import * as cli from "effect/unstable/cli";
17
+
18
+ // src/dev/define-cli.ts
19
+ import { Effect } from "effect";
20
+ var defineDevCli = (config) => runDevCli({
21
+ name: config.name,
22
+ dir: config.dir,
23
+ options: config.options,
24
+ makeHandler: (opts) => Effect.gen(function* () {
25
+ const sessions = yield* DevSessions;
26
+ const session = yield* Effect.cached(sessions.getLatestOrCreate);
27
+ return yield* config.run(
28
+ {
29
+ session,
30
+ getStickyPort: () => Effect.flatMap(session, getStickyPort),
31
+ runManagedSubprocess,
32
+ publishRunning: (data) => publishRunningSignal(runningSignalPath(config.dir), data),
33
+ awaitRunning: (pkg) => awaitRunningSignal(
34
+ runningSignalPath(resolveSiblingDir(pkg, config.dir)),
35
+ { parse: (raw) => JSON.parse(raw) }
36
+ )
37
+ },
38
+ opts
39
+ );
40
+ })
41
+ });
42
+ export {
43
+ DevSessions,
44
+ SessionState,
45
+ SessionStateError,
46
+ cli,
47
+ defineDevCli,
48
+ makeDevSessionsLayer
49
+ };
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/dev/define-cli.ts"],"sourcesContent":["// Re-exported so consumers can declare CLI flags/arguments without a direct\n// dependency on `effect/unstable/cli`, e.g. `cli.Flag.string('local')`.\nexport * as cli from 'effect/unstable/cli';\n\nexport { defineDevCli } from './dev/define-cli';\nexport { SessionState, SessionStateError } from './dev/session-state';\nexport {\n\ttype DevSession,\n\tDevSessions,\n\tmakeDevSessionsLayer,\n} from './dev-sessions';\n","import type { NodeServices } from '@effect/platform-node';\nimport { Effect, type Scope } from 'effect';\nimport type { FileSystem } from 'effect/FileSystem';\nimport type { Path } from 'effect/Path';\nimport type { PlatformError } from 'effect/PlatformError';\nimport { type DevSession, DevSessions } from '../dev-sessions';\nimport { type CommandConfig, runDevCli } from './run-dev-cli';\nimport {\n\tawaitRunningSignal,\n\tpublishRunningSignal,\n\tresolveSiblingDir,\n\trunningSignalPath,\n} from './running-signal';\nimport { getStickyPort } from './sticky-port';\nimport { runManagedSubprocess } from './subprocess';\n\ntype RunContext = {\n\tsession: Effect.Effect<DevSession, PlatformError>;\n\tgetStickyPort: () => ReturnType<typeof getStickyPort>;\n\trunManagedSubprocess: typeof runManagedSubprocess;\n\tpublishRunning: (\n\t\tdata: unknown,\n\t) => Effect.Effect<void, PlatformError, Scope.Scope | FileSystem | Path>;\n\tawaitRunning: <T>(\n\t\tpkg: string,\n\t) => Effect.Effect<T, PlatformError, FileSystem | Path>;\n};\n\ntype RunEffect = Effect.Effect<\n\tvoid,\n\tunknown,\n\tDevSessions | NodeServices.NodeServices | Scope.Scope\n>;\n\nexport const defineDevCli = (config: {\n\tname: string;\n\tdir: string;\n\toptions?: CommandConfig;\n\trun: (ctx: RunContext, opts: Record<string, unknown>) => RunEffect;\n}): ((argv: string[]) => void) =>\n\trunDevCli({\n\t\tname: config.name,\n\t\tdir: config.dir,\n\t\toptions: config.options,\n\t\tmakeHandler: (opts) =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst sessions = yield* DevSessions;\n\t\t\t\tconst session = yield* Effect.cached(sessions.getLatestOrCreate);\n\t\t\t\treturn yield* config.run(\n\t\t\t\t\t{\n\t\t\t\t\t\tsession,\n\t\t\t\t\t\tgetStickyPort: () => Effect.flatMap(session, getStickyPort),\n\t\t\t\t\t\trunManagedSubprocess,\n\t\t\t\t\t\tpublishRunning: (data) =>\n\t\t\t\t\t\t\tpublishRunningSignal(runningSignalPath(config.dir), data),\n\t\t\t\t\t\tawaitRunning: <T>(pkg: string) =>\n\t\t\t\t\t\t\tawaitRunningSignal<T>(\n\t\t\t\t\t\t\t\trunningSignalPath(resolveSiblingDir(pkg, config.dir)),\n\t\t\t\t\t\t\t\t{ parse: (raw) => JSON.parse(raw) as T },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\topts,\n\t\t\t\t);\n\t\t\t}),\n\t});\n"],"mappings":";;;;;;;;;;;;;;;AAEA,YAAY,SAAS;;;ACDrB,SAAS,cAA0B;AAiC5B,IAAM,eAAe,CAAC,WAM5B,UAAU;AAAA,EACT,MAAM,OAAO;AAAA,EACb,KAAK,OAAO;AAAA,EACZ,SAAS,OAAO;AAAA,EAChB,aAAa,CAAC,SACb,OAAO,IAAI,aAAa;AACvB,UAAM,WAAW,OAAO;AACxB,UAAM,UAAU,OAAO,OAAO,OAAO,SAAS,iBAAiB;AAC/D,WAAO,OAAO,OAAO;AAAA,MACpB;AAAA,QACC;AAAA,QACA,eAAe,MAAM,OAAO,QAAQ,SAAS,aAAa;AAAA,QAC1D;AAAA,QACA,gBAAgB,CAAC,SAChB,qBAAqB,kBAAkB,OAAO,GAAG,GAAG,IAAI;AAAA,QACzD,cAAc,CAAI,QACjB;AAAA,UACC,kBAAkB,kBAAkB,KAAK,OAAO,GAAG,CAAC;AAAA,UACpD,EAAE,OAAO,CAAC,QAAQ,KAAK,MAAM,GAAG,EAAO;AAAA,QACxC;AAAA,MACF;AAAA,MACA;AAAA,IACD;AAAA,EACD,CAAC;AACH,CAAC;","names":[]}
@@ -0,0 +1,50 @@
1
+ import { PGlite } from '@electric-sql/pglite';
2
+ import { Effect } from 'effect';
3
+ import { FileSystem } from 'effect/FileSystem';
4
+ import { Path } from 'effect/Path';
5
+ import type { DevSession } from '../dev-sessions';
6
+ declare const PgliteError_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: "PgliteError";
8
+ } & Readonly<A>;
9
+ export declare class PgliteError extends PgliteError_base<{
10
+ message: string;
11
+ cause?: unknown;
12
+ }> {
13
+ }
14
+ export type PgliteMigrations = {
15
+ migrationsFolder: string;
16
+ migrationsTable?: string;
17
+ migrationsSchema?: string;
18
+ };
19
+ export declare const createPgliteFromDump: (opts: {
20
+ dataDir?: string;
21
+ dumpPath: string;
22
+ }) => Effect.Effect<PGlite, PgliteError | import("effect/PlatformError").PlatformError, FileSystem>;
23
+ export declare const dumpPgliteToFile: (client: PGlite, dest: string) => Effect.Effect<void, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
24
+ export declare const migratePglite: (client: PGlite, migrations: PgliteMigrations) => Effect.Effect<void, PgliteError, never>;
25
+ export declare const getDbMigrationCount: (client: PGlite, migrations?: Pick<PgliteMigrations, 'migrationsTable' | 'migrationsSchema'>) => Effect.Effect<number, PgliteError, never>;
26
+ export declare const getExpectedMigrationCount: (migrationsFolder: string) => Effect.Effect<number, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
27
+ export declare const buildPgliteDump: (opts: PgliteMigrations & {
28
+ dumpPath: string;
29
+ }) => Effect.Effect<void, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
30
+ export declare const ensurePgliteDump: (opts: PgliteMigrations & {
31
+ dumpPath: string;
32
+ }) => Effect.Effect<void, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
33
+ export declare const openLitePglite: (opts: PgliteMigrations & {
34
+ dataDir: string;
35
+ dumpPath: string;
36
+ }) => Effect.Effect<PGlite, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
37
+ /**
38
+ * Prepares a PGlite database scoped to a dev session: the data dir lives at
39
+ * `<session>/pglite` and the migration dump at `<session>/pglite.dump`. Builds
40
+ * the dump from `migrationsFolder` if missing, hydrates the client, and runs
41
+ * pending migrations. Returns the open client plus the resolved paths so the
42
+ * caller can pass them to the app (e.g. as `DATABASE_LITE_PATH`).
43
+ */
44
+ export declare const prepareSessionPglite: (session: DevSession, opts: PgliteMigrations) => Effect.Effect<{
45
+ client: PGlite;
46
+ dataDir: string;
47
+ dumpPath: string;
48
+ }, PgliteError | import("effect/PlatformError").PlatformError, FileSystem | Path>;
49
+ export {};
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/pglite/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAG9C,OAAO,EAAQ,MAAM,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;;;;AAElD,qBAAa,WAAY,SAAQ,iBAAgC;IAChE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB,CAAC;CAAG;AAQL,MAAM,MAAM,gBAAgB,GAAG;IAC9B,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAwBF,eAAO,MAAM,oBAAoB,SAAU;IAC1C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CACjB,kGAsBE,CAAC;AAeJ,eAAO,MAAM,gBAAgB,WAAY,MAAM,QAAQ,MAAM,uGAuB1D,CAAC;AAEJ,eAAO,MAAM,aAAa,WAAY,MAAM,cAAc,gBAAgB,4CAavE,CAAC;AAYJ,eAAO,MAAM,mBAAmB,WACvB,MAAM,eACD,IAAI,CAAC,gBAAgB,EAAE,iBAAiB,GAAG,kBAAkB,CAAC,8CA4DzE,CAAC;AAEJ,eAAO,MAAM,yBAAyB,qBAAsB,MAAM,yGA8B/D,CAAC;AAEJ,eAAO,MAAM,eAAe,SACrB,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,uGAO3C,CAAC;AAEJ,eAAO,MAAM,gBAAgB,SACtB,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,uGAQ3C,CAAC;AAEJ,eAAO,MAAM,cAAc,SACpB,gBAAgB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,yGAwB5D,CAAC;AAEJ;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,YACvB,UAAU,QACb,gBAAgB;;;;iFAWpB,CAAC"}
@@ -0,0 +1,218 @@
1
+ // src/pglite/index.ts
2
+ import { PGlite } from "@electric-sql/pglite";
3
+ import { drizzle } from "drizzle-orm/pglite";
4
+ import { migrate } from "drizzle-orm/pglite/migrator";
5
+ import { Data, Effect } from "effect";
6
+ import { FileSystem } from "effect/FileSystem";
7
+ import { Path } from "effect/Path";
8
+ var PgliteError = class extends Data.TaggedError("PgliteError") {
9
+ };
10
+ var IN_MEMORY_DATA_DIR = "memory://";
11
+ var DEFAULT_MIGRATIONS_TABLE = "__drizzle_migrations";
12
+ var DEFAULT_MIGRATIONS_SCHEMA = "drizzle";
13
+ var quoteIdentifierPart = (part) => `"${part.replaceAll('"', '""')}"`;
14
+ var qualifiedMigrationsTable = (migrations) => `${quoteIdentifierPart(migrations.migrationsSchema ?? DEFAULT_MIGRATIONS_SCHEMA)}.${quoteIdentifierPart(migrations.migrationsTable ?? DEFAULT_MIGRATIONS_TABLE)}`;
15
+ var shouldReuseExistingDatabase = (dataDir) => Effect.gen(function* () {
16
+ if (!dataDir || dataDir === IN_MEMORY_DATA_DIR) {
17
+ return false;
18
+ }
19
+ const fs = yield* FileSystem;
20
+ return yield* fs.exists(dataDir);
21
+ });
22
+ var createPgliteFromDump = (opts) => Effect.gen(function* () {
23
+ const fs = yield* FileSystem;
24
+ if (yield* shouldReuseExistingDatabase(opts.dataDir)) {
25
+ return new PGlite(opts.dataDir);
26
+ }
27
+ if (!(yield* fs.exists(opts.dumpPath))) {
28
+ return yield* new PgliteError({
29
+ message: `Dump file not found at ${opts.dumpPath}`
30
+ });
31
+ }
32
+ const buffer = yield* fs.readFile(opts.dumpPath);
33
+ const file = new Blob([new Uint8Array(buffer)]);
34
+ const client = new PGlite(opts.dataDir, {
35
+ loadDataDir: file
36
+ });
37
+ return client;
38
+ });
39
+ var toUint8Array = (input) => Effect.gen(function* () {
40
+ const buf = yield* Effect.tryPromise({
41
+ try: () => input.arrayBuffer(),
42
+ catch: (error) => new PgliteError({
43
+ message: "Failed to convert dump to Uint8Array",
44
+ cause: error
45
+ })
46
+ });
47
+ return new Uint8Array(buf);
48
+ });
49
+ var dumpPgliteToFile = (client, dest) => Effect.gen(function* () {
50
+ const fs = yield* FileSystem;
51
+ const path = yield* Path;
52
+ const destDir = path.dirname(dest);
53
+ const dirExists = yield* fs.exists(destDir);
54
+ if (!dirExists) {
55
+ yield* fs.makeDirectory(destDir, { recursive: true });
56
+ }
57
+ const dump = yield* Effect.tryPromise({
58
+ try: () => client.dumpDataDir(),
59
+ catch: (error) => new PgliteError({
60
+ message: "Failed to dump PGlite database",
61
+ cause: error
62
+ })
63
+ });
64
+ const data = yield* toUint8Array(dump);
65
+ yield* fs.writeFile(dest, data);
66
+ });
67
+ var migratePglite = (client, migrations) => Effect.tryPromise({
68
+ try: () => migrate(drizzle(client), {
69
+ migrationsFolder: migrations.migrationsFolder,
70
+ migrationsTable: migrations.migrationsTable,
71
+ migrationsSchema: migrations.migrationsSchema
72
+ }),
73
+ catch: (error) => new PgliteError({
74
+ message: `Failed to migrate pglite from ${migrations.migrationsFolder}`,
75
+ cause: error
76
+ })
77
+ });
78
+ var closePglite = (client) => Effect.tryPromise({
79
+ try: () => client.close(),
80
+ catch: (error) => new PgliteError({
81
+ message: "Failed to close PGlite client",
82
+ cause: error
83
+ })
84
+ });
85
+ var getDbMigrationCount = (client, migrations) => Effect.gen(function* () {
86
+ const qualifiedTable = qualifiedMigrationsTable(migrations ?? {});
87
+ yield* Effect.tryPromise({
88
+ try: () => client.waitReady,
89
+ catch: (error) => new PgliteError({
90
+ message: "Failed to wait for PGlite ready",
91
+ cause: error
92
+ })
93
+ });
94
+ const existsResult = yield* Effect.tryPromise({
95
+ try: () => client.query(
96
+ 'SELECT to_regclass($1) IS NOT NULL AS "exists"',
97
+ [qualifiedTable]
98
+ ),
99
+ catch: (error) => new PgliteError({
100
+ message: "Failed to check drizzle migrations table",
101
+ cause: error
102
+ })
103
+ });
104
+ const existsRow = existsResult.rows[0];
105
+ if (!existsRow) {
106
+ return yield* Effect.fail(
107
+ new PgliteError({
108
+ message: "Missing row from drizzle migrations existence check"
109
+ })
110
+ );
111
+ }
112
+ if (!existsRow.exists) {
113
+ return 0;
114
+ }
115
+ const countResult = yield* Effect.tryPromise({
116
+ try: () => client.query(
117
+ `SELECT count(*)::int AS c FROM ${qualifiedTable}`
118
+ ),
119
+ catch: (error) => new PgliteError({
120
+ message: "Failed to count drizzle migrations",
121
+ cause: error
122
+ })
123
+ });
124
+ const countRow = countResult.rows[0];
125
+ if (!countRow) {
126
+ return yield* Effect.fail(
127
+ new PgliteError({
128
+ message: "Missing row from drizzle migrations count query"
129
+ })
130
+ );
131
+ }
132
+ return countRow.c;
133
+ });
134
+ var getExpectedMigrationCount = (migrationsFolder) => Effect.gen(function* () {
135
+ const fs = yield* FileSystem;
136
+ const path = yield* Path;
137
+ const journalPath = path.join(migrationsFolder, "meta/_journal.json");
138
+ const journalExists = yield* fs.exists(journalPath);
139
+ if (!journalExists) {
140
+ return yield* Effect.fail(
141
+ new PgliteError({
142
+ message: `Migration journal not found at ${journalPath}`
143
+ })
144
+ );
145
+ }
146
+ const content = yield* fs.readFileString(journalPath);
147
+ const journal = yield* Effect.try({
148
+ try: () => JSON.parse(content),
149
+ catch: (cause) => new PgliteError({
150
+ message: `Failed to parse migration journal at ${journalPath}`,
151
+ cause
152
+ })
153
+ });
154
+ if (!Array.isArray(journal.entries)) {
155
+ return yield* Effect.fail(
156
+ new PgliteError({
157
+ message: `Migration journal at ${journalPath} is missing an "entries" array`
158
+ })
159
+ );
160
+ }
161
+ return journal.entries.length;
162
+ });
163
+ var buildPgliteDump = (opts) => Effect.gen(function* () {
164
+ const client = new PGlite(IN_MEMORY_DATA_DIR);
165
+ yield* migratePglite(client, opts);
166
+ yield* dumpPgliteToFile(client, opts.dumpPath);
167
+ yield* closePglite(client);
168
+ });
169
+ var ensurePgliteDump = (opts) => Effect.gen(function* () {
170
+ const fs = yield* FileSystem;
171
+ const dumpExists = yield* fs.exists(opts.dumpPath);
172
+ if (!dumpExists) {
173
+ yield* buildPgliteDump(opts);
174
+ }
175
+ });
176
+ var openLitePglite = (opts) => Effect.gen(function* () {
177
+ yield* ensurePgliteDump(opts);
178
+ const client = yield* createPgliteFromDump({
179
+ dataDir: opts.dataDir,
180
+ dumpPath: opts.dumpPath
181
+ });
182
+ const expected = yield* getExpectedMigrationCount(opts.migrationsFolder);
183
+ const actual = yield* getDbMigrationCount(client, opts);
184
+ const predatesMigrationJournal = expected > 0 && actual === 0;
185
+ if (predatesMigrationJournal) {
186
+ return yield* Effect.fail(
187
+ new PgliteError({
188
+ message: `Stale local pglite at ${opts.dataDir} (schema present, no migration journal) \u2014 it was built by an older scheme. Remove it and the dump, then restart:
189
+ rm -rf ${opts.dataDir} ${opts.dumpPath}`
190
+ })
191
+ );
192
+ }
193
+ yield* migratePglite(client, opts);
194
+ return client;
195
+ });
196
+ var prepareSessionPglite = (session, opts) => Effect.gen(function* () {
197
+ const dataDir = yield* session.path("pglite");
198
+ const dumpPath = yield* session.path("pglite.dump");
199
+ const client = yield* openLitePglite({
200
+ ...opts,
201
+ dataDir,
202
+ dumpPath
203
+ });
204
+ return { client, dataDir, dumpPath };
205
+ });
206
+ export {
207
+ PgliteError,
208
+ buildPgliteDump,
209
+ createPgliteFromDump,
210
+ dumpPgliteToFile,
211
+ ensurePgliteDump,
212
+ getDbMigrationCount,
213
+ getExpectedMigrationCount,
214
+ migratePglite,
215
+ openLitePglite,
216
+ prepareSessionPglite
217
+ };
218
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/pglite/index.ts"],"sourcesContent":["import { PGlite } from '@electric-sql/pglite';\nimport { drizzle } from 'drizzle-orm/pglite';\nimport { migrate } from 'drizzle-orm/pglite/migrator';\nimport { Data, Effect } from 'effect';\nimport { FileSystem } from 'effect/FileSystem';\nimport { Path } from 'effect/Path';\nimport type { DevSession } from '../dev-sessions';\n\nexport class PgliteError extends Data.TaggedError('PgliteError')<{\n\tmessage: string;\n\tcause?: unknown;\n}> {}\n\nconst IN_MEMORY_DATA_DIR = 'memory://';\n\n/** Drizzle's own defaults, used whenever a caller doesn't override them. */\nconst DEFAULT_MIGRATIONS_TABLE = '__drizzle_migrations';\nconst DEFAULT_MIGRATIONS_SCHEMA = 'drizzle';\n\nexport type PgliteMigrations = {\n\tmigrationsFolder: string;\n\tmigrationsTable?: string;\n\tmigrationsSchema?: string;\n};\n\n/** Double-quotes an identifier part for safe interpolation into SQL. */\nconst quoteIdentifierPart = (part: string) => `\"${part.replaceAll('\"', '\"\"')}\"`;\n\nconst qualifiedMigrationsTable = (\n\tmigrations: Pick<PgliteMigrations, 'migrationsTable' | 'migrationsSchema'>,\n) =>\n\t`${quoteIdentifierPart(migrations.migrationsSchema ?? DEFAULT_MIGRATIONS_SCHEMA)}.${quoteIdentifierPart(migrations.migrationsTable ?? DEFAULT_MIGRATIONS_TABLE)}`;\n\n/**\n * A persisted data dir that already exists holds a hydrated database, so it is\n * opened as-is rather than re-seeded from the dump. In-memory clients have\n * nothing to reuse.\n */\nconst shouldReuseExistingDatabase = (dataDir: string | undefined) =>\n\tEffect.gen(function* () {\n\t\tif (!dataDir || dataDir === IN_MEMORY_DATA_DIR) {\n\t\t\treturn false;\n\t\t}\n\t\tconst fs = yield* FileSystem;\n\t\treturn yield* fs.exists(dataDir);\n\t});\n\nexport const createPgliteFromDump = (opts: {\n\tdataDir?: string;\n\tdumpPath: string;\n}) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\n\t\tif (yield* shouldReuseExistingDatabase(opts.dataDir)) {\n\t\t\treturn new PGlite(opts.dataDir);\n\t\t}\n\n\t\tif (!(yield* fs.exists(opts.dumpPath))) {\n\t\t\treturn yield* new PgliteError({\n\t\t\t\tmessage: `Dump file not found at ${opts.dumpPath}`,\n\t\t\t});\n\t\t}\n\n\t\tconst buffer = yield* fs.readFile(opts.dumpPath);\n\t\tconst file = new Blob([new Uint8Array(buffer)]);\n\n\t\tconst client = new PGlite(opts.dataDir, {\n\t\t\tloadDataDir: file,\n\t\t});\n\n\t\treturn client;\n\t});\n\nconst toUint8Array = (input: File | Blob) =>\n\tEffect.gen(function* () {\n\t\tconst buf = yield* Effect.tryPromise({\n\t\t\ttry: () => input.arrayBuffer(),\n\t\t\tcatch: (error) =>\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Failed to convert dump to Uint8Array',\n\t\t\t\t\tcause: error,\n\t\t\t\t}),\n\t\t});\n\t\treturn new Uint8Array(buf);\n\t});\n\nexport const dumpPgliteToFile = (client: PGlite, dest: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\t\tconst path = yield* Path;\n\n\t\tconst destDir = path.dirname(dest);\n\t\tconst dirExists = yield* fs.exists(destDir);\n\n\t\tif (!dirExists) {\n\t\t\tyield* fs.makeDirectory(destDir, { recursive: true });\n\t\t}\n\n\t\tconst dump = yield* Effect.tryPromise({\n\t\t\ttry: () => client.dumpDataDir(),\n\t\t\tcatch: (error) =>\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Failed to dump PGlite database',\n\t\t\t\t\tcause: error,\n\t\t\t\t}),\n\t\t});\n\n\t\tconst data = yield* toUint8Array(dump);\n\t\tyield* fs.writeFile(dest, data);\n\t});\n\nexport const migratePglite = (client: PGlite, migrations: PgliteMigrations) =>\n\tEffect.tryPromise({\n\t\ttry: () =>\n\t\t\tmigrate(drizzle(client), {\n\t\t\t\tmigrationsFolder: migrations.migrationsFolder,\n\t\t\t\tmigrationsTable: migrations.migrationsTable,\n\t\t\t\tmigrationsSchema: migrations.migrationsSchema,\n\t\t\t}),\n\t\tcatch: (error) =>\n\t\t\tnew PgliteError({\n\t\t\t\tmessage: `Failed to migrate pglite from ${migrations.migrationsFolder}`,\n\t\t\t\tcause: error,\n\t\t\t}),\n\t});\n\nconst closePglite = (client: PGlite) =>\n\tEffect.tryPromise({\n\t\ttry: () => client.close(),\n\t\tcatch: (error) =>\n\t\t\tnew PgliteError({\n\t\t\t\tmessage: 'Failed to close PGlite client',\n\t\t\t\tcause: error,\n\t\t\t}),\n\t});\n\nexport const getDbMigrationCount = (\n\tclient: PGlite,\n\tmigrations?: Pick<PgliteMigrations, 'migrationsTable' | 'migrationsSchema'>,\n) =>\n\tEffect.gen(function* () {\n\t\tconst qualifiedTable = qualifiedMigrationsTable(migrations ?? {});\n\n\t\tyield* Effect.tryPromise({\n\t\t\ttry: () => client.waitReady,\n\t\t\tcatch: (error) =>\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Failed to wait for PGlite ready',\n\t\t\t\t\tcause: error,\n\t\t\t\t}),\n\t\t});\n\n\t\tconst existsResult = yield* Effect.tryPromise({\n\t\t\ttry: () =>\n\t\t\t\tclient.query<{ exists: boolean }>(\n\t\t\t\t\t'SELECT to_regclass($1) IS NOT NULL AS \"exists\"',\n\t\t\t\t\t[qualifiedTable],\n\t\t\t\t),\n\t\t\tcatch: (error) =>\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Failed to check drizzle migrations table',\n\t\t\t\t\tcause: error,\n\t\t\t\t}),\n\t\t});\n\n\t\tconst existsRow = existsResult.rows[0];\n\t\tif (!existsRow) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Missing row from drizzle migrations existence check',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tif (!existsRow.exists) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst countResult = yield* Effect.tryPromise({\n\t\t\ttry: () =>\n\t\t\t\tclient.query<{ c: number }>(\n\t\t\t\t\t`SELECT count(*)::int AS c FROM ${qualifiedTable}`,\n\t\t\t\t),\n\t\t\tcatch: (error) =>\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Failed to count drizzle migrations',\n\t\t\t\t\tcause: error,\n\t\t\t\t}),\n\t\t});\n\n\t\tconst countRow = countResult.rows[0];\n\t\tif (!countRow) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: 'Missing row from drizzle migrations count query',\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn countRow.c;\n\t});\n\nexport const getExpectedMigrationCount = (migrationsFolder: string) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\t\tconst path = yield* Path;\n\t\tconst journalPath = path.join(migrationsFolder, 'meta/_journal.json');\n\t\tconst journalExists = yield* fs.exists(journalPath);\n\t\tif (!journalExists) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: `Migration journal not found at ${journalPath}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tconst content = yield* fs.readFileString(journalPath);\n\t\tconst journal = yield* Effect.try({\n\t\t\ttry: () => JSON.parse(content) as { entries: unknown[] },\n\t\t\tcatch: (cause) =>\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: `Failed to parse migration journal at ${journalPath}`,\n\t\t\t\t\tcause,\n\t\t\t\t}),\n\t\t});\n\t\tif (!Array.isArray(journal.entries)) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage: `Migration journal at ${journalPath} is missing an \"entries\" array`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\treturn journal.entries.length;\n\t});\n\nexport const buildPgliteDump = (\n\topts: PgliteMigrations & { dumpPath: string },\n) =>\n\tEffect.gen(function* () {\n\t\tconst client = new PGlite(IN_MEMORY_DATA_DIR);\n\t\tyield* migratePglite(client, opts);\n\t\tyield* dumpPgliteToFile(client, opts.dumpPath);\n\t\tyield* closePglite(client);\n\t});\n\nexport const ensurePgliteDump = (\n\topts: PgliteMigrations & { dumpPath: string },\n) =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem;\n\t\tconst dumpExists = yield* fs.exists(opts.dumpPath);\n\t\tif (!dumpExists) {\n\t\t\tyield* buildPgliteDump(opts);\n\t\t}\n\t});\n\nexport const openLitePglite = (\n\topts: PgliteMigrations & { dataDir: string; dumpPath: string },\n) =>\n\tEffect.gen(function* () {\n\t\tyield* ensurePgliteDump(opts);\n\t\tconst client = yield* createPgliteFromDump({\n\t\t\tdataDir: opts.dataDir,\n\t\t\tdumpPath: opts.dumpPath,\n\t\t});\n\t\tconst expected = yield* getExpectedMigrationCount(opts.migrationsFolder);\n\t\tconst actual = yield* getDbMigrationCount(client, opts);\n\t\t/** Schema is present but nothing is journaled — it predates journaled migrations. */\n\t\tconst predatesMigrationJournal = expected > 0 && actual === 0;\n\t\tif (predatesMigrationJournal) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\tnew PgliteError({\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Stale local pglite at ${opts.dataDir} (schema present, no migration journal) — ` +\n\t\t\t\t\t\t'it was built by an older scheme. Remove it and the dump, then restart:\\n' +\n\t\t\t\t\t\t` rm -rf ${opts.dataDir} ${opts.dumpPath}`,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t\tyield* migratePglite(client, opts);\n\t\treturn client;\n\t});\n\n/**\n * Prepares a PGlite database scoped to a dev session: the data dir lives at\n * `<session>/pglite` and the migration dump at `<session>/pglite.dump`. Builds\n * the dump from `migrationsFolder` if missing, hydrates the client, and runs\n * pending migrations. Returns the open client plus the resolved paths so the\n * caller can pass them to the app (e.g. as `DATABASE_LITE_PATH`).\n */\nexport const prepareSessionPglite = (\n\tsession: DevSession,\n\topts: PgliteMigrations,\n) =>\n\tEffect.gen(function* () {\n\t\tconst dataDir = yield* session.path('pglite');\n\t\tconst dumpPath = yield* session.path('pglite.dump');\n\t\tconst client = yield* openLitePglite({\n\t\t\t...opts,\n\t\t\tdataDir,\n\t\t\tdumpPath,\n\t\t});\n\t\treturn { client, dataDir, dumpPath };\n\t});\n"],"mappings":"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","names":[]}