@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,267 @@
1
+ import { R as RevenuePlugin } from '../../plugin-Bb9HOE10.js';
2
+ export { d as definePlugin } from '../../plugin-Bb9HOE10.js';
3
+ import { T as TaxConfig } from '../../tax-CV8A0sxl.js';
4
+ import '../../core/events.js';
5
+ import '../../index-cLJBLUvx.js';
6
+ import 'mongoose';
7
+ import '@classytic/shared-types';
8
+ import '../../providers/index.js';
9
+ import '../../settlement.schema-CpamV7ZY.js';
10
+ import '../../split.enums-DG3TxQf9.js';
11
+
12
+ /**
13
+ * Logging Plugin
14
+ * @classytic/revenue
15
+ *
16
+ * Logs all revenue operations at specified log level
17
+ */
18
+
19
+ /**
20
+ * Logging plugin options
21
+ */
22
+ interface LoggingPluginOptions {
23
+ /** Log level: 'debug' or 'info' */
24
+ level?: 'debug' | 'info';
25
+ }
26
+ /**
27
+ * Logging plugin - logs all operations
28
+ *
29
+ * Logs payment creation, verification, and refund operations
30
+ *
31
+ * @param options - Plugin options
32
+ * @returns Logging plugin
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * import { Revenue } from '@classytic/revenue';
37
+ * import { loggingPlugin } from '@classytic/revenue/plugins';
38
+ *
39
+ * const revenue = Revenue
40
+ * .create()
41
+ * .withPlugin(loggingPlugin({ level: 'debug' }))
42
+ * .build();
43
+ * ```
44
+ */
45
+ declare function loggingPlugin(options?: LoggingPluginOptions): RevenuePlugin;
46
+
47
+ /**
48
+ * Audit Plugin
49
+ * @classytic/revenue
50
+ *
51
+ * Records all operations for compliance and audit trails
52
+ */
53
+
54
+ /**
55
+ * Audit entry record
56
+ */
57
+ interface AuditEntry {
58
+ action: string;
59
+ requestId: string;
60
+ timestamp: Date;
61
+ input: Record<string, unknown>;
62
+ output: Record<string, unknown>;
63
+ idempotencyKey?: string;
64
+ }
65
+ /**
66
+ * Audit plugin options
67
+ */
68
+ interface AuditPluginOptions {
69
+ /** Custom storage function for audit entries */
70
+ store?: (entry: AuditEntry) => Promise<void>;
71
+ }
72
+ /**
73
+ * Audit plugin - records all operations for compliance
74
+ *
75
+ * Records payment creation, refunds, and other operations with sanitized data
76
+ *
77
+ * @param options - Plugin options
78
+ * @returns Audit plugin
79
+ *
80
+ * @example
81
+ * ```typescript
82
+ * import { Revenue } from '@classytic/revenue';
83
+ * import { auditPlugin } from '@classytic/revenue/plugins';
84
+ *
85
+ * const revenue = Revenue
86
+ * .create()
87
+ * .withPlugin(auditPlugin({
88
+ * store: async (entry) => {
89
+ * await AuditLog.create(entry);
90
+ * }
91
+ * }))
92
+ * .build();
93
+ * ```
94
+ */
95
+ declare function auditPlugin(options?: AuditPluginOptions): RevenuePlugin;
96
+
97
+ /**
98
+ * Metrics Plugin
99
+ * @classytic/revenue
100
+ *
101
+ * Collects operation metrics (duration, success/failure)
102
+ */
103
+
104
+ /**
105
+ * Metric record
106
+ */
107
+ interface Metric {
108
+ name: string;
109
+ duration: number;
110
+ success: boolean;
111
+ error?: string;
112
+ [key: string]: unknown;
113
+ }
114
+ /**
115
+ * Metrics plugin options
116
+ */
117
+ interface MetricsPluginOptions {
118
+ /** Callback for each metric */
119
+ onMetric?: (metric: Metric) => void;
120
+ }
121
+ /**
122
+ * Metrics plugin - collects operation metrics
123
+ *
124
+ * Tracks duration and success/failure of operations
125
+ *
126
+ * @param options - Plugin options
127
+ * @returns Metrics plugin
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * import { Revenue } from '@classytic/revenue';
132
+ * import { metricsPlugin } from '@classytic/revenue/plugins';
133
+ *
134
+ * const revenue = Revenue
135
+ * .create()
136
+ * .withPlugin(metricsPlugin({
137
+ * onMetric: (metric) => {
138
+ * // Send to Datadog, Prometheus, etc.
139
+ * statsd.timing(metric.name, metric.duration);
140
+ * if (!metric.success) {
141
+ * statsd.increment(`${metric.name}.error`);
142
+ * }
143
+ * }
144
+ * }))
145
+ * .build();
146
+ * ```
147
+ */
148
+ declare function metricsPlugin(options?: MetricsPluginOptions): RevenuePlugin;
149
+
150
+ /**
151
+ * Tax Plugin Options
152
+ */
153
+ interface TaxPluginOptions {
154
+ /**
155
+ * Function to get tax configuration for an organization
156
+ * Apps implement this to return jurisdiction-specific config
157
+ *
158
+ * @param orgId - Organization ID
159
+ * @returns Tax configuration or null if not registered
160
+ *
161
+ * @example
162
+ * ```typescript
163
+ * getTaxConfig: async (orgId) => {
164
+ * const org = await Organization.findById(orgId);
165
+ * if (!org) return null;
166
+ *
167
+ * return {
168
+ * isRegistered: org.country === 'AU',
169
+ * defaultRate: org.country === 'AU' ? 0.10 : 0, // 10% GST in Australia
170
+ * pricesIncludeTax: org.pricesIncludeTax || false,
171
+ * exemptCategories: ['education', 'medical'],
172
+ * };
173
+ * }
174
+ * ```
175
+ */
176
+ getTaxConfig: (orgId: string) => Promise<TaxConfig | null>;
177
+ /**
178
+ * Category mappings for resolving transaction categories
179
+ * Maps entity names to category strings
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * {
184
+ * Order: 'order_subscription',
185
+ * PlatformSubscription: 'platform_subscription',
186
+ * Membership: 'gym_membership',
187
+ * }
188
+ * ```
189
+ */
190
+ categoryMappings?: Record<string, string>;
191
+ /**
192
+ * Categories that represent income (vs expense)
193
+ * Used to determine tax type: 'collected' vs 'paid'
194
+ *
195
+ * Default: ['subscription', 'purchase', 'course_enrollment']
196
+ */
197
+ incomeCategories?: string[];
198
+ }
199
+ /**
200
+ * Create Tax Plugin
201
+ *
202
+ * Automatically calculates and applies tax to transactions during monetization.create()
203
+ *
204
+ * @param options - Plugin options
205
+ * @returns Tax plugin
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * import { Revenue } from '@classytic/revenue';
210
+ * import { createTaxPlugin } from '@classytic/revenue/plugins';
211
+ *
212
+ * const revenue = Revenue
213
+ * .create({ defaultCurrency: 'USD' })
214
+ * .withModels({ Transaction, Subscription })
215
+ * .withProvider('stripe', stripeProvider)
216
+ * .withPlugin(createTaxPlugin({
217
+ * getTaxConfig: async (orgId) => {
218
+ * const org = await Organization.findById(orgId);
219
+ * return {
220
+ * isRegistered: true,
221
+ * defaultRate: 0.15, // 15% tax
222
+ * pricesIncludeTax: false,
223
+ * exemptCategories: ['education'],
224
+ * };
225
+ * },
226
+ * categoryMappings: {
227
+ * Order: 'order_subscription',
228
+ * Membership: 'gym_membership',
229
+ * },
230
+ * }))
231
+ * .build();
232
+ *
233
+ * // Tax is now automatically calculated
234
+ * await revenue.monetization.create({
235
+ * data: { organizationId: 'org_123', customerId: 'cust_456' },
236
+ * planKey: 'monthly',
237
+ * amount: 10000, // $100
238
+ * entity: 'Order',
239
+ * monetizationType: 'subscription',
240
+ * });
241
+ * // → Creates transaction with tax: {
242
+ * // isApplicable: true,
243
+ * // rate: 0.15,
244
+ * // baseAmount: 10000,
245
+ * // taxAmount: 1500,
246
+ * // totalAmount: 11500,
247
+ * // type: 'collected'
248
+ * // }
249
+ * ```
250
+ */
251
+ declare function createTaxPlugin(options: TaxPluginOptions): RevenuePlugin;
252
+
253
+ /**
254
+ * Built-in Plugins
255
+ * @classytic/revenue/plugins
256
+ *
257
+ * Collection of built-in plugins for common use cases
258
+ */
259
+
260
+ declare const _default: {
261
+ loggingPlugin: typeof loggingPlugin;
262
+ auditPlugin: typeof auditPlugin;
263
+ metricsPlugin: typeof metricsPlugin;
264
+ createTaxPlugin: typeof createTaxPlugin;
265
+ };
266
+
267
+ export { type AuditEntry, type AuditPluginOptions, type LoggingPluginOptions, type Metric, type MetricsPluginOptions, type TaxPluginOptions, auditPlugin, createTaxPlugin, _default as default, loggingPlugin, metricsPlugin };
@@ -0,0 +1,292 @@
1
+ // @classytic/revenue - Enterprise Revenue Management System
2
+
3
+ // src/core/plugin.ts
4
+ function definePlugin(plugin) {
5
+ return plugin;
6
+ }
7
+
8
+ // src/infrastructure/plugins/business/logging.plugin.ts
9
+ function loggingPlugin(options = {}) {
10
+ const level = options.level ?? "info";
11
+ return definePlugin({
12
+ name: "logging",
13
+ version: "1.0.0",
14
+ description: "Logs all revenue operations",
15
+ hooks: {
16
+ "payment.create.after": async (ctx, input, next) => {
17
+ ctx.logger[level]("Creating payment", { amount: input.amount, currency: input.currency });
18
+ const result = await next();
19
+ ctx.logger[level]("Payment created", { paymentIntentId: result?.paymentIntentId });
20
+ return result;
21
+ },
22
+ "payment.verify.after": async (ctx, input, next) => {
23
+ ctx.logger[level]("Verifying payment", { id: input.id });
24
+ const result = await next();
25
+ ctx.logger[level]("Payment verified", { verified: result?.verified });
26
+ return result;
27
+ },
28
+ "payment.refund.after": async (ctx, input, next) => {
29
+ ctx.logger[level]("Processing refund", { transactionId: input.transactionId, amount: input.amount });
30
+ const result = await next();
31
+ ctx.logger[level]("Refund processed", { refundId: result?.refundId });
32
+ return result;
33
+ }
34
+ }
35
+ });
36
+ }
37
+
38
+ // src/infrastructure/plugins/business/audit.plugin.ts
39
+ function sanitizeInput(input) {
40
+ if (typeof input !== "object" || !input) return {};
41
+ const sanitized = { ...input };
42
+ delete sanitized.apiKey;
43
+ delete sanitized.secretKey;
44
+ delete sanitized.password;
45
+ return sanitized;
46
+ }
47
+ function sanitizeOutput(output) {
48
+ if (typeof output !== "object" || !output) return {};
49
+ return { ...output };
50
+ }
51
+ function auditPlugin(options = {}) {
52
+ const store = options.store ?? (async (entry) => {
53
+ });
54
+ return definePlugin({
55
+ name: "audit",
56
+ version: "1.0.0",
57
+ description: "Audit trail for all operations",
58
+ hooks: {
59
+ "payment.create.after": async (ctx, input, next) => {
60
+ const result = await next();
61
+ await store({
62
+ action: "payment.create",
63
+ requestId: ctx.meta.requestId,
64
+ timestamp: ctx.meta.timestamp,
65
+ input: sanitizeInput(input),
66
+ output: sanitizeOutput(result),
67
+ idempotencyKey: ctx.meta.idempotencyKey
68
+ });
69
+ return result;
70
+ },
71
+ "payment.refund.after": async (ctx, input, next) => {
72
+ const result = await next();
73
+ await store({
74
+ action: "payment.refund",
75
+ requestId: ctx.meta.requestId,
76
+ timestamp: ctx.meta.timestamp,
77
+ input: sanitizeInput(input),
78
+ output: sanitizeOutput(result),
79
+ idempotencyKey: ctx.meta.idempotencyKey
80
+ });
81
+ return result;
82
+ }
83
+ }
84
+ });
85
+ }
86
+
87
+ // src/infrastructure/plugins/business/metrics.plugin.ts
88
+ function metricsPlugin(options = {}) {
89
+ const record = options.onMetric ?? ((metric) => {
90
+ });
91
+ return definePlugin({
92
+ name: "metrics",
93
+ version: "1.0.0",
94
+ description: "Collects operation metrics",
95
+ hooks: {
96
+ "payment.create.before": async (_ctx, input, next) => {
97
+ const start = Date.now();
98
+ try {
99
+ const result = await next();
100
+ record({
101
+ name: "payment.create",
102
+ duration: Date.now() - start,
103
+ success: true,
104
+ amount: input.amount,
105
+ currency: input.currency
106
+ });
107
+ return result;
108
+ } catch (error) {
109
+ record({
110
+ name: "payment.create",
111
+ duration: Date.now() - start,
112
+ success: false,
113
+ error: error.message
114
+ });
115
+ throw error;
116
+ }
117
+ }
118
+ }
119
+ });
120
+ }
121
+
122
+ // src/shared/utils/calculators/tax.ts
123
+ function calculateTax(amount, category, config) {
124
+ if (!config?.isRegistered || config.exemptCategories?.includes(category)) {
125
+ return {
126
+ isApplicable: false,
127
+ rate: 0,
128
+ baseAmount: amount,
129
+ taxAmount: 0,
130
+ totalAmount: amount,
131
+ pricesIncludeTax: false
132
+ };
133
+ }
134
+ const rate = config.defaultRate;
135
+ const [baseAmount, taxAmount, totalAmount] = config.pricesIncludeTax ? [
136
+ // Tax-inclusive: extract tax from total
137
+ Math.round(amount / (1 + rate)),
138
+ // baseAmount
139
+ Math.round(amount - amount / (1 + rate)),
140
+ // taxAmount
141
+ amount
142
+ // totalAmount (already integer)
143
+ ] : [
144
+ // Tax-exclusive: add tax to base
145
+ amount,
146
+ // baseAmount (already integer)
147
+ Math.round(amount * rate),
148
+ // taxAmount
149
+ Math.round(amount * (1 + rate))
150
+ // totalAmount
151
+ ];
152
+ return {
153
+ isApplicable: true,
154
+ rate,
155
+ baseAmount,
156
+ taxAmount,
157
+ totalAmount,
158
+ pricesIncludeTax: config.pricesIncludeTax
159
+ };
160
+ }
161
+ function getTaxType(transactionFlow, category, exemptCategories = []) {
162
+ if (exemptCategories.includes(category)) {
163
+ return "exempt";
164
+ }
165
+ return transactionFlow === "inflow" ? "collected" : "paid";
166
+ }
167
+
168
+ // src/enums/transaction.enums.ts
169
+ var TRANSACTION_FLOW = {
170
+ INFLOW: "inflow",
171
+ OUTFLOW: "outflow"
172
+ };
173
+ var TRANSACTION_FLOW_VALUES = Object.values(
174
+ TRANSACTION_FLOW
175
+ );
176
+ var TRANSACTION_STATUS = {
177
+ PENDING: "pending",
178
+ PAYMENT_INITIATED: "payment_initiated",
179
+ PROCESSING: "processing",
180
+ REQUIRES_ACTION: "requires_action",
181
+ VERIFIED: "verified",
182
+ COMPLETED: "completed",
183
+ FAILED: "failed",
184
+ CANCELLED: "cancelled",
185
+ EXPIRED: "expired",
186
+ REFUNDED: "refunded",
187
+ PARTIALLY_REFUNDED: "partially_refunded"
188
+ };
189
+ var TRANSACTION_STATUS_VALUES = Object.values(
190
+ TRANSACTION_STATUS
191
+ );
192
+ var LIBRARY_CATEGORIES = {
193
+ SUBSCRIPTION: "subscription",
194
+ PURCHASE: "purchase"
195
+ };
196
+ var LIBRARY_CATEGORY_VALUES = Object.values(
197
+ LIBRARY_CATEGORIES
198
+ );
199
+ new Set(TRANSACTION_FLOW_VALUES);
200
+ new Set(
201
+ TRANSACTION_STATUS_VALUES
202
+ );
203
+ new Set(LIBRARY_CATEGORY_VALUES);
204
+
205
+ // src/shared/utils/validators/category-resolver.ts
206
+ function resolveCategory(entity, monetizationType, categoryMappings = {}) {
207
+ if (entity && categoryMappings[entity]) {
208
+ return categoryMappings[entity];
209
+ }
210
+ switch (monetizationType) {
211
+ case "subscription":
212
+ return LIBRARY_CATEGORIES.SUBSCRIPTION;
213
+ // 'subscription'
214
+ case "purchase":
215
+ return LIBRARY_CATEGORIES.PURCHASE;
216
+ // 'purchase'
217
+ default:
218
+ return LIBRARY_CATEGORIES.SUBSCRIPTION;
219
+ }
220
+ }
221
+
222
+ // src/infrastructure/plugins/business/tax.plugin.ts
223
+ function createTaxPlugin(options) {
224
+ const {
225
+ getTaxConfig,
226
+ categoryMappings = {},
227
+ incomeCategories = ["subscription", "purchase", "course_enrollment", "product_order"]
228
+ } = options;
229
+ return definePlugin({
230
+ name: "tax",
231
+ version: "1.0.0",
232
+ description: "Automatic tax calculation for transactions",
233
+ hooks: {
234
+ /**
235
+ * Calculate tax before monetization creation
236
+ * Injects tax data into the input so it's saved with the transaction
237
+ */
238
+ "monetization.create.before": async (ctx, input, next) => {
239
+ const orgId = input.data.organizationId;
240
+ if (!orgId) {
241
+ ctx.logger.debug("Tax plugin: No organizationId in input.data, skipping tax calculation");
242
+ return next();
243
+ }
244
+ try {
245
+ const config = await getTaxConfig(orgId);
246
+ if (!config) {
247
+ ctx.logger.debug("Tax plugin: No tax config for org", { orgId });
248
+ return next();
249
+ }
250
+ const category = resolveCategory(
251
+ input.entity,
252
+ input.monetizationType || "subscription",
253
+ categoryMappings
254
+ );
255
+ const transactionFlow = incomeCategories.includes(category) ? "inflow" : "outflow";
256
+ const taxCalc = calculateTax(input.amount, category, config);
257
+ const taxType = getTaxType(transactionFlow, category, config.exemptCategories);
258
+ input.tax = {
259
+ ...taxCalc,
260
+ type: taxType
261
+ };
262
+ ctx.logger.debug("Tax plugin: Tax calculated", {
263
+ orgId,
264
+ category,
265
+ entity: input.entity,
266
+ monetizationType: input.monetizationType,
267
+ taxAmount: taxCalc.taxAmount,
268
+ type: taxType
269
+ });
270
+ } catch (error) {
271
+ ctx.logger.error("Tax plugin: Failed to calculate tax", {
272
+ orgId,
273
+ error: error.message
274
+ });
275
+ }
276
+ return next();
277
+ }
278
+ }
279
+ });
280
+ }
281
+
282
+ // src/infrastructure/plugins/index.ts
283
+ var plugins_default = {
284
+ loggingPlugin,
285
+ auditPlugin,
286
+ metricsPlugin,
287
+ createTaxPlugin
288
+ };
289
+
290
+ export { auditPlugin, createTaxPlugin, plugins_default as default, definePlugin, loggingPlugin, metricsPlugin };
291
+ //# sourceMappingURL=index.js.map
292
+ //# sourceMappingURL=index.js.map