Add TypeScript Example to Install Script Instructions

Hey team.
It would be great to include a TypeScript implementation in the install/setup script examples of background.js.

Right now, the docs only show a plain JavaScript version, which causes TypeScript to complain about missing types or implicit anys.

Since most projects today use TS by default, having a TypeScript-friendly snippet (with proper typings) would make onboarding much smoother.

Here’s an example of a version with typings:

// use same paywall id everywhere
export const PAYWALL_ID = XXX;

const connectedPorts = new Set<chrome.runtime.Port>();

chrome.runtime.onConnectExternal.addListener(port => {
  if (
    port.sender?.url &&
    (port.sender.url.includes('onlineapp.pro') ||
      port.sender.url.includes('onlineapp.live') ||
      port.sender.url.includes('onlineapp.stream'))
  ) {
    connectedPorts.add(port);

    port.onDisconnect.addListener(() => {
      connectedPorts.delete(port);
    });
  } else {
    console.warn('Connection attempt from unauthorized domain:', port.sender?.url);
    port.disconnect();
  }
});

function trackEvent(eventName: string, additionalData = {}) {
  getUserId((userId: string) => {
    fetch('https://onlineapp.pro/api/track-event', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        event: eventName,
        wallId: PAYWALL_ID,
        extensionId: chrome.runtime.id,
        userId: userId,
        ...additionalData,
      }),
    });
  });
}

function notifyConnectedClients(notification: Record<string, any>) {
  connectedPorts.forEach(port => {
    try {
      port.postMessage(notification);
    } catch (error) {
      console.error('Error sending notification to port:', error);
      connectedPorts.delete(port);
    }
  });
}

function getUserId(callback: (user_id: string) => void) {
  chrome.storage.sync.get(['user_id'], result => {
    if (result.user_id) {
      callback(result.user_id);
    } else {
      const userId = crypto.randomUUID();
      chrome.storage.sync.set({ user_id: userId, ['pw-591-visitor-id']: userId }, () => {
        callback(userId);
      });
    }
  });
}

chrome.runtime.onMessageExternal.addListener((message, sender, sendResponse) => {
  if (
    sender.url &&
    (sender.url.includes('onlineapp.pro') ||
      sender.url.includes('onlineapp.live') ||
      sender.url.includes('onlineapp.stream'))
  ) {
    if (message.source === 'supabase-auth-adapter') {
      switch (message.action) {
        case 'ping':
          sendResponse({ status: 'ok' });
          break;

        case 'getItem':
          try {
            const { key } = message.data;
            chrome.storage.sync.get(key, result => {
              if (chrome.runtime.lastError) {
                const errorMessage = chrome.runtime.lastError.message;
                console.error('Storage error:', errorMessage);
                sendResponse({ status: 'error', message: errorMessage });
              } else {
                sendResponse({ status: 'success', value: result[key] || null });
              }
            });
            return true;
          } catch (error) {
            if (error instanceof Error) {
              console.error('Error in getItem:', error);
              sendResponse({ status: 'error', message: error.message });
            }
          }
          break;

        case 'setItem':
          try {
            const { key, value } = message.data;
            chrome.storage.sync.set({ [key]: value }, () => {
              if (chrome.runtime.lastError) {
                const errorMessage = chrome.runtime.lastError.message;
                console.error('Storage error:', errorMessage);
                sendResponse({ status: 'error', message: errorMessage });
              } else {
                sendResponse({ status: 'success' });
                notifyConnectedClients({
                  type: 'storage_update',
                  action: 'set',
                  key,
                  value,
                  timestamp: Date.now(),
                });
              }
            });
            return true;
          } catch (error) {
            if (error instanceof Error) {
              console.error('Error in setItem:', error);
              sendResponse({ status: 'error', message: error.message });
            }
          }
          break;

        case 'removeItem':
          try {
            const { key } = message.data;
            chrome.storage.sync.remove(key, () => {
              if (chrome.runtime.lastError) {
                const errorMessage = chrome.runtime.lastError.message;
                console.error('Storage error:', errorMessage);
                sendResponse({ status: 'error', message: errorMessage });
              } else {
                notifyConnectedClients({
                  type: 'storage_update',
                  action: 'remove',
                  key,
                  timestamp: Date.now(),
                });
                sendResponse({ status: 'success' });
              }
            });
            return true;
          } catch (error) {
            if (error instanceof Error) {
              console.error('Error in removeItem:', error);
              sendResponse({ status: 'error', message: error.message });
            }
          }
          break;

        default:
          console.warn('Unknown action:', message.action);
          sendResponse({ status: 'error', message: 'Unknown action' });
          break;
      }
    } else if (message.type === 'broadcast') {
      notifyConnectedClients(message.data || message);

      sendResponse({
        status: 'success',
        message: 'Message broadcasted successfully',
        clientsCount: connectedPorts.size,
      });
    } else {
      console.warn('Message has neither source nor type');
      sendResponse({ status: 'error', message: 'Invalid message format' });
    }
  } else {
    console.warn('Message from unauthorized domain:', sender.url);
    sendResponse({ status: 'error', message: 'Unauthorized domain' });
  }

  return true;
});

Please authenticate to join the conversation.

Upvoters
Status

In Review

Board

πŸ’‘ Feature Request

Date

3 months ago

Author

Alexander Kozhurkin

Subscribe to post

Get notified by email when there are changes.