keryx 0.29.0 → 0.29.4
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/initializers/redis.ts +1 -0
- package/package.json +1 -1
- package/testing/index.ts +8 -4
- package/tsconfig.json +1 -1
- package/util/cli.ts +6 -1
- package/util/scaffold.ts +17 -1
package/initializers/redis.ts
CHANGED
package/package.json
CHANGED
package/testing/index.ts
CHANGED
|
@@ -16,16 +16,20 @@ export {
|
|
|
16
16
|
} from "./websocket";
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
|
-
* Generous lifecycle hook timeout (
|
|
19
|
+
* Generous lifecycle hook timeout (60s) for `beforeAll` / `afterAll`.
|
|
20
20
|
*
|
|
21
21
|
* `api.start()` and `api.stop()` connect to Redis, Postgres, run migrations,
|
|
22
|
-
*
|
|
23
|
-
*
|
|
22
|
+
* load plugins, bring up workers, and start servers. That can comfortably
|
|
23
|
+
* exceed 15s on a fresh CI runner with Docker service containers, especially
|
|
24
|
+
* with plugins loaded. If it times out Bun aborts the hook and `api.stop()`
|
|
25
|
+
* runs against partially-initialized state, which cascades into confusing
|
|
26
|
+
* "api.mcp is undefined" style errors during cleanup — always prefer a higher
|
|
27
|
+
* hook timeout over adding null guards to every initializer's `stop()`.
|
|
24
28
|
*
|
|
25
29
|
* Note: `bun:test`'s `setDefaultTimeout` and `bunfig.toml [test].timeout` only
|
|
26
30
|
* apply to `test()` blocks, not lifecycle hooks.
|
|
27
31
|
*/
|
|
28
|
-
export const HOOK_TIMEOUT =
|
|
32
|
+
export const HOOK_TIMEOUT = 60_000;
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
35
|
* Return the actual URL the web server bound to (with resolved port).
|
package/tsconfig.json
CHANGED
package/util/cli.ts
CHANGED
|
@@ -41,6 +41,10 @@ export async function buildProgram(opts: {
|
|
|
41
41
|
.option("--no-interactive", "Skip prompts and use defaults")
|
|
42
42
|
.option("--no-db", "Skip database setup files")
|
|
43
43
|
.option("--no-example", "Skip example action")
|
|
44
|
+
.option(
|
|
45
|
+
"--force",
|
|
46
|
+
"Scaffold into an existing directory (skips files that already exist)",
|
|
47
|
+
)
|
|
44
48
|
.action(async (projectName: string | undefined, cmdOpts) => {
|
|
45
49
|
let options: ScaffoldOptions;
|
|
46
50
|
|
|
@@ -49,11 +53,12 @@ export async function buildProgram(opts: {
|
|
|
49
53
|
options = {
|
|
50
54
|
includeDb: cmdOpts.db !== false,
|
|
51
55
|
includeExample: cmdOpts.example !== false,
|
|
56
|
+
force: cmdOpts.force === true,
|
|
52
57
|
};
|
|
53
58
|
} else {
|
|
54
59
|
const result = await interactiveScaffold(projectName);
|
|
55
60
|
projectName = result.projectName;
|
|
56
|
-
options = result.options;
|
|
61
|
+
options = { ...result.options, force: cmdOpts.force === true };
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
const targetDir = path.resolve(process.cwd(), projectName);
|
package/util/scaffold.ts
CHANGED
|
@@ -9,6 +9,12 @@ import { loadScaffoldTemplate as loadTemplate } from "./componentRegistry";
|
|
|
9
9
|
export interface ScaffoldOptions {
|
|
10
10
|
includeDb: boolean;
|
|
11
11
|
includeExample: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* When true, scaffold into an existing directory instead of refusing.
|
|
14
|
+
* Files that already exist on disk are left untouched (merge-skip); only
|
|
15
|
+
* missing files are created. User files are never overwritten.
|
|
16
|
+
*/
|
|
17
|
+
force?: boolean;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
20
|
async function prompt(question: string, defaultValue: string): Promise<string> {
|
|
@@ -263,9 +269,15 @@ export async function scaffoldProject(
|
|
|
263
269
|
const keryxVersion = pkg.version;
|
|
264
270
|
const createdFiles: string[] = [];
|
|
265
271
|
|
|
266
|
-
|
|
272
|
+
const dirExists = fs.existsSync(targetDir);
|
|
273
|
+
if (dirExists && !options.force) {
|
|
267
274
|
throw new Error(`Directory "${projectName}" already exists`);
|
|
268
275
|
}
|
|
276
|
+
if (dirExists && options.force) {
|
|
277
|
+
console.log(
|
|
278
|
+
` ⚠ scaffolding into existing directory — existing files will be preserved`,
|
|
279
|
+
);
|
|
280
|
+
}
|
|
269
281
|
|
|
270
282
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
271
283
|
|
|
@@ -273,6 +285,10 @@ export async function scaffoldProject(
|
|
|
273
285
|
|
|
274
286
|
const write = async (filePath: string, content: string) => {
|
|
275
287
|
const fullPath = path.join(targetDir, filePath);
|
|
288
|
+
if (options.force && fs.existsSync(fullPath)) {
|
|
289
|
+
console.log(` ⊘ skipped ${filePath}`);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
276
292
|
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
277
293
|
await Bun.write(fullPath, content);
|
|
278
294
|
createdFiles.push(filePath);
|