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.
In Review
π‘ Feature Request
10 months ago

Alexander Kozhurkin
Get notified by email when there are changes.
In Review
π‘ Feature Request
10 months ago

Alexander Kozhurkin
Get notified by email when there are changes.