Skip to content

Feat/new session store#406

Open
pesickaa wants to merge 36 commits intokinde-oss:mainfrom
pesickaa:feat/new-session-store
Open

Feat/new session store#406
pesickaa wants to merge 36 commits intokinde-oss:mainfrom
pesickaa:feat/new-session-store

Conversation

@pesickaa
Copy link
Copy Markdown
Contributor

@pesickaa pesickaa commented Oct 3, 2025

Explain your changes

Create new NextJs cookie store for the app router.
Ensure new cookie store is testable.

Checklist

🛟 If you need help, consider asking for advice over in the Kinde community.

@pesickaa pesickaa self-assigned this Oct 3, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Oct 3, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (2)
  • package.json is excluded by !**/*.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/*.yaml

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

  • 🔍 Trigger a full review

Walkthrough

Adds cookie-based session storage (CookieStorage) with chunked cookie read/write/remove, serialization/deserialization via destr, batch ops, session destruction, CookieStorageSettings type, index re-exports, and frontend tests for Next.js App Router contexts.

Changes

Cohort / File(s) Summary
Cookie-based Session Manager
src/session/sessionManager/cookieManager.ts
New CookieStorage class and cookieStorageSettings export: lazy cookie-store init for middleware/server contexts, cookie chunking (MAX_COOKIE_LENGTH), serialize/deserialize (destr), set/get/remove single and batch ops, and destroySession clearing known cookie prefixes.
Session Manager Exports
src/session/sessionManager/index.ts
Adds re-exports for CookieStorage and CookieStorageSettings.
Settings and Types
src/session/sessionManager/settings.ts
New CookieStorageSettings interface (extends storage settings) adding domain, sameSite, secure, and httpOnly fields.
Frontend Tests
tests/frontend/cookie-manager.test.ts
New tests with FakeCookieStore covering chunking, reassembly, (de)serialization for primitives/objects, removals, destroySession behavior, undefined/missing key handling, and key prefix verification.
Repository Metadata
CODEOWNERS
Adds ownership entries for package.json, pnpm-lock.yaml (recursive globs) to CODEOWNERS.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Handler as Server Handler / Middleware
  participant CS as CookieStorage
  participant NS as Next.js Cookies API

  rect rgba(248,250,255,0.5)
  note right of CS: Initialization (lazy)
  Handler->>CS: new CookieStorage(req, resp, { persistent })
  CS->>CS: ensureCookieStore()\n(middleware: resp.cookies,\nserver: cookieStore())
  CS-->>Handler: instance
  end

  rect rgba(235,255,235,0.5)
  note over Handler,CS: Set session item (chunk + write)
  Handler->>CS: setSessionItem(key, value)
  CS->>CS: serialize + chunk by MAX_COOKIE_LENGTH
  loop per chunk
    CS->>NS: set cookie(key.partN, chunk, opts)
  end
  CS-->>Handler: done
  end

  rect rgba(255,245,235,0.5)
  note over Handler,CS: Get session item (read + reassemble)
  Handler->>CS: getSessionItem(key)
  CS->>NS: read cookies(key.part*)
  CS->>CS: reassemble + parse (destr)
  CS-->>Handler: value | null
  end

  rect rgba(255,235,240,0.5)
  note over Handler,CS: Remove / Destroy
  Handler->>CS: removeSessionItem(key)
  CS->>NS: delete cookies(key.part*)
  Handler->>CS: destroySession()
  CS->>NS: delete cookies(COOKIE_LIST prefixes)
  CS-->>Handler: done
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • DaveOrDead
  • peterphanouvong
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'Feat/new session store' directly relates to the main change: introducing a new NextJS cookie-based session store (CookieStorage) for the app router.
Description check ✅ Passed The description is directly related to the changeset, explaining the creation of a new NextJS cookie store for the app router and ensuring it is testable, which aligns with the implemented CookieStorage class and comprehensive test suite.
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
  • Post copyable unit tests in a comment

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
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8599cc and c809a17.

📒 Files selected for processing (5)
  • src/session/sessionManager/cookieManager.ts (1 hunks)
  • src/session/sessionManager/index.ts (1 hunks)
  • src/session/sessionManager/settings.ts (1 hunks)
  • src/session/sessionManager/types.ts (1 hunks)
  • tests/frontend/cookie-manager.test.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-13T10:45:31.961Z
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:165-188
Timestamp: 2024-11-13T10:45:31.961Z
Learning: There's a new implementation coming soon for `src/session/sessionManager.js`, so refactoring suggestions related to cookie parsing logic may not be necessary at this time.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
🧬 Code graph analysis (4)
src/session/sessionManager/types.ts (1)
src/session/sessionManager/index.ts (2)
  • StorageKeys (8-8)
  • SessionManager (9-9)
tests/frontend/cookie-manager.test.ts (3)
src/session/sessionManager.js (1)
  • options (27-27)
src/session/sessionManager/cookieManager.ts (1)
  • CookieStorage (24-146)
src/utils/constants.ts (2)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
src/session/sessionManager/settings.ts (1)
src/session/sessionManager/types.ts (1)
  • StorageSettingsType (15-27)
src/session/sessionManager/cookieManager.ts (4)
src/session/sessionManager/settings.ts (1)
  • CookieStorageSettings (44-49)
src/utils/constants.ts (4)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
  • GLOBAL_COOKIE_OPTIONS (5-10)
  • TWENTY_NINE_DAYS (3-3)
src/session/sessionManager/types.ts (1)
  • SessionManager (61-105)
src/session/sessionManager.js (1)
  • options (27-27)
🪛 GitHub Actions: Build and test
src/session/sessionManager/index.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

tests/frontend/cookie-manager.test.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

src/session/sessionManager/settings.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

src/session/sessionManager/cookieManager.ts

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

@pesickaa pesickaa requested a review from DanielRivers October 3, 2025 11:18
Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (1)
src/session/sessionManager/cookieManager.ts (1)

33-42: Fix constructor typing to allow session cookies.

The constructor's options: { persistent: true } type prevents callers from passing persistent: false, breaking session cookie functionality.

Apply this diff:

  constructor(
-    req: NextApiRequest,
-    resp: NextApiResponse,
-    options: { persistent: true },
+    req: NextApiRequest | undefined,
+    resp: NextApiResponse | undefined,
+    options: { persistent: boolean } = { persistent: true },
  ) {
    super();
    this.req = req;
    this.resp = resp;
    this.sessionState = options;
  }
🧹 Nitpick comments (4)
tests/frontend/cookie-manager.test.ts (1)

42-50: Consider testing session cookie behavior.

The test setup always uses persistent: true. Consider adding tests for persistent: false to verify session cookie behavior (no maxAge set).

For example:

it("creates session cookies when persistent is false", async () => {
  const sessionStorage = new CookieStorage<any>(undefined as any, undefined as any, {
    persistent: false,
  });
  // @ts-ignore
  sessionStorage._cookieStore = fake as any;
  
  await sessionStorage.setSessionItem(StorageKeys.state, "test");
  
  // Verify cookie was set without maxAge (session cookie)
  const cookie = fake.get(StorageKeys.state);
  expect(cookie).toBeDefined();
  // In real implementation, session cookies have undefined maxAge
});
src/session/sessionManager/cookieManager.ts (3)

69-83: Refactor cookie name extraction for clarity.

The current pattern chains .map() and .forEach() on separate lines. Consider combining into a single iteration for better readability.

Apply this diff:

  async destroySession(): Promise<void> {
    const cookieStore = await this.ensureCookieStore();
-    cookieStore
-      .getAll()
-      .map((c) => c.name)
-      .forEach((key) => {
-        if (COOKIE_LIST.some((substr) => key.startsWith(substr))) {
-          cookieStore.set(key, "", {
-            domain: config.cookieDomain ? config.cookieDomain : undefined,
-            maxAge: 0,
-            ...GLOBAL_COOKIE_OPTIONS,
-          });
-        }
-      });
+    for (const { name } of cookieStore.getAll()) {
+      if (COOKIE_LIST.some((substr) => name.startsWith(substr))) {
+        cookieStore.set(name, "", {
+          domain: config.cookieDomain ? config.cookieDomain : undefined,
+          maxAge: 0,
+          ...GLOBAL_COOKIE_OPTIONS,
+        });
+      }
+    }
  }

88-116: LGTM with optional refactor.

The chunking and serialization logic correctly handles objects, primitives, and undefined values. Cookie naming and expiry settings are appropriate.

Consider the same iteration refactor as suggested for destroySession:

  async setSessionItem(
    itemKey: V | StorageKeys,
    itemValue: unknown,
  ): Promise<void> {
    const cookieStore = await this.ensureCookieStore();
-    cookieStore
-      .getAll()
-      .map((c) => c.name)
-      .forEach((key) => {
-        if (key.startsWith(`${String(itemKey)}`)) {
-          cookieStore.delete(key);
-        }
-      });
+    for (const { name } of cookieStore.getAll()) {
+      if (name.startsWith(`${String(itemKey)}`)) {
+        cookieStore.delete(name);
+      }
+    }
    if (itemValue !== undefined) {
      // ... rest remains the same
    }
  }

145-155: LGTM with optional refactor.

The removal logic correctly deletes all cookie chunks for the given key.

Apply the same iteration refactor as suggested for destroySession and setSessionItem:

  async removeSessionItem(itemKey: V | StorageKeys): Promise<void> {
    const cookieStore = await this.ensureCookieStore();
-    cookieStore
-      .getAll()
-      .map((c) => c.name)
-      .forEach((key) => {
-        if (key.startsWith(`${String(itemKey)}`)) {
-          cookieStore.delete(key);
-        }
-      });
+    for (const { name } of cookieStore.getAll()) {
+      if (name.startsWith(`${String(itemKey)}`)) {
+        cookieStore.delete(name);
+      }
+    }
  }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c809a17 and 6e1d234.

📒 Files selected for processing (4)
  • src/session/sessionManager/cookieManager.ts (1 hunks)
  • src/session/sessionManager/index.ts (1 hunks)
  • src/session/sessionManager/settings.ts (1 hunks)
  • tests/frontend/cookie-manager.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/session/sessionManager/settings.ts
  • src/session/sessionManager/index.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-13T10:45:31.961Z
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:165-188
Timestamp: 2024-11-13T10:45:31.961Z
Learning: There's a new implementation coming soon for `src/session/sessionManager.js`, so refactoring suggestions related to cookie parsing logic may not be necessary at this time.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
🧬 Code graph analysis (2)
tests/frontend/cookie-manager.test.ts (3)
src/session/sessionManager.js (1)
  • options (27-27)
src/session/sessionManager/cookieManager.ts (1)
  • CookieStorage (23-156)
src/utils/constants.ts (2)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
src/session/sessionManager/cookieManager.ts (3)
src/session/sessionManager/settings.ts (1)
  • CookieStorageSettings (44-49)
src/utils/constants.ts (4)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
  • GLOBAL_COOKIE_OPTIONS (5-10)
  • TWENTY_NINE_DAYS (3-3)
src/session/sessionManager/types.ts (1)
  • SessionManager (61-105)
🔇 Additional comments (4)
tests/frontend/cookie-manager.test.ts (3)

1-5: LGTM!

Clean imports using the public API surface and test utilities.


6-36: LGTM!

The FakeCookieStore mock implementation accurately mirrors the cookie store API behavior, including correct handling of expired cookies via maxAge <= 0.


52-154: LGTM!

Comprehensive test coverage of core functionality:

  • Chunking and reassembly with correct naming conventions
  • Serialization/deserialization via destr
  • Removal of chunked cookies
  • Prefix-based destruction
  • Edge cases (undefined, primitives, objects)
src/session/sessionManager/cookieManager.ts (1)

47-63: Verify CookieManager constructor usage
Check all new CookieManager(...) instantiations to ensure req is only omitted (undefined) in App Router contexts so the cookies() fallback isn’t ever reached in Pages Router or middleware.

Copy link
Copy Markdown
Contributor

@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: 0

🧹 Nitpick comments (1)
src/session/sessionManager/cookieManager.ts (1)

123-145: Reconsider fallback to item.value on parse failure.

Line 143 falls back to item.value (first chunk only) when itemValue is falsy. If parsing fails but multiple chunks were successfully reassembled into an empty or falsy itemValue, returning only the first chunk loses data. Consider:

-      return itemValue || item.value;
+      return itemValue;

This ensures the full reassembled string is returned even when parsing fails, maintaining data integrity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e95712 and fbe31d6.

📒 Files selected for processing (2)
  • src/session/sessionManager/cookieManager.ts (1 hunks)
  • tests/frontend/cookie-manager.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/frontend/cookie-manager.test.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-13T10:45:31.961Z
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:165-188
Timestamp: 2024-11-13T10:45:31.961Z
Learning: There's a new implementation coming soon for `src/session/sessionManager.js`, so refactoring suggestions related to cookie parsing logic may not be necessary at this time.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
🧬 Code graph analysis (1)
src/session/sessionManager/cookieManager.ts (3)
src/session/sessionManager/settings.ts (1)
  • CookieStorageSettings (44-49)
src/utils/constants.ts (4)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
  • GLOBAL_COOKIE_OPTIONS (5-10)
  • TWENTY_NINE_DAYS (3-3)
src/session/sessionManager/types.ts (1)
  • SessionManager (61-105)
🔇 Additional comments (9)
src/session/sessionManager/cookieManager.ts (9)

1-15: LGTM!

All imports are appropriate for the cookie-based session storage implementation. The use of destr for safe JSON parsing aligns with best practices for handling untrusted data.


17-21: LGTM!

The storage settings are correctly configured with the unified "kinde-" prefix and appropriate security defaults.


23-26: LGTM!

Class declaration correctly extends SessionBase and implements SessionManager with appropriate generic constraints.


27-31: LGTM!

Class properties are correctly typed with appropriate visibility modifiers and sensible defaults.


33-42: LGTM!

Constructor signature correctly allows both persistent and session cookies, addressing previous feedback.


88-118: LGTM!

The method correctly:

  • Applies the unified prefix
  • Clears stale chunks before writing new ones
  • Handles serialization for both objects and primitives
  • Chunks large values appropriately
  • Respects the persistent flag for maxAge

150-161: LGTM!

The method correctly removes all chunked cookies associated with the given key by matching the prefix.


69-83: Use mutable RequestCookies for cookie mutations
Ensure ensureCookieStore returns RequestCookies (from next/headers) instead of ReadonlyRequestCookies, since set()/delete() require a mutable store.


47-63: Asymmetric App Router enforcement is correct. When req is undefined you’re already in App Router context; when provided, isAppRouter(req) accurately guards for web Request. No changes needed.

Copy link
Copy Markdown
Contributor

@Yoshify Yoshify left a comment

Choose a reason for hiding this comment

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

Left some comments - happy to discuss further 😄

* Clears all tracked items from the cookie store.
* @returns {void}
*/
async destroySession(): Promise<void> {
Copy link
Copy Markdown
Contributor

@Yoshify Yoshify Oct 3, 2025

Choose a reason for hiding this comment

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

This unfortunately won't work in middleware in Next versions <15, it'll throw Error: Cookies can only be modified in a Server Action or Route Handler. - this applies to all mutations on cookies. We'd need to mutate the cookies on the req/res objects. See https://github.com/kinde-oss/kinde-auth-nextjs/blob/c8599cc4d0a8b6ef76e71ebac823dcc6dc526b10/src/authMiddleware/authMiddleware.ts

The reason we'd need to also mutate the cookies on the request and not just the response is during SSR in Next versions prior to 14.2.8, Cookies are read from the Set-Cookie from the request, not the response. See this part of the middleware specifically: https://github.com/kinde-oss/kinde-auth-nextjs/blob/c8599cc4d0a8b6ef76e71ebac823dcc6dc526b10/src/authMiddleware/authMiddleware.ts#L166C7-L170C39

It's a big gotcha that they resolved in 15 and above thankfully, but ideally we should continue supporting 14 as a good portion of the Next userbase is still on there.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

hey @Yoshify, I'd love a chance to discuss this with you further so I can better understand the desired flow within NextJS.

/**
* Sets the provided key-value store into cookies (split into chunks if needed).
*/
async setSessionItem(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See above comment.

/**
* Removes all cookie parts associated with the provided key.
*/
async removeSessionItem(itemKey: V | StorageKeys): Promise<void> {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See above comment.

this._cookieStore = await cookies();
return this._cookieStore;
} else {
throw new Error("This store is to be used for App Router.");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Instead of throwing here we should probably use the request cookies to support middleware in v14> <v15, that will also potentially allow us to use the same store for pages router. This shouldn't be too difficult given we have the req/res objects already. https://github.com/kinde-oss/kinde-auth-nextjs/blob/c8599cc4d0a8b6ef76e71ebac823dcc6dc526b10/src/authMiddleware/authMiddleware.ts has some good examples of this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hey @Yoshify I've made some changes to the way this works. Can you re-review please?

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (3)
src/session/sessionManager/cookieManager.ts (3)

110-176: Consider extracting the serialization logic

The cookie serialization and chunking logic is duplicated between the middleware and non-middleware branches (lines 132-150 and 158-174). While the current implementation is correct, extracting this into a helper function would improve maintainability.

Example refactor:

private prepareChunks(itemValue: unknown): string[] {
  if (itemValue === undefined) return [];
  const itemValueString =
    typeof itemValue === "object"
      ? JSON.stringify(itemValue)
      : String(itemValue);
  return splitString(itemValueString, MAX_COOKIE_LENGTH);
}

Then use it in both branches:

const chunks = this.prepareChunks(itemValue);
chunks.forEach((value, index) => {
  // set cookie with appropriate API
});

232-236: Consider parallelizing batch operations

The method sequentially awaits each setSessionItem call. If ordering is not critical, you could improve performance by parallelizing with Promise.all.

async setItems(items: Partial<Record<V, unknown>>): Promise<void> {
  await Promise.all(
    Object.entries(items).map(([key, value]) =>
      this.setSessionItem(key as V, value)
    )
  );
}

241-245: Consider parallelizing batch operations

Similar to setItems, this method could benefit from parallelization if ordering is not critical.

async removeItems(...items: V[]): Promise<void> {
  await Promise.all(items.map((item) => this.removeSessionItem(item)));
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbe31d6 and 4d23613.

⛔ Files ignored due to path filters (2)
  • package.json is excluded by !**/*.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/*.yaml
📒 Files selected for processing (3)
  • src/session/sessionManager/cookieManager.ts (1 hunks)
  • src/session/sessionManager/index.ts (1 hunks)
  • src/session/sessionManager/settings.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/session/sessionManager/settings.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-11-13T10:45:31.961Z
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:165-188
Timestamp: 2024-11-13T10:45:31.961Z
Learning: There's a new implementation coming soon for `src/session/sessionManager.js`, so refactoring suggestions related to cookie parsing logic may not be necessary at this time.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
📚 Learning: 2024-12-17T00:41:07.608Z
Learnt from: Yoshify
PR: kinde-oss/kinde-auth-nextjs#254
File: src/session/isAuthenticated.js:14-17
Timestamp: 2024-12-17T00:41:07.608Z
Learning: In `src/session/isAuthenticated.js` of this Next.js application, cookies cannot be modified in React Server Components (RSC). Therefore, to prevent accessing stale data outside of middleware, the application redirects on token expiry.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
🧬 Code graph analysis (1)
src/session/sessionManager/cookieManager.ts (3)
src/session/sessionManager/settings.ts (1)
  • CookieStorageSettings (3-8)
src/utils/constants.ts (4)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
  • GLOBAL_COOKIE_OPTIONS (5-10)
  • TWENTY_NINE_DAYS (3-3)
src/session/sessionManager.js (1)
  • options (27-27)
🔇 Additional comments (8)
src/session/sessionManager/index.ts (1)

1-4: LGTM!

The re-exports are clean and follow proper TypeScript conventions. The previous issue with file extensions has been correctly addressed.

src/session/sessionManager/cookieManager.ts (7)

1-15: LGTM!

The imports correctly use Next.js App Router types (NextRequest, NextResponse) rather than Pages Router types, addressing previous feedback.


17-21: LGTM!

The settings are well-defined, and the keyPrefix is consistently applied across all cookie operations in the class methods.


31-42: LGTM!

The constructor correctly accepts both persistent and session-scoped cookie configurations, addressing the previous type constraint issue.


48-50: LGTM!

Simple and correct helper for detecting middleware context.


79-105: LGTM!

The method correctly differentiates between middleware and non-middleware contexts for cookie deletion. The middleware path properly uses resp.cookies for mutations to support Next.js < 15.


181-203: LGTM!

The method correctly reassembles chunked cookies with proper null-checking to prevent race conditions, and safely parses values using destr.


208-227: LGTM!

The method correctly removes all cookie chunks with proper context differentiation.

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (2)
src/session/sessionManager/cookieManager.ts (2)

232-236: Consider parallel execution for better performance.

The sequential await calls may be slower when setting multiple items. While the current implementation is correct and easier to reason about, parallel execution could improve performance.

If you'd like to optimize, apply this diff:

  async setItems(items: Partial<Record<V, unknown>>): Promise<void> {
-   for (const [key, value] of Object.entries(items)) {
-     await this.setSessionItem(key as V, value);
-   }
+   await Promise.all(
+     Object.entries(items).map(([key, value]) =>
+       this.setSessionItem(key as V, value)
+     )
+   );
  }

Note: Only apply this optimization if profiling shows it's beneficial, as sequential execution may be preferred for debugging or when order matters.


241-245: Consider parallel execution for better performance.

Similar to setItems, the sequential await calls may be slower when removing multiple items.

If you'd like to optimize:

  async removeItems(...items: V[]): Promise<void> {
-   for (const item of items) {
-     await this.removeSessionItem(item);
-   }
+   await Promise.all(items.map((item) => this.removeSessionItem(item)));
  }

Note: Only apply if profiling shows benefit, as sequential execution may be preferred for debugging or when order matters.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4d23613 and 6499c16.

⛔ Files ignored due to path filters (2)
  • package.json is excluded by !**/*.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/*.yaml
📒 Files selected for processing (1)
  • src/session/sessionManager/cookieManager.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-11-13T10:45:31.961Z
Learnt from: DanielRivers
PR: kinde-oss/kinde-auth-nextjs#229
File: src/session/sessionManager.js:165-188
Timestamp: 2024-11-13T10:45:31.961Z
Learning: There's a new implementation coming soon for `src/session/sessionManager.js`, so refactoring suggestions related to cookie parsing logic may not be necessary at this time.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
📚 Learning: 2024-12-17T00:41:07.608Z
Learnt from: Yoshify
PR: kinde-oss/kinde-auth-nextjs#254
File: src/session/isAuthenticated.js:14-17
Timestamp: 2024-12-17T00:41:07.608Z
Learning: In `src/session/isAuthenticated.js` of this Next.js application, cookies cannot be modified in React Server Components (RSC). Therefore, to prevent accessing stale data outside of middleware, the application redirects on token expiry.

Applied to files:

  • src/session/sessionManager/cookieManager.ts
🧬 Code graph analysis (1)
src/session/sessionManager/cookieManager.ts (3)
src/session/sessionManager/settings.ts (1)
  • CookieStorageSettings (3-8)
src/utils/constants.ts (4)
  • MAX_COOKIE_LENGTH (23-23)
  • COOKIE_LIST (12-21)
  • GLOBAL_COOKIE_OPTIONS (5-10)
  • TWENTY_NINE_DAYS (3-3)
src/session/sessionManager.js (1)
  • options (27-27)
🔇 Additional comments (8)
src/session/sessionManager/cookieManager.ts (8)

17-21: LGTM!

The cookie storage settings are properly configured with sensible defaults. The keyPrefix alignment and maxLength constraint prevent cookie size issues.


23-42: LGTM!

The class declaration and constructor are well-structured. The constructor properly accepts both persistent modes, resolving the previous type constraint issue.


44-50: LGTM!

The middleware context detection is correct and well-documented. The comment clearly explains the Next.js < 15 requirement.


75-105: LGTM!

The session destruction logic correctly handles both middleware and server contexts. The filtering by COOKIE_LIST prefixes and setting maxAge: 0 is the proper approach for cookie deletion.


110-176: LGTM with a minor note on serialization.

The chunking logic and dual-path handling for middleware/server contexts are well-implemented. The keyPrefix is now correctly applied to all operations.

One minor consideration: Line 135 uses String(itemValue) for non-object primitives. This works for numbers and booleans but converts null to "null" string. Ensure upstream code doesn't pass null when undefined is intended, or add explicit null handling if needed.


181-203: LGTM!

The reassembly logic with null guard (line 191-192) properly handles edge cases. The use of destr for safe parsing and the debug logging for parse failures follow best practices.

Based on learnings.


208-227: LGTM!

The removal logic correctly handles all chunks and maintains consistency with the dual-path approach used throughout the class.


55-73: Add middleware context branch for Next.js < 14.2.8
Current code always calls await cookies() in middleware, so mutations via resp.cookies aren’t visible in Next.js < 14.2.8. Introduce before the existing branches:

 private async ensureCookieStore(): Promise<ReadonlyRequestCookies> {
   if (this._cookieStore) return this._cookieStore;

+  if (this.isMiddlewareContext() && this.req) {
+    this._cookieStore = this.req.cookies;
+    return this._cookieStore;
+  }

   if (!this.req) {
     this._cookieStore = await cookies();

Confirm that NextRequest.cookies is compatible with ReadonlyRequestCookies.

@pesickaa pesickaa requested a review from a team as a code owner October 14, 2025 09:04
pesickaa and others added 20 commits December 2, 2025 11:27
Bumps [next](https://github.com/vercel/next.js) from 16.0.0 to 16.1.6.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](vercel/next.js@v16.0.0...v16.1.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 16.1.6
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
…rn/next-16.1.6

chore(deps): bump next from 16.0.0 to 16.1.6
@pesickaa pesickaa requested a review from a team as a code owner February 2, 2026 11:21
Copy link
Copy Markdown
Contributor

@dtoxvanilla1991 dtoxvanilla1991 left a comment

Choose a reason for hiding this comment

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

Good work! Some feedback 💭

.map((c) => c.name)
.filter((key) => COOKIE_LIST.some((substr) => key.startsWith(substr)));

// In middleware context, use resp.cookies (Next.js < 15 requirement)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

destroySession() currently filters only by COOKIE_LIST prefixes, but this class writes session keys using kinde- prefixed names. That mismatch can leave prefixed auth cookies behind after logout/session destruction. Please align delete matching with the same namespace strategy used by setSessionItem/getSessionItem/removeSessionItem (and preserve legacy cleanup if needed).

Comment on lines +69 to +74
this._cookieStore = cookies();
return this._cookieStore;
}

if (isAppRouter(this.req)) {
this._cookieStore = cookies();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

cookies() in current Next.js versions is async and returns a promise-backed cookie store (Promise<ReadonlyRequestCookies>). Assigning it directly here risks runtime/type drift in non-middleware paths, and subsequent .set/.delete calls can fail depending on context. Please resolve this branch to await and normalize store type consistently with the rest of ensureCookieStore.

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.

5 participants