feat(core): add complete schema validation to all authentication flows#162
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (3)
📒 Files selected for processing (10)
📝 WalkthroughWalkthroughAdds a universal validator and a schema-registry (deriveSchema, deriveSchemaWithJWT, getFullSchema, createSchemaRegistry), tightens schema type constraints/type-guards, rewires context/session/updateSession to use SchemaRegistryContext, updates tests, and adjusts minor package/TS config entries. ChangesSchema Validation Refactoring
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (2)
packages/core/tsconfig.json (1)
8-8: ⚡ Quick winFor published packages, keep
skipLibCheckdisabled to catch type declaration errors.Setting
skipLibChecktotrueskips type-checking of.d.tsfiles from dependencies, which can hide incompatible declaration-file problems. For a published core package, TypeScript's recommended practice is to keep this disabled when validating the package's own types. Instead of masking issues, address root causes like dependency conflicts.Proposed change
- "skipLibCheck": true, + "skipLibCheck": false,🤖 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/core/tsconfig.json` at line 8, The tsconfig currently enables "skipLibCheck": true which hides declaration-file type errors; change the compiler option to "skipLibCheck": false (or remove the option) in the project's tsconfig so dependency .d.ts files are type-checked, then run the TypeScript build/emit and fix any revealed declaration or dependency type issues (resolve version mismatches, update types, or add necessary type overrides) until the build passes; look for the "skipLibCheck" key in the tsconfig to locate and update it.packages/core/src/validator/validator.ts (1)
46-50: ⚡ Quick winTypeBox validation provides no error details.
When TypeBox validation fails, the code returns a generic
Error("Validation failed")with no details about what failed. This makes debugging difficult for users. Consider using TypeBox's error reporting utilities to provide more context.💡 Consider using TypeBox's Errors utility for detailed validation errors
if (IsObject(schema)) { const isValid = Check(schema, data) - return isValid - ? { success: true, data: data as T, error: null } - : { success: false, data: null, error: new Error("Validation failed") } + if (isValid) { + return { success: true, data: data as T, error: null } + } + // Import Errors from 'typebox/value' at the top + const errors = Errors(schema, data) + return { success: false, data: null, error: Array.from(errors) } }🤖 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/core/src/validator/validator.ts` around lines 46 - 50, The current IsObject(schema) branch returns a generic Error("Validation failed") when Check(schema, data) is false; replace that generic error with a detailed validation error using TypeBox's Errors utility: call Errors(schema, data) (or Errors(CheckSchema, data) as appropriate) to collect the validation error items, format or stringify those items into a concise message, and return that message (or the error array) inside the returned error (e.g., new Error(formattedErrors)) so the function (in packages/core/src/validator/validator.ts around the IsObject/Check logic) returns meaningful validation details instead of the generic message.
🤖 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/core/package.json`:
- Line 89: The package manifest was changed to bump the dependency
"@aura-stack/router" in package.json but the pnpm lockfile is out of sync; run
pnpm install at the repo root to regenerate pnpm-lock.yaml (or pnpm install
--lockfile-only if preferred), verify the updated pnpm-lock.yaml includes the
new "@aura-stack/router@^0.7.0" entry, and commit the updated lockfile alongside
the package.json change so CI no longer errors with ERR_PNPM_OUTDATED_LOCKFILE.
In `@packages/core/src/validator/registry.ts`:
- Around line 68-77: The error-handling checks inside parseAsPartial use the
wrong schema variable; update the isZodSchema checks and the AuthValidationError
cause to reference partialSchema (the schema validated by partialValidator)
instead of schema so zod errors are formatted and attached correctly—modify the
conditional calls to isZodSchema(partialSchema), use formatZodError(error) when
partialSchema is Zod, and pass cause: isZodSchema(partialSchema) ? error :
undefined in the AuthValidationError instantiation within parseAsPartial
(references: parseAsPartial, partialValidator, partialSchema, isZodSchema,
formatZodError, AuthValidationError).
- Around line 57-66: The parse function currently only formats validation errors
for Zod (using isZodSchema and formatZodError) which leaves Valibot and ArkType
errors unformatted; update parse (the block that calls validator.validate and
throws AuthValidationError) to detect Valibot and ArkType schemas (e.g., via
isValibotSchema / isArkTypeSchema or by inspecting validator/error shape),
generate human-friendly error details with appropriate formatters (e.g.,
formatValibotError, formatArkTypeError or inline formatting logic), include
those details in the JSON.stringify output instead of an empty object, and set
the AuthValidationError cause to the original error for non-Zod cases as well so
all schema types produce consistent, informative error messages.
- Line 19: The code calls the removed Zod v4 instance method schema.loose() in
the passthrough logic; replace that call with the top-level z.looseObject(...)
usage by passing the object shape (the same schema shape used before) into
z.looseObject to produce a loose object schema. Locate the passthrough branch
that references schema.loose() in registry.ts and change it to call
z.looseObject(shape) (using the original schema shape variable) so it conforms
to Zod v4's API.
In `@packages/core/src/validator/validator.ts`:
- Around line 34-44: The current error detection in validator.ts uses shape
inspection of parsed.summary; instead compute validation failure using ArkType's
API by replacing that logic with const isError = !schema.allows(data) (keep the
existing parsed = schema(data) call so you can still return the parsed error
when isError is true). Update the block guarded by isArkType(schema) to use
schema.allows(data) for the isError check instead of checking for a summary
property, preserving the return branches that use parsed for success/error
cases.
---
Nitpick comments:
In `@packages/core/src/validator/validator.ts`:
- Around line 46-50: The current IsObject(schema) branch returns a generic
Error("Validation failed") when Check(schema, data) is false; replace that
generic error with a detailed validation error using TypeBox's Errors utility:
call Errors(schema, data) (or Errors(CheckSchema, data) as appropriate) to
collect the validation error items, format or stringify those items into a
concise message, and return that message (or the error array) inside the
returned error (e.g., new Error(formattedErrors)) so the function (in
packages/core/src/validator/validator.ts around the IsObject/Check logic)
returns meaningful validation details instead of the generic message.
In `@packages/core/tsconfig.json`:
- Line 8: The tsconfig currently enables "skipLibCheck": true which hides
declaration-file type errors; change the compiler option to "skipLibCheck":
false (or remove the option) in the project's tsconfig so dependency .d.ts files
are type-checked, then run the TypeScript build/emit and fix any revealed
declaration or dependency type issues (resolve version mismatches, update types,
or add necessary type overrides) until the build passes; look for the
"skipLibCheck" key in the tsconfig to locate and update it.
🪄 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
Run ID: e04da9e7-5dc5-4d7e-ab8a-3ec168e873d8
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (10)
package.jsonpackages/core/package.jsonpackages/core/src/@types/config.tspackages/core/src/schema-registry.tspackages/core/src/shared/assert.tspackages/core/src/validator/registry.tspackages/core/src/validator/validator.tspackages/core/test/actions/updateSession/updateSession.test.tspackages/core/test/identity.test.tspackages/core/tsconfig.json
💤 Files with no reviewable changes (1)
- package.json
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/core/src/@types/session.ts (1)
238-255: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winReplace inline
identityshapes withSchemaRegistryContext.Both
CreateSessionStrategyOptions.identityandJWTStrategyOptions.identityare structurally identical to the newly exportedSchemaRegistryContextfrom@/@types/config.ts. Importing the type keeps the registry-backed identity contract in one place; right now any change toSchemaRegistryContext(e.g. adding a field) has to be hand-mirrored in two more spots, which is exactly the kind of drift the registry refactor is trying to avoid.♻️ Proposed change
-import type { CookieStoreConfig, IdentityConfig, InternalLogger, JoseInstance } from "`@/`@types/config.ts" +import type { CookieStoreConfig, InternalLogger, JoseInstance, SchemaRegistryContext } from "`@/`@types/config.ts" @@ export interface CreateSessionStrategyOptions<Identity extends Identities> { config?: SessionConfig jose: JoseInstance<FromShapeToObject<Identity> & User> cookies: () => CookieStoreConfig logger?: InternalLogger - identity: { - schemaRegistry: ReturnType<typeof createSchemaRegistry> - skipValidation?: boolean - unknownKeys: "passthrough" | "strict" | "strip" - } + identity: SchemaRegistryContext } @@ export interface JWTStrategyOptions<DefaultUser extends User = User> { config?: StatelessStrategyConfig jose: JoseInstance<DefaultUser> logger?: InternalLogger cookies: () => CookieStoreConfig - identity: { - schemaRegistry: ReturnType<typeof createSchemaRegistry> - skipValidation?: boolean - unknownKeys: "passthrough" | "strict" | "strip" - } + identity: SchemaRegistryContext }After this, the local
createSchemaRegistryimport (line 10) and the leftoverIdentityConfigimport (line 5) are no longer needed.🤖 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/core/src/`@types/session.ts around lines 238 - 255, Replace the inline identity object types on CreateSessionStrategyOptions.identity and JWTStrategyOptions.identity with the centralized SchemaRegistryContext type exported from `@/`@types/config.ts: import SchemaRegistryContext and use it as the type for both identity properties instead of the current inline shape (which references createSchemaRegistry ReturnType and skipValidation/unknownKeys). After switching the types, remove the now-unnecessary local import of createSchemaRegistry and the leftover IdentityConfig import so the file only references the single shared SchemaRegistryContext.packages/core/src/validator/registry.ts (1)
15-41:⚠️ Potential issue | 🟠 Major | ⚡ Quick winAsymmetric
partialmode across libraries — Zod branch additionally wraps in.optional().For
mode === "partial":
- Zod (Line 22):
schema.partial().optional()— the whole object also becomes optional, soundefinedvalidates successfully andparseAsPartial(undefined)returnsundefinedinstead of{}.- Valibot (Line 31):
valibot.partial(schema)— keys partial, top-level still required.- ArkType (Line 40):
schema.partial()— keys partial, top-level still required.This divergence will surface as different runtime behavior between identity providers (e.g., Zod silently passes
undefinedwhile Valibot/ArkType reject it). Drop the trailing.optional()unless the optional-root semantics are intentional and documented.🐛 Proposed fix
- : schema.partial().optional() + : schema.partial()🤖 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/core/src/validator/registry.ts` around lines 15 - 41, The Zod branch in registry's schema normalization makes the entire object optional by returning schema.partial().optional(), causing parseAsPartial(undefined) to succeed while Valibot/ArkType still require a top-level object; update the isZodSchema branch to drop the trailing .optional() so it returns schema.partial() (keeping other modes intact) to match the valibot/ark behavior and ensure consistent semantics across isZodSchema, isValibotSchema, and isArkType handling.
🧹 Nitpick comments (5)
packages/core/src/@types/config.ts (1)
289-294: ⚡ Quick winReuse
SchemaTypesfor the generic constraint.The
ZodObject<any> | ObjectSchema<any, undefined> | Type<{}>union here is identical to the newSchemaTypesexported from@/shared/identity.ts. Reusing it removes the duplication and keeps the schema-type surface in one place if it ever needs to grow.♻️ Proposed change
-import { Identities, UserIdentity } from "`@/shared/identity.ts`" +import { Identities, UserIdentity, type SchemaTypes } from "`@/shared/identity.ts`" @@ -export interface IdentityConfig<Schema extends ZodObject<any> | ObjectSchema<any, undefined> | Type<{}> = typeof UserIdentity> { +export interface IdentityConfig<Schema extends SchemaTypes = typeof UserIdentity> { schema?: Schema schemaAsPartial?: Schema skipValidation?: boolean unknownKeys?: "passthrough" | "strict" | "strip" }🤖 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/core/src/`@types/config.ts around lines 289 - 294, Replace the duplicated union type in the IdentityConfig generic constraint with the centralized SchemaTypes export: import SchemaTypes from "`@/shared/identity.ts`" (or the named export) and change IdentityConfig<Schema extends ZodObject<any> | ObjectSchema<any, undefined> | Type<{}> = typeof UserIdentity> to use SchemaTypes (e.g., IdentityConfig<Schema extends SchemaTypes = typeof UserIdentity>); update the imports at the top of the file to reference SchemaTypes and ensure the default remains typeof UserIdentity.packages/core/test/actions/updateSession/updateSession.test.ts (1)
60-148: ⚡ Quick winReduce duplication and add a negative case for valibot/arktype tests.
The three "updates user session with X schema" tests share ~30 lines of identical setup and assertions; only
schema(and the resultinghandlers/jose) differ. Consider parameterizing withtest.each([["valibot", UserIdentityValibot], ["arktype", UserIdentityArkType]])to keep them in lockstep.Also, none of the new tests assert that the valibot/arktype validators actually reject invalid payloads — they only exercise the happy path, which the existing zod test already covers. A single negative-path test per validator (e.g., invalid
strict) would justify the added test surface and guard against the validator silently no-op'ing.🤖 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/core/test/actions/updateSession/updateSession.test.ts` around lines 60 - 148, Consolidate the two near-identical tests by parameterizing them with test.each over the schemas (UserIdentityValibot and UserIdentityArkType) and reusing the shared setup (createAuth, jose.encodeJWT, createCSRF, handlers.PATCH) and assertions; then add one negative test per validator (e.g., with the same test.each) that sends an invalid user payload (bad email format or an extra disallowed field) to handlers.PATCH and asserts a validation failure response (HTTP 400 or error body) to ensure UserIdentityValibot and UserIdentityArkType actually reject invalid input.packages/core/src/validator/registry.ts (2)
11-14: ⚖️ Poor tradeoff
: anyreturn types erase library-specific schema inference.
deriveSchema,deriveSchemaWithJWT, andgetFullSchemaall declare: any, which propagates throughcreateSchemaRegistry's returnedschema/schemaAsPartial/schemaWithJWTand downstream consumers (SchemaRegistryContext, callers in context/session). Even returningSchema(or a narrow per-branch return type) would preserve enough information for consumers to keep type-safety on the registry surface.Also applies to: 48-48, 83-83
🤖 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/core/src/validator/registry.ts` around lines 11 - 14, The current : any return types on deriveSchema, deriveSchemaWithJWT, and getFullSchema erase type inference; change their signatures to return the generic Schema (or a properly narrowed mapped type based on the mode) rather than any so the registry preserves type information—for example, update deriveSchema<Schema extends SchemaTypes>(schema: Schema, mode: ...) to return Schema or a mode-specific mapped Schema type; do the same for deriveSchemaWithJWT and getFullSchema so createSchemaRegistry's returned properties (schema, schemaAsPartial, schemaWithJWT) and downstream consumers (SchemaRegistryContext and context/session callers) retain compile-time schema types instead of any.
125-180: ⚡ Quick winExtract the duplicated error-formatting block into a helper.
The 8-line
errorDetailsdiscrimination +JSON.stringify+AuthValidationErrorthrow is repeated almost verbatim inparse,parseAsPartial, andparseWithJWT. Drift between copies has already started — note thatparseAsPartialchecksisZodSchema(schema)forerrorDetails(Lines 148/150/152) while thecausecorrectly checksschemaAsPartial(Line 157). Centralizing prevents future inconsistencies and trims ~30 lines.♻️ Proposed helper
+ const throwValidationError = (activeSchema: SchemaTypes, error: unknown): never => { + let errorDetails: unknown = {} + if (isZodSchema(activeSchema)) { + errorDetails = formatZodError(error as any) + } else if (isValibotSchema(activeSchema)) { + errorDetails = { issues: error } + } else if (isArkType(activeSchema)) { + errorDetails = { error } + } + throw new AuthValidationError( + "INVALID_IDENTITY_VALIDATION_FAILED", + JSON.stringify(errorDetails, null, 2), + { cause: isZodSchema(activeSchema) ? error : undefined } + ) + }Then each parse function becomes:
if (!success) throwValidationError(schemaAsPartial, error)🤖 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/core/src/validator/registry.ts` around lines 125 - 180, There’s duplicated error-formatting + throw logic in parse, parseAsPartial, and parseWithJWT; extract it into a helper (e.g., throwValidationError) that accepts the schema to check (schema | schemaAsPartial | schemaWithJWT) and the validator error, builds errorDetails using isZodSchema/formatZodError, isValibotSchema, isArkType, JSON.stringifys the details, and throws AuthValidationError with cause set only when isZodSchema(schemaArg) is true; then replace each failure branch in parse, parseAsPartial, and parseWithJWT with a single call like throwValidationError(schemaOrPartialOrWithJWT, error) so the cause check uses the correct schema reference and removes the duplicated block.packages/core/src/router/context.ts (1)
22-25: ⚡ Quick winNormalize
identitydefaults once before building the registry.
schemaRegistryis created from raw optional config values, butctx.identitypublishes defaulted values. That makes the registry and the exposed flags easy to desync the next time one default changes.♻️ Proposed refactor
+ const unknownKeys = config?.identity?.unknownKeys ?? "strip" + const skipValidation = config?.identity?.skipValidation ?? false + const schemaRegistry = createSchemaRegistry({ schema: config?.identity?.schema, - skipValidation: config?.identity?.skipValidation, - unknownKeys: config?.identity?.unknownKeys, + skipValidation, + unknownKeys, }) @@ identity: { schemaRegistry, - unknownKeys: config?.identity?.unknownKeys ?? "strip", - skipValidation: config?.identity?.skipValidation ?? false, + unknownKeys, + skipValidation, },Also applies to: 41-43
🤖 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/core/src/router/context.ts` around lines 22 - 25, Normalize the identity config once into a single defaulted object (e.g., let normalizedIdentity = { schema: ..., skipValidation: ..., unknownKeys: ... } or a helper like normalizeIdentity(config?.identity)) and use that normalizedIdentity when constructing schemaRegistry via createSchemaRegistry and when assigning ctx.identity (instead of reading raw optional fields). Update both the createSchemaRegistry call (currently creating schemaRegistry) and the later uses around lines referenced (41-43) to consume the same normalizedIdentity so the published ctx.identity flags and the registry stay in sync.
🤖 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/core/src/actions/updateSession/updateSession.ts`:
- Around line 7-12: The current config function calls
getFullSchema(identity.schemaRegistry.schemaAsPartial!) unguarded and will throw
when schemaAsPartial is absent; update the config in the exported config
function to first check whether identity.schemaRegistry?.schemaAsPartial exists
and only call getFullSchema when present (else set body schema to undefined or
an empty/fallback schema), then pass that conditional bodySchema into
createEndpointConfig (symbols: config, identity.schemaRegistry.schemaAsPartial,
getFullSchema, bodySchema, createEndpointConfig).
In `@packages/core/src/session/stateless.ts`:
- Around line 125-127: The early-return when updateExpires(...) yields no
expiresAt currently returns the incoming request headers variable `headers`,
which can echo request headers back; change this to return the response header
set used elsewhere (do not return `headers`) — e.g., return an empty response
headers object ({} or the module's response-headers variable) with the same
session payload (session.expires, userClaims). Update the return in the branch
containing `updateExpires({ exp: parsedClaims.exp })` so it returns `{ session:
{ expires: session.expires, user: userClaims }, headers: <response headers
object> }` instead of the incoming `headers`.
- Around line 115-117: The code calls
identity.schemaRegistry.parseWithJWT(claims) and then re-runs
identity.schemaRegistry.parse(parsedClaims), which fails strict unknownKeys
because parsedClaims still contains JWT fields (exp/iat/mexp). Fix by NOT
re-parsing the full parsedClaims; either pass only the application/user payload
into parse (e.g., extract the user-specific object from parsedClaims and call
identity.schemaRegistry.parse(userPayload)) or strip JWT fields (exp, iat, mexp,
nbf, jti) from parsedClaims before calling identity.schemaRegistry.parse;
alternatively simply use the result of parseWithJWT as the final user claims and
remove the second call to identity.schemaRegistry.parse to avoid the strict
unknownKeys error.
- Around line 180-186: The verified JWT claims are being validated with
identity.schemaRegistry.parse (via defaultPayload) which can strip or reject
standard JWT fields (exp/iat/mexp); instead use the JWT-aware/partial parser so
those JWT fields are preserved when refreshing claims. Change the logic that
sets defaultPayload to parse the verified claims with
identity.schemaRegistry.parseAsPartial (or the schema registry's JWT-aware
parse) rather than parse, keeping the subsequent sessionPayload logic intact
(i.e., use identity.schemaRegistry.parseAsPartial for claims when
identity.skipValidation is false, and keep identity.skipValidation branch
as-is).
In `@packages/core/src/validator/registry.ts`:
- Around line 137-139: The AuthValidationError currently sets cause only for Zod
schemas (throw new AuthValidationError(..., { cause: isZodSchema(schema) ? error
: undefined })); update those throws to always pass the original error object as
the cause (i.e., { cause: error }) so Valibot and ArkType errors retain their
original error instances for instanceof checks and structured logging; make the
same change in the parseAsPartial and parseWithJWT error-throwing blocks so
every validation path attaches the original error as cause.
In `@packages/core/test/identity.test.ts`:
- Line 285: The test titles inside the describe("createSchemaRegistry", ...)
block are misleading: they say "schema with '<mode>' deriveSchema" but the tests
call createSchemaRegistry({ unknownKeys }) not deriveSchema; update each test
title (including the zod, valibot, and arktype variants) to reflect the actual
API by replacing "deriveSchema" with "unknownKeys" (e.g., "zod schema with
'strip' unknownKeys" or similar), keeping the same mode strings and referencing
createSchemaRegistry so failures point to the correct function.
---
Outside diff comments:
In `@packages/core/src/`@types/session.ts:
- Around line 238-255: Replace the inline identity object types on
CreateSessionStrategyOptions.identity and JWTStrategyOptions.identity with the
centralized SchemaRegistryContext type exported from `@/`@types/config.ts: import
SchemaRegistryContext and use it as the type for both identity properties
instead of the current inline shape (which references createSchemaRegistry
ReturnType and skipValidation/unknownKeys). After switching the types, remove
the now-unnecessary local import of createSchemaRegistry and the leftover
IdentityConfig import so the file only references the single shared
SchemaRegistryContext.
In `@packages/core/src/validator/registry.ts`:
- Around line 15-41: The Zod branch in registry's schema normalization makes the
entire object optional by returning schema.partial().optional(), causing
parseAsPartial(undefined) to succeed while Valibot/ArkType still require a
top-level object; update the isZodSchema branch to drop the trailing .optional()
so it returns schema.partial() (keeping other modes intact) to match the
valibot/ark behavior and ensure consistent semantics across isZodSchema,
isValibotSchema, and isArkType handling.
---
Nitpick comments:
In `@packages/core/src/`@types/config.ts:
- Around line 289-294: Replace the duplicated union type in the IdentityConfig
generic constraint with the centralized SchemaTypes export: import SchemaTypes
from "`@/shared/identity.ts`" (or the named export) and change
IdentityConfig<Schema extends ZodObject<any> | ObjectSchema<any, undefined> |
Type<{}> = typeof UserIdentity> to use SchemaTypes (e.g., IdentityConfig<Schema
extends SchemaTypes = typeof UserIdentity>); update the imports at the top of
the file to reference SchemaTypes and ensure the default remains typeof
UserIdentity.
In `@packages/core/src/router/context.ts`:
- Around line 22-25: Normalize the identity config once into a single defaulted
object (e.g., let normalizedIdentity = { schema: ..., skipValidation: ...,
unknownKeys: ... } or a helper like normalizeIdentity(config?.identity)) and use
that normalizedIdentity when constructing schemaRegistry via
createSchemaRegistry and when assigning ctx.identity (instead of reading raw
optional fields). Update both the createSchemaRegistry call (currently creating
schemaRegistry) and the later uses around lines referenced (41-43) to consume
the same normalizedIdentity so the published ctx.identity flags and the registry
stay in sync.
In `@packages/core/src/validator/registry.ts`:
- Around line 11-14: The current : any return types on deriveSchema,
deriveSchemaWithJWT, and getFullSchema erase type inference; change their
signatures to return the generic Schema (or a properly narrowed mapped type
based on the mode) rather than any so the registry preserves type
information—for example, update deriveSchema<Schema extends SchemaTypes>(schema:
Schema, mode: ...) to return Schema or a mode-specific mapped Schema type; do
the same for deriveSchemaWithJWT and getFullSchema so createSchemaRegistry's
returned properties (schema, schemaAsPartial, schemaWithJWT) and downstream
consumers (SchemaRegistryContext and context/session callers) retain
compile-time schema types instead of any.
- Around line 125-180: There’s duplicated error-formatting + throw logic in
parse, parseAsPartial, and parseWithJWT; extract it into a helper (e.g.,
throwValidationError) that accepts the schema to check (schema | schemaAsPartial
| schemaWithJWT) and the validator error, builds errorDetails using
isZodSchema/formatZodError, isValibotSchema, isArkType, JSON.stringifys the
details, and throws AuthValidationError with cause set only when
isZodSchema(schemaArg) is true; then replace each failure branch in parse,
parseAsPartial, and parseWithJWT with a single call like
throwValidationError(schemaOrPartialOrWithJWT, error) so the cause check uses
the correct schema reference and removes the duplicated block.
In `@packages/core/test/actions/updateSession/updateSession.test.ts`:
- Around line 60-148: Consolidate the two near-identical tests by parameterizing
them with test.each over the schemas (UserIdentityValibot and
UserIdentityArkType) and reusing the shared setup (createAuth, jose.encodeJWT,
createCSRF, handlers.PATCH) and assertions; then add one negative test per
validator (e.g., with the same test.each) that sends an invalid user payload
(bad email format or an extra disallowed field) to handlers.PATCH and asserts a
validation failure response (HTTP 400 or error body) to ensure
UserIdentityValibot and UserIdentityArkType actually reject invalid input.
🪄 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
Run ID: 38b792f2-d173-44e4-a195-1fae981d5f9c
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (19)
package.jsonpackages/core/src/@types/config.tspackages/core/src/@types/session.tspackages/core/src/actions/callback/callback.tspackages/core/src/actions/updateSession/updateSession.tspackages/core/src/createAuth.tspackages/core/src/router/context.tspackages/core/src/session/stateless.tspackages/core/src/shared/identity.tspackages/core/src/validator/registry.tspackages/core/src/validator/validator.tspackages/core/test/actions/updateSession/updateSession.test.tspackages/core/test/identity.test.tspackages/elysia/package.jsonpackages/express/package.jsonpackages/hono/package.jsonpackages/next/package.jsonpackages/react-router/package.jsonpackages/react/package.json
✅ Files skipped from review due to trivial changes (8)
- packages/core/src/actions/callback/callback.ts
- packages/next/package.json
- packages/react/package.json
- packages/express/package.json
- packages/hono/package.json
- packages/core/src/createAuth.ts
- packages/elysia/package.json
- packages/react-router/package.json
Description
This pull request adds complete schema validation coverage across all authentication flows in the library, including full support for:
Validation is now consistently applied throughout the authentication system, including the
PATCH /sessionendpoint used to update session identity fields such as:subemailnameimageand any additional fields defined by the configured identity schema.
Additionally, this update improves HTTP status handling for schema validation failures. Validation errors related to request parameters, search parameters, or request bodies now correctly return
422 Unprocessable Entityinstead of401 Unauthorized.Key Changes
PATCH /session401→422@aura-stack/routerdependency from0.6.0to0.7.0@aura-stack/router@0.7.0Related PRs