@firela/billclaw-core 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/LICENSE +21 -0
  2. package/dist/billclaw.d.ts +8 -0
  3. package/dist/billclaw.d.ts.map +1 -1
  4. package/dist/billclaw.js +51 -1
  5. package/dist/billclaw.js.map +1 -1
  6. package/dist/config/config-manager.d.ts +127 -0
  7. package/dist/config/config-manager.d.ts.map +1 -0
  8. package/dist/config/config-manager.js +304 -0
  9. package/dist/config/config-manager.js.map +1 -0
  10. package/dist/config/env-loader.d.ts +33 -0
  11. package/dist/config/env-loader.d.ts.map +1 -0
  12. package/dist/config/env-loader.js +115 -0
  13. package/dist/config/env-loader.js.map +1 -0
  14. package/dist/config/index.d.ts +14 -0
  15. package/dist/config/index.d.ts.map +1 -0
  16. package/dist/config/index.js +14 -0
  17. package/dist/config/index.js.map +1 -0
  18. package/dist/index.d.ts +4 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +7 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/models/config.d.ts +147 -0
  23. package/dist/models/config.d.ts.map +1 -1
  24. package/dist/models/config.js +36 -0
  25. package/dist/models/config.js.map +1 -1
  26. package/dist/oauth/index.d.ts +12 -0
  27. package/dist/oauth/index.d.ts.map +1 -0
  28. package/dist/oauth/index.js +13 -0
  29. package/dist/oauth/index.js.map +1 -0
  30. package/dist/oauth/providers/gmail.d.ts +63 -0
  31. package/dist/oauth/providers/gmail.d.ts.map +1 -0
  32. package/dist/oauth/providers/gmail.js +213 -0
  33. package/dist/oauth/providers/gmail.js.map +1 -0
  34. package/dist/oauth/providers/plaid.d.ts +40 -0
  35. package/dist/oauth/providers/plaid.d.ts.map +1 -0
  36. package/dist/oauth/providers/plaid.js +90 -0
  37. package/dist/oauth/providers/plaid.js.map +1 -0
  38. package/dist/oauth/types.d.ts +102 -0
  39. package/dist/oauth/types.d.ts.map +1 -0
  40. package/dist/oauth/types.js +10 -0
  41. package/dist/oauth/types.js.map +1 -0
  42. package/dist/runtime/types.d.ts +2 -0
  43. package/dist/runtime/types.d.ts.map +1 -1
  44. package/dist/runtime/types.js.map +1 -1
  45. package/dist/storage/locking.d.ts +4 -0
  46. package/dist/storage/locking.d.ts.map +1 -1
  47. package/dist/storage/locking.js +4 -0
  48. package/dist/storage/locking.js.map +1 -1
  49. package/dist/test-fixtures.d.ts.map +1 -1
  50. package/dist/test-fixtures.js +5 -0
  51. package/dist/test-fixtures.js.map +1 -1
  52. package/dist/webhooks/deduplication.d.ts +117 -0
  53. package/dist/webhooks/deduplication.d.ts.map +1 -0
  54. package/dist/webhooks/deduplication.js +258 -0
  55. package/dist/webhooks/deduplication.js.map +1 -0
  56. package/dist/webhooks/handlers/gmail.d.ts +39 -0
  57. package/dist/webhooks/handlers/gmail.d.ts.map +1 -0
  58. package/dist/webhooks/handlers/gmail.js +56 -0
  59. package/dist/webhooks/handlers/gmail.js.map +1 -0
  60. package/dist/webhooks/handlers/gocardless.d.ts +39 -0
  61. package/dist/webhooks/handlers/gocardless.d.ts.map +1 -0
  62. package/dist/webhooks/handlers/gocardless.js +73 -0
  63. package/dist/webhooks/handlers/gocardless.js.map +1 -0
  64. package/dist/webhooks/handlers/index.d.ts +10 -0
  65. package/dist/webhooks/handlers/index.d.ts.map +1 -0
  66. package/dist/webhooks/handlers/index.js +10 -0
  67. package/dist/webhooks/handlers/index.js.map +1 -0
  68. package/dist/webhooks/handlers/plaid.d.ts +73 -0
  69. package/dist/webhooks/handlers/plaid.d.ts.map +1 -0
  70. package/dist/webhooks/handlers/plaid.js +169 -0
  71. package/dist/webhooks/handlers/plaid.js.map +1 -0
  72. package/dist/webhooks/index.d.ts +15 -0
  73. package/dist/webhooks/index.d.ts.map +1 -0
  74. package/dist/webhooks/index.js +17 -0
  75. package/dist/webhooks/index.js.map +1 -0
  76. package/dist/webhooks/processor.d.ts +76 -0
  77. package/dist/webhooks/processor.d.ts.map +1 -0
  78. package/dist/webhooks/processor.js +116 -0
  79. package/dist/webhooks/processor.js.map +1 -0
  80. package/dist/webhooks/router.d.ts +80 -0
  81. package/dist/webhooks/router.d.ts.map +1 -0
  82. package/dist/webhooks/router.js +107 -0
  83. package/dist/webhooks/router.js.map +1 -0
  84. package/dist/webhooks/security.d.ts +90 -0
  85. package/dist/webhooks/security.d.ts.map +1 -0
  86. package/dist/webhooks/security.js +138 -0
  87. package/dist/webhooks/security.js.map +1 -0
  88. package/dist/webhooks/sync-rate-limiter.d.ts +138 -0
  89. package/dist/webhooks/sync-rate-limiter.d.ts.map +1 -0
  90. package/dist/webhooks/sync-rate-limiter.js +228 -0
  91. package/dist/webhooks/sync-rate-limiter.js.map +1 -0
  92. package/dist/webhooks/types.d.ts +140 -0
  93. package/dist/webhooks/types.d.ts.map +1 -0
  94. package/dist/webhooks/types.js +18 -0
  95. package/dist/webhooks/types.js.map +1 -0
  96. package/package.json +12 -12
@@ -63,6 +63,7 @@ export const mockAccounts = [
63
63
  * Sample complete configuration
64
64
  */
65
65
  export const mockConfig = {
66
+ version: 1,
66
67
  accounts: mockAccounts,
67
68
  webhooks: [
68
69
  {
@@ -99,6 +100,10 @@ export const mockConfig = {
99
100
  requireAmount: false,
100
101
  requireDate: false,
101
102
  },
103
+ connect: {
104
+ port: 4456,
105
+ host: "localhost",
106
+ },
102
107
  };
103
108
  /**
104
109
  * Sample Gmail email content
@@ -1 +1 @@
1
- {"version":3,"file":"test-fixtures.js","sourceRoot":"","sources":["../src/test-fixtures.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-fixtures.js","sourceRoot":"","sources":["../src/test-fixtures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Webhook deduplication cache (P0)
3
+ *
4
+ * File-based deduplication cache for webhook nonce tracking.
5
+ * Uses proper-lockfile for concurrent access safety.
6
+ *
7
+ * Design decisions:
8
+ * - File-based (NOT in-memory) for multi-process safety
9
+ * - TTL-based cleanup to prevent unbounded growth
10
+ * - Uses existing locking infrastructure
11
+ */
12
+ import type { Logger } from "../errors/errors.js";
13
+ /**
14
+ * Configuration for webhook deduplication
15
+ */
16
+ export interface WebhookDeduplicationConfig {
17
+ /**
18
+ * Base directory for cache storage
19
+ */
20
+ basePath: string;
21
+ /**
22
+ * Cache file name
23
+ */
24
+ cacheFile?: string;
25
+ /**
26
+ * Logger instance
27
+ */
28
+ logger: Logger;
29
+ }
30
+ /**
31
+ * Webhook deduplication cache
32
+ *
33
+ * Tracks processed webhook nonces to prevent duplicate processing.
34
+ * Uses file-based storage with locking for multi-process safety.
35
+ */
36
+ export declare class WebhookDeduplication {
37
+ private readonly cachePath;
38
+ private readonly lockPath;
39
+ private readonly logger;
40
+ private cache;
41
+ constructor(config: WebhookDeduplicationConfig);
42
+ /**
43
+ * Initialize the deduplication cache
44
+ *
45
+ * Loads existing cache or creates new one.
46
+ */
47
+ initialize(): Promise<void>;
48
+ /**
49
+ * Check if webhook has been processed
50
+ *
51
+ * @param nonce - Webhook nonce
52
+ * @returns True if already processed
53
+ */
54
+ isProcessed(nonce: string): Promise<boolean>;
55
+ /**
56
+ * Mark webhook as processed
57
+ *
58
+ * @param nonce - Webhook nonce
59
+ * @param ttl - Time-to-live in milliseconds
60
+ */
61
+ markProcessed(nonce: string, ttl: number): Promise<void>;
62
+ /**
63
+ * Remove a nonce from the cache
64
+ *
65
+ * @param nonce - Nonce to remove
66
+ */
67
+ removeNonce(nonce: string): Promise<void>;
68
+ /**
69
+ * Clean up expired entries
70
+ */
71
+ cleanup(): Promise<void>;
72
+ /**
73
+ * Ensure cache directory exists
74
+ */
75
+ private ensureCacheDirectory;
76
+ /**
77
+ * Load cache from disk
78
+ */
79
+ private loadCache;
80
+ /**
81
+ * Save cache to disk
82
+ */
83
+ private saveCache;
84
+ /**
85
+ * Load cache if not already loaded
86
+ */
87
+ private loadCacheIfNeeded;
88
+ /**
89
+ * Run cleanup if needed
90
+ */
91
+ private maybeCleanup;
92
+ /**
93
+ * Get cache statistics
94
+ */
95
+ getStats(): Promise<{
96
+ totalNonces: number;
97
+ lastCleanup: number;
98
+ }>;
99
+ }
100
+ /**
101
+ * Create a webhook deduplication instance
102
+ */
103
+ export declare function createWebhookDeduplication(config: WebhookDeduplicationConfig): Promise<WebhookDeduplication>;
104
+ /**
105
+ * In-memory deduplication cache for testing
106
+ *
107
+ * WARNING: Do not use in production - not multi-process safe.
108
+ */
109
+ export declare class InMemoryWebhookDeduplication {
110
+ private readonly nonces;
111
+ private readonly logger;
112
+ constructor(logger: Logger);
113
+ isProcessed(nonce: string): Promise<boolean>;
114
+ markProcessed(nonce: string, ttl: number): Promise<void>;
115
+ cleanup(): Promise<void>;
116
+ }
117
+ //# sourceMappingURL=deduplication.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplication.d.ts","sourceRoot":"","sources":["../../src/webhooks/deduplication.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAqBjD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAA;IAEhB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,KAAK,CAAkC;gBAEnC,MAAM,EAAE,0BAA0B;IAU9C;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBlD;;;;;OAKG;IACG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgB9D;;;;OAIG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAW/C;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B9B;;OAEG;YACW,oBAAoB;IAUlC;;OAEG;YACW,SAAS;IAiBvB;;OAEG;YACW,SAAS;IAcvB;;OAEG;YACW,iBAAiB;IAM/B;;OAEG;YACW,YAAY;IAW1B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;CAYxE;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAI/B;AAED;;;;GAIG;AACH,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA4B;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,MAAM,EAAE,MAAM;IAIpB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAc5C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAe/B"}
@@ -0,0 +1,258 @@
1
+ /**
2
+ * Webhook deduplication cache (P0)
3
+ *
4
+ * File-based deduplication cache for webhook nonce tracking.
5
+ * Uses proper-lockfile for concurrent access safety.
6
+ *
7
+ * Design decisions:
8
+ * - File-based (NOT in-memory) for multi-process safety
9
+ * - TTL-based cleanup to prevent unbounded growth
10
+ * - Uses existing locking infrastructure
11
+ */
12
+ import * as fs from "node:fs/promises";
13
+ import * as path from "node:path";
14
+ import { withLock } from "../storage/locking.js";
15
+ /**
16
+ * Default cache file name
17
+ */
18
+ const CACHE_FILE = "webhook-nonces.json";
19
+ /**
20
+ * Cleanup interval in milliseconds (5 minutes)
21
+ */
22
+ const CLEANUP_INTERVAL = 5 * 60 * 1000;
23
+ /**
24
+ * Webhook deduplication cache
25
+ *
26
+ * Tracks processed webhook nonces to prevent duplicate processing.
27
+ * Uses file-based storage with locking for multi-process safety.
28
+ */
29
+ export class WebhookDeduplication {
30
+ cachePath;
31
+ lockPath;
32
+ logger;
33
+ cache = null;
34
+ constructor(config) {
35
+ this.cachePath = path.join(config.basePath, "cache", config.cacheFile || CACHE_FILE);
36
+ this.lockPath = `${this.cachePath}.lock`;
37
+ this.logger = config.logger;
38
+ }
39
+ /**
40
+ * Initialize the deduplication cache
41
+ *
42
+ * Loads existing cache or creates new one.
43
+ */
44
+ async initialize() {
45
+ await this.ensureCacheDirectory();
46
+ await this.loadCache();
47
+ await this.maybeCleanup();
48
+ }
49
+ /**
50
+ * Check if webhook has been processed
51
+ *
52
+ * @param nonce - Webhook nonce
53
+ * @returns True if already processed
54
+ */
55
+ async isProcessed(nonce) {
56
+ await this.loadCacheIfNeeded();
57
+ if (!this.cache) {
58
+ return false;
59
+ }
60
+ const entry = this.cache.nonces[nonce];
61
+ if (!entry) {
62
+ return false;
63
+ }
64
+ // Check if nonce has expired
65
+ if (Date.now() > entry.expiresAt) {
66
+ await this.removeNonce(nonce);
67
+ return false;
68
+ }
69
+ return true;
70
+ }
71
+ /**
72
+ * Mark webhook as processed
73
+ *
74
+ * @param nonce - Webhook nonce
75
+ * @param ttl - Time-to-live in milliseconds
76
+ */
77
+ async markProcessed(nonce, ttl) {
78
+ await withLock(this.lockPath, async () => {
79
+ await this.loadCacheIfNeeded();
80
+ if (!this.cache) {
81
+ this.cache = { nonces: {}, lastCleanup: Date.now() };
82
+ }
83
+ this.cache.nonces[nonce] = {
84
+ expiresAt: Date.now() + ttl,
85
+ };
86
+ await this.saveCache();
87
+ }, { logger: this.logger });
88
+ }
89
+ /**
90
+ * Remove a nonce from the cache
91
+ *
92
+ * @param nonce - Nonce to remove
93
+ */
94
+ async removeNonce(nonce) {
95
+ await withLock(this.lockPath, async () => {
96
+ await this.loadCacheIfNeeded();
97
+ if (this.cache && this.cache.nonces[nonce]) {
98
+ delete this.cache.nonces[nonce];
99
+ await this.saveCache();
100
+ }
101
+ }, { logger: this.logger });
102
+ }
103
+ /**
104
+ * Clean up expired entries
105
+ */
106
+ async cleanup() {
107
+ await withLock(this.lockPath, async () => {
108
+ await this.loadCacheIfNeeded();
109
+ if (!this.cache) {
110
+ return;
111
+ }
112
+ const now = Date.now();
113
+ let removedCount = 0;
114
+ for (const nonce in this.cache.nonces) {
115
+ if (now > this.cache.nonces[nonce].expiresAt) {
116
+ delete this.cache.nonces[nonce];
117
+ removedCount++;
118
+ }
119
+ }
120
+ if (removedCount > 0) {
121
+ this.logger.debug?.(`Cleaned up ${removedCount} expired nonces`);
122
+ }
123
+ this.cache.lastCleanup = now;
124
+ await this.saveCache();
125
+ }, { logger: this.logger });
126
+ }
127
+ /**
128
+ * Ensure cache directory exists
129
+ */
130
+ async ensureCacheDirectory() {
131
+ const cacheDir = path.dirname(this.cachePath);
132
+ try {
133
+ await fs.mkdir(cacheDir, { recursive: true });
134
+ }
135
+ catch (error) {
136
+ this.logger.error?.(`Failed to create cache directory: ${cacheDir}`, error);
137
+ throw error;
138
+ }
139
+ }
140
+ /**
141
+ * Load cache from disk
142
+ */
143
+ async loadCache() {
144
+ try {
145
+ const data = await fs.readFile(this.cachePath, "utf-8");
146
+ this.cache = JSON.parse(data);
147
+ this.logger.debug?.(`Loaded deduplication cache from ${this.cachePath}`);
148
+ }
149
+ catch (error) {
150
+ if (error.code === "ENOENT") {
151
+ // Cache file doesn't exist, create new cache
152
+ this.cache = { nonces: {}, lastCleanup: Date.now() };
153
+ await this.saveCache();
154
+ }
155
+ else {
156
+ this.logger.error?.(`Failed to load cache from ${this.cachePath}`, error);
157
+ this.cache = { nonces: {}, lastCleanup: Date.now() };
158
+ }
159
+ }
160
+ }
161
+ /**
162
+ * Save cache to disk
163
+ */
164
+ async saveCache() {
165
+ if (!this.cache) {
166
+ return;
167
+ }
168
+ try {
169
+ const data = JSON.stringify(this.cache, null, 2);
170
+ await fs.writeFile(this.cachePath, data, "utf-8");
171
+ }
172
+ catch (error) {
173
+ this.logger.error?.(`Failed to save cache to ${this.cachePath}`, error);
174
+ throw error;
175
+ }
176
+ }
177
+ /**
178
+ * Load cache if not already loaded
179
+ */
180
+ async loadCacheIfNeeded() {
181
+ if (!this.cache) {
182
+ await this.loadCache();
183
+ }
184
+ }
185
+ /**
186
+ * Run cleanup if needed
187
+ */
188
+ async maybeCleanup() {
189
+ if (!this.cache) {
190
+ return;
191
+ }
192
+ const now = Date.now();
193
+ if (now - this.cache.lastCleanup > CLEANUP_INTERVAL) {
194
+ await this.cleanup();
195
+ }
196
+ }
197
+ /**
198
+ * Get cache statistics
199
+ */
200
+ async getStats() {
201
+ await this.loadCacheIfNeeded();
202
+ if (!this.cache) {
203
+ return { totalNonces: 0, lastCleanup: 0 };
204
+ }
205
+ return {
206
+ totalNonces: Object.keys(this.cache.nonces).length,
207
+ lastCleanup: this.cache.lastCleanup,
208
+ };
209
+ }
210
+ }
211
+ /**
212
+ * Create a webhook deduplication instance
213
+ */
214
+ export async function createWebhookDeduplication(config) {
215
+ const dedup = new WebhookDeduplication(config);
216
+ await dedup.initialize();
217
+ return dedup;
218
+ }
219
+ /**
220
+ * In-memory deduplication cache for testing
221
+ *
222
+ * WARNING: Do not use in production - not multi-process safe.
223
+ */
224
+ export class InMemoryWebhookDeduplication {
225
+ nonces = new Map();
226
+ logger;
227
+ constructor(logger) {
228
+ this.logger = logger;
229
+ }
230
+ async isProcessed(nonce) {
231
+ const expiresAt = this.nonces.get(nonce);
232
+ if (!expiresAt) {
233
+ return false;
234
+ }
235
+ if (Date.now() > expiresAt) {
236
+ this.nonces.delete(nonce);
237
+ return false;
238
+ }
239
+ return true;
240
+ }
241
+ async markProcessed(nonce, ttl) {
242
+ this.nonces.set(nonce, Date.now() + ttl);
243
+ }
244
+ async cleanup() {
245
+ const now = Date.now();
246
+ let removedCount = 0;
247
+ for (const [nonce, expiresAt] of this.nonces.entries()) {
248
+ if (now > expiresAt) {
249
+ this.nonces.delete(nonce);
250
+ removedCount++;
251
+ }
252
+ }
253
+ if (removedCount > 0) {
254
+ this.logger.debug?.(`Cleaned up ${removedCount} expired nonces`);
255
+ }
256
+ }
257
+ }
258
+ //# sourceMappingURL=deduplication.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deduplication.js","sourceRoot":"","sources":["../../src/webhooks/deduplication.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Gmail webhook handler (stub)
3
+ *
4
+ * Processes webhooks from Gmail via Cloud Pub/Sub.
5
+ *
6
+ * NOTE: This is a placeholder implementation for future use.
7
+ * Gmail uses Cloud Pub/Sub for push notifications, which requires
8
+ * additional infrastructure not yet implemented.
9
+ */
10
+ import type { WebhookHandler, WebhookRequest, WebhookResponse } from "../types.js";
11
+ import type { Logger } from "../../errors/errors.js";
12
+ /**
13
+ * Gmail webhook handler configuration
14
+ */
15
+ export interface GmailWebhookHandlerConfig {
16
+ /**
17
+ * Logger instance
18
+ */
19
+ logger: Logger;
20
+ }
21
+ /**
22
+ * Gmail webhook handler (stub)
23
+ *
24
+ * Handles inbound webhooks from Gmail via Cloud Pub/Sub.
25
+ * This is a placeholder implementation for future use.
26
+ */
27
+ export declare class GmailWebhookHandler implements WebhookHandler {
28
+ readonly source: "gmail";
29
+ private readonly logger;
30
+ constructor(config: GmailWebhookHandlerConfig);
31
+ handle(_request: WebhookRequest): Promise<WebhookResponse>;
32
+ verify(): boolean;
33
+ getSupportedEvents(): string[];
34
+ }
35
+ /**
36
+ * Create a Gmail webhook handler
37
+ */
38
+ export declare function createGmailWebhookHandler(config: GmailWebhookHandlerConfig): GmailWebhookHandler;
39
+ //# sourceMappingURL=gmail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail.d.ts","sourceRoot":"","sources":["../../../src/webhooks/handlers/gmail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EAChB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAEpD;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,qBAAa,mBAAoB,YAAW,cAAc;IACxD,QAAQ,CAAC,MAAM,EAAG,OAAO,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,MAAM,EAAE,yBAAyB;IAIvC,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAuBhE,MAAM,IAAI,OAAO;IAKjB,kBAAkB,IAAI,MAAM,EAAE;CAG/B;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,yBAAyB,GAChC,mBAAmB,CAErB"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Gmail webhook handler (stub)
3
+ *
4
+ * Processes webhooks from Gmail via Cloud Pub/Sub.
5
+ *
6
+ * NOTE: This is a placeholder implementation for future use.
7
+ * Gmail uses Cloud Pub/Sub for push notifications, which requires
8
+ * additional infrastructure not yet implemented.
9
+ */
10
+ /**
11
+ * Gmail webhook handler (stub)
12
+ *
13
+ * Handles inbound webhooks from Gmail via Cloud Pub/Sub.
14
+ * This is a placeholder implementation for future use.
15
+ */
16
+ export class GmailWebhookHandler {
17
+ source = "gmail";
18
+ logger;
19
+ constructor(config) {
20
+ this.logger = config.logger;
21
+ }
22
+ async handle(_request) {
23
+ try {
24
+ this.logger.info?.(`Received Gmail webhook`);
25
+ // Stub implementation
26
+ // Gmail uses Cloud Pub/Sub for notifications
27
+ // This would require Pub/Sub subscription handling
28
+ this.logger.debug?.(`Gmail webhook handler is not yet implemented`);
29
+ return { status: 200, body: { received: true } };
30
+ }
31
+ catch (error) {
32
+ this.logger.error?.(`Error handling Gmail webhook:`, error);
33
+ return {
34
+ status: 500,
35
+ body: {
36
+ received: false,
37
+ error: error instanceof Error ? error.message : "Internal server error",
38
+ },
39
+ };
40
+ }
41
+ }
42
+ verify() {
43
+ // Gmail uses Pub/Sub authentication
44
+ return true;
45
+ }
46
+ getSupportedEvents() {
47
+ return [];
48
+ }
49
+ }
50
+ /**
51
+ * Create a Gmail webhook handler
52
+ */
53
+ export function createGmailWebhookHandler(config) {
54
+ return new GmailWebhookHandler(config);
55
+ }
56
+ //# sourceMappingURL=gmail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gmail.js","sourceRoot":"","sources":["../../../src/webhooks/handlers/gmail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmBH;;;;;GAKG;AACH,MAAM,OAAO,mBAAmB;IACrB,MAAM,GAAG,OAAgB,CAAA;IACjB,MAAM,CAAQ;IAE/B,YAAY,MAAiC;QAC3C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,QAAwB;QACnC,IAAI,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,wBAAwB,CAAC,CAAA;YAE5C,sBAAsB;YACtB,6CAA6C;YAC7C,mDAAmD;YAEnD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,8CAA8C,CAAC,CAAA;YAEnE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAA;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,+BAA+B,EAAE,KAAK,CAAC,CAAA;YAC3D,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE;oBACJ,QAAQ,EAAE,KAAK;oBACf,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB;iBACxE;aACF,CAAA;QACH,CAAC;IACH,CAAC;IAED,MAAM;QACJ,oCAAoC;QACpC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,kBAAkB;QAChB,OAAO,EAAE,CAAA;IACX,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAiC;IAEjC,OAAO,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAA;AACxC,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * GoCardless webhook handler
3
+ *
4
+ * Processes webhooks from GoCardless:
5
+ * - mandate events (created, cancelled)
6
+ * - payment events (paid_out)
7
+ *
8
+ * NOTE: This is a stub implementation for future use.
9
+ */
10
+ import type { WebhookHandler, WebhookRequest, WebhookResponse } from "../types.js";
11
+ import type { Logger } from "../../errors/errors.js";
12
+ /**
13
+ * GoCardless webhook handler configuration
14
+ */
15
+ export interface GoCardlessWebhookHandlerConfig {
16
+ /**
17
+ * Logger instance
18
+ */
19
+ logger: Logger;
20
+ }
21
+ /**
22
+ * GoCardless webhook handler (stub)
23
+ *
24
+ * Handles inbound webhooks from GoCardless.
25
+ * This is a placeholder implementation for future use.
26
+ */
27
+ export declare class GoCardlessWebhookHandler implements WebhookHandler {
28
+ readonly source: "gocardless";
29
+ private readonly logger;
30
+ constructor(config: GoCardlessWebhookHandlerConfig);
31
+ handle(request: WebhookRequest): Promise<WebhookResponse>;
32
+ verify(_request: WebhookRequest, _secret: string): boolean;
33
+ getSupportedEvents(): string[];
34
+ }
35
+ /**
36
+ * Create a GoCardless webhook handler
37
+ */
38
+ export declare function createGoCardlessWebhookHandler(config: GoCardlessWebhookHandlerConfig): GoCardlessWebhookHandler;
39
+ //# sourceMappingURL=gocardless.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gocardless.d.ts","sourceRoot":"","sources":["../../../src/webhooks/handlers/gocardless.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EAChB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAA;AAcpD;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;GAKG;AACH,qBAAa,wBAAyB,YAAW,cAAc;IAC7D,QAAQ,CAAC,MAAM,EAAG,YAAY,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;gBAEnB,MAAM,EAAE,8BAA8B;IAI5C,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAmC/D,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAM1D,kBAAkB,IAAI,MAAM,EAAE;CAO/B;AAED;;GAEG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,8BAA8B,GACrC,wBAAwB,CAE1B"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * GoCardless webhook handler
3
+ *
4
+ * Processes webhooks from GoCardless:
5
+ * - mandate events (created, cancelled)
6
+ * - payment events (paid_out)
7
+ *
8
+ * NOTE: This is a stub implementation for future use.
9
+ */
10
+ /**
11
+ * GoCardless webhook handler (stub)
12
+ *
13
+ * Handles inbound webhooks from GoCardless.
14
+ * This is a placeholder implementation for future use.
15
+ */
16
+ export class GoCardlessWebhookHandler {
17
+ source = "gocardless";
18
+ logger;
19
+ constructor(config) {
20
+ this.logger = config.logger;
21
+ }
22
+ async handle(request) {
23
+ try {
24
+ const body = request.body;
25
+ const action = body.action;
26
+ this.logger.info?.(`Received GoCardless webhook: ${action}`);
27
+ // Stub implementation
28
+ switch (action) {
29
+ case "created":
30
+ case "cancelled":
31
+ // Handle mandate events
32
+ this.logger.debug?.(`GoCardless mandate event: ${action}`);
33
+ break;
34
+ case "paid_out":
35
+ // Handle payment events
36
+ this.logger.debug?.(`GoCardless payment event: ${action}`);
37
+ break;
38
+ default:
39
+ this.logger.debug?.(`Unhandled GoCardless webhook: ${action}`);
40
+ }
41
+ return { status: 200, body: { received: true } };
42
+ }
43
+ catch (error) {
44
+ this.logger.error?.(`Error handling GoCardless webhook:`, error);
45
+ return {
46
+ status: 500,
47
+ body: {
48
+ received: false,
49
+ error: error instanceof Error ? error.message : "Internal server error",
50
+ },
51
+ };
52
+ }
53
+ }
54
+ verify(_request, _secret) {
55
+ // GoCardless uses body.signature
56
+ // Signature verification should be done by security layer
57
+ return true;
58
+ }
59
+ getSupportedEvents() {
60
+ return [
61
+ "mandates.created",
62
+ "mandates.cancelled",
63
+ "payments.paid_out",
64
+ ];
65
+ }
66
+ }
67
+ /**
68
+ * Create a GoCardless webhook handler
69
+ */
70
+ export function createGoCardlessWebhookHandler(config) {
71
+ return new GoCardlessWebhookHandler(config);
72
+ }
73
+ //# sourceMappingURL=gocardless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gocardless.js","sourceRoot":"","sources":["../../../src/webhooks/handlers/gocardless.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA+BH;;;;;GAKG;AACH,MAAM,OAAO,wBAAwB;IAC1B,MAAM,GAAG,YAAqB,CAAA;IACtB,MAAM,CAAQ;IAE/B,YAAY,MAAsC;QAChD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAA;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAAuB;QAClC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,OAAO,CAAC,IAA6B,CAAA;YAClD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;YAE1B,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,gCAAgC,MAAM,EAAE,CAAC,CAAA;YAE5D,sBAAsB;YACtB,QAAQ,MAAM,EAAE,CAAC;gBACf,KAAK,SAAS,CAAC;gBACf,KAAK,WAAW;oBACd,wBAAwB;oBACxB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAA;oBAC1D,MAAK;gBACP,KAAK,UAAU;oBACb,wBAAwB;oBACxB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAA;oBAC1D,MAAK;gBACP;oBACE,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,iCAAiC,MAAM,EAAE,CAAC,CAAA;YAClE,CAAC;YAED,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAA;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAA;YAChE,OAAO;gBACL,MAAM,EAAE,GAAG;gBACX,IAAI,EAAE;oBACJ,QAAQ,EAAE,KAAK;oBACf,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB;iBACxE;aACF,CAAA;QACH,CAAC;IACH,CAAC;IAED,MAAM,CAAC,QAAwB,EAAE,OAAe;QAC9C,iCAAiC;QACjC,0DAA0D;QAC1D,OAAO,IAAI,CAAA;IACb,CAAC;IAED,kBAAkB;QAChB,OAAO;YACL,kBAAkB;YAClB,oBAAoB;YACpB,mBAAmB;SACpB,CAAA;IACH,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAsC;IAEtC,OAAO,IAAI,wBAAwB,CAAC,MAAM,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Webhook handlers for different data sources
3
+ *
4
+ * Protocol-specific implementations for processing webhooks from
5
+ * Plaid, GoCardless, Gmail, etc.
6
+ */
7
+ export * from "./plaid.js";
8
+ export * from "./gocardless.js";
9
+ export * from "./gmail.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/webhooks/handlers/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,YAAY,CAAA;AAC1B,cAAc,iBAAiB,CAAA;AAC/B,cAAc,YAAY,CAAA"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Webhook handlers for different data sources
3
+ *
4
+ * Protocol-specific implementations for processing webhooks from
5
+ * Plaid, GoCardless, Gmail, etc.
6
+ */
7
+ export * from "./plaid.js";
8
+ export * from "./gocardless.js";
9
+ export * from "./gmail.js";
10
+ //# sourceMappingURL=index.js.map