Skip to content

feat(openapi): add allow option to OpenAPIReferenceHandlerPlugin - #1911

Merged
dinwwwh merged 2 commits into
middleapi:mainfrom
dinwwwh:claude/github-issue-1907-145b25
Aug 22, 2026
Merged

feat(openapi): add allow option to OpenAPIReferenceHandlerPlugin#1911
dinwwwh merged 2 commits into
middleapi:mainfrom
dinwwwh:claude/github-issue-1907-145b25

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Aug 21, 2026

Copy link
Copy Markdown
Member

Adds an allow option to OpenAPIReferenceHandlerPlugin so the docs UI and OpenAPI spec can be served conditionally, for example only to authenticated users. When it resolves to false, the request falls through as unmatched, as if the plugin were not installed, so unauthorized clients cannot tell the docs and spec paths exist.

Resolves #1907

Design

  • allow: Value<Promisable<boolean>, [StandardHandlerRoutingInterceptorOptions<T>]>, defaulting to true. It receives the same options as spec, docsTitle, and docsHead, so decisions can use the handler context or request headers.
  • Evaluated only after a docs/spec path matches, so no check runs on unrelated requests.

Testing

  • Denied requests return the unmatched result for both paths without generating the spec, and the predicate receives the routing interceptor options.
  • The predicate is never called for unrelated paths; behavior is unchanged when the option is omitted.
  • Docs gain a "Restricting Access" section on the plugin page.

Allows serving the docs UI and OpenAPI spec conditionally, e.g. only to
authenticated users. When allow resolves to false, the request falls
through as unmatched, as if the plugin were not installed.

Resolves middleapi#1907
@vercel

vercel Bot commented Aug 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
orpc Ready Ready Preview Aug 22, 2026 12:42am

@pkg-pr-new

pkg-pr-new Bot commented Aug 21, 2026

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@1911

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@1911

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@1911

@orpc/client

npm i https://pkg.pr.new/@orpc/client@1911

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@1911

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@1911

@orpc/experimental-effect

npm i https://pkg.pr.new/@orpc/experimental-effect@1911

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@1911

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@1911

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@1911

@orpc/experimental-msw

npm i https://pkg.pr.new/@orpc/experimental-msw@1911

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@1911

@orpc/next

npm i https://pkg.pr.new/@orpc/next@1911

@orpc/node

npm i https://pkg.pr.new/@orpc/node@1911

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@1911

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@1911

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@1911

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@1911

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@1911

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@1911

@orpc/server

npm i https://pkg.pr.new/@orpc/server@1911

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@1911

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@1911

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@1911

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@1911

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@1911

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@1911

commit: 6966814

@pullfrog pullfrog 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.

✅ No new issues found. The allow option is correctly scoped, well-typed, and the coverages genuinely exercise the new behavior.

Reviewed changes

  • allow option on OpenAPIReferenceHandlerPlugin: New allow: Value<Promisable<boolean>, [...]> option (default true), stored via options.allow ?? true. In init, it's awaited only after a GET request falls through as unmatched AND its URL matches specPath/docsPath, and before the spec is generated — so a denied request returns the original unmatched result and never touches spec, matching the "as if the plugin were not installed" contract.
  • Tests: Two new cases. The deny case loops / and /spec.json, asserts the unmatched result is returned unchanged and spec is not called, and that the predicate receives the routing options (including request.url). The allow-true case asserts allow is not invoked for unrelated paths and the spec serves with 200.
  • Docs: New ## Restricting Access section with a allow example, heading level consistent with ## Learn More.

No regressions found. The default is unchanged (allow omitted = served), the new tests fail if the gate regresses, and value()'s boolean/function handling makes the true default a no-op.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing dinwwwh:claude/github-issue-1907-145b25 (6966814) with main (416b6bc)

Open in CodSpeed

@pullfrog pullfrog 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.

✅ No new issues found. The refactor keeps the implemented behavior intact and tightens the deny contract.

Reviewed changes

  • Dropped the stored true default: this.allow = options.allow ?? truethis.allow = options.allow, and the @default true JSDoc line was removed. Omitting allow now stores undefined.
  • Stricter gate: if (!await value(this.allow, opts))if (await value(this.allow, opts) === false). This is exactly what makes dropping the default safe: value(undefined, opts) yields undefined, and undefined === false is false, so omitted allow still serves. It also prevents a predicate that happens to resolve to a falsy-but-not-false value (e.g. a missing return in an async fn) from silently denying the docs — consistent with the documented contract "when it resolves to false".
  • Tests and docs were not touched by this commit; the existing deny/allow-true/unrelated-path cases continue to cover the gate. I re-ran the plugin test file (10/10 pass) and tsc -b for @orpc/openapi (clean).

No regressions found. await value(...) === false parses as (await value(...)) === false, confirming the strict comparison applies to the resolved value.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@dinwwwh
dinwwwh merged commit 4e59295 into middleapi:main Aug 22, 2026
12 checks passed
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.

Possibility for OpenAPIReferenceHandlerPlugin to respect auth middleware

1 participant