@classytic/revenue 1.0.2 → 1.1.2

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 (53) hide show
  1. package/README.md +603 -486
  2. package/dist/application/services/index.d.ts +6 -0
  3. package/dist/application/services/index.js +3288 -0
  4. package/dist/application/services/index.js.map +1 -0
  5. package/dist/core/events.d.ts +455 -0
  6. package/dist/core/events.js +122 -0
  7. package/dist/core/events.js.map +1 -0
  8. package/dist/core/index.d.ts +12 -889
  9. package/dist/core/index.js +2361 -705
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/enums/index.d.ts +54 -25
  12. package/dist/enums/index.js +143 -14
  13. package/dist/enums/index.js.map +1 -1
  14. package/dist/escrow.enums-CE0VQsfe.d.ts +76 -0
  15. package/dist/{index-BnJWVXuw.d.ts → index-DxIK0UmZ.d.ts} +281 -26
  16. package/dist/index-EnfKzDbs.d.ts +806 -0
  17. package/dist/{index-ChVD3P9k.d.ts → index-cLJBLUvx.d.ts} +55 -81
  18. package/dist/index.d.ts +16 -15
  19. package/dist/index.js +2583 -2066
  20. package/dist/index.js.map +1 -1
  21. package/dist/infrastructure/plugins/index.d.ts +267 -0
  22. package/dist/infrastructure/plugins/index.js +292 -0
  23. package/dist/infrastructure/plugins/index.js.map +1 -0
  24. package/dist/money-widWVD7r.d.ts +111 -0
  25. package/dist/payment.enums-C1BiGlRa.d.ts +69 -0
  26. package/dist/plugin-Bb9HOE10.d.ts +336 -0
  27. package/dist/providers/index.d.ts +19 -6
  28. package/dist/providers/index.js +22 -3
  29. package/dist/providers/index.js.map +1 -1
  30. package/dist/reconciliation/index.d.ts +215 -0
  31. package/dist/reconciliation/index.js +140 -0
  32. package/dist/reconciliation/index.js.map +1 -0
  33. package/dist/{retry-80lBCmSe.d.ts → retry-D4hFUwVk.d.ts} +1 -41
  34. package/dist/schemas/index.d.ts +1927 -166
  35. package/dist/schemas/index.js +357 -40
  36. package/dist/schemas/index.js.map +1 -1
  37. package/dist/schemas/validation.d.ts +87 -12
  38. package/dist/schemas/validation.js +71 -17
  39. package/dist/schemas/validation.js.map +1 -1
  40. package/dist/settlement.enums-ByC1x0ye.d.ts +130 -0
  41. package/dist/settlement.schema-CpamV7ZY.d.ts +343 -0
  42. package/dist/split.enums-DG3TxQf9.d.ts +42 -0
  43. package/dist/tax-CV8A0sxl.d.ts +60 -0
  44. package/dist/utils/index.d.ts +487 -13
  45. package/dist/utils/index.js +370 -235
  46. package/dist/utils/index.js.map +1 -1
  47. package/package.json +27 -13
  48. package/dist/actions-CwG-b7fR.d.ts +0 -519
  49. package/dist/services/index.d.ts +0 -3
  50. package/dist/services/index.js +0 -1632
  51. package/dist/services/index.js.map +0 -1
  52. package/dist/split.enums-Bh24jw8p.d.ts +0 -255
  53. package/dist/split.schema-DYVP7Wu2.d.ts +0 -958
@@ -0,0 +1,455 @@
1
+ import { T as TransactionDocument, S as SubscriptionDocument, P as PaymentIntentData, a as SplitInfo, W as WebhookEventData, b as PaymentResultData } from '../index-cLJBLUvx.js';
2
+ import { PaymentResult, RefundResult } from '../providers/index.js';
3
+ import { S as SettlementDocument } from '../settlement.schema-CpamV7ZY.js';
4
+ import 'mongoose';
5
+ import '@classytic/shared-types';
6
+ import '../split.enums-DG3TxQf9.js';
7
+
8
+ /**
9
+ * Event System - Type-safe pub/sub
10
+ * @classytic/revenue
11
+ *
12
+ * Strongly typed events with async handlers
13
+ * Inspired by: Node.js EventEmitter, mitt, EventTarget
14
+ */
15
+
16
+ /**
17
+ * All revenue events with their payload types
18
+ */
19
+ interface RevenueEvents {
20
+ 'payment.verified': PaymentVerifiedEvent;
21
+ 'payment.failed': PaymentFailedEvent;
22
+ 'payment.refunded': PaymentRefundedEvent;
23
+ 'payment.requires_action': PaymentRequiresActionEvent;
24
+ 'payment.processing': PaymentProcessingEvent;
25
+ 'monetization.created': MonetizationCreatedEvent;
26
+ 'purchase.created': PurchaseCreatedEvent;
27
+ 'free.created': FreeCreatedEvent;
28
+ 'subscription.created': SubscriptionCreatedEvent;
29
+ 'subscription.activated': SubscriptionActivatedEvent;
30
+ 'subscription.renewed': SubscriptionRenewedEvent;
31
+ 'subscription.cancelled': SubscriptionCancelledEvent;
32
+ 'subscription.paused': SubscriptionPausedEvent;
33
+ 'subscription.resumed': SubscriptionResumedEvent;
34
+ 'transaction.updated': TransactionUpdatedEvent;
35
+ 'escrow.held': EscrowHeldEvent;
36
+ 'escrow.released': EscrowReleasedEvent;
37
+ 'escrow.cancelled': EscrowCancelledEvent;
38
+ 'escrow.split': EscrowSplitEvent;
39
+ 'settlement.created': SettlementCreatedEvent;
40
+ 'settlement.scheduled': SettlementScheduledEvent;
41
+ 'settlement.processing': SettlementProcessingEvent;
42
+ 'settlement.completed': SettlementCompletedEvent;
43
+ 'settlement.failed': SettlementFailedEvent;
44
+ 'webhook.processed': WebhookProcessedEvent;
45
+ '*': BaseEvent;
46
+ }
47
+ /**
48
+ * Base event with auto-injected fields
49
+ */
50
+ interface BaseEvent {
51
+ readonly type: string;
52
+ readonly timestamp: Date;
53
+ readonly metadata?: Record<string, unknown>;
54
+ }
55
+ /**
56
+ * Event data types (what services emit - without type/timestamp)
57
+ * These are clean, explicit types that make it obvious what data to pass
58
+ */
59
+ interface PaymentVerifiedEventData {
60
+ transaction: TransactionDocument;
61
+ paymentResult: PaymentResult | PaymentResultData;
62
+ verifiedBy?: string | null;
63
+ }
64
+ interface PaymentFailedEventData {
65
+ transaction: TransactionDocument;
66
+ error: string;
67
+ provider: string;
68
+ paymentIntentId: string;
69
+ }
70
+ interface PaymentRefundedEventData {
71
+ transaction: TransactionDocument;
72
+ refundTransaction: TransactionDocument;
73
+ refundResult: RefundResult;
74
+ refundAmount: number;
75
+ reason?: string;
76
+ isPartialRefund: boolean;
77
+ }
78
+ interface PaymentRequiresActionEventData {
79
+ transaction: TransactionDocument;
80
+ paymentResult: PaymentResult | PaymentResultData;
81
+ action?: string | Record<string, unknown>;
82
+ }
83
+ interface PaymentProcessingEventData {
84
+ transaction: TransactionDocument;
85
+ paymentResult: PaymentResult | PaymentResultData;
86
+ }
87
+ interface MonetizationCreatedEventData {
88
+ monetizationType: string;
89
+ subscription?: SubscriptionDocument;
90
+ transaction?: TransactionDocument;
91
+ paymentIntent?: PaymentIntentData;
92
+ }
93
+ interface SubscriptionActivatedEventData {
94
+ subscription: SubscriptionDocument;
95
+ activatedAt: Date;
96
+ }
97
+ interface TransactionUpdatedEventData {
98
+ transaction: TransactionDocument;
99
+ updates: Partial<TransactionDocument>;
100
+ }
101
+ interface PaymentVerifiedEvent extends BaseEvent {
102
+ type: 'payment.verified';
103
+ transaction: TransactionDocument;
104
+ paymentResult: PaymentResult;
105
+ verifiedBy?: string;
106
+ }
107
+ interface PaymentFailedEvent extends BaseEvent {
108
+ type: 'payment.failed';
109
+ transaction: TransactionDocument;
110
+ error: string;
111
+ provider: string;
112
+ paymentIntentId: string;
113
+ }
114
+ interface PaymentRefundedEvent extends BaseEvent {
115
+ type: 'payment.refunded';
116
+ transaction: TransactionDocument;
117
+ refundTransaction: TransactionDocument;
118
+ refundResult: RefundResult;
119
+ refundAmount: number;
120
+ reason?: string;
121
+ isPartialRefund: boolean;
122
+ }
123
+ interface PaymentRequiresActionEvent extends BaseEvent {
124
+ type: 'payment.requires_action';
125
+ transaction: TransactionDocument;
126
+ paymentResult: PaymentResult;
127
+ action?: string | Record<string, unknown>;
128
+ }
129
+ interface PaymentProcessingEvent extends BaseEvent {
130
+ type: 'payment.processing';
131
+ transaction: TransactionDocument;
132
+ paymentResult: PaymentResult;
133
+ }
134
+ interface MonetizationCreatedEvent extends BaseEvent {
135
+ type: 'monetization.created';
136
+ monetizationType: string;
137
+ subscription?: SubscriptionDocument;
138
+ transaction?: TransactionDocument;
139
+ paymentIntent?: PaymentIntentData;
140
+ }
141
+ interface PurchaseCreatedEvent extends BaseEvent {
142
+ type: 'purchase.created';
143
+ monetizationType: string;
144
+ subscription?: SubscriptionDocument;
145
+ transaction: TransactionDocument;
146
+ paymentIntent?: PaymentIntentData;
147
+ }
148
+ interface FreeCreatedEvent extends BaseEvent {
149
+ type: 'free.created';
150
+ monetizationType: string;
151
+ subscription?: SubscriptionDocument;
152
+ transaction?: TransactionDocument;
153
+ paymentIntent?: PaymentIntentData;
154
+ }
155
+ interface SubscriptionCreatedEvent extends BaseEvent {
156
+ type: 'subscription.created';
157
+ subscriptionId: string;
158
+ subscription: SubscriptionDocument;
159
+ transactionId?: string;
160
+ }
161
+ interface SubscriptionActivatedEvent extends BaseEvent {
162
+ type: 'subscription.activated';
163
+ subscription: SubscriptionDocument;
164
+ activatedAt: Date;
165
+ }
166
+ interface SubscriptionRenewedEvent extends BaseEvent {
167
+ type: 'subscription.renewed';
168
+ subscription: SubscriptionDocument;
169
+ transaction: TransactionDocument;
170
+ paymentIntent?: PaymentIntentData;
171
+ renewalCount: number;
172
+ }
173
+ interface SubscriptionCancelledEvent extends BaseEvent {
174
+ type: 'subscription.cancelled';
175
+ subscription: SubscriptionDocument;
176
+ immediate: boolean;
177
+ reason?: string;
178
+ canceledAt: Date;
179
+ }
180
+ interface SubscriptionPausedEvent extends BaseEvent {
181
+ type: 'subscription.paused';
182
+ subscription: SubscriptionDocument;
183
+ reason?: string;
184
+ pausedAt: Date;
185
+ }
186
+ interface SubscriptionResumedEvent extends BaseEvent {
187
+ type: 'subscription.resumed';
188
+ subscription: SubscriptionDocument;
189
+ extendPeriod: boolean;
190
+ pauseDuration: number;
191
+ resumedAt: Date;
192
+ }
193
+ interface TransactionUpdatedEvent extends BaseEvent {
194
+ type: 'transaction.updated';
195
+ transaction: TransactionDocument;
196
+ updates: Partial<TransactionDocument>;
197
+ }
198
+ interface EscrowHeldEvent extends BaseEvent {
199
+ type: 'escrow.held';
200
+ transaction: TransactionDocument;
201
+ heldAmount: number;
202
+ reason: string;
203
+ }
204
+ interface EscrowReleasedEvent extends BaseEvent {
205
+ type: 'escrow.released';
206
+ transaction: TransactionDocument;
207
+ releaseTransaction: TransactionDocument | null;
208
+ releaseAmount: number;
209
+ recipientId: string;
210
+ recipientType: string;
211
+ reason: string;
212
+ isFullRelease: boolean;
213
+ isPartialRelease: boolean;
214
+ }
215
+ interface EscrowCancelledEvent extends BaseEvent {
216
+ type: 'escrow.cancelled';
217
+ transaction: TransactionDocument;
218
+ reason: string;
219
+ }
220
+ interface EscrowSplitEvent extends BaseEvent {
221
+ type: 'escrow.split';
222
+ transaction: TransactionDocument;
223
+ splits: SplitInfo[];
224
+ splitTransactions: TransactionDocument[];
225
+ organizationTransaction: TransactionDocument | null;
226
+ organizationPayout: number;
227
+ }
228
+ interface SettlementCreatedEvent extends BaseEvent {
229
+ type: 'settlement.created';
230
+ settlements: SettlementDocument[];
231
+ transactionId: string;
232
+ count: number;
233
+ }
234
+ interface SettlementScheduledEvent extends BaseEvent {
235
+ type: 'settlement.scheduled';
236
+ settlement: SettlementDocument;
237
+ scheduledAt: Date;
238
+ }
239
+ interface SettlementProcessingEvent extends BaseEvent {
240
+ type: 'settlement.processing';
241
+ settlement: SettlementDocument;
242
+ processedAt?: Date;
243
+ }
244
+ interface SettlementCompletedEvent extends BaseEvent {
245
+ type: 'settlement.completed';
246
+ settlement: SettlementDocument;
247
+ completedAt?: Date;
248
+ }
249
+ interface SettlementFailedEvent extends BaseEvent {
250
+ type: 'settlement.failed';
251
+ settlement: SettlementDocument;
252
+ reason: string;
253
+ code?: string;
254
+ retry: boolean;
255
+ }
256
+ interface WebhookProcessedEvent extends BaseEvent {
257
+ type: 'webhook.processed';
258
+ webhookType: string;
259
+ provider: string;
260
+ event: WebhookEventData;
261
+ transaction: TransactionDocument;
262
+ processedAt: Date;
263
+ }
264
+ /**
265
+ * Event data for free.created (transaction is optional)
266
+ */
267
+ interface FreeCreatedEventData {
268
+ monetizationType: string;
269
+ subscription?: SubscriptionDocument;
270
+ transaction?: TransactionDocument;
271
+ paymentIntent?: PaymentIntentData;
272
+ }
273
+ /**
274
+ * Event data for subscription.created
275
+ */
276
+ interface SubscriptionCreatedEventData {
277
+ subscriptionId: string;
278
+ subscription: SubscriptionDocument;
279
+ transactionId?: string;
280
+ }
281
+ /**
282
+ * Event data for subscription lifecycle events
283
+ */
284
+ interface SubscriptionRenewedEventData {
285
+ subscription: SubscriptionDocument;
286
+ transaction: TransactionDocument;
287
+ paymentIntent?: PaymentIntentData;
288
+ renewalCount: number;
289
+ }
290
+ interface SubscriptionCancelledEventData {
291
+ subscription: SubscriptionDocument;
292
+ immediate: boolean;
293
+ reason?: string;
294
+ canceledAt: Date;
295
+ }
296
+ interface SubscriptionPausedEventData {
297
+ subscription: SubscriptionDocument;
298
+ reason?: string;
299
+ pausedAt: Date;
300
+ }
301
+ interface SubscriptionResumedEventData {
302
+ subscription: SubscriptionDocument;
303
+ extendPeriod: boolean;
304
+ pauseDuration: number;
305
+ resumedAt: Date;
306
+ }
307
+ /**
308
+ * Event data for escrow events
309
+ */
310
+ interface EscrowHeldEventData {
311
+ transaction: TransactionDocument;
312
+ heldAmount: number;
313
+ reason: string;
314
+ }
315
+ interface EscrowReleasedEventData {
316
+ transaction: TransactionDocument;
317
+ releaseTransaction: TransactionDocument | null;
318
+ releaseAmount: number;
319
+ recipientId: string;
320
+ recipientType: string;
321
+ reason: string;
322
+ isFullRelease: boolean;
323
+ isPartialRelease: boolean;
324
+ }
325
+ interface EscrowCancelledEventData {
326
+ transaction: TransactionDocument;
327
+ reason: string;
328
+ }
329
+ interface EscrowSplitEventData {
330
+ transaction: TransactionDocument;
331
+ splits: SplitInfo[];
332
+ splitTransactions: TransactionDocument[];
333
+ organizationTransaction: TransactionDocument | null;
334
+ organizationPayout: number;
335
+ }
336
+ /**
337
+ * Event data for settlement events
338
+ */
339
+ interface SettlementCreatedEventData {
340
+ settlements: SettlementDocument[];
341
+ transactionId: string;
342
+ count: number;
343
+ }
344
+ interface SettlementScheduledEventData {
345
+ settlement: SettlementDocument;
346
+ scheduledAt: Date;
347
+ }
348
+ interface SettlementProcessingEventData {
349
+ settlement: SettlementDocument;
350
+ processedAt?: Date;
351
+ }
352
+ interface SettlementCompletedEventData {
353
+ settlement: SettlementDocument;
354
+ completedAt?: Date;
355
+ }
356
+ interface SettlementFailedEventData {
357
+ settlement: SettlementDocument;
358
+ reason: string;
359
+ code?: string;
360
+ retry: boolean;
361
+ }
362
+ /**
363
+ * Event data for webhook events
364
+ */
365
+ interface WebhookProcessedEventData {
366
+ webhookType: string;
367
+ provider: string;
368
+ event: WebhookEventData;
369
+ transaction: TransactionDocument;
370
+ processedAt: Date;
371
+ }
372
+ /**
373
+ * Clean mapping of event names to their data types (what you emit)
374
+ * This makes it crystal clear what data each event needs
375
+ * Only includes events that are actually emitted in the codebase
376
+ */
377
+ interface EventDataMap {
378
+ 'payment.verified': PaymentVerifiedEventData;
379
+ 'payment.failed': PaymentFailedEventData;
380
+ 'payment.refunded': PaymentRefundedEventData;
381
+ 'payment.requires_action': PaymentRequiresActionEventData;
382
+ 'payment.processing': PaymentProcessingEventData;
383
+ 'monetization.created': MonetizationCreatedEventData;
384
+ 'purchase.created': MonetizationCreatedEventData;
385
+ 'free.created': FreeCreatedEventData;
386
+ 'subscription.created': SubscriptionCreatedEventData;
387
+ 'subscription.activated': SubscriptionActivatedEventData;
388
+ 'subscription.renewed': SubscriptionRenewedEventData;
389
+ 'subscription.cancelled': SubscriptionCancelledEventData;
390
+ 'subscription.paused': SubscriptionPausedEventData;
391
+ 'subscription.resumed': SubscriptionResumedEventData;
392
+ 'transaction.updated': TransactionUpdatedEventData;
393
+ 'escrow.held': EscrowHeldEventData;
394
+ 'escrow.released': EscrowReleasedEventData;
395
+ 'escrow.cancelled': EscrowCancelledEventData;
396
+ 'escrow.split': EscrowSplitEventData;
397
+ 'settlement.created': SettlementCreatedEventData;
398
+ 'settlement.scheduled': SettlementScheduledEventData;
399
+ 'settlement.processing': SettlementProcessingEventData;
400
+ 'settlement.completed': SettlementCompletedEventData;
401
+ 'settlement.failed': SettlementFailedEventData;
402
+ 'webhook.processed': WebhookProcessedEventData;
403
+ }
404
+ type EventHandler<T> = (event: T) => void | Promise<void>;
405
+ type EventKey = keyof RevenueEvents;
406
+ /**
407
+ * Type-safe event bus with clean, simple API
408
+ */
409
+ declare class EventBus {
410
+ private handlers;
411
+ private onceHandlers;
412
+ /**
413
+ * Subscribe to an event
414
+ */
415
+ on<K extends EventKey>(event: K, handler: EventHandler<RevenueEvents[K]>): () => void;
416
+ /**
417
+ * Subscribe to an event once
418
+ */
419
+ once<K extends EventKey>(event: K, handler: EventHandler<RevenueEvents[K]>): () => void;
420
+ /**
421
+ * Unsubscribe from an event
422
+ */
423
+ off<K extends EventKey>(event: K, handler: EventHandler<RevenueEvents[K]>): void;
424
+ /**
425
+ * Emit an event (fire and forget, non-blocking)
426
+ *
427
+ * @example
428
+ * ```typescript
429
+ * events.emit('payment.verified', {
430
+ * transaction: txDoc,
431
+ * paymentResult: result,
432
+ * verifiedBy: 'admin_123'
433
+ * });
434
+ * ```
435
+ */
436
+ emit<K extends keyof EventDataMap>(event: K, data: EventDataMap[K]): void;
437
+ /**
438
+ * Emit and wait for all handlers to complete
439
+ */
440
+ emitAsync<K extends EventKey>(event: K, payload: Omit<RevenueEvents[K], 'timestamp' | 'type'>): Promise<void>;
441
+ /**
442
+ * Remove all handlers
443
+ */
444
+ clear(): void;
445
+ /**
446
+ * Get handler count for an event
447
+ */
448
+ listenerCount(event: EventKey): number;
449
+ }
450
+ /**
451
+ * Create a new event bus
452
+ */
453
+ declare function createEventBus(): EventBus;
454
+
455
+ export { type BaseEvent, type EscrowCancelledEvent, type EscrowCancelledEventData, type EscrowHeldEvent, type EscrowHeldEventData, type EscrowReleasedEvent, type EscrowReleasedEventData, type EscrowSplitEvent, type EscrowSplitEventData, EventBus, type EventDataMap, type FreeCreatedEvent, type FreeCreatedEventData, type MonetizationCreatedEvent, type MonetizationCreatedEventData, type PaymentFailedEvent, type PaymentFailedEventData, type PaymentProcessingEvent, type PaymentProcessingEventData, type PaymentRefundedEvent, type PaymentRefundedEventData, type PaymentRequiresActionEvent, type PaymentRequiresActionEventData, type PaymentVerifiedEvent, type PaymentVerifiedEventData, type PurchaseCreatedEvent, type RevenueEvents, type SettlementCompletedEvent, type SettlementCompletedEventData, type SettlementCreatedEvent, type SettlementCreatedEventData, type SettlementFailedEvent, type SettlementFailedEventData, type SettlementProcessingEvent, type SettlementProcessingEventData, type SettlementScheduledEvent, type SettlementScheduledEventData, type SubscriptionActivatedEvent, type SubscriptionActivatedEventData, type SubscriptionCancelledEvent, type SubscriptionCancelledEventData, type SubscriptionCreatedEvent, type SubscriptionCreatedEventData, type SubscriptionPausedEvent, type SubscriptionPausedEventData, type SubscriptionRenewedEvent, type SubscriptionRenewedEventData, type SubscriptionResumedEvent, type SubscriptionResumedEventData, type TransactionUpdatedEvent, type TransactionUpdatedEventData, type WebhookProcessedEvent, type WebhookProcessedEventData, createEventBus, EventBus as default };
@@ -0,0 +1,122 @@
1
+ // @classytic/revenue - Enterprise Revenue Management System
2
+
3
+ // src/core/events.ts
4
+ var EventBus = class {
5
+ handlers = /* @__PURE__ */ new Map();
6
+ onceHandlers = /* @__PURE__ */ new Map();
7
+ /**
8
+ * Subscribe to an event
9
+ */
10
+ on(event, handler) {
11
+ if (!this.handlers.has(event)) {
12
+ this.handlers.set(event, /* @__PURE__ */ new Set());
13
+ }
14
+ this.handlers.get(event).add(handler);
15
+ return () => this.off(event, handler);
16
+ }
17
+ /**
18
+ * Subscribe to an event once
19
+ */
20
+ once(event, handler) {
21
+ if (!this.onceHandlers.has(event)) {
22
+ this.onceHandlers.set(event, /* @__PURE__ */ new Set());
23
+ }
24
+ this.onceHandlers.get(event).add(handler);
25
+ return () => this.onceHandlers.get(event)?.delete(handler);
26
+ }
27
+ /**
28
+ * Unsubscribe from an event
29
+ */
30
+ off(event, handler) {
31
+ this.handlers.get(event)?.delete(handler);
32
+ this.onceHandlers.get(event)?.delete(handler);
33
+ }
34
+ emit(event, data) {
35
+ const fullPayload = {
36
+ ...data,
37
+ type: event,
38
+ timestamp: /* @__PURE__ */ new Date()
39
+ };
40
+ const handlers = this.handlers.get(event);
41
+ if (handlers) {
42
+ for (const handler of handlers) {
43
+ Promise.resolve(handler(fullPayload)).catch((err) => {
44
+ console.error(`[Revenue] Event handler error for "${event}":`, err);
45
+ });
46
+ }
47
+ }
48
+ const onceHandlers = this.onceHandlers.get(event);
49
+ if (onceHandlers) {
50
+ for (const handler of onceHandlers) {
51
+ Promise.resolve(handler(fullPayload)).catch((err) => {
52
+ console.error(`[Revenue] Once handler error for "${event}":`, err);
53
+ });
54
+ }
55
+ this.onceHandlers.delete(event);
56
+ }
57
+ if (event !== "*") {
58
+ const wildcardHandlers = this.handlers.get("*");
59
+ if (wildcardHandlers) {
60
+ for (const handler of wildcardHandlers) {
61
+ Promise.resolve(handler(fullPayload)).catch((err) => {
62
+ console.error(`[Revenue] Wildcard handler error:`, err);
63
+ });
64
+ }
65
+ }
66
+ }
67
+ }
68
+ /**
69
+ * Emit and wait for all handlers to complete
70
+ */
71
+ async emitAsync(event, payload) {
72
+ const fullPayload = {
73
+ ...payload,
74
+ type: event,
75
+ timestamp: /* @__PURE__ */ new Date()
76
+ };
77
+ const promises = [];
78
+ const handlers = this.handlers.get(event);
79
+ if (handlers) {
80
+ for (const handler of handlers) {
81
+ promises.push(Promise.resolve(handler(fullPayload)));
82
+ }
83
+ }
84
+ const onceHandlers = this.onceHandlers.get(event);
85
+ if (onceHandlers) {
86
+ for (const handler of onceHandlers) {
87
+ promises.push(Promise.resolve(handler(fullPayload)));
88
+ }
89
+ this.onceHandlers.delete(event);
90
+ }
91
+ if (event !== "*") {
92
+ const wildcardHandlers = this.handlers.get("*");
93
+ if (wildcardHandlers) {
94
+ for (const handler of wildcardHandlers) {
95
+ promises.push(Promise.resolve(handler(fullPayload)));
96
+ }
97
+ }
98
+ }
99
+ await Promise.all(promises);
100
+ }
101
+ /**
102
+ * Remove all handlers
103
+ */
104
+ clear() {
105
+ this.handlers.clear();
106
+ this.onceHandlers.clear();
107
+ }
108
+ /**
109
+ * Get handler count for an event
110
+ */
111
+ listenerCount(event) {
112
+ return (this.handlers.get(event)?.size ?? 0) + (this.onceHandlers.get(event)?.size ?? 0);
113
+ }
114
+ };
115
+ function createEventBus() {
116
+ return new EventBus();
117
+ }
118
+ var events_default = EventBus;
119
+
120
+ export { EventBus, createEventBus, events_default as default };
121
+ //# sourceMappingURL=events.js.map
122
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/events.ts"],"names":[],"mappings":"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","file":"events.js","sourcesContent":["/**\n * Event System - Type-safe pub/sub\n * @classytic/revenue\n *\n * Strongly typed events with async handlers\n * Inspired by: Node.js EventEmitter, mitt, EventTarget\n */\n\nimport type {\n TransactionDocument,\n SubscriptionDocument,\n PaymentResultData,\n PaymentIntentData,\n SplitInfo,\n WebhookEventData,\n} from '../shared/types/index.js';\nimport type { PaymentResult, RefundResult } from '../providers/base.js';\nimport type { SettlementDocument } from '../schemas/settlement/settlement.schema.js';\n\n// ============ EVENT DEFINITIONS ============\n\n/**\n * All revenue events with their payload types\n */\nexport interface RevenueEvents {\n // Payment events\n 'payment.verified': PaymentVerifiedEvent;\n 'payment.failed': PaymentFailedEvent;\n 'payment.refunded': PaymentRefundedEvent;\n 'payment.requires_action': PaymentRequiresActionEvent;\n 'payment.processing': PaymentProcessingEvent;\n\n // Monetization events\n 'monetization.created': MonetizationCreatedEvent;\n 'purchase.created': PurchaseCreatedEvent;\n 'free.created': FreeCreatedEvent;\n\n // Subscription events\n 'subscription.created': SubscriptionCreatedEvent;\n 'subscription.activated': SubscriptionActivatedEvent;\n 'subscription.renewed': SubscriptionRenewedEvent;\n 'subscription.cancelled': SubscriptionCancelledEvent;\n 'subscription.paused': SubscriptionPausedEvent;\n 'subscription.resumed': SubscriptionResumedEvent;\n\n // Transaction events\n 'transaction.updated': TransactionUpdatedEvent;\n\n // Escrow events\n 'escrow.held': EscrowHeldEvent;\n 'escrow.released': EscrowReleasedEvent;\n 'escrow.cancelled': EscrowCancelledEvent;\n 'escrow.split': EscrowSplitEvent;\n\n // Settlement events\n 'settlement.created': SettlementCreatedEvent;\n 'settlement.scheduled': SettlementScheduledEvent;\n 'settlement.processing': SettlementProcessingEvent;\n 'settlement.completed': SettlementCompletedEvent;\n 'settlement.failed': SettlementFailedEvent;\n\n // Webhook events\n 'webhook.processed': WebhookProcessedEvent;\n\n // Wildcard - catches all events\n '*': BaseEvent;\n}\n\n// ============ EVENT PAYLOADS ============\n\n/**\n * Base event with auto-injected fields\n */\nexport interface BaseEvent {\n readonly type: string;\n readonly timestamp: Date;\n readonly metadata?: Record<string, unknown>;\n}\n\n/**\n * Event data types (what services emit - without type/timestamp)\n * These are clean, explicit types that make it obvious what data to pass\n */\nexport interface PaymentVerifiedEventData {\n transaction: TransactionDocument;\n paymentResult: PaymentResult | PaymentResultData;\n verifiedBy?: string | null;\n}\n\nexport interface PaymentFailedEventData {\n transaction: TransactionDocument;\n error: string;\n provider: string;\n paymentIntentId: string;\n}\n\nexport interface PaymentRefundedEventData {\n transaction: TransactionDocument;\n refundTransaction: TransactionDocument;\n refundResult: RefundResult;\n refundAmount: number;\n reason?: string;\n isPartialRefund: boolean;\n}\n\nexport interface PaymentRequiresActionEventData {\n transaction: TransactionDocument;\n paymentResult: PaymentResult | PaymentResultData;\n action?: string | Record<string, unknown>;\n}\n\nexport interface PaymentProcessingEventData {\n transaction: TransactionDocument;\n paymentResult: PaymentResult | PaymentResultData;\n}\n\nexport interface MonetizationCreatedEventData {\n monetizationType: string;\n subscription?: SubscriptionDocument;\n transaction?: TransactionDocument;\n paymentIntent?: PaymentIntentData;\n}\n\nexport interface SubscriptionActivatedEventData {\n subscription: SubscriptionDocument;\n activatedAt: Date;\n}\n\nexport interface TransactionUpdatedEventData {\n transaction: TransactionDocument;\n updates: Partial<TransactionDocument>;\n}\n\nexport interface PaymentVerifiedEvent extends BaseEvent {\n type: 'payment.verified';\n transaction: TransactionDocument;\n paymentResult: PaymentResult;\n verifiedBy?: string;\n}\n\nexport interface PaymentFailedEvent extends BaseEvent {\n type: 'payment.failed';\n transaction: TransactionDocument;\n error: string;\n provider: string;\n paymentIntentId: string;\n}\n\nexport interface PaymentRefundedEvent extends BaseEvent {\n type: 'payment.refunded';\n transaction: TransactionDocument;\n refundTransaction: TransactionDocument;\n refundResult: RefundResult;\n refundAmount: number;\n reason?: string;\n isPartialRefund: boolean;\n}\n\nexport interface PaymentRequiresActionEvent extends BaseEvent {\n type: 'payment.requires_action';\n transaction: TransactionDocument;\n paymentResult: PaymentResult;\n action?: string | Record<string, unknown>;\n}\n\nexport interface PaymentProcessingEvent extends BaseEvent {\n type: 'payment.processing';\n transaction: TransactionDocument;\n paymentResult: PaymentResult;\n}\n\nexport interface MonetizationCreatedEvent extends BaseEvent {\n type: 'monetization.created';\n monetizationType: string;\n subscription?: SubscriptionDocument;\n transaction?: TransactionDocument;\n paymentIntent?: PaymentIntentData;\n}\n\nexport interface PurchaseCreatedEvent extends BaseEvent {\n type: 'purchase.created';\n monetizationType: string;\n subscription?: SubscriptionDocument;\n transaction: TransactionDocument;\n paymentIntent?: PaymentIntentData;\n}\n\nexport interface FreeCreatedEvent extends BaseEvent {\n type: 'free.created';\n monetizationType: string;\n subscription?: SubscriptionDocument;\n transaction?: TransactionDocument; // Optional: free flows may not create transactions\n paymentIntent?: PaymentIntentData;\n}\n\nexport interface SubscriptionCreatedEvent extends BaseEvent {\n type: 'subscription.created';\n subscriptionId: string;\n subscription: SubscriptionDocument;\n transactionId?: string;\n}\n\nexport interface SubscriptionActivatedEvent extends BaseEvent {\n type: 'subscription.activated';\n subscription: SubscriptionDocument;\n activatedAt: Date;\n}\n\nexport interface SubscriptionRenewedEvent extends BaseEvent {\n type: 'subscription.renewed';\n subscription: SubscriptionDocument;\n transaction: TransactionDocument;\n paymentIntent?: PaymentIntentData;\n renewalCount: number;\n}\n\nexport interface SubscriptionCancelledEvent extends BaseEvent {\n type: 'subscription.cancelled';\n subscription: SubscriptionDocument;\n immediate: boolean;\n reason?: string;\n canceledAt: Date;\n}\n\nexport interface SubscriptionPausedEvent extends BaseEvent {\n type: 'subscription.paused';\n subscription: SubscriptionDocument;\n reason?: string;\n pausedAt: Date;\n}\n\nexport interface SubscriptionResumedEvent extends BaseEvent {\n type: 'subscription.resumed';\n subscription: SubscriptionDocument;\n extendPeriod: boolean;\n pauseDuration: number;\n resumedAt: Date;\n}\n\nexport interface TransactionUpdatedEvent extends BaseEvent {\n type: 'transaction.updated';\n transaction: TransactionDocument;\n updates: Partial<TransactionDocument>;\n}\n\nexport interface EscrowHeldEvent extends BaseEvent {\n type: 'escrow.held';\n transaction: TransactionDocument;\n heldAmount: number;\n reason: string;\n}\n\nexport interface EscrowReleasedEvent extends BaseEvent {\n type: 'escrow.released';\n transaction: TransactionDocument;\n releaseTransaction: TransactionDocument | null;\n releaseAmount: number;\n recipientId: string;\n recipientType: string;\n reason: string;\n isFullRelease: boolean;\n isPartialRelease: boolean;\n}\n\nexport interface EscrowCancelledEvent extends BaseEvent {\n type: 'escrow.cancelled';\n transaction: TransactionDocument;\n reason: string;\n}\n\nexport interface EscrowSplitEvent extends BaseEvent {\n type: 'escrow.split';\n transaction: TransactionDocument;\n splits: SplitInfo[];\n splitTransactions: TransactionDocument[];\n organizationTransaction: TransactionDocument | null;\n organizationPayout: number;\n}\n\nexport interface SettlementCreatedEvent extends BaseEvent {\n type: 'settlement.created';\n settlements: SettlementDocument[];\n transactionId: string;\n count: number;\n}\n\nexport interface SettlementScheduledEvent extends BaseEvent {\n type: 'settlement.scheduled';\n settlement: SettlementDocument;\n scheduledAt: Date;\n}\n\nexport interface SettlementProcessingEvent extends BaseEvent {\n type: 'settlement.processing';\n settlement: SettlementDocument;\n processedAt?: Date;\n}\n\nexport interface SettlementCompletedEvent extends BaseEvent {\n type: 'settlement.completed';\n settlement: SettlementDocument;\n completedAt?: Date;\n}\n\nexport interface SettlementFailedEvent extends BaseEvent {\n type: 'settlement.failed';\n settlement: SettlementDocument;\n reason: string;\n code?: string;\n retry: boolean;\n}\n\nexport interface WebhookProcessedEvent extends BaseEvent {\n type: 'webhook.processed';\n webhookType: string;\n provider: string;\n event: WebhookEventData;\n transaction: TransactionDocument;\n processedAt: Date;\n}\n\n/**\n * Event data for free.created (transaction is optional)\n */\nexport interface FreeCreatedEventData {\n monetizationType: string;\n subscription?: SubscriptionDocument;\n transaction?: TransactionDocument;\n paymentIntent?: PaymentIntentData;\n}\n\n/**\n * Event data for subscription.created\n */\nexport interface SubscriptionCreatedEventData {\n subscriptionId: string;\n subscription: SubscriptionDocument;\n transactionId?: string;\n}\n\n/**\n * Event data for subscription lifecycle events\n */\nexport interface SubscriptionRenewedEventData {\n subscription: SubscriptionDocument;\n transaction: TransactionDocument;\n paymentIntent?: PaymentIntentData;\n renewalCount: number;\n}\n\nexport interface SubscriptionCancelledEventData {\n subscription: SubscriptionDocument;\n immediate: boolean;\n reason?: string;\n canceledAt: Date;\n}\n\nexport interface SubscriptionPausedEventData {\n subscription: SubscriptionDocument;\n reason?: string;\n pausedAt: Date;\n}\n\nexport interface SubscriptionResumedEventData {\n subscription: SubscriptionDocument;\n extendPeriod: boolean;\n pauseDuration: number;\n resumedAt: Date;\n}\n\n/**\n * Event data for escrow events\n */\nexport interface EscrowHeldEventData {\n transaction: TransactionDocument;\n heldAmount: number;\n reason: string;\n}\n\nexport interface EscrowReleasedEventData {\n transaction: TransactionDocument;\n releaseTransaction: TransactionDocument | null;\n releaseAmount: number;\n recipientId: string;\n recipientType: string;\n reason: string;\n isFullRelease: boolean;\n isPartialRelease: boolean;\n}\n\nexport interface EscrowCancelledEventData {\n transaction: TransactionDocument;\n reason: string;\n}\n\nexport interface EscrowSplitEventData {\n transaction: TransactionDocument;\n splits: SplitInfo[];\n splitTransactions: TransactionDocument[];\n organizationTransaction: TransactionDocument | null;\n organizationPayout: number;\n}\n\n/**\n * Event data for settlement events\n */\nexport interface SettlementCreatedEventData {\n settlements: SettlementDocument[];\n transactionId: string;\n count: number;\n}\n\nexport interface SettlementScheduledEventData {\n settlement: SettlementDocument;\n scheduledAt: Date;\n}\n\nexport interface SettlementProcessingEventData {\n settlement: SettlementDocument;\n processedAt?: Date;\n}\n\nexport interface SettlementCompletedEventData {\n settlement: SettlementDocument;\n completedAt?: Date;\n}\n\nexport interface SettlementFailedEventData {\n settlement: SettlementDocument;\n reason: string;\n code?: string;\n retry: boolean;\n}\n\n/**\n * Event data for webhook events\n */\nexport interface WebhookProcessedEventData {\n webhookType: string;\n provider: string;\n event: WebhookEventData;\n transaction: TransactionDocument;\n processedAt: Date;\n}\n\n/**\n * Clean mapping of event names to their data types (what you emit)\n * This makes it crystal clear what data each event needs\n * Only includes events that are actually emitted in the codebase\n */\nexport interface EventDataMap {\n // Payment events\n 'payment.verified': PaymentVerifiedEventData;\n 'payment.failed': PaymentFailedEventData;\n 'payment.refunded': PaymentRefundedEventData;\n 'payment.requires_action': PaymentRequiresActionEventData;\n 'payment.processing': PaymentProcessingEventData;\n\n // Monetization events\n 'monetization.created': MonetizationCreatedEventData;\n 'purchase.created': MonetizationCreatedEventData;\n 'free.created': FreeCreatedEventData;\n\n // Subscription events\n 'subscription.created': SubscriptionCreatedEventData;\n 'subscription.activated': SubscriptionActivatedEventData;\n 'subscription.renewed': SubscriptionRenewedEventData;\n 'subscription.cancelled': SubscriptionCancelledEventData;\n 'subscription.paused': SubscriptionPausedEventData;\n 'subscription.resumed': SubscriptionResumedEventData;\n\n // Transaction events\n 'transaction.updated': TransactionUpdatedEventData;\n\n // Escrow events\n 'escrow.held': EscrowHeldEventData;\n 'escrow.released': EscrowReleasedEventData;\n 'escrow.cancelled': EscrowCancelledEventData;\n 'escrow.split': EscrowSplitEventData;\n\n // Settlement events\n 'settlement.created': SettlementCreatedEventData;\n 'settlement.scheduled': SettlementScheduledEventData;\n 'settlement.processing': SettlementProcessingEventData;\n 'settlement.completed': SettlementCompletedEventData;\n 'settlement.failed': SettlementFailedEventData;\n\n // Webhook events\n 'webhook.processed': WebhookProcessedEventData;\n}\n\n// ============ EVENT BUS ============\n\ntype EventHandler<T> = (event: T) => void | Promise<void>;\ntype EventKey = keyof RevenueEvents;\n\n/**\n * Type-safe event bus with clean, simple API\n */\nexport class EventBus {\n private handlers = new Map<string, Set<EventHandler<any>>>();\n private onceHandlers = new Map<string, Set<EventHandler<any>>>();\n\n /**\n * Subscribe to an event\n */\n on<K extends EventKey>(\n event: K,\n handler: EventHandler<RevenueEvents[K]>\n ): () => void {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n this.handlers.get(event)!.add(handler);\n \n // Return unsubscribe function\n return () => this.off(event, handler);\n }\n\n /**\n * Subscribe to an event once\n */\n once<K extends EventKey>(\n event: K,\n handler: EventHandler<RevenueEvents[K]>\n ): () => void {\n if (!this.onceHandlers.has(event)) {\n this.onceHandlers.set(event, new Set());\n }\n this.onceHandlers.get(event)!.add(handler);\n \n return () => this.onceHandlers.get(event)?.delete(handler);\n }\n\n /**\n * Unsubscribe from an event\n */\n off<K extends EventKey>(\n event: K,\n handler: EventHandler<RevenueEvents[K]>\n ): void {\n this.handlers.get(event)?.delete(handler);\n this.onceHandlers.get(event)?.delete(handler);\n }\n\n /**\n * Emit an event (fire and forget, non-blocking)\n *\n * @example\n * ```typescript\n * events.emit('payment.verified', {\n * transaction: txDoc,\n * paymentResult: result,\n * verifiedBy: 'admin_123'\n * });\n * ```\n */\n emit<K extends keyof EventDataMap>(event: K, data: EventDataMap[K]): void;\n emit<K extends EventKey>(event: K, data: any): void {\n const fullPayload = {\n ...data,\n type: event,\n timestamp: new Date(),\n } as RevenueEvents[K];\n\n // Regular handlers\n const handlers = this.handlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n // Fire and forget - don't await\n Promise.resolve(handler(fullPayload)).catch(err => {\n console.error(`[Revenue] Event handler error for \"${event}\":`, err);\n });\n }\n }\n\n // Once handlers\n const onceHandlers = this.onceHandlers.get(event);\n if (onceHandlers) {\n for (const handler of onceHandlers) {\n Promise.resolve(handler(fullPayload)).catch(err => {\n console.error(`[Revenue] Once handler error for \"${event}\":`, err);\n });\n }\n this.onceHandlers.delete(event);\n }\n\n // Wildcard handlers\n if (event !== '*') {\n const wildcardHandlers = this.handlers.get('*');\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n Promise.resolve(handler(fullPayload)).catch(err => {\n console.error(`[Revenue] Wildcard handler error:`, err);\n });\n }\n }\n }\n }\n\n /**\n * Emit and wait for all handlers to complete\n */\n async emitAsync<K extends EventKey>(\n event: K,\n payload: Omit<RevenueEvents[K], 'timestamp' | 'type'>\n ): Promise<void> {\n const fullPayload = {\n ...payload,\n type: event,\n timestamp: new Date(),\n } as RevenueEvents[K];\n\n const promises: Promise<void>[] = [];\n\n const handlers = this.handlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n promises.push(Promise.resolve(handler(fullPayload)));\n }\n }\n\n const onceHandlers = this.onceHandlers.get(event);\n if (onceHandlers) {\n for (const handler of onceHandlers) {\n promises.push(Promise.resolve(handler(fullPayload)));\n }\n this.onceHandlers.delete(event);\n }\n\n if (event !== '*') {\n const wildcardHandlers = this.handlers.get('*');\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n promises.push(Promise.resolve(handler(fullPayload)));\n }\n }\n }\n\n await Promise.all(promises);\n }\n\n /**\n * Remove all handlers\n */\n clear(): void {\n this.handlers.clear();\n this.onceHandlers.clear();\n }\n\n /**\n * Get handler count for an event\n */\n listenerCount(event: EventKey): number {\n return (this.handlers.get(event)?.size ?? 0) + \n (this.onceHandlers.get(event)?.size ?? 0);\n }\n}\n\n/**\n * Create a new event bus\n */\nexport function createEventBus(): EventBus {\n return new EventBus();\n}\n\nexport default EventBus;\n\n"]}