@gobing-ai/ts-runtime 0.3.17 → 0.3.19

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
@@ -17,6 +17,7 @@ and Cloudflare Workers through a factory pattern that auto-detects the runtime.
17
17
  | Runtime factory | `RuntimeFactory` → `loadRuntimeFactory()` | `nodeBunFactory` | `cloudflareWorkersFactory` |
18
18
  | File system | `FileSystem` | `createNodeFileSystem()` (sync `node:fs`) | `createCfFileSystem()` (stub) |
19
19
  | Process execution | `ProcessExecutor` (class) | `run()` via execa, `runStreaming()` via `Bun.spawn` | throws |
20
+ | SQL database | `createDbAdapter(config)` → `DbAdapter` | Bun SQLite via `@gobing-ai/ts-db` | throws `D1NotConfiguredError` (D1 round pending) |
20
21
  | Configuration | `Config` (Zod schema) | YAML + env vars | CONFIG_YAML blob + env vars |
21
22
  | Context | `RuntimeContext` | service locator | service locator |
22
23
  | Path utilities | `SEP`, `basenamePath`, `dirnamePath`, `joinPath`, `resolvePath`, `relativePath`, … | runtime-portable (zero `node:*`) | runtime-portable (zero `node:*`) |
@@ -31,24 +32,24 @@ classDiagram
31
32
  class RuntimeFactory {
32
33
  <<interface>>
33
34
  +string runtimeName
34
- +RuntimeCapabilities capabilities
35
35
  +createFileSystem() FileSystem
36
36
  +createProcessExecutor() ProcessExecutor
37
37
  +loadConfig() Promise~Config~
38
+ +createDbAdapter(config) Promise~DbAdapter~
38
39
  }
39
40
 
40
41
  class nodeBunFactory {
41
- +string runtimeName
42
42
  +createFileSystem() createNodeFileSystem()
43
43
  +createProcessExecutor() ProcessExecutor
44
44
  +loadConfig() Promise~Config~
45
+ +createDbAdapter() Promise~DbAdapter~
45
46
  }
46
47
 
47
48
  class cloudflareWorkersFactory {
48
- +string runtimeName
49
49
  +createFileSystem() createCfFileSystem()
50
50
  +createProcessExecutor() never
51
51
  +loadConfig() Promise~Config~
52
+ +createDbAdapter() never
52
53
  }
53
54
 
54
55
  class FileSystem {
@@ -368,7 +369,36 @@ cffs.readFile('/x'); // throws: "use D1, KV, or R2"
368
369
  The old `getFs()` / `setFileSystem` global swap and `SyncFileSystem` are marked `@deprecated` —
369
370
  use `createNodeFileSystem()` or `ctx.require('fileSystem')` instead.
370
371
 
371
- ### 8. Graceful disposal
372
+ ### 8. Database adapter (`createDbAdapter`)
373
+
374
+ The factory's `createDbAdapter(config)` opens a connected adapter satisfying the `RuntimeDbAdapter` contract
375
+ (the runtime-facing subset of `@gobing-ai/ts-db`'s `DbAdapter`) at the configured path. **ts-runtime owns
376
+ connection; the consumer owns schema** — the returned adapter is connected but NOT migrated. The consumer
377
+ composes its own migrations on top.
378
+
379
+ ```ts
380
+ import { loadRuntimeFactory } from '@gobing-ai/ts-runtime';
381
+
382
+ const factory = await loadRuntimeFactory();
383
+
384
+ if (factory.capabilities.hasSqlDatabase) {
385
+ const adapter = await factory.createDbAdapter({ url: '.spur/spur.db' });
386
+ // adapter is connected — apply YOUR migrations here, then use DAOs.
387
+ adapter.close();
388
+ }
389
+ ```
390
+
391
+ On Cloudflare Workers, `capabilities.hasSqlDatabase` is `false` and `createDbAdapter` throws a typed
392
+ `D1NotConfiguredError` — the method exists on the interface so consumer code is forward-compatible and
393
+ needs no change when the D1 round ships.
394
+
395
+ **Dependency note:** `@gobing-ai/ts-db` is not a static dependency of `ts-runtime` (it would create a
396
+ cycle, since `ts-db` depends on `ts-runtime`). The factory interface uses a structural
397
+ `RuntimeDbAdapter` type (defined locally) that a ts-db `DbAdapter` satisfies via structural subtyping;
398
+ `nodeBunFactory.createDbAdapter` loads `ts-db` via a dynamic `import()` at runtime. Consumers that call
399
+ `createDbAdapter` must have `@gobing-ai/ts-db` in their dependency graph.
400
+
401
+ ### 9. Graceful disposal
372
402
 
373
403
  `RuntimeContext.dispose()` calls `dispose()` on every registered service that implements the pattern:
374
404
 
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,IAAI,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChE,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,MAAM,CAAC;AAErF,8GAA8G;AAC9G,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,yDAAyD;AACzD,MAAM,WAAW,qBAAqB,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB;IAC1F,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CACjC;AAED,uGAAuG;AACvG,qBAAa,cAAc,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB;IAC/E,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,mDAA0D;gBAE/D,OAAO,GAAE,qBAAqB,CAAC,SAAS,CAAM;IA2B1D,QAAQ,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAKxE,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS;IAIhE,OAAO,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAQxD,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO;IAIzC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAejC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,+BAA+B,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB,EACzG,OAAO,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAiBpC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB,EACxF,OAAO,GAAE,qBAAqB,CAAC,SAAS,CAAM,GAC/C,cAAc,CAAC,SAAS,CAAC,CAE3B"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,IAAI,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAEpF,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChE,4FAA4F;AAC5F,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,MAAM,CAAC;AAErF,8GAA8G;AAC9G,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,CAAC,EAAE,sBAAsB,CAAC;IACzC,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,yDAAyD;AACzD,MAAM,WAAW,qBAAqB,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB;IAC1F,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CACjC;AAED,uGAAuG;AACvG,qBAAa,cAAc,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB;IAC/E,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAC3C,QAAQ,CAAC,QAAQ,mDAA0D;gBAE/D,OAAO,GAAE,qBAAqB,CAAC,SAAS,CAAM;IA4B1D,QAAQ,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAKxE,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS;IAIhE,OAAO,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAQxD,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,OAAO;IAIzC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAejC;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,+BAA+B,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB,EACzG,OAAO,CAAC,EAAE,qBAAqB,CAAC,SAAS,CAAC,GAC3C,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAiBpC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,SAAS,iBAAiB,GAAG,iBAAiB,EACxF,OAAO,GAAE,qBAAqB,CAAC,SAAS,CAAM,GAC/C,cAAc,CAAC,SAAS,CAAC,CAE3B"}
package/dist/context.js CHANGED
@@ -17,6 +17,7 @@ export class RuntimeContext {
17
17
  hasFilesystem: true,
18
18
  hasProcessExecution: true,
19
19
  hasPersistentStorage: true,
20
+ hasSqlDatabase: true,
20
21
  };
21
22
  this.register('config', (options.services?.config ?? buildConfigFromObject({})));
22
23
  this.register('fileSystem', (options.services?.fileSystem ?? createNodeFileSystem()));
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Thrown by {@link RuntimeFactory.createDbAdapter} on runtimes that cannot yet
3
+ * provide a SQL database adapter.
4
+ *
5
+ * Today only the Cloudflare Workers factory throws this: the D1 `DbAdapter`
6
+ * lives in a future `@gobing-ai/ts-db` round. The method exists on the
7
+ * interface so consumer app code is forward-compatible — it calls
8
+ * `createDbAdapter` uniformly and the Worker path surfaces this clear typed
9
+ * failure instead of a silent `undefined`.
10
+ */
11
+ export declare class D1NotConfiguredError extends Error {
12
+ constructor(message?: string);
13
+ }
14
+ //# sourceMappingURL=db-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-errors.d.ts","sourceRoot":"","sources":["../src/db-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;gBAC/B,OAAO,SAAiE;CAIvF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Thrown by {@link RuntimeFactory.createDbAdapter} on runtimes that cannot yet
3
+ * provide a SQL database adapter.
4
+ *
5
+ * Today only the Cloudflare Workers factory throws this: the D1 `DbAdapter`
6
+ * lives in a future `@gobing-ai/ts-db` round. The method exists on the
7
+ * interface so consumer app code is forward-compatible — it calls
8
+ * `createDbAdapter` uniformly and the Worker path surfaces this clear typed
9
+ * failure instead of a silent `undefined`.
10
+ */
11
+ export class D1NotConfiguredError extends Error {
12
+ constructor(message = 'D1 DbAdapter is not yet implemented; see the ts-db D1 round.') {
13
+ super(message);
14
+ this.name = 'D1NotConfiguredError';
15
+ }
16
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './config';
2
2
  export * from './context';
3
3
  export { createRuntimeContextFromFactory } from './context';
4
+ export { D1NotConfiguredError } from './db-errors';
4
5
  export type { FileStat, FileSystem } from './file-system';
5
6
  export { createCfFileSystem } from './file-system-cf';
6
7
  export { createNodeFileSystem, findProjectRoot } from './file-system-node';
@@ -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,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"}
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,MAAM,aAAa,CAAC;AACnD,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,6 +1,7 @@
1
1
  export * from './config.js';
2
2
  export * from './context.js';
3
3
  export { createRuntimeContextFromFactory } from './context.js';
4
+ export { D1NotConfiguredError } from './db-errors.js';
4
5
  export { createCfFileSystem } from './file-system-cf.js';
5
6
  export { createNodeFileSystem, findProjectRoot } from './file-system-node.js';
6
7
  export { atomicWriteFile, atomicWriteJson, CloudflareFileSystem, createLogStream, ensureDirForFile, ensureDirForFileSync, getFs, getProjectRoot, NodeFileSystem, NodeSyncFileSystem, readJsonFile, resolveProjectPath, setFileSystem, walkDir, writeJsonFile, } from './fs.js';
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-cf.d.ts","sourceRoot":"","sources":["../src/runtime-cf.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMxD;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,cA6BtC,CAAC"}
1
+ {"version":3,"file":"runtime-cf.d.ts","sourceRoot":"","sources":["../src/runtime-cf.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAMxD;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,cAoCtC,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { parse as parseYaml } from 'yaml';
2
2
  import { buildConfigFromObject } from './config.js';
3
+ import { D1NotConfiguredError } from './db-errors.js';
3
4
  import { createCfFileSystem } from './file-system-cf.js';
4
5
  /** Binding name for the YAML config text blob set in wrangler.toml. */
5
6
  const CONFIG_YAML_BINDING = 'CONFIG_YAML';
@@ -12,11 +13,18 @@ export const cloudflareWorkersFactory = {
12
13
  hasFilesystem: false,
13
14
  hasProcessExecution: false,
14
15
  hasPersistentStorage: false,
16
+ hasSqlDatabase: false,
15
17
  },
16
18
  createFileSystem: () => createCfFileSystem(),
17
19
  createProcessExecutor: (_config) => {
18
20
  throw new Error('ProcessExecutor is not available on Cloudflare Workers.');
19
21
  },
22
+ createDbAdapter(_config) {
23
+ // The D1 DbAdapter ships in a future ts-db round. The method exists on
24
+ // the interface so consumer code is forward-compatible and needs no
25
+ // change when D1 lands. Until then, surface a clear typed failure.
26
+ return Promise.reject(new D1NotConfiguredError());
27
+ },
20
28
  async loadConfig(options) {
21
29
  const yamlString = options?.envBindings?.[CONFIG_YAML_BINDING];
22
30
  let raw = {};
@@ -1,7 +1,7 @@
1
1
  import type { Config } from './config';
2
2
  import type { FileSystem } from './file-system';
3
3
  import type { ProcessExecutor, ProcessExecutorConfig } from './process-executor';
4
- import type { LoadConfigOptions, RuntimeCapabilities, RuntimeName } from './types';
4
+ import type { DatabaseConfig, LoadConfigOptions, RuntimeCapabilities, RuntimeDbAdapter, RuntimeName } from './types';
5
5
  /**
6
6
  * Abstract factory for creating runtime-aware infrastructure.
7
7
  *
@@ -20,5 +20,16 @@ export interface RuntimeFactory {
20
20
  createProcessExecutor(config?: ProcessExecutorConfig): ProcessExecutor;
21
21
  /** Load config from the runtime's config backend. */
22
22
  loadConfig(options?: LoadConfigOptions): Promise<Config>;
23
+ /**
24
+ * Create a runtime-specific database adapter.
25
+ *
26
+ * ts-runtime owns *connection* (opens the adapter at `config.url`); the
27
+ * consumer owns *schema* (migrations). The returned adapter is connected
28
+ * but NOT migrated.
29
+ *
30
+ * On runtimes without a SQL database (`capabilities.hasSqlDatabase === false`)
31
+ * this throws {@link D1NotConfiguredError}.
32
+ */
33
+ createDbAdapter(config: DatabaseConfig): Promise<RuntimeDbAdapter>;
23
34
  }
24
35
  //# sourceMappingURL=runtime-factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-factory.d.ts","sourceRoot":"","sources":["../src/runtime-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEnF;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAElC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAE3C,yFAAyF;IACzF,gBAAgB,IAAI,UAAU,CAAC;IAE/B,oGAAoG;IACpG,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAAC;IAEvE,qDAAqD;IACrD,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC5D"}
1
+ {"version":3,"file":"runtime-factory.d.ts","sourceRoot":"","sources":["../src/runtime-factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAErH;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAElC,QAAQ,CAAC,YAAY,EAAE,mBAAmB,CAAC;IAE3C,yFAAyF;IACzF,gBAAgB,IAAI,UAAU,CAAC;IAE/B,oGAAoG;IACpG,qBAAqB,CAAC,MAAM,CAAC,EAAE,qBAAqB,GAAG,eAAe,CAAC;IAEvE,qDAAqD;IACrD,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD;;;;;;;;;OASG;IACH,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACtE"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-node-bun.d.ts","sourceRoot":"","sources":["../src/runtime-node-bun.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,oEAAoE;AACpE,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,cAgB5B,CAAC"}
1
+ {"version":3,"file":"runtime-node-bun.d.ts","sourceRoot":"","sources":["../src/runtime-node-bun.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,oEAAoE;AACpE,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,cA8B5B,CAAC"}
@@ -22,12 +22,24 @@ export const nodeBunFactory = {
22
22
  hasFilesystem: true,
23
23
  hasProcessExecution: true,
24
24
  hasPersistentStorage: true,
25
+ hasSqlDatabase: true,
25
26
  },
26
27
  createFileSystem: () => getNodeFileSystem(),
27
28
  createProcessExecutor: (config) => new ProcessExecutor(config),
28
29
  async loadConfig(options) {
29
30
  return loadNodeConfig(options);
30
31
  },
32
+ async createDbAdapter(config) {
33
+ // Dynamic import via a variable specifier keeps ts-db out of the
34
+ // static dependency graph (it depends on ts-runtime, so a static dep
35
+ // would cycle). The variable prevents tsc from type-resolving the
36
+ // module at build time (ts-db builds after ts-runtime); at runtime
37
+ // Bun resolves it via the workspace + tsconfig paths. Connection only
38
+ // — the caller owns schema/migrations.
39
+ const moduleSpecifier = '@gobing-ai/ts-db';
40
+ const mod = (await import(moduleSpecifier));
41
+ return mod.createDbAdapter({ driver: 'bun-sqlite', url: config.url });
42
+ },
31
43
  };
32
44
  // ── Config loading (Node/Bun) ────────────────────────────────────────────
33
45
  /**
package/dist/types.d.ts CHANGED
@@ -1,11 +1,63 @@
1
1
  import type { Config } from './config';
2
2
  /** Identifier for the target runtime platform. */
3
3
  export type RuntimeName = 'node-bun' | 'cloudflare-workers' | 'test';
4
- /** Feature flags describing what a runtime platform supports (filesystem, process execution, persistent storage). */
4
+ /**
5
+ * Feature flags describing what a runtime platform supports (filesystem, process
6
+ * execution, persistent storage, SQL database).
7
+ */
5
8
  export interface RuntimeCapabilities {
6
9
  readonly hasFilesystem: boolean;
7
10
  readonly hasProcessExecution: boolean;
8
11
  readonly hasPersistentStorage: boolean;
12
+ /**
13
+ * Whether the runtime can provide a connected {@link DbAdapter}.
14
+ *
15
+ * `true` on Node/Bun (Bun SQLite); `false` on Cloudflare Workers until the
16
+ * D1 round ships — the CF factory's `createDbAdapter` throws a typed
17
+ * {@link D1NotConfiguredError} so consumer code is forward-compatible.
18
+ */
19
+ readonly hasSqlDatabase: boolean;
20
+ }
21
+ /**
22
+ * Configuration for {@link RuntimeFactory.createDbAdapter}.
23
+ *
24
+ * Focused on the DB facility so it does not bloat the general runtime {@link Config}.
25
+ * The Bun path reads `url` (a filesystem path or `":memory:"`); the Cloudflare path
26
+ * would read `d1Binding` (scoped to a later ts-db round).
27
+ */
28
+ export interface DatabaseConfig {
29
+ /** SQLite database path or `":memory:"`. Bun path only. */
30
+ url: string;
31
+ /** Optional driver hint. Reserved for future drivers. */
32
+ driver?: string;
33
+ /** Name of the D1 binding in wrangler.toml. CF path (future D1 round). */
34
+ d1Binding?: string;
35
+ }
36
+ /**
37
+ * Structural database adapter contract — the runtime-facing subset of
38
+ * `@gobing-ai/ts-db`'s `DbAdapter`.
39
+ *
40
+ * ts-runtime cannot import the `DbAdapter` type from ts-db at build time
41
+ * (ts-db depends on ts-runtime, so the build order is runtime → db). This
42
+ * structural type captures the public method surface; a ts-db `DbAdapter` is
43
+ * assignable to it because it implements every method (plus the `@internal db`
44
+ * property, which is extra and harmless under structural subtyping).
45
+ *
46
+ * The full `DbAdapter` type is re-exported from the package index via
47
+ * `import type` for consumer convenience; this structural type is the
48
+ * build-time contract used inside the factory.
49
+ */
50
+ export interface RuntimeDbAdapter {
51
+ /** Run a raw SQL statement with no parameters (DDL). */
52
+ exec(sql: string): Promise<void>;
53
+ /** Parameterized write (INSERT/UPDATE/DELETE) that returns no rows. */
54
+ run(sql: string, ...params: unknown[]): Promise<void>;
55
+ /** Parameterized read returning the first row, or undefined. */
56
+ queryFirst<T>(sql: string, ...params: unknown[]): Promise<T | undefined>;
57
+ /** Parameterized read returning all rows. */
58
+ queryAll<T>(sql: string, ...params: unknown[]): Promise<T[]>;
59
+ /** Close the underlying connection. */
60
+ close(): void;
9
61
  }
10
62
  /** Options passed to config loading functions, including overrides and environment variable bindings. */
11
63
  export interface LoadConfigOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAErE,qHAAqH;AACrH,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;CAC1C;AAED,yGAAyG;AACzG,MAAM,WAAW,iBAAiB;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;CAC1D"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,kDAAkD;AAClD,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,oBAAoB,GAAG,MAAM,CAAC;AAErE;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAChC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC;IACvC;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC3B,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,gBAAgB;IAC7B,wDAAwD;IACxD,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,gEAAgE;IAChE,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IACzE,6CAA6C;IAC7C,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7D,uCAAuC;IACvC,KAAK,IAAI,IAAI,CAAC;CACjB;AAED,yGAAyG;AACzG,MAAM,WAAW,iBAAiB;IAC9B,SAAS,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACzC;AAED,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;CAC1D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/ts-runtime",
3
- "version": "0.3.17",
3
+ "version": "0.3.19",
4
4
  "description": "@gobing-ai/ts-runtime — Runtime abstractions for Bun, Node, and Cloudflare Workers.",
5
5
  "keywords": [
6
6
  "typescript",
@@ -58,12 +58,13 @@
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.3.17",
61
+ "@gobing-ai/ts-utils": "^0.3.19",
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.3.19",
67
68
  "@types/bun": "1.3.14"
68
69
  },
69
70
  "publishConfig": {
package/src/context.ts CHANGED
@@ -41,6 +41,7 @@ export class RuntimeContext<TServices extends RuntimeServiceMap = RuntimeService
41
41
  hasFilesystem: true,
42
42
  hasProcessExecution: true,
43
43
  hasPersistentStorage: true,
44
+ hasSqlDatabase: true,
44
45
  } satisfies RuntimeCapabilities);
45
46
 
46
47
  this.register('config', (options.services?.config ?? buildConfigFromObject({})) as TServices['config']);
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Thrown by {@link RuntimeFactory.createDbAdapter} on runtimes that cannot yet
3
+ * provide a SQL database adapter.
4
+ *
5
+ * Today only the Cloudflare Workers factory throws this: the D1 `DbAdapter`
6
+ * lives in a future `@gobing-ai/ts-db` round. The method exists on the
7
+ * interface so consumer app code is forward-compatible — it calls
8
+ * `createDbAdapter` uniformly and the Worker path surfaces this clear typed
9
+ * failure instead of a silent `undefined`.
10
+ */
11
+ export class D1NotConfiguredError extends Error {
12
+ constructor(message = 'D1 DbAdapter is not yet implemented; see the ts-db D1 round.') {
13
+ super(message);
14
+ this.name = 'D1NotConfiguredError';
15
+ }
16
+ }
package/src/index.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './config';
2
2
  export * from './context';
3
3
  export { createRuntimeContextFromFactory } from './context';
4
+ export { D1NotConfiguredError } from './db-errors';
4
5
  export type { FileStat, FileSystem } from './file-system';
5
6
  export { createCfFileSystem } from './file-system-cf';
6
7
  export { createNodeFileSystem, findProjectRoot } from './file-system-node';
package/src/runtime-cf.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { parse as parseYaml } from 'yaml';
2
2
  import type { Config } from './config';
3
3
  import { buildConfigFromObject } from './config';
4
+ import { D1NotConfiguredError } from './db-errors';
4
5
  import { createCfFileSystem } from './file-system-cf';
5
6
  import type { ProcessExecutorConfig } from './process-executor';
6
7
  import type { RuntimeFactory } from './runtime-factory';
7
- import type { LoadConfigOptions } from './types';
8
+ import type { DatabaseConfig, LoadConfigOptions, RuntimeDbAdapter } from './types';
8
9
 
9
10
  /** Binding name for the YAML config text blob set in wrangler.toml. */
10
11
  const CONFIG_YAML_BINDING = 'CONFIG_YAML';
@@ -14,11 +15,11 @@ const CONFIG_YAML_BINDING = 'CONFIG_YAML';
14
15
  */
15
16
  export const cloudflareWorkersFactory: RuntimeFactory = {
16
17
  runtimeName: 'cloudflare-workers',
17
-
18
18
  capabilities: {
19
19
  hasFilesystem: false,
20
20
  hasProcessExecution: false,
21
21
  hasPersistentStorage: false,
22
+ hasSqlDatabase: false,
22
23
  },
23
24
 
24
25
  createFileSystem: () => createCfFileSystem(),
@@ -27,6 +28,13 @@ export const cloudflareWorkersFactory: RuntimeFactory = {
27
28
  throw new Error('ProcessExecutor is not available on Cloudflare Workers.');
28
29
  },
29
30
 
31
+ createDbAdapter(_config: DatabaseConfig): Promise<RuntimeDbAdapter> {
32
+ // The D1 DbAdapter ships in a future ts-db round. The method exists on
33
+ // the interface so consumer code is forward-compatible and needs no
34
+ // change when D1 lands. Until then, surface a clear typed failure.
35
+ return Promise.reject(new D1NotConfiguredError());
36
+ },
37
+
30
38
  async loadConfig(options?: LoadConfigOptions): Promise<Config> {
31
39
  const yamlString = options?.envBindings?.[CONFIG_YAML_BINDING] as string | undefined;
32
40
  let raw: Record<string, unknown> = {};
@@ -1,7 +1,7 @@
1
1
  import type { Config } from './config';
2
2
  import type { FileSystem } from './file-system';
3
3
  import type { ProcessExecutor, ProcessExecutorConfig } from './process-executor';
4
- import type { LoadConfigOptions, RuntimeCapabilities, RuntimeName } from './types';
4
+ import type { DatabaseConfig, LoadConfigOptions, RuntimeCapabilities, RuntimeDbAdapter, RuntimeName } from './types';
5
5
 
6
6
  /**
7
7
  * Abstract factory for creating runtime-aware infrastructure.
@@ -25,4 +25,16 @@ export interface RuntimeFactory {
25
25
 
26
26
  /** Load config from the runtime's config backend. */
27
27
  loadConfig(options?: LoadConfigOptions): Promise<Config>;
28
+
29
+ /**
30
+ * Create a runtime-specific database adapter.
31
+ *
32
+ * ts-runtime owns *connection* (opens the adapter at `config.url`); the
33
+ * consumer owns *schema* (migrations). The returned adapter is connected
34
+ * but NOT migrated.
35
+ *
36
+ * On runtimes without a SQL database (`capabilities.hasSqlDatabase === false`)
37
+ * this throws {@link D1NotConfiguredError}.
38
+ */
39
+ createDbAdapter(config: DatabaseConfig): Promise<RuntimeDbAdapter>;
28
40
  }
@@ -5,7 +5,7 @@ import type { FileSystem } from './file-system';
5
5
  import { createNodeFileSystem } from './file-system-node';
6
6
  import { ProcessExecutor, type ProcessExecutorConfig } from './process-executor';
7
7
  import type { RuntimeFactory } from './runtime-factory';
8
- import type { LoadConfigOptions } from './types';
8
+ import type { DatabaseConfig, LoadConfigOptions, RuntimeDbAdapter } from './types';
9
9
 
10
10
  // Lazy re-initialisable singleton for test isolation.
11
11
  let _nodeFileSystem: FileSystem | undefined;
@@ -24,11 +24,11 @@ export function _resetNodeFileSystem(): void {
24
24
  */
25
25
  export const nodeBunFactory: RuntimeFactory = {
26
26
  runtimeName: 'node-bun',
27
-
28
27
  capabilities: {
29
28
  hasFilesystem: true,
30
29
  hasProcessExecution: true,
31
30
  hasPersistentStorage: true,
31
+ hasSqlDatabase: true,
32
32
  },
33
33
 
34
34
  createFileSystem: () => getNodeFileSystem(),
@@ -38,6 +38,20 @@ export const nodeBunFactory: RuntimeFactory = {
38
38
  async loadConfig(options?: LoadConfigOptions): Promise<Config> {
39
39
  return loadNodeConfig(options);
40
40
  },
41
+
42
+ async createDbAdapter(config: DatabaseConfig): Promise<RuntimeDbAdapter> {
43
+ // Dynamic import via a variable specifier keeps ts-db out of the
44
+ // static dependency graph (it depends on ts-runtime, so a static dep
45
+ // would cycle). The variable prevents tsc from type-resolving the
46
+ // module at build time (ts-db builds after ts-runtime); at runtime
47
+ // Bun resolves it via the workspace + tsconfig paths. Connection only
48
+ // — the caller owns schema/migrations.
49
+ const moduleSpecifier = '@gobing-ai/ts-db';
50
+ const mod = (await import(moduleSpecifier)) as {
51
+ createDbAdapter: (config: { driver: 'bun-sqlite'; url?: string }) => RuntimeDbAdapter;
52
+ };
53
+ return mod.createDbAdapter({ driver: 'bun-sqlite', url: config.url });
54
+ },
41
55
  };
42
56
 
43
57
  // ── Config loading (Node/Bun) ────────────────────────────────────────────
package/src/types.ts CHANGED
@@ -3,11 +3,65 @@ import type { Config } from './config';
3
3
  /** Identifier for the target runtime platform. */
4
4
  export type RuntimeName = 'node-bun' | 'cloudflare-workers' | 'test';
5
5
 
6
- /** Feature flags describing what a runtime platform supports (filesystem, process execution, persistent storage). */
6
+ /**
7
+ * Feature flags describing what a runtime platform supports (filesystem, process
8
+ * execution, persistent storage, SQL database).
9
+ */
7
10
  export interface RuntimeCapabilities {
8
11
  readonly hasFilesystem: boolean;
9
12
  readonly hasProcessExecution: boolean;
10
13
  readonly hasPersistentStorage: boolean;
14
+ /**
15
+ * Whether the runtime can provide a connected {@link DbAdapter}.
16
+ *
17
+ * `true` on Node/Bun (Bun SQLite); `false` on Cloudflare Workers until the
18
+ * D1 round ships — the CF factory's `createDbAdapter` throws a typed
19
+ * {@link D1NotConfiguredError} so consumer code is forward-compatible.
20
+ */
21
+ readonly hasSqlDatabase: boolean;
22
+ }
23
+
24
+ /**
25
+ * Configuration for {@link RuntimeFactory.createDbAdapter}.
26
+ *
27
+ * Focused on the DB facility so it does not bloat the general runtime {@link Config}.
28
+ * The Bun path reads `url` (a filesystem path or `":memory:"`); the Cloudflare path
29
+ * would read `d1Binding` (scoped to a later ts-db round).
30
+ */
31
+ export interface DatabaseConfig {
32
+ /** SQLite database path or `":memory:"`. Bun path only. */
33
+ url: string;
34
+ /** Optional driver hint. Reserved for future drivers. */
35
+ driver?: string;
36
+ /** Name of the D1 binding in wrangler.toml. CF path (future D1 round). */
37
+ d1Binding?: string;
38
+ }
39
+
40
+ /**
41
+ * Structural database adapter contract — the runtime-facing subset of
42
+ * `@gobing-ai/ts-db`'s `DbAdapter`.
43
+ *
44
+ * ts-runtime cannot import the `DbAdapter` type from ts-db at build time
45
+ * (ts-db depends on ts-runtime, so the build order is runtime → db). This
46
+ * structural type captures the public method surface; a ts-db `DbAdapter` is
47
+ * assignable to it because it implements every method (plus the `@internal db`
48
+ * property, which is extra and harmless under structural subtyping).
49
+ *
50
+ * The full `DbAdapter` type is re-exported from the package index via
51
+ * `import type` for consumer convenience; this structural type is the
52
+ * build-time contract used inside the factory.
53
+ */
54
+ export interface RuntimeDbAdapter {
55
+ /** Run a raw SQL statement with no parameters (DDL). */
56
+ exec(sql: string): Promise<void>;
57
+ /** Parameterized write (INSERT/UPDATE/DELETE) that returns no rows. */
58
+ run(sql: string, ...params: unknown[]): Promise<void>;
59
+ /** Parameterized read returning the first row, or undefined. */
60
+ queryFirst<T>(sql: string, ...params: unknown[]): Promise<T | undefined>;
61
+ /** Parameterized read returning all rows. */
62
+ queryAll<T>(sql: string, ...params: unknown[]): Promise<T[]>;
63
+ /** Close the underlying connection. */
64
+ close(): void;
11
65
  }
12
66
 
13
67
  /** Options passed to config loading functions, including overrides and environment variable bindings. */