fix: make Endpoint properties readonly and fix OpenAPI schema types#122
Merged
himself65 merged 1 commit intobetter-auth:mainfrom Mar 20, 2026
Merged
Conversation
Two type-level fixes that affect consumers using strict TypeScript:
1. Make `options` and `path` on `Endpoint` type readonly.
These properties were mutable, making type parameters like `Meta`
invariant. This prevented concrete endpoint types (e.g.,
`Endpoint<..., { SERVER_ONLY: true }, ...>`) from being assigned
to index signatures using bare `Endpoint`.
Making them readonly makes `Meta`, `Method`, and `Path` covariant
(read-only positions only), fixing the variance issue.
2. Add explicit `| undefined` to optional properties in
`OpenAPIParameter.schema`.
With `exactOptionalPropertyTypes: true`, `format?: string` means
"absent or string" but NOT "explicitly undefined". When endpoints
infer `format` as `string | undefined` (e.g., from optional zod
fields), this causes a type mismatch. Adding `| undefined` makes
the types compatible under strict optional property checking.
Runtime behavior is unchanged — these are type-level-only fixes.
himself65
approved these changes
Mar 20, 2026
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two type-level fixes that affect consumers using strict TypeScript configurations. No runtime behavior changes.
1.
Endpoint.optionsandEndpoint.pathare nowreadonlyThe problem:
The
Endpointtype hasoptionsandpathas mutable properties:Because
optionsis mutable, TypeScript treatsMetaas invariant — it appears in both a readable (covariant) and writable (contravariant) position. This means a concreteEndpoint<..., { SERVER_ONLY: true }, ...>is not assignable toEndpoint<..., EndpointMetadata | undefined, ...>:This is a critical issue for
better-auth, whereBetterAuthPlugin.endpointsis typed as{ [key: string]: Endpoint }and plugins produce endpoints with concrete metadata types like{ SERVER_ONLY: true },{ scope: "server" }, or{ openapi: { ... } }.Making these
readonlymakesMeta,Method, andPathcovariant — they only appear in readable positions. This allows concrete endpoint types to be assigned to wider container types.Why this is safe at runtime: These properties are only assigned during endpoint construction inside
createEndpoint()(via anas anycast at line 471), and are never mutated after. Thereadonlymodifier accurately reflects how they're used.2.
OpenAPIParameter.schemaoptional properties now include| undefinedThe problem:
With
exactOptionalPropertyTypes: true(a strict TypeScript option), there's a distinction between:format?: string— property can be absent or string, but NOT explicitly undefinedformat?: string | undefined— property can be absent, string, OR explicitly undefinedWhen endpoints infer query parameter schemas from Zod types, optional fields produce
string | undefined. WithexactOptionalPropertyTypes, this is incompatible withformat?: string: