@gobing-ai/ts-runtime 0.3.1 → 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.
Files changed (61) hide show
  1. package/README.md +234 -176
  2. package/dist/config.d.ts +13 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +14 -0
  5. package/dist/context.d.ts +28 -1
  6. package/dist/context.d.ts.map +1 -1
  7. package/dist/context.js +45 -2
  8. package/dist/file-system-cf.d.ts +25 -0
  9. package/dist/file-system-cf.d.ts.map +1 -0
  10. package/dist/file-system-cf.js +59 -0
  11. package/dist/file-system-node.d.ts +29 -0
  12. package/dist/file-system-node.d.ts.map +1 -0
  13. package/dist/file-system-node.js +94 -0
  14. package/dist/file-system.d.ts +47 -0
  15. package/dist/file-system.d.ts.map +1 -0
  16. package/dist/file-system.js +0 -0
  17. package/dist/fs.d.ts +31 -1
  18. package/dist/fs.d.ts.map +1 -1
  19. package/dist/fs.js +32 -19
  20. package/dist/index.d.ts +21 -2
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +10 -2
  23. package/dist/path.d.ts +12 -0
  24. package/dist/path.d.ts.map +1 -1
  25. package/dist/path.js +65 -4
  26. package/dist/platform.d.ts +12 -0
  27. package/dist/platform.d.ts.map +1 -0
  28. package/dist/platform.js +41 -0
  29. package/dist/process-executor.d.ts +77 -19
  30. package/dist/process-executor.d.ts.map +1 -1
  31. package/dist/process-executor.js +209 -37
  32. package/dist/runtime-cf.d.ts +6 -0
  33. package/dist/runtime-cf.d.ts.map +1 -0
  34. package/dist/runtime-cf.js +33 -0
  35. package/dist/runtime-factory.d.ts +24 -0
  36. package/dist/runtime-factory.d.ts.map +1 -0
  37. package/dist/runtime-factory.js +0 -0
  38. package/dist/runtime-node-bun.d.ts +8 -0
  39. package/dist/runtime-node-bun.d.ts.map +1 -0
  40. package/dist/runtime-node-bun.js +67 -0
  41. package/dist/schema-validation.d.ts +16 -0
  42. package/dist/schema-validation.d.ts.map +1 -1
  43. package/dist/schema-validation.js +9 -4
  44. package/dist/types.d.ts +4 -0
  45. package/dist/types.d.ts.map +1 -1
  46. package/package.json +2 -2
  47. package/src/config.ts +16 -4
  48. package/src/context.ts +58 -4
  49. package/src/file-system-cf.ts +74 -0
  50. package/src/file-system-node.ts +122 -0
  51. package/src/file-system.ts +55 -0
  52. package/src/fs.ts +35 -18
  53. package/src/index.ts +57 -2
  54. package/src/path.ts +68 -4
  55. package/src/platform.ts +47 -0
  56. package/src/process-executor.ts +296 -58
  57. package/src/runtime-cf.ts +44 -0
  58. package/src/runtime-factory.ts +28 -0
  59. package/src/runtime-node-bun.ts +83 -0
  60. package/src/schema-validation.ts +20 -4
  61. package/src/types.ts +4 -0
package/dist/fs.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
2
+ import { findProjectRoot } from './file-system-node.js';
2
3
  import { dirnamePath, getProcessCwd, joinPath, resolvePath } from './path.js';
3
4
  let fsPromisesModule = null;
4
5
  let fsModule = null;
@@ -10,6 +11,8 @@ function nodeFs() {
10
11
  fsModule ??= import('node:fs');
11
12
  return fsModule;
12
13
  }
14
+ /** {@link FileSystem} backed by `node:fs/promises`. Lazy-loads the module to avoid top-level import cost. */
15
+ /** @deprecated Use createNodeFileSystem() from './file-system-node.js' instead. */
13
16
  export class NodeFileSystem {
14
17
  async readFile(path) {
15
18
  const { readFile } = await nodeFsPromises();
@@ -78,6 +81,8 @@ export class NodeFileSystem {
78
81
  return new LazyNodeLogStream(path);
79
82
  }
80
83
  }
84
+ /** {@link SyncFileSystem} backed by `node:fs` synchronous APIs. */
85
+ /** @deprecated Use createNodeFileSystem() from './file-system-node.js' instead — its FileSystem interface has union return types, eliminating the need for a separate sync implementation. */
81
86
  export class NodeSyncFileSystem {
82
87
  readFile(path) {
83
88
  return readFileSync(path, 'utf-8');
@@ -149,6 +154,8 @@ class LazyNodeLogStream {
149
154
  }
150
155
  }
151
156
  const CLOUDFLARE_FS_ERROR = 'FileSystem is not available on Cloudflare Workers. Use D1, KV, or R2.';
157
+ /** {@link FileSystem} stub for Cloudflare Workers — all file operations throw. Use D1, KV, or R2 instead. */
158
+ /** @deprecated Use createCfFileSystem() from './file-system-cf.js' instead. */
152
159
  export class CloudflareFileSystem {
153
160
  async readFile(path) {
154
161
  throw unsupportedCloudflareFs('readFile', path);
@@ -191,6 +198,8 @@ function unsupportedCloudflareFs(operation, path) {
191
198
  return new Error(`CloudflareFileSystem.${operation} failed for "${path}": ${CLOUDFLARE_FS_ERROR}`);
192
199
  }
193
200
  let activeFileSystem = new NodeFileSystem();
201
+ /** Swaps the active global file system, returning a restore function for the previous instance. */
202
+ /** @deprecated Use RuntimeFactory.createFileSystem() or ctx.require('fileSystem') instead. The global swap is replaced by factory-based DI. */
194
203
  export function setFileSystem(fileSystem) {
195
204
  const previous = activeFileSystem;
196
205
  activeFileSystem = fileSystem;
@@ -198,38 +207,50 @@ export function setFileSystem(fileSystem) {
198
207
  activeFileSystem = previous;
199
208
  };
200
209
  }
210
+ /** Returns the currently active global {@link FileSystem} instance. */
211
+ /** @deprecated Use RuntimeFactory.createFileSystem() or ctx.require('fileSystem') instead. */
201
212
  export function getFs() {
202
213
  return activeFileSystem;
203
214
  }
215
+ /** Creates parent directories for a file path before writing. */
204
216
  export async function ensureDirForFile(path, fs = getFs()) {
205
217
  await fs.mkdir(dirnamePath(path));
206
218
  }
219
+ /** Synchronous variant of {@link ensureDirForFile}. */
220
+ /** @deprecated The new createNodeFileSystem() handles parent-directory creation internally. */
207
221
  export function ensureDirForFileSync(path, fs) {
208
222
  fs.mkdir(dirnamePath(path));
209
223
  }
224
+ /** Atomically writes a file by writing to a temp path then renaming, avoiding partial writes on crash. */
210
225
  export async function atomicWriteFile(path, content, fs = getFs()) {
211
226
  await ensureDirForFile(path, fs);
212
227
  const tempPath = `${path}.${getProcessPid()}.${uniqueToken()}.tmp`;
213
228
  await fs.writeFile(tempPath, content);
214
229
  await fs.rename(tempPath, path);
215
230
  }
231
+ /** Atomically writes a value as JSON with trailing newline. */
216
232
  export async function atomicWriteJson(path, value, fs = getFs()) {
217
233
  await atomicWriteFile(path, `${JSON.stringify(value, null, 2)}\n`, fs);
218
234
  }
235
+ /** Reads and parses a JSON file. */
219
236
  export async function readJsonFile(path, fs = getFs()) {
220
237
  return JSON.parse(await fs.readFile(path));
221
238
  }
239
+ /** Writes a value as JSON with 2-space indentation and trailing newline. */
222
240
  export async function writeJsonFile(path, value, fs = getFs()) {
223
241
  await fs.writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
224
242
  }
225
- export async function walkDir(path, fs = getFs()) {
243
+ /** Recursively walks a directory, returning sorted paths to all files, optionally excluding entries by name. */
244
+ export async function walkDir(path, fs = getFs(), exclude) {
226
245
  const entries = (await fs.readDir(path)).sort();
227
246
  const result = [];
228
247
  for (const entry of entries) {
248
+ if (exclude?.has(entry))
249
+ continue;
229
250
  const fullPath = joinPath(path, entry);
230
251
  const entryStat = await fs.stat(fullPath);
231
252
  if (entryStat?.isDirectory()) {
232
- result.push(...(await walkDir(fullPath, fs)));
253
+ result.push(...(await walkDir(fullPath, fs, exclude)));
233
254
  }
234
255
  else if (entryStat?.isFile()) {
235
256
  result.push(fullPath);
@@ -237,31 +258,23 @@ export async function walkDir(path, fs = getFs()) {
237
258
  }
238
259
  return result;
239
260
  }
261
+ /**
262
+ * Walks up from `startDir` looking for a `package.json` or `bun.lock` to locate the project root.
263
+ *
264
+ * @deprecated Use {@link import('./file-system-node.js').findProjectRoot} (or `createNodeFileSystem().getProjectRoot()`).
265
+ * This delegates to the single shared implementation.
266
+ */
240
267
  export function getProjectRoot(startDir = getProcessCwd()) {
241
- let current = resolvePath(startDir);
242
- for (let i = 0; i < 12; i++) {
243
- if (hasBunFile(joinPath(current, 'bun.lock')) || hasBunFile(joinPath(current, 'package.json'))) {
244
- return current;
245
- }
246
- const parent = dirnamePath(current);
247
- if (parent === current)
248
- return startDir;
249
- current = parent;
250
- }
251
- return startDir;
268
+ return findProjectRoot(startDir);
252
269
  }
270
+ /** Resolves path segments relative to the project root. */
253
271
  export function resolveProjectPath(...segments) {
254
272
  return resolvePath(getProjectRoot(), ...segments);
255
273
  }
274
+ /** Creates a {@link LogStream} at the given path using the active file system. */
256
275
  export function createLogStream(path, fs = getFs()) {
257
276
  return fs.createLogStream(path);
258
277
  }
259
- function hasBunFile(path) {
260
- const bun = globalThis.Bun;
261
- if (bun === undefined)
262
- return false;
263
- return bun.file(path).size !== 0;
264
- }
265
278
  function getProcessPid() {
266
279
  return globalThis.process?.pid ?? 0;
267
280
  }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,27 @@
1
1
  export * from './config';
2
2
  export * from './context';
3
- export * from './fs';
3
+ export { createRuntimeContextFromFactory } from './context';
4
+ export type { FileStat, FileSystem } from './file-system';
5
+ export { createCfFileSystem } from './file-system-cf';
6
+ export { createNodeFileSystem, findProjectRoot } from './file-system-node';
7
+ export { atomicWriteFile, atomicWriteJson, CloudflareFileSystem, createLogStream, ensureDirForFile, ensureDirForFileSync, type FileSystem as LegacyFileSystem, getFs, getProjectRoot, NodeFileSystem, NodeSyncFileSystem, readJsonFile, resolveProjectPath, type SyncFileSystem, setFileSystem, walkDir, writeJsonFile, } from './fs';
4
8
  export * from './path';
5
- export * from './process-executor';
9
+ export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform';
10
+ export type { OutputPolicy, PipeProcess, PipeProcessOptions, ProcessEventDetail, ProcessEventSink, ProcessEvents, ProcessExecutorConfig, ProcessExitReason, ProcessOptions, ProcessResult, ProcessSignal, TracerPort, } from './process-executor';
11
+ export { ProcessExecutor } from './process-executor';
12
+ export { cloudflareWorkersFactory } from './runtime-cf';
13
+ export type { RuntimeFactory } from './runtime-factory';
14
+ export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun';
6
15
  export * from './schema-validation';
7
16
  export * from './types';
17
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor';
18
+ /**
19
+ * @deprecated Use {@link ProcessExecutor} directly for async execution.
20
+ * Use `Bun.spawnSync` or `child_process.spawnSync` for sync.
21
+ */
22
+ export type SyncProcessExecutor = InstanceType<typeof import('./process-executor').BunSyncProcessExecutor>;
23
+ /**
24
+ * @deprecated Use {@link ProcessExecutor.runStreaming} instead.
25
+ */
26
+ export type PipeProcessSpawner = InstanceType<typeof import('./process-executor').BunPipeProcessSpawner>;
8
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,MAAM,CAAC;AACrB,cAAc,QAAQ,CAAC;AACvB,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,+BAA+B,EAAE,MAAM,WAAW,CAAC;AAC5D,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC3E,OAAO,EACH,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,UAAU,IAAI,gBAAgB,EACnC,KAAK,EACL,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,kBAAkB,EAClB,KAAK,cAAc,EACnB,aAAa,EACb,OAAO,EACP,aAAa,GAChB,MAAM,MAAM,CAAC;AACd,cAAc,QAAQ,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjG,YAAY,EACR,YAAY,EACZ,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,aAAa,EACb,UAAU,GACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AAIxB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAExG;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,sBAAsB,CAAC,CAAC;AAE3G;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,qBAAqB,CAAC,CAAC"}
package/dist/index.js CHANGED
@@ -1,7 +1,15 @@
1
1
  export * from './config.js';
2
2
  export * from './context.js';
3
- export * from './fs.js';
3
+ export { createRuntimeContextFromFactory } from './context.js';
4
+ export { createCfFileSystem } from './file-system-cf.js';
5
+ export { createNodeFileSystem, findProjectRoot } from './file-system-node.js';
6
+ export { atomicWriteFile, atomicWriteJson, CloudflareFileSystem, createLogStream, ensureDirForFile, ensureDirForFileSync, getFs, getProjectRoot, NodeFileSystem, NodeSyncFileSystem, readJsonFile, resolveProjectPath, setFileSystem, walkDir, writeJsonFile, } from './fs.js';
4
7
  export * from './path.js';
5
- export * from './process-executor.js';
8
+ export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform.js';
9
+ export { ProcessExecutor } from './process-executor.js';
10
+ export { cloudflareWorkersFactory } from './runtime-cf.js';
11
+ export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun.js';
6
12
  export * from './schema-validation.js';
7
13
  export * from './types.js';
14
+ // ── Deprecated re-exports (backward compatibility) ──────────────────────
15
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor.js';
package/dist/path.d.ts CHANGED
@@ -1,7 +1,19 @@
1
+ /** Replaces Windows backslashes with forward slashes for consistent POSIX-style path handling. */
1
2
  export declare function normalizeSeparators(path: string): string;
3
+ /** Platform-specific path segment separator (`'/'` on POSIX, `'\\'` on Windows). */
4
+ export declare const SEP: string;
5
+ /** Returns `true` for POSIX absolute paths and Windows drive paths (`C:/…`). */
2
6
  export declare function isAbsolutePath(path: string): boolean;
7
+ /** Returns the parent directory of a path. Platform-independent — avoids `node:path`. */
3
8
  export declare function dirnamePath(path: string): string;
9
+ /** Return the last segment of a path. Optionally strip a trailing extension. */
10
+ export declare function basenamePath(p: string, ext?: string): string;
11
+ /** Compute a platform-independent relative path from `from` to `to`. Both paths should be absolute. */
12
+ export declare function relativePath(from: string, to: string): string;
13
+ /** Joins path segments with `/`, normalizing separators and collapsing redundant slashes. */
4
14
  export declare function joinPath(...segments: string[]): string;
15
+ /** Resolves a sequence of path segments to an absolute path, collapsing `..` and `.`. */
5
16
  export declare function resolvePath(...segments: string[]): string;
17
+ /** Returns `process.cwd()` if available, or `/` as fallback (Cloudflare Workers). */
6
18
  export declare function getProcessCwd(): string;
7
19
  //# sourceMappingURL=path.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAIA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED,wBAAgB,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMtD;AAED,wBAAgB,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAkBzD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
1
+ {"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAIA,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,oFAAoF;AACpF,eAAO,MAAM,GAAG,EAAE,MACgF,CAAC;AAEnG,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAmBD,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED,uGAAuG;AACvG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAkB7D;AAED,6FAA6F;AAC7F,wBAAgB,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMtD;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAqBzD;AAED,qFAAqF;AACrF,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
package/dist/path.js CHANGED
@@ -1,14 +1,37 @@
1
1
  // Runtime-portable path math. Deliberately avoids `node:path` so the same logic works on
2
2
  // `cloudflare-workers` (no `node:*`) as on node-bun (ADR-008). POSIX-style separators throughout;
3
3
  // Windows drive paths (`C:/...`) are normalized and treated as absolute.
4
+ /** Replaces Windows backslashes with forward slashes for consistent POSIX-style path handling. */
4
5
  export function normalizeSeparators(path) {
5
6
  return path.replaceAll('\\', '/');
6
7
  }
8
+ /** Platform-specific path segment separator (`'/'` on POSIX, `'\\'` on Windows). */
9
+ export const SEP = globalThis.process?.platform === 'win32' ? '\\' : '/';
10
+ /** Returns `true` for POSIX absolute paths and Windows drive paths (`C:/…`). */
7
11
  export function isAbsolutePath(path) {
8
12
  return path.startsWith('/') || /^[A-Za-z]:\//.test(normalizeSeparators(path));
9
13
  }
14
+ function splitRoot(path) {
15
+ const normalized = normalizeSeparators(path);
16
+ const drive = normalized.match(/^([A-Za-z]:)(?:\/|$)/);
17
+ if (drive) {
18
+ return { root: drive[1] ?? '', rest: normalized.slice((drive[1] ?? '').length).replace(/^\/+/, '') };
19
+ }
20
+ if (normalized.startsWith('/')) {
21
+ return { root: '/', rest: normalized.replace(/^\/+/, '') };
22
+ }
23
+ return { root: '', rest: normalized };
24
+ }
25
+ function pathParts(path) {
26
+ const { root, rest } = splitRoot(path);
27
+ return { root, parts: rest.split('/').filter(Boolean) };
28
+ }
29
+ /** Returns the parent directory of a path. Platform-independent — avoids `node:path`. */
10
30
  export function dirnamePath(path) {
11
31
  const input = normalizeSeparators(path);
32
+ const { root } = splitRoot(input);
33
+ if (root !== '' && input.replace(/\/+$/, '') === root)
34
+ return root === '/' ? '/' : `${root}/`;
12
35
  if (/^\/+$/.test(input))
13
36
  return '/';
14
37
  const normalized = input.replace(/\/+$/, '');
@@ -21,6 +44,36 @@ export function dirnamePath(path) {
21
44
  return '/';
22
45
  return normalized.slice(0, index);
23
46
  }
47
+ /** Return the last segment of a path. Optionally strip a trailing extension. */
48
+ export function basenamePath(p, ext) {
49
+ const normalized = normalizeSeparators(p).replace(/\/+$/, '');
50
+ const index = normalized.lastIndexOf('/');
51
+ let base = index < 0 ? normalized : normalized.slice(index + 1);
52
+ if (ext !== undefined && base !== ext && base.endsWith(ext)) {
53
+ base = base.slice(0, -ext.length);
54
+ }
55
+ return base;
56
+ }
57
+ /** Compute a platform-independent relative path from `from` to `to`. Both paths should be absolute. */
58
+ export function relativePath(from, to) {
59
+ const fromParsed = pathParts(resolvePath(from));
60
+ const toParsed = pathParts(resolvePath(to));
61
+ if (fromParsed.root.toLowerCase() !== toParsed.root.toLowerCase()) {
62
+ return resolvePath(to);
63
+ }
64
+ const fromParts = fromParsed.parts;
65
+ const toParts = toParsed.parts;
66
+ // Strip common prefix.
67
+ let i = 0;
68
+ const minLen = Math.min(fromParts.length, toParts.length);
69
+ while (i < minLen && fromParts[i] === toParts[i])
70
+ i++;
71
+ const up = fromParts.slice(i).map(() => '..');
72
+ const down = toParts.slice(i);
73
+ const result = [...up, ...down].join('/');
74
+ return result || '.';
75
+ }
76
+ /** Joins path segments with `/`, normalizing separators and collapsing redundant slashes. */
24
77
  export function joinPath(...segments) {
25
78
  const filtered = segments.filter((segment) => segment.length > 0).map(normalizeSeparators);
26
79
  if (filtered.length === 0)
@@ -29,6 +82,7 @@ export function joinPath(...segments) {
29
82
  const joined = filtered.join('/').replace(/\/+/g, '/');
30
83
  return absolute ? joined : joined.replace(/^\//, '');
31
84
  }
85
+ /** Resolves a sequence of path segments to an absolute path, collapsing `..` and `.`. */
32
86
  export function resolvePath(...segments) {
33
87
  const candidates = segments.length === 0 ? [getProcessCwd()] : segments;
34
88
  let resolved = '';
@@ -37,19 +91,26 @@ export function resolvePath(...segments) {
37
91
  continue;
38
92
  resolved = isAbsolutePath(segment) ? segment : joinPath(resolved || getProcessCwd(), segment);
39
93
  }
94
+ const { root, rest } = splitRoot(resolved);
40
95
  const parts = [];
41
- const absolute = isAbsolutePath(resolved);
42
- for (const part of resolved.split('/')) {
96
+ const absolute = root !== '';
97
+ for (const part of rest.split('/')) {
43
98
  if (part === '' || part === '.')
44
99
  continue;
45
100
  if (part === '..') {
46
- parts.pop();
101
+ if (parts.length > 0)
102
+ parts.pop();
47
103
  continue;
48
104
  }
49
105
  parts.push(part);
50
106
  }
51
- return `${absolute ? '/' : ''}${parts.join('/')}` || (absolute ? '/' : '.');
107
+ if (!absolute)
108
+ return parts.join('/') || '.';
109
+ if (root === '/')
110
+ return `/${parts.join('/')}` || '/';
111
+ return parts.length > 0 ? `${root}/${parts.join('/')}` : `${root}/`;
52
112
  }
113
+ /** Returns `process.cwd()` if available, or `/` as fallback (Cloudflare Workers). */
53
114
  export function getProcessCwd() {
54
115
  return globalThis.process?.cwd?.() ?? '/';
55
116
  }
@@ -0,0 +1,12 @@
1
+ import type { RuntimeFactory } from './runtime-factory';
2
+ /** True when running in a Cloudflare Worker (server-tier only). */
3
+ export declare function isCloudflareWorkerRuntime(): boolean;
4
+ /**
5
+ * Lazy-load and cache the appropriate {@link RuntimeFactory} based on environment detection.
6
+ */
7
+ export declare function loadRuntimeFactory(): Promise<RuntimeFactory>;
8
+ /**
9
+ * Reset the cached runtime factory and name (for test isolation).
10
+ */
11
+ export declare function _resetRuntimeFactory(): void;
12
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../src/platform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAQxD,mEAAmE;AACnE,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAKD;;GAEG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,cAAc,CAAC,CAalE;AAQD;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAG3C"}
@@ -0,0 +1,41 @@
1
+ // Single authoritative source for runtime detection.
2
+ // All other code MUST consume RuntimeFactory via loadRuntimeFactory().
3
+ // Probe-once contract: each primitive is invoked at most once per process and
4
+ // the result is cached in `_factory` / `_runtimeName`.
5
+ /** True when running in a Cloudflare Worker (server-tier only). */
6
+ export function isCloudflareWorkerRuntime() {
7
+ return globalThis.navigator?.userAgent?.startsWith('Cloudflare-Workers') ?? false;
8
+ }
9
+ let _factory;
10
+ let _runtimeName;
11
+ /**
12
+ * Lazy-load and cache the appropriate {@link RuntimeFactory} based on environment detection.
13
+ */
14
+ export async function loadRuntimeFactory() {
15
+ if (_factory)
16
+ return _factory;
17
+ let factory;
18
+ if (getRuntimeName() === 'cloudflare-workers') {
19
+ const { cloudflareWorkersFactory } = await import('./runtime-cf.js');
20
+ factory = cloudflareWorkersFactory;
21
+ }
22
+ else {
23
+ const { nodeBunFactory } = await import('./runtime-node-bun.js');
24
+ factory = nodeBunFactory;
25
+ }
26
+ _factory = factory;
27
+ return factory;
28
+ }
29
+ function getRuntimeName() {
30
+ if (_runtimeName)
31
+ return _runtimeName;
32
+ _runtimeName = isCloudflareWorkerRuntime() ? 'cloudflare-workers' : 'node-bun';
33
+ return _runtimeName;
34
+ }
35
+ /**
36
+ * Reset the cached runtime factory and name (for test isolation).
37
+ */
38
+ export function _resetRuntimeFactory() {
39
+ _factory = undefined;
40
+ _runtimeName = undefined;
41
+ }
@@ -1,31 +1,31 @@
1
+ /** Controls how stdout/stderr is captured: buffered in memory or streamed to the caller's terminal. */
1
2
  export type OutputPolicy = {
2
3
  mode: 'buffered';
3
4
  } | {
4
5
  mode: 'stream';
5
6
  isTTY?: boolean;
6
7
  };
8
+ /** Shared configuration for a process executor (default timeout, output buffering, output policy). */
7
9
  export interface ProcessExecutorConfig {
8
10
  defaultTimeout?: number;
9
11
  defaultMaxOutput?: number;
10
12
  output?: OutputPolicy;
13
+ events?: ProcessEventSink;
14
+ tracer?: TracerPort;
11
15
  }
16
+ /** Options for spawning a child process. */
12
17
  export interface ProcessOptions {
13
18
  command: string;
14
19
  args?: string[];
15
20
  cwd?: string;
16
- /**
17
- * Environment forwarded verbatim to the child process. Caller-controlled — when launching an
18
- * untrusted command, pass an explicit allowlist rather than the parent's full environment, so
19
- * inherited secrets are not leaked into the subprocess.
20
- */
21
21
  env?: Record<string, string>;
22
22
  timeout?: number;
23
- /** Maximum output buffer size in bytes (maps to execa `maxBuffer`). */
24
23
  maxOutput?: number;
25
24
  label?: string;
26
25
  rejectOnError?: boolean;
27
26
  forceBuffered?: boolean;
28
27
  }
28
+ /** Result of a completed child process, including exit code, captured output, and duration. */
29
29
  export interface ProcessResult {
30
30
  command: string;
31
31
  args: string[];
@@ -35,19 +35,46 @@ export interface ProcessResult {
35
35
  signal?: string;
36
36
  durationMs: number;
37
37
  }
38
- export interface ProcessExecutor {
39
- run(options: ProcessOptions): Promise<ProcessResult>;
38
+ /** Reason a process completion event was emitted. */
39
+ export type ProcessExitReason = 'exit' | 'signal' | 'timeout' | 'error';
40
+ /** Payload emitted for process execution observability. */
41
+ export interface ProcessEventDetail {
42
+ command: string;
43
+ args: string[];
44
+ exitCode: number | null;
45
+ signal?: string;
46
+ durationMs: number;
47
+ reason: ProcessExitReason;
48
+ timestamp: string;
49
+ label?: string;
50
+ error?: string;
40
51
  }
41
- export interface SyncProcessExecutor {
42
- runSync(options: Omit<ProcessOptions, 'timeout'>): ProcessResult;
52
+ /** Zero-dependency structural event sink for process observability. */
53
+ export interface ProcessEventSink {
54
+ emit(event: 'process.started' | 'process.exited', detail: ProcessEventDetail): void;
55
+ }
56
+ /** Typed process event map, consumable by `EventBus<ProcessEvents>` in higher layers. */
57
+ export type ProcessEvents = {
58
+ 'process.started': (detail: ProcessEventDetail) => void;
59
+ 'process.exited': (detail: ProcessEventDetail) => void;
60
+ };
61
+ /** Minimal structural tracing port; concrete adapters live above `ts-runtime`. */
62
+ export interface TracerPort {
63
+ traceAsync<T>(name: string, fn: (span: unknown) => Promise<T>): Promise<T>;
43
64
  }
65
+ /** Options for spawning a long-running interactive process. */
44
66
  export interface PipeProcessOptions {
45
67
  command: string;
46
68
  args?: string[];
47
69
  cwd?: string;
48
- /** Forwarded verbatim to the child — pass an allowlist for untrusted commands (see {@link ProcessOptions.env}). */
49
70
  env?: Record<string, string>;
71
+ label?: string;
50
72
  }
73
+ /** Signal values accepted by subprocess kill. */
74
+ type BunSubprocess = ReturnType<typeof Bun.spawn>;
75
+ /** Signal values accepted by subprocess kill (e.g. 'SIGTERM', 'SIGKILL'). */
76
+ export type ProcessSignal = Parameters<BunSubprocess['kill']>[0];
77
+ /** Handle to a running pipe process with streaming stdout/stderr and stdin write support. */
51
78
  export interface PipeProcess {
52
79
  readonly pid: number | null;
53
80
  readonly stdout: ReadableStream<Uint8Array> | null;
@@ -57,21 +84,52 @@ export interface PipeProcess {
57
84
  endStdin(): void;
58
85
  kill(signal?: ProcessSignal): void;
59
86
  }
60
- export interface PipeProcessSpawner {
61
- spawn(options: PipeProcessOptions): PipeProcess;
62
- }
63
- export declare class NodeProcessExecutor implements ProcessExecutor {
87
+ /**
88
+ * Runtime-agnostic process executor wrapping `execa`.
89
+ *
90
+ * Every invocation supports timeout enforcement, output capture, and
91
+ * configurable output policy (buffered vs streamed).
92
+ */
93
+ export declare class ProcessExecutor {
64
94
  private readonly config;
65
95
  constructor(config?: ProcessExecutorConfig);
96
+ /**
97
+ * Run a command, buffered by default. Returns a structured {@link ProcessResult}.
98
+ * Does NOT throw on non-zero exit codes unless `rejectOnError` is set.
99
+ */
66
100
  run(options: ProcessOptions): Promise<ProcessResult>;
101
+ private runUntraced;
102
+ /**
103
+ * Spawn a long-running interactive process with streaming I/O.
104
+ *
105
+ * Uses `Bun.spawn` for bidirectional pipe communication (stdin write,
106
+ * stdout/stderr as ReadableStreams). Returns a {@link PipeProcess} handle.
107
+ */
108
+ runStreaming(options: PipeProcessOptions): PipeProcess;
109
+ private trace;
110
+ private emitExitedFromResult;
111
+ private emitProcessEvent;
67
112
  }
68
- export declare class BunSyncProcessExecutor implements SyncProcessExecutor {
113
+ /**
114
+ * @deprecated Use {@link ProcessExecutor} directly.
115
+ * This subclass is kept for backward compatibility.
116
+ */
117
+ export declare class NodeProcessExecutor extends ProcessExecutor {
118
+ }
119
+ /**
120
+ * @deprecated Use `Bun.spawnSync` or `child_process.spawnSync` directly.
121
+ * Synchronous process execution is no longer recommended from ts-runtime.
122
+ * This class is kept for backward compatibility.
123
+ */
124
+ export declare class BunSyncProcessExecutor {
69
125
  runSync(options: Omit<ProcessOptions, 'timeout'>): ProcessResult;
70
126
  }
71
- export declare class BunPipeProcessSpawner implements PipeProcessSpawner {
127
+ /**
128
+ * @deprecated Use {@link ProcessExecutor.runStreaming} instead.
129
+ * This class is kept for backward compatibility.
130
+ */
131
+ export declare class BunPipeProcessSpawner {
72
132
  spawn(options: PipeProcessOptions): PipeProcess;
73
133
  }
74
- type BunSubprocess = ReturnType<typeof Bun.spawn>;
75
- type ProcessSignal = Parameters<BunSubprocess['kill']>[0];
76
134
  export {};
77
135
  //# sourceMappingURL=process-executor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"process-executor.d.ts","sourceRoot":"","sources":["../src/process-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"process-executor.d.ts","sourceRoot":"","sources":["../src/process-executor.ts"],"names":[],"mappings":"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"}