feat(create-db): Add --ttl, --copy, --quiet, and --open to create-db CLI#78
feat(create-db): Add --ttl, --copy, --quiet, and --open to create-db CLI#78aidankmcalister merged 8 commits intomainfrom
--ttl, --copy, --quiet, and --open to create-db CLI#78Conversation
validation and cleaner help
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
claim-db-worker | f3143b8 | Commit Preview URL Branch Preview URL |
Feb 26 2026, 03:37 PM |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThreads TTL from CLI and programmatic entrypoints through core services into the background worker: adds TTL parsing/validation/utilities, new CLI flags (--ttl, --copy, --quiet, --open), clipboard/open helpers, tests and docs, and uses TTL to compute the worker delay before issuing DELETE. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
create-db/README.md (1)
263-263:⚠️ Potential issue | 🟡 MinorLine 263 no longer accurately reflects TTL behavior
With
--ttl, the deletion window is now 30 minutes to 24 hours, not always 24 hours.📝 Suggested fix
-When you create a database, it is temporary and will be deleted after **24 hours**. +When you create a database, it is temporary and will be deleted after **24 hours** by default (configurable with `--ttl`).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/README.md` at line 263, Update the README sentence that claims "When you create a database, it is temporary and will be deleted after **24 hours**." to reflect the new TTL behavior by stating that with the --ttl flag the deletion window ranges from 30 minutes to 24 hours (default 24 hours if --ttl not provided); locate the exact line containing that sentence in create-db/README.md and replace it with a concise note that mentions the optional --ttl flag and the 30 minutes–24 hours deletion window.
🧹 Nitpick comments (7)
create-db/__tests__/ttl.test.ts (1)
12-15: Case-insensitivity test only covers the hour suffix —"30M"is untestedThe
parseTtlToSecondsimplementation normalizes via.toLowerCase(), so"30M"should return1800. Consider adding that case, and a whitespace-trimming case (e.g." 1h ") to fully exercise the normalization logic.♻️ Suggested additions
it("is case-insensitive", () => { expect(parseTtlToSeconds("2H")).toBe(7200); expect(parseTtlToSeconds("24H")).toBe(86400); + expect(parseTtlToSeconds("30M")).toBe(1800); + }); + + it("trims whitespace", () => { + expect(parseTtlToSeconds(" 1h ")).toBe(3600); + expect(parseTtlToSeconds(" 30m ")).toBe(1800); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/__tests__/ttl.test.ts` around lines 12 - 15, The test only verifies case-insensitivity for hour suffixes; add assertions to cover minute suffixes and trimming behavior so parseTtlToSeconds normalization is fully exercised: update the test in create-db/__tests__/ttl.test.ts to include expectations like parseTtlToSeconds("30M") returning 1800 and parseTtlToSeconds(" 1h ") returning 3600 (or similar trimmed input), referencing the parseTtlToSeconds function to ensure both .toLowerCase() and whitespace trimming logic are validated.create-db/src/utils/ttl.ts (1)
1-5: Consider freezingTTL_TO_SECONDSafter construction
TTL_TO_SECONDSis module-level and nothing should mutate it after initialization. Freezing makes that intent explicit and prevents accidental future modifications.♻️ Suggested change
-const TTL_TO_SECONDS: Record<string, number> = { "30m": 30 * 60 }; +const TTL_TO_SECONDS: Readonly<Record<string, number>> = Object.freeze( + (() => { + const m: Record<string, number> = { "30m": 30 * 60 }; + for (let hour = 1; hour <= 24; hour += 1) { + m[`${hour}h`] = hour * 60 * 60; + } + return m; + })() +);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/src/utils/ttl.ts` around lines 1 - 5, TTL_TO_SECONDS is a module-level mutable object that should be immutable; after building it (the constant TTL_TO_SECONDS), freeze it to prevent future mutation (e.g., use Object.freeze) and, if desired, tighten its TypeScript type to Readonly<Record<string, number>> to reflect immutability; ensure the freeze call is applied after the loop that populates TTL_TO_SECONDS so the map remains unmodifiable thereafter.create-db/src/cli/output.ts (2)
103-131:writeEnvFilereturn type is a duplicate of the newOperationResultaliasThe inline
{ success: true } | { success: false; error: string }on line 107 is structurally identical toOperationResultintroduced on line 9. Using the alias keeps the API surface consistent.♻️ Suggested change
export function writeEnvFile( envPath: string, connectionString: string | null, claimUrl: string -): { success: true } | { success: false; error: string } { +): OperationResult {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/src/cli/output.ts` around lines 103 - 131, The writeEnvFile function currently declares its return type inline ({ success: true } | { success: false; error: string })—replace that union with the existing OperationResult type alias so the signature becomes writeEnvFile(...): OperationResult; update any references to OperationResult if needed and ensure the function still returns the same shape ({ success: true } or { success: false, error }) to maintain behavior; locate the declaration by the function name writeEnvFile and the OperationResult type alias introduced near the top of the file.
151-167:spawnSynccalls have no timeout — CLI can hang indefinitelyIf a clipboard command is installed but stalls (e.g. a broken Wayland socket for
wl-copy),spawnSyncwill block the process forever. Adding atimeoutoption caps the worst case.♻️ Suggested change
const result = spawnSync(command, args, { input: text, encoding: "utf8", stdio: ["pipe", "ignore", "pipe"], + timeout: 3000, });The same applies to the
spawnSynccall insideopenUrlInBrowserat line 187.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/src/cli/output.ts` around lines 151 - 167, The spawnSync calls can block indefinitely; update both occurrences (the spawnSync inside the for loop iterating over commands and the spawnSync call in openUrlInBrowser) to include a timeout option (e.g. timeout: 5000) and a kill signal (e.g. killSignal: "SIGTERM") so stalled clipboard/browser helper processes are terminated; keep the existing stdio/encoding options and ensure error handling still collects result.error and result.stderr after the call.create-db/src/cli.ts (1)
36-39:as nevercast oncli.runis fragileIf
trpc-clichanges the overload signature ofrun(), this cast will silence compile-time errors. Consider using a typed intermediate variable oras Parameters<typeof cli.run>[1]if the type is accessible.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/src/cli.ts` around lines 36 - 39, The code silences type-safety by casting program to `never` when calling `cli.run`; instead remove the unsafe `as never` and pass a properly typed second argument by creating a typed intermediate (e.g., declare `const runArg: Parameters<typeof cli.run>[1] = program` or assert `program` to the expected `CommandLike`/parameter type) and then call `cli.run(undefined, runArg)`—locate `createDbCli()`, `cli`, `program`, `simplifyHelpFlags` and replace the `void cli.run(undefined, program as never);` call with a call that uses the typed intermediate or `as Parameters<typeof cli.run>[1]` to preserve compile-time checks.create-db-worker/src/index.ts (1)
148-155:!parsedTtlSecondsobscures intent — prefer explicit=== undefinedcheck.
!parsedTtlSecondsis truthy for bothundefined(non-finite input) and0(floored sub-second value), which is correct but non-obvious. The<= 0guard already handles zero and negative integers whenparsedTtlSecondsis defined.♻️ Suggested clarification
-if (ttlSeconds !== undefined && (!parsedTtlSeconds || parsedTtlSeconds <= 0)) { +if (ttlSeconds !== undefined && (parsedTtlSeconds === undefined || parsedTtlSeconds <= 0)) {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db-worker/src/index.ts` around lines 148 - 155, The check using "!parsedTtlSeconds" in the validation branch obscures intent and incorrectly collapses undefined and zero; update the condition that currently reads "if (ttlSeconds !== undefined && (!parsedTtlSeconds || parsedTtlSeconds <= 0))" to explicitly test for undefined (e.g., "parsedTtlSeconds === undefined") so the logic becomes: when ttlSeconds is provided and parsedTtlSeconds is undefined (non-finite input) or parsedTtlSeconds <= 0, return the 400 response; change references to parsedTtlSeconds and ttlSeconds in this block to use the explicit undefined check.create-db/src/core/database.ts (1)
24-34: Duplicate TTL validation — extract once.The same three-part guard (
typeof … && isFinite … && > 0) is evaluated at lines 32 and 144. Extracting it to a single variable eliminates the duplication and makes thepayload.ttlSecondsassignment andttlSecondsToUseselection read from the same value.♻️ Proposed refactor
+ const parsedTtlSeconds = + typeof ttlSeconds === "number" && Number.isFinite(ttlSeconds) && ttlSeconds > 0 + ? Math.floor(ttlSeconds) + : undefined; + const payload: Record<string, unknown> = { region, name, utm_source: getCommandName(), userAgent, source: source || "cli", }; - if (typeof ttlSeconds === "number" && Number.isFinite(ttlSeconds) && ttlSeconds > 0) { - payload.ttlSeconds = Math.floor(ttlSeconds); - } + if (parsedTtlSeconds !== undefined) { + payload.ttlSeconds = parsedTtlSeconds; + }Then later:
- const ttlSecondsToUse = - typeof ttlSeconds === "number" && Number.isFinite(ttlSeconds) && ttlSeconds > 0 - ? Math.floor(ttlSeconds) - : 24 * 60 * 60; + const ttlSecondsToUse = parsedTtlSeconds ?? 24 * 60 * 60;Also applies to: 143-147
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db/src/core/database.ts` around lines 24 - 34, The TTL validation logic is duplicated; extract the three-part guard into a single boolean (e.g., isValidTtl) computed from ttlSeconds and also compute a normalized value (e.g., normalizedTtl = Math.floor(ttlSeconds)) once, then use isValidTtl to conditionally set payload.ttlSeconds = normalizedTtl and to choose the ttlSecondsToUse later; update references in the payload construction and wherever ttlSecondsToUse is selected (use symbols ttlSeconds, payload, ttlSecondsToUse) so both places read the same validated/normalized value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@create-db-worker/src/delete-workflow.ts`:
- Around line 20-23: The current computation for effectiveTtlSeconds only
validates positivity and should instead clamp ttlSeconds into the allowed range
used by the CLI; update the effectiveTtlSeconds calculation to use the same
bounds as parseTtlToSeconds (min 1800, max 86400), e.g. convert ttlSeconds to a
finite integer via Math.floor and then clamp it with Math.max(1800,
Math.min(86400, value)); ensure you still default to 86400 when ttlSeconds is
missing/invalid, and reference the ttlSeconds input and effectiveTtlSeconds
symbol when making the change so callers invoking the worker directly cannot
pass out-of-range values.
In `@create-db/src/cli/commands/create.ts`:
- Around line 211-221: Currently the --quiet flow prints the connection string
only after applyCopyFlag/applyOpenFlag, but those helpers (applyCopyFlag,
applyOpenFlag) may call process.exit(1) and prevent output; move or duplicate
the quiet-output so result.connectionString is written to stdout
(console.log(result.connectionString ?? "")) before invoking applyCopyFlag and
applyOpenFlag (or ensure printDatabaseResult is invoked first) so that the
connection string is always emitted even if the helpers fail/exit; keep the
existing quiet-only behavior and call the side-effect helpers afterwards.
---
Outside diff comments:
In `@create-db/README.md`:
- Line 263: Update the README sentence that claims "When you create a database,
it is temporary and will be deleted after **24 hours**." to reflect the new TTL
behavior by stating that with the --ttl flag the deletion window ranges from 30
minutes to 24 hours (default 24 hours if --ttl not provided); locate the exact
line containing that sentence in create-db/README.md and replace it with a
concise note that mentions the optional --ttl flag and the 30 minutes–24 hours
deletion window.
---
Nitpick comments:
In `@create-db-worker/src/index.ts`:
- Around line 148-155: The check using "!parsedTtlSeconds" in the validation
branch obscures intent and incorrectly collapses undefined and zero; update the
condition that currently reads "if (ttlSeconds !== undefined &&
(!parsedTtlSeconds || parsedTtlSeconds <= 0))" to explicitly test for undefined
(e.g., "parsedTtlSeconds === undefined") so the logic becomes: when ttlSeconds
is provided and parsedTtlSeconds is undefined (non-finite input) or
parsedTtlSeconds <= 0, return the 400 response; change references to
parsedTtlSeconds and ttlSeconds in this block to use the explicit undefined
check.
In `@create-db/__tests__/ttl.test.ts`:
- Around line 12-15: The test only verifies case-insensitivity for hour
suffixes; add assertions to cover minute suffixes and trimming behavior so
parseTtlToSeconds normalization is fully exercised: update the test in
create-db/__tests__/ttl.test.ts to include expectations like
parseTtlToSeconds("30M") returning 1800 and parseTtlToSeconds(" 1h ") returning
3600 (or similar trimmed input), referencing the parseTtlToSeconds function to
ensure both .toLowerCase() and whitespace trimming logic are validated.
In `@create-db/src/cli.ts`:
- Around line 36-39: The code silences type-safety by casting program to `never`
when calling `cli.run`; instead remove the unsafe `as never` and pass a properly
typed second argument by creating a typed intermediate (e.g., declare `const
runArg: Parameters<typeof cli.run>[1] = program` or assert `program` to the
expected `CommandLike`/parameter type) and then call `cli.run(undefined,
runArg)`—locate `createDbCli()`, `cli`, `program`, `simplifyHelpFlags` and
replace the `void cli.run(undefined, program as never);` call with a call that
uses the typed intermediate or `as Parameters<typeof cli.run>[1]` to preserve
compile-time checks.
In `@create-db/src/cli/output.ts`:
- Around line 103-131: The writeEnvFile function currently declares its return
type inline ({ success: true } | { success: false; error: string })—replace that
union with the existing OperationResult type alias so the signature becomes
writeEnvFile(...): OperationResult; update any references to OperationResult if
needed and ensure the function still returns the same shape ({ success: true }
or { success: false, error }) to maintain behavior; locate the declaration by
the function name writeEnvFile and the OperationResult type alias introduced
near the top of the file.
- Around line 151-167: The spawnSync calls can block indefinitely; update both
occurrences (the spawnSync inside the for loop iterating over commands and the
spawnSync call in openUrlInBrowser) to include a timeout option (e.g. timeout:
5000) and a kill signal (e.g. killSignal: "SIGTERM") so stalled
clipboard/browser helper processes are terminated; keep the existing
stdio/encoding options and ensure error handling still collects result.error and
result.stderr after the call.
In `@create-db/src/core/database.ts`:
- Around line 24-34: The TTL validation logic is duplicated; extract the
three-part guard into a single boolean (e.g., isValidTtl) computed from
ttlSeconds and also compute a normalized value (e.g., normalizedTtl =
Math.floor(ttlSeconds)) once, then use isValidTtl to conditionally set
payload.ttlSeconds = normalizedTtl and to choose the ttlSecondsToUse later;
update references in the payload construction and wherever ttlSecondsToUse is
selected (use symbols ttlSeconds, payload, ttlSecondsToUse) so both places read
the same validated/normalized value.
In `@create-db/src/utils/ttl.ts`:
- Around line 1-5: TTL_TO_SECONDS is a module-level mutable object that should
be immutable; after building it (the constant TTL_TO_SECONDS), freeze it to
prevent future mutation (e.g., use Object.freeze) and, if desired, tighten its
TypeScript type to Readonly<Record<string, number>> to reflect immutability;
ensure the freeze call is applied after the loop that populates TTL_TO_SECONDS
so the map remains unmodifiable thereafter.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
create-db-worker/src/delete-workflow.tscreate-db-worker/src/index.tscreate-db/README.mdcreate-db/__tests__/cli.test.tscreate-db/__tests__/flags.test.tscreate-db/__tests__/ttl.test.tscreate-db/package.jsoncreate-db/src/cli.tscreate-db/src/cli/commands/create.tscreate-db/src/cli/flags.tscreate-db/src/cli/output.tscreate-db/src/core/database.tscreate-db/src/core/services.tscreate-db/src/utils/ttl.ts
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
There was a problem hiding this comment.
♻️ Duplicate comments (1)
create-db-worker/src/delete-workflow.ts (1)
23-26:⚠️ Potential issue | 🟡 MinorTreat non‑positive
ttlSecondsas invalid before clamping.Right now
ttlSeconds <= 0gets clamped to the minimum (30m), which can shorten TTL unexpectedly for bad inputs. Consider only clamping when the value is positive; otherwise default to max.🛠️ Suggested tweak
- const effectiveTtlSeconds = - typeof ttlSeconds === 'number' && Number.isFinite(ttlSeconds) - ? Math.max(MIN_TTL_SECONDS, Math.min(MAX_TTL_SECONDS, Math.floor(ttlSeconds))) - : MAX_TTL_SECONDS; + const effectiveTtlSeconds = + typeof ttlSeconds === 'number' && Number.isFinite(ttlSeconds) && ttlSeconds > 0 + ? Math.max(MIN_TTL_SECONDS, Math.min(MAX_TTL_SECONDS, Math.floor(ttlSeconds))) + : MAX_TTL_SECONDS;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@create-db-worker/src/delete-workflow.ts` around lines 23 - 26, The current computation of effectiveTtlSeconds clamps any numeric ttlSeconds (including <=0) into the valid range which treats non‑positive values as MIN_TTL_SECONDS; update the logic in the effectiveTtlSeconds calculation so you only apply clamping when ttlSeconds is a positive finite number (e.g., typeof ttlSeconds === 'number' && Number.isFinite(ttlSeconds) && ttlSeconds > 0), otherwise fall back to MAX_TTL_SECONDS; reference the existing symbols effectiveTtlSeconds, ttlSeconds, MIN_TTL_SECONDS, MAX_TTL_SECONDS and preserve the floor/clamping behavior only for positive inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@create-db-worker/src/delete-workflow.ts`:
- Around line 23-26: The current computation of effectiveTtlSeconds clamps any
numeric ttlSeconds (including <=0) into the valid range which treats
non‑positive values as MIN_TTL_SECONDS; update the logic in the
effectiveTtlSeconds calculation so you only apply clamping when ttlSeconds is a
positive finite number (e.g., typeof ttlSeconds === 'number' &&
Number.isFinite(ttlSeconds) && ttlSeconds > 0), otherwise fall back to
MAX_TTL_SECONDS; reference the existing symbols effectiveTtlSeconds, ttlSeconds,
MIN_TTL_SECONDS, MAX_TTL_SECONDS and preserve the floor/clamping behavior only
for positive inputs.
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@create-db-worker/src/index.ts`:
- Around line 147-152: When a client supplies ttlMs, the code currently lets
parseTtlMsInput return undefined and silently uses the default; change the
validation so that if ttlMs is present (ttlMs !== undefined) and
parseTtlMsInput(ttlMs) returns undefined you return a 400 response indicating
invalid ttlMs, otherwise continue with the existing isTtlMsInRange(parsedTtlMs)
check; update the logic around parsedTtlMs, ttlMs, parseTtlMsInput and
isTtlMsInRange to first detect a supplied-but-non-numeric TTL and reject it
before the range validation.
In `@create-db-worker/src/ttl.ts`:
- Around line 16-21: The clampTtlMs function currently only checks typeof value
=== 'number', which allows NaN/Infinity through and can return NaN; update the
guard in clampTtlMs to treat non-finite values as invalid by using
Number.isFinite(value) (or equivalent) so that NaN/Infinity fall back to
MAX_TTL_MS, then keep the existing clamp logic using MIN_TTL_MS and MAX_TTL_MS
to bound valid numeric inputs.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
create-db-worker/src/delete-workflow.tscreate-db-worker/src/index.tscreate-db-worker/src/ttl.tscreate-db/README.mdcreate-db/__tests__/flags.test.tscreate-db/__tests__/ttl.test.tscreate-db/src/cli/commands/create.tscreate-db/src/cli/flags.tscreate-db/src/core/database.tscreate-db/src/core/services.tscreate-db/src/index.tscreate-db/src/types.tscreate-db/src/utils/ttl.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- create-db/src/core/services.ts
- create-db/src/cli/flags.ts
- create-db/tests/flags.test.ts
- create-db/README.md
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
|
✅ Preview CLIs & Workers are live! Test the CLIs locally under tag npx create-db@pr78
npx create-pg@pr78
npx create-postgres@pr78Worker URLs
|
Summary
This PR adds four new CLI flags to improve day-to-day
create-dbusage.New features
--ttlto set custom auto-delete time--copyto copy the connection string to clipboard--quietto print only the connection string--opento open the claim URL in the browserTTL behavior
30m1hthrough24httlSecondsand schedules deletion based on that value.Help output
--ttl [duration]with short explanatory text.Tests/verification
pnpm --filter create-db buildpnpm --filter create-db exec vitest run __tests__/flags.test.ts __tests__/ttl.test.ts __tests__/cli.test.tspnpm --filter create-db-worker exec tsc --noEmitSummary by CodeRabbit
New Features
Documentation
Tests
Chores