Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web 3309 patch - Fixed hardcoded feature identification with API check based logic #345

Merged
merged 1 commit into from
Jan 28, 2025

Conversation

singhkunal2050
Copy link
Contributor

@singhkunal2050 singhkunal2050 commented Jan 27, 2025

Changes

This change fixes the issue where Chrome and Firefox IOS were not able to set up Web Push due to the hardcoded browser version check we were doing. This is replaced by a check which is API based which is more reliable and generic for all browsers.

Changes to Public Facing API if any

NA

How Has This Been Tested?

Dev Tested https://ctwebpush.netlify.app/?region=sk1-staging-4&accountId=W86-7WR-5K7Z on IOS Chrome, Safari and firefox

Checklist

  • Code compiles without errors
  • Version Bump added to package.json & CHANGELOG.md
  • [] All tests pass
  • Build process is successful
  • Documentation has been updated (if needed)

Summary by CodeRabbit

  • New Features

    • Added support for Vapid Web Push on Safari (Mac and iOS)
  • Bug Fixes

    • Improved browser identification methods
  • Chores

    • Updated SDK version from 1.11.16 to 1.12.0
    • Corrected changelog dates for previous versions

Copy link

coderabbitai bot commented Jan 27, 2025

Walkthrough

This pull request introduces version 1.12.0 of the CleverTap Web SDK, focusing on enhancing web push notification support for Safari browsers on Mac and iOS. The changes include new browser detection functions, updates to notification handling methods, and modifications to support Vapid Web Push. The SDK's versioning and changelog have been updated to reflect these improvements, with corrections to previous version dates and the addition of new feature support.

Changes

File Change Summary
CHANGELOG.md - Updated version from 1.11.16 to 1.12.0
- Corrected dates for versions 1.11.15 and 1.11.16
- Added features for Safari Web Push support
clevertap.js - Added browser detection functions (isChrome, isFirefox, isSafari)
- Updated SDK version
- Modified push notification setup methods
package.json - Version updated from 1.11.16 to 1.12.0
src/modules/notification.js - Added new constants for notification tracking
- Refactored notification setup methods
- Enhanced Safari notification support
src/modules/webPushPrompt/prompt.js - Updated push notification enable functions
- Added FCM public key handling
src/util/constants.js - Added VAPID_MIGRATION_PROMPT_SHOWN
- Added NOTIF_LAST_TIME
src/util/helpers.js - Removed tcWrapper function
- Added browser detection utility functions

Sequence Diagram

sequenceDiagram
    participant Browser
    participant SDK
    participant NotificationService
    
    Browser->>SDK: Request Web Push
    SDK->>SDK: Detect Browser Type
    alt Safari Browser
        SDK->>SDK: Check Native Web Push Support
        SDK->>NotificationService: Set Up Safari Notifications
    else Chrome/Firefox
        SDK->>NotificationService: Set Up Standard Web Push
    end
    NotificationService->>Browser: Request Notification Permission
    Browser-->>NotificationService: Permission Response
    NotificationService->>SDK: Subscription Details
    SDK->>Browser: Complete Push Setup
Loading

Possibly related PRs

Suggested reviewers

  • kkyusuftk

Poem

🐰 A Rabbit's Ode to Safari's Embrace 🌐

Web pushes dance on Mac and iOS shore,
Vapid whispers through browser's core,
Chrome, Firefox, Safari take flight,
SDK's magic shines ever so bright!
Notifications leap with newfound grace 🚀


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 013900e and 994f41e.

⛔ Files ignored due to path filters (2)
  • clevertap.js.map is excluded by !**/*.map
  • clevertap.min.js is excluded by !**/*.min.js
📒 Files selected for processing (7)
  • CHANGELOG.md (1 hunks)
  • clevertap.js (20 hunks)
  • package.json (1 hunks)
  • src/modules/notification.js (9 hunks)
  • src/modules/webPushPrompt/prompt.js (5 hunks)
  • src/util/constants.js (1 hunks)
  • src/util/helpers.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • package.json
🧰 Additional context used
🪛 LanguageTool
CHANGELOG.md

[inconsistency] ~9-~9: The suffix does not match the ordinal number.
Context: ...er Identification methods ## [1.11.16] 20nd Jan, 2025 - Fixed Web Inbox Notificatio...

(ORDINAL_NUMBER_SUFFIX)

🔇 Additional comments (13)
src/modules/notification.js (6)

4-6: Ensure constant naming is self-explanatory
The newly imported constants PUSH_SUBSCRIPTION_DATA, VAPID_MIGRATION_PROMPT_SHOWN, and NOTIF_LAST_TIME look appropriate for tracking notification-related states. Just confirm that their names are clear enough for broader team understanding and that documentation is provided where needed.


66-69: Provide a default path for unsupported browsers
The logic selectively calls #setUpChromeFirefoxNotifications or #setUpSafariNotifications if the browser matches known conditions. To avoid silent failures on other browsers, consider adding an else branch to log or handle any unrecognized environment.


190-198: Validate service worker registration timing
The logic for delaying service worker readiness by 5 seconds or verifying getRegistrations() for Firefox is functional, yet somewhat ad-hoc. If feasible, confirm that 5 seconds is consistently sufficient under various network conditions or consider more robust detection for readiness.


210-211: Limit or mask sensitive data in logs
Logging the entire subscription object (including endpoint info) can expose potentially sensitive data in the console. Consider masking or removing sensitive fields before logging in production to adhere to privacy best practices.
[security]


292-292: Clarify vapidSupportedAndMigrated usage
vapidSupportedAndMigrated helps unify Safari’s native web push with VAPID, but its usage might not be obvious at first glance. Consider a code comment or doc note clarifying how this flag interacts with the legacy APNs route.


364-364: Confirm iOS Chrome/Firefox push support
iOS Chrome and Firefox historically lacked full push capabilities, so check that logic remains consistent for these. This is especially relevant for user expectations on iOS devices.

clevertap.js (5)

210-211: LGTM: Constants for web push notification

The addition of these constants for managing web push notification state is well-structured.


5401-5463: Enhance web push notification setup for Safari

The Safari web push notification setup has been improved with VAPID support and proper error handling.

Key improvements:

  1. Checks for native web push support
  2. Handles VAPID migration
  3. Proper service worker registration and subscription
  4. Error handling for subscription failures
  5. Cleanup of existing bell wrapper elements

The implementation follows best practices for web push notifications.


5465-5498: Add validation for APNS configuration

The code properly validates APNS configuration before proceeding with Safari push notification setup.

The validation includes:

  1. Checking for required APNS Web Push ID
  2. Verifying APNS service URL
  3. Proper error logging for missing parameters

7571-7571: Update SDK version

The SDK version has been updated to 1.12.0.


5994-6014: Verify notification display conditions

The code checks multiple conditions before displaying notifications:

  1. Time-based throttling using webpush_last_notif_time
  2. Browser-specific checks
  3. VAPID migration status

However, we should add error handling for edge cases.

src/util/constants.js (1)

60-61: LGTM! Constants are well-named and follow conventions.

The new constants are appropriately named and their purpose is clear.

src/modules/webPushPrompt/prompt.js (1)

128-129: LGTM! Good use of descriptive variable.

The shouldShowNotification variable improves code readability by clearly expressing the condition's purpose.

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@singhkunal2050 singhkunal2050 changed the base branch from master to develop January 27, 2025 05:32
Copy link

@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.

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 5

🧹 Nitpick comments (11)
src/modules/notification.js (7)

12-12: Consider covering additional browsers
Using isChrome, isFirefox, and isSafari is a good start for mainstream browsers. Keep in mind that some users may be using browsers like Edge or Opera, which often share the same basic capabilities as Chrome. If possible, handle or gracefully degrade for other browsers.


44-44: Add error handling or feedback
When calling enablePush(...), consider employing additional error handling or logging if there’s a failure during the process. This allows for quicker debugging or fallback logic if push enablement fails.


77-79: Check for older browser prefixes
#isNativeWebPushSupported checks for 'PushManager' in window, which is typically sufficient, but older or unusual browsers might use prefixed or partial implementations. If you expect broad coverage, consider a fallback or specialized check for older browsers.


81-163: Unify Mac and iOS logic if possible
The #setUpSafariNotifications method contains separate code paths for VAPID-based notifications vs. the legacy Safari web push approach. Consider consolidating common logic (like logging, storing subscription data, or invoking callbacks) across the two flows to reduce duplication and improve maintainability.


217-220: Handle other Chromium-based browsers
You’re setting subscriptionData.browser = 'Chrome' or 'Firefox' upon subscription. Note that browsers like Edge, Opera, and Brave will appear as Chromium-based, so you may want to refine these classifiers or handle them consistently.


344-352: Fallback for Edge or unknown browsers
When isChrome()/isFirefox() returns false yet the browser supports web push, the code short-circuits. If you must handle other browsers for a broader user base, consider extending this logic or providing a warning.


392-409: Make askAgainTimeInSeconds user-configurable
You’re defaulting to 7 days if askAgainTimeInSeconds is not provided. This is reasonable, but you might consider making this setting easily configurable for more flexible user experiences.

clevertap.js (2)

9286-9286: Ensure SDK version consistency

The SDK version is hardcoded in multiple places. This should be maintained in a single location.

+ const SDK_VERSION = '1.12.0';

- return 'web-sdk-v1.12.0';
+ return `web-sdk-v${SDK_VERSION}`;

- lib: 'web-sdk-v1.12.0',
+ lib: `web-sdk-v${SDK_VERSION}`,

5747-5758: Improve notification frequency control

The notification frequency control logic could be enhanced for better user experience.

- if (now - notifLastTime < askAgainTimeInSeconds) {
-   if (!isSafari()) {
-     return;
-   }
-   if (vapidSupportedAndMigrated) {
-     return;
-   }
- } else {
-   StorageManager.setMetaProp(NOTIF_LAST_TIME, now);
- }

+ const shouldShowNotification = () => {
+   if (now - notifLastTime < askAgainTimeInSeconds) {
+     // Only show for Safari with VAPID migration pending
+     return isSafari() && !vapidSupportedAndMigrated;
+   }
+   StorageManager.setMetaProp(NOTIF_LAST_TIME, now);
+   return true;
+ };
+ 
+ if (!shouldShowNotification()) {
+   return;
+ }

This refactoring:

  1. Encapsulates notification timing logic
  2. Makes the code more readable and maintainable
  3. Reduces nested conditionals
src/modules/webPushPrompt/prompt.js (1)

130-145: Extract magic number to a named constant.

The popup frequency default value of 7 days should be extracted to a named constant:

+const DEFAULT_POPUP_FREQUENCY_DAYS = 7;
+
 if (shouldShowNotification) {
   if (!isSafari()) {
     document.body.appendChild(wrapper)
     if (!configData.isPreview) {
       StorageManager.setMetaProp('webpush_last_notif_time', now)
       addEventListeners(wrapper)
     }
   } else {
     const vapidSupportedAndNotMigrated = ('PushManager' in window) && 
       !StorageManager.getMetaProp(VAPID_MIGRATION_PROMPT_SHOWN) && 
       fcmPublicKey !== null
     if (vapidSupportedAndNotMigrated) {
       document.body.appendChild(wrapper)
       if (!configData.isPreview) {
         addEventListeners(wrapper)
         StorageManager.setMetaProp('webpush_last_notif_time', now)
       }
     }
   }
 }
CHANGELOG.md (1)

9-9: Fix ordinal number format in date.

Correct the date format:

-## [1.11.16] 20nd Jan, 2025
+## [1.11.16] 20th Jan, 2025
🧰 Tools
🪛 LanguageTool

[inconsistency] ~9-~9: The suffix does not match the ordinal number.
Context: ...er Identification methods ## [1.11.16] 20nd Jan, 2025 - Fixed Web Inbox Notificatio...

(ORDINAL_NUMBER_SUFFIX)

🛑 Comments failed to post (5)
clevertap.js (1)

5233-5245: 🛠️ Refactor suggestion

Improve browser detection functions with more robust checks

The browser detection functions could be enhanced for better reliability and maintainability.

const isChrome = () => {
-  const ua = navigator.userAgent;
-  return ua.includes('Chrome') || ua.includes('CriOS');
+  // Check for both Chrome and CriOS (Chrome on iOS) but exclude Edge/Opera
+  return /Chrome|CriOS/.test(navigator.userAgent) && 
+         !/Edg|OPR/.test(navigator.userAgent);
};

const isFirefox = () => {
-  const ua = navigator.userAgent;
-  return ua.includes('Firefox') || ua.includes('FxiOS');
+  // Check for both Firefox and FxiOS (Firefox on iOS)
+  return /Firefox|FxiOS/.test(navigator.userAgent);
};

const isSafari = () => {
-  const ua = navigator.userAgent;
-  return ua.includes('Safari') && !ua.includes('CriOS') && !ua.includes('FxiOS') && !ua.includes('Chrome') && !ua.includes('Firefox');
+  // More reliable Safari detection
+  return /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
};

The improvements include:

  • More precise browser detection using regex patterns
  • Better handling of edge cases like Edge/Opera browsers
  • More maintainable and readable code structure
  • Improved Safari detection to avoid false positives
📝 Committable suggestion

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

  const isChrome = () => {
    // Check for both Chrome and CriOS (Chrome on iOS) but exclude Edge/Opera
    return /Chrome|CriOS/.test(navigator.userAgent) && 
           !/Edg|OPR/.test(navigator.userAgent);
  };
  const isFirefox = () => {
    // Check for both Firefox and FxiOS (Firefox on iOS)
    return /Firefox|FxiOS/.test(navigator.userAgent);
  };
  const isSafari = () => {
    // More reliable Safari detection
    return /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
  };
src/util/helpers.js (3)

6-9: 🛠️ Refactor suggestion

Consider using feature detection for Firefox.

Similar to Chrome, Firefox can be detected more reliably using feature detection:

 export const isFirefox = () => {
-  const ua = navigator.userAgent
-  return ua.includes('Firefox') || ua.includes('FxiOS')
+  return typeof InstallTrigger !== 'undefined'
 }
📝 Committable suggestion

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

export const isFirefox = () => {
  return typeof InstallTrigger !== 'undefined'
}

1-4: 🛠️ Refactor suggestion

Consider using feature detection for Chrome.

Instead of relying on user agent strings which can be spoofed, consider using feature detection:

 export const isChrome = () => {
-  const ua = navigator.userAgent
-  return ua.includes('Chrome') || ua.includes('CriOS')
+  return window.chrome !== undefined && navigator.vendor === 'Google Inc.'
 }
📝 Committable suggestion

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

export const isChrome = () => {
  return window.chrome !== undefined && navigator.vendor === 'Google Inc.'
}

11-18: 🛠️ Refactor suggestion

Consider using feature detection for Safari.

The current implementation handles false positives well, but feature detection would be more reliable:

 export const isSafari = () => {
-  const ua = navigator.userAgent
-  // Ignoring the False Positive of Safari on iOS devices because it gives Safari in all Browsers
-  return ua.includes('Safari') &&
-         !ua.includes('CriOS') &&
-         !ua.includes('FxiOS') &&
-         !ua.includes('Chrome') &&
-         !ua.includes('Firefox')
+  return /^((?!chrome|android).)*safari/i.test(navigator.userAgent) &&
+         'safari' in window
 }

Committable suggestion skipped: line range outside the PR's diff.

src/modules/webPushPrompt/prompt.js (1)

27-27: 🛠️ Refactor suggestion

Validate fcmPublicKey parameter.

Consider adding parameter validation to handle undefined/null cases explicitly:

-export const enablePush = (logger, account, request, customSwPath, skipDialog, fcmPublicKey) => {
+export const enablePush = (logger, account, request, customSwPath, skipDialog, fcmPublicKey = null) => {
📝 Committable suggestion

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

export const enablePush = (logger, account, request, customSwPath, skipDialog, fcmPublicKey = null) => {

@singhkunal2050 singhkunal2050 merged commit ee75c1f into develop Jan 28, 2025
3 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Feb 6, 2025
5 tasks
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