Skip to content

feat: User activity tracking#1339

Open
asafshen wants to merge 9 commits intomainfrom
user-activity-tracking
Open

feat: User activity tracking#1339
asafshen wants to merge 9 commits intomainfrom
user-activity-tracking

Conversation

@asafshen
Copy link
Member

Related Issues

Fixes https://github.com/descope/etc/issues/13944

Description

User activity tracking (opt in)

asafshen and others added 5 commits January 28, 2026 20:42
Replace localStorage opt-in + DOM listener approach with a config-driven
developer-managed API: `autoRefresh: { whenActive: true }` + `sdk.markActive()`.

- `withAutoRefresh`: parse `autoRefresh` as `boolean | { whenActive }`;
  expose `markActive()` on the SDK (no-op when not in whenActive mode);
  remove DOM event listeners and localStorage check
- `types.ts`: `autoRefresh` now accepts `boolean | AutoRefreshConfig`
- `react-sdk` AuthProvider: update `autoRefresh` prop type to `AutoRefreshConfig`
- `react-sdk` types/useSdk: add `markActive` to `Sdk` type
- `react-sdk` example: add `ActivityTracker` component with click/keydown listeners
- READMEs: document new API

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@shuni-bot-dev
Copy link

shuni-bot-dev bot commented Feb 23, 2026

✅ Code review completed successfully

#1339

@vercel
Copy link

vercel bot commented Feb 23, 2026

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

Project Deployment Actions Updated (UTC)
access-key-management-widget Ready Ready Preview, Comment Mar 2, 2026 4:22pm
audit-management-widget Ready Ready Preview, Comment Mar 2, 2026 4:22pm
role-management-widget Ready Ready Preview, Comment Mar 2, 2026 4:22pm
user-management-widget Ready Ready Preview, Comment Mar 2, 2026 4:22pm
user-profile-widget Ready Ready Preview, Comment Mar 2, 2026 4:22pm

Request Review

@nx-cloud
Copy link

nx-cloud bot commented Feb 23, 2026

View your CI Pipeline Execution ↗ for commit 7b7be3a

Command Status Duration Result
nx affected --target test ❌ Failed 3m 57s View ↗
nx affected --target lint --fix=true ✅ Succeeded 1s View ↗
nx affected --target build ✅ Succeeded 40s View ↗
nx affected --target licenseCheck ✅ Succeeded <1s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-02 16:29:46 UTC

import { getLocalStorage } from '../helpers';

// localStorage key for opt-in activity-based refresh
export const ACTIVITY_REFRESH_KEY = '__descope_activity_refresh';
Copy link

Choose a reason for hiding this comment

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

🟠 HIGH: Dead code - ACTIVITY_REFRESH_KEY is defined but never used in the codebase.

The code defines a localStorage key for "opt-in activity-based refresh", but this localStorage approach isn't actually used in the implementation. The whenActive flag is passed directly via the config object instead.

Recommendation: Remove this constant and the related isActivityRefreshEnabled() function (lines 20-27) if localStorage-based opt-in is not needed.

}, ACTIVITY_DEBOUNCE_MS);
};

const attachListeners = () => {
Copy link

Choose a reason for hiding this comment

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

🟠 HIGH: attachListeners() and detachListeners() methods are never called.

The activity tracker creates these methods for automatic DOM event listening, but they're never invoked in withAutoRefresh/index.ts. This means:

  1. The automatic event listeners (mousemove, keydown, touchstart, scroll, click, pointerdown) are never attached
  2. Developers must manually call sdk.markActive() for activity tracking to work
  3. There's confusion between automatic vs manual activity tracking

Recommendation: Either:

  • Remove these unused methods if manual sdk.markActive() calls are the intended design
  • OR call attachListeners() when whenActive is enabled and detachListeners() on cleanup

The current implementation creates dead code that suggests functionality that doesn't exist.

@shuni-bot-dev
Copy link

shuni-bot-dev bot commented Feb 23, 2026

🐕 Shuni Code Review

Summary

This PR adds activity-based session refresh functionality, allowing developers to skip refresh calls for idle users. The feature is well-intentioned and addresses a real need for reducing unnecessary API calls. However, there are several code quality issues that should be addressed before merging, including dead code, missing test coverage, and a memory leak in event listener cleanup.

Findings by Severity

🔴 Critical Issues (0)

No critical security vulnerabilities or data loss risks identified.

🟠 High Priority Issues (3)

  1. Dead code - Unused localStorage functions: ACTIVITY_REFRESH_KEY and isActivityRefreshEnabled() are defined but never used. This suggests incomplete implementation or abandoned approach. (helpers.ts:7)

  2. Dead code - Unused event listener methods: attachListeners() and detachListeners() are fully implemented but never called, creating confusion about whether activity tracking is automatic or manual. (helpers.ts:64)

  3. Memory leak - visibilitychange listener: Event listener added on line 67 of index.ts is never removed, causing memory leak when SDK is recreated or page unmounted. (index.ts:67)

🟡 Medium Priority Issues (2)

  1. Missing test coverage: No tests for the new whenActive feature in test/autoRefresh.test.ts. Critical scenarios like activity tracking, idle behavior, and activity-triggered refresh are untested. (index.ts:138)

  2. Commented code in production: Lines 17-20 and 46 in App.tsx contain commented-out example code that should be removed or moved to documentation. (App.tsx:17)

🟢 Low Priority Suggestions (2)

  1. Unused import: getLocalStorage is imported in helpers.ts but only used in the unused isActivityRefreshEnabled() function.

  2. Comment clarity: The comment on line 97 of helpers.ts mentions "visibility change" but markActive() is general-purpose, not specific to visibility changes.

✅ Strengths

  • Clear API design: The autoRefresh={{ whenActive: true }} config option is intuitive and well-documented
  • Good documentation: README examples are comprehensive and easy to follow
  • Backward compatible: Existing autoRefresh={true} behavior is preserved
  • Debouncing strategy: 1-second debounce on activity events prevents excessive processing
  • Server-side coordination: Works well with Descope's session inactivity feature

Security Assessment

No security vulnerabilities identified. The implementation:

  • ✅ Uses passive event listeners correctly
  • ✅ Doesn't store sensitive data
  • ✅ Doesn't introduce XSS or injection risks
  • ✅ Handles JWT expiration safely
  • ✅ Preserves existing security patterns

Code Quality Assessment

Architecture: Generally follows existing patterns but has dead code that suggests incomplete refactoring.

Maintainability: Good documentation but dead code reduces clarity.

Performance: Debouncing strategy is appropriate, though unused listener methods suggest potential confusion.

Overall Recommendation

REQUEST CHANGES ⚠️

The feature implementation is solid, but code quality issues should be resolved before merging:

  1. Remove dead code (ACTIVITY_REFRESH_KEY, isActivityRefreshEnabled, unused listener methods)
  2. Fix memory leak by cleaning up visibilitychange listener
  3. Add test coverage for new feature
  4. Remove commented code from example files

These are straightforward fixes that will significantly improve code maintainability.

Next Steps

  1. Required: Remove dead code and fix memory leak
  2. Required: Add test coverage for whenActive feature
  3. Required: Remove commented code from App.tsx
  4. Recommended: Consider whether automatic event listeners should be implemented or removed entirely
  5. Optional: Add JSDoc comments to new public methods (markActive)

🤖 Automated review by Shuni (Claude Opus 4.6)
Note: Oracle agent was unavailable for this review due to model access issues, but comprehensive manual analysis was performed.

asafshen and others added 2 commits February 24, 2026 08:24
Remove unused DOM listener code (ACTIVITY_EVENTS, ACTIVITY_REFRESH_KEY,
isActivityRefreshEnabled, attachListeners, detachListeners, debounce logic)
left over from the previous localStorage opt-in approach.

Add JSDoc to createActivityTracker describing its state and flow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@asafshen
Copy link
Member Author

  1. remove comments from the react smaple app (or think how to configure this)
  2. add tests (build fails because coverage in web-js-sdk)

… var

- Add 6 tests covering whenActive activity-based refresh: idle skip,
  catch-up refresh on markActive, no-op without prior skip, active user
  timer flow, and no-op when whenActive is not set
- Uncomment ActivityTracker in react-sdk example, controlled by
  DESCOPE_ACTIVITY_TRACKING=true env var

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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