@classytic/revenue 0.0.1
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/README.md +454 -0
- package/core/builder.js +170 -0
- package/core/container.js +119 -0
- package/core/errors.js +262 -0
- package/enums/index.js +70 -0
- package/enums/monetization.enums.js +15 -0
- package/enums/payment.enums.js +43 -0
- package/enums/subscription.enums.js +33 -0
- package/enums/transaction.enums.js +53 -0
- package/index.js +58 -0
- package/package.json +62 -0
- package/providers/base.js +162 -0
- package/providers/manual.js +171 -0
- package/revenue.d.ts +290 -0
- package/schemas/index.js +21 -0
- package/schemas/subscription/index.js +17 -0
- package/schemas/subscription/info.schema.js +115 -0
- package/schemas/subscription/plan.schema.js +48 -0
- package/schemas/transaction/common.schema.js +22 -0
- package/schemas/transaction/gateway.schema.js +69 -0
- package/schemas/transaction/index.js +20 -0
- package/schemas/transaction/payment.schema.js +110 -0
- package/services/payment.service.js +400 -0
- package/services/subscription.service.js +537 -0
- package/services/transaction.service.js +142 -0
- package/utils/hooks.js +44 -0
- package/utils/index.js +8 -0
- package/utils/logger.js +36 -0
- package/utils/transaction-type.js +254 -0
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@classytic/revenue",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Enterprise revenue management system with subscriptions, purchases, proration, and payment processing",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "revenue.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"revenue",
|
|
10
|
+
"monetization",
|
|
11
|
+
"subscription",
|
|
12
|
+
"payment",
|
|
13
|
+
"saas",
|
|
14
|
+
"billing",
|
|
15
|
+
"proration",
|
|
16
|
+
"recurring",
|
|
17
|
+
"gateway",
|
|
18
|
+
"webhook",
|
|
19
|
+
"stripe",
|
|
20
|
+
"sslcommerz",
|
|
21
|
+
"bkash",
|
|
22
|
+
"transaction",
|
|
23
|
+
"invoice"
|
|
24
|
+
],
|
|
25
|
+
"author": "Sadman Chowdhury",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/classytic/revenue"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/classytic/revenue/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/classytic/revenue#readme",
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"mongoose": "^8.0.0"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
41
|
+
"exports": {
|
|
42
|
+
".": "./index.js",
|
|
43
|
+
"./enums": "./enums/index.js",
|
|
44
|
+
"./schemas": "./schemas/index.js",
|
|
45
|
+
"./utils": "./utils/index.js"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"index.js",
|
|
49
|
+
"revenue.d.ts",
|
|
50
|
+
"LICENSE",
|
|
51
|
+
"README.md",
|
|
52
|
+
"core/",
|
|
53
|
+
"providers/",
|
|
54
|
+
"services/",
|
|
55
|
+
"enums/",
|
|
56
|
+
"schemas/",
|
|
57
|
+
"utils/"
|
|
58
|
+
],
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"nanoid": "^5.1.6"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment Provider Base Class
|
|
3
|
+
* @classytic/revenue
|
|
4
|
+
*
|
|
5
|
+
* Abstract base class for all payment providers
|
|
6
|
+
* Inspired by: Vercel AI SDK, Stripe SDK
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Payment Intent - standardized response from createIntent
|
|
11
|
+
*/
|
|
12
|
+
export class PaymentIntent {
|
|
13
|
+
constructor(data) {
|
|
14
|
+
this.id = data.id;
|
|
15
|
+
this.provider = data.provider;
|
|
16
|
+
this.status = data.status; // 'pending', 'processing', 'requires_action', 'succeeded', 'failed'
|
|
17
|
+
this.amount = data.amount;
|
|
18
|
+
this.currency = data.currency || 'BDT';
|
|
19
|
+
this.metadata = data.metadata || {};
|
|
20
|
+
|
|
21
|
+
// Provider-specific data
|
|
22
|
+
this.clientSecret = data.clientSecret; // For frontend (Stripe)
|
|
23
|
+
this.paymentUrl = data.paymentUrl; // For redirect (SSLCommerz)
|
|
24
|
+
this.instructions = data.instructions; // For manual
|
|
25
|
+
this.raw = data.raw; // Raw provider response
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Payment Result - standardized response from verifyPayment
|
|
31
|
+
*/
|
|
32
|
+
export class PaymentResult {
|
|
33
|
+
constructor(data) {
|
|
34
|
+
this.id = data.id;
|
|
35
|
+
this.provider = data.provider;
|
|
36
|
+
this.status = data.status; // 'succeeded', 'failed', 'processing'
|
|
37
|
+
this.amount = data.amount;
|
|
38
|
+
this.currency = data.currency || 'BDT';
|
|
39
|
+
this.paidAt = data.paidAt;
|
|
40
|
+
this.metadata = data.metadata || {};
|
|
41
|
+
this.raw = data.raw;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Refund Result - standardized response from refund
|
|
47
|
+
*/
|
|
48
|
+
export class RefundResult {
|
|
49
|
+
constructor(data) {
|
|
50
|
+
this.id = data.id;
|
|
51
|
+
this.provider = data.provider;
|
|
52
|
+
this.status = data.status; // 'succeeded', 'failed', 'processing'
|
|
53
|
+
this.amount = data.amount;
|
|
54
|
+
this.currency = data.currency || 'BDT';
|
|
55
|
+
this.refundedAt = data.refundedAt;
|
|
56
|
+
this.reason = data.reason;
|
|
57
|
+
this.metadata = data.metadata || {};
|
|
58
|
+
this.raw = data.raw;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Webhook Event - standardized webhook event
|
|
64
|
+
*/
|
|
65
|
+
export class WebhookEvent {
|
|
66
|
+
constructor(data) {
|
|
67
|
+
this.id = data.id;
|
|
68
|
+
this.provider = data.provider;
|
|
69
|
+
this.type = data.type; // 'payment.succeeded', 'payment.failed', 'refund.succeeded', etc.
|
|
70
|
+
this.data = data.data;
|
|
71
|
+
this.createdAt = data.createdAt;
|
|
72
|
+
this.raw = data.raw;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Base Payment Provider
|
|
78
|
+
* All payment providers must extend this class
|
|
79
|
+
*/
|
|
80
|
+
export class PaymentProvider {
|
|
81
|
+
constructor(config = {}) {
|
|
82
|
+
this.config = config;
|
|
83
|
+
this.name = 'base'; // Override in subclass
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Create a payment intent
|
|
88
|
+
* @param {Object} params - Payment parameters
|
|
89
|
+
* @param {number} params.amount - Amount in smallest currency unit
|
|
90
|
+
* @param {string} params.currency - Currency code
|
|
91
|
+
* @param {Object} params.metadata - Additional metadata
|
|
92
|
+
* @returns {Promise<PaymentIntent>}
|
|
93
|
+
*/
|
|
94
|
+
async createIntent(params) {
|
|
95
|
+
throw new Error(`${this.constructor.name}: createIntent() must be implemented`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Verify a payment
|
|
100
|
+
* @param {string} intentId - Payment intent ID
|
|
101
|
+
* @returns {Promise<PaymentResult>}
|
|
102
|
+
*/
|
|
103
|
+
async verifyPayment(intentId) {
|
|
104
|
+
throw new Error(`${this.constructor.name}: verifyPayment() must be implemented`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Get payment status
|
|
109
|
+
* @param {string} intentId - Payment intent ID
|
|
110
|
+
* @returns {Promise<PaymentResult>}
|
|
111
|
+
*/
|
|
112
|
+
async getStatus(intentId) {
|
|
113
|
+
throw new Error(`${this.constructor.name}: getStatus() must be implemented`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Refund a payment
|
|
118
|
+
* @param {string} paymentId - Payment ID
|
|
119
|
+
* @param {number} amount - Amount to refund (optional, full refund if not provided)
|
|
120
|
+
* @param {Object} options - Refund options
|
|
121
|
+
* @returns {Promise<RefundResult>}
|
|
122
|
+
*/
|
|
123
|
+
async refund(paymentId, amount, options = {}) {
|
|
124
|
+
throw new Error(`${this.constructor.name}: refund() must be implemented`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Handle webhook from provider
|
|
129
|
+
* @param {Object} payload - Webhook payload
|
|
130
|
+
* @param {Object} headers - Request headers (for signature verification)
|
|
131
|
+
* @returns {Promise<WebhookEvent>}
|
|
132
|
+
*/
|
|
133
|
+
async handleWebhook(payload, headers = {}) {
|
|
134
|
+
throw new Error(`${this.constructor.name}: handleWebhook() must be implemented`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Verify webhook signature (optional)
|
|
139
|
+
* @param {Object} payload - Webhook payload
|
|
140
|
+
* @param {string} signature - Webhook signature
|
|
141
|
+
* @returns {boolean}
|
|
142
|
+
*/
|
|
143
|
+
verifyWebhookSignature(payload, signature) {
|
|
144
|
+
// Override in subclass if provider supports webhook signatures
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Get provider capabilities
|
|
150
|
+
* @returns {Object}
|
|
151
|
+
*/
|
|
152
|
+
getCapabilities() {
|
|
153
|
+
return {
|
|
154
|
+
supportsWebhooks: false,
|
|
155
|
+
supportsRefunds: false,
|
|
156
|
+
supportsPartialRefunds: false,
|
|
157
|
+
requiresManualVerification: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export default PaymentProvider;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual Payment Provider
|
|
3
|
+
* @classytic/revenue
|
|
4
|
+
*
|
|
5
|
+
* Built-in provider for manual payment verification
|
|
6
|
+
* Perfect for: Cash, bank transfers, mobile money without API
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { PaymentProvider, PaymentIntent, PaymentResult, RefundResult } from './base.js';
|
|
10
|
+
import { nanoid } from 'nanoid';
|
|
11
|
+
|
|
12
|
+
export class ManualProvider extends PaymentProvider {
|
|
13
|
+
constructor(config = {}) {
|
|
14
|
+
super(config);
|
|
15
|
+
this.name = 'manual';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Create manual payment intent
|
|
20
|
+
* Returns instructions for manual payment
|
|
21
|
+
*/
|
|
22
|
+
async createIntent(params) {
|
|
23
|
+
const intentId = `manual_${nanoid(16)}`;
|
|
24
|
+
|
|
25
|
+
return new PaymentIntent({
|
|
26
|
+
id: intentId,
|
|
27
|
+
provider: 'manual',
|
|
28
|
+
status: 'pending',
|
|
29
|
+
amount: params.amount,
|
|
30
|
+
currency: params.currency || 'BDT',
|
|
31
|
+
metadata: params.metadata || {},
|
|
32
|
+
instructions: this._getPaymentInstructions(params),
|
|
33
|
+
raw: params,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Verify manual payment
|
|
39
|
+
* Note: This is called by admin after checking payment proof
|
|
40
|
+
*/
|
|
41
|
+
async verifyPayment(intentId) {
|
|
42
|
+
// Manual verification doesn't auto-verify
|
|
43
|
+
// Admin must explicitly call payment verification endpoint
|
|
44
|
+
return new PaymentResult({
|
|
45
|
+
id: intentId,
|
|
46
|
+
provider: 'manual',
|
|
47
|
+
status: 'requires_manual_approval',
|
|
48
|
+
amount: 0, // Amount will be filled by transaction
|
|
49
|
+
currency: 'BDT',
|
|
50
|
+
metadata: {
|
|
51
|
+
message: 'Manual payment requires admin verification',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get payment status
|
|
58
|
+
*/
|
|
59
|
+
async getStatus(intentId) {
|
|
60
|
+
return this.verifyPayment(intentId);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Refund manual payment
|
|
65
|
+
*/
|
|
66
|
+
async refund(paymentId, amount, options = {}) {
|
|
67
|
+
const refundId = `refund_${nanoid(16)}`;
|
|
68
|
+
|
|
69
|
+
return new RefundResult({
|
|
70
|
+
id: refundId,
|
|
71
|
+
provider: 'manual',
|
|
72
|
+
status: 'succeeded', // Manual refunds are immediately marked as succeeded
|
|
73
|
+
amount: amount,
|
|
74
|
+
currency: options.currency || 'BDT',
|
|
75
|
+
refundedAt: new Date(),
|
|
76
|
+
reason: options.reason || 'Manual refund',
|
|
77
|
+
metadata: options.metadata || {},
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Manual provider doesn't support webhooks
|
|
83
|
+
*/
|
|
84
|
+
async handleWebhook(payload, headers) {
|
|
85
|
+
throw new Error('Manual provider does not support webhooks');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Get provider capabilities
|
|
90
|
+
*/
|
|
91
|
+
getCapabilities() {
|
|
92
|
+
return {
|
|
93
|
+
supportsWebhooks: false,
|
|
94
|
+
supportsRefunds: true,
|
|
95
|
+
supportsPartialRefunds: true,
|
|
96
|
+
requiresManualVerification: true,
|
|
97
|
+
supportedMethods: ['cash', 'bank', 'bkash', 'nagad', 'rocket', 'manual'],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Generate payment instructions for customer
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
_getPaymentInstructions(params) {
|
|
106
|
+
const { organizationPaymentInfo, method } = params.metadata || {};
|
|
107
|
+
|
|
108
|
+
if (!organizationPaymentInfo) {
|
|
109
|
+
return 'Please contact the organization for payment details.';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const instructions = [];
|
|
113
|
+
|
|
114
|
+
// Add method-specific instructions
|
|
115
|
+
switch (method) {
|
|
116
|
+
case 'bkash':
|
|
117
|
+
case 'nagad':
|
|
118
|
+
case 'rocket':
|
|
119
|
+
if (organizationPaymentInfo[`${method}Number`]) {
|
|
120
|
+
instructions.push(
|
|
121
|
+
`Send money via ${method.toUpperCase()}:`,
|
|
122
|
+
`Number: ${organizationPaymentInfo[`${method}Number`]}`,
|
|
123
|
+
`Amount: ${params.amount} ${params.currency || 'BDT'}`,
|
|
124
|
+
``,
|
|
125
|
+
`After payment, provide the transaction ID/reference number.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
|
|
130
|
+
case 'bank':
|
|
131
|
+
if (organizationPaymentInfo.bankAccount) {
|
|
132
|
+
const bank = organizationPaymentInfo.bankAccount;
|
|
133
|
+
instructions.push(
|
|
134
|
+
`Bank Transfer Details:`,
|
|
135
|
+
`Bank: ${bank.bankName || 'N/A'}`,
|
|
136
|
+
`Account: ${bank.accountNumber || 'N/A'}`,
|
|
137
|
+
`Account Name: ${bank.accountName || 'N/A'}`,
|
|
138
|
+
`Amount: ${params.amount} ${params.currency || 'BDT'}`,
|
|
139
|
+
``,
|
|
140
|
+
`After payment, upload proof and provide reference.`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
|
|
145
|
+
case 'cash':
|
|
146
|
+
instructions.push(
|
|
147
|
+
`Cash Payment:`,
|
|
148
|
+
`Amount: ${params.amount} ${params.currency || 'BDT'}`,
|
|
149
|
+
``,
|
|
150
|
+
`Pay at the organization's office and get a receipt.`
|
|
151
|
+
);
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
default:
|
|
155
|
+
instructions.push(
|
|
156
|
+
`Payment Amount: ${params.amount} ${params.currency || 'BDT'}`,
|
|
157
|
+
``,
|
|
158
|
+
`Contact the organization for payment details.`
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Add custom instructions if provided
|
|
163
|
+
if (organizationPaymentInfo.paymentInstructions) {
|
|
164
|
+
instructions.push(``, `Additional Instructions:`, organizationPaymentInfo.paymentInstructions);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return instructions.join('\n');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export default ManualProvider;
|
package/revenue.d.ts
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript definitions for @classytic/revenue
|
|
3
|
+
* Enterprise Revenue Management System
|
|
4
|
+
*
|
|
5
|
+
* Thin, focused, production-ready library with smart defaults.
|
|
6
|
+
*
|
|
7
|
+
* @version 1.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Schema, Model, Document } from 'mongoose';
|
|
11
|
+
|
|
12
|
+
// ============ CORE API ============
|
|
13
|
+
|
|
14
|
+
// Container
|
|
15
|
+
export class Container {
|
|
16
|
+
register(name: string, implementation: any, options?: { singleton?: boolean; factory?: boolean }): this;
|
|
17
|
+
singleton(name: string, implementation: any): this;
|
|
18
|
+
transient(name: string, factory: Function): this;
|
|
19
|
+
get(name: string): any;
|
|
20
|
+
has(name: string): boolean;
|
|
21
|
+
keys(): string[];
|
|
22
|
+
clear(): void;
|
|
23
|
+
createScope(): Container;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Provider System
|
|
27
|
+
export interface PaymentIntentParams {
|
|
28
|
+
amount: number;
|
|
29
|
+
currency?: string;
|
|
30
|
+
metadata?: Record<string, any>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class PaymentIntent {
|
|
34
|
+
id: string;
|
|
35
|
+
provider: string;
|
|
36
|
+
status: string;
|
|
37
|
+
amount: number;
|
|
38
|
+
currency: string;
|
|
39
|
+
metadata: Record<string, any>;
|
|
40
|
+
clientSecret?: string;
|
|
41
|
+
paymentUrl?: string;
|
|
42
|
+
instructions?: string;
|
|
43
|
+
raw?: any;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class PaymentResult {
|
|
47
|
+
id: string;
|
|
48
|
+
provider: string;
|
|
49
|
+
status: string;
|
|
50
|
+
amount: number;
|
|
51
|
+
currency: string;
|
|
52
|
+
paidAt?: Date;
|
|
53
|
+
metadata: Record<string, any>;
|
|
54
|
+
raw?: any;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class RefundResult {
|
|
58
|
+
id: string;
|
|
59
|
+
provider: string;
|
|
60
|
+
status: string;
|
|
61
|
+
amount: number;
|
|
62
|
+
currency: string;
|
|
63
|
+
refundedAt?: Date;
|
|
64
|
+
reason?: string;
|
|
65
|
+
metadata: Record<string, any>;
|
|
66
|
+
raw?: any;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class WebhookEvent {
|
|
70
|
+
id: string;
|
|
71
|
+
provider: string;
|
|
72
|
+
type: string;
|
|
73
|
+
data: any;
|
|
74
|
+
createdAt: Date;
|
|
75
|
+
raw?: any;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export abstract class PaymentProvider {
|
|
79
|
+
name: string;
|
|
80
|
+
config: any;
|
|
81
|
+
|
|
82
|
+
createIntent(params: PaymentIntentParams): Promise<PaymentIntent>;
|
|
83
|
+
verifyPayment(intentId: string): Promise<PaymentResult>;
|
|
84
|
+
getStatus(intentId: string): Promise<PaymentResult>;
|
|
85
|
+
refund(paymentId: string, amount?: number, options?: any): Promise<RefundResult>;
|
|
86
|
+
handleWebhook(payload: any, headers?: any): Promise<WebhookEvent>;
|
|
87
|
+
verifyWebhookSignature(payload: any, signature: string): boolean;
|
|
88
|
+
getCapabilities(): {
|
|
89
|
+
supportsWebhooks: boolean;
|
|
90
|
+
supportsRefunds: boolean;
|
|
91
|
+
supportsPartialRefunds: boolean;
|
|
92
|
+
requiresManualVerification: boolean;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Note: ManualProvider moved to @classytic/revenue-manual (separate package)
|
|
97
|
+
|
|
98
|
+
// Services
|
|
99
|
+
export class SubscriptionService {
|
|
100
|
+
constructor(container: Container);
|
|
101
|
+
|
|
102
|
+
create(params: {
|
|
103
|
+
data: any;
|
|
104
|
+
planKey: string;
|
|
105
|
+
amount: number;
|
|
106
|
+
currency?: string;
|
|
107
|
+
gateway?: string;
|
|
108
|
+
paymentData?: any;
|
|
109
|
+
metadata?: Record<string, any>;
|
|
110
|
+
idempotencyKey?: string;
|
|
111
|
+
}): Promise<{ subscription: any; transaction: any; paymentIntent: PaymentIntent | null }>;
|
|
112
|
+
|
|
113
|
+
activate(subscriptionId: string, options?: { timestamp?: Date }): Promise<any>;
|
|
114
|
+
renew(subscriptionId: string, params?: any): Promise<{ subscription: any; transaction: any; paymentIntent: PaymentIntent }>;
|
|
115
|
+
cancel(subscriptionId: string, options?: { immediate?: boolean; reason?: string }): Promise<any>;
|
|
116
|
+
pause(subscriptionId: string, options?: { reason?: string }): Promise<any>;
|
|
117
|
+
resume(subscriptionId: string, options?: { extendPeriod?: boolean }): Promise<any>;
|
|
118
|
+
list(filters?: any, options?: any): Promise<any[]>;
|
|
119
|
+
get(subscriptionId: string): Promise<any>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export class PaymentService {
|
|
123
|
+
constructor(container: Container);
|
|
124
|
+
|
|
125
|
+
verify(paymentIntentId: string, options?: { verifiedBy?: string }): Promise<{ transaction: any; paymentResult: PaymentResult; status: string }>;
|
|
126
|
+
getStatus(paymentIntentId: string): Promise<{ transaction: any; paymentResult: PaymentResult; status: string; provider: string }>;
|
|
127
|
+
refund(paymentId: string, amount?: number, options?: { reason?: string }): Promise<{ transaction: any; refundResult: RefundResult; status: string }>;
|
|
128
|
+
handleWebhook(providerName: string, payload: any, headers?: any): Promise<{ event: WebhookEvent; transaction: any; status: string }>;
|
|
129
|
+
list(filters?: any, options?: any): Promise<any[]>;
|
|
130
|
+
get(transactionId: string): Promise<any>;
|
|
131
|
+
getProvider(providerName: string): PaymentProvider;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export class TransactionService {
|
|
135
|
+
constructor(container: Container);
|
|
136
|
+
|
|
137
|
+
get(transactionId: string): Promise<any>;
|
|
138
|
+
list(filters?: any, options?: any): Promise<{ transactions: any[]; total: number; page: number; limit: number; pages: number }>;
|
|
139
|
+
update(transactionId: string, updates: any): Promise<any>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Error Classes
|
|
143
|
+
export class RevenueError extends Error {
|
|
144
|
+
code: string;
|
|
145
|
+
retryable: boolean;
|
|
146
|
+
metadata: Record<string, any>;
|
|
147
|
+
toJSON(): { name: string; message: string; code: string; retryable: boolean; metadata: Record<string, any> };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export class ConfigurationError extends RevenueError {}
|
|
151
|
+
export class ModelNotRegisteredError extends ConfigurationError {}
|
|
152
|
+
export class ProviderError extends RevenueError {}
|
|
153
|
+
export class ProviderNotFoundError extends ProviderError {}
|
|
154
|
+
export class ProviderCapabilityError extends ProviderError {}
|
|
155
|
+
export class PaymentIntentCreationError extends ProviderError {}
|
|
156
|
+
export class PaymentVerificationError extends ProviderError {}
|
|
157
|
+
export class NotFoundError extends RevenueError {}
|
|
158
|
+
export class SubscriptionNotFoundError extends NotFoundError {}
|
|
159
|
+
export class TransactionNotFoundError extends NotFoundError {}
|
|
160
|
+
export class ValidationError extends RevenueError {}
|
|
161
|
+
export class InvalidAmountError extends ValidationError {}
|
|
162
|
+
export class MissingRequiredFieldError extends ValidationError {}
|
|
163
|
+
export class StateError extends RevenueError {}
|
|
164
|
+
export class AlreadyVerifiedError extends StateError {}
|
|
165
|
+
export class InvalidStateTransitionError extends StateError {}
|
|
166
|
+
export class SubscriptionNotActiveError extends StateError {}
|
|
167
|
+
export class OperationError extends RevenueError {}
|
|
168
|
+
export class RefundNotSupportedError extends OperationError {}
|
|
169
|
+
export class RefundError extends OperationError {}
|
|
170
|
+
|
|
171
|
+
export function isRetryable(error: Error): boolean;
|
|
172
|
+
export function isRevenueError(error: Error): boolean;
|
|
173
|
+
|
|
174
|
+
// Revenue Instance (Immutable)
|
|
175
|
+
export interface Revenue {
|
|
176
|
+
readonly container: Container;
|
|
177
|
+
readonly providers: Readonly<Record<string, PaymentProvider>>;
|
|
178
|
+
readonly config: Readonly<any>;
|
|
179
|
+
|
|
180
|
+
readonly subscriptions: SubscriptionService;
|
|
181
|
+
readonly payments: PaymentService;
|
|
182
|
+
readonly transactions: TransactionService;
|
|
183
|
+
|
|
184
|
+
getProvider(name: string): PaymentProvider;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface RevenueOptions {
|
|
188
|
+
models: {
|
|
189
|
+
Transaction: Model<any>;
|
|
190
|
+
Subscription?: Model<any>;
|
|
191
|
+
[key: string]: Model<any> | undefined;
|
|
192
|
+
};
|
|
193
|
+
providers?: Record<string, PaymentProvider>;
|
|
194
|
+
hooks?: Record<string, Function[]>;
|
|
195
|
+
config?: {
|
|
196
|
+
targetModels?: string[];
|
|
197
|
+
categoryMappings?: Record<string, string>;
|
|
198
|
+
[key: string]: any;
|
|
199
|
+
};
|
|
200
|
+
logger?: Console | any;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function createRevenue(options: RevenueOptions): Revenue;
|
|
204
|
+
|
|
205
|
+
// ============ ENUMS ============
|
|
206
|
+
|
|
207
|
+
export const TRANSACTION_STATUS: {
|
|
208
|
+
PENDING: 'pending';
|
|
209
|
+
PAYMENT_INITIATED: 'payment_initiated';
|
|
210
|
+
PROCESSING: 'processing';
|
|
211
|
+
REQUIRES_ACTION: 'requires_action';
|
|
212
|
+
VERIFIED: 'verified';
|
|
213
|
+
COMPLETED: 'completed';
|
|
214
|
+
FAILED: 'failed';
|
|
215
|
+
CANCELLED: 'cancelled';
|
|
216
|
+
EXPIRED: 'expired';
|
|
217
|
+
REFUNDED: 'refunded';
|
|
218
|
+
PARTIALLY_REFUNDED: 'partially_refunded';
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
export const TRANSACTION_TYPES: {
|
|
222
|
+
INCOME: 'income';
|
|
223
|
+
EXPENSE: 'expense';
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// Note: PAYMENT_METHOD removed - users define their own payment methods
|
|
227
|
+
|
|
228
|
+
export const PAYMENT_GATEWAY_TYPE: {
|
|
229
|
+
MANUAL: 'manual';
|
|
230
|
+
STRIPE: 'stripe';
|
|
231
|
+
SSLCOMMERZ: 'sslcommerz';
|
|
232
|
+
BKASH_GATEWAY: 'bkash_gateway';
|
|
233
|
+
NAGAD_GATEWAY: 'nagad_gateway';
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export const SUBSCRIPTION_STATUS: {
|
|
237
|
+
ACTIVE: 'active';
|
|
238
|
+
PAUSED: 'paused';
|
|
239
|
+
CANCELLED: 'cancelled';
|
|
240
|
+
EXPIRED: 'expired';
|
|
241
|
+
PENDING: 'pending';
|
|
242
|
+
INACTIVE: 'inactive';
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
export const PLAN_KEYS: {
|
|
246
|
+
MONTHLY: 'monthly';
|
|
247
|
+
QUARTERLY: 'quarterly';
|
|
248
|
+
YEARLY: 'yearly';
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
export const MONETIZATION_TYPES: {
|
|
252
|
+
FREE: 'free';
|
|
253
|
+
PURCHASE: 'purchase';
|
|
254
|
+
SUBSCRIPTION: 'subscription';
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// ============ SCHEMAS ============
|
|
258
|
+
|
|
259
|
+
export const currentPaymentSchema: Schema;
|
|
260
|
+
export const paymentSummarySchema: Schema;
|
|
261
|
+
export const subscriptionInfoSchema: Schema;
|
|
262
|
+
export const subscriptionPlanSchema: Schema;
|
|
263
|
+
export const gatewaySchema: Schema;
|
|
264
|
+
export const commissionSchema: Schema;
|
|
265
|
+
export const paymentDetailsSchema: Schema;
|
|
266
|
+
export const tenantSnapshotSchema: Schema;
|
|
267
|
+
export const timelineEventSchema: Schema;
|
|
268
|
+
export const customerInfoSchema: Schema;
|
|
269
|
+
export const customDiscountSchema: Schema;
|
|
270
|
+
export const stripeAccountSchema: Schema;
|
|
271
|
+
export const sslcommerzAccountSchema: Schema;
|
|
272
|
+
export const bkashMerchantSchema: Schema;
|
|
273
|
+
export const bankAccountSchema: Schema;
|
|
274
|
+
export const walletSchema: Schema;
|
|
275
|
+
|
|
276
|
+
// ============ UTILITIES ============
|
|
277
|
+
|
|
278
|
+
export const logger: Console | any;
|
|
279
|
+
export function setLogger(logger: Console | any): void;
|
|
280
|
+
|
|
281
|
+
// ============ DEFAULT EXPORT ============
|
|
282
|
+
|
|
283
|
+
declare const _default: {
|
|
284
|
+
createRevenue: typeof createRevenue;
|
|
285
|
+
PaymentProvider: typeof PaymentProvider;
|
|
286
|
+
RevenueError: typeof RevenueError;
|
|
287
|
+
Container: typeof Container;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
export default _default;
|
package/schemas/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema Index
|
|
3
|
+
* @classytic/revenue
|
|
4
|
+
*
|
|
5
|
+
* Core schemas for injection into your models
|
|
6
|
+
*
|
|
7
|
+
* Note: Enums are separate. Import them from '@classytic/revenue/enums'
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Re-export core schemas only
|
|
11
|
+
export * from './transaction/index.js';
|
|
12
|
+
export * from './subscription/index.js';
|
|
13
|
+
|
|
14
|
+
// Default export with core schemas
|
|
15
|
+
import transactionSchemas from './transaction/index.js';
|
|
16
|
+
import subscriptionSchemas from './subscription/index.js';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
...transactionSchemas,
|
|
20
|
+
...subscriptionSchemas,
|
|
21
|
+
};
|