chargeback-guard 2.0.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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +311 -0
  3. package/docs/api.md +278 -0
  4. package/docs/architecture.md +281 -0
  5. package/docs/configuration.md +292 -0
  6. package/docs/getting-started.md +155 -0
  7. package/examples/advancedConfig.ts +123 -0
  8. package/examples/basicUsage.ts +98 -0
  9. package/examples/stripeIntegration.ts +106 -0
  10. package/package.json +181 -0
  11. package/src/ai/fraudDetection.ts +261 -0
  12. package/src/ai/patternRecognition.ts +218 -0
  13. package/src/analytics/dashboard.ts +195 -0
  14. package/src/analytics/metrics.ts +175 -0
  15. package/src/analytics/predictions.ts +135 -0
  16. package/src/analytics/reports.ts +221 -0
  17. package/src/api/controllers.ts +339 -0
  18. package/src/api/middleware.ts +172 -0
  19. package/src/api/routes.ts +141 -0
  20. package/src/config.ts +231 -0
  21. package/src/core/chargebackGuard.ts +616 -0
  22. package/src/core/eventEmitter.ts +118 -0
  23. package/src/core/lifecycle.ts +215 -0
  24. package/src/database/schema.ts +392 -0
  25. package/src/dispute/analyzer.ts +317 -0
  26. package/src/dispute/bankIntegration.ts +274 -0
  27. package/src/dispute/detector.ts +239 -0
  28. package/src/dispute/responseEngine.ts +440 -0
  29. package/src/evidence/collector.ts +426 -0
  30. package/src/evidence/encryption.ts +168 -0
  31. package/src/evidence/storage.ts +197 -0
  32. package/src/evidence/validator.ts +184 -0
  33. package/src/index.ts +43 -0
  34. package/src/integrations/paypal.ts +258 -0
  35. package/src/integrations/stripe.ts +280 -0
  36. package/src/integrations/webhook.ts +332 -0
  37. package/src/notifications/email.ts +161 -0
  38. package/src/notifications/inApp.ts +319 -0
  39. package/src/notifications/sms.ts +58 -0
  40. package/src/security/auth.ts +153 -0
  41. package/src/security/rateLimit.ts +77 -0
  42. package/src/security/validation.ts +166 -0
  43. package/src/server.ts +122 -0
  44. package/src/types/index.ts +790 -0
  45. package/src/utils/formatters.ts +72 -0
  46. package/src/utils/helpers.ts +193 -0
  47. package/src/utils/logger.ts +88 -0
  48. package/src/utils/validators.ts +39 -0
@@ -0,0 +1,118 @@
1
+ // ============================================================
2
+ // CHARGEBACK GUARD — Enhanced Event Emitter
3
+ // ============================================================
4
+
5
+ import { EventEmitter as NodeEventEmitter } from 'events';
6
+ import { NotificationEvent } from '../types';
7
+ import { createLogger } from '../utils/logger';
8
+
9
+ const log = createLogger('EventEmitter');
10
+
11
+ export interface EventPayload {
12
+ event: string;
13
+ timestamp: string;
14
+ data: Record<string, unknown>;
15
+ }
16
+
17
+ export type EventHandler = (payload: EventPayload) => void | Promise<void>;
18
+
19
+ // ────────────────────────────────────────────────────────────
20
+ // ENHANCED EVENT EMITTER
21
+ // ────────────────────────────────────────────────────────────
22
+
23
+ export class ChargebackEventEmitter extends NodeEventEmitter {
24
+ private readonly eventHistory: EventPayload[] = [];
25
+ private readonly maxHistorySize: number = 500;
26
+ private readonly asyncHandlers: Map<string, EventHandler[]> = new Map();
27
+
28
+ constructor() {
29
+ super();
30
+ this.setMaxListeners(50);
31
+ }
32
+
33
+ // ──────────────────────────────────────────
34
+ // EMIT WITH STRUCTURED PAYLOAD
35
+ // ──────────────────────────────────────────
36
+
37
+ emitEvent(event: NotificationEvent | string, data: Record<string, unknown>): boolean {
38
+ const payload: EventPayload = {
39
+ event,
40
+ timestamp: new Date().toISOString(),
41
+ data,
42
+ };
43
+
44
+ // Store in history
45
+ this.eventHistory.push(payload);
46
+ if (this.eventHistory.length > this.maxHistorySize) {
47
+ this.eventHistory.shift();
48
+ }
49
+
50
+ log.debug(`Event emitted: ${event}`, { data });
51
+
52
+ // Run async handlers
53
+ const asyncList = this.asyncHandlers.get(event) ?? [];
54
+ asyncList.forEach(handler => {
55
+ handler(payload).catch(err => {
56
+ log.error(`Async handler error for event "${event}"`, { error: err.message });
57
+ });
58
+ });
59
+
60
+ return this.emit(event, payload);
61
+ }
62
+
63
+ // ──────────────────────────────────────────
64
+ // REGISTER ASYNC HANDLER
65
+ // ──────────────────────────────────────────
66
+
67
+ onAsync(event: string, handler: EventHandler): this {
68
+ if (!this.asyncHandlers.has(event)) {
69
+ this.asyncHandlers.set(event, []);
70
+ }
71
+ this.asyncHandlers.get(event)!.push(handler);
72
+ return this;
73
+ }
74
+
75
+ // ──────────────────────────────────────────
76
+ // WAIT FOR EVENT (Promise-based)
77
+ // ──────────────────────────────────────────
78
+
79
+ waitFor(event: string, timeoutMs = 30000): Promise<EventPayload> {
80
+ return new Promise((resolve, reject) => {
81
+ const timer = setTimeout(() => {
82
+ reject(new Error(`Timeout waiting for event: ${event}`));
83
+ }, timeoutMs);
84
+
85
+ this.once(event, (payload: EventPayload) => {
86
+ clearTimeout(timer);
87
+ resolve(payload);
88
+ });
89
+ });
90
+ }
91
+
92
+ // ──────────────────────────────────────────
93
+ // EVENT HISTORY
94
+ // ──────────────────────────────────────────
95
+
96
+ getHistory(event?: string): EventPayload[] {
97
+ if (event) {
98
+ return this.eventHistory.filter(e => e.event === event);
99
+ }
100
+ return [...this.eventHistory];
101
+ }
102
+
103
+ clearHistory(): void {
104
+ this.eventHistory.length = 0;
105
+ }
106
+
107
+ // ──────────────────────────────────────────
108
+ // STATS
109
+ // ──────────────────────────────────────────
110
+
111
+ getStats(): Record<string, number> {
112
+ const stats: Record<string, number> = {};
113
+ this.eventHistory.forEach(({ event }) => {
114
+ stats[event] = (stats[event] ?? 0) + 1;
115
+ });
116
+ return stats;
117
+ }
118
+ }
@@ -0,0 +1,215 @@
1
+ // ============================================================
2
+ // CHARGEBACK GUARD — Lifecycle Manager
3
+ // Handles initialization, health-checks, and graceful shutdown
4
+ // ============================================================
5
+
6
+ import { createLogger } from '../utils/logger';
7
+
8
+ const log = createLogger('Lifecycle');
9
+
10
+ export type LifecycleStatus =
11
+ | 'uninitialized'
12
+ | 'initializing'
13
+ | 'ready'
14
+ | 'degraded'
15
+ | 'shutting_down'
16
+ | 'terminated';
17
+
18
+ export interface HealthCheck {
19
+ name: string;
20
+ status: 'healthy' | 'unhealthy' | 'degraded';
21
+ latencyMs?: number;
22
+ message?: string;
23
+ checkedAt: string;
24
+ }
25
+
26
+ export interface LifecycleHook {
27
+ name: string;
28
+ fn: () => Promise<void>;
29
+ timeout?: number;
30
+ }
31
+
32
+ // ────────────────────────────────────────────────────────────
33
+ // LIFECYCLE MANAGER CLASS
34
+ // ────────────────────────────────────────────────────────────
35
+
36
+ export class LifecycleManager {
37
+ private status: LifecycleStatus = 'uninitialized';
38
+ private startTime: Date = new Date();
39
+ private initHooks: LifecycleHook[] = [];
40
+ private shutdownHooks: LifecycleHook[] = [];
41
+ private healthCheckers: Map<string, () => Promise<HealthCheck>> = new Map();
42
+ private lastHealthCheck: HealthCheck[] = [];
43
+
44
+ // ──────────────────────────────────────────
45
+ // STATUS MANAGEMENT
46
+ // ──────────────────────────────────────────
47
+
48
+ getStatus(): LifecycleStatus {
49
+ return this.status;
50
+ }
51
+
52
+ isReady(): boolean {
53
+ return this.status === 'ready';
54
+ }
55
+
56
+ getUptime(): number {
57
+ return Date.now() - this.startTime.getTime();
58
+ }
59
+
60
+ // ──────────────────────────────────────────
61
+ // HOOK REGISTRATION
62
+ // ──────────────────────────────────────────
63
+
64
+ registerInitHook(hook: LifecycleHook): void {
65
+ this.initHooks.push(hook);
66
+ log.debug(`Init hook registered: ${hook.name}`);
67
+ }
68
+
69
+ registerShutdownHook(hook: LifecycleHook): void {
70
+ this.shutdownHooks.push(hook);
71
+ log.debug(`Shutdown hook registered: ${hook.name}`);
72
+ }
73
+
74
+ registerHealthChecker(name: string, checker: () => Promise<HealthCheck>): void {
75
+ this.healthCheckers.set(name, checker);
76
+ log.debug(`Health checker registered: ${name}`);
77
+ }
78
+
79
+ // ──────────────────────────────────────────
80
+ // INITIALIZATION
81
+ // ──────────────────────────────────────────
82
+
83
+ async initialize(): Promise<void> {
84
+ if (this.status !== 'uninitialized') {
85
+ throw new Error(`Cannot initialize: current status is "${this.status}"`);
86
+ }
87
+
88
+ this.status = 'initializing';
89
+ this.startTime = new Date();
90
+ log.info('ChargebackGuard initializing...');
91
+
92
+ for (const hook of this.initHooks) {
93
+ try {
94
+ log.debug(`Running init hook: ${hook.name}`);
95
+ await this.runWithTimeout(hook.fn, hook.timeout ?? 30000, hook.name);
96
+ log.debug(`Init hook completed: ${hook.name}`);
97
+ } catch (err) {
98
+ const msg = err instanceof Error ? err.message : String(err);
99
+ log.error(`Init hook failed: ${hook.name} — ${msg}`);
100
+ this.status = 'degraded';
101
+ throw new Error(`Initialization failed at hook "${hook.name}": ${msg}`);
102
+ }
103
+ }
104
+
105
+ this.status = 'ready';
106
+ log.info('ChargebackGuard ready ✅', { uptimeMs: this.getUptime() });
107
+ }
108
+
109
+ // ──────────────────────────────────────────
110
+ // GRACEFUL SHUTDOWN
111
+ // ──────────────────────────────────────────
112
+
113
+ async shutdown(reason = 'manual'): Promise<void> {
114
+ if (this.status === 'shutting_down' || this.status === 'terminated') {
115
+ return;
116
+ }
117
+
118
+ this.status = 'shutting_down';
119
+ log.info(`ChargebackGuard shutting down. Reason: ${reason}`);
120
+
121
+ // Run shutdown hooks in reverse order
122
+ for (const hook of [...this.shutdownHooks].reverse()) {
123
+ try {
124
+ log.debug(`Running shutdown hook: ${hook.name}`);
125
+ await this.runWithTimeout(hook.fn, hook.timeout ?? 10000, hook.name);
126
+ } catch (err) {
127
+ const msg = err instanceof Error ? err.message : String(err);
128
+ log.warn(`Shutdown hook failed (non-fatal): ${hook.name} — ${msg}`);
129
+ }
130
+ }
131
+
132
+ this.status = 'terminated';
133
+ log.info('ChargebackGuard terminated.');
134
+ }
135
+
136
+ // ──────────────────────────────────────────
137
+ // HEALTH CHECKS
138
+ // ──────────────────────────────────────────
139
+
140
+ async runHealthChecks(): Promise<HealthCheck[]> {
141
+ const results: HealthCheck[] = [];
142
+
143
+ for (const [name, checker] of this.healthCheckers.entries()) {
144
+ try {
145
+ const start = Date.now();
146
+ const result = await this.runWithTimeout(
147
+ () => checker(),
148
+ 5000,
149
+ `health:${name}`
150
+ );
151
+ results.push({ ...result, latencyMs: Date.now() - start });
152
+ } catch (err) {
153
+ results.push({
154
+ name,
155
+ status: 'unhealthy',
156
+ message: err instanceof Error ? err.message : 'Unknown error',
157
+ checkedAt: new Date().toISOString(),
158
+ });
159
+ }
160
+ }
161
+
162
+ this.lastHealthCheck = results;
163
+ return results;
164
+ }
165
+
166
+ getLastHealthCheck(): HealthCheck[] {
167
+ return this.lastHealthCheck;
168
+ }
169
+
170
+ async getSystemHealth(): Promise<{
171
+ status: 'healthy' | 'degraded' | 'unhealthy';
172
+ checks: HealthCheck[];
173
+ uptime: number;
174
+ lifecycleStatus: LifecycleStatus;
175
+ }> {
176
+ const checks = await this.runHealthChecks();
177
+ const hasUnhealthy = checks.some(c => c.status === 'unhealthy');
178
+ const hasDegraded = checks.some(c => c.status === 'degraded');
179
+
180
+ const overallStatus = hasUnhealthy ? 'unhealthy' : hasDegraded ? 'degraded' : 'healthy';
181
+
182
+ return {
183
+ status: overallStatus,
184
+ checks,
185
+ uptime: this.getUptime(),
186
+ lifecycleStatus: this.status,
187
+ };
188
+ }
189
+
190
+ // ──────────────────────────────────────────
191
+ // PRIVATE HELPERS
192
+ // ──────────────────────────────────────────
193
+
194
+ private async runWithTimeout<T>(
195
+ fn: () => Promise<T>,
196
+ timeoutMs: number,
197
+ label: string
198
+ ): Promise<T> {
199
+ return new Promise<T>((resolve, reject) => {
200
+ const timer = setTimeout(() => {
201
+ reject(new Error(`Timeout after ${timeoutMs}ms: ${label}`));
202
+ }, timeoutMs);
203
+
204
+ fn()
205
+ .then(result => {
206
+ clearTimeout(timer);
207
+ resolve(result);
208
+ })
209
+ .catch(err => {
210
+ clearTimeout(timer);
211
+ reject(err);
212
+ });
213
+ });
214
+ }
215
+ }