Skip to content

feat: add getCookieOptions utility function#184

Open
dtoxvanilla1991 wants to merge 9 commits intokinde-oss:mainfrom
dtoxvanilla1991:feat/getCookiesOptions
Open

feat: add getCookieOptions utility function#184
dtoxvanilla1991 wants to merge 9 commits intokinde-oss:mainfrom
dtoxvanilla1991:feat/getCookiesOptions

Conversation

@dtoxvanilla1991
Copy link

@dtoxvanilla1991 dtoxvanilla1991 commented Oct 22, 2025

Explain your changes

  • Built framework-agnostic getCookieOptions with explicit typing, optional env injection, and warnings when runtime config is incomplete.
  • Added whitespace handling and diagnostic logs so malformed cookie domains or missing NODE_ENV don’t slip through silently.
  • Wrote targeted Vitest coverage for defaults, overrides, runtime fallbacks, warnings, and removeTrailingSlash edge cases; all tests pass.

Checklist

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

@dtoxvanilla1991 dtoxvanilla1991 self-assigned this Oct 22, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

Walkthrough

Adds a new cookie-options utility with defaults and a merging function, tests for its behavior, and re-exports the utility and its type from utils and main; updates expected public exports accordingly.

Changes

Cohort / File(s) Summary
New Cookie Options Utility
lib/utils/getCookieOptions.ts
Adds CookieOptions interface, TWENTY_NINE_DAYS and GLOBAL_COOKIE_OPTIONS constants, and exported getCookieOptions(options?: CookieOptions): CookieOptions which merges provided options over global defaults.
Tests
lib/utils/getCookieOptions.test.ts
Adds tests verifying defaults, consumer overrides, preservation of global defaults, precedence of user options, and passthrough/custom option behaviors.
Utils Re-exports
lib/utils/index.ts
Re-exports getCookieOptions and the CookieOptions type from ./getCookieOptions.
Public Re-export
lib/main.ts
Re-exports getCookieOptions and the CookieOptions type from utils.
Export Validation Test
lib/main.test.ts
Updates expected public exports to include getCookieOptions (and CookieOptions type).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10–15 minutes

  • Review merge logic in lib/utils/getCookieOptions.ts for correct precedence and default values.
  • Verify TWENTY_NINE_DAYS and GLOBAL_COOKIE_OPTIONS constants align with intended defaults and storageSettings.maxLength usage.
  • Confirm re-exports in lib/utils/index.ts and lib/main.ts expose the function and type correctly.
  • Check lib/utils/getCookieOptions.test.ts covers edge cases and matches constants used.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add getCookieOptions utility function' directly and clearly summarizes the main change—the addition of a new getCookieOptions utility function, which is confirmed across all modified files.
Description check ✅ Passed The description explains the implementation details (framework-agnostic design, typing, env injection, whitespace handling, diagnostic logs) and testing approach (Vitest coverage), which align with the changeset's additions of getCookieOptions, CookieOptions interface, constants, and comprehensive tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c59ff0a and 70e9189.

📒 Files selected for processing (4)
  • lib/main.ts (1 hunks)
  • lib/utils/getCookieOptions.test.ts (1 hunks)
  • lib/utils/getCookieOptions.ts (1 hunks)
  • lib/utils/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • lib/utils/getCookieOptions.ts
  • lib/utils/getCookieOptions.test.ts
  • lib/main.ts
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: dtoxvanilla1991
Repo: kinde-oss/js-utils PR: 184
File: lib/utils/getCookieOptions.ts:17-23
Timestamp: 2025-12-18T23:04:04.194Z
Learning: In lib/utils/getCookieOptions.ts, the `secure` flag is intentionally omitted from GLOBAL_COOKIE_OPTIONS by design because this is a universal js-utils library used across multiple Kinde SDKs and needs to support various environments including local development over HTTP. Consumers can override with `secure: true` when needed.
📚 Learning: 2024-09-23T22:08:18.788Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 12
File: lib/main.ts:0-0
Timestamp: 2024-09-23T22:08:18.788Z
Learning: When exporting modules in `lib/main.ts`, ensure that paths to modules like `./utils/token` are explicitly set to include `index.ts` (e.g., `./utils/token/index.ts`) to prevent missing export issues.

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-12-18T23:04:04.194Z
Learnt from: dtoxvanilla1991
Repo: kinde-oss/js-utils PR: 184
File: lib/utils/getCookieOptions.ts:17-23
Timestamp: 2025-12-18T23:04:04.194Z
Learning: In lib/utils/getCookieOptions.ts, the `secure` flag is intentionally omitted from GLOBAL_COOKIE_OPTIONS by design because this is a universal js-utils library used across multiple Kinde SDKs and needs to support various environments including local development over HTTP. Consumers can override with `secure: true` when needed.

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2025-01-16T21:47:40.307Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2024-11-10T23:29:36.293Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/exchangeAuthCode.ts:51-51
Timestamp: 2024-11-10T23:29:36.293Z
Learning: In `lib/utils/exchangeAuthCode.ts`, the `exchangeAuthCode` function intentionally uses `getInsecureStorage()` to store temporary authentication flow values locally between sessions. This is necessary for storing data needed for the return trip. The `getInsecureStorage()` function returns the secure storage if no active insecure storage is defined.

Applied to files:

  • lib/utils/index.ts
🔇 Additional comments (1)
lib/utils/index.ts (1)

12-13: LGTM! Clean exports following TypeScript best practices.

The exports are syntactically correct and follow established patterns in the file. Using export type for the type export is good practice as it clearly marks type-only exports for better tree-shaking.


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.

@codecov
Copy link

codecov bot commented Oct 22, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@dtoxvanilla1991 dtoxvanilla1991 changed the title feat: add getCookieOptions and removeTrailingSlash utility functions … feat: add getCookieOptions utility function Oct 22, 2025
@dtoxvanilla1991 dtoxvanilla1991 marked this pull request as ready for review December 16, 2025 10:06
@dtoxvanilla1991 dtoxvanilla1991 requested a review from a team as a code owner December 16, 2025 10:06
Copy link
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 (3)
lib/utils/getCookieOptions.test.ts (1)

50-73: Consider using vi.stubEnv for cleaner environment variable mocking.

The manual save/restore pattern works but is verbose. Vitest's vi.stubEnv provides cleaner isolation:

 it("falls back to runtime environment variables when env param is omitted", () => {
-  const previousNodeEnv = process.env.NODE_ENV;
-  const previousCookieDomain = process.env.KINDE_COOKIE_DOMAIN;
-
-  process.env.NODE_ENV = "production";
-  process.env.KINDE_COOKIE_DOMAIN = "runtime-domain.io/";
+  vi.stubEnv("NODE_ENV", "production");
+  vi.stubEnv("KINDE_COOKIE_DOMAIN", "runtime-domain.io/");

   const result = getCookieOptions();

   expect(result.domain).toBe("runtime-domain.io");
   expect(result.secure).toBe(true);

-  if (previousNodeEnv === undefined) {
-    delete process.env.NODE_ENV;
-  } else {
-    process.env.NODE_ENV = previousNodeEnv;
-  }
-
-  if (previousCookieDomain === undefined) {
-    delete process.env.KINDE_COOKIE_DOMAIN;
-  } else {
-    process.env.KINDE_COOKIE_DOMAIN = previousCookieDomain;
-  }
+  vi.unstubAllEnvs();
 });
lib/utils/getCookieOptions.ts (2)

7-7: Consider removing null from CookieOptionValue.

Including both undefined and null is unusual in TypeScript. Typically, optional values use only undefined. Having both can lead to confusion and requires callers to handle both cases.

Apply this diff if null is not specifically required:

-export type CookieOptionValue = string | number | boolean | undefined | null;
+export type CookieOptionValue = string | number | boolean | undefined;

29-38: Clarify the environment detection check.

The check typeof globalThis === "undefined" is confusing because globalThis is a standard feature in modern JavaScript and should always be available. The comment mentions process being undefined, but the check is for globalThis.

While the code works correctly (falling back to {} in browsers where process doesn't exist), the logic would be clearer if it directly checked for process:

 const getRuntimeEnv = (): CookieEnv => {
-  // In browser/react-native bundles process is undefined
-  if (typeof globalThis === "undefined") {
+  // In browser/react-native environments, process may not be defined
+  if (typeof process === "undefined") {
     return {};
   }
 
-  const maybeProcess = (globalThis as { process?: { env?: CookieEnv } })
-    .process;
-  return maybeProcess?.env ?? {};
+  return process?.env ?? {};
 };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 246d2a3 and 0c1c8c0.

📒 Files selected for processing (6)
  • lib/main.test.ts (1 hunks)
  • lib/main.ts (1 hunks)
  • lib/utils/exchangeAuthCode.test.ts (13 hunks)
  • lib/utils/getCookieOptions.test.ts (1 hunks)
  • lib/utils/getCookieOptions.ts (1 hunks)
  • lib/utils/index.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.
📚 Learning: 2024-09-23T22:08:18.788Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 12
File: lib/main.ts:0-0
Timestamp: 2024-09-23T22:08:18.788Z
Learning: When exporting modules in `lib/main.ts`, ensure that paths to modules like `./utils/token` are explicitly set to include `index.ts` (e.g., `./utils/token/index.ts`) to prevent missing export issues.

Applied to files:

  • lib/main.ts
  • lib/main.test.ts
  • lib/utils/index.ts
📚 Learning: 2025-01-16T21:47:40.307Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.

Applied to files:

  • lib/main.ts
  • lib/utils/index.ts
  • lib/utils/exchangeAuthCode.test.ts
  • lib/utils/getCookieOptions.test.ts
  • lib/utils/getCookieOptions.ts
📚 Learning: 2024-10-25T23:50:56.599Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.ts:27-30
Timestamp: 2024-10-25T23:50:56.599Z
Learning: In `lib/utils/generateAuthUrl.ts`, `StorageKeys` is imported from `../main` and includes the `state` key.

Applied to files:

  • lib/main.ts
  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-09-19T22:17:02.939Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 8
File: lib/utils/token/testUtils/index.ts:3-39
Timestamp: 2024-09-19T22:17:02.939Z
Learning: The file `lib/utils/token/testUtils/index.ts` is a test utility, not production code.

Applied to files:

  • lib/main.test.ts
  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-11-10T23:29:36.293Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/exchangeAuthCode.ts:51-51
Timestamp: 2024-11-10T23:29:36.293Z
Learning: In `lib/utils/exchangeAuthCode.ts`, the `exchangeAuthCode` function intentionally uses `getInsecureStorage()` to store temporary authentication flow values locally between sessions. This is necessary for storing data needed for the return trip. The `getInsecureStorage()` function returns the secure storage if no active insecure storage is defined.

Applied to files:

  • lib/utils/index.ts
  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-10-25T23:53:26.124Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.test.ts:104-104
Timestamp: 2024-10-25T23:53:26.124Z
Learning: In `lib/utils/generateAuthUrl.test.ts`, the code is test code and may not require strict adherence to PKCE specifications.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-11-19T20:31:59.197Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/index.test.ts:59-62
Timestamp: 2024-11-19T20:31:59.197Z
Learning: In `lib/utils/token/index.test.ts`, the test "getInsecureStorage returns active storage when no insecure storage is set" is intentional. It verifies that when insecure storage is not set, `getInsecureStorage()` returns the active storage as a fallback, preferring secure storage but allowing for insecure storage when needed by consumers of the library.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
🧬 Code graph analysis (1)
lib/utils/getCookieOptions.test.ts (1)
lib/utils/getCookieOptions.ts (4)
  • getCookieOptions (57-94)
  • TWENTY_NINE_DAYS (20-20)
  • MAX_COOKIE_LENGTH (21-21)
  • removeTrailingSlash (40-55)
🔇 Additional comments (17)
lib/utils/exchangeAuthCode.test.ts (6)

13-21: LGTM! Clean fetch mock abstraction.

The fetchMock typed as vi.fn<typeof fetch>() and the jsonResponse helper provide a clean, type-safe way to mock fetch responses. This is a good improvement over the vitest-fetch-mock dependency.


35-49: LGTM! Proper test lifecycle management.

The beforeEach/afterEach setup ensures proper test isolation by resetting the mock before each test and cleaning up globals after each test.


146-182: LGTM!

The mock setup and assertions are well-structured, properly verifying both the fetch URL and request headers.


304-322: LGTM! Proper HTTP error simulation.

Using new Response("error", { status: 500, statusText: "Internal Server Error" }) correctly simulates server error responses, allowing the code under test to handle the response as it would in production.


461-474: LGTM!

Correctly uses mockRejectedValueOnce to simulate network-level fetch failures, distinct from HTTP error responses.


563-584: LGTM!

The test properly verifies auto-refresh functionality, including storage interaction for the refresh token.

lib/main.test.ts (1)

50-50: LGTM!

The test correctly includes getCookieOptions in the expected exports, maintaining the export contract validation.

lib/main.ts (1)

27-29: LGTM!

The new exports follow the existing pattern in the file. The export type syntax correctly handles the type-only exports.

lib/utils/index.ts (1)

12-17: LGTM!

The new exports follow the existing barrel export pattern in this file, correctly separating the function export from the type exports.

lib/utils/getCookieOptions.test.ts (5)

1-9: LGTM!

Clean imports with proper separation of concerns - test utilities from vitest and the module under test.


10-26: LGTM!

Good test coverage for the default configuration, including verification that trailing slashes are removed from the domain.


28-48: LGTM!

Good test coverage for option overrides, including verification that custom passthrough options are preserved.


75-102: LGTM!

Good coverage of the warning scenarios with proper spy cleanup. Both tests verify the specific warning messages emitted.


105-122: LGTM!

Comprehensive test coverage for removeTrailingSlash including edge cases for nullish values and whitespace-only strings.

lib/utils/getCookieOptions.ts (3)

23-27: LGTM: Secure defaults configured.

The cookie options provide good security defaults with httpOnly: true to prevent XSS access and sameSite: "lax" to provide CSRF protection while maintaining usability.


40-55: LGTM: Edge cases handled correctly.

The function properly handles null, undefined, whitespace-only strings, and empty strings by returning undefined, ensuring consistent behavior for malformed inputs.


57-94: LGTM: Merge logic and warnings are well-structured.

The function correctly:

  • Merges options in the proper order (defaults → global options → user overrides)
  • Handles the secure flag with environment-aware defaults
  • Emits diagnostic warnings for malformed domains and missing NODE_ENV
  • Allows user options to override environment-derived values

Note: Domain validation is intentionally minimal—the function trims whitespace and removes trailing slashes but does not validate domain format (e.g., invalid characters or protocol prefixes). This is consistent with the library's design to delegate format validation to the cookie-setting layer or consuming code.

Copy link
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/utils/exchangeAuthCode.test.ts (2)

188-188: Unused store2 makes assertion meaningless.

store2 is created at line 188 but never set as any storage (active or insecure). The assertion at lines 231-234 checks store2 for refreshToken, but since store2 was never connected to the system, it will always be null regardless of the test's behavior.

If the intent is to verify refresh token storage behavior, this should either be removed or corrected to check the appropriate storage.

🔎 Option 1: Remove unused code
-    const store2 = new MemoryStorage();
     const state = "state";
-    const insecureRefreshToken = await store2.getSessionItem(
-      StorageKeys.refreshToken,
-    );
-    expect(insecureRefreshToken).toBeNull();
🔎 Option 2: If intent is to verify refresh token is stored in insecure storage
     const postCodeVerifier = await store.getSessionItem(
       StorageKeys.codeVerifier,
     );
     expect(postCodeVerifier).toBeNull();
-    const insecureRefreshToken = await store2.getSessionItem(
+    const insecureRefreshToken = await store.getSessionItem(
       StorageKeys.refreshToken,
     );
-    expect(insecureRefreshToken).toBeNull();
+    expect(insecureRefreshToken).toBe("refresh_token");

Also applies to: 231-234


600-606: Fix: mockResponseOnce is not a function — causes pipeline failure.

This test still uses the old vitest-fetch-mock API (mockResponseOnce), but the file has migrated to native Vitest mocking with vi.fn(). This is the direct cause of the pipeline failure.

🔎 Apply this diff to fix the issue:
-    fetchMock.mockResponseOnce(
-      JSON.stringify({
+    fetchMock.mockResolvedValueOnce(
+      jsonResponse({
         access_token: "access_token",
         refresh_token: "refresh_token",
         id_token: "id_token",
       }),
     );
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c1c8c0 and 13a637a.

📒 Files selected for processing (3)
  • lib/main.test.ts (1 hunks)
  • lib/main.ts (1 hunks)
  • lib/utils/exchangeAuthCode.test.ts (13 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/main.test.ts
  • lib/main.ts
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2024-10-25T23:53:26.124Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.test.ts:104-104
Timestamp: 2024-10-25T23:53:26.124Z
Learning: In `lib/utils/generateAuthUrl.test.ts`, the code is test code and may not require strict adherence to PKCE specifications.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-11-10T23:29:36.293Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/exchangeAuthCode.ts:51-51
Timestamp: 2024-11-10T23:29:36.293Z
Learning: In `lib/utils/exchangeAuthCode.ts`, the `exchangeAuthCode` function intentionally uses `getInsecureStorage()` to store temporary authentication flow values locally between sessions. This is necessary for storing data needed for the return trip. The `getInsecureStorage()` function returns the secure storage if no active insecure storage is defined.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-09-19T22:17:02.939Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 8
File: lib/utils/token/testUtils/index.ts:3-39
Timestamp: 2024-09-19T22:17:02.939Z
Learning: The file `lib/utils/token/testUtils/index.ts` is a test utility, not production code.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2025-01-16T21:47:40.307Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-11-19T20:31:59.197Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/index.test.ts:59-62
Timestamp: 2024-11-19T20:31:59.197Z
Learning: In `lib/utils/token/index.test.ts`, the test "getInsecureStorage returns active storage when no insecure storage is set" is intentional. It verifies that when insecure storage is not set, `getInsecureStorage()` returns the active storage as a fallback, preferring secure storage but allowing for insecure storage when needed by consumers of the library.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-10-25T23:50:56.599Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.ts:27-30
Timestamp: 2024-10-25T23:50:56.599Z
Learning: In `lib/utils/generateAuthUrl.ts`, `StorageKeys` is imported from `../main` and includes the `state` key.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
🪛 GitHub Actions: Build and test
lib/utils/exchangeAuthCode.test.ts

[error] 1-1: TypeError: fetchMock.mockResponseOnce is not a function

🔇 Additional comments (2)
lib/utils/exchangeAuthCode.test.ts (2)

13-21: LGTM!

Clean setup for native Vitest fetch mocking. The jsonResponse helper provides a good abstraction for creating properly typed Response objects.


35-49: LGTM!

Proper mock lifecycle management with mockReset(), stubGlobal(), and cleanup in afterEach.

Copy link
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)
lib/utils/exchangeAuthCode.test.ts (1)

563-569: Consider using mockResolvedValueOnce for consistency.

This test uses mockResolvedValue while all others use mockResolvedValueOnce. Although it works (only one fetch call occurs), using mockResolvedValueOnce would be consistent with the rest of the file and make the intent clearer.

🔎 Apply this diff for consistency:
-    fetchMock.mockResolvedValue(
+    fetchMock.mockResolvedValueOnce(
       jsonResponse({
         access_token: "access",
         id_token: "id",
         refresh_token: "refresh",
       }),
     );
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13a637a and 9d615c1.

📒 Files selected for processing (1)
  • lib/utils/exchangeAuthCode.test.ts (14 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2024-10-25T23:53:26.124Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.test.ts:104-104
Timestamp: 2024-10-25T23:53:26.124Z
Learning: In `lib/utils/generateAuthUrl.test.ts`, the code is test code and may not require strict adherence to PKCE specifications.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-11-10T23:29:36.293Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/exchangeAuthCode.ts:51-51
Timestamp: 2024-11-10T23:29:36.293Z
Learning: In `lib/utils/exchangeAuthCode.ts`, the `exchangeAuthCode` function intentionally uses `getInsecureStorage()` to store temporary authentication flow values locally between sessions. This is necessary for storing data needed for the return trip. The `getInsecureStorage()` function returns the secure storage if no active insecure storage is defined.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-10-08T23:57:58.113Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 8
File: lib/utils/token/testUtils/index.ts:3-39
Timestamp: 2024-10-08T23:57:58.113Z
Learning: The file `lib/utils/token/testUtils/index.ts` is a test utility, not production code.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-11-19T20:31:59.197Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/index.test.ts:59-62
Timestamp: 2024-11-19T20:31:59.197Z
Learning: In `lib/utils/token/index.test.ts`, the test "getInsecureStorage returns active storage when no insecure storage is set" is intentional. It verifies that when insecure storage is not set, `getInsecureStorage()` returns the active storage as a fallback, preferring secure storage but allowing for insecure storage when needed by consumers of the library.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
📚 Learning: 2024-10-25T23:50:56.599Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 15
File: lib/utils/generateAuthUrl.ts:27-30
Timestamp: 2024-10-25T23:50:56.599Z
Learning: In `lib/utils/generateAuthUrl.ts`, `StorageKeys` is imported from `../main` and includes the `state` key.

Applied to files:

  • lib/utils/exchangeAuthCode.test.ts
🔇 Additional comments (2)
lib/utils/exchangeAuthCode.test.ts (2)

13-21: LGTM! Clean mock implementation.

The local fetch mock with the jsonResponse helper is well-designed. The helper properly sets Content-Type headers and allows customization via the init parameter.


36-37: LGTM! Proper test isolation.

The setup and teardown correctly manage the fetch mock lifecycle, ensuring clean state between tests.

Also applies to: 46-47

Comment on lines 40 to 55
export function removeTrailingSlash(
url: string | undefined | null,
): string | undefined {
if (url === undefined || url === null) return undefined;

url = url.trim();
if (url.length === 0) {
return undefined;
}

if (url.endsWith("/")) {
url = url.slice(0, -1);
}

return url;
}
Copy link
Member

Choose a reason for hiding this comment

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

We have a method for this called sanatizeUrl

Copy link
Author

@dtoxvanilla1991 dtoxvanilla1991 Dec 18, 2025

Choose a reason for hiding this comment

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

Addressed 🟢 and simplified, since I think after all trimming logic here is an overkill, additionally, sanitizeUrl is designed for URL paths (normalizing slashes, preserving :// protocols) whereas cookie domains are hostnames that should never contain protocols. I think the caller should remain responsible for providing a clean domain value.

Copy link
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 (1)
lib/utils/getCookieOptions.ts (1)

7-7: Consider using a literal type for sameSite.

For better type safety, sameSite should use a literal union type instead of string:

sameSite?: "strict" | "lax" | "none";

This prevents invalid values and provides better IDE autocomplete.

🔎 View suggested change
-  sameSite?: string;
+  sameSite?: "strict" | "lax" | "none";
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d615c1 and 557652d.

📒 Files selected for processing (4)
  • lib/main.ts (1 hunks)
  • lib/utils/getCookieOptions.test.ts (1 hunks)
  • lib/utils/getCookieOptions.ts (1 hunks)
  • lib/utils/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/main.ts
  • lib/utils/getCookieOptions.test.ts
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2025-01-16T21:47:40.307Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.

Applied to files:

  • lib/utils/getCookieOptions.ts
  • lib/utils/index.ts
📚 Learning: 2024-11-19T20:35:25.531Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/refreshToken.ts:3-3
Timestamp: 2024-11-19T20:35:25.531Z
Learning: The function `sanitizeUrl` is correctly named with a lowercase 'u' in 'Url'. There is no function named `sanitizeURL` in the codebase. Ensure that import statements use `sanitizeUrl` to match the function name.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2024-10-08T23:57:58.113Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 12
File: lib/main.ts:0-0
Timestamp: 2024-10-08T23:57:58.113Z
Learning: When exporting modules in `lib/main.ts`, ensure that paths to modules like `./utils/token` are explicitly set to include `index.ts` (e.g., `./utils/token/index.ts`) to prevent missing export issues.

Applied to files:

  • lib/utils/index.ts
📚 Learning: 2024-11-10T23:29:36.293Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/exchangeAuthCode.ts:51-51
Timestamp: 2024-11-10T23:29:36.293Z
Learning: In `lib/utils/exchangeAuthCode.ts`, the `exchangeAuthCode` function intentionally uses `getInsecureStorage()` to store temporary authentication flow values locally between sessions. This is necessary for storing data needed for the return trip. The `getInsecureStorage()` function returns the secure storage if no active insecure storage is defined.

Applied to files:

  • lib/utils/index.ts
🔇 Additional comments (3)
lib/utils/index.ts (1)

12-13: LGTM! Exports follow existing patterns.

The re-exports for getCookieOptions and its types are correctly structured and consistent with other exports in this file.

lib/utils/getCookieOptions.ts (2)

14-15: Well-chosen default constants.

The 29-day maxAge and 3000-byte maxCookieLength are sensible defaults that balance usability with browser limitations.


25-32: Implementation is correct but PR description is outdated.

The function correctly merges user options with global defaults, giving user options precedence. However, the PR description mentions features that are not present in the code:

  • "emits warnings when runtime configuration is incomplete"
  • "whitespace handling and diagnostic logs to detect malformed cookie domains"
  • "Handles removeTrailingSlash edge cases"

Based on the past review comments, these features were intentionally removed. Please update the PR description to accurately reflect the current implementation.

Copy link
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 (2)
lib/utils/getCookieOptions.ts (2)

11-11: Consider removing the index signature unless arbitrary properties are required.

The [key: string]: CookieOptionValue index signature allows any additional properties beyond the explicitly defined ones. While this provides flexibility, it may silently accept typos or unintended properties (e.g., httpOnyl: true would be accepted without error).

If cookie options are meant to be strictly typed to the defined properties, consider removing the index signature. If there's a specific need for extensibility, document why arbitrary properties are allowed.

🔎 Proposed fix to remove index signature
 export interface CookieOptions {
   maxAge?: number;
   domain?: string;
   maxCookieLength?: number;
   sameSite?: string;
   httpOnly?: boolean;
   secure?: boolean;
   path?: string;
-  [key: string]: CookieOptionValue;
 }

7-7: Consider stricter typing for sameSite.

The sameSite property is currently typed as string?, which allows any string value. Standard cookie sameSite values are "strict", "lax", or "none". Using a string literal union would provide better type safety and prevent invalid values.

🔎 Proposed fix for stricter sameSite typing
 export interface CookieOptions {
   maxAge?: number;
   domain?: string;
   maxCookieLength?: number;
-  sameSite?: string;
+  sameSite?: "strict" | "lax" | "none";
   httpOnly?: boolean;
   secure?: boolean;
   path?: string;
   [key: string]: CookieOptionValue;
 }

Note: If you remove the index signature as suggested in the other comment, this change becomes straightforward. If you keep the index signature, you may need to adjust it to accommodate the union type, e.g., by using CookieOptionValue | ("strict" | "lax" | "none") for the signature.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 557652d and 2875e93.

📒 Files selected for processing (1)
  • lib/utils/getCookieOptions.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: dtoxvanilla1991
Repo: kinde-oss/js-utils PR: 184
File: lib/utils/getCookieOptions.ts:17-23
Timestamp: 2025-12-18T23:03:56.010Z
Learning: In lib/utils/getCookieOptions.ts, the `secure` flag is intentionally omitted from GLOBAL_COOKIE_OPTIONS by design because this is a universal js-utils library used across multiple Kinde SDKs and needs to support various environments including local development over HTTP. Consumers can override with `secure: true` when needed.
📚 Learning: 2025-12-18T23:03:56.010Z
Learnt from: dtoxvanilla1991
Repo: kinde-oss/js-utils PR: 184
File: lib/utils/getCookieOptions.ts:17-23
Timestamp: 2025-12-18T23:03:56.010Z
Learning: In lib/utils/getCookieOptions.ts, the `secure` flag is intentionally omitted from GLOBAL_COOKIE_OPTIONS by design because this is a universal js-utils library used across multiple Kinde SDKs and needs to support various environments including local development over HTTP. Consumers can override with `secure: true` when needed.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2025-01-16T21:47:40.307Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.307Z
Learning: Security documentation for configuration options in this codebase should be placed in the implementation file (e.g., index.ts) rather than the types file, as demonstrated with `useInsecureForRefreshToken` in `lib/sessionManager/index.ts`.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2024-11-19T20:35:25.531Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/refreshToken.ts:3-3
Timestamp: 2024-11-19T20:35:25.531Z
Learning: The function `sanitizeUrl` is correctly named with a lowercase 'u' in 'Url'. There is no function named `sanitizeURL` in the codebase. Ensure that import statements use `sanitizeUrl` to match the function name.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2025-01-28T14:24:26.982Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 69
File: lib/utils/exchangeAuthCode.ts:152-154
Timestamp: 2025-01-28T14:24:26.982Z
Learning: Security implications of insecure token storage for non-custom domains in js-utils are documented in the library documentation, and warnings are implemented through the localStorage implementation.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2025-01-16T21:47:40.306Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 61
File: lib/sessionManager/types.ts:20-20
Timestamp: 2025-01-16T21:47:40.306Z
Learning: The `useInsecureForRefreshToken` setting in `lib/sessionManager/index.ts` should only be used when not using a custom domain and when there's no backend app to authenticate on, as documented in the implementation file.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2025-01-20T20:01:21.460Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 69
File: lib/utils/token/refreshToken.ts:54-57
Timestamp: 2025-01-20T20:01:21.460Z
Learning: In the Kinde JS utils library, when not using a custom domain, local storage is used by default for storing refresh tokens. This is an intentional design decision that will be documented. Users can explicitly opt out of this behavior if needed.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2025-05-28T10:56:50.579Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 128
File: lib/utils/generateProfileUrl.ts:30-35
Timestamp: 2025-05-28T10:56:50.579Z
Learning: In the Kinde js-utils codebase, if the storage system returns non-string values for access tokens, it indicates wider systemic issues. The team prefers to keep simple type casting in generateProfileUrl rather than adding defensive type checking, as the root cause would need to be addressed elsewhere.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2024-10-08T23:57:58.113Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 8
File: lib/utils/token/testUtils/index.ts:3-39
Timestamp: 2024-10-08T23:57:58.113Z
Learning: The file `lib/utils/token/testUtils/index.ts` is a test utility, not production code.

Applied to files:

  • lib/utils/getCookieOptions.ts
📚 Learning: 2024-11-19T20:31:59.197Z
Learnt from: DanielRivers
Repo: kinde-oss/js-utils PR: 11
File: lib/utils/token/index.test.ts:59-62
Timestamp: 2024-11-19T20:31:59.197Z
Learning: In `lib/utils/token/index.test.ts`, the test "getInsecureStorage returns active storage when no insecure storage is set" is intentional. It verifies that when insecure storage is not set, `getInsecureStorage()` returns the active storage as a fallback, preferring secure storage but allowing for insecure storage when needed by consumers of the library.

Applied to files:

  • lib/utils/getCookieOptions.ts
🧬 Code graph analysis (1)
lib/utils/getCookieOptions.ts (2)
lib/utils/index.ts (3)
  • CookieOptionValue (13-13)
  • CookieOptions (13-13)
  • getCookieOptions (12-12)
lib/main.ts (3)
  • CookieOptionValue (29-29)
  • CookieOptions (29-29)
  • getCookieOptions (27-27)
🔇 Additional comments (3)
lib/utils/getCookieOptions.ts (3)

14-15: LGTM!

The constant values are correct. TWENTY_NINE_DAYS correctly represents 29 days in seconds (29 × 86,400 = 2,505,600), and MAX_COOKIE_LENGTH of 3000 bytes is a sensible limit well below typical browser cookie size constraints.


17-34: Excellent documentation addressing security concerns!

The JSDoc comment effectively explains the design decision to omit the secure flag and provides clear guidance for production deployments. The default values are sensible for a framework-agnostic utility.


54-61: LGTM!

The implementation is clean and correct. The object spread merge gives proper precedence to user-provided options while maintaining sensible defaults. The JSDoc documentation with examples and security warnings effectively guides consumers.

httpOnly?: boolean;
secure?: boolean;
path?: string;
[key: string]: CookieOptionValue;
Copy link
Member

Choose a reason for hiding this comment

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

Remove this item, as it will break typesafety.

Can remove CookieOptionValue also

Copy link
Author

Choose a reason for hiding this comment

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

Yea I was not sure if flexible option is needed just in case. Happily removed.

}

export const TWENTY_NINE_DAYS = 2505600;
export const MAX_COOKIE_LENGTH = 3000;
Copy link
Member

Choose a reason for hiding this comment

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

This should be taken from the storageSettings.maxLength

Copy link
Author

@dtoxvanilla1991 dtoxvanilla1991 Dec 20, 2025

Choose a reason for hiding this comment

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

addressed 👍🏼 . Removed 🟢

*/
export const GLOBAL_COOKIE_OPTIONS: CookieOptions = {
maxAge: TWENTY_NINE_DAYS,
maxCookieLength: MAX_COOKIE_LENGTH,
Copy link
Member

Choose a reason for hiding this comment

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

This can be read from storageSettings.maxLength once its defined, its already exported.

Copy link
Author

Choose a reason for hiding this comment

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

addressed 👍🏼

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.

2 participants