Skip to content

add social login to auth#28

Merged
cobraprojects merged 4 commits into
mainfrom
social-login
May 8, 2026
Merged

add social login to auth#28
cobraprojects merged 4 commits into
mainfrom
social-login

Conversation

@cobraprojects
Copy link
Copy Markdown
Owner

@cobraprojects cobraprojects commented May 7, 2026

Summary by CodeRabbit

  • New Features

    • Added Google and GitHub OAuth sign-in links and callback endpoints across apps.
  • Documentation

    • Updated social login, forms, and validation guides for env-based redirects and the new callback flow.
  • Refactor

    • Unified response-cookie handling across adapters and auth runtime.
    • Forms/validation now treat password fields as password/sensitive types.
  • Bug Fixes

    • Client now clears sensitive fields (passwords, marked sensitive) on failed form submissions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aee67a99-5359-4fb5-b59f-7c74c745737b

📥 Commits

Reviewing files that changed from the base of the PR and between a18c1c2 and 6e24bcd.

📒 Files selected for processing (2)
  • packages/forms/src/contracts.ts
  • packages/forms/tests/contracts.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/forms/tests/contracts.test.ts
  • packages/forms/src/contracts.ts

📝 Walkthrough

Walkthrough

This PR adds Google/GitHub OAuth routes and callback handlers across Next/Nuxt/SvelteKit, refactors social callbacks to return structured results, centralizes response-cookie propagation via adapter/runtime appendResponseCookie hooks, and makes forms validation schema-aware for sensitive/password fields while updating tests and docs.

Changes

OAuth Social Authentication & Cookie Handling

Layer / File(s) Summary
Validation & Forms Contracts
packages/validation/*, packages/forms/*
Adds field.password() / .sensitive(), FieldDefinition.sensitive, schema-aware sanitization/clearing, and structured form-failure types/options.
Forms Client Behavior
packages/forms/src/*
Submission serialization and creation accept an optional schemaDefinition; client applyServerState clears sensitive fields using schema-aware helpers.
Social Callback Contracts
packages/auth-social/src/index.ts
callback() now returns SocialCallbackResult union (success/failure) and runtime bindings moved to a global symbol.
Auth Runtime & Holo Contracts
packages/auth/src/contracts.ts, packages/core/src/portable/holo.ts
Adds optional appendResponseCookie to AuthRuntimeContext and request auth accessors; request-aware auth context exposes it.
Auth Runtime Integration
packages/auth/src/runtime.ts
Introduces appendResponseCookies() helper and uses it during session establishment and logout flows.
Next.js Adapter
packages/adapter-next/src/runtime.ts, packages/adapter-next/src/config.ts
Parses Set-Cookie strings, provides appendResponseCookie that writes to Next's cookies store, and resolves optional serverExternalPackages from project package.json.
Nuxt Adapter
packages/adapter-nuxt/src/runtime/composables/index.ts, apps/blog-nuxt/server/lib/request.ts
Adds toWebRequest H3Event→Request adapter and appendResponseCookie implementation that appends Set-Cookie headers to event.node.res.
SvelteKit Adapter
packages/adapter-sveltekit/src/index.ts, packages/auth/src/sveltekit/server.ts
Uses a global AsyncLocalStorage-backed request store, adds cookie parsing, and exposes appendResponseCookie that uses cookies.set.
Social Auth Implementation
packages/auth-social/src/index.ts
Validates OAuth params, returns structured callback results, and defers session creation/login to caller code that uses auth.guard(...).loginUsing(...).
OAuth Redirect Routes
apps/*/app/auth/{github,google}/route.ts, apps/*/server/routes/auth/{github,google}.get.ts
Implements GET redirect handlers invoking redirect(provider, request) to start provider auth.
OAuth Callback Routes
apps/*/app/auth/*/callback/route.ts, apps/*/server/routes/auth/*/callback.get.ts
Callback handlers inspect callback() result, return JSON errors on failure, perform auth.guard(result.guard).loginUsing(result.user) on success, and redirect to /admin.
App API Handlers
apps/*/app/api/*, apps/*/server/api/*
Removed manual set-cookie header construction from login/register/logout/related handlers; handlers now return submission.fail() shaped failures and rely on adapter/runtime appenders for cookies.
Login Page UI
apps/blog-next/app/login/page.tsx, apps/blog-nuxt/app/pages/login.vue, apps/blog-sveltekit/src/routes/login/+page.svelte
Adds "Continue with Google" and "Continue with GitHub" links and styling.
Tests & Integration
packages/*/tests/*, tests/example-app-auth-flow.mjs
Updated tests for appendResponseCookie behavior, adapter cookie parsing, structured social callback results, and expanded E2E negative cases (throttling, token/verification/reset errors).
Documentation
apps/docs/docs/*
Updates examples to use validate()/submission.fail(), field.password() for passwords, env-based provider redirect URIs, and updated callback handling guidance.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I hopped through code with a twitchy nose,

OAuth links bloom where the login goes.
Cookies now append through one clean door,
Tests and docs sing — less header chores.
Hooray — social login, ready to explore!

✨ 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 social-login

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (3)
packages/auth/tests/package.test.ts (1)

774-805: ⚡ Quick win

Consider also exercising an async appendResponseCookie.

The new test validates the sync path. Since the contract allows void | Promise<void>, a small additional assertion (or a second test) using an async implementation would lock in that the runtime awaits the hook before resolving loginUsing/logout. Otherwise a regression that fires-and-forgets the hook would slip through.

🤖 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/auth/tests/package.test.ts` around lines 774 - 805, The test only
verifies the synchronous appendResponseCookie path; add a case that
registers/configures the runtime with an async appendResponseCookie
implementation (returns a Promise and pushes to appendedCookies after a small
await) and then call register/loginUsing and logout to assert the test waits for
the async hook to complete (i.e., appendedCookies contains cookies after
loginUsing and logout). Update the existing test or add a new it block that uses
configureAuthRuntime with context.appendResponseCookie as an async function and
asserts appendedCookies matches established.cookies and then appendedCookies
includes loggedOut.cookies after logout to ensure loginUsing/logout await the
hook.
apps/blog-sveltekit/src/routes/auth/google/+server.ts (1)

3-5: 💤 Low value

Use SvelteKit's typed RequestHandler from ./$types.

The inline type annotation { request: Request } works but bypasses SvelteKit's generated types. Using RequestHandler keeps the signature in sync with route-specific params, cookies, and locals if this endpoint ever needs them.

♻️ Suggested refactor
 import { redirect } from '@holo-js/auth-social'
+import type { RequestHandler } from './$types'

-export function GET({ request }: { request: Request }): Promise<Response> {
-  return redirect('google', request)
-}
+export const GET: RequestHandler = async ({ request }) => redirect('google', request)
🤖 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 `@apps/blog-sveltekit/src/routes/auth/google/`+server.ts around lines 3 - 5,
Change the GET handler to use SvelteKit's generated RequestHandler type from
./$types: import the type RequestHandler and update the exported handler
signature to use RequestHandler (e.g., export const GET: RequestHandler = async
({ request, params, cookies, locals }) => ...) so the route stays in sync with
route-specific params/cookies/locals and still calls the existing redirect(...)
helper; keep the same return behavior (Promise<Response>) and ensure the handler
destructures request from the provided argument as before.
packages/adapter-sveltekit/src/index.ts (1)

43-57: ⚡ Quick win

Implicit cross-package contract via globalThis.__holoSvelteKitRequestEventStore key.

Both packages/adapter-sveltekit/src/index.ts and packages/auth/src/sveltekit/server.ts independently define getSvelteKitRequestEventStore() using the same globalThis.__holoSvelteKitRequestEventStore key (but typed differently — AsyncLocalStorage<SvelteKitRequestEvent> here vs. AsyncLocalStorage<SvelteKitStoredRequestEvent> in server.ts). The architecture is intentional (avoiding a circular package dependency), but the key is an unprotected implicit contract: renaming it in one file silently breaks response-cookie appending for all auth operations covered by the auth-server handle hooks, with no type or build error.

Consider extracting the key name as a shared constant in an internal utility, or at minimum add a co-location comment in both files referencing the shared contract.

💡 Minimal approach: document the shared contract
+// NOTE: This key is shared with packages/auth/src/sveltekit/server.ts.
+// Both files must use the same string to coordinate on the same ALS instance.
 type SvelteKitRuntimeGlobal = typeof globalThis & {
   __holoSvelteKitRequestEventStore?: AsyncLocalStorage<SvelteKitRequestEvent>
 }
🤖 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/adapter-sveltekit/src/index.ts` around lines 43 - 57, The global key
__holoSvelteKitRequestEventStore is an implicit cross-package contract used by
getSvelteKitRequestEventStore() in this file and a similarly named function in
packages/auth; to prevent silent breakage, extract that string into a shared
internal constant (e.g., HoloSvelteKitRequestEventStoreKey) in a tiny
cross-package utility or shared types module and import it here and in
packages/auth, or at minimum add a prominent co-location comment in both
getSvelteKitRequestEventStore() implementations documenting the exact key, its
expected AsyncLocalStorage type (AsyncLocalStorage<SvelteKitRequestEvent> vs
AsyncLocalStorage<SvelteKitStoredRequestEvent>), and that both files must 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 `@apps/blog-sveltekit/src/routes/auth/google/callback/`+server.ts:
- Around line 19-20: The guest-only guard is not covering the OAuth callback
routes so runWithSvelteKitRequestEvent is never invoked and AsyncLocalStorage
isn’t established; update the guestOnly configuration in hooks.server.ts to
include '/auth/google/callback' and '/auth/github/callback' in the routes array
(e.g., add those strings to the routes passed to guestOnly) or alternatively
ensure the callback handler (the function that calls auth.guard(...).loginUsing
and redirect) is wrapped with runWithSvelteKitRequestEvent so
appendResponseCookies runs with a valid SvelteKit request event store.

In `@apps/docs/docs/auth/social-login.md`:
- Around line 216-218: Update the callback flow bullet that currently says the
callback “establishes a local authenticated session” so it covers both session
and token-based guards; change the wording to note that the callback either
establishes a local session (when using a session guard and loginUsing()) or
returns an authenticated user (which can be used to create an access token for
token guards), referencing the existing loginUsing() guidance and the
token-guard note for clarity.

In `@packages/adapter-next/src/config.ts`:
- Around line 81-84: The JSON.parse call in config resolution can throw on
malformed package.json; wrap the read+parse in a try/catch inside the function
that builds the parsed variable (the block assigning parsed from JSON.parse in
packages/adapter-next/src/config.ts) and on any error log/debug if appropriate
and return undefined so withHolo()/Next config loading degrades to “no optional
externals”; ensure you still validate that parsed is an object/ not an array
(the existing checks) after successful parse.

In `@tests/example-app-auth-flow.mjs`:
- Around line 157-165: The test's assertSocialRedirect currently asserts
result.response.status === 302 which is brittle; update the assert in
assertSocialRedirect to accept any 3xx response (e.g.,
assert.ok(result.response.status >= 300 && result.response.status < 400,
'Expected redirect status in 3xx range') ), and adjust the assertion message
accordingly; leave the rest of the function (location extraction,
authorizationUrl checks, and state assertion) unchanged so location,
authorizationUrl.origin/pathname, and state validation still run.
- Around line 303-316: The throttled-login uses Date.now() inside the retry loop
which changes the email each attempt and can avoid the IP+email throttle; fix by
computing a single stable email before the loop (e.g., const throttledEmail =
`${appName}-throttled-login-${Date.now()}@app.test`) and then call
fetchAuthJson('/api/login', { fields: { email: throttledEmail, password:
'wrong-password' }, ... }) inside the for loop, keeping the rest
(throttleLoginIp headers, allowFailure flag) unchanged so throttledLogin and
assertThrottleFailure() exercise a deterministic throttling scenario.

---

Nitpick comments:
In `@apps/blog-sveltekit/src/routes/auth/google/`+server.ts:
- Around line 3-5: Change the GET handler to use SvelteKit's generated
RequestHandler type from ./$types: import the type RequestHandler and update the
exported handler signature to use RequestHandler (e.g., export const GET:
RequestHandler = async ({ request, params, cookies, locals }) => ...) so the
route stays in sync with route-specific params/cookies/locals and still calls
the existing redirect(...) helper; keep the same return behavior
(Promise<Response>) and ensure the handler destructures request from the
provided argument as before.

In `@packages/adapter-sveltekit/src/index.ts`:
- Around line 43-57: The global key __holoSvelteKitRequestEventStore is an
implicit cross-package contract used by getSvelteKitRequestEventStore() in this
file and a similarly named function in packages/auth; to prevent silent
breakage, extract that string into a shared internal constant (e.g.,
HoloSvelteKitRequestEventStoreKey) in a tiny cross-package utility or shared
types module and import it here and in packages/auth, or at minimum add a
prominent co-location comment in both getSvelteKitRequestEventStore()
implementations documenting the exact key, its expected AsyncLocalStorage type
(AsyncLocalStorage<SvelteKitRequestEvent> vs
AsyncLocalStorage<SvelteKitStoredRequestEvent>), and that both files must stay
in sync.

In `@packages/auth/tests/package.test.ts`:
- Around line 774-805: The test only verifies the synchronous
appendResponseCookie path; add a case that registers/configures the runtime with
an async appendResponseCookie implementation (returns a Promise and pushes to
appendedCookies after a small await) and then call register/loginUsing and
logout to assert the test waits for the async hook to complete (i.e.,
appendedCookies contains cookies after loginUsing and logout). Update the
existing test or add a new it block that uses configureAuthRuntime with
context.appendResponseCookie as an async function and asserts appendedCookies
matches established.cookies and then appendedCookies includes loggedOut.cookies
after logout to ensure loginUsing/logout await the hook.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: dfe8ec65-eca1-46ec-9d47-c6373be814b1

📥 Commits

Reviewing files that changed from the base of the PR and between c6a8265 and 53b2b3c.

📒 Files selected for processing (42)
  • apps/blog-next/app/api/login/route.ts
  • apps/blog-next/app/api/logout/route.ts
  • apps/blog-next/app/api/register/route.ts
  • apps/blog-next/app/auth/github/callback/route.ts
  • apps/blog-next/app/auth/github/route.ts
  • apps/blog-next/app/auth/google/callback/route.ts
  • apps/blog-next/app/auth/google/route.ts
  • apps/blog-next/app/login/page.tsx
  • apps/blog-nuxt/app/pages/login.vue
  • apps/blog-nuxt/server/api/login.post.ts
  • apps/blog-nuxt/server/api/logout.post.ts
  • apps/blog-nuxt/server/api/register.post.ts
  • apps/blog-nuxt/server/lib/request.ts
  • apps/blog-nuxt/server/routes/auth/github.get.ts
  • apps/blog-nuxt/server/routes/auth/github/callback.get.ts
  • apps/blog-nuxt/server/routes/auth/google.get.ts
  • apps/blog-nuxt/server/routes/auth/google/callback.get.ts
  • apps/blog-sveltekit/src/routes/api/login/+server.ts
  • apps/blog-sveltekit/src/routes/api/logout/+server.ts
  • apps/blog-sveltekit/src/routes/api/register/+server.ts
  • apps/blog-sveltekit/src/routes/auth/github/+server.ts
  • apps/blog-sveltekit/src/routes/auth/github/callback/+server.ts
  • apps/blog-sveltekit/src/routes/auth/google/+server.ts
  • apps/blog-sveltekit/src/routes/auth/google/callback/+server.ts
  • apps/blog-sveltekit/src/routes/login/+page.svelte
  • apps/docs/docs/auth/social-login.md
  • packages/adapter-next/src/config.ts
  • packages/adapter-next/src/runtime.ts
  • packages/adapter-next/tests/adapter.test.ts
  • packages/adapter-nuxt/src/runtime/composables/index.ts
  • packages/adapter-nuxt/tests/module.test.ts
  • packages/adapter-sveltekit/src/index.ts
  • packages/adapter-sveltekit/tests/runtime.test.ts
  • packages/auth-social/src/index.ts
  • packages/auth-social/tests/package.test.ts
  • packages/auth/src/contracts.ts
  • packages/auth/src/runtime.ts
  • packages/auth/src/sveltekit/server.ts
  • packages/auth/tests/package.test.ts
  • packages/core/src/portable/holo.ts
  • scripts/validate-framework-smoke.mjs
  • tests/example-app-auth-flow.mjs
💤 Files with no reviewable changes (4)
  • apps/blog-nuxt/server/api/register.post.ts
  • apps/blog-nuxt/server/api/login.post.ts
  • apps/blog-next/app/api/register/route.ts
  • apps/blog-sveltekit/src/routes/api/register/+server.ts

Comment on lines +19 to +20
await auth.guard(result.guard).loginUsing(result.user)
throw redirect(303, '/admin')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the SvelteKit blog app's hooks.server.ts for runWithSvelteKitRequestEvent coverage
fd -e ts 'hooks.server' apps/blog-sveltekit --exec cat {}

Repository: cobraprojects/holo-js

Length of output: 409


🏁 Script executed:

# Find the `@holo-js/auth` package implementation of guestOnly and authOnly
fd -type f -name '*.ts' | xargs rg -l 'export.*guestOnly|export.*authOnly' | head -20

Repository: cobraprojects/holo-js

Length of output: 488


🏁 Script executed:

# Verify the exact file path of the callback handler
find apps/blog-sveltekit -type f -name '+server.ts' | grep -i callback

Repository: cobraprojects/holo-js

Length of output: 191


🏁 Script executed:

# Check if there are any other references to the callback route or auth routes in hooks
rg 'auth/google|callback' apps/blog-sveltekit

Repository: cobraprojects/holo-js

Length of output: 753


🏁 Script executed:

# Read the guestOnly and authOnly implementations
cat packages/auth/src/sveltekit/server.ts

Repository: cobraprojects/holo-js

Length of output: 6098


🏁 Script executed:

# Find the adapter-sveltekit implementation
fd -type f -name '*.ts' -path '*/adapter-sveltekit/*' | head -20

Repository: cobraprojects/holo-js

Length of output: 236


🏁 Script executed:

# Search for appendResponseCookie implementation
rg -A 10 'appendResponseCookie' packages/auth/src/sveltekit

Repository: cobraprojects/holo-js

Length of output: 47


🏁 Script executed:

# Search for appendResponseCookie more broadly
rg 'appendResponseCookie' --max-count=50

Repository: cobraprojects/holo-js

Length of output: 2259


🏁 Script executed:

# Find all files in packages/auth
find packages/auth -type f -name '*.ts' | head -20

Repository: cobraprojects/holo-js

Length of output: 708


🏁 Script executed:

# Read the adapter-sveltekit implementation
cat packages/adapter-sveltekit/src/index.ts

Repository: cobraprojects/holo-js

Length of output: 5695


🏁 Script executed:

# Read the actual callback handler to confirm the flow
cat apps/blog-sveltekit/src/routes/auth/google/callback/+server.ts

Repository: cobraprojects/holo-js

Length of output: 636


🏁 Script executed:

# Verify the loginUsing flow by checking auth/src/runtime.ts
rg -A 20 'async function appendResponseCookies' packages/auth/src/runtime.ts

Repository: cobraprojects/holo-js

Length of output: 572


🏁 Script executed:

# Check if there's any other mechanism that might populate ALS for the callback route
rg 'runWithSvelteKitRequestEvent' apps/blog-sveltekit

Repository: cobraprojects/holo-js

Length of output: 47


Add callback routes to guestOnly guard in hooks.server.ts.

The /auth/google/callback and /auth/github/callback routes are not covered by the guestOnly or authOnly handlers in hooks.server.ts. This means runWithSvelteKitRequestEvent is never called for these routes, so the AsyncLocalStorage context is not established. When loginUsing() calls appendResponseCookies(), the session cookie call reaches appendResponseCookie in the adapter, which silently returns without setting the cookie because getSvelteKitRequestEventStore().getStore() is undefined. The session is created server-side but the cookie is never sent to the client—the user is redirected to /admin but arrives unauthenticated.

Add both callback routes to the guestOnly routes list (or wrap the handler with runWithSvelteKitRequestEvent if they should be auth-required):

guestOnly({
  routes: ['/login', '/register', '/forgot-password', '/reset-password', '/auth/google/callback', '/auth/github/callback'],
  redirectTo: '/admin',
})
🤖 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 `@apps/blog-sveltekit/src/routes/auth/google/callback/`+server.ts around lines
19 - 20, The guest-only guard is not covering the OAuth callback routes so
runWithSvelteKitRequestEvent is never invoked and AsyncLocalStorage isn’t
established; update the guestOnly configuration in hooks.server.ts to include
'/auth/google/callback' and '/auth/github/callback' in the routes array (e.g.,
add those strings to the routes passed to guestOnly) or alternatively ensure the
callback handler (the function that calls auth.guard(...).loginUsing and
redirect) is wrapped with runWithSvelteKitRequestEvent so appendResponseCookies
runs with a valid SvelteKit request event store.

Comment thread apps/docs/docs/auth/social-login.md
Comment thread packages/adapter-next/src/config.ts Outdated
Comment thread tests/example-app-auth-flow.mjs
Comment thread tests/example-app-auth-flow.mjs
apps/blog-sveltekit/src/hooks.server.ts: did not add /auth/google/callback and /auth/github/callback to guestOnly.routes.

Reason: after checking the current framework implementation, packages/auth/src/sveltekit/server.ts wraps the entire guestOnly handler body in runWithSvelteKitRequestEvent(event, ...) before it checks matchesRoutes(...). That means even routes not matched by guestOnly.routes, including OAuth callbacks, still run inside the SvelteKit AsyncLocalStorage context when resolve(event) is called. The reported issue said ALS was not established for callbacks unless the callback routes were listed, but that is not true in the current code.

apps/blog-sveltekit/src/routes/auth/google/callback/+server.ts: did not wrap the callback handler directly with runWithSvelteKitRequestEvent.

Reason: same root cause as above. The framework-level SvelteKit handle already establishes the request-event store before route resolution reaches this callback handler. Adding a second manual wrapper in the route would duplicate framework integration logic in userland/example code, which goes against the repo’s API discipline for auth flows.
@cobraprojects
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

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 (1)
packages/forms/src/client.ts (1)

133-166: ⚡ Quick win

normalizeFailureInput and normalizeFailureErrors are duplicated verbatim in contracts.ts

Both functions (lines 135–168 in contracts.ts) are identical to this implementation. If one copy diverges — say, to handle a new edge case — server and client failure payloads will silently behave differently.

client.ts already imports types from contracts.ts, so the simplest fix is to export these two utilities from contracts.ts (or a dedicated internal module) and import them here instead.

♻️ Option A — export from contracts.ts and re-import

In contracts.ts, change the private declarations to exported ones:

-function normalizeFailureInput(input: FormFailureInput, fallbackStatus: number): {
+export function normalizeFailureInput(input: FormFailureInput, fallbackStatus: number): {
   readonly status: number
   readonly errors?: FormFailureErrors
 } { ... }

-function normalizeFailureErrors(
+export function normalizeFailureErrors(
   fallback: Record<string, readonly string[]>,
   override: FormFailureErrors | undefined,
 ): Record<string, readonly string[]> { ... }

In client.ts, remove the duplicate bodies and import from contracts.ts:

 import type {
   FormFailureErrors,
   FormFailureInput,
   ...
 } from './contracts'
+import { normalizeFailureInput, normalizeFailureErrors } from './contracts'

Then delete lines 133–166 of client.ts.

🤖 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/forms/src/client.ts` around lines 133 - 166, Duplicate
implementations of normalizeFailureInput and normalizeFailureErrors exist in
client.ts and contracts.ts; remove the duplication by exporting these utilities
from contracts.ts and importing them in client.ts. Modify contracts.ts to export
normalizeFailureInput and normalizeFailureErrors (or move both into a shared
internal module and export them), then in packages/forms/src/client.ts delete
the local function bodies for normalizeFailureInput and normalizeFailureErrors
and add imports that reference the exported symbols from contracts.ts (or the
shared module) so both client and server use the single shared implementation.
🤖 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/adapter-sveltekit/src/index.ts`:
- Around line 27-35: Add support for the Partitioned cookie attribute by adding
a partitioned?: boolean field to the SvelteKitCookieOptions type and updating
the parseResponseCookie switch in parseResponseCookie to handle the
'partitioned' attribute (set options.partitioned = true or parse a boolean if a
value is provided) so the parsed cookie options are passed through to
event.cookies.set(); modify the switch inside the parseResponseCookie function
to include a 'partitioned' case that sets the partitioned flag on the options
object.

In `@packages/forms/src/sensitiveInput.ts`:
- Around line 103-109: The code in sanitizeFlashedInput creates only a shallow
clone (output = Object.fromEntries(...)) so deletePath(output, path) mutates
nested structures inside the original values; change to a deep clone before
deleting sensitive nested paths (e.g., use structuredClone(values) or your
project deepClone util) and then run deletePath against that deep-cloned output;
apply the same deep-clone fix to the second occurrence around the 114-119 block
so callers receive a non-mutating sanitized object (referencing
variables/functions: sanitizeFlashedInput, output, values, sensitivePaths, and
deletePath).

---

Nitpick comments:
In `@packages/forms/src/client.ts`:
- Around line 133-166: Duplicate implementations of normalizeFailureInput and
normalizeFailureErrors exist in client.ts and contracts.ts; remove the
duplication by exporting these utilities from contracts.ts and importing them in
client.ts. Modify contracts.ts to export normalizeFailureInput and
normalizeFailureErrors (or move both into a shared internal module and export
them), then in packages/forms/src/client.ts delete the local function bodies for
normalizeFailureInput and normalizeFailureErrors and add imports that reference
the exported symbols from contracts.ts (or the shared module) so both client and
server use the single shared implementation.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4551257-3857-4392-9c76-e361b93e6560

📥 Commits

Reviewing files that changed from the base of the PR and between 53b2b3c and f14cf73.

📒 Files selected for processing (47)
  • apps/blog-next/app/api/forgot-password/route.ts
  • apps/blog-next/app/api/login/route.ts
  • apps/blog-next/app/api/register/route.ts
  • apps/blog-next/app/api/reset-password/route.ts
  • apps/blog-next/app/api/verify-email/route.ts
  • apps/blog-next/lib/schemas/auth.ts
  • apps/blog-nuxt/server/api/forgot-password.post.ts
  • apps/blog-nuxt/server/api/login.post.ts
  • apps/blog-nuxt/server/api/register.post.ts
  • apps/blog-nuxt/server/api/reset-password.post.ts
  • apps/blog-nuxt/server/api/verify-email.post.ts
  • apps/blog-nuxt/shared/schemas/auth.ts
  • apps/blog-sveltekit/src/lib/schemas/auth.ts
  • apps/blog-sveltekit/src/routes/api/forgot-password/+server.ts
  • apps/blog-sveltekit/src/routes/api/login/+server.ts
  • apps/blog-sveltekit/src/routes/api/register/+server.ts
  • apps/blog-sveltekit/src/routes/api/reset-password/+server.ts
  • apps/blog-sveltekit/src/routes/api/verify-email/+server.ts
  • apps/blog-sveltekit/src/routes/auth/google/+server.ts
  • apps/docs/docs/auth/index.md
  • apps/docs/docs/auth/local-auth.md
  • apps/docs/docs/auth/social-login.md
  • apps/docs/docs/forms/client-usage.md
  • apps/docs/docs/forms/framework-integration.md
  • apps/docs/docs/forms/index.md
  • apps/docs/docs/forms/server-validation.md
  • apps/docs/docs/security.md
  • apps/docs/docs/validation/index.md
  • apps/docs/docs/validation/rules-and-errors.md
  • packages/adapter-next/src/config.ts
  • packages/adapter-next/tests/adapter.test.ts
  • packages/adapter-sveltekit/src/index.ts
  • packages/auth/src/sveltekit/server.ts
  • packages/auth/tests/package.test.ts
  • packages/forms/src/client.ts
  • packages/forms/src/contracts.ts
  • packages/forms/src/index.ts
  • packages/forms/src/sensitiveInput.ts
  • packages/forms/tests/client.test.ts
  • packages/forms/tests/client.type.test.ts
  • packages/forms/tests/contracts.test.ts
  • packages/forms/tests/docs-examples.test.ts
  • packages/validation/src/contracts-support.ts
  • packages/validation/src/contracts-types.ts
  • packages/validation/src/contracts.ts
  • packages/validation/tests/contracts.test.ts
  • tests/example-app-auth-flow.mjs
✅ Files skipped from review due to trivial changes (3)
  • apps/docs/docs/validation/rules-and-errors.md
  • apps/docs/docs/forms/client-usage.md
  • apps/docs/docs/auth/social-login.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • apps/blog-nuxt/server/api/login.post.ts
  • apps/blog-nuxt/server/api/register.post.ts
  • apps/blog-sveltekit/src/routes/api/register/+server.ts
  • apps/blog-next/app/api/login/route.ts
  • apps/blog-sveltekit/src/routes/api/login/+server.ts
  • packages/adapter-next/src/config.ts
  • tests/example-app-auth-flow.mjs
  • packages/auth/src/sveltekit/server.ts

Comment thread packages/adapter-sveltekit/src/index.ts
Comment thread packages/forms/src/sensitiveInput.ts Outdated
@cobraprojects
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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/forms/tests/contracts.test.ts`:
- Around line 283-299: Add a test that disambiguates replace-vs-merge semantics
by asserting that fail({ errors }) merges override errors with validation errors
rather than replacing them: when calling the same test helper used in this file
(failure.fail) simulate validation producing an error on a field the override
does not touch (e.g. token: ['Missing token']) and the override only setting
email errors, then assert the returned payload contains both token and email
errors. Update the assertion in packages/forms/tests/contracts.test.ts to
reference failure.fail and ensure normalizeFailureErrors (from contracts.ts)
preserves/merges existing validation errors into the final errors object rather
than dropping them.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d0458add-21df-43e7-a343-8ad3a4a6b398

📥 Commits

Reviewing files that changed from the base of the PR and between f14cf73 and a18c1c2.

📒 Files selected for processing (6)
  • packages/adapter-sveltekit/src/index.ts
  • packages/adapter-sveltekit/tests/runtime.test.ts
  • packages/forms/src/client.ts
  • packages/forms/src/contracts.ts
  • packages/forms/src/sensitiveInput.ts
  • packages/forms/tests/contracts.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/forms/src/sensitiveInput.ts
  • packages/adapter-sveltekit/src/index.ts
  • packages/forms/src/client.ts

Comment thread packages/forms/tests/contracts.test.ts
@cobraprojects
Copy link
Copy Markdown
Owner Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@cobraprojects cobraprojects merged commit c567556 into main May 8, 2026
1 check passed
@cobraprojects cobraprojects deleted the social-login branch May 8, 2026 11:18
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.

1 participant