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

10 months ago

Author

Alexander Kozhurkin

Subscribe to post

Get notified by email when there are changes.