Skip to content

feat(express): add express integration package (@aura-stack/express)#138

Merged
halvaradop merged 4 commits intomasterfrom
feat/add-express-pkg
Apr 10, 2026
Merged

feat(express): add express integration package (@aura-stack/express)#138
halvaradop merged 4 commits intomasterfrom
feat/add-express-pkg

Conversation

@halvaradop
Copy link
Copy Markdown
Member

@halvaradop halvaradop commented Apr 10, 2026

Description

This pull request introduces the @aura-stack/express package, providing seamless integration for Express applications. The package includes built-in middlewares and adapters that bridge Web Standard APIs (Request, Response) with Express’s IncomingMessage and ServerResponse.

This enables Aura Auth to run natively within Express environments while preserving compatibility with its internal Web API-based architecture.


Key Changes

  • Introduced dedicated @aura-stack/express package
  • Added built-in withAuth middleware for protected routes
  • Added built-in toHandler adapter to connect Aura Auth handlers with Express routes
  • Automatically infers user session types from createAuth
  • Updated apps/express to use the dedicated package

Usage

import express, { type Express } from "express"
import { createAuth } from "@/createAuth.ts"

const app: Express = express()

export const auth = createAuth({
  oauth: ["github"],
  basePath: "/api/auth",
})

app.use(express.json())
app.use(express.urlencoded({ extended: true }))

app.all("/api/auth/*", auth.toHandler)

app.get("/api/protected", auth.withAuth, (_, res) => {
  if (!res.locals.session) {
    return res.status(401).json({ message: "Unauthorized" })
  }

  return res.json({
    message: "You have access to this protected resource.",
    session: res.locals.session,
  })
})

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Apr 10, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
auth Skipped Skipped Apr 10, 2026 9:48pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

Warning

Rate limit exceeded

@halvaradop has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 27 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 27 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b36f2cda-af86-4e4a-87cf-066a93dbc491

📥 Commits

Reviewing files that changed from the base of the PR and between 67554ce and e0fd6d8.

📒 Files selected for processing (1)
  • packages/express/src/lib/with-auth.ts
📝 Walkthrough

Walkthrough

A new @aura-stack/express package is added, extracting Express-specific auth helpers (createAuth, withAuth, toHandler). The demo app is refactored to consume the package; auth logic and server setup are moved/renamed, tests and typings updated, and package/tooling manifests added or adjusted.

Changes

Cohort / File(s) Summary
New package metadata & tooling
packages/express/package.json, packages/express/deno.json, packages/express/tsconfig.json, packages/express/tsup.config.ts, packages/express/vitest.config.ts
Add package manifests, build/test configs, deno manifest, and Vitest config (enable globals).
@aura-stack/express public API & core
packages/express/src/index.ts, packages/express/src/createAuth.ts, packages/express/src/lib/handler.ts, packages/express/src/lib/with-auth.ts, packages/express/src/oauth/index.ts
New public entrypoint and core modules: createAuth factory, Express handler bridge (toExpressHandler/toHandler), withAuth middleware, types, and OAuth re-exports.
Package docs, changelog & tests
packages/express/README.md, packages/express/CHANGELOG.md, packages/express/test/*, packages/express/test/presets.ts, packages/express/test/types.test-d.ts
Add README, changelog, tests and test presets for Express integration and type-level assertions.
Apps/express: refactor to consume package
apps/express/src/lib/auth.ts, apps/express/src/app.ts, apps/express/src/index.ts
Move auth instantiation into src/lib/auth.ts using @aura-stack/express; new app.ts exports Express app configured with JSON/urlencoded middleware, mounted auth handler, and a protected /api/protected route; update startup import.
Apps/express: removals & cleanup
apps/express/src/auth.ts (removed), apps/express/src/lib/verify-session.ts (removed), apps/express/src/server.ts (removed), apps/express/src/types.d.ts (removed), apps/express/tsconfig.json, apps/express/package.json, apps/express/README.md
Remove previous inline auth modules and verifySession middleware; delete global Express Locals session typing; simplify tsconfig; update package.json deps/scripts and README formatting/content.
apps/express package manifest change
apps/express/package.json
Add workspace dependency on @aura-stack/express, remove supertest and its types, remove test:run script, update metadata and license.
Test updates
packages/express/test/index.test.ts
Update tests to use auth preset, adjust JWT encoding calls and expected unauthorized response, and add tests for credential sign-in and session patch endpoints.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Express as "Express App"
    participant withAuth as "withAuth Middleware"
    participant AuthAPI as "Auth API (api.getSession)"
    participant Handler as "Route Handler"
    participant Response

    Client->>Express: HTTP Request
    Express->>withAuth: invoke middleware
    withAuth->>AuthAPI: getSession(headers)
    AuthAPI-->>withAuth: session | null
    withAuth->>Express: set res.locals.session
    withAuth->>Handler: next()
    alt session exists
        Handler->>Response: 200 + session data
    else session missing
        Handler->>Response: 401 { message: "Unauthorized" }
    end
    Response-->>Client: HTTP Response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

feature, enhancement

Poem

🐰 A tidy lib hops into place,
handlers and middleware find their space.
withAuth guards the burrowed door,
toHandler bridges web to core,
now auth and app both leap—encore! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing a new Express integration package (@aura-stack/express) with clear, specific language.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-express-pkg

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 and usage tips.

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: 4

🧹 Nitpick comments (1)
packages/express/test/index.test.ts (1)

25-29: Consider deduplicating the repeated JWT payload setup.

Both tests construct the same token payload; extracting a small helper/fixture would reduce drift risk in future edits.

Also applies to: 67-71

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/express/test/index.test.ts` around lines 25 - 29, Extract the
repeated JWT payload used with auth.jose.encodeJWT into a shared test
fixture/helper (e.g., a const jwtPayload or function makeTestJwtPayload and/or
helper makeSessionToken that calls auth.jose.encodeJWT) and replace the
duplicate inline payloads in the tests that call auth.jose.encodeJWT (the
occurrences around the current tests and the ones at lines ~67-71) to use the
shared helper; ensure the helper is exported or available in the test scope so
both tests import/use the same payload/creation logic to avoid drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/express/src/app.ts`:
- Around line 12-18: The handler currently sends a 401 with
res.status(401).json({ message: "Unauthorized" }) but does not stop execution,
causing a second res.json(...) send and a "Cannot set headers after they are
sent" crash; change the control flow around the res.locals.session check in
app.ts to return immediately after sending the 401 (or use an else block) so
execution does not fall through to the subsequent res.json(...) that references
res.locals.session.

In `@packages/express/package.json`:
- Around line 19-20: The package.json scripts use "prepublish" and run
"clean:cts" which is deprecated and can run at install time; change the
lifecycle hook to "prepublishOnly" and update the "clean:cts" script to guard
against a missing dist directory (e.g., test for existence of dist before
running find) so the command returns zero when dist is absent; update the
"clean:cts" and replace the "prepublish" entry with "prepublishOnly" in
package.json to ensure cleanup runs only on publish and does not fail when dist/
doesn't exist.

In `@packages/express/test/presets.ts`:
- Around line 12-18: The handler currently checks res.locals.session then calls
res.status(401).json(...) but does not return, so execution continues and later
calls res.json(...) again; update the control flow in the block that inspects
res.locals.session so that after sending the 401 response you return immediately
(e.g., add a return before/after res.status(401).json(...)), and likewise ensure
the success path returns after sending the JSON response to avoid
double-response errors; locate the conditional using res.locals.session and the
two res.json/res.status calls to apply the fixes.

In `@packages/express/test/types.test-d.ts`:
- Around line 9-13: The test assertions wrongly expect res.locals.session to
allow undefined and be optional; update the two type assertions to match the
middleware's LocalsWithSession from with-auth.ts by removing "| undefined" from
the concrete type and removing the optional property form—i.e., assert
res.locals.session is exactly Session<ShapeToObject<EditableShape<UserShape>>> |
null (no undefined) and assert res.locals equals an object with a required
session: Session<ShapeToObject<EditableShape<UserShape>>> | null combined with
Locals, matching the LocalsWithSession definition.

---

Nitpick comments:
In `@packages/express/test/index.test.ts`:
- Around line 25-29: Extract the repeated JWT payload used with
auth.jose.encodeJWT into a shared test fixture/helper (e.g., a const jwtPayload
or function makeTestJwtPayload and/or helper makeSessionToken that calls
auth.jose.encodeJWT) and replace the duplicate inline payloads in the tests that
call auth.jose.encodeJWT (the occurrences around the current tests and the ones
at lines ~67-71) to use the shared helper; ensure the helper is exported or
available in the test scope so both tests import/use the same payload/creation
logic to avoid drift.
🪄 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: 509c0f8d-fb34-4b33-88bf-5ec6cbd85ca0

📥 Commits

Reviewing files that changed from the base of the PR and between 078cb68 and 55dad13.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (25)
  • apps/express/README.md
  • apps/express/package.json
  • apps/express/src/app.ts
  • apps/express/src/auth.ts
  • apps/express/src/index.ts
  • apps/express/src/lib/auth.ts
  • apps/express/src/lib/verify-session.ts
  • apps/express/src/server.ts
  • apps/express/src/types.d.ts
  • apps/express/tsconfig.json
  • packages/express/CHANGELOG.md
  • packages/express/README.md
  • packages/express/deno.json
  • packages/express/package.json
  • packages/express/src/createAuth.ts
  • packages/express/src/index.ts
  • packages/express/src/lib/handler.ts
  • packages/express/src/lib/with-auth.ts
  • packages/express/src/oauth/index.ts
  • packages/express/test/index.test.ts
  • packages/express/test/presets.ts
  • packages/express/test/types.test-d.ts
  • packages/express/tsconfig.json
  • packages/express/tsup.config.ts
  • packages/express/vitest.config.ts
💤 Files with no reviewable changes (4)
  • apps/express/src/types.d.ts
  • apps/express/src/server.ts
  • apps/express/src/lib/verify-session.ts
  • apps/express/src/auth.ts

Comment on lines +19 to +20
"clean:cts": "find dist -type f -name \"*.cts\" -delete",
"prepublish": "pnpm clean:cts"
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 | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -u
echo "Inspecting scripts in packages/express/package.json"
jq -r '.scripts | {clean_cts: ."clean:cts", prepublish, prepublishOnly}' packages/express/package.json

echo
echo "Checking current behavior of clean:cts command when dist is missing/present"
code=0
(
  cd packages/express || exit 1
  find dist -type f -name "*.cts" -print >/dev/null
) || code=$?
echo "find command exit code: $code (non-zero indicates fragility if dist is absent)"

Repository: aura-stack-ts/auth

Length of output: 445


🏁 Script executed:

# Check if there are any other prepublish uses in the repo that might provide context
rg -i "prepublish" --type json

# Check the project structure and build configuration
cat -n packages/express/package.json | head -40

Repository: aura-stack-ts/auth

Length of output: 1513


🌐 Web query:

npm prepublish vs prepublishOnly lifecycle hooks

💡 Result:

npm prepublish and prepublishOnly are lifecycle scripts in package.json with distinct behaviors. prepublish (DEPRECATED): Does not run during npm publish. Runs during npm install and npm ci (in the package directory). This changed from its original behavior due to historical reasons causing confusion. prepublishOnly: Runs BEFORE the package is prepared and packed, ONLY during npm publish. Ideal for final validation like tests or linting before publishing, without running on install. Key difference: prepublishOnly is exclusive to npm publish, while prepublish runs on install/ci but skips publish. Lifecycle order for npm publish: - prepublishOnly - prepack - prepare - postpack - publish - postpublish Use prepublishOnly for publish-only checks. For build steps needed on both publish and local install, use prepare instead. prepublish usage triggers deprecation warnings and is not recommended. As of npm v11.12.0 (latest in 2026), no further changes to these scripts are planned.

Citations:


Use prepublishOnly instead of prepublish for the clean:cts script.

The prepublish hook is deprecated and runs during npm install/npm ci, not during npm publish. This means the .cts file cleanup won't execute when actually publishing the package. Additionally, the find dist command will fail with a non-zero exit code if the dist/ directory doesn't exist.

Update to:

  • Use prepublishOnly to ensure the script runs only during publish
  • Add a directory existence check to prevent failures when dist/ is absent
Suggested fix
-    "clean:cts": "find dist -type f -name \"*.cts\" -delete",
-    "prepublish": "pnpm clean:cts"
+    "clean:cts": "[ -d dist ] && find dist -type f -name \"*.cts\" -delete || true",
+    "prepublishOnly": "pnpm clean:cts"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"clean:cts": "find dist -type f -name \"*.cts\" -delete",
"prepublish": "pnpm clean:cts"
"clean:cts": "[ -d dist ] && find dist -type f -name \"*.cts\" -delete || true",
"prepublishOnly": "pnpm clean:cts"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/express/package.json` around lines 19 - 20, The package.json scripts
use "prepublish" and run "clean:cts" which is deprecated and can run at install
time; change the lifecycle hook to "prepublishOnly" and update the "clean:cts"
script to guard against a missing dist directory (e.g., test for existence of
dist before running find) so the command returns zero when dist is absent;
update the "clean:cts" and replace the "prepublish" entry with "prepublishOnly"
in package.json to ensure cleanup runs only on publish and does not fail when
dist/ doesn't exist.

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 the current code and only fix it if needed.

Inline comments:
In `@packages/express/src/lib/with-auth.ts`:
- Around line 25-29: getSession is returning response headers that are currently
discarded; update the handler around the api.getSession call so you capture the
returned headers and forward them to the outgoing Express response before
calling next() (e.g., assign const { session, headers } = await
api.getSession(...); set those headers onto res using the appropriate Express
method and then set res.locals.session = session and return next()). Ensure you
forward all header entries from headers and do this in the same block where
webRequest.headers is passed to getSession.
🪄 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: 44a2cdf5-5cd9-44d7-bbaa-01e4626a2861

📥 Commits

Reviewing files that changed from the base of the PR and between 55dad13 and 67554ce.

📒 Files selected for processing (4)
  • apps/express/src/app.ts
  • packages/express/src/lib/with-auth.ts
  • packages/express/test/index.test.ts
  • packages/express/test/presets.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/express/src/app.ts
  • packages/express/test/index.test.ts
  • packages/express/test/presets.ts

@halvaradop halvaradop added enhancement New feature or request feature New functionality experimental labels Apr 10, 2026
@halvaradop halvaradop merged commit b49ff7e into master Apr 10, 2026
5 checks passed
@halvaradop halvaradop deleted the feat/add-express-pkg branch April 10, 2026 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request experimental feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant