@gobing-ai/ts-runtime 0.4.8 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,15 +8,13 @@ and Cloudflare Workers through a factory pattern that auto-detects the runtime.
8
8
 
9
9
  ## Overview
10
10
 
11
-
12
-
13
11
  **Key abstractions:**
14
12
 
15
13
  | Concept | Interface | Bun/Node impl | Cloudflare impl |
16
- |---------|-----------|---------------|-----------------|
14
+ | --------- | ----------- | --------------- | ----------------- |
17
15
  | Runtime factory | `RuntimeFactory` → `loadRuntimeFactory()` | `nodeBunFactory` | `cloudflareWorkersFactory` |
18
16
  | File system | `FileSystem` | `createNodeFileSystem()` (sync `node:fs`) | `createCfFileSystem()` (stub) |
19
- | Process execution | `ProcessExecutor` (class) | `run()` via execa, `runStreaming()` via `Bun.spawn` | throws |
17
+ | Process execution | `ProcessExecutor` (interface) | `NodeProcessExecutor` — `run()` via execa, `runStreaming()` via `Bun.spawn` | throws |
20
18
  | SQL database | `createDbAdapter(config)` → `DbAdapter` | Bun SQLite via `@gobing-ai/ts-db` (optional peer) | throws `D1NotConfiguredError` (D1 round pending) |
21
19
  | Configuration | `Config` (Zod schema) | YAML + env vars | CONFIG_YAML blob + env vars |
22
20
  | Context | `RuntimeContext` | service locator | service locator |
@@ -88,6 +86,12 @@ classDiagram
88
86
  }
89
87
 
90
88
  class ProcessExecutor {
89
+ <<interface>>
90
+ +run(options) Promise~ProcessResult~
91
+ +runStreaming(options) PipeProcess
92
+ }
93
+
94
+ class NodeProcessExecutor {
91
95
  +run(options) Promise~ProcessResult~
92
96
  +runStreaming(options) PipeProcess
93
97
  }
@@ -133,8 +137,9 @@ classDiagram
133
137
  FileSystem <|.. createNodeFileSystem : implements
134
138
  FileSystem <|.. createCfFileSystem : implements
135
139
  ProcessExecutor --> PipeProcess : creates
140
+ ProcessExecutor <|.. NodeProcessExecutor : implements
136
141
  nodeBunFactory --> createNodeFileSystem : creates
137
- nodeBunFactory --> ProcessExecutor : creates
142
+ nodeBunFactory --> NodeProcessExecutor : creates
138
143
  cloudflareWorkersFactory --> createCfFileSystem : creates
139
144
  RuntimeContext --> FileSystem : "fileSystem"
140
145
  RuntimeContext --> Config : "config"
@@ -232,7 +237,7 @@ There are three ways a config file can name its schema. **Prefer the bundled pac
232
237
  the most secure and performant default:
233
238
 
234
239
  | Style | Example | Resolution | Notes |
235
- |-------|---------|------------|-------|
240
+ | ------- | --------- | ------------ | ------- |
236
241
  | **Package specifier** (recommended) | `$schema: "@gobing-ai/ts-rule-engine/schemas/rule-file.schema.json"` | Resolved through `node_modules` via the module resolver, then read from disk | No network, no path guessing; survives hoisting/pnpm/monorepo layouts. Schemas ship in each package's `schemas/` (declared in `files`). **Quote the value** — YAML treats a leading `@` as reserved. |
237
242
  | Relative path | `$schema: ./schemas/rule-file.schema.json` | Resolved against the config file's directory | Fine for repo-local schemas; brittle if the config moves. |
238
243
  | Remote URL | `$schema: https://json-schema.org/.../rule-file.schema.json` | Fetched over HTTP(S) — **off by default** | SSRF/DoS surface for third-party configs. Opt in with `{ allowRemote: true }` (5s timeout) or supply your own `fetch`. |
@@ -251,7 +256,6 @@ await loadStructuredConfig('rules.yaml', { fetch: myFetch }); // or in
251
256
  > `node_modules` keeps validation entirely local — no outbound request, no dependency on a schema host's
252
257
  > availability, and no chance for a malicious config to point validation at an internal URL.
253
258
 
254
-
255
259
  ### 5. Path utilities
256
260
 
257
261
  Runtime-portable path math that avoids `node:path` so the same logic works on Cloudflare Workers
@@ -284,6 +288,7 @@ The `./extension` subpath exposes a generic, domain-agnostic extension/capabilit
284
288
  with origin metadata, a trust-gated extension loader, and a path guard — without knowing anything
285
289
  about evaluators, resolvers, actions, or guards. Each engine owns its domain-specific kinds,
286
290
  schemas, error types, and override semantics.
291
+
287
292
  #### Capability registry
288
293
 
289
294
  ```ts
@@ -462,6 +467,7 @@ process.on('SIGTERM', async () => {
462
467
  await ctx.dispose();
463
468
  process.exit(0);
464
469
  });
470
+
465
471
  ```
466
472
 
467
473
  ## Usage
@@ -513,6 +519,7 @@ const config = buildConfigFromObject({
513
519
  database: { url: ':memory:' },
514
520
  });
515
521
  ```
522
+
516
523
  // From YAML file
517
524
  const config = buildConfigFromYaml(yamlText);
518
525
 
@@ -521,16 +528,17 @@ const config = buildConfigFromObject({
521
528
  app: { name: 'api', env: 'production', port: 3000 },
522
529
  database: { url: ':memory:' },
523
530
  });
531
+
524
532
  ```
525
533
 
526
534
  ### Process execution
527
535
 
528
- `ProcessExecutor` is a single class wrapping `execa` (buffered) and `Bun.spawn` (streaming):
536
+ `ProcessExecutor` is the canonical interface for process execution. `NodeProcessExecutor` is the concrete implementation wrapping `execa` (buffered) and `Bun.spawn` (streaming):
529
537
 
530
538
  ```ts
531
- import { ProcessExecutor } from '@gobing-ai/ts-runtime';
539
+ import { NodeProcessExecutor } from '@gobing-ai/ts-runtime';
532
540
 
533
- const exec = new ProcessExecutor({ defaultTimeout: 30_000 });
541
+ const exec = new NodeProcessExecutor({ defaultTimeout: 30_000 });
534
542
 
535
543
  // Buffered — captures stdout/stderr, no throw on non-zero
536
544
  const result = await exec.run({
@@ -557,8 +565,9 @@ maxOutput, and forceBuffered.
557
565
  Cloudflare Workers do not expose process execution; check
558
566
  `factory.capabilities.hasProcessExecution` first.
559
567
 
560
- Old classes (`NodeProcessExecutor`, `BunSyncProcessExecutor`, `BunPipeProcessSpawner`)
561
- are kept as deprecated backward-compatible wrappers.
568
+ The `ProcessExecutor` const (value alias for `NodeProcessExecutor`), `BunSyncProcessExecutor`,
569
+ and `BunPipeProcessSpawner` are kept as deprecated backward-compatible wrappers. Prefer
570
+ `NodeProcessExecutor` or `nodeBunFactory.createProcessExecutor()` in new code.
562
571
 
563
572
  ### SpanContext (for telemetry)
564
573
 
package/dist/context.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { buildConfigFromObject } from './config.js';
2
2
  import { createNodeFileSystem } from './file-system-node.js';
3
3
  import { loadRuntimeFactory } from './platform.js';
4
- import { ProcessExecutor } from './process-executor.js';
4
+ import { nodeBunFactory } from './runtime-node-bun.js';
5
5
  /** Injectable service container scoped to a runtime environment (process, request, event, or test). */
6
6
  export class RuntimeContext {
7
7
  scope;
@@ -22,7 +22,7 @@ export class RuntimeContext {
22
22
  this.register('config', (options.services?.config ?? buildConfigFromObject({})));
23
23
  this.register('fileSystem', (options.services?.fileSystem ?? createNodeFileSystem()));
24
24
  if (this.capabilities.hasProcessExecution && options.services?.processExecutor === undefined) {
25
- this.register('processExecutor', new ProcessExecutor());
25
+ this.register('processExecutor', nodeBunFactory.createProcessExecutor());
26
26
  }
27
27
  for (const [key, value] of Object.entries(options.services ?? {})) {
28
28
  if (value !== undefined) {
package/dist/index.d.ts CHANGED
@@ -9,13 +9,13 @@ export { atomicWriteFile, atomicWriteJson, createLogStream, ensureDirForFile, re
9
9
  export * from './path';
10
10
  export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform';
11
11
  export type { OutputPolicy, PipeProcess, PipeProcessOptions, ProcessEventDetail, ProcessEventSink, ProcessEvents, ProcessExecutorConfig, ProcessExitReason, ProcessOptions, ProcessResult, ProcessSignal, TracerPort, } from './process-executor';
12
- export { ProcessExecutor } from './process-executor';
12
+ export { NodeProcessExecutor, ProcessExecutor } from './process-executor';
13
13
  export { cloudflareWorkersFactory } from './runtime-cf';
14
14
  export type { RuntimeFactory } from './runtime-factory';
15
15
  export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun';
16
16
  export * from './schema-validation';
17
17
  export * from './types';
18
- export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor';
18
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor } from './process-executor';
19
19
  /**
20
20
  * @deprecated Use {@link ProcessExecutor} directly for async execution.
21
21
  * Use `Bun.spawnSync` or `child_process.spawnSync` for sync.
@@ -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,OAAO,EAAE,+BAA+B,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC9E,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,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,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"}
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,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAC9E,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,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,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,mBAAmB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,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,MAAM,oBAAoB,CAAC;AAEnF;;;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
@@ -7,10 +7,10 @@ export { createNodeFileSystem, findProjectRoot } from './file-system-node.js';
7
7
  export { atomicWriteFile, atomicWriteJson, createLogStream, ensureDirForFile, readJsonFile, walkDir, writeJsonFile, } from './fs.js';
8
8
  export * from './path.js';
9
9
  export { _resetRuntimeFactory, isCloudflareWorkerRuntime, loadRuntimeFactory } from './platform.js';
10
- export { ProcessExecutor } from './process-executor.js';
10
+ export { NodeProcessExecutor, ProcessExecutor } from './process-executor.js';
11
11
  export { cloudflareWorkersFactory } from './runtime-cf.js';
12
12
  export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun.js';
13
13
  export * from './schema-validation.js';
14
14
  export * from './types.js';
15
15
  // ── Deprecated re-exports (backward compatibility) ──────────────────────
16
- export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor.js';
16
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor } from './process-executor.js';
@@ -87,12 +87,37 @@ export interface PipeProcess {
87
87
  kill(signal?: ProcessSignal): void;
88
88
  }
89
89
  /**
90
- * Runtime-agnostic process executor wrapping `execa`.
90
+ * Runtime-agnostic process executor contract.
91
91
  *
92
92
  * Every invocation supports timeout enforcement, output capture, and
93
- * configurable output policy (buffered vs streamed).
93
+ * configurable output policy (buffered vs streamed). Concrete implementations
94
+ * are obtained through `RuntimeFactory.createProcessExecutor`; the Node/Bun
95
+ * implementation is {@link NodeProcessExecutor}. Test doubles implement this
96
+ * interface structurally — no concrete subclassing required.
94
97
  */
95
- export declare class ProcessExecutor {
98
+ export interface ProcessExecutor {
99
+ /**
100
+ * Run a command, buffered by default. Returns a structured {@link ProcessResult}.
101
+ * Does NOT throw on non-zero exit codes unless `rejectOnError` is set.
102
+ */
103
+ run(options: ProcessOptions): Promise<ProcessResult>;
104
+ /**
105
+ * Spawn a long-running interactive process with streaming I/O.
106
+ *
107
+ * Returns a {@link PipeProcess} handle with streaming stdout/stderr and
108
+ * stdin write support.
109
+ */
110
+ runStreaming(options: PipeProcessOptions): PipeProcess;
111
+ }
112
+ /**
113
+ * Concrete Node/Bun implementation of {@link ProcessExecutor}, wrapping `execa`
114
+ * for buffered execution and `Bun.spawn` for streaming pipe execution.
115
+ *
116
+ * Obtain a default instance through `RuntimeFactory.createProcessExecutor`
117
+ * (e.g. `nodeBunFactory.createProcessExecutor()`); construct directly only in
118
+ * runtime-factory wiring or concrete implementation tests.
119
+ */
120
+ export declare class NodeProcessExecutor implements ProcessExecutor {
96
121
  private readonly config;
97
122
  constructor(config?: ProcessExecutorConfig);
98
123
  /**
@@ -113,11 +138,13 @@ export declare class ProcessExecutor {
113
138
  private emitProcessEvent;
114
139
  }
115
140
  /**
116
- * @deprecated Use {@link ProcessExecutor} directly.
117
- * This subclass is kept for backward compatibility.
141
+ * @deprecated Construct {@link NodeProcessExecutor} directly or obtain a default
142
+ * through `RuntimeFactory.createProcessExecutor` (e.g. `nodeBunFactory.createProcessExecutor()`).
143
+ * This value alias preserves source compatibility for `new ProcessExecutor(...)` callers
144
+ * during the interface extraction release; it will be removed in a future release.
145
+ * `import type { ProcessExecutor }` resolves to the canonical interface, not this alias.
118
146
  */
119
- export declare class NodeProcessExecutor extends ProcessExecutor {
120
- }
147
+ export declare const ProcessExecutor: typeof NodeProcessExecutor;
121
148
  /**
122
149
  * @deprecated Use `Bun.spawnSync` or `child_process.spawnSync` directly.
123
150
  * Synchronous process execution is no longer recommended from ts-runtime.
@@ -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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"}
@@ -1,13 +1,15 @@
1
1
  import { isatty } from 'node:tty';
2
2
  import { execa } from 'execa';
3
- // ── ProcessExecutor ───────────────────────────────────────────────────────
3
+ // ── NodeProcessExecutor (concrete Node/Bun implementation) ───────────────
4
4
  /**
5
- * Runtime-agnostic process executor wrapping `execa`.
5
+ * Concrete Node/Bun implementation of {@link ProcessExecutor}, wrapping `execa`
6
+ * for buffered execution and `Bun.spawn` for streaming pipe execution.
6
7
  *
7
- * Every invocation supports timeout enforcement, output capture, and
8
- * configurable output policy (buffered vs streamed).
8
+ * Obtain a default instance through `RuntimeFactory.createProcessExecutor`
9
+ * (e.g. `nodeBunFactory.createProcessExecutor()`); construct directly only in
10
+ * runtime-factory wiring or concrete implementation tests.
9
11
  */
10
- export class ProcessExecutor {
12
+ export class NodeProcessExecutor {
11
13
  config;
12
14
  constructor(config = {}) {
13
15
  this.config = config;
@@ -224,13 +226,16 @@ class BunPipeProcess {
224
226
  this.subprocess.kill(signal);
225
227
  }
226
228
  }
227
- // ── Deprecated backward-compatible subclasses ─────────────────────────────
229
+ // ── Deprecated constructible ProcessExecutor value alias ──────────────────
228
230
  /**
229
- * @deprecated Use {@link ProcessExecutor} directly.
230
- * This subclass is kept for backward compatibility.
231
+ * @deprecated Construct {@link NodeProcessExecutor} directly or obtain a default
232
+ * through `RuntimeFactory.createProcessExecutor` (e.g. `nodeBunFactory.createProcessExecutor()`).
233
+ * This value alias preserves source compatibility for `new ProcessExecutor(...)` callers
234
+ * during the interface extraction release; it will be removed in a future release.
235
+ * `import type { ProcessExecutor }` resolves to the canonical interface, not this alias.
231
236
  */
232
- export class NodeProcessExecutor extends ProcessExecutor {
233
- }
237
+ export const ProcessExecutor = NodeProcessExecutor;
238
+ // ── Deprecated backward-compatible helpers ────────────────────────────────
234
239
  /**
235
240
  * @deprecated Use `Bun.spawnSync` or `child_process.spawnSync` directly.
236
241
  * Synchronous process execution is no longer recommended from ts-runtime.
@@ -2,7 +2,7 @@ import { parse as parseYaml } from 'yaml';
2
2
  import { buildConfigFromObject, getProcessEnv } from './config.js';
3
3
  import { DbModuleNotInstalledError } from './db-errors.js';
4
4
  import { createNodeFileSystem } from './file-system-node.js';
5
- import { ProcessExecutor } from './process-executor.js';
5
+ import { NodeProcessExecutor } from './process-executor.js';
6
6
  // Lazy re-initialisable singleton for test isolation.
7
7
  let _nodeFileSystem;
8
8
  function getNodeFileSystem() {
@@ -26,7 +26,7 @@ export const nodeBunFactory = {
26
26
  hasSqlDatabase: true,
27
27
  },
28
28
  createFileSystem: () => getNodeFileSystem(),
29
- createProcessExecutor: (config) => new ProcessExecutor(config),
29
+ createProcessExecutor: (config) => new NodeProcessExecutor(config),
30
30
  async loadConfig(options) {
31
31
  return loadNodeConfig(options);
32
32
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-runtime",
3
- "version": "0.4.8",
3
+ "version": "0.4.9",
4
4
  "description": "@gobing-ai/ts-runtime — Runtime abstractions for Bun, Node, and Cloudflare Workers.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -58,17 +58,17 @@
58
58
  "release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-runtime-v<version> && git push --tags' && exit 1"
59
59
  },
60
60
  "dependencies": {
61
- "@gobing-ai/ts-utils": "^0.4.8",
61
+ "@gobing-ai/ts-utils": "^0.4.9",
62
62
  "execa": "^9.5.0",
63
63
  "yaml": "^2.7.0",
64
64
  "zod": "^4.1.0"
65
65
  },
66
66
  "devDependencies": {
67
- "@gobing-ai/ts-db": "^0.4.8",
67
+ "@gobing-ai/ts-db": "^0.4.9",
68
68
  "@types/bun": "1.3.14"
69
69
  },
70
70
  "peerDependencies": {
71
- "@gobing-ai/ts-db": "^0.4.8"
71
+ "@gobing-ai/ts-db": "^0.4.9"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "@gobing-ai/ts-db": {
package/src/context.ts CHANGED
@@ -4,7 +4,7 @@ import type { FileSystem } from './file-system';
4
4
  import { createNodeFileSystem } from './file-system-node';
5
5
  import { loadRuntimeFactory } from './platform';
6
6
  import type { ProcessExecutor as ProcessExecutorService } from './process-executor';
7
- import { ProcessExecutor } from './process-executor';
7
+ import { nodeBunFactory } from './runtime-node-bun';
8
8
  import type { RuntimeCapabilities, RuntimeName } from './types';
9
9
  /** Execution scope of a runtime context — determines service lifecycle and availability. */
10
10
  export type RuntimeScope = 'process' | 'server-request' | 'scheduled-event' | 'test';
@@ -50,7 +50,7 @@ export class RuntimeContext<TServices extends RuntimeServiceMap = RuntimeService
50
50
  (options.services?.fileSystem ?? createNodeFileSystem()) as TServices['fileSystem'],
51
51
  );
52
52
  if (this.capabilities.hasProcessExecution && options.services?.processExecutor === undefined) {
53
- this.register('processExecutor', new ProcessExecutor() as TServices['processExecutor']);
53
+ this.register('processExecutor', nodeBunFactory.createProcessExecutor() as TServices['processExecutor']);
54
54
  }
55
55
 
56
56
  for (const [key, value] of Object.entries(options.services ?? {})) {
package/src/index.ts CHANGED
@@ -30,7 +30,7 @@ export type {
30
30
  ProcessSignal,
31
31
  TracerPort,
32
32
  } from './process-executor';
33
- export { ProcessExecutor } from './process-executor';
33
+ export { NodeProcessExecutor, ProcessExecutor } from './process-executor';
34
34
  export { cloudflareWorkersFactory } from './runtime-cf';
35
35
  export type { RuntimeFactory } from './runtime-factory';
36
36
  export { _resetNodeFileSystem, nodeBunFactory } from './runtime-node-bun';
@@ -39,7 +39,7 @@ export * from './types';
39
39
 
40
40
  // ── Deprecated re-exports (backward compatibility) ──────────────────────
41
41
 
42
- export { BunPipeProcessSpawner, BunSyncProcessExecutor, NodeProcessExecutor } from './process-executor';
42
+ export { BunPipeProcessSpawner, BunSyncProcessExecutor } from './process-executor';
43
43
 
44
44
  /**
45
45
  * @deprecated Use {@link ProcessExecutor} directly for async execution.
@@ -99,15 +99,44 @@ export interface PipeProcess {
99
99
  kill(signal?: ProcessSignal): void;
100
100
  }
101
101
 
102
- // ── ProcessExecutor ───────────────────────────────────────────────────────
102
+ // ── ProcessExecutor (canonical interface) ────────────────────────────────
103
103
 
104
104
  /**
105
- * Runtime-agnostic process executor wrapping `execa`.
105
+ * Runtime-agnostic process executor contract.
106
106
  *
107
107
  * Every invocation supports timeout enforcement, output capture, and
108
- * configurable output policy (buffered vs streamed).
108
+ * configurable output policy (buffered vs streamed). Concrete implementations
109
+ * are obtained through `RuntimeFactory.createProcessExecutor`; the Node/Bun
110
+ * implementation is {@link NodeProcessExecutor}. Test doubles implement this
111
+ * interface structurally — no concrete subclassing required.
109
112
  */
110
- export class ProcessExecutor {
113
+ export interface ProcessExecutor {
114
+ /**
115
+ * Run a command, buffered by default. Returns a structured {@link ProcessResult}.
116
+ * Does NOT throw on non-zero exit codes unless `rejectOnError` is set.
117
+ */
118
+ run(options: ProcessOptions): Promise<ProcessResult>;
119
+
120
+ /**
121
+ * Spawn a long-running interactive process with streaming I/O.
122
+ *
123
+ * Returns a {@link PipeProcess} handle with streaming stdout/stderr and
124
+ * stdin write support.
125
+ */
126
+ runStreaming(options: PipeProcessOptions): PipeProcess;
127
+ }
128
+
129
+ // ── NodeProcessExecutor (concrete Node/Bun implementation) ───────────────
130
+
131
+ /**
132
+ * Concrete Node/Bun implementation of {@link ProcessExecutor}, wrapping `execa`
133
+ * for buffered execution and `Bun.spawn` for streaming pipe execution.
134
+ *
135
+ * Obtain a default instance through `RuntimeFactory.createProcessExecutor`
136
+ * (e.g. `nodeBunFactory.createProcessExecutor()`); construct directly only in
137
+ * runtime-factory wiring or concrete implementation tests.
138
+ */
139
+ export class NodeProcessExecutor implements ProcessExecutor {
111
140
  private readonly config: ProcessExecutorConfig;
112
141
 
113
142
  constructor(config: ProcessExecutorConfig = {}) {
@@ -374,13 +403,18 @@ class BunPipeProcess implements PipeProcess {
374
403
  }
375
404
  }
376
405
 
377
- // ── Deprecated backward-compatible subclasses ─────────────────────────────
406
+ // ── Deprecated constructible ProcessExecutor value alias ──────────────────
378
407
 
379
408
  /**
380
- * @deprecated Use {@link ProcessExecutor} directly.
381
- * This subclass is kept for backward compatibility.
409
+ * @deprecated Construct {@link NodeProcessExecutor} directly or obtain a default
410
+ * through `RuntimeFactory.createProcessExecutor` (e.g. `nodeBunFactory.createProcessExecutor()`).
411
+ * This value alias preserves source compatibility for `new ProcessExecutor(...)` callers
412
+ * during the interface extraction release; it will be removed in a future release.
413
+ * `import type { ProcessExecutor }` resolves to the canonical interface, not this alias.
382
414
  */
383
- export class NodeProcessExecutor extends ProcessExecutor {}
415
+ export const ProcessExecutor = NodeProcessExecutor;
416
+
417
+ // ── Deprecated backward-compatible helpers ────────────────────────────────
384
418
 
385
419
  /**
386
420
  * @deprecated Use `Bun.spawnSync` or `child_process.spawnSync` directly.
@@ -4,7 +4,7 @@ import { buildConfigFromObject, getProcessEnv } from './config';
4
4
  import { DbModuleNotInstalledError } from './db-errors';
5
5
  import type { FileSystem } from './file-system';
6
6
  import { createNodeFileSystem } from './file-system-node';
7
- import { ProcessExecutor, type ProcessExecutorConfig } from './process-executor';
7
+ import { NodeProcessExecutor, type ProcessExecutorConfig } from './process-executor';
8
8
  import type { RuntimeFactory } from './runtime-factory';
9
9
  import type { DatabaseConfig, LoadConfigOptions, RuntimeDbAdapter } from './types';
10
10
 
@@ -34,7 +34,7 @@ export const nodeBunFactory: RuntimeFactory = {
34
34
 
35
35
  createFileSystem: () => getNodeFileSystem(),
36
36
 
37
- createProcessExecutor: (config?: ProcessExecutorConfig) => new ProcessExecutor(config),
37
+ createProcessExecutor: (config?: ProcessExecutorConfig) => new NodeProcessExecutor(config),
38
38
 
39
39
  async loadConfig(options?: LoadConfigOptions): Promise<Config> {
40
40
  return loadNodeConfig(options);