Skip to content

feat: enhance callback data handling by supporting URL hash for encrypted data#32

Merged
elibosley merged 2 commits into
mainfrom
feat/use-hash-instead-of-query-param
Dec 12, 2025
Merged

feat: enhance callback data handling by supporting URL hash for encrypted data#32
elibosley merged 2 commits into
mainfrom
feat/use-hash-instead-of-query-param

Conversation

@elibosley
Copy link
Copy Markdown
Member

@elibosley elibosley commented Dec 12, 2025

Summary by CodeRabbit

  • New Features

    • Added configuration to choose where encrypted callback data is stored (hash by default or query parameter).
  • Documentation

    • Added URL format configuration docs describing default behavior and parsing support for both hash and query parameter formats.
  • Tests

    • Updated and added tests to cover hash-based and query-parameter modes and related URL handling.
  • Chore

    • Restored some dev dependencies and updated package manager configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 12, 2025

📝 Walkthrough

Walkthrough

Adds a CallbackConfig.useHash option (default true) and updates URL generation, parsing, and watcher logic so encrypted callback data is placed in the URL hash by default or in the data query parameter when disabled; tests and README updated to reflect both formats.

Changes

Cohort / File(s) Summary
Documentation
README.md
Adds URL format configuration section describing default hash-based placement of encrypted callback data and the CallbackConfig.useHash flag; documents that parsing helpers support both hash and data query formats.
Type Definitions
src/types.ts
Adds useHash?: boolean to CallbackConfig to toggle hash (true) vs query-parameter (false) placement.
Core Implementation
src/index.ts
Adds conditional logic to write/read encrypted payload to/from the URL hash or data query parameter depending on useHash; parsing prefers query param but falls back to hash variants for compatibility.
Tests
src/__tests__/useSharedCallback.test.ts
Switches to dynamic per-test import of useCallback; updates expectations to read from url.hash; adds tests covering useHash: false (query param mode) and hash-based parsing/generation; adjusts mocks for window.open/location.
Package metadata
package.json
Restores devDependencies (@vueuse/core, rimraf), bumps pnpm tool version, and adds esbuild to pnpm.onlyBuiltDependencies.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–30 minutes

  • Review focus:
    • src/index.ts — conditional branches for hash vs query parameter handling and fallback precedence.
    • src/__tests__/useSharedCallback.test.ts — dynamic import pattern, test isolation, and correctness of new assertions for both modes.
    • README — ensure documented behavior matches implemented default and edge-case parsing.

Poem

🐰 I hid the secret in the hash tonight,
A tiny flag to set it right.
Query or fragment, choose your tune,
I hop between them by the moon.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main change: adding support for storing encrypted callback data in the URL hash instead of query parameters, which is the primary focus across all modified files (types, index.ts, tests, and documentation).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/use-hash-instead-of-query-param

Comment @coderabbitai help to get the list of available commands and usage tips.

@elibosley elibosley force-pushed the feat/use-hash-instead-of-query-param branch from 3ed8c9c to b4ecb6a Compare December 12, 2025 19:08
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: 0

🧹 Nitpick comments (1)
src/__tests__/useSharedCallback.test.ts (1)

7-7: Type any is acceptable here for test flexibility.

The dynamic import pattern requires this, but consider using the actual type if available:

-let useCallback: any
+let useCallback: typeof import('../index')['useCallback']
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be29ddc and b4ecb6a.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • src/__tests__/useSharedCallback.test.ts (15 hunks)
  • src/index.ts (4 hunks)
  • src/types.ts (1 hunks)
🔇 Additional comments (10)
README.md (1)

80-98: Documentation looks good and accurately reflects the implementation.

The explanation of the security benefit (preventing sensitive data from being sent in referrers) is helpful context for users. The interface definition matches src/types.ts.

Minor note: Line 85 references useCallback, but the earlier usage example (lines 21-48) shows createCallbackStore. Consider clarifying the relationship or updating the example to show useCallback usage with the config.

src/types.ts (1)

185-193: Type definition is clean and well-documented.

The optional useHash property with JSDoc comment clearly communicates the default behavior. The implementation in src/index.ts correctly uses config.useHash !== false to treat undefined as true.

src/index.ts (4)

103-104: Correct default behavior for useHash.

Using !== false ensures that both undefined and true result in hash-based URLs, which matches the documented default.


126-131: Hash vs query parameter switching looks correct.

The implementation consistently uses encodeURI for both paths, maintaining parity between the two modes.


172-202: Parsing logic is thorough but has a minor edge case consideration.

The fallback chain (searchParamData || hashData) correctly prioritizes query parameter for backward compatibility while supporting hash-based data.

Note: Lines 189-194 support parsing #data=... format in the hash, but send() and generateUrl() only produce raw #encryptedData format. This is fine for robustness, but if intentional for future use, consider adding a comment explaining when #data=... in hash would occur.


232-237: generateUrl correctly mirrors the send logic.

Consistent behavior between send() and generateUrl() for hash vs query parameter switching.

src/__tests__/useSharedCallback.test.ts (4)

14-38: Dynamic re-import pattern is necessary and correctly implemented.

Since createSharedComposable caches the composable instance, re-importing the module fresh per test is the right approach to allow different configurations. The chained .then() calls work correctly with vitest's async beforeEach support.


172-190: Good test coverage for query parameter mode.

This test verifies the useHash: false configuration works correctly for the send() function, ensuring backward compatibility is maintained.


296-314: Good test for hash-based watcher parsing.

This complements the existing query-param-based baseUrl test and ensures the watcher correctly extracts data from URL hash.


535-555: Comprehensive test for generateUrl with useHash: false.

Properly verifies that the query parameter mode works in URL generation and that the data can be successfully parsed back.

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 12, 2025

Codecov Report

❌ Patch coverage is 96.00000% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 98.06%. Comparing base (be29ddc) to head (9c93dcc).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/index.ts 96.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##              main      #32      +/-   ##
===========================================
- Coverage   100.00%   98.06%   -1.94%     
===========================================
  Files            2        2              
  Lines          134      155      +21     
  Branches        38       47       +9     
===========================================
+ Hits           134      152      +18     
- Misses           0        3       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@elibosley elibosley merged commit 4114a8e into main Dec 12, 2025
2 of 5 checks passed
@elibosley elibosley deleted the feat/use-hash-instead-of-query-param branch December 12, 2025 19:34
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: 0

Caution

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

⚠️ Outside diff range comments (2)
src/__tests__/useSharedCallback.test.ts (2)

14-49: Refactor redundant window mocking and consider performance impact.

The beforeEach has two issues:

  1. Redundant window stubbing (lines 17-27): The window is stubbed if undefined, but lines 36-49 immediately re-mock window.open and window.location with more detailed implementations, making the initial stub unnecessary.

  2. Performance concern (line 31): vi.resetModules() runs before every test, causing the module to be re-imported fresh each time. While this enables per-test configuration despite createSharedComposable, it may significantly slow down the test suite as it grows.

Apply this diff to remove redundant window stubbing:

   beforeEach(async () => {
     vi.clearAllMocks()
-
-    // Ensure window exists (JS DOM or stubbed) before importing the module.
-    if (typeof window === 'undefined') {
-      vi.stubGlobal('window', {
-        location: {
-          href: 'http://test.com/Tools/Update',
-          toString: () => 'http://test.com/Tools/Update',
-          replace: vi.fn(),
-        },
-        open: vi.fn(),
-      })
-    }
 
     // Re-import useCallback fresh for each test so configuration
     // (including useHash) can vary per test despite createSharedComposable.

Consider grouping tests by configuration to minimize resetModules() calls. For example, use nested describe blocks for useHash: true (default) and useHash: false tests, resetting modules only when switching between configurations.


301-308: Remove commented-out code.

The commented code blocks should be removed to improve readability and maintainability.

Apply this diff:

-      // The global URL is already mocked in setup.ts
-      // const originalURL = global.URL
-      // global.URL = MockURL as any // Use the mocked URL class
 
       const result = callback.watcher({ baseUrl: url.toString() })
       
-      // Restore the original URL constructor
-      // global.URL = originalURL
-      
       expect(result).toEqual(testData)
🧹 Nitpick comments (3)
src/__tests__/useSharedCallback.test.ts (3)

7-8: Consider explicit typing.

While any is acceptable in test code, consider typing useCallback explicitly as ReturnType<typeof import('../index').useCallback> for better type safety and IDE support.


100-102: Extract repeated hash extraction logic.

The hash extraction pattern url.hash.startsWith('#data=') ? url.hash.slice('#data='.length) : '' is repeated throughout the test file. Consider extracting this into a helper function to follow DRY principles.

Add a helper function at the top of the test suite:

function extractHashData(url: URL): string {
  return url.hash.startsWith('#data=')
    ? url.hash.slice('#data='.length)
    : ''
}

Then replace all instances with:

-      const encryptedData = url.hash.startsWith('#data=')
-        ? url.hash.slice('#data='.length)
-        : ''
+      const encryptedData = extractHashData(url)

Also applies to: 123-125, 152-154, 442-444, 462-464, 485-487, 548-550


642-642: Remove trailing blank line.

Minor formatting: remove the extra blank line at the end of the file.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b4ecb6a and 9c93dcc.

📒 Files selected for processing (3)
  • package.json (1 hunks)
  • src/__tests__/useSharedCallback.test.ts (15 hunks)
  • src/index.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/index.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/__tests__/useSharedCallback.test.ts (5)
src/index.ts (2)
  • useCallback (248-248)
  • ExternalSignOut (282-282)
dist/index.js (2)
  • useCallback (106-106)
  • useCallback (106-106)
dist/index.d.ts (1)
  • ExternalSignOut (10-10)
dist/types.d.ts (1)
  • ExternalSignOut (75-77)
src/types.ts (1)
  • ExternalSignOut (131-133)
🔇 Additional comments (6)
src/__tests__/useSharedCallback.test.ts (4)

190-207: Good test coverage for backward compatibility.

The new tests for useHash: false mode provide excellent coverage for the query parameter fallback, ensuring backward compatibility when the hash-based approach is disabled.

Also applies to: 560-580


313-331: Good coverage for hash-based baseUrl.

This test correctly validates that the watcher can parse data from the URL hash when a baseUrl is provided, aligning with the new hash-based data handling feature.


439-450: Correctly updated expectations for hash-based data.

The test expectations have been properly updated to verify that generateUrl places encrypted data in the URL hash by default, aligning with the new feature behavior.

Also applies to: 512-514, 525-526, 538-539


636-640: SSR test correctly updated.

The server-side rendering test for generateUrl has been properly updated to verify hash-based data handling, ensuring the feature works in SSR contexts.

package.json (2)

33-34: Restored devDependencies are secure.

@vueuse/core@^13.0.0 and rimraf@^6.0.0 have no direct known vulnerabilities. However, consider upgrading rimraf to ^6.1.2 to include transitive dependency fixes (e.g., glob-parent patching).


38-38: pnpm version 10.25.0 is legitimate and recently released.

The version was officially released on December 8, 2025, with improvements to per-registry inline certificate support, a new pnpm init --bare flag, and several patch fixes. Update this version safely. Note that pnpm 10.x has a breaking change: dependency lifecycle scripts are not executed during install by default (a security measure). If any dependencies require install/build scripts, they should be added to pnpm.onlyBuiltDependencies in package.json.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant