@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.
- package/LICENSE +21 -0
- package/dist/billclaw.d.ts +8 -0
- package/dist/billclaw.d.ts.map +1 -1
- package/dist/billclaw.js +51 -1
- package/dist/billclaw.js.map +1 -1
- package/dist/config/config-manager.d.ts +127 -0
- package/dist/config/config-manager.d.ts.map +1 -0
- package/dist/config/config-manager.js +304 -0
- package/dist/config/config-manager.js.map +1 -0
- package/dist/config/env-loader.d.ts +33 -0
- package/dist/config/env-loader.d.ts.map +1 -0
- package/dist/config/env-loader.js +115 -0
- package/dist/config/env-loader.js.map +1 -0
- package/dist/config/index.d.ts +14 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +14 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/models/config.d.ts +147 -0
- package/dist/models/config.d.ts.map +1 -1
- package/dist/models/config.js +36 -0
- package/dist/models/config.js.map +1 -1
- package/dist/oauth/index.d.ts +12 -0
- package/dist/oauth/index.d.ts.map +1 -0
- package/dist/oauth/index.js +13 -0
- package/dist/oauth/index.js.map +1 -0
- package/dist/oauth/providers/gmail.d.ts +63 -0
- package/dist/oauth/providers/gmail.d.ts.map +1 -0
- package/dist/oauth/providers/gmail.js +213 -0
- package/dist/oauth/providers/gmail.js.map +1 -0
- package/dist/oauth/providers/plaid.d.ts +40 -0
- package/dist/oauth/providers/plaid.d.ts.map +1 -0
- package/dist/oauth/providers/plaid.js +90 -0
- package/dist/oauth/providers/plaid.js.map +1 -0
- package/dist/oauth/types.d.ts +102 -0
- package/dist/oauth/types.d.ts.map +1 -0
- package/dist/oauth/types.js +10 -0
- package/dist/oauth/types.js.map +1 -0
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js.map +1 -1
- package/dist/storage/locking.d.ts +4 -0
- package/dist/storage/locking.d.ts.map +1 -1
- package/dist/storage/locking.js +4 -0
- package/dist/storage/locking.js.map +1 -1
- package/dist/test-fixtures.d.ts.map +1 -1
- package/dist/test-fixtures.js +5 -0
- package/dist/test-fixtures.js.map +1 -1
- package/dist/webhooks/deduplication.d.ts +117 -0
- package/dist/webhooks/deduplication.d.ts.map +1 -0
- package/dist/webhooks/deduplication.js +258 -0
- package/dist/webhooks/deduplication.js.map +1 -0
- package/dist/webhooks/handlers/gmail.d.ts +39 -0
- package/dist/webhooks/handlers/gmail.d.ts.map +1 -0
- package/dist/webhooks/handlers/gmail.js +56 -0
- package/dist/webhooks/handlers/gmail.js.map +1 -0
- package/dist/webhooks/handlers/gocardless.d.ts +39 -0
- package/dist/webhooks/handlers/gocardless.d.ts.map +1 -0
- package/dist/webhooks/handlers/gocardless.js +73 -0
- package/dist/webhooks/handlers/gocardless.js.map +1 -0
- package/dist/webhooks/handlers/index.d.ts +10 -0
- package/dist/webhooks/handlers/index.d.ts.map +1 -0
- package/dist/webhooks/handlers/index.js +10 -0
- package/dist/webhooks/handlers/index.js.map +1 -0
- package/dist/webhooks/handlers/plaid.d.ts +73 -0
- package/dist/webhooks/handlers/plaid.d.ts.map +1 -0
- package/dist/webhooks/handlers/plaid.js +169 -0
- package/dist/webhooks/handlers/plaid.js.map +1 -0
- package/dist/webhooks/index.d.ts +15 -0
- package/dist/webhooks/index.d.ts.map +1 -0
- package/dist/webhooks/index.js +17 -0
- package/dist/webhooks/index.js.map +1 -0
- package/dist/webhooks/processor.d.ts +76 -0
- package/dist/webhooks/processor.d.ts.map +1 -0
- package/dist/webhooks/processor.js +116 -0
- package/dist/webhooks/processor.js.map +1 -0
- package/dist/webhooks/router.d.ts +80 -0
- package/dist/webhooks/router.d.ts.map +1 -0
- package/dist/webhooks/router.js +107 -0
- package/dist/webhooks/router.js.map +1 -0
- package/dist/webhooks/security.d.ts +90 -0
- package/dist/webhooks/security.d.ts.map +1 -0
- package/dist/webhooks/security.js +138 -0
- package/dist/webhooks/security.js.map +1 -0
- package/dist/webhooks/sync-rate-limiter.d.ts +138 -0
- package/dist/webhooks/sync-rate-limiter.d.ts.map +1 -0
- package/dist/webhooks/sync-rate-limiter.js +228 -0
- package/dist/webhooks/sync-rate-limiter.js.map +1 -0
- package/dist/webhooks/types.d.ts +140 -0
- package/dist/webhooks/types.d.ts.map +1 -0
- package/dist/webhooks/types.js +18 -0
- package/dist/webhooks/types.js.map +1 -0
- package/package.json +12 -12
package/dist/test-fixtures.js
CHANGED
|
@@ -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":"AAAA;;GAEG;AAmBH,MAAM,CAAC,MAAM,qBAAqB,GAA2B;IAC3D;QACE,cAAc,EAAE,eAAe;QAC/B,UAAU,EAAE,gBAAgB;QAC5B,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,KAAK;QACb,iBAAiB,EAAE,KAAK;QACxB,QAAQ,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC;QACjC,aAAa,EAAE,iBAAiB;QAChC,eAAe,EAAE,QAAQ;QACzB,OAAO,EAAE,KAAK;KACf;IACD;QACE,cAAc,EAAE,eAAe;QAC/B,UAAU,EAAE,gBAAgB;QAC5B,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,KAAK;QACb,iBAAiB,EAAE,KAAK;QACxB,QAAQ,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC;QACrC,aAAa,EAAE,YAAY;QAC3B,eAAe,EAAE,UAAU;QAC3B,OAAO,EAAE,IAAI;KACd;CACF,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAoB;IAC3C;QACE,EAAE,EAAE,mBAAmB;QACvB,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,IAAI;QACb,aAAa,EAAE,OAAO;QACtB,QAAQ,EAAE,sBAAsB;QAChC,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,kBAAkB;QAC/B,gBAAgB,EAAE,qBAAqB;KACxC;IACD;QACE,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,IAAI;QACb,aAAa,EAAE,QAAQ;QACvB,QAAQ,EAAE,sBAAsB;QAChC,UAAU,EAAE,SAAS;QACrB,iBAAiB,EAAE,kBAAkB;QACrC,YAAY,EAAE,CAAC,gBAAgB,CAAC;KACjC;IACD;QACE,EAAE,EAAE,wBAAwB;QAC5B,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,KAAK;QACd,aAAa,EAAE,QAAQ;KACxB;CACF,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAmB;IACxC,QAAQ,EAAE,YAAY;IACtB,QAAQ,EAAE;QACR;YACE,OAAO,EAAE,IAAI;YACb,GAAG,EAAE,6BAA6B;YAClC,MAAM,EAAE,oBAAoB;YAC5B,MAAM,EAAE,CAAC,iBAAiB,EAAE,aAAa,CAAC;YAC1C,WAAW,EAAE;gBACX,UAAU,EAAE,CAAC;gBACb,YAAY,EAAE,IAAI;gBAClB,QAAQ,EAAE,KAAK;aAChB;SACF;KACF;IACD,OAAO,EAAE;QACP,IAAI,EAAE,aAAa;QACnB,MAAM,EAAE,MAAM;QACd,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;KAC/B;IACD,IAAI,EAAE;QACJ,gBAAgB,EAAE,OAAO;QACzB,UAAU,EAAE,CAAC;QACb,cAAc,EAAE,IAAI;KACrB;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,gBAAgB;QAC1B,MAAM,EAAE,aAAa;QACrB,WAAW,EAAE,SAAS;KACvB;IACD,KAAK,EAAE;QACL,eAAe,EAAE,CAAC,WAAW,CAAC;QAC9B,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,CAAC;QAC7C,mBAAmB,EAAE,GAAG;QACxB,aAAa,EAAE,KAAK;QACpB,WAAW,EAAE,KAAK;KACnB;CACF,CAAA;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B;QACE,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,qBAAqB;QAC3B,OAAO,EAAE,0BAA0B;QACnC,IAAI,EAAE;;;;;;;;;KASL;QACD,IAAI,EAAE,sBAAsB;KAC7B;IACD;QACE,EAAE,EAAE,eAAe;QACnB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,2BAA2B;QACpC,IAAI,EAAE;;;;;;KAML;QACD,IAAI,EAAE,sBAAsB;KAC7B;CACF,CAAA"}
|
|
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
|