Skip to content

Add package invocation URL guardrails - #568

Merged
kentcdodds merged 2 commits into
mainfrom
package-invocation-url-guardrails
Jun 26, 2026
Merged

kentcdodds merged 2 commits into
mainfrom
package-invocation-url-guardrails

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jun 26, 2026 •

Copy link
Copy Markdown
Member

Walkthrough

  • Clarify the official package_invocation_token_setup guide with the owner-scoped invocation route shape, the Kent YouTube WebSub Worker example, and troubleshooting guidance that checks the owner slug before rotating tokens.
  • Add canonical package invocation URL helpers and surface per-export external invocation metadata from package_get and package entity search details.
  • Route stale unscoped POST /api/package-invocations/... requests to a structured owner_slug_required 404 before OAuth token handling.
  • Motivated by the YouTube WebSub Worker issue where agents called the unscoped route and misdiagnosed invalid_token; future agents should use the canonical URL helper/metadata instead of manually constructing package invocation routes.

Testing

  • npx vitest run packages/worker/src/package-invocations/http.workers.test.ts packages/worker/src/package-invocations/public-url.node.test.ts packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts packages/worker/src/mcp/tools/search-format.node.test.ts
  • npm run format:check
  • npm run lint (passes; reports existing warnings in unrelated test files)
  • npm run typecheck
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added owner-scoped “external package invocation” URLs and surfaced per-export invocation metadata (method, URL/path, export name mapping, token setup link, and source guidance) in package details and search results.
  • Bug Fixes

    • Improved handling of malformed/unscoped invocation requests with a clearer 404 error requiring the owner slug.
    • Ensured root export routes resolve correctly and token setup links are not treated as invocation endpoints.
  • Documentation

    • Updated setup and verification instructions with the canonical owner-scoped URL format, correct headers/body examples, and export-name/source rules.
  • Tests

    • Expanded coverage for invocation URL formatting, routing precedence, and external invocation metadata.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Jun 26, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 17053ef2-86cf-49df-b3b9-a92b51784e12

📥 Commits

Reviewing files that changed from the base of the PR and between 184332e and 0e82db8.

📒 Files selected for processing (9)
  • docs/guides/account-package-invocation-token-setup.md
  • packages/shared/src/public-urls.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.ts
  • packages/worker/src/mcp/capabilities/packages/shared.ts
  • packages/worker/src/package-invocations/http.ts
  • packages/worker/src/package-invocations/http.workers.test.ts
  • packages/worker/src/package-invocations/public-url.node.test.ts
  • packages/worker/src/package-invocations/public-url.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • packages/worker/src/mcp/capabilities/packages/shared.ts
  • packages/worker/src/package-invocations/http.workers.test.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.ts
  • packages/shared/src/public-urls.ts
  • packages/worker/src/package-invocations/public-url.node.test.ts
  • docs/guides/account-package-invocation-token-setup.md
  • packages/worker/src/package-invocations/http.ts
  • packages/worker/src/package-invocations/public-url.ts

📝 Walkthrough

Walkthrough

Adds owner-scoped package invocation URL builders and descriptors, threads invocation metadata through package lookup and search outputs, updates unscoped invocation HTTP handling, and revises the token-setup guide and related wording.

Changes

Owner-scoped package invocation flow

Layer / File(s) Summary
Canonical invocation URL builders
packages/shared/src/public-urls.ts, packages/worker/src/package-invocations/public-url.ts, packages/worker/src/package-invocations/service.ts, packages/worker/src/package-invocations/public-url.node.test.ts
Adds shared export-name normalization and owner-scoped invocation URL, path, and token-setup builders, and aligns service normalization and descriptor tests.
Package metadata exposes invocation data
packages/worker/src/mcp/capabilities/packages/get-package.ts, packages/worker/src/mcp/capabilities/packages/shared.ts, packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts
Extends package capability responses with required external_invocation data, resolves a public username for URL ownership, and updates schema and test expectations.
Search formatting renders invocation data
packages/worker/src/mcp/tools/search.ts, packages/worker/src/mcp/tools/search-format.ts, packages/worker/src/mcp/tools/search-format.node.test.ts
Carries baseUrl and ownerUsername into package detail resolution, adds externalInvocation to structured and markdown search output, and updates formatter tests.
Unscoped invocation route handling
packages/worker/src/package-invocations/http.ts, packages/worker/src/package-invocations/http.workers.test.ts
Recognizes unscoped package-invocation routes, returns owner_slug_required before token authentication on those paths, and adjusts request-routing tests.
Token-setup docs and guide text
docs/guides/account-package-invocation-token-setup.md, packages/worker/src/mcp/capabilities/coding/kody-official-guide.ts, packages/worker/src/package-invocations/public-url.node.test.ts
Clarifies the token-setup guide, updates guide metadata wording, and adds a docs check that matched invocation URLs are owner-scoped.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • kentcdodds/kody#275: Implements the package-invocation HTTP API and owner-scoped route handling that this PR extends with canonical metadata and docs.
  • kentcdodds/kody#242: Touches the MCP search formatting pipeline, which this PR extends with per-export invocation metadata.
  • kentcdodds/kody#546: Touches the same invocation-token normalization and source-scope logic used by the new URL builders and guidance text.

Poem

🐰 I hopped through routes with care and glee,
to owner-scoped URLs by the sea.
With tokens tucked in carrot packs,
my whiskers traced the API tracks.
Hop hop—safe invocations, whee!

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding guardrails around package invocation URLs.
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.
✨ 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 package-invocation-url-guardrails

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.

@kody-bot
kody-bot marked this pull request as ready for review June 26, 2026 13:41
@github-actions

github-actions Bot commented Jun 26, 2026 •

Copy link
Copy Markdown
Contributor

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

Worker: kody-pr-568
D1: kody-pr-568-db
KV: kody-pr-568-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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
docs/guides/account-package-invocation-token-setup.md (1)

148-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Clarify the invalid_token vs owner_slug_required boundary.

With the new handler, a request missing the owner slug returns owner_slug_required (404), not invalid_token, and a present-but-wrong slug returns not_found. So by the time a caller actually receives invalid_token, the route shape and slug presence are already guaranteed correct. The guidance to "first verify the endpoint includes the @:username owner slug" on an invalid_token response is therefore somewhat redundant and could re-introduce the diagnostic confusion this PR is trying to remove. Consider reframing so that invalid_token points directly at token rotation/secret correctness, while slug/route-shape checks are tied to the owner_slug_required/not_found responses.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/guides/account-package-invocation-token-setup.md` around lines 148 -
156, The guidance around `invalid_token` in the token setup doc is mixing up
route/slug validation with auth failure handling. Update the section in the
package invocation token setup guide so `invalid_token` points directly to token
rotation or external secret correctness, and move the owner slug / route-shape
checks to the `owner_slug_required` and `not_found` cases. Keep the route
examples aligned with the `@:username` pattern and make the troubleshooting flow
reflect the new handler behavior.
packages/worker/src/package-invocations/public-url.ts (1)

43-60: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant re-normalization of the export name.

routeExportName is already the normalized route segment, but it is then passed as exportName to buildPackageInvocationUrl/buildPackageInvocationPath, which internally call buildPackageInvocationRouteExportName (and thus normalizePackageInvocationExportName) again. It is idempotent so the output is correct, but passing an already-route-form value into helpers that expect a raw export name is easy to misread. Consider passing normalizedExportName (the raw-but-normalized form) to make the contract clearer, or document the intent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/package-invocations/public-url.ts` around lines 43 - 60,
The export name is being normalized twice in the public URL/path assembly, which
makes the contract of the helpers unclear. In the package-invocations/public-url
logic, use the raw normalized value from normalizePackageInvocationExportName
when calling buildPackageInvocationUrl and buildPackageInvocationPath, since
those helpers already invoke buildPackageInvocationRouteExportName internally.
Keep routeExportName only if you need the final route segment locally, otherwise
pass normalizedExportName to match the expected input shape and avoid the
misleading re-normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/shared/src/public-urls.ts`:
- Around line 42-50: The package invocation path builder is using a root-export
marker that becomes a single dot segment and gets normalized away by URL
parsers, breaking matching for root exports. Update buildPackageInvocationPath
to use a URL-safe sentinel for the root export and adjust
parsePackageInvocationPath in the worker HTTP handler to translate that sentinel
back to the root export. Keep the change consistent with
buildPackageInvocationRouteExportName so both path construction and parsing
agree on the same symbol.

In `@packages/worker/src/mcp/capabilities/packages/get-package.ts`:
- Around line 45-54: `get-package.ts` currently throws when
`resolvePublicUsername` returns null, which makes `package_get` fail entirely
instead of returning the rest of the package data. Update the `package_get` flow
to match `search-format.ts` by treating the external invocation as optional:
keep building metadata/exports/imports, and set `external_invocation` to null or
omit it when no username can be resolved. Also update the `shared.ts` schema for
`external_invocation` so it is nullable/optional, and ensure any code using
`buildExternalPackageInvocationDescriptor` or the `get-package` response handles
the missing value safely.

---

Nitpick comments:
In `@docs/guides/account-package-invocation-token-setup.md`:
- Around line 148-156: The guidance around `invalid_token` in the token setup
doc is mixing up route/slug validation with auth failure handling. Update the
section in the package invocation token setup guide so `invalid_token` points
directly to token rotation or external secret correctness, and move the owner
slug / route-shape checks to the `owner_slug_required` and `not_found` cases.
Keep the route examples aligned with the `@:username` pattern and make the
troubleshooting flow reflect the new handler behavior.

In `@packages/worker/src/package-invocations/public-url.ts`:
- Around line 43-60: The export name is being normalized twice in the public
URL/path assembly, which makes the contract of the helpers unclear. In the
package-invocations/public-url logic, use the raw normalized value from
normalizePackageInvocationExportName when calling buildPackageInvocationUrl and
buildPackageInvocationPath, since those helpers already invoke
buildPackageInvocationRouteExportName internally. Keep routeExportName only if
you need the final route segment locally, otherwise pass normalizedExportName to
match the expected input shape and avoid the misleading re-normalization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4af2c96-2676-4c70-9dd7-14bb3530e237

📥 Commits

Reviewing files that changed from the base of the PR and between b0d768f and 184332e.

📒 Files selected for processing (14)
  • docs/guides/account-package-invocation-token-setup.md
  • packages/shared/src/public-urls.ts
  • packages/worker/src/mcp/capabilities/coding/kody-official-guide.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.node.test.ts
  • packages/worker/src/mcp/capabilities/packages/get-package.ts
  • packages/worker/src/mcp/capabilities/packages/shared.ts
  • packages/worker/src/mcp/tools/search-format.node.test.ts
  • packages/worker/src/mcp/tools/search-format.ts
  • packages/worker/src/mcp/tools/search.ts
  • packages/worker/src/package-invocations/http.ts
  • packages/worker/src/package-invocations/http.workers.test.ts
  • packages/worker/src/package-invocations/public-url.node.test.ts
  • packages/worker/src/package-invocations/public-url.ts
  • packages/worker/src/package-invocations/service.ts

Comment thread packages/shared/src/public-urls.ts
Comment thread packages/worker/src/mcp/capabilities/packages/get-package.ts Outdated
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds
kentcdodds merged commit 99d7f02 into main Jun 26, 2026
5 checks passed
@kentcdodds
kentcdodds deleted the package-invocation-url-guardrails branch June 26, 2026 14:04
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.

3 participants