Skip to content

Conversation

@AmanVarshney01
Copy link

@AmanVarshney01 AmanVarshney01 commented Dec 2, 2025

Summary by CodeRabbit

  • New Features

    • Added comprehensive TypeScript support with type definitions for enhanced type safety.
  • Refactor

    • Rewrote core implementation using modern TypeScript and ESM standards.
    • Modernized build system with improved tooling and configuration.
    • Enhanced test infrastructure with expanded test coverage and improved CI/CD workflows.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 2, 2025

Walkthrough

The create-db package is refactored from a monolithic JavaScript CLI entry point to a modularized TypeScript architecture. The original index.js is removed and replaced with src/index.ts (comprehensive CLI and programmatic API), src/cli.ts (CLI entrypoint), and src/types.ts (type definitions). Build tooling (tsdown, TypeScript), test files migrated to TypeScript, package.json restructured with ESM exports and dist-based entry points, and GitHub workflows updated.

Changes

Cohort / File(s) Summary
TypeScript Source Files
create-db/src/index.ts, create-db/src/cli.ts, create-db/src/types.ts
Added comprehensive TypeScript implementation: index.ts provides TRPC-based CLI router with create/regions commands, location detection, region validation, and analytics; cli.ts serves as minimal entry point; types.ts defines Region, CreateDatabaseResult, type guards, API schemas, and validation utilities.
Build & Configuration
create-db/tsconfig.json, create-db/tsdown.config.ts, create-db/vitest.config.ts, create-db/package.json
Added TypeScript compiler config (ES2022, strict, bundler resolution), tsdown build config with entry points and ESM output, Vitest test runner config for .ts tests; updated package.json to add type: module, exports map, bin entries pointing to dist/cli.mjs, build/dev/typecheck scripts, and shifted dependencies.
Test Suite Migration
create-db/__tests__/create.test.js.ts, create-db/__tests__/regions.test.js.ts, create-db/__tests__/utils.test.js.ts, create-db/__tests__/utils.test.ts (new)
Removed old .js tests; added TypeScript equivalents with updated assertions: create.test.ts validates CLI binary (dist/cli.mjs) with default/json/regions modes; regions.test.ts validates regions() API and RegionSchema; new utils.test.ts tests isDatabaseError/isDatabaseSuccess type guards.
Deleted Files
create-db/index.js
Removed entire monolithic CLI module containing database creation workflow, analytics, region management, and command-line parsing logic.
GitHub Workflows
.github/workflows/tests.yml, .github/workflows/release.yml
Updated tests.yml to add Build create-db step and environment variables (CREATE_DB_WORKER_URL, CLAIM_DB_WORKER_URL); significantly restructured release.yml to support push/pull_request/workflow_dispatch triggers, multi-mode releases, preview PR jobs, and improved permissions/secrets handling.
Workflow Removal
.github/workflows/preview.yml
Deleted preview workflow that provisioned and published preview CLI versions per PR (functionality now consolidated into release.yml).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • create-db/src/index.ts: High logic density with CLI router, analytics batching, location detection, region validation, database creation workflow, and multiple output modes; requires careful verification of API integration and error handling paths.
  • create-db/package.json: Significant structural changes to exports, bin entries, build scripts, and dependency rewiring; verify ESM module resolution and dist artifact alignment with new entry points.
  • .github/workflows/release.yml: Substantial rewrite with new job structure, environment secrets integration, and multi-mode release/preview paths; cross-check trigger conditions and permission scope.
  • Test file rewrites: Verify CLI invocation assertions match new dist/cli.mjs behavior and that type guard tests cover all discriminator cases.

Possibly related PRs

  • DC-6214 Feat: Accelerate removed #65: Modifies the CLI output field from directConnectionString to connectionString, which is reflected in the new CreateDatabaseResult type and index.ts implementation.
  • DC-4635 Add Tests #58: Updates tests and exports for CLI helpers (getRegionClosestToLocation, getCommandName), which are re-implemented in the new src/index.ts.
  • pnpm fix #62: Adjusts CLI analytics control-flow and adds cliRunId propagation, which relates to the new analytics batching and flushing logic in src/index.ts.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add programmatic api' directly and clearly reflects the main change: introducing a programmatic API (create, regions functions) alongside converting the CLI from JavaScript to TypeScript with a new build system.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 2, 2025

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
claim-db-worker 3dbbffd Commit Preview URL

Branch Preview URL
Dec 03 2025, 07:05 PM

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (7)
create-db/tsconfig.json (1)

1-15: Minor formatting inconsistency: mixed tabs and spaces.

Lines 3-12 use tabs for indentation while lines 13-14 use spaces. Consider normalizing to consistent indentation throughout.

 {
   "compilerOptions": {
-		"target": "ES2022",
-		"module": "ESNext",
-		"moduleResolution": "bundler",
-		"esModuleInterop": true,
-		"verbatimModuleSyntax": true,
-		"strict": true,
-		"skipLibCheck": true,
-		"outDir": "dist",
-		"types": ["node"]
-	},
+    "target": "ES2022",
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "esModuleInterop": true,
+    "verbatimModuleSyntax": true,
+    "strict": true,
+    "skipLibCheck": true,
+    "outDir": "dist",
+    "types": ["node"]
+  },
   "include": ["src/**/*"],
   "exclude": ["node_modules", "dist", "__tests__"]
 }
create-db/tsdown.config.ts (1)

10-12: Apply shebang banner only to the CLI entry.

The outputOptions.banner currently applies the shebang (#!/usr/bin/env node) to all entry outputs, including dist/index.mjs. While Node.js strips the shebang before parsing, it should be applied only to executable CLI files per best practices. Some toolchain components may also struggle with shebangs in library modules.

Use outputOptions as a function to conditionally apply the banner only when building cli.ts:

outputOptions: (output) => {
  if (output.fileName?.includes('cli')) {
    output.banner = "#!/usr/bin/env node";
  }
  return output;
}
create-db/__tests__/regions.test.ts (1)

4-21: Tests rely on external API without mocking.

These tests make real network requests to the regions API. While this validates end-to-end behavior, it makes tests flaky if the API is unavailable. Consider adding unit tests with mocked fetch for deterministic testing, keeping these as integration tests.

create-db/src/index.ts (4)

229-238: No timeout on database creation fetch request.

Unlike analytics (5s timeout), the createDatabaseCore fetch has no timeout. A slow/hanging API response could block indefinitely.

+    const controller = new AbortController();
+    const timeoutId = setTimeout(() => controller.abort(), 30000);
+
     const resp = await fetch(`${CREATE_DB_WORKER_URL}/create`, {
         method: "POST",
         headers: { "Content-Type": "application/json" },
         body: JSON.stringify({
             region,
             name,
             utm_source: getCommandName(),
             userAgent,
         }),
+        signal: controller.signal,
     });
+
+    clearTimeout(timeoutId);

54-83: pendingAnalytics array grows unbounded.

Promises are pushed to pendingAnalytics but never removed after flushAnalytics(). In a long-running process using the programmatic API, this could cause a memory leak.

 async function flushAnalytics(maxWaitMs = 500): Promise<void> {
     if (pendingAnalytics.length === 0) return;
     await Promise.race([
         Promise.all(pendingAnalytics),
         new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),
     ]);
+    pendingAnalytics.length = 0;
 }

575-579: Programmatic create() doesn't validate region.

Unlike the CLI handler which calls validateRegion(), the programmatic API accepts any RegionId without checking if that region is currently available.

Consider validating against available regions or documenting that the region must be valid:

 export async function create(
     options?: ProgrammaticCreateOptions
 ): Promise<CreateDatabaseResult> {
+    if (options?.region) {
+        await validateRegion(options.region);
+    }
     return createDatabaseCore(options?.region || "us-east-1", options?.userAgent);
 }

549-556: Hardcoded version string.

Consider reading version from package.json to avoid version drift.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 082dd39 and 6824f9f.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • create-db/__tests__/create.test.js (0 hunks)
  • create-db/__tests__/create.test.ts (1 hunks)
  • create-db/__tests__/regions.test.js (0 hunks)
  • create-db/__tests__/regions.test.ts (1 hunks)
  • create-db/__tests__/utils.test.js (0 hunks)
  • create-db/__tests__/utils.test.ts (1 hunks)
  • create-db/index.js (0 hunks)
  • create-db/package.json (2 hunks)
  • create-db/src/cli.ts (1 hunks)
  • create-db/src/index.ts (1 hunks)
  • create-db/src/types.ts (1 hunks)
  • create-db/tsconfig.json (1 hunks)
  • create-db/tsdown.config.ts (1 hunks)
  • create-db/vitest.config.ts (1 hunks)
💤 Files with no reviewable changes (4)
  • create-db/tests/utils.test.js
  • create-db/tests/regions.test.js
  • create-db/tests/create.test.js
  • create-db/index.js
🧰 Additional context used
🧬 Code graph analysis (4)
create-db/src/cli.ts (1)
create-db/src/index.ts (1)
  • createDbCli (549-556)
create-db/__tests__/utils.test.ts (1)
create-db/src/types.ts (3)
  • CreateDatabaseResult (59-59)
  • isDatabaseError (61-65)
  • isDatabaseSuccess (67-71)
create-db/__tests__/regions.test.ts (2)
create-db/src/index.ts (2)
  • regions (592-594)
  • RegionSchema (34-34)
create-db/src/types.ts (1)
  • RegionSchema (3-10)
create-db/src/index.ts (1)
create-db/src/types.ts (10)
  • RegionId (12-12)
  • RegionCoordinates (28-31)
  • UserLocation (14-21)
  • GeoLocationResponse (111-118)
  • Region (33-37)
  • RegionsResponse (124-124)
  • CreateDatabaseResult (59-59)
  • ApiResponse (99-104)
  • RegionSchema (3-10)
  • ProgrammaticCreateOptions (126-129)
🪛 GitHub Actions: Tests
create-db/__tests__/create.test.ts

[error] 24-24: AssertionError: expected '' to contain 'Database created successfully!'


[error] 29-29: SyntaxError: Unexpected end of JSON input


[error] 37-37: AssertionError: expected '' to contain 'Available Prisma Postgres regions'

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: create-db-worker
  • GitHub Check: Workers Builds: claim-db-worker
🔇 Additional comments (9)
create-db/src/cli.ts (1)

1-3: LGTM!

Clean CLI entrypoint that correctly delegates to the createDbCli() API. The .js extension in the import is appropriate for ESM TypeScript with moduleResolution: "bundler".

create-db/vitest.config.ts (1)

1-7: LGTM!

Clean Vitest configuration that correctly targets the TypeScript test files under __tests__/.

create-db/package.json (2)

5-17: Well-structured ESM package exports.

The exports map correctly defines both the library entry point (.) with types and the CLI entry (./cli). The setup properly supports modern ESM consumption patterns.


35-48: Build and publish workflow looks solid.

Good use of prepublishOnly to ensure the package is built before publishing. The bin entries correctly point to the built CLI artifact.

create-db/__tests__/regions.test.ts (1)

23-35: LGTM!

Good coverage of RegionSchema validation including valid region IDs, invalid strings, empty strings, and type coercion rejection.

create-db/__tests__/utils.test.ts (1)

8-35: LGTM!

Type guard tests correctly verify both positive and negative cases with representative payloads matching the DatabaseResult and DatabaseError interfaces.

create-db/src/types.ts (3)

1-12: LGTM!

Clean Zod schema definition with proper type inference for RegionId.


39-71: LGTM!

Well-designed discriminated union with success as the discriminator and correctly implemented type guards.


23-26: Remove unused PartialUserLocation interface.

This interface is defined but has no usages in the codebase. Consider removing it to keep the types clean.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
create-db/src/index.ts (3)

416-420: Use isCancel() instead of === null for cancellation check.

As flagged in past reviews, @clack/prompts' select() returns a cancel symbol when cancelled, not null. You must use the isCancel() helper to properly detect cancellation.

Apply this diff to fix the cancellation check:

-                if (selectedRegion === null) {
+                if (isCancel(selectedRegion)) {
                     cancel(pc.red("Operation cancelled."));
                     await flushAnalytics();
                     process.exit(0);
                 }

446-453: Add return after --env output to prevent fall-through.

As flagged in past reviews, after outputting the DATABASE_URL format (lines 451-452), the code falls through to line 455 which shows the interactive intro. The function must return after the --env output.

Apply this diff to add the missing return:

                 console.log(`DATABASE_URL="${result.connectionString}"`);
                 console.error(`\n# Claim your database at: ${result.claimUrl}`);
+                return;
             }

469-473: Use isCancel() instead of === null for cancellation check.

Same issue as line 416 - @clack/prompts' select() returns a cancel symbol, not null. Use the isCancel() helper.

Apply this diff to fix the cancellation check:

-                if (selectedRegion === null) {
+                if (isCancel(selectedRegion)) {
                     cancel(pc.red("Operation cancelled."));
                     await flushAnalytics();
                     process.exit(0);
                 }
🧹 Nitpick comments (1)
create-db/src/index.ts (1)

573-577: Consider validating region in programmatic API.

The create() function doesn't validate the region before calling createDatabaseCore(). While the API will reject invalid regions, validating upfront would provide better error messages and avoid unnecessary network calls.

Apply this diff to add region validation:

 export async function create(
     options?: ProgrammaticCreateOptions
 ): Promise<CreateDatabaseResult> {
+    if (options?.region) {
+        await validateRegion(options.region);
+    }
     return createDatabaseCore(options?.region || "us-east-1", options?.userAgent);
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6824f9f and 209691d.

📒 Files selected for processing (3)
  • .github/workflows/tests.yml (1 hunks)
  • create-db/__tests__/create.test.ts (1 hunks)
  • create-db/src/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • create-db/tests/create.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: create-db-worker
  • GitHub Check: Workers Builds: claim-db-worker
🔇 Additional comments (2)
.github/workflows/tests.yml (2)

44-46: Build step correctly positioned before test execution.

The new build step is properly placed in the workflow sequence and necessary for the TypeScript-to-ESM compilation required by this PR.


53-54: These environment variables have fallback defaults and are already documented.

The code in create-db/src/index.ts defines default values for both CREATE_DB_WORKER_URL and CLAIM_DB_WORKER_URL:

  • CREATE_DB_WORKER_URL defaults to "https://create-db-temp.prisma.io"
  • CLAIM_DB_WORKER_URL defaults to "https://create-db.prisma.io"

If the GitHub Actions secrets are not configured, these variables will use the hardcoded defaults rather than being empty strings. The README.md already documents these environment variables and their purpose, including example values for local development. The workflow implementation is correct—the secrets allow overriding the defaults for CI if needed, but the tests will run successfully with the default endpoints if secrets are unconfigured.

Likely an incorrect or invalid review comment.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
create-db/src/index.ts (1)

404-453: Add return after --env output to avoid falling through into interactive mode

When input.env is true (and input.json is false), the handler prints DATABASE_URL and the claim URL but then falls through out of the if (input.json || input.env) block into the interactive flow below. That can cause a second database to be created and an unexpected prompt even though the user requested non‑interactive .env output.

Add a return after the console.error to terminate the handler in --env mode:

             if (!result.success) {
                 console.error(result.message);
                 process.exit(1);
             }

             console.log(`DATABASE_URL="${result.connectionString}"`);
             console.error(`\n# Claim your database at: ${result.claimUrl}`);
+            return;
         }

Note: when both --json and --env are supplied, JSON currently wins and .env output is skipped because of the earlier if (input.json) { ... return; } – if that’s not intentional, you may want to enforce mutual exclusivity or emit both in a defined order.

🧹 Nitpick comments (6)
create-db/src/index.ts (6)

54-91: Avoid unbounded growth of pendingAnalytics in long‑lived processes

sendAnalytics keeps appending promises to pendingAnalytics, and flushAnalytics never clears the array. In a long‑running process (e.g. using the programmatic API repeatedly), this can accumulate resolved promises and re‑await them on every flush.

You can snapshot and clear the queue before waiting:

 async function flushAnalytics(maxWaitMs = 500): Promise<void> {
-    if (pendingAnalytics.length === 0) return;
-    await Promise.race([
-        Promise.all(pendingAnalytics),
-        new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),
-    ]);
+    if (pendingAnalytics.length === 0) return;
+
+    const toWait = pendingAnalytics.splice(0, pendingAnalytics.length);
+
+    await Promise.race([
+        Promise.all(toWait),
+        new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),
+    ]);
 }

36-38: Consider moving dotenv side‑effect out of the library entrypoint

Calling dotenv.config() at module load time couples importing create-db (for the programmatic API) to reading and mutating process.env. That’s convenient for the CLI, but can be surprising when the package is used as a library inside other apps.

If you want a cleaner library surface, consider moving dotenv.config() into the actual CLI entry (e.g. cli.ts / bin script) and letting host applications decide when/how to load env files.


155-174: Avoid re‑parsing .env now that dotenv.config() is already used

readUserEnvFile manually parses .env, even though dotenv.config() has already populated process.env. That duplicates parsing logic and can subtly diverge from dotenv’s behavior.

Given you only need a couple of keys, you could simplify to reading from process.env (which will already include .env content) and drop the custom parser, or at least gate this helper behind a clear reason (e.g. “read only from file, ignore real env”).


221-338: Defensive handling for non‑2xx responses without error payload (optional)

createDatabaseCore special‑cases 429 and otherwise relies on the worker always returning either valid JSON with an error field or a non‑JSON body (caught as invalid_json). If the API ever returns a non‑2xx JSON response without error (e.g. a bare {} with status 500), this path would be treated as success.

If you want extra robustness, consider also checking !resp.ok before returning success, e.g.:

-    if (result.error) {
+    if (!resp.ok || result.error) {
         // existing error handling...

This keeps current behavior but guards against unexpected wire formats.


532-544: Optional: reuse checkOnline() for the regions command for consistent UX

The regions sub‑command currently calls getRegions() directly. If the API is unreachable or returns a non‑OK response, users may see a thrown error stack rather than the friendly “Cannot reach Prisma Postgres API server” messaging you implemented in checkOnline().

For consistency with create, consider:

     regions: os
         .meta({ description: "List available Prisma Postgres regions" })
         .handler(async (): Promise<void> => {
-            const regions = await getRegions();
+            await checkOnline();
+            const regions = await getRegions();

573-592: Programmatic API reuses core logic but never flushes analytics (design choice)

create() and regions() nicely reuse createDatabaseCore and getRegions, giving a clean programmatic surface. However, createDatabaseCore sends analytics and relies on flushAnalytics() being called by the CLI; the programmatic path never flushes, and callers have no way to opt out or flush explicitly.

If this API is intended for embedding in other apps/services, consider one of:

  • Disabling analytics for programmatic calls (e.g. flag parameter).
  • Exposing a documented flushAnalytics() export for hosts that care.
  • Injecting an analytics sink so library users can stub/disable it in tests.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 209691d and 99989a1.

📒 Files selected for processing (1)
  • create-db/src/index.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
create-db/src/index.ts (1)
create-db/src/types.ts (10)
  • RegionId (12-12)
  • RegionCoordinates (28-31)
  • UserLocation (14-21)
  • GeoLocationResponse (111-118)
  • Region (33-37)
  • RegionsResponse (124-124)
  • CreateDatabaseResult (59-59)
  • ApiResponse (99-104)
  • RegionSchema (3-10)
  • ProgrammaticCreateOptions (126-129)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: claim-db-worker
  • GitHub Check: Workers Builds: create-db-worker
🔇 Additional comments (2)
create-db/src/index.ts (2)

100-153: Location → nearest‑region helpers look correct and defensive

The detectUserLocation + getRegionClosestToLocation combo handles network failures and malformed/partial coordinates gracefully (null + NaN checks) while doing a proper Haversine distance calculation over the known REGION_COORDINATES. This is a solid, side‑effect‑free helper pair.


176-219: Online check and region fetching/validation are straightforward and consistent

checkOnline, getRegions, and validateRegion form a clear, reusable layer: health‑check first, then fetch, then validate against the live region list with a helpful error message. Error paths exit with a non‑zero code and flush analytics, which is appropriate for a CLI.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
create-db/src/index.ts (2)

100-121: Add timeout to geolocation fetch to prevent CLI hangs.

Unlike the analytics calls, detectUserLocation blocks the main flow. If ipapi.co is slow or unresponsive, the CLI will hang indefinitely. Consider adding an AbortController with a reasonable timeout (e.g., 3-5 seconds).

 async function detectUserLocation(): Promise<UserLocation | null> {
     try {
+        const controller = new AbortController();
+        const timer = setTimeout(() => controller.abort(), 3000);
         const response = await fetch("https://ipapi.co/json/", {
             method: "GET",
             headers: { "User-Agent": "create-db-cli/1.0" },
+            signal: controller.signal,
         });
+        clearTimeout(timer);

         if (!response.ok) return null;

176-206: Consider adding timeouts to API fetches for resilience.

checkOnline() and getRegions() lack timeouts. While they have error handling, a hung connection will block indefinitely without feedback to the user. Adding a 10-second timeout would improve resilience.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99989a1 and 1d96c16.

📒 Files selected for processing (1)
  • create-db/src/index.ts (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: claim-db-worker
  • GitHub Check: Workers Builds: create-db-worker
🔇 Additional comments (7)
create-db/src/index.ts (7)

1-34: Imports and type exports look good.

The isCancel import is now included, addressing the previous review feedback. The type exports provide a clean public API surface.


36-52: Configuration setup is appropriate.

The quiet: true option correctly suppresses warnings for missing .env files. Region coordinates are appropriately hardcoded for geolocation calculations.


123-153: Haversine distance calculation is correctly implemented.

The function properly handles type coercion and edge cases, returning null for invalid coordinates.


155-174: Basic .env parsing is acceptable for this use case.

The simple parser handles the expected PRISMA_ACTOR_NAME and PRISMA_ACTOR_PROJECT variables. More complex edge cases (multiline values, escaped quotes) aren't handled, but this is fine given the limited scope.


221-338: Database creation logic is well-structured with comprehensive error handling.

The function properly handles rate limiting, JSON parse errors, and API errors. Connection string construction and analytics tracking are correctly implemented.


340-591: Router and CLI handlers are correctly implemented.

The cancellation checks now properly use isCancel(), and the control flow for JSON/env output modes includes proper returns. The interactive region selection logic is sound.


610-628: Programmatic API exports are clean and well-documented.

The create() and regions() functions provide a clean programmatic interface with helpful JSDoc examples.

Comment on lines +54 to +91
const pendingAnalytics: Promise<void>[] = [];

async function sendAnalytics(
eventName: string,
properties: Record<string, unknown>,
cliRunId: string
): Promise<void> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);

const promise = (async () => {
try {
await fetch(`${CREATE_DB_WORKER_URL}/analytics`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
eventName,
properties: { distinct_id: cliRunId, ...properties },
}),
signal: controller.signal,
});
} catch {
// Analytics failures should not block CLI
} finally {
clearTimeout(timer);
}
})();

pendingAnalytics.push(promise);
}

async function flushAnalytics(maxWaitMs = 500): Promise<void> {
if (pendingAnalytics.length === 0) return;
await Promise.race([
Promise.all(pendingAnalytics),
new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),
]);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

pendingAnalytics array is never cleared, causing unbounded growth.

After flushAnalytics() completes, the pendingAnalytics array still contains all previous (now-settled) promises. On subsequent calls, you re-await already-settled promises and the array grows indefinitely. Clear the array after flushing.

 async function flushAnalytics(maxWaitMs = 500): Promise<void> {
     if (pendingAnalytics.length === 0) return;
     await Promise.race([
         Promise.all(pendingAnalytics),
         new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),
     ]);
+    pendingAnalytics.length = 0;
 }
🤖 Prompt for AI Agents
In create-db/src/index.ts around lines 54 to 91, pendingAnalytics is never
cleared which leads to unbounded growth; update flushAnalytics so it operates on
a snapshot of the current pending promises and clears the shared array
immediately (e.g., copy or splice the array into a local variable and set the
original to empty) before awaiting Promise.race on that snapshot, ensuring
settled promises are not retained and new sendAnalytics calls can push into an
empty array.

});
}

const caller = createRouterClient(router, { context: {} });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove unused caller variable.

caller is created but never referenced anywhere in the file. This is dead code.

-const caller = createRouterClient(router, { context: {} });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const caller = createRouterClient(router, { context: {} });
🤖 Prompt for AI Agents
In create-db/src/index.ts around line 593, the variable "caller" is created with
const caller = createRouterClient(router, { context: {} }); but never used;
remove this dead-code declaration (delete that line) or, if a client is intended
to be used later, replace with a used identifier and use it; otherwise simply
remove the unused const to eliminate the unused variable.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
create-db/src/index.ts (2)

86-92: pendingAnalytics array is never cleared after flushing.

After flushAnalytics() completes, the array still contains all settled promises, causing unbounded growth on repeated calls.

Apply this diff to clear the array after flushing:

 async function flushAnalytics(maxWaitMs = 500): Promise<void> {
     if (pendingAnalytics.length === 0) return;
+    const toFlush = [...pendingAnalytics];
+    pendingAnalytics.length = 0;
     await Promise.race([
-        Promise.all(pendingAnalytics),
+        Promise.all(toFlush),
         new Promise<void>((resolve) => setTimeout(resolve, maxWaitMs)),
     ]);
 }

594-594: Remove unused caller variable.

caller is created but never used anywhere in the file.

-const caller = createRouterClient(router, { context: {} });
🧹 Nitpick comments (4)
create-db/src/index.ts (4)

101-122: Consider adding a timeout to the geolocation request.

detectUserLocation lacks a timeout, so a slow or unresponsive ipapi.co could cause the CLI to hang. Consider using AbortController similar to sendAnalytics.

 async function detectUserLocation(): Promise<UserLocation | null> {
     try {
+        const controller = new AbortController();
+        const timer = setTimeout(() => controller.abort(), 3000);
         const response = await fetch("https://ipapi.co/json/", {
             method: "GET",
             headers: { "User-Agent": "create-db-cli/1.0" },
+            signal: controller.signal,
         });
+        clearTimeout(timer);

         if (!response.ok) return null;

457-488: Consider handling the case where envPath is a directory.

The code appends to envPath without checking if it's a valid file path. If a user passes a directory path, appendFileSync will fail with a cryptic error.

             try {
                     const targetEnvPath = envPath!;
+                    const stat = fs.existsSync(targetEnvPath) ? fs.statSync(targetEnvPath) : null;
+                    if (stat?.isDirectory()) {
+                        console.error(pc.red(`Cannot write to directory: ${targetEnvPath}. Please specify a file path.`));
+                        process.exit(1);
+                    }
                     const lines = [

589-589: Hardcoded version string may drift from package.json.

Consider importing the version from package.json or using a build-time replacement to keep them in sync.


618-622: Consider validating the region in the programmatic API.

The create function doesn't validate the region option before calling createDatabaseCore. An invalid region will result in an API error from the backend rather than a clear client-side validation error.

 export async function create(
     options?: ProgrammaticCreateOptions
 ): Promise<CreateDatabaseResult> {
+    const region = options?.region || "us-east-1";
+    if (options?.region) {
+        await validateRegion(region);
+    }
-    return createDatabaseCore(options?.region || "us-east-1", options?.userAgent);
+    return createDatabaseCore(region, options?.userAgent);
 }

Alternatively, if you want to allow the backend to handle validation, document this behavior in the JSDoc.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d96c16 and 550b435.

📒 Files selected for processing (1)
  • create-db/src/index.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
create-db/src/index.ts (1)
create-db/src/types.ts (10)
  • RegionId (12-12)
  • RegionCoordinates (28-31)
  • UserLocation (14-21)
  • GeoLocationResponse (111-118)
  • Region (33-37)
  • RegionsResponse (124-124)
  • CreateDatabaseResult (59-59)
  • ApiResponse (99-104)
  • RegionSchema (3-10)
  • ProgrammaticCreateOptions (126-129)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: claim-db-worker
  • GitHub Check: Workers Builds: create-db-worker
🔇 Additional comments (5)
create-db/src/index.ts (5)

1-35: LGTM!

Imports and re-exports are well-organized. The isCancel import from @clack/prompts is correctly included as addressed from previous feedback.


37-53: LGTM!

Configuration setup with sensible defaults and well-defined region coordinates matching the RegionSchema enum.


177-207: LGTM!

Online check and region fetching are appropriately implemented. The health check provides clear user feedback on connection issues.


222-339: LGTM!

createDatabaseCore handles rate limiting, JSON parsing errors, and API errors robustly with appropriate analytics tracking. Connection string construction properly URL-encodes credentials.


570-583: LGTM!

The regions handler is clean and straightforward. Error propagation to the CLI framework is acceptable.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🧹 Nitpick comments (2)
.github/workflows/publish.yml (2)

65-76: Extract duplicated build logic into a reusable workflow.

The build steps (checking for build script and running pnpm run build) are duplicated between the build job and experimental-release job. Consider extracting this into a reusable workflow to reduce maintenance burden.

Create .github/workflows/build-packages.yml as a reusable workflow, then call it from both jobs:

# .github/workflows/build-packages.yml
name: Build Packages

on:
  workflow_call:

jobs:
  build-packages:
    runs-on: ubuntu-latest
    steps:
      - name: 🔨 Build packages
        run: |
          for pkg in create-db create-pg create-postgres; do
            if [ -f "$pkg/package.json" ]; then
              cd "$pkg"
              if grep -q '"build"' package.json; then
                echo "Building $pkg..."
                pnpm run build || echo "Build skipped for $pkg (no build script)"
              fi
              cd - >/dev/null
            fi
          done

Then in publish.yml, call the reusable workflow after setup steps in both build and experimental-release jobs.

Also applies to: 219-230


65-76: Extract duplicated build logic into a reusable workflow.

The build step (checking for build script and running pnpm run build) is duplicated between build and experimental-release jobs. Create a reusable workflow to reduce maintenance burden and ensure consistency.

Also applies to: 219-230

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 550b435 and 3d5dd13.

📒 Files selected for processing (3)
  • .github/workflows/preview.yml (0 hunks)
  • .github/workflows/publish.yml (1 hunks)
  • .github/workflows/release.yml (0 hunks)
💤 Files with no reviewable changes (2)
  • .github/workflows/preview.yml
  • .github/workflows/release.yml
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/publish.yml

215-215: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)


260-260: the runner of "actions/github-script@v6" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: create-db-worker
  • GitHub Check: Workers Builds: claim-db-worker
🔇 Additional comments (5)
.github/workflows/publish.yml (5)

21-22: Workflow permissions set restrictively at the top level.

The default permissions are contents: read, which is appropriate. Child jobs explicitly elevate permissions only where needed (release jobs need contents: write, pull-requests: write, id-token: write). This follows least-privilege principle well.


12-12: Concurrency control prevents simultaneous workflow runs.

The concurrency group is scoped to workflow + ref, which prevents duplicate runs for the same branch/PR. This is appropriate.


21-22: Permission model appropriately follows least-privilege principle.

Top-level permissions are read-only by default. Jobs that need elevated permissions (contents: write, pull-requests: write, id-token: write) explicitly declare them. This is a security best practice.

Also applies to: 94-97


12-12: Concurrency control prevents simultaneous runs.

Concurrency group scoped to workflow + ref appropriately prevents duplicate executions on the same branch/PR.


154-159: The auto-generation code doesn't execute in normal operation.

The condition if [ -z "$(ls -A .changeset 2>/dev/null)" ] checks whether the .changeset directory is empty. Since .changeset/config.json and .changeset/README.md are committed to the repository and always present, the directory is never empty. The defensive code block never runs in normal circumstances.

The architectural concern about auto-generated changesets is theoretically sound, but it doesn't apply to this codebase in its current state. The condition that would trigger the auto-generation (an empty .changeset directory) should not occur during normal workflow execution.

Likely an incorrect or invalid review comment.

Comment on lines 49 to 50
- name: 📦 Update npm to support Trusted Publishers
run: npm install -g npm@11.5.1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

npm 11.5.1 GitHub Actions Trusted Publishers latest version 2025

💡 Result:

Summary — Trusted Publishing (GitHub Actions & npm CLI)

  • npm Trusted Publishing (OIDC) reached general availability on July 31, 2025 and supports GitHub Actions; it requires npm CLI v11.5.1 or later. [1]
  • GitHub has been rolling related npm security changes and recommending migration to Trusted Publishing in 2025. [2]
  • Note: there have been follow-up npm CLI patch releases (e.g., 11.5.2) with reported Windows issues — test upgrades in CI before wide rollout. [3]

Sources:
[1] GitHub / npm changelog: “npm trusted publishing with OpenID Connect (OIDC) is generally available” (July 31, 2025).
[2] GitHub Changelog: “Strengthening npm security… Trusted publishers” (Sept 29, 2025).
[3] npm/cli GitHub issue reporting problems with npm 11.5.2 (Aug 2025).


🌐 Web query:

npm Trusted Publishers GitHub Actions requirements

💡 Result:

Short checklist — requirements to use npm Trusted Publishers with GitHub Actions

  • npm CLI v11.5.1 or later. [1]
  • Use GitHub-hosted runners (self-hosted runners not supported). [1]
  • Configure a Trusted Publisher for the package on npmjs.com: specify organization/user, repository, and the workflow filename (exact filename, must include .yml/.yaml and live in .github/workflows/). Environment name is optional. Each package can have only one trusted publisher at a time. [1]
  • Workflow must request OIDC ID token permission (id-token: write) so GitHub can issue the job-specific token. [1][2]
  • The npm CLI will use OIDC for npm publish (provenance is generated automatically when using Trusted Publishing). [1][3]
  • Trusted publishing applies only to publish (npm publish); other npm commands (install, view, access) still need normal auth for private packages. For installing private deps in CI you may still need a read token. [1]

Sources: npm Trusted Publishers docs and GitHub/npm announcements. [1][2][3]


🌐 Web query:

npm latest version December 2025

💡 Result:

The latest stable npm CLI version as of December 3, 2025 is v11.6.2 (released Oct 8, 2025). [1][2]

Sources:
[1] Node.js release notes showing bundled npm v11.6.2.
[2] npm/cli release v11.6.2 (release date Oct 8, 2025).


Consider upgrading npm to v11.6.2, the latest stable version for Trusted Publishers support.

Line 50 pins npm to v11.5.1, which meets the minimum requirement for Trusted Publishers (GA July 31, 2025). However, v11.6.2 (released October 8, 2025) is now available and includes bug fixes from v11.5.x patch releases that had reported Windows issues. Upgrading to v11.6.2 provides better stability without breaking changes.

🤖 Prompt for AI Agents
.github/workflows/publish.yml around lines 49 to 50: the workflow currently
installs npm@11.5.1; update the pinned npm version to 11.6.2 to use the latest
stable Trusted Publishers-supporting release. Modify the run step to install
npm@11.6.2, then re-run the workflow to verify the action works on all runner
OSes (especially Windows) and that no other steps depend on the older npm patch
version.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

npm 11.5.1 GitHub Actions Trusted Publishers OIDC latest version 2025

💡 Result:

Short answer: Trusted publishing (OIDC) for npm was made generally available in July 2025 and requires npm CLI v11.5.1 or later. [1][2][3]

Details:

  • GitHub announced npm "trusted publishing with OpenID Connect (OIDC)" GA on July 31, 2025. [1]
  • npm's docs state trusted publishing requires npm CLI v11.5.1 or later. [2]
  • npm CLI v11.5.1 was released July 24, 2025 (follow-up patch 11.5.2 released July 30, 2025). [3]

Sources:
[1] GitHub Blog changelog: "npm trusted publishing with OIDC is generally available" (July 31, 2025).
[2] npm Docs: "Trusted publishing for npm packages" (requires npm CLI v11.5.1 or later).
[3] npm/cli release notes: v11.5.1 (released July 24, 2025).


🌐 Web query:

GitHub Actions npm Trusted Publishers recommended version

💡 Result:

Use npm CLI version 11.5.1 or later (npm@>=11.5.1) when using npm Trusted Publishing with GitHub Actions — this enables OIDC/trusted-publisher publishing (no long‑lived npm token) and automatic provenance. [1][2]

Sources:
[1] GitHub Changelog: "Trusted publishing requires npm CLI v11.5.1 or later."
[2] npm Docs: "Trusted publishing — configure for GitHub Actions"


Consider using npm@11.5.2 or a version constraint like npm@>=11.5.1 instead of pinning to 11.5.1.

npm@11.5.1 is the minimum required version for Trusted Publishers (GA July 2025), but npm@11.5.2 (released July 30, 2025) is available with additional patches. Pinning to the exact minimum version may miss important bug fixes; consider using a flexible constraint or updating to the latest patch.

🤖 Prompt for AI Agents
.github/workflows/publish.yml around lines 49 to 50: the workflow pins npm to
the exact version 11.5.1 which misses later patches; update the run step to
install either npm@11.5.2 (recommended) or use a flexible constraint such as
npm@">=11.5.1" to ensure bugfixes are included while still meeting the Trusted
Publishers minimum requirement.

Comment on lines +146 to +150
if ! pnpm publish --access public --no-git-checks; then
echo "Publish failed, trying to bump version and retry..."
npm version patch --no-git-tag-version
pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/publish.yml | sed -n '130,160p'

Repository: prisma/create-db

Length of output: 1867


🏁 Script executed:

cat -n .github/workflows/publish.yml | sed -n '145,175p'

Repository: prisma/create-db

Length of output: 1603


Fix publish failure handling to prevent silent deployment failures.

The workflow silences the second publish failure with || echo instead of failing explicitly. If both publish attempts fail for any package, the loop continues and the job reports success despite the release being incomplete.

Since this is a monorepo with multiple packages, a single failed publish should block the workflow. Replace line 149 with an explicit failure:

                    if ! pnpm publish --access public --no-git-checks; then
                      echo "Publish failed, trying to bump version and retry..."
                      npm version patch --no-git-tag-version
-                     pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
+                     if ! pnpm publish --access public --no-git-checks; then
+                       echo "❌ Publish failed for $pkg after retry"
+                       exit 1
+                     fi
                    fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ! pnpm publish --access public --no-git-checks; then
echo "Publish failed, trying to bump version and retry..."
npm version patch --no-git-tag-version
pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
fi
if ! pnpm publish --access public --no-git-checks; then
echo "Publish failed, trying to bump version and retry..."
npm version patch --no-git-tag-version
if ! pnpm publish --access public --no-git-checks; then
echo "❌ Publish failed for $pkg after retry"
exit 1
fi
fi
🤖 Prompt for AI Agents
.github/workflows/publish.yml around lines 146 to 150: the second publish
attempt currently uses "|| echo" which swallows failures and lets the job
continue; change the failure handling to explicitly fail the workflow when the
second publish fails (for example, replace the "|| echo" with logic that prints
the error and exits non‑zero or wrap the second publish in a conditional that on
failure prints a clear message and calls exit 1) so any package publish failure
stops the job.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/publish.yml | sed -n '135,160p'

Repository: prisma/create-db

Length of output: 1527


Hard-fail on publish failures to prevent silent deployment failures.

The publish step silently suppresses the second retry with || echo "...", causing the loop to continue and the workflow to report success even if all packages fail to publish. This is particularly dangerous in a multi-package loop—failed releases are masked entirely.

Remove the error suppression:

                   # First try to publish
                   if ! pnpm publish --access public --no-git-checks; then
                     echo "Publish failed, trying to bump version and retry..."
                     npm version patch --no-git-tag-version
-                    pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
+                    pnpm publish --access public --no-git-checks
                   fi

Alternatively, track failed packages and exit with a non-zero code if any publish fails.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ! pnpm publish --access public --no-git-checks; then
echo "Publish failed, trying to bump version and retry..."
npm version patch --no-git-tag-version
pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
fi
if ! pnpm publish --access public --no-git-checks; then
echo "Publish failed, trying to bump version and retry..."
npm version patch --no-git-tag-version
pnpm publish --access public --no-git-checks
fi
🤖 Prompt for AI Agents
.github/workflows/publish.yml around lines 146 to 150: the publish retry
suppresses errors with `|| echo ...`, allowing the workflow to continue as
success even when publish fails; remove the error-suppression so the command
exits non-zero on failure (or replace it with logic that records failed package
names and exits non-zero after the loop), e.g., make the second publish
invocation fail loudly and/or append failure tracking and an explicit exit 1 if
any package failed.

Comment on lines +154 to +159
- name: 📝 Ensure Changeset Exists
run: |
if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
echo "No changeset found. Creating a default one..."
pnpm changeset add --empty --message "chore(release): auto-generated changeset"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Changeset fallback creates generic entries that may mask missing release notes.

Creating an empty changeset with auto-generated messages could hide real version bumps without proper documentation of what changed. This should either fail explicitly or require manual intervention to ensure releases are properly documented.

Consider failing explicitly when changesets are missing:

             - name: 📝 Ensure Changeset Exists
               run: |
-                  if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
-                    echo "No changeset found. Creating a default one..."
-                    pnpm changeset add --empty --message "chore(release): auto-generated changeset"
-                  fi
+                  if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
+                    echo "❌ No changeset found. Please run 'pnpm changeset' and commit your changes."
+                    exit 1
+                  fi
🤖 Prompt for AI Agents
.github/workflows/publish.yml around lines 154-159: the current step
auto-creates an empty changeset which can mask missing release notes; change
this step to fail the workflow if .changeset is empty (exit non-zero with a
clear message instructing the author to add a proper changeset) or gate
auto-generation behind an explicit opt-in flag (e.g., only create an auto
changeset when a repo secret/env var is set), and update the run script to emit
the failure message and exit 1 when the directory is empty unless the opt-in
flag is present.

done

- name: 💬 Post preview-testing instructions
uses: actions/github-script@v6
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

latest version actions/github-script GitHub Actions

💡 Result:

The latest released version is 8.0.0 — use actions/github-script@v8 (or @v8.0.0). [1][2]

Sources:
[1] actions/packages (github-script) — latest version 8.0.0.
[2] actions/github-script repository (releases/tags).


🌐 Web query:

actions/github-script v6 maintained supported 2025

💡 Result:

Short answer: v6 is not the current release and GitHub treats the repository as low‑activity — they’re not taking contributions and only promise security/major-breaking fixes. Upgrade to the latest (v8) if you want current Node/runtime support. Sources: GitHub repo README (actions/github-script) and Marketplace listing. [1][2]

Sources
[1] actions/github-script repository README (shows note about not taking contributions, V6 uses Node 16, and examples using v8).
[2] GitHub Marketplace listing for actions/github-script (same maintenance note).


Upgrade actions/github-script from v6 to v8.

Version 6 is outdated and uses Node 16. The latest supported version is v8.0.0, which provides current Node.js runtime support. Version 6 is no longer actively maintained—GitHub only provides security fixes for it.

Also applies to: 267-267

🧰 Tools
🪛 actionlint (1.7.9)

260-260: the runner of "actions/github-script@v6" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
.github/workflows/publish.yml around lines 260 and 267: the workflow uses
actions/github-script@v6 which is outdated and uses Node 16; update both
occurrences to actions/github-script@v8 (or pin to actions/github-script@v8.0.0)
so the action runs on the current supported Node runtime and receives the latest
fixes/security updates.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

actions/github-script latest version 2025 current maintenance

💡 Result:

Latest release: actions/github-script v8.0.0 (released Sep 4, 2025). [1]

Maintenance status: the repository is in limited-maintenance — GitHub notes they are not taking contributions right now but will provide security updates and fix major breaking issues; support requests are directed to Community Discussions / GitHub Support. [2]

Sources:

  • Release page (v8.0.0). [1]
  • Repository README / maintenance note. [2]

Update actions/github-script to v8 or latest version.

v6 is two major versions behind the current v8.0.0 release (Sep 2025). While v6 receives security updates under limited maintenance, upgrading to the latest stable version ensures access to improvements and full compatibility with current Node.js environments.

🧰 Tools
🪛 actionlint (1.7.9)

260-260: the runner of "actions/github-script@v6" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
.github/workflows/publish.yml around line 260: the workflow pins
actions/github-script to v6 which is outdated; update the action reference to
the current major (use actions/github-script@v8 or actions/github-script@v8.0.0
or the latest stable tag), commit the change to the workflow file, and
run/validate the CI workflow to ensure compatibility with your Node.js runner
and no breaking changes in the updated action.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (4)
.github/workflows/publish.yml (4)

85-91: ⚠️ Fix silent publish failure handling to prevent incomplete releases.

Line 88 uses || echo to suppress publish failures, allowing the loop to continue even if all retries fail. In a monorepo, a single failed package should block the entire workflow. This was flagged in prior reviews and remains unresolved.

Replace the error suppression with an explicit failure:

-                    pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
+                    if ! pnpm publish --access public --no-git-checks; then
+                      echo "❌ Publish failed for $pkg after retry"
+                      exit 1
+                    fi

93-99: ⚠️ Replace automatic changeset fallback with explicit failure.

Auto-generating an empty changeset can mask missing release notes and hide real version bumps. This was flagged in prior reviews.

Fail explicitly if changesets are missing:

             - name: 📝 Ensure Changeset Exists
               run: |
-                  if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
-                    echo "No changeset found. Creating a default one..."
-                    pnpm changeset add --empty --message "chore(release): auto-generated changeset"
-                  fi
+                  if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
+                    echo "❌ No changeset found. Please run 'pnpm changeset' and commit your changes."
+                    exit 1
+                  fi

152-156: 🔴 Fix script injection vulnerability in preview tag creation.

Line 154 directly interpolates github.event.pull_request.head.ref into a shell script. Although tr sanitizes forward slashes, it does not prevent shell metacharacter injection (e.g., $, backticks, ;, |). An attacker can craft a malicious branch name to execute arbitrary commands. GitHub's security documentation requires untrusted context values to be passed via environment variables. This was flagged in prior reviews.

Apply this diff:

             - name: 🔖 Create unique preview tag
+              env:
+                HEAD_REF: ${{ github.event.pull_request.head.ref }}
               run: |
-                  SAFE_REF=$(echo "${{ github.event.pull_request.head.ref }}" | tr '/' '-')
+                  SAFE_REF=$(echo "${HEAD_REF}" | tr '/' '-')
                   echo "PRE_TAG=pr${{ github.event.number }}-${SAFE_REF}-${{ github.run_id }}" >> $GITHUB_ENV

191-224: ⚠️ Upgrade actions/github-script from v6 to v8.

Line 192 uses actions/github-script@v6, which is outdated and runs on Node 16. The latest stable version is v8.0.0 (released September 2025), which provides current Node.js runtime support and critical updates. This was flagged in prior reviews.

Update the action reference:

-              uses: actions/github-script@v6
+              uses: actions/github-script@v8
🧹 Nitpick comments (1)
.github/workflows/publish.yml (1)

166-171: Clean up redundant environment variable reassignments.

Lines 166–171 reassign CREATE_DB_WORKER_URL and CLAIM_DB_WORKER_URL after they are already declared in the step's env block (lines 160–163). This is redundant; remove the inline reassignments.

               run: |
-                  # Resolve URLs with fallback
-                  CREATE_DB_WORKER_URL="${{ secrets.CREATE_DB_WORKER_URL }}"
-                  CLAIM_DB_WORKER_URL="${{ secrets.CLAIM_DB_WORKER_URL }}"
-
-                  # Persist for next steps
-                  echo "CREATE_DB_WORKER_URL=$CREATE_DB_WORKER_URL" >> $GITHUB_ENV
-                  echo "CLAIM_DB_WORKER_URL=$CLAIM_DB_WORKER_URL" >> $GITHUB_ENV
-
                   echo "Using CREATE_DB_WORKER_URL=$CREATE_DB_WORKER_URL"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d5dd13 and 3a9d744.

📒 Files selected for processing (1)
  • .github/workflows/publish.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/publish.yml

153-153: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)


192-192: the runner of "actions/github-script@v6" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: claim-db-worker
  • GitHub Check: Workers Builds: create-db-worker
🔇 Additional comments (5)
.github/workflows/publish.yml (5)

1-27: ✅ Workflow triggers and environment setup look good.

Concurrency, event triggers, and secret/workspace env variables are properly configured.


29-64: ✅ Release job setup is correct.

Node/pnpm configuration and permissions are appropriate.


100-108: ✅ Changesets PR preparation is correct.


110-145: ✅ Preview job setup is correct.


146-151: ✅ README copying logic is straightforward.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
.github/workflows/release.yml (3)

93-98: Changeset fallback creates generic entries that may mask missing release notes.

Creating an empty changeset with auto-generated messages could hide real version bumps without proper documentation of what changed. This should either fail explicitly or require manual intervention to ensure releases are properly documented.

Consider failing explicitly when changesets are missing:

             - name: 📝 Ensure Changeset Exists
               run: |
-                  if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
-                    echo "No changeset found. Creating a default one..."
-                    pnpm changeset add --empty --message "chore(release): auto-generated changeset"
-                  fi
+                  if [ -z "$(ls -A .changeset 2>/dev/null)" ]; then
+                    echo "❌ No changeset found. Please run 'pnpm changeset' and commit your changes."
+                    exit 1
+                  fi

85-89: Hard-fail on publish failures to prevent silent deployment failures.

Line 88 silently suppresses the second publish retry with || echo "...", allowing the workflow to continue and report success even if all packages fail to publish. This is particularly dangerous in a multi-package loop—failed releases are masked entirely.

Remove the error suppression:

                    # First try to publish
                    if ! pnpm publish --access public --no-git-checks; then
                      echo "Publish failed, trying to bump version and retry..."
                      npm version patch --no-git-tag-version
-                     pnpm publish --access public --no-git-checks || echo "Publish failed again for $pkg"
+                     pnpm publish --access public --no-git-checks
                    fi

Alternatively, track failed packages and exit with a non-zero code if any publish fails.


191-192: Upgrade actions/github-script from v6 to v8.

Version 6 is outdated. The latest version is v8.0.0 and should be used instead.

-              uses: actions/github-script@v6
+              uses: actions/github-script@v8
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3a9d744 and 3dbbffd.

📒 Files selected for processing (1)
  • .github/workflows/release.yml (1 hunks)
🧰 Additional context used
🪛 actionlint (1.7.9)
.github/workflows/release.yml

153-153: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)


192-192: the runner of "actions/github-script@v6" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: claim-db-worker
  • GitHub Check: Workers Builds: create-db-worker

Comment on lines +152 to +156
- name: 🔖 Create unique preview tag
run: |
SAFE_REF=$(echo "${{ github.event.pull_request.head.ref }}" | tr '/' '-')
echo "PRE_TAG=pr${{ github.event.number }}-${SAFE_REF}-${{ github.run_id }}" >> $GITHUB_ENV
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

GitHub Actions security context variables shell injection best practices

💡 Result:

Short best-practices to avoid shell/command injection from GitHub Actions context variables

  1. Never interpolate untrusted expressions directly into run: avoid patterns like run: echo "…${{ github.event.issue.title }}…". Treat github/event fields (title, body, ref, name, email, etc.) as untrusted. [1][2]

  2. Use an intermediate env (recommended for inline scripts): assign the expression to env then reference the env var inside run (and quote it). Example:
    env: TITLE: ${{ github.event.issue.title }}
    run: echo "$TITLE"
    This prevents expression evaluation from producing executable shell code. [1][2][3]

  3. Prefer an action (JavaScript/TypeScript action or composite action) and pass the value as an input instead of building shell scripts with the value. Actions receive arguments without generating shell code. [2]

  4. Always quote shell variables and avoid eval/command substitution (no eval, no backticks, no $(...) on untrusted data). Use safe argument-passing (array args) where possible. [1][2]

  5. Limit workflow permissions & tokens: give the least privilege (restrict GITHUB_TOKEN, avoid write when unnecessary), require environment reviewers for secrets, and avoid running untrusted PRs with high privileges (be careful with pull_request_target). [2][4]

  6. Validate or sanitize inputs when you must use them (whitelisting, strict regex) and prefer transforming inputs in code (action) rather than in shell string interpolation. [1][3]

  7. Monitor advisories and scan workflows: apply known fixes and use static analysis / CodeQL queries aimed at expression/script-injection patterns. Review recent disclosure examples to learn failure modes. [3][4]

Sources

  • GitHub Docs — Script injections / Security hardening for Actions. [1][2]
  • GitHub Security Lab — “Keeping your GitHub Actions and workflows secure: Untrusted input” (env pattern + CodeQL). [3]
  • GitHub Security Lab advisories (real-world expression-injection incidents, examples). [4]

If you want, I can: (a) show a safe/unsafe example diff for your workflow, or (b) run a quick scan (static heuristics) of a workflow file you paste. Which would you prefer?


🌐 Web query:

github.event.pull_request.head.ref untrusted user input security

💡 Result:

Short answer: treat github.event.pull_request.head.ref as untrusted user input. It can be attacker-controlled (branch names from forks/PRs) and — if interpolated into shell/checkout/API calls in privileged workflows (especially pull_request_target) — can lead to expression/code injection, TOCTOU, or secret exfiltration.

Why it's dangerous (high-level):

  • head.ref is attacker-controllable and has been used to inject expressions/commands into workflows. [1][2]
  • Using it with pull_request_target (runs in repo context/secrets) + checkout/run of PR code can give an attacker repository-level code execution and secret theft. [2][3][4]
  • Branch names are mutable (TOCTOU): resolving by name (ref) instead of immutable SHA can be exploited. [7]

Concrete mitigations (apply these immediately):

  • Never directly interpolate into shell/run lines. Don’t do: run: git checkout ${{ github.event.pull_request.head.ref }}. Use SHA instead: ${{ github.event.pull_request.head.sha }} where you need exact commit. [1][5]
  • Avoid actions/checkout@... with ref set to head.ref in pull_request_target workflows. Prefer checking out the base/default branch (github.base_ref or default branch) or use pull_request (unprivileged) triggers. [3][6]
  • If you must act on PR content in a privileged workflow: do not run code from the PR until a trusted human or bot has approved/merged; restrict permissions (least privilege for GITHUB_TOKEN); avoid exposing secrets to PR runs; use environment branch-protection rules. [4][5][7]
  • Sanitize and treat any github.event.* fields (including head.ref) as tainted: pass through action inputs/env vars (not inline shells), validate against an allowlist, and escape before use. Prefer actions that accept parameters rather than embedding into scripts. [5][6]
  • Use code scanning/CI checks (CodeQL) and the GitHub Security Lab guidance to find expression-injection patterns. Monitor advisories for workflow vulnerabilities. [1][5]

References
[1] GitHub Security Lab — GHSL advisory and examples of expression injection via github.event.pull_request.head.ref.
[2] GitHub Security Lab — “Keeping your GitHub Actions and workflows secure: Untrusted input.”
[3] Spotipy advisory / real-world PoC showing pull_request_target + checkout of head.ref leads to secret exfiltration.
[4] GitHub Changelog — changes around pull_request_target/default-branch behavior and environment protections.
[5] Orca Security blog — workflow injection risks and guidance (never interpolate user input into shell).
[6] Guidance pages / docs showing safer checkout patterns (use base_ref/default, bind to env or use inputs).
[7] GitHub Security Lab — newer writeups on TOCTOU and mitigation strategies.

If you want, I can (a) scan a specific workflow file and highlight risky lines, or (b) produce a safe rewrite of a given workflow snippet. Which would you like?


🌐 Web query:

GitHub Actions official security documentation context variables

💡 Result:

Key official sources and short summary:

  • Contexts reference — lists available contexts (github, secrets, env, etc.) and warns the github context includes sensitive fields (github.token) and that some contexts are only available in specific workflow keys. [1]

  • Security hardening (Secure use reference) — advises treating certain contexts as untrusted input, avoid injecting context values directly into run/commands (use env variables instead), mask sensitive data, use least-privilege for GITHUB_TOKEN, rotate/delete exposed secrets, and pin third-party actions. [2]

  • Using secrets in GitHub Actions — details how to use secrets (secrets context), notes secrets aren’t passed to forked workflows (except GITHUB_TOKEN), recommends masking and safe handling (avoid printing, prefer env or STDIN), and shows limitations on where secrets are available. [3]

If you want, I can extract the exact warning lines and code examples from those pages.

Sources: [1] Contexts reference — GitHub Docs. [2] Security hardening for GitHub Actions — GitHub Docs. [3] Using secrets in GitHub Actions — GitHub Docs.


Fix critical shell injection vulnerability in preview tag creation.

The github.event.pull_request.head.ref context is untrusted user input that can be controlled by attackers through malicious branch names. Line 154 interpolates this directly into the shell script without proper protection. Using tr alone is insufficient—shell metacharacters like $, backticks, ;, and | can still execute arbitrary commands. GitHub's official security documentation requires passing untrusted context through environment variables to prevent expression evaluation.

Apply this diff:

             - name: 🔖 Create unique preview tag
+              env:
+                HEAD_REF: ${{ github.event.pull_request.head.ref }}
               run: |
-                  SAFE_REF=$(echo "${{ github.event.pull_request.head.ref }}" | tr '/' '-')
+                  SAFE_REF=$(echo "${HEAD_REF}" | tr '/' '-')
                   echo "PRE_TAG=pr${{ github.event.number }}-${SAFE_REF}-${{ github.run_id }}" >> $GITHUB_ENV
🧰 Tools
🪛 actionlint (1.7.9)

153-153: "github.event.pull_request.head.ref" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

🤖 Prompt for AI Agents
.github/workflows/release.yml lines 152-156: the workflow currently interpolates
the untrusted github.event.pull_request.head.ref directly into a shell run
block, allowing shell injection; instead, pass that value into the runner via an
env mapping (e.g. SAFE_REF: ${{ github.event.pull_request.head.ref }}) so GitHub
sets it without shell evaluation, then in the run step read $SAFE_REF and
sanitize it before using (replace slashes with dashes and strip or collapse any
characters outside a safe whitelist such as A–Za–z0–9._-), then construct
PRE_TAG from trusted components and append it to GITHUB_ENV; ensure you never
inject the raw expression into the shell and only use the sanitized env value
when writing PRE_TAG.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants