Skip to content

Support npm dependencies in saved packages - #306

Merged
kentcdodds merged 2 commits into
mainfrom
cursor/saved-package-npm-dependencies-3995
May 1, 2026
Merged

kentcdodds merged 2 commits into
mainfrom
cursor/saved-package-npm-dependencies-3995

Conversation

@kentcdodds

@kentcdodds kentcdodds commented May 1, 2026 •

Copy link
Copy Markdown
Member

Summary

  • make the saved-package bundler preserve a real root package.json/Wrangler config and root-level node_modules entries so @cloudflare/worker-bundler can resolve declared npm dependencies for package exports, services, apps, jobs, and subscriptions
  • make repo-session package checks actually validate dependency-backed runtime bundles instead of only reporting package.json presence, so unsupported or unresolved npm imports fail during checks instead of surfacing later at runtime
  • fix repo-check path collisions so a file reused as both a package app entry and a module/job/service entry is validated with both bundle kinds instead of silently dropping one validation path
  • add a lightweight published-source dependency guard for missing bundle artifacts and lazy-load the worker bundler in package/runtime check paths so npm-backed packages fail with clear republish guidance without breaking unrelated node test discovery
  • document saved-package package.json dependency support and the publish/check-time resolution model for both users and contributors

Testing

  • npx vitest run --config vitest.node.config.ts packages/worker/src/repo/checks.node.test.ts packages/worker/src/package-invocations/service.node.test.ts
  • npx vitest run --config vitest.workers.config.ts packages/worker/src/package-runtime/module-graph.workers.test.ts
  • npx vitest run --config vitest.node.config.ts packages/worker/src/repo/checks.node.test.ts
  • npx vitest run --config vitest.workers.config.ts packages/worker/src/package-runtime/module-graph.workers.test.ts
  • npm run test
  • npm run test:e2e:run (via the successful git push pre-push hook)

Notes

  • no new user-facing config option was added for dependency installation; saved-package dependency support is built into the checks/publish/runtime pipeline
  • runtime safety remains the same: dependency resolution happens through the existing bundling pipeline, not by arbitrary package installation from user code at execution time
  • follow-up review fixes removed an unused exported helper and hardened the workers regression assertion for unresolved npm imports
Open in Web Open in Cursor 

Summary by CodeRabbit

Release Notes

Documentation

  • Added guidance on declaring and using npm dependencies in saved packages

Improvements

  • Enhanced package validation to detect missing npm dependencies during checks, providing clear error messages before runtime execution
  • Declared npm dependencies are now automatically bundled into package runtime artifacts for exports, apps, services, jobs, and subscriptions

@coderabbitai

coderabbitai Bot commented May 1, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR introduces npm dependency declaration and validation for saved Kody packages. It adds runtime dependency support where packages declare dependencies in package.json, validates these during bundling, and ensures unresolved dependencies are caught early during package checks and artifact rebuilds rather than at runtime.

Changes

Cohort / File(s) Summary
Documentation
docs/contributing/packages-and-manifests.md, docs/use/packages.md
Introduces documentation defining how saved packages declare npm runtime dependencies in package.json, specifying that Kody bundles them during checks/publish and that unresolved dependencies cause repo check failures.
Import Specifier Parsing
packages/worker/src/package-runtime/import-specifiers.ts
New module that parses JavaScript/TypeScript source to extract literal import specifiers from import/export declarations, classify bare vs. relative/absolute imports, and extract bare package names from specifiers.
Module Graph & Bundling
packages/worker/src/package-runtime/module-graph.ts
Refactored to lazily load worker-bundler, replace AST parsing with new import specifier extraction, validate unresolved bare package imports after bundling, and update file staging to copy package.json and exclude node_modules entries directly into bundler root.
Dependency Validation Utility
packages/worker/src/package-runtime/published-source-dependencies.ts
New module exporting assertPublishedSourceCanRebuildWithoutInstallingDeps that validates declared package.json dependencies exist in published bundle's node_modules.
Runtime Service Updates
packages/worker/src/jobs/service.ts, packages/worker/src/package-invocations/service.ts, packages/worker/src/package-runtime/package-app.ts, packages/worker/src/package-runtime/package-service.ts
Multiple services now call the dependency assertion function before rebuilding bundles to validate dependencies are available.
Repo Checks Infrastructure
packages/worker/src/repo/checks.ts, packages/worker/src/repo/repo-session-do.ts
Repo checks now lazily load bundler/TypeScript, parse npm dependencies from package.json, perform bundling validation for entrypoints, report dependency status, and accept env, baseUrl, userId context; repo session forwards execution context to checks.
Test Additions & Mocks
packages/worker/src/package-runtime/module-graph.workers.test.ts, packages/worker/src/package-invocations/service.node.test.ts, packages/worker/src/repo/checks.node.test.ts
New test for bundling with npm dependencies, test for missing published artifact scenario, and updated repo checks tests with bundler/TypeScript mocking and four new dependency-related test cases.

Sequence Diagram(s)

sequenceDiagram
    participant Source as Package Source<br/>(with package.json)
    participant Checks as Repo Checks
    participant Graph as Module Graph<br/>Bundler
    participant Assert as Dependency<br/>Assertion
    participant Bundle as Runtime<br/>Bundle
    participant Exec as Execution

    Source->>Checks: Parse package.json<br/>for dependencies
    Checks->>Checks: Extract declared<br/>dependencies
    Checks->>Graph: Invoke buildKodyModuleBundle<br/>with sourceFiles
    Graph->>Graph: Extract literal import<br/>specifiers from code
    Graph->>Bundle: Create worker bundle
    Bundle-->>Graph: Return modules
    Graph->>Assert: Call assertion with<br/>declared dependencies
    Assert->>Bundle: Check node_modules<br/>entries match
    alt Dependencies Available
        Assert-->>Graph: ✓ Pass
        Graph-->>Checks: ✓ Bundle successful
        Checks->>Exec: Artifact ready
    else Missing Dependencies
        Assert-->>Graph: ✗ Throw error
        Graph-->>Checks: ✗ Bundle failed
        Checks-->>Source: ✗ Repo check fails
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 Dependencies bundled tight and clean,
No node_modules in between!
Assert they're there before we build,
With eager checks, the gaps are filled.
Runtime artifacts, safe and sound,
Workers hop with joy around! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Support npm dependencies in saved packages' directly and clearly describes the main objective of the PR—enabling npm dependency support in saved packages, which is reflected throughout the changeset (documentation, bundling validation, runtime checks, and dependency resolution).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/saved-package-npm-dependencies-3995

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.

@kentcdodds
kentcdodds marked this pull request as ready for review May 1, 2026 03:11
@github-actions

github-actions Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-306.kentcdodds.workers.dev

Worker: kody-pr-306
D1: kody-pr-306-db
KV: kody-pr-306-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/worker/src/package-runtime/module-graph.workers.test.ts (1)

47-47: ⚡ Quick win

Harden the unresolved-import assertion pattern.

Line 47 only checks one import spelling, so equivalent unresolved forms can slip through undetected.

Proposed diff
-	expect(moduleSources).not.toContain(`from "kleur"`)
+	expect(moduleSources).not.toMatch(
+		/\bfrom\s+['"]kleur['"]|\brequire\(\s*['"]kleur['"]\s*\)/,
+	)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/worker/src/package-runtime/module-graph.workers.test.ts` at line 47,
The test currently only checks for the exact string `from "kleur"` which misses
other equivalent unresolved import forms; update the assertion on moduleSources
(the variable used in the test) to assert it does not match a regex that covers
variations (single or double quotes, any spacing, named/default imports) such as
using a negative regex match instead of not.toContain; replace the
expect(moduleSources).not.toContain(...) usage with an assertion that
moduleSources does not match /from\s+['"]kleur['"]/ (or a slightly broader
pattern to catch variations) so all unresolved-import forms for "kleur" are
caught.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/worker/src/package-runtime/module-graph.workers.test.ts`:
- Line 47: The test currently only checks for the exact string `from "kleur"`
which misses other equivalent unresolved import forms; update the assertion on
moduleSources (the variable used in the test) to assert it does not match a
regex that covers variations (single or double quotes, any spacing,
named/default imports) such as using a negative regex match instead of
not.toContain; replace the expect(moduleSources).not.toContain(...) usage with
an assertion that moduleSources does not match /from\s+['"]kleur['"]/ (or a
slightly broader pattern to catch variations) so all unresolved-import forms for
"kleur" are caught.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8578ef8f-03c7-48ef-aca5-cfe033db1df5

📥 Commits

Reviewing files that changed from the base of the PR and between d0703c0 and 645095e.

📒 Files selected for processing (14)
  • docs/contributing/packages-and-manifests.md
  • docs/use/packages.md
  • packages/worker/src/jobs/service.ts
  • packages/worker/src/package-invocations/service.node.test.ts
  • packages/worker/src/package-invocations/service.ts
  • packages/worker/src/package-runtime/import-specifiers.ts
  • packages/worker/src/package-runtime/module-graph.ts
  • packages/worker/src/package-runtime/module-graph.workers.test.ts
  • packages/worker/src/package-runtime/package-app.ts
  • packages/worker/src/package-runtime/package-service.ts
  • packages/worker/src/package-runtime/published-source-dependencies.ts
  • packages/worker/src/repo/checks.node.test.ts
  • packages/worker/src/repo/checks.ts
  • packages/worker/src/repo/repo-session-do.ts

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 645095e. Configure here.

remember(service.entry, true, 'module')
}
for (const subscription of listPackageSubscriptions(manifest)) {
remember(subscription.handler, true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duplicate entry bundleKind not updated on path collision

Medium Severity

The remember helper in collectPackageTypecheckTargets merges includeStorage on path collision but silently drops the second bundleKind. If the same file path is registered as both an 'app' entry and a 'module' export/job/service, only the first bundleKind is retained. validatePackageBundles then only calls buildKodyAppBundle or buildKodyModuleBundle for that path — never both — so the other bundle kind is never validated during repo checks.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 645095e. Configure here.

return `${scope}/${name}`
}
return specifier.split('/', 2)[0] ?? specifier
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Exported function getBarePackageNameFromSpecifier is never used

Low Severity

getBarePackageNameFromSpecifier is exported from import-specifiers.ts but is never imported or referenced by any other file in the codebase. It's dead code that was introduced in this PR.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 645095e. Configure here.

@kentcdodds
kentcdodds merged commit 320ddf8 into main May 1, 2026
16 checks passed
@kentcdodds
kentcdodds deleted the cursor/saved-package-npm-dependencies-3995 branch May 1, 2026 04:40
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