Files
gridpilot.gg/packages/infrastructure/adapters/ipc/ElectronCheckoutConfirmationAdapter.ts
2025-11-26 17:03:29 +01:00

90 lines
3.0 KiB
TypeScript

/**
* ElectronCheckoutConfirmationAdapter
* Implements ICheckoutConfirmationPort using Electron IPC for main-renderer communication.
*/
import type { BrowserWindow } from 'electron';
import { ipcMain } from 'electron';
import { Result } from '../../../shared/result/Result';
import type { ICheckoutConfirmationPort, CheckoutConfirmationRequest } from '../../../application/ports/ICheckoutConfirmationPort';
import { CheckoutConfirmation } from '../../../domain/value-objects/CheckoutConfirmation';
export class ElectronCheckoutConfirmationAdapter implements ICheckoutConfirmationPort {
private mainWindow: BrowserWindow;
private pendingConfirmation: {
resolve: (confirmation: CheckoutConfirmation) => void;
reject: (error: Error) => void;
timeoutId: NodeJS.Timeout;
} | null = null;
constructor(mainWindow: BrowserWindow) {
this.mainWindow = mainWindow;
this.setupIpcHandlers();
}
private setupIpcHandlers(): void {
// Listen for confirmation response from renderer
ipcMain.on('checkout:confirm', (_event, decision: 'confirmed' | 'cancelled' | 'timeout') => {
if (!this.pendingConfirmation) {
return;
}
// Clear timeout
clearTimeout(this.pendingConfirmation.timeoutId);
// Create confirmation based on decision
const confirmation = CheckoutConfirmation.create(decision);
this.pendingConfirmation.resolve(confirmation);
this.pendingConfirmation = null;
});
}
async requestCheckoutConfirmation(
request: CheckoutConfirmationRequest
): Promise<Result<CheckoutConfirmation>> {
try {
// Only allow one pending confirmation at a time
if (this.pendingConfirmation) {
return Result.err(new Error('Confirmation already pending'));
}
// Send request to renderer
this.mainWindow.webContents.send('checkout:request-confirmation', {
price: request.price.toDisplayString(),
state: request.state.isReady() ? 'ready' : 'insufficient_funds',
sessionMetadata: request.sessionMetadata,
timeoutMs: request.timeoutMs,
});
// Wait for response with timeout
const confirmation = await new Promise<CheckoutConfirmation>((resolve, reject) => {
const timeoutId = setTimeout(() => {
this.pendingConfirmation = null;
const timeoutConfirmation = CheckoutConfirmation.create('timeout');
resolve(timeoutConfirmation);
}, request.timeoutMs);
this.pendingConfirmation = {
resolve,
reject,
timeoutId,
};
});
return Result.ok(confirmation);
} catch (error) {
this.pendingConfirmation = null;
return Result.err(
error instanceof Error ? error : new Error('Failed to request confirmation')
);
}
}
public cleanup(): void {
if (this.pendingConfirmation) {
clearTimeout(this.pendingConfirmation.timeoutId);
this.pendingConfirmation = null;
}
ipcMain.removeAllListeners('checkout:confirm');
}
}