@gobing-ai/ts-runtime 0.4.5 → 0.4.6
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 +20 -6
- package/dist/db-errors.d.ts +13 -0
- package/dist/db-errors.d.ts.map +1 -1
- package/dist/db-errors.js +16 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/path.d.ts +2 -0
- package/dist/path.d.ts.map +1 -1
- package/dist/path.js +18 -0
- package/dist/runtime-node-bun.d.ts.map +1 -1
- package/dist/runtime-node-bun.js +19 -7
- package/package.json +11 -3
- package/src/db-errors.ts +20 -0
- package/src/index.ts +1 -1
- package/src/path.ts +21 -0
- package/src/runtime-node-bun.ts +20 -9
package/README.md
CHANGED
|
@@ -17,7 +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
|
+
| SQL database | `createDbAdapter(config)` → `DbAdapter` | Bun SQLite via `@gobing-ai/ts-db` (optional peer) | throws `D1NotConfiguredError` (D1 round pending) |
|
|
21
21
|
| Configuration | `Config` (Zod schema) | YAML + env vars | CONFIG_YAML blob + env vars |
|
|
22
22
|
| Context | `RuntimeContext` | service locator | service locator |
|
|
23
23
|
| Path utilities | `SEP`, `basenamePath`, `dirnamePath`, `joinPath`, `resolvePath`, `relativePath`, … | runtime-portable (zero `node:*`) | runtime-portable (zero `node:*`) |
|
|
@@ -392,11 +392,25 @@ On Cloudflare Workers, `capabilities.hasSqlDatabase` is `false` and `createDbAda
|
|
|
392
392
|
`D1NotConfiguredError` — the method exists on the interface so consumer code is forward-compatible and
|
|
393
393
|
needs no change when the D1 round ships.
|
|
394
394
|
|
|
395
|
-
**Dependency note:** `@gobing-ai/ts-db` is
|
|
396
|
-
|
|
397
|
-
`
|
|
398
|
-
`
|
|
399
|
-
`
|
|
395
|
+
**Dependency note (optional peer):** `@gobing-ai/ts-db` is declared as an **optional
|
|
396
|
+
`peerDependency`** of `ts-runtime` (ADR-012 addendum), not a regular dependency — a regular entry
|
|
397
|
+
would create a manifest cycle (`ts-db` depends on `ts-runtime`) and force-install `ts-db` (plus its
|
|
398
|
+
`drizzle-orm` peer) on every consumer, including Workers bundles and apps that never touch SQL.
|
|
399
|
+
The factory interface uses a structural `RuntimeDbAdapter` type (defined locally) that a ts-db
|
|
400
|
+
`DbAdapter` satisfies via structural subtyping; `nodeBunFactory.createDbAdapter` loads `ts-db` via a
|
|
401
|
+
literal dynamic `import()` at runtime.
|
|
402
|
+
|
|
403
|
+
**Who must install it:** only consumers that call `nodeBunFactory.createDbAdapter` on Node/Bun —
|
|
404
|
+
install `@gobing-ai/ts-db` yourself (`bun add @gobing-ai/ts-db`). Workers consumers do not need it
|
|
405
|
+
(`capabilities.hasSqlDatabase` is `false`; the method throws `D1NotConfiguredError`).
|
|
406
|
+
|
|
407
|
+
**Bundling (`Bun --compile` / esbuild / Vite):** the literal specifier keeps `ts-db` bundler-visible,
|
|
408
|
+
so `Bun --compile` can fold it into a standalone binary. If you bundle for a different runtime, mark
|
|
409
|
+
`@gobing-ai/ts-db` `external` to preserve the dynamic import.
|
|
410
|
+
|
|
411
|
+
**Failure mode:** if `@gobing-ai/ts-db` is absent or exports no `createDbAdapter` (incompatible
|
|
412
|
+
version), `createDbAdapter` throws a typed `DbModuleNotInstalledError` (with the underlying resolution
|
|
413
|
+
error chained as `cause`) instead of a raw `MODULE_NOT_FOUND`.
|
|
400
414
|
|
|
401
415
|
### 9. Graceful disposal
|
|
402
416
|
|
package/dist/db-errors.d.ts
CHANGED
|
@@ -11,4 +11,17 @@
|
|
|
11
11
|
export declare class D1NotConfiguredError extends Error {
|
|
12
12
|
constructor(message?: string);
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Thrown by {@link RuntimeFactory.createDbAdapter} on `node-bun` when the
|
|
16
|
+
* optional peer `@gobing-ai/ts-db` is not installed.
|
|
17
|
+
*
|
|
18
|
+
* `ts-db` is an **optional peerDependency** of `ts-runtime` (ADR-012 addendum):
|
|
19
|
+
* it cannot be a regular dependency because `ts-db` depends on `ts-runtime`
|
|
20
|
+
* (manifest cycle). Consumers who call `nodeBunFactory.createDbAdapter` must
|
|
21
|
+
* install `@gobing-ai/ts-db` themselves. This error surfaces a missing module
|
|
22
|
+
* as an actionable, typed failure instead of a raw `MODULE_NOT_FOUND`.
|
|
23
|
+
*/
|
|
24
|
+
export declare class DbModuleNotInstalledError extends Error {
|
|
25
|
+
constructor(message?: string, options?: ErrorOptions);
|
|
26
|
+
}
|
|
14
27
|
//# sourceMappingURL=db-errors.d.ts.map
|
package/dist/db-errors.d.ts.map
CHANGED
|
@@ -1 +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"}
|
|
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;AAED;;;;;;;;;GASG;AACH,qBAAa,yBAA0B,SAAQ,KAAK;gBAE5C,OAAO,SAAoO,EAC3O,OAAO,CAAC,EAAE,YAAY;CAK7B"}
|
package/dist/db-errors.js
CHANGED
|
@@ -14,3 +14,19 @@ export class D1NotConfiguredError extends Error {
|
|
|
14
14
|
this.name = 'D1NotConfiguredError';
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Thrown by {@link RuntimeFactory.createDbAdapter} on `node-bun` when the
|
|
19
|
+
* optional peer `@gobing-ai/ts-db` is not installed.
|
|
20
|
+
*
|
|
21
|
+
* `ts-db` is an **optional peerDependency** of `ts-runtime` (ADR-012 addendum):
|
|
22
|
+
* it cannot be a regular dependency because `ts-db` depends on `ts-runtime`
|
|
23
|
+
* (manifest cycle). Consumers who call `nodeBunFactory.createDbAdapter` must
|
|
24
|
+
* install `@gobing-ai/ts-db` themselves. This error surfaces a missing module
|
|
25
|
+
* as an actionable, typed failure instead of a raw `MODULE_NOT_FOUND`.
|
|
26
|
+
*/
|
|
27
|
+
export class DbModuleNotInstalledError extends Error {
|
|
28
|
+
constructor(message = '@gobing-ai/ts-db is not installed. It is an optional peer of @gobing-ai/ts-runtime, required only for createDbAdapter on node-bun. Install it (`bun add @gobing-ai/ts-db`) or, when bundling, mark `@gobing-ai/ts-db` external.', options) {
|
|
29
|
+
super(message, options);
|
|
30
|
+
this.name = 'DbModuleNotInstalledError';
|
|
31
|
+
}
|
|
32
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +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
|
+
export { D1NotConfiguredError, DbModuleNotInstalledError } from './db-errors';
|
|
5
5
|
export type { FileStat, FileSystem } from './file-system';
|
|
6
6
|
export { createCfFileSystem } from './file-system-cf';
|
|
7
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,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,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,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC1E,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AAIxB,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAExG;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,sBAAsB,CAAC,CAAC;AAE3G;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,cAAc,oBAAoB,EAAE,qBAAqB,CAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,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
|
+
export { D1NotConfiguredError, DbModuleNotInstalledError } from './db-errors.js';
|
|
5
5
|
export { createCfFileSystem } from './file-system-cf.js';
|
|
6
6
|
export { createNodeFileSystem, findProjectRoot } from './file-system-node.js';
|
|
7
7
|
export { atomicWriteFile, atomicWriteJson, createLogStream, ensureDirForFile, readJsonFile, walkDir, writeJsonFile, } from './fs.js';
|
package/dist/path.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export declare function isAbsolutePath(path: string): boolean;
|
|
|
8
8
|
export declare function dirnamePath(path: string): string;
|
|
9
9
|
/** Return the last segment of a path. Optionally strip a trailing extension. */
|
|
10
10
|
export declare function basenamePath(p: string, ext?: string): string;
|
|
11
|
+
/** Convert a file:// URL into the portable path format used by this package. */
|
|
12
|
+
export declare function fileUrlToPath(url: string): string;
|
|
11
13
|
/** Compute a platform-independent relative path from `from` to `to`. Both paths should be absolute. */
|
|
12
14
|
export declare function relativePath(from: string, to: string): string;
|
|
13
15
|
/** Joins path segments with `/`, normalizing separators and collapsing redundant slashes. */
|
package/dist/path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAIA,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,oFAAoF;AACpF,eAAO,MAAM,GAAG,EAAE,MACgF,CAAC;AAEnG,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAmBD,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED,uGAAuG;AACvG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAkB7D;AAED,6FAA6F;AAC7F,wBAAgB,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMtD;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAqBzD;AAED,qFAAqF;AACrF,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
|
1
|
+
{"version":3,"file":"path.d.ts","sourceRoot":"","sources":["../src/path.ts"],"names":[],"mappings":"AAIA,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,oFAAoF;AACpF,eAAO,MAAM,GAAG,EAAE,MACgF,CAAC;AAEnG,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAmBD,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,gFAAgF;AAChF,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAED,uGAAuG;AACvG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAkB7D;AAED,6FAA6F;AAC7F,wBAAgB,QAAQ,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAMtD;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAqBzD;AAED,qFAAqF;AACrF,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
package/dist/path.js
CHANGED
|
@@ -54,6 +54,24 @@ export function basenamePath(p, ext) {
|
|
|
54
54
|
}
|
|
55
55
|
return base;
|
|
56
56
|
}
|
|
57
|
+
/** Convert a file:// URL into the portable path format used by this package. */
|
|
58
|
+
export function fileUrlToPath(url) {
|
|
59
|
+
const parsed = new URL(url);
|
|
60
|
+
if (parsed.protocol !== 'file:') {
|
|
61
|
+
throw new Error(`Expected file URL, got "${parsed.protocol}"`);
|
|
62
|
+
}
|
|
63
|
+
// Encoded separators would decode into extra path segments (e.g. "%2F..%2F"
|
|
64
|
+
// becoming "/../"), silently changing path semantics — reject like node:url does.
|
|
65
|
+
if (/%2f|%5c/i.test(parsed.pathname)) {
|
|
66
|
+
throw new Error('File URL path must not include encoded "/" or "\\" characters');
|
|
67
|
+
}
|
|
68
|
+
const pathname = decodeURIComponent(parsed.pathname);
|
|
69
|
+
const localPath = /^\/[A-Za-z]:\//.test(pathname) ? pathname.slice(1) : pathname;
|
|
70
|
+
if (parsed.hostname.length > 0 && parsed.hostname !== 'localhost') {
|
|
71
|
+
return normalizeSeparators(`//${parsed.hostname}${localPath}`);
|
|
72
|
+
}
|
|
73
|
+
return normalizeSeparators(localPath);
|
|
74
|
+
}
|
|
57
75
|
/** Compute a platform-independent relative path from `from` to `to`. Both paths should be absolute. */
|
|
58
76
|
export function relativePath(from, to) {
|
|
59
77
|
const fromParsed = pathParts(resolvePath(from));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-node-bun.d.ts","sourceRoot":"","sources":["../src/runtime-node-bun.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime-node-bun.d.ts","sourceRoot":"","sources":["../src/runtime-node-bun.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAUxD,oEAAoE;AACpE,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,cAwC5B,CAAC"}
|
package/dist/runtime-node-bun.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { parse as parseYaml } from 'yaml';
|
|
2
2
|
import { buildConfigFromObject, getProcessEnv } from './config.js';
|
|
3
|
+
import { DbModuleNotInstalledError } from './db-errors.js';
|
|
3
4
|
import { createNodeFileSystem } from './file-system-node.js';
|
|
4
5
|
import { ProcessExecutor } from './process-executor.js';
|
|
5
6
|
// Lazy re-initialisable singleton for test isolation.
|
|
@@ -30,14 +31,25 @@ export const nodeBunFactory = {
|
|
|
30
31
|
return loadNodeConfig(options);
|
|
31
32
|
},
|
|
32
33
|
async createDbAdapter(config) {
|
|
33
|
-
// Dynamic import via a variable specifier
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
34
|
+
// Dynamic import via a variable specifier — this prevents tsc from
|
|
35
|
+
// statically resolving @gobing-ai/ts-db at build time. ts-db builds
|
|
36
|
+
// AFTER ts-runtime (it depends on ts-runtime), so a literal specifier
|
|
37
|
+
// or `typeof import()` annotation triggers TS2307 in a clean CI
|
|
38
|
+
// checkout where no prebuilt dist/ exists yet. At runtime Bun resolves
|
|
39
|
+
// the module via the workspace symlink.
|
|
40
|
+
// ts-db is an optional peerDependency (ADR-012 addendum) — if the
|
|
41
|
+
// consumer has not installed it, surface a typed error.
|
|
39
42
|
const moduleSpecifier = '@gobing-ai/ts-db';
|
|
40
|
-
|
|
43
|
+
let mod;
|
|
44
|
+
try {
|
|
45
|
+
mod = (await import(moduleSpecifier));
|
|
46
|
+
}
|
|
47
|
+
catch (cause) {
|
|
48
|
+
throw new DbModuleNotInstalledError(undefined, { cause });
|
|
49
|
+
}
|
|
50
|
+
if (typeof mod.createDbAdapter !== 'function') {
|
|
51
|
+
throw new DbModuleNotInstalledError('@gobing-ai/ts-db is installed but does not export createDbAdapter — the installed version may be incompatible or partial.');
|
|
52
|
+
}
|
|
41
53
|
return mod.createDbAdapter({ driver: 'bun-sqlite', url: config.url });
|
|
42
54
|
},
|
|
43
55
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/ts-runtime",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "@gobing-ai/ts-runtime — Runtime abstractions for Bun, Node, and Cloudflare Workers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -58,15 +58,23 @@
|
|
|
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.
|
|
61
|
+
"@gobing-ai/ts-utils": "^0.4.6",
|
|
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.
|
|
67
|
+
"@gobing-ai/ts-db": "^0.4.6",
|
|
68
68
|
"@types/bun": "1.3.14"
|
|
69
69
|
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"@gobing-ai/ts-db": "^0.4.6"
|
|
72
|
+
},
|
|
73
|
+
"peerDependenciesMeta": {
|
|
74
|
+
"@gobing-ai/ts-db": {
|
|
75
|
+
"optional": true
|
|
76
|
+
}
|
|
77
|
+
},
|
|
70
78
|
"publishConfig": {
|
|
71
79
|
"access": "public"
|
|
72
80
|
}
|
package/src/db-errors.ts
CHANGED
|
@@ -14,3 +14,23 @@ export class D1NotConfiguredError extends Error {
|
|
|
14
14
|
this.name = 'D1NotConfiguredError';
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Thrown by {@link RuntimeFactory.createDbAdapter} on `node-bun` when the
|
|
20
|
+
* optional peer `@gobing-ai/ts-db` is not installed.
|
|
21
|
+
*
|
|
22
|
+
* `ts-db` is an **optional peerDependency** of `ts-runtime` (ADR-012 addendum):
|
|
23
|
+
* it cannot be a regular dependency because `ts-db` depends on `ts-runtime`
|
|
24
|
+
* (manifest cycle). Consumers who call `nodeBunFactory.createDbAdapter` must
|
|
25
|
+
* install `@gobing-ai/ts-db` themselves. This error surfaces a missing module
|
|
26
|
+
* as an actionable, typed failure instead of a raw `MODULE_NOT_FOUND`.
|
|
27
|
+
*/
|
|
28
|
+
export class DbModuleNotInstalledError extends Error {
|
|
29
|
+
constructor(
|
|
30
|
+
message = '@gobing-ai/ts-db is not installed. It is an optional peer of @gobing-ai/ts-runtime, required only for createDbAdapter on node-bun. Install it (`bun add @gobing-ai/ts-db`) or, when bundling, mark `@gobing-ai/ts-db` external.',
|
|
31
|
+
options?: ErrorOptions,
|
|
32
|
+
) {
|
|
33
|
+
super(message, options);
|
|
34
|
+
this.name = 'DbModuleNotInstalledError';
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +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
|
+
export { D1NotConfiguredError, DbModuleNotInstalledError } from './db-errors';
|
|
5
5
|
export type { FileStat, FileSystem } from './file-system';
|
|
6
6
|
export { createCfFileSystem } from './file-system-cf';
|
|
7
7
|
export { createNodeFileSystem, findProjectRoot } from './file-system-node';
|
package/src/path.ts
CHANGED
|
@@ -58,6 +58,27 @@ export function basenamePath(p: string, ext?: string): string {
|
|
|
58
58
|
return base;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/** Convert a file:// URL into the portable path format used by this package. */
|
|
62
|
+
export function fileUrlToPath(url: string): string {
|
|
63
|
+
const parsed = new URL(url);
|
|
64
|
+
if (parsed.protocol !== 'file:') {
|
|
65
|
+
throw new Error(`Expected file URL, got "${parsed.protocol}"`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Encoded separators would decode into extra path segments (e.g. "%2F..%2F"
|
|
69
|
+
// becoming "/../"), silently changing path semantics — reject like node:url does.
|
|
70
|
+
if (/%2f|%5c/i.test(parsed.pathname)) {
|
|
71
|
+
throw new Error('File URL path must not include encoded "/" or "\\" characters');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const pathname = decodeURIComponent(parsed.pathname);
|
|
75
|
+
const localPath = /^\/[A-Za-z]:\//.test(pathname) ? pathname.slice(1) : pathname;
|
|
76
|
+
if (parsed.hostname.length > 0 && parsed.hostname !== 'localhost') {
|
|
77
|
+
return normalizeSeparators(`//${parsed.hostname}${localPath}`);
|
|
78
|
+
}
|
|
79
|
+
return normalizeSeparators(localPath);
|
|
80
|
+
}
|
|
81
|
+
|
|
61
82
|
/** Compute a platform-independent relative path from `from` to `to`. Both paths should be absolute. */
|
|
62
83
|
export function relativePath(from: string, to: string): string {
|
|
63
84
|
const fromParsed = pathParts(resolvePath(from));
|
package/src/runtime-node-bun.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parse as parseYaml } from 'yaml';
|
|
2
2
|
import type { Config } from './config';
|
|
3
3
|
import { buildConfigFromObject, getProcessEnv } from './config';
|
|
4
|
+
import { DbModuleNotInstalledError } from './db-errors';
|
|
4
5
|
import type { FileSystem } from './file-system';
|
|
5
6
|
import { createNodeFileSystem } from './file-system-node';
|
|
6
7
|
import { ProcessExecutor, type ProcessExecutorConfig } from './process-executor';
|
|
@@ -40,16 +41,26 @@ export const nodeBunFactory: RuntimeFactory = {
|
|
|
40
41
|
},
|
|
41
42
|
|
|
42
43
|
async createDbAdapter(config: DatabaseConfig): Promise<RuntimeDbAdapter> {
|
|
43
|
-
// Dynamic import via a variable specifier
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
44
|
+
// Dynamic import via a variable specifier — this prevents tsc from
|
|
45
|
+
// statically resolving @gobing-ai/ts-db at build time. ts-db builds
|
|
46
|
+
// AFTER ts-runtime (it depends on ts-runtime), so a literal specifier
|
|
47
|
+
// or `typeof import()` annotation triggers TS2307 in a clean CI
|
|
48
|
+
// checkout where no prebuilt dist/ exists yet. At runtime Bun resolves
|
|
49
|
+
// the module via the workspace symlink.
|
|
50
|
+
// ts-db is an optional peerDependency (ADR-012 addendum) — if the
|
|
51
|
+
// consumer has not installed it, surface a typed error.
|
|
49
52
|
const moduleSpecifier = '@gobing-ai/ts-db';
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
let mod: { createDbAdapter: (config: { driver: 'bun-sqlite'; url?: string }) => RuntimeDbAdapter };
|
|
54
|
+
try {
|
|
55
|
+
mod = (await import(moduleSpecifier)) as typeof mod;
|
|
56
|
+
} catch (cause) {
|
|
57
|
+
throw new DbModuleNotInstalledError(undefined, { cause });
|
|
58
|
+
}
|
|
59
|
+
if (typeof mod.createDbAdapter !== 'function') {
|
|
60
|
+
throw new DbModuleNotInstalledError(
|
|
61
|
+
'@gobing-ai/ts-db is installed but does not export createDbAdapter — the installed version may be incompatible or partial.',
|
|
62
|
+
);
|
|
63
|
+
}
|
|
53
64
|
return mod.createDbAdapter({ driver: 'bun-sqlite', url: config.url });
|
|
54
65
|
},
|
|
55
66
|
};
|