@classytic/revenue 0.1.0 → 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/README.md CHANGED
@@ -494,24 +494,71 @@ const transactions = await Transaction.find({ ... })
494
494
  const revenue = createRevenue({
495
495
  models: { Transaction },
496
496
  hooks: {
497
- 'subscription.created': async ({ subscription, transaction }) => {
498
- console.log('New subscription:', subscription._id);
497
+ // Monetization lifecycle (specific)
498
+ 'purchase.created': async ({ transaction, isFree }) => {
499
+ console.log('One-time purchase:', transaction._id);
499
500
  },
501
+ 'subscription.created': async ({ transaction, isFree }) => {
502
+ console.log('Recurring subscription:', transaction._id);
503
+ },
504
+ 'free.created': async ({ transaction }) => {
505
+ console.log('Free access granted:', transaction._id);
506
+ },
507
+
508
+ // Generic event (fires for all types)
509
+ 'monetization.created': async ({ transaction, monetizationType }) => {
510
+ console.log(`${monetizationType} created:`, transaction._id);
511
+ },
512
+
513
+ // Payment lifecycle
500
514
  'payment.verified': async ({ transaction }) => {
501
515
  // Send confirmation email
502
516
  },
517
+ 'payment.failed': async ({ transaction, error, provider }) => {
518
+ // Alert admin or send customer notification
519
+ console.error('Payment failed:', error);
520
+ },
503
521
  'payment.refunded': async ({ refundTransaction }) => {
504
522
  // Process refund notification
505
523
  },
524
+
525
+ // Subscription management (requires Subscription model)
526
+ 'subscription.activated': async ({ subscription }) => {
527
+ // Subscription activated after payment
528
+ },
529
+ 'subscription.renewed': async ({ subscription, renewalCount }) => {
530
+ // Subscription renewed
531
+ },
532
+ 'subscription.paused': async ({ subscription }) => {
533
+ // Subscription paused
534
+ },
535
+ 'subscription.resumed': async ({ subscription }) => {
536
+ // Subscription resumed
537
+ },
538
+ 'subscription.cancelled': async ({ subscription }) => {
539
+ // Subscription cancelled
540
+ },
506
541
  },
507
542
  });
508
543
  ```
509
544
 
510
545
  **Available hooks:**
511
- - `subscription.created`, `subscription.activated`, `subscription.renewed`
546
+
547
+ **Monetization Events (specific):**
548
+ - `purchase.created` - One-time purchase
549
+ - `subscription.created` - Recurring subscription
550
+ - `free.created` - Free access granted
551
+ - `monetization.created` - Generic event (fires for all types)
552
+
553
+ **Payment Events:**
554
+ - `payment.verified` - Payment confirmed
555
+ - `payment.failed` - Payment verification failed
556
+ - `payment.refunded` - Refund processed
557
+ - `payment.webhook.{type}` - Webhook events from providers
558
+
559
+ **Subscription Management Events (requires Subscription model):**
560
+ - `subscription.activated`, `subscription.renewed`
512
561
  - `subscription.paused`, `subscription.resumed`, `subscription.cancelled`
513
- - `payment.verified`, `payment.refunded`
514
- - `payment.webhook.{type}` (for webhook events)
515
562
 
516
563
  ## Provider Patterns
517
564
 
@@ -599,6 +646,7 @@ const subscription = await revenue.subscriptions.create({ ... });
599
646
  - [`examples/transaction.model.js`](examples/transaction.model.js) - Complete model setup
600
647
  - [`examples/complete-flow.js`](examples/complete-flow.js) - Full lifecycle (types, refs, state)
601
648
  - [`examples/commission-tracking.js`](examples/commission-tracking.js) - Commission calculation
649
+ - [`examples/hooks-v0.2.0.js`](examples/hooks-v0.2.0.js) - v0.2.0 semantic hooks (NEW)
602
650
 
603
651
  ## Error Handling
604
652
 
package/core/builder.js CHANGED
@@ -18,7 +18,7 @@ import { ConfigurationError } from './errors.js';
18
18
  *
19
19
  * @param {Object} options - Configuration options
20
20
  * @param {Object} options.models - Mongoose models { Transaction, Subscription, etc. }
21
- * @param {Object} options.providers - Payment providers { manual, stripe, etc. }
21
+ * @param {Record<string, import('../providers/base.js').PaymentProvider>} options.providers - Payment providers - Register ANY custom gateway by name
22
22
  * @param {Object} options.hooks - Event hooks
23
23
  * @param {Object} options.config - Additional configuration
24
24
  * @param {Object} options.logger - Logger instance
@@ -26,7 +26,8 @@ import { ConfigurationError } from './errors.js';
26
26
  *
27
27
  * @example
28
28
  * ```javascript
29
- * import { createRevenue, ManualProvider } from '@classytic/revenue';
29
+ * import { createRevenue } from '@classytic/revenue';
30
+ * import { ManualProvider } from '@classytic/revenue-manual';
30
31
  *
31
32
  * const revenue = createRevenue({
32
33
  * models: {
@@ -35,6 +36,10 @@ import { ConfigurationError } from './errors.js';
35
36
  * },
36
37
  * providers: {
37
38
  * manual: new ManualProvider(),
39
+ * bkash: new BkashProvider(), // Custom gateway
40
+ * nagad: new NagadProvider(), // Custom gateway
41
+ * stripe: new StripeProvider(), // Custom gateway
42
+ * // ... register any gateway you want
38
43
  * },
39
44
  * config: {
40
45
  * targetModels: ['Subscription', 'Membership'],
@@ -45,8 +50,11 @@ import { ConfigurationError } from './errors.js';
45
50
  * },
46
51
  * });
47
52
  *
48
- * // Use anywhere
49
- * const subscription = await revenue.subscriptions.create({ ... });
53
+ * // Use any registered gateway by name
54
+ * const subscription = await revenue.subscriptions.create({
55
+ * gateway: 'bkash', // Use your custom gateway
56
+ * // ...
57
+ * });
50
58
  * await revenue.payments.verify(txnId);
51
59
  * ```
52
60
  */
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @param {Object} options - Configuration options
5
5
  * @param {Object} options.models - Mongoose models { Transaction, Subscription, etc. }
6
- * @param {Object} options.providers - Payment providers { manual, stripe, etc. }
6
+ * @param {Record<string, import('../providers/base.js').PaymentProvider>} options.providers - Payment providers - Register ANY custom gateway by name
7
7
  * @param {Object} options.hooks - Event hooks
8
8
  * @param {Object} options.config - Additional configuration
9
9
  * @param {Object} options.logger - Logger instance
@@ -11,7 +11,8 @@
11
11
  *
12
12
  * @example
13
13
  * ```javascript
14
- * import { createRevenue, ManualProvider } from '@classytic/revenue';
14
+ * import { createRevenue } from '@classytic/revenue';
15
+ * import { ManualProvider } from '@classytic/revenue-manual';
15
16
  *
16
17
  * const revenue = createRevenue({
17
18
  * models: {
@@ -20,6 +21,10 @@
20
21
  * },
21
22
  * providers: {
22
23
  * manual: new ManualProvider(),
24
+ * bkash: new BkashProvider(), // Custom gateway
25
+ * nagad: new NagadProvider(), // Custom gateway
26
+ * stripe: new StripeProvider(), // Custom gateway
27
+ * // ... register any gateway you want
23
28
  * },
24
29
  * config: {
25
30
  * targetModels: ['Subscription', 'Membership'],
@@ -30,14 +35,17 @@
30
35
  * },
31
36
  * });
32
37
  *
33
- * // Use anywhere
34
- * const subscription = await revenue.subscriptions.create({ ... });
38
+ * // Use any registered gateway by name
39
+ * const subscription = await revenue.subscriptions.create({
40
+ * gateway: 'bkash', // Use your custom gateway
41
+ * // ...
42
+ * });
35
43
  * await revenue.payments.verify(txnId);
36
44
  * ```
37
45
  */
38
46
  export function createRevenue(options?: {
39
47
  models: any;
40
- providers: any;
48
+ providers: Record<string, import("../providers/base.js").PaymentProvider>;
41
49
  hooks: any;
42
50
  config: any;
43
51
  logger: any;
@@ -18,7 +18,7 @@ export class SubscriptionService {
18
18
  * @param {String} params.planKey - Plan key ('monthly', 'quarterly', 'yearly')
19
19
  * @param {Number} params.amount - Subscription amount
20
20
  * @param {String} params.currency - Currency code (default: 'BDT')
21
- * @param {String} params.gateway - Payment gateway to use (default: 'manual')
21
+ * @param {String} params.gateway - Payment gateway name (default: 'manual') - Use ANY registered provider name: 'manual', 'bkash', 'nagad', 'stripe', etc.
22
22
  * @param {String} params.entity - Logical entity identifier (e.g., 'Order', 'PlatformSubscription', 'Membership')
23
23
  * NOTE: This is NOT a database model name - it's just a logical identifier for categoryMappings
24
24
  * @param {String} params.monetizationType - Monetization type ('free', 'subscription', 'purchase')
@@ -35,6 +35,7 @@ export class SubscriptionService {
35
35
  * referenceId: subscription._id, // Links to entity
36
36
  * referenceModel: 'Subscription', // Model name
37
37
  * },
38
+ * gateway: 'bkash', // Any registered provider
38
39
  * amount: 1500,
39
40
  * // ...
40
41
  * });
@@ -66,7 +67,7 @@ export class SubscriptionService {
66
67
  *
67
68
  * @param {String} subscriptionId - Subscription ID
68
69
  * @param {Object} params - Renewal parameters
69
- * @param {String} params.gateway - Payment gateway to use (default: 'manual')
70
+ * @param {String} params.gateway - Payment gateway name (default: 'manual') - Use ANY registered provider name: 'manual', 'bkash', 'nagad', 'stripe', etc.
70
71
  * @param {String} params.entity - Logical entity identifier (optional, inherits from subscription)
71
72
  * @param {Object} params.paymentData - Payment method details
72
73
  * @param {Object} params.metadata - Additional metadata
@@ -22,13 +22,34 @@ export const PAYMENT_STATUS_VALUES = Object.values(PAYMENT_STATUS);
22
22
 
23
23
  // ============ PAYMENT GATEWAY TYPES ============
24
24
  /**
25
- * Gateway types that providers can be built for
25
+ * Common gateway type constants for convenience
26
26
  *
27
- * MANUAL: Built-in manual provider
28
- * STRIPE: Stripe provider (build with @classytic/revenue-stripe)
29
- * SSLCOMMERZ: SSLCommerz provider (build with @classytic/revenue-sslcommerz)
27
+ * ⚠️ IMPORTANT: These are NOT restrictions - just common reference values
30
28
  *
31
- * Users can register custom providers for any gateway type
29
+ * You can register ANY custom gateway provider by passing it to createRevenue():
30
+ *
31
+ * @example
32
+ * ```javascript
33
+ * const revenue = createRevenue({
34
+ * providers: {
35
+ * manual: new ManualProvider(),
36
+ * bkash: new BkashProvider(), // ✅ Custom gateway
37
+ * nagad: new NagadProvider(), // ✅ Custom gateway
38
+ * stripe: new StripeProvider(), // ✅ Custom gateway
39
+ * paypal: new PaypalProvider(), // ✅ Any gateway you want
40
+ * }
41
+ * });
42
+ *
43
+ * // Use by name
44
+ * await revenue.subscriptions.create({ gateway: 'bkash', ... });
45
+ * ```
46
+ *
47
+ * Reference values:
48
+ * - MANUAL: Built-in manual provider (@classytic/revenue-manual)
49
+ * - STRIPE: Stripe provider (build with @classytic/revenue-stripe)
50
+ * - SSLCOMMERZ: SSLCommerz provider (build with @classytic/revenue-sslcommerz)
51
+ *
52
+ * Add your own: bkash, nagad, rocket, paypal, razorpay, flutterwave, etc.
32
53
  */
33
54
  export const PAYMENT_GATEWAY_TYPE = {
34
55
  MANUAL: 'manual',
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @classytic/revenue
3
- * Enterprise Revenue Management System
3
+ * Revenue Management System
4
4
  *
5
5
  * A unified, enterprise-grade revenue management system combining
6
6
  * monetization (subscriptions, purchases, proration) and payment processing
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Thin, focused, production-ready library with smart defaults.
10
10
  *
11
- * @version 1.0.0
11
+ * @version 0.2.0
12
12
  * @author Classytic (Classytic)
13
13
  * @license MIT
14
14
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/revenue",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Enterprise revenue management system with subscriptions, purchases, proration, payment processing, escrow, and multi-party splits",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -83,12 +83,22 @@ export class PaymentService {
83
83
 
84
84
  // Update transaction as failed
85
85
  transaction.status = 'failed';
86
+ transaction.failureReason = error.message;
86
87
  transaction.metadata = {
87
88
  ...transaction.metadata,
88
89
  verificationError: error.message,
90
+ failedAt: new Date().toISOString(),
89
91
  };
90
92
  await transaction.save();
91
93
 
94
+ // Trigger payment.failed hook
95
+ this._triggerHook('payment.failed', {
96
+ transaction,
97
+ error: error.message,
98
+ provider: gatewayType,
99
+ paymentIntentId,
100
+ });
101
+
92
102
  throw new PaymentVerificationError(paymentIntentId, error.message);
93
103
  }
94
104
 
@@ -45,14 +45,14 @@ export class SubscriptionService {
45
45
  * @param {String} params.planKey - Plan key ('monthly', 'quarterly', 'yearly')
46
46
  * @param {Number} params.amount - Subscription amount
47
47
  * @param {String} params.currency - Currency code (default: 'BDT')
48
- * @param {String} params.gateway - Payment gateway to use (default: 'manual')
48
+ * @param {String} params.gateway - Payment gateway name (default: 'manual') - Use ANY registered provider name: 'manual', 'bkash', 'nagad', 'stripe', etc.
49
49
  * @param {String} params.entity - Logical entity identifier (e.g., 'Order', 'PlatformSubscription', 'Membership')
50
50
  * NOTE: This is NOT a database model name - it's just a logical identifier for categoryMappings
51
51
  * @param {String} params.monetizationType - Monetization type ('free', 'subscription', 'purchase')
52
52
  * @param {Object} params.paymentData - Payment method details
53
53
  * @param {Object} params.metadata - Additional metadata
54
54
  * @param {String} params.idempotencyKey - Idempotency key for duplicate prevention
55
- *
55
+ *
56
56
  * @example
57
57
  * // With polymorphic reference (recommended)
58
58
  * await revenue.subscriptions.create({
@@ -62,10 +62,11 @@ export class SubscriptionService {
62
62
  * referenceId: subscription._id, // Links to entity
63
63
  * referenceModel: 'Subscription', // Model name
64
64
  * },
65
+ * gateway: 'bkash', // Any registered provider
65
66
  * amount: 1500,
66
67
  * // ...
67
68
  * });
68
- *
69
+ *
69
70
  * @returns {Promise<Object>} { subscription, transaction, paymentIntent }
70
71
  */
71
72
  async create(params) {
@@ -204,13 +205,26 @@ export class SubscriptionService {
204
205
  subscription = await SubscriptionModel.create(subscriptionData);
205
206
  }
206
207
 
207
- // Trigger hook
208
- this._triggerHook('subscription.created', {
208
+ // Trigger hooks - emit specific event based on monetization type
209
+ const eventData = {
209
210
  subscription,
210
211
  transaction,
211
212
  paymentIntent,
212
213
  isFree,
213
- });
214
+ monetizationType,
215
+ };
216
+
217
+ // Emit specific monetization event
218
+ if (monetizationType === MONETIZATION_TYPES.PURCHASE) {
219
+ this._triggerHook('purchase.created', eventData);
220
+ } else if (monetizationType === MONETIZATION_TYPES.SUBSCRIPTION) {
221
+ this._triggerHook('subscription.created', eventData);
222
+ } else if (monetizationType === MONETIZATION_TYPES.FREE) {
223
+ this._triggerHook('free.created', eventData);
224
+ }
225
+
226
+ // Also emit generic event for backward compatibility
227
+ this._triggerHook('monetization.created', eventData);
214
228
 
215
229
  return {
216
230
  subscription,
@@ -271,7 +285,7 @@ export class SubscriptionService {
271
285
  *
272
286
  * @param {String} subscriptionId - Subscription ID
273
287
  * @param {Object} params - Renewal parameters
274
- * @param {String} params.gateway - Payment gateway to use (default: 'manual')
288
+ * @param {String} params.gateway - Payment gateway name (default: 'manual') - Use ANY registered provider name: 'manual', 'bkash', 'nagad', 'stripe', etc.
275
289
  * @param {String} params.entity - Logical entity identifier (optional, inherits from subscription)
276
290
  * @param {Object} params.paymentData - Payment method details
277
291
  * @param {Object} params.metadata - Additional metadata