Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 22 additions & 5 deletions src/background/service-worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ console.log('ProofSnap background service worker loaded');
const assetStorage = indexedDBService;
const metadataStorage = storageService;

// Initialize storage services
Promise.all([
// Readiness gate: all message handlers must await this before accessing storage
const initPromise = Promise.all([
assetStorage.init(),
metadataStorage.init()
]).then(async () => {
Expand Down Expand Up @@ -96,7 +96,10 @@ chrome.runtime.onMessage.addListener((message: ExtensionMessage, _sender, sendRe

switch (message.type) {
case 'CAPTURE_SCREENSHOT':
handleScreenshotCaptureMessage(message as CaptureScreenshotMessage)
(async () => {
await initPromise;
return handleScreenshotCaptureMessage(message as CaptureScreenshotMessage);
})()
.then((result) => {
if (result && result.cancelled) {
sendResponse({ success: false, cancelled: true });
Expand All @@ -108,7 +111,10 @@ chrome.runtime.onMessage.addListener((message: ExtensionMessage, _sender, sendRe
return true; // Keep channel open for async response

case 'UPLOAD_ASSET':
handleAssetUpload(message.payload)
(async () => {
await initPromise;
return handleAssetUpload(message.payload);
})()
.then(() => sendResponse({ success: true }))
.catch((error) => sendResponse({ success: false, error: error.message }));
return true;
Expand All @@ -117,6 +123,7 @@ chrome.runtime.onMessage.addListener((message: ExtensionMessage, _sender, sendRe
console.log('Starting Google Auth in background...');
(async () => {
try {
await initPromise;
const numbersApi = await getNumbersApi();

// 1. Get ID Token via Chrome Identity (interactive flow)
Expand All @@ -140,7 +147,10 @@ chrome.runtime.onMessage.addListener((message: ExtensionMessage, _sender, sendRe

case 'SELECTION_COMPLETE':
// Handle selection complete from content script
handleSelectionComplete(message.payload);
(async () => {
await initPromise;
await handleSelectionComplete(message.payload);
})().catch((error) => console.error('Error handling SELECTION_COMPLETE:', error));
sendResponse({ success: true });
return false;

Expand Down Expand Up @@ -185,6 +195,13 @@ async function handleSelectionCapture(tab: chrome.tabs.Tab): Promise<any> {

// Wait for selection to complete via message
return new Promise((resolve, reject) => {
// If there is already a pending selection, cancel it before starting a new one
if (pendingSelectionReject) {
pendingSelectionReject(new Error('Selection cancelled: a new selection was started'));
pendingSelectionResolve = null;
pendingSelectionReject = null;
}

pendingSelectionResolve = resolve;
pendingSelectionReject = reject;

Expand Down
17 changes: 15 additions & 2 deletions src/services/NumbersApiManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ export class NumbersApiManager {
async clearAuth(): Promise<void> {
await this.auth.clearAuth();
await storageService.clearAuth();
resetInstance();
}

/**
Expand Down Expand Up @@ -150,10 +151,22 @@ export class NumbersApiManager {
// Lazy singleton pattern
let instance: NumbersApiManager | null = null;

export function resetInstance(): void {
instance = null;
}

export async function getNumbersApi(): Promise<NumbersApiManager> {
if (!instance) {
instance = new NumbersApiManager();
await instance.initialize();
const manager = new NumbersApiManager();
instance = manager;
await manager.initialize();
// If clearAuth() was called during initialize (stale/invalid token),
// instance was reset; provide a fresh unauthenticated manager.
if (!instance) {
const freshManager = new NumbersApiManager();
instance = freshManager;
await freshManager.initialize();
}
}
return instance;
}