Repository: novuhq/novu
File: packages/add-inbox/src/generators/frameworks/react.ts (TypeScript)

Code before:

    if (major > 17) return true;
    if (major === 17 && minor >= 0) return true;

    return false;
  } catch (error) {
    // If anything goes wrong, default to legacy React (not modern)
    return false;
  }
}

function generateSharedInboxCode(
  subscriberId: string | null, 
  region: string = 'us', 
  envAccessor: string,
  backendUrl: string | null = null,
  socketUrl: string | null = null
): string {
  // Use custom URLs if provided, otherwise fall back to region-based URLs
  const finalBackendUrl = backendUrl || (region === 'eu' ? 'https://eu.api.novu.co' : null);
  const finalSocketUrl = socketUrl || (region === 'eu' ? 'https://eu.ws.novu.co' : null);

  // Build URL props string
  let urlProps = '';
  if (finalBackendUrl || finalSocketUrl) {
    const props = [];
    if (finalBackendUrl) {
      props.push(`backendUrl="${finalBackendUrl}"`);
    }
    if (finalSocketUrl) {
      props.push(`socketUrl="${finalSocketUrl}"`);
    }
    urlProps = `\n    ${props.join(' ')}`;
  }

  return `import { Inbox } from '@novu/react';

// import { dark } from '@novu/react/themes'; => To enable dark theme support, uncomment this line.

export function NovuInbox() {
 // ${subscriberId ? 'Using provided subscriber ID - replace with your actual subscriber ID from your auth system' : 'TODO: Replace with your actual subscriber ID from your auth system'}
 const temporarySubscriberId = ${subscriberId ? `"${subscriberId.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"` : '""'};

  const tabs = [
    // Basic tab with no filtering (shows all notifications)
    {
      label: 'All',
      filter: { tags: [] },
    },
    
    // Filter by tags - shows notifications from workflows tagged "promotions"

Review comment (security):
Missing string escaping for URL values.

Unlike the Next.js implementation, this code doesn't escape the URL strings before injecting them into the generated code. This could lead to issues if URLs contain special characters like quotes or backslashes.

```
   let urlProps = '';
   if (finalBackendUrl || finalSocketUrl) {
     const props = [];
     if (finalBackendUrl) {
-      props.push(`backendUrl="${finalBackendUrl}"`);
+      props.push(`backendUrl="${finalBackendUrl.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`);
     }
     if (finalSocketUrl) {
-      props.push(`socketUrl="${finalSocketUrl}"`);
+      props.push(`socketUrl="${finalSocketUrl.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`);
     }
     urlProps = `\n    ${props.join(' ')}`;
   }
```


Code after:

    if (major > 17) return true;
    if (major === 17 && minor >= 0) return true;

    return false;
  } catch (error) {
    // If anything goes wrong, default to legacy React (not modern)
    return false;
  }
}

function generateSharedInboxCode(
  subscriberId: string | null, 
  region: string = 'us', 
  envAccessor: string,
  backendUrl: string | null = null,
  socketUrl: string | null = null
): string {
  // Use custom URLs if provided, otherwise fall back to region-based URLs
  const finalBackendUrl = backendUrl || (region === 'eu' ? 'https://eu.api.novu.co' : null);
  const finalSocketUrl = socketUrl || (region === 'eu' ? 'wss://eu.ws.novu.co' : null);

  const escapeString = (str: string) =>
    str.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');

  // Build URL props string
  let urlProps = '';
  if (finalBackendUrl || finalSocketUrl) {
    const props = [];
    if (finalBackendUrl) {
      props.push(`backendUrl="${escapeString(finalBackendUrl)}"`);
    }
    if (finalSocketUrl) {
      props.push(`socketUrl="${escapeString(finalSocketUrl)}"`);
    }
    urlProps = `\n    ${props.join(' ')}`;
  }

  return `import { Inbox } from '@novu/react';

// import { dark } from '@novu/react/themes'; => To enable dark theme support, uncomment this line.

export function NovuInbox() {
 // ${subscriberId ? 'Using provided subscriber ID - replace with your actual subscriber ID from your auth system' : 'TODO: Replace with your actual subscriber ID from your auth system'}
 const temporarySubscriberId = ${subscriberId ? `"${escapeString(subscriberId)}"` : '""'};

  const tabs = [
    // Basic tab with no filtering (shows all notifications)
    {
      label: 'All',
      filter: { tags: [] },