Files
bunq/ts/bunq.classes.webhook.ts

198 lines
5.5 KiB
TypeScript

import * as plugins from './bunq.plugins.js';
import { BunqAccount } from './bunq.classes.account.js';
import { BunqMonetaryAccount } from './bunq.classes.monetaryaccount.js';
import { BunqNotification, BunqWebhookHandler } from './bunq.classes.notification.js';
import { BunqCrypto } from './bunq.classes.crypto.js';
/**
* Webhook management for monetary accounts
*/
export class BunqWebhook {
private bunqAccount: BunqAccount;
constructor(bunqAccount: BunqAccount) {
this.bunqAccount = bunqAccount;
}
/**
* Create a webhook for a monetary account
*/
public async create(monetaryAccount: BunqMonetaryAccount, url: string): Promise<number> {
await this.bunqAccount.apiContext.ensureValidSession();
const response = await this.bunqAccount.getHttpClient().post(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url`,
{
category: 'MUTATION',
notification_target: url
}
);
if (response.Response && response.Response[0] && response.Response[0].Id) {
return response.Response[0].Id.id;
}
throw new Error('Failed to create webhook');
}
/**
* List all webhooks for a monetary account
*/
public async list(monetaryAccount: BunqMonetaryAccount): Promise<Array<{
id: number;
url: string;
category: string;
}>> {
await this.bunqAccount.apiContext.ensureValidSession();
const response = await this.bunqAccount.getHttpClient().list(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url`
);
const webhooks: Array<{
id: number;
url: string;
category: string;
}> = [];
if (response.Response) {
for (const item of response.Response) {
if (item.NotificationFilterUrl) {
webhooks.push({
id: item.NotificationFilterUrl.id,
url: item.NotificationFilterUrl.notification_target,
category: item.NotificationFilterUrl.category
});
}
}
}
return webhooks;
}
/**
* Get a specific webhook
*/
public async get(monetaryAccount: BunqMonetaryAccount, webhookId: number): Promise<{
id: number;
url: string;
category: string;
}> {
await this.bunqAccount.apiContext.ensureValidSession();
const response = await this.bunqAccount.getHttpClient().get(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url/${webhookId}`
);
if (response.Response && response.Response[0] && response.Response[0].NotificationFilterUrl) {
const webhook = response.Response[0].NotificationFilterUrl;
return {
id: webhook.id,
url: webhook.notification_target,
category: webhook.category
};
}
throw new Error('Webhook not found');
}
/**
* Update a webhook URL
*/
public async update(monetaryAccount: BunqMonetaryAccount, webhookId: number, newUrl: string): Promise<void> {
await this.bunqAccount.apiContext.ensureValidSession();
await this.bunqAccount.getHttpClient().put(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url/${webhookId}`,
{
notification_target: newUrl
}
);
}
/**
* Delete a webhook
*/
public async delete(monetaryAccount: BunqMonetaryAccount, webhookId: number): Promise<void> {
await this.bunqAccount.apiContext.ensureValidSession();
await this.bunqAccount.getHttpClient().delete(
`/v1/user/${this.bunqAccount.userId}/monetary-account/${monetaryAccount.id}/notification-filter-url/${webhookId}`
);
}
}
/**
* Webhook server for receiving bunq notifications
*/
export class BunqWebhookServer {
private bunqAccount: BunqAccount;
private notification: BunqNotification;
private handler: BunqWebhookHandler;
private server?: any; // HTTP server instance
private port: number;
private path: string;
private publicUrl: string;
constructor(
bunqAccount: BunqAccount,
options: {
port?: number;
path?: string;
publicUrl: string;
}
) {
this.bunqAccount = bunqAccount;
this.notification = new BunqNotification(bunqAccount);
this.handler = new BunqWebhookHandler();
this.port = options.port || 3000;
this.path = options.path || '/webhook';
this.publicUrl = options.publicUrl;
}
/**
* Get the webhook handler for registering event callbacks
*/
public getHandler(): BunqWebhookHandler {
return this.handler;
}
/**
* Start the webhook server
*/
public async start(): Promise<void> {
// Implementation would use an HTTP server library
// For now, this is a placeholder
console.log(`Webhook server would start on port ${this.port}`);
}
/**
* Stop the webhook server
*/
public async stop(): Promise<void> {
if (this.server) {
// Stop the server
console.log('Webhook server stopped');
}
}
/**
* Register the webhook URL with bunq
*/
public async register(): Promise<void> {
const webhookUrl = `${this.publicUrl}${this.path}`;
// Register for all payment-related events
await this.notification.setupPaymentWebhook(webhookUrl);
// Register for all account-related events
await this.notification.setupAccountWebhook(webhookUrl);
}
/**
* Verify webhook signature
*/
public verifySignature(body: string, signature: string): boolean {
const crypto = new BunqCrypto();
// In production, use bunq's server public key
return true; // Placeholder
}
}