@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 +34 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +1 -0
- package/dist/db-errors.d.ts +14 -0
- package/dist/db-errors.d.ts.map +1 -0
- package/dist/db-errors.js +16 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/runtime-cf.d.ts.map +1 -1
- package/dist/runtime-cf.js +8 -0
- package/dist/runtime-factory.d.ts +12 -1
- package/dist/runtime-factory.d.ts.map +1 -1
- package/dist/runtime-node-bun.d.ts.map +1 -1
- package/dist/runtime-node-bun.js +12 -0
- package/dist/types.d.ts +53 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/context.ts +1 -0
- package/src/db-errors.ts +16 -0
- package/src/index.ts +1 -0
- package/src/runtime-cf.ts +10 -2
- package/src/runtime-factory.ts +13 -1
- package/src/runtime-node-bun.ts +16 -2
- package/src/types.ts +55 -1
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.
|
|
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
|
|
package/dist/context.d.ts.map
CHANGED
|
@@ -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;
|
|
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';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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';
|
package/dist/runtime-cf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-cf.d.ts","sourceRoot":"","sources":["../src/runtime-cf.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/runtime-cf.js
CHANGED
|
@@ -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;
|
|
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,
|
|
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"}
|
package/dist/runtime-node-bun.js
CHANGED
|
@@ -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
|
-
/**
|
|
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 {
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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
|
|
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.
|
|
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.
|
|
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']);
|
package/src/db-errors.ts
ADDED
|
@@ -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> = {};
|
package/src/runtime-factory.ts
CHANGED
|
@@ -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
|
}
|
package/src/runtime-node-bun.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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. */
|