@classytic/revenue 1.1.2 → 1.1.4
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 +8 -7
- package/dist/application/services/index.d.mts +4 -0
- package/dist/application/services/index.mjs +3 -0
- package/dist/base-CsTlVQJe.d.mts +136 -0
- package/dist/base-DCoyIUj6.mjs +152 -0
- package/dist/category-resolver-DV83N8ok.mjs +284 -0
- package/dist/commission-split-BzB8cd39.mjs +485 -0
- package/dist/core/events.d.mts +294 -0
- package/dist/core/events.mjs +100 -0
- package/dist/core/index.d.mts +9 -0
- package/dist/core/index.mjs +8 -0
- package/dist/enums/index.d.mts +157 -0
- package/dist/enums/index.mjs +56 -0
- package/dist/errors-rRdOqnWx.d.mts +787 -0
- package/dist/escrow.enums-CZGrrdg7.mjs +101 -0
- package/dist/{escrow.enums-CE0VQsfe.d.ts → escrow.enums-DwdLuuve.d.mts} +30 -28
- package/dist/idempotency-DaYcUGY1.mjs +172 -0
- package/dist/index-Dsp7H5Wb.d.mts +471 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +38 -0
- package/dist/infrastructure/plugins/{index.d.ts → index.d.mts} +81 -109
- package/dist/infrastructure/plugins/index.mjs +345 -0
- package/dist/money-CvrDOijQ.mjs +271 -0
- package/dist/money-DPG8AtJ8.d.mts +112 -0
- package/dist/{payment.enums-C1BiGlRa.d.ts → payment.enums-HAuAS9Pp.d.mts} +14 -13
- package/dist/payment.enums-tEFVa-Xp.mjs +69 -0
- package/dist/plugin-BbK0OVHy.d.mts +327 -0
- package/dist/plugin-Cd_V04Em.mjs +210 -0
- package/dist/providers/index.d.mts +3 -0
- package/dist/providers/index.mjs +3 -0
- package/dist/reconciliation/{index.d.ts → index.d.mts} +90 -112
- package/dist/reconciliation/index.mjs +192 -0
- package/dist/retry-HHCOXYdn.d.mts +186 -0
- package/dist/revenue-BhdS7nXh.mjs +553 -0
- package/dist/schemas/index.d.mts +2665 -0
- package/dist/schemas/index.mjs +717 -0
- package/dist/schemas/validation.d.mts +375 -0
- package/dist/schemas/validation.mjs +325 -0
- package/dist/{settlement.enums-ByC1x0ye.d.ts → settlement.enums-DFhkqZEY.d.mts} +31 -29
- package/dist/settlement.schema-DnNSFpGd.d.mts +344 -0
- package/dist/settlement.service-DjzAjezU.d.mts +594 -0
- package/dist/settlement.service-DmdKv0Zu.mjs +2511 -0
- package/dist/split.enums-BrjabxIX.mjs +86 -0
- package/dist/split.enums-DmskfLOM.d.mts +43 -0
- package/dist/tax-BoCt5cEd.d.mts +61 -0
- package/dist/tax-EQ15DO81.mjs +162 -0
- package/dist/transaction.enums-pCyMFT4Z.mjs +96 -0
- package/dist/utils/{index.d.ts → index.d.mts} +91 -161
- package/dist/utils/index.mjs +346 -0
- package/package.json +39 -37
- package/dist/application/services/index.d.ts +0 -6
- package/dist/application/services/index.js +0 -3288
- package/dist/application/services/index.js.map +0 -1
- package/dist/core/events.d.ts +0 -455
- package/dist/core/events.js +0 -122
- package/dist/core/events.js.map +0 -1
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.js +0 -4591
- package/dist/core/index.js.map +0 -1
- package/dist/enums/index.d.ts +0 -159
- package/dist/enums/index.js +0 -296
- package/dist/enums/index.js.map +0 -1
- package/dist/index-DxIK0UmZ.d.ts +0 -633
- package/dist/index-EnfKzDbs.d.ts +0 -806
- package/dist/index-cLJBLUvx.d.ts +0 -478
- package/dist/index.d.ts +0 -43
- package/dist/index.js +0 -4864
- package/dist/index.js.map +0 -1
- package/dist/infrastructure/plugins/index.js +0 -292
- package/dist/infrastructure/plugins/index.js.map +0 -1
- package/dist/money-widWVD7r.d.ts +0 -111
- package/dist/plugin-Bb9HOE10.d.ts +0 -336
- package/dist/providers/index.d.ts +0 -145
- package/dist/providers/index.js +0 -141
- package/dist/providers/index.js.map +0 -1
- package/dist/reconciliation/index.js +0 -140
- package/dist/reconciliation/index.js.map +0 -1
- package/dist/retry-D4hFUwVk.d.ts +0 -194
- package/dist/schemas/index.d.ts +0 -2655
- package/dist/schemas/index.js +0 -841
- package/dist/schemas/index.js.map +0 -1
- package/dist/schemas/validation.d.ts +0 -384
- package/dist/schemas/validation.js +0 -303
- package/dist/schemas/validation.js.map +0 -1
- package/dist/settlement.schema-CpamV7ZY.d.ts +0 -343
- package/dist/split.enums-DG3TxQf9.d.ts +0 -42
- package/dist/tax-CV8A0sxl.d.ts +0 -60
- package/dist/utils/index.js +0 -1202
- package/dist/utils/index.js.map +0 -1
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { createEventBus } from "./core/events.mjs";
|
|
2
|
+
import { t as PluginManager } from "./plugin-Cd_V04Em.mjs";
|
|
3
|
+
import { c as retry, s as createCircuitBreaker, y as tryCatch } from "./commission-split-BzB8cd39.mjs";
|
|
4
|
+
import { n as createIdempotencyManager } from "./idempotency-DaYcUGY1.mjs";
|
|
5
|
+
import { r as ConfigurationError } from "./category-resolver-DV83N8ok.mjs";
|
|
6
|
+
import { a as MonetizationService, g as resolveConfig, i as PaymentService, n as EscrowService, r as TransactionService, t as SettlementService } from "./settlement.service-DmdKv0Zu.mjs";
|
|
7
|
+
import { nanoid } from "nanoid";
|
|
8
|
+
|
|
9
|
+
//#region src/core/container.ts
|
|
10
|
+
var Container = class Container {
|
|
11
|
+
_services;
|
|
12
|
+
_singletons;
|
|
13
|
+
constructor() {
|
|
14
|
+
this._services = /* @__PURE__ */ new Map();
|
|
15
|
+
this._singletons = /* @__PURE__ */ new Map();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Register a service
|
|
19
|
+
* @param name - Service name
|
|
20
|
+
* @param implementation - Service implementation or factory
|
|
21
|
+
* @param options - Registration options
|
|
22
|
+
*/
|
|
23
|
+
register(name, implementation, options = {}) {
|
|
24
|
+
this._services.set(name, {
|
|
25
|
+
implementation,
|
|
26
|
+
singleton: options.singleton !== false,
|
|
27
|
+
factory: options.factory ?? false
|
|
28
|
+
});
|
|
29
|
+
return this;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Register a singleton service
|
|
33
|
+
* @param name - Service name
|
|
34
|
+
* @param implementation - Service implementation
|
|
35
|
+
*/
|
|
36
|
+
singleton(name, implementation) {
|
|
37
|
+
return this.register(name, implementation, { singleton: true });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Register a transient service (new instance each time)
|
|
41
|
+
* @param name - Service name
|
|
42
|
+
* @param factory - Factory function
|
|
43
|
+
*/
|
|
44
|
+
transient(name, factory) {
|
|
45
|
+
return this.register(name, factory, {
|
|
46
|
+
singleton: false,
|
|
47
|
+
factory: true
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get a service from the container
|
|
52
|
+
* @param name - Service name
|
|
53
|
+
* @returns Service instance
|
|
54
|
+
*/
|
|
55
|
+
get(name) {
|
|
56
|
+
if (this._singletons.has(name)) return this._singletons.get(name);
|
|
57
|
+
const service = this._services.get(name);
|
|
58
|
+
if (!service) throw new Error(`Service "${name}" not registered in container`);
|
|
59
|
+
if (service.factory) {
|
|
60
|
+
const factory = service.implementation;
|
|
61
|
+
const instance = factory(this);
|
|
62
|
+
if (service.singleton) this._singletons.set(name, instance);
|
|
63
|
+
return instance;
|
|
64
|
+
}
|
|
65
|
+
const instance = service.implementation;
|
|
66
|
+
if (service.singleton) this._singletons.set(name, instance);
|
|
67
|
+
return instance;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if service is registered
|
|
71
|
+
* @param name - Service name
|
|
72
|
+
*/
|
|
73
|
+
has(name) {
|
|
74
|
+
return this._services.has(name);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get all registered service names
|
|
78
|
+
*/
|
|
79
|
+
keys() {
|
|
80
|
+
return Array.from(this._services.keys());
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Clear all services (useful for testing)
|
|
84
|
+
*/
|
|
85
|
+
clear() {
|
|
86
|
+
this._services.clear();
|
|
87
|
+
this._singletons.clear();
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Create a child container (for scoped dependencies)
|
|
91
|
+
*/
|
|
92
|
+
createScope() {
|
|
93
|
+
const scope = new Container();
|
|
94
|
+
this._services.forEach((value, key) => {
|
|
95
|
+
scope._services.set(key, value);
|
|
96
|
+
});
|
|
97
|
+
return scope;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/core/revenue.ts
|
|
103
|
+
/**
|
|
104
|
+
* Revenue - Modern Payment Management
|
|
105
|
+
* @classytic/revenue
|
|
106
|
+
*
|
|
107
|
+
* Fluent Builder API with integrated services
|
|
108
|
+
* Less code, more power
|
|
109
|
+
*
|
|
110
|
+
* Inspired by: Vercel AI SDK, Stripe SDK, tRPC
|
|
111
|
+
*/
|
|
112
|
+
/**
|
|
113
|
+
* Revenue - Main entry point
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const revenue = Revenue
|
|
118
|
+
* .create({ defaultCurrency: 'USD' })
|
|
119
|
+
* .withModels({ Transaction, Subscription })
|
|
120
|
+
* .withProvider('stripe', new StripeProvider({ apiKey: '...' }))
|
|
121
|
+
* .withProvider('manual', new ManualProvider())
|
|
122
|
+
* .withPlugin(auditPlugin())
|
|
123
|
+
* .build();
|
|
124
|
+
*
|
|
125
|
+
* // Access services directly
|
|
126
|
+
* await revenue.monetization.create({ ... });
|
|
127
|
+
* await revenue.payments.verify({ ... });
|
|
128
|
+
*
|
|
129
|
+
* // Or use events
|
|
130
|
+
* revenue.on('payment.verified', (event) => { ... });
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
var Revenue = class Revenue {
|
|
134
|
+
_container;
|
|
135
|
+
_events;
|
|
136
|
+
_plugins;
|
|
137
|
+
_idempotency;
|
|
138
|
+
_circuitBreaker;
|
|
139
|
+
_options;
|
|
140
|
+
_logger;
|
|
141
|
+
_providers;
|
|
142
|
+
_config;
|
|
143
|
+
/** Monetization service - purchases, subscriptions, free items */
|
|
144
|
+
monetization;
|
|
145
|
+
/** Payment service - verify, refund, webhooks */
|
|
146
|
+
payments;
|
|
147
|
+
/** Transaction service - query, update transactions */
|
|
148
|
+
transactions;
|
|
149
|
+
/** Escrow service - hold, release, splits */
|
|
150
|
+
escrow;
|
|
151
|
+
/** Settlement service - payout tracking */
|
|
152
|
+
settlement;
|
|
153
|
+
constructor(container, events, plugins, options, providers, config) {
|
|
154
|
+
this._container = container;
|
|
155
|
+
this._events = events;
|
|
156
|
+
this._plugins = plugins;
|
|
157
|
+
this._options = options;
|
|
158
|
+
this._logger = options.logger;
|
|
159
|
+
this._providers = providers;
|
|
160
|
+
this._config = config;
|
|
161
|
+
this._idempotency = createIdempotencyManager({ ttl: options.idempotencyTtl });
|
|
162
|
+
if (options.circuitBreaker) this._circuitBreaker = createCircuitBreaker(typeof options.circuitBreaker === "boolean" ? {} : options.circuitBreaker);
|
|
163
|
+
container.singleton("events", events);
|
|
164
|
+
container.singleton("plugins", plugins);
|
|
165
|
+
container.singleton("idempotency", this._idempotency);
|
|
166
|
+
container.singleton("logger", this._logger);
|
|
167
|
+
container.singleton("retryConfig", options.retry || {});
|
|
168
|
+
container.singleton("circuitBreaker", this._circuitBreaker || null);
|
|
169
|
+
this.monetization = new MonetizationService(container);
|
|
170
|
+
this.payments = new PaymentService(container);
|
|
171
|
+
this.transactions = new TransactionService(container);
|
|
172
|
+
this.escrow = new EscrowService(container);
|
|
173
|
+
this.settlement = new SettlementService(container);
|
|
174
|
+
Object.freeze(this._providers);
|
|
175
|
+
Object.freeze(this._config);
|
|
176
|
+
}
|
|
177
|
+
/** @internal Used by RevenueBuilder — do not call directly */
|
|
178
|
+
static _fromBuilder(container, events, plugins, options, providers, config) {
|
|
179
|
+
return new Revenue(container, events, plugins, options, providers, config);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Create a new Revenue builder
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```typescript
|
|
186
|
+
* const revenue = Revenue
|
|
187
|
+
* .create({ defaultCurrency: 'BDT' })
|
|
188
|
+
* .withModels({ Transaction, Subscription })
|
|
189
|
+
* .withProvider('manual', new ManualProvider())
|
|
190
|
+
* .build();
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
static create(options = {}) {
|
|
194
|
+
return new RevenueBuilder(options);
|
|
195
|
+
}
|
|
196
|
+
/** DI container (for advanced usage) */
|
|
197
|
+
get container() {
|
|
198
|
+
return this._container;
|
|
199
|
+
}
|
|
200
|
+
/** Event bus */
|
|
201
|
+
get events() {
|
|
202
|
+
return this._events;
|
|
203
|
+
}
|
|
204
|
+
/** Registered providers (frozen) */
|
|
205
|
+
get providers() {
|
|
206
|
+
return this._providers;
|
|
207
|
+
}
|
|
208
|
+
/** Configuration (frozen) */
|
|
209
|
+
get config() {
|
|
210
|
+
return this._config;
|
|
211
|
+
}
|
|
212
|
+
/** Default currency */
|
|
213
|
+
get defaultCurrency() {
|
|
214
|
+
return this._options.defaultCurrency;
|
|
215
|
+
}
|
|
216
|
+
/** Current environment */
|
|
217
|
+
get environment() {
|
|
218
|
+
return this._options.environment;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Get a provider by name
|
|
222
|
+
*/
|
|
223
|
+
getProvider(name) {
|
|
224
|
+
const provider = this._providers[name];
|
|
225
|
+
if (!provider) throw new ConfigurationError(`Provider "${name}" not found. Available: ${Object.keys(this._providers).join(", ")}`);
|
|
226
|
+
return provider;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get all provider names
|
|
230
|
+
*/
|
|
231
|
+
getProviderNames() {
|
|
232
|
+
return Object.keys(this._providers);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Check if provider exists
|
|
236
|
+
*/
|
|
237
|
+
hasProvider(name) {
|
|
238
|
+
return name in this._providers;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Subscribe to events
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* ```typescript
|
|
245
|
+
* revenue.on('payment.verified', (event) => {
|
|
246
|
+
* console.log('Payment:', event.transaction._id);
|
|
247
|
+
* });
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
on = (event, handler) => {
|
|
251
|
+
return this._events.on(event, handler);
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Subscribe once
|
|
255
|
+
*/
|
|
256
|
+
once = (event, handler) => {
|
|
257
|
+
return this._events.once(event, handler);
|
|
258
|
+
};
|
|
259
|
+
/**
|
|
260
|
+
* Unsubscribe
|
|
261
|
+
*/
|
|
262
|
+
off = (event, handler) => {
|
|
263
|
+
this._events.off(event, handler);
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* Emit an event
|
|
267
|
+
*/
|
|
268
|
+
emit = (event, payload) => {
|
|
269
|
+
this._events.emit(event, payload);
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* Execute operation with retry and idempotency
|
|
273
|
+
*/
|
|
274
|
+
async execute(operation, options = {}) {
|
|
275
|
+
const { idempotencyKey, params, useRetry = true, useCircuitBreaker = true } = options;
|
|
276
|
+
const idempotentOp = async () => {
|
|
277
|
+
if (idempotencyKey) {
|
|
278
|
+
const result = await this._idempotency.execute(idempotencyKey, params, operation);
|
|
279
|
+
if (!result.ok) throw result.error;
|
|
280
|
+
return result.value;
|
|
281
|
+
}
|
|
282
|
+
return operation();
|
|
283
|
+
};
|
|
284
|
+
const resilientOp = async () => {
|
|
285
|
+
if (useCircuitBreaker && this._circuitBreaker) return this._circuitBreaker.execute(idempotentOp);
|
|
286
|
+
return idempotentOp();
|
|
287
|
+
};
|
|
288
|
+
if (useRetry && this._options.retry) return tryCatch(() => retry(resilientOp, this._options.retry));
|
|
289
|
+
return tryCatch(resilientOp);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Create plugin context (for advanced usage)
|
|
293
|
+
*/
|
|
294
|
+
createContext(meta = {}) {
|
|
295
|
+
return {
|
|
296
|
+
events: this._events,
|
|
297
|
+
logger: this._logger,
|
|
298
|
+
storage: /* @__PURE__ */ new Map(),
|
|
299
|
+
meta: {
|
|
300
|
+
...meta,
|
|
301
|
+
requestId: nanoid(12),
|
|
302
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Destroy instance and cleanup
|
|
308
|
+
*/
|
|
309
|
+
async destroy() {
|
|
310
|
+
await this._plugins.destroy();
|
|
311
|
+
this._events.clear();
|
|
312
|
+
this._idempotency.destroy();
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
/**
|
|
316
|
+
* Revenue Builder - Fluent configuration API
|
|
317
|
+
*/
|
|
318
|
+
var RevenueBuilder = class {
|
|
319
|
+
options;
|
|
320
|
+
models = null;
|
|
321
|
+
providers = {};
|
|
322
|
+
plugins = [];
|
|
323
|
+
categoryMappings = {};
|
|
324
|
+
transactionTypeMapping = {};
|
|
325
|
+
constructor(options = {}) {
|
|
326
|
+
this.options = options;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Register models (required)
|
|
330
|
+
*
|
|
331
|
+
* @example
|
|
332
|
+
* ```typescript
|
|
333
|
+
* .withModels({
|
|
334
|
+
* Transaction: TransactionModel,
|
|
335
|
+
* Subscription: SubscriptionModel,
|
|
336
|
+
* })
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
withModels(models) {
|
|
340
|
+
this.models = models;
|
|
341
|
+
return this;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Register a single model
|
|
345
|
+
*/
|
|
346
|
+
withModel(name, model) {
|
|
347
|
+
if (!this.models) this.models = {};
|
|
348
|
+
this.models[name] = model;
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Register a payment provider
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```typescript
|
|
356
|
+
* .withProvider('stripe', new StripeProvider({ apiKey: '...' }))
|
|
357
|
+
* .withProvider('manual', new ManualProvider())
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
withProvider(name, provider) {
|
|
361
|
+
this.providers[name] = provider;
|
|
362
|
+
return this;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Register multiple providers at once
|
|
366
|
+
*/
|
|
367
|
+
withProviders(providers) {
|
|
368
|
+
this.providers = {
|
|
369
|
+
...this.providers,
|
|
370
|
+
...providers
|
|
371
|
+
};
|
|
372
|
+
return this;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Register a plugin
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* ```typescript
|
|
379
|
+
* .withPlugin(loggingPlugin())
|
|
380
|
+
* .withPlugin(auditPlugin({ store: saveToDb }))
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
withPlugin(plugin) {
|
|
384
|
+
this.plugins.push(plugin);
|
|
385
|
+
return this;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Register multiple plugins
|
|
389
|
+
*/
|
|
390
|
+
withPlugins(plugins) {
|
|
391
|
+
this.plugins.push(...plugins);
|
|
392
|
+
return this;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Set retry configuration
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```typescript
|
|
399
|
+
* .withRetry({ maxAttempts: 5, baseDelay: 2000 })
|
|
400
|
+
* ```
|
|
401
|
+
*/
|
|
402
|
+
withRetry(config) {
|
|
403
|
+
this.options.retry = config;
|
|
404
|
+
return this;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Enable circuit breaker
|
|
408
|
+
*/
|
|
409
|
+
withCircuitBreaker(enabled = true) {
|
|
410
|
+
this.options.circuitBreaker = enabled;
|
|
411
|
+
return this;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Set custom logger
|
|
415
|
+
*/
|
|
416
|
+
withLogger(logger) {
|
|
417
|
+
this.options.logger = logger;
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Set environment
|
|
422
|
+
*/
|
|
423
|
+
forEnvironment(env) {
|
|
424
|
+
this.options.environment = env;
|
|
425
|
+
return this;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Enable debug mode
|
|
429
|
+
*/
|
|
430
|
+
withDebug(enabled = true) {
|
|
431
|
+
this.options.debug = enabled;
|
|
432
|
+
return this;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Set commission rate as decimal (0-1, e.g., 0.10 for 10%)
|
|
436
|
+
*
|
|
437
|
+
* @param rate - Commission rate (0-1 decimal format)
|
|
438
|
+
* @param gatewayFeeRate - Gateway fee rate (0-1 decimal format, e.g., 0.029 for 2.9%)
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```typescript
|
|
442
|
+
* .withCommission(0.10, 0.029) // 10% commission + 2.9% gateway fee
|
|
443
|
+
* ```
|
|
444
|
+
*/
|
|
445
|
+
withCommission(rate, gatewayFeeRate = 0) {
|
|
446
|
+
this.options.commissionRate = rate;
|
|
447
|
+
this.options.gatewayFeeRate = gatewayFeeRate;
|
|
448
|
+
return this;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Set category mappings (entity → category)
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* ```typescript
|
|
455
|
+
* .withCategoryMappings({
|
|
456
|
+
* PlatformSubscription: 'platform_subscription',
|
|
457
|
+
* CourseEnrollment: 'course_enrollment',
|
|
458
|
+
* ProductOrder: 'product_order',
|
|
459
|
+
* })
|
|
460
|
+
* ```
|
|
461
|
+
*/
|
|
462
|
+
withCategoryMappings(mappings) {
|
|
463
|
+
this.categoryMappings = {
|
|
464
|
+
...this.categoryMappings,
|
|
465
|
+
...mappings
|
|
466
|
+
};
|
|
467
|
+
return this;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Set transaction flow mapping by category or monetization type
|
|
471
|
+
*
|
|
472
|
+
* @example
|
|
473
|
+
* ```typescript
|
|
474
|
+
* .withTransactionTypeMapping({
|
|
475
|
+
* platform_subscription: 'inflow',
|
|
476
|
+
* subscription: 'inflow',
|
|
477
|
+
* refund: 'outflow',
|
|
478
|
+
* })
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
withTransactionTypeMapping(mapping) {
|
|
482
|
+
this.transactionTypeMapping = {
|
|
483
|
+
...this.transactionTypeMapping,
|
|
484
|
+
...mapping
|
|
485
|
+
};
|
|
486
|
+
return this;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Build the Revenue instance
|
|
490
|
+
*/
|
|
491
|
+
build() {
|
|
492
|
+
if (!this.models) throw new ConfigurationError("Models are required. Use .withModels({ Transaction, Subscription })");
|
|
493
|
+
if (!this.models.Transaction) throw new ConfigurationError("Transaction model is required in models configuration");
|
|
494
|
+
if (Object.keys(this.providers).length === 0) throw new ConfigurationError("At least one provider is required. Use .withProvider(name, provider)");
|
|
495
|
+
const container = new Container();
|
|
496
|
+
const resolvedOptions = {
|
|
497
|
+
defaultCurrency: this.options.defaultCurrency ?? "USD",
|
|
498
|
+
environment: this.options.environment ?? "development",
|
|
499
|
+
debug: this.options.debug ?? false,
|
|
500
|
+
retry: this.options.retry ?? { maxAttempts: 3 },
|
|
501
|
+
idempotencyTtl: this.options.idempotencyTtl ?? 1440 * 60 * 1e3,
|
|
502
|
+
circuitBreaker: this.options.circuitBreaker ?? false,
|
|
503
|
+
logger: this.options.logger ?? {
|
|
504
|
+
debug: (msg, data) => this.options.debug && console.debug(`[Revenue] ${msg}`, data ?? ""),
|
|
505
|
+
info: (msg, data) => console.info(`[Revenue] ${msg}`, data ?? ""),
|
|
506
|
+
warn: (msg, data) => console.warn(`[Revenue] ${msg}`, data ?? ""),
|
|
507
|
+
error: (msg, data) => console.error(`[Revenue] ${msg}`, data ?? "")
|
|
508
|
+
},
|
|
509
|
+
commissionRate: this.options.commissionRate ?? 0,
|
|
510
|
+
gatewayFeeRate: this.options.gatewayFeeRate ?? 0
|
|
511
|
+
};
|
|
512
|
+
const config = {
|
|
513
|
+
...resolveConfig(resolvedOptions),
|
|
514
|
+
targetModels: [],
|
|
515
|
+
categoryMappings: this.categoryMappings,
|
|
516
|
+
transactionTypeMapping: this.transactionTypeMapping
|
|
517
|
+
};
|
|
518
|
+
for (const provider of Object.values(this.providers)) if (typeof provider.setDefaultCurrency === "function") provider.setDefaultCurrency(resolvedOptions.defaultCurrency);
|
|
519
|
+
container.singleton("models", this.models);
|
|
520
|
+
container.singleton("providers", this.providers);
|
|
521
|
+
container.singleton("config", config);
|
|
522
|
+
const events = createEventBus();
|
|
523
|
+
const pluginManager = new PluginManager();
|
|
524
|
+
for (const plugin of this.plugins) pluginManager.register(plugin);
|
|
525
|
+
const revenue = Revenue._fromBuilder(container, events, pluginManager, resolvedOptions, this.providers, config);
|
|
526
|
+
const ctx = revenue.createContext();
|
|
527
|
+
pluginManager.init(ctx).catch((err) => {
|
|
528
|
+
resolvedOptions.logger.error("Failed to initialize plugins", err);
|
|
529
|
+
});
|
|
530
|
+
return revenue;
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
/**
|
|
534
|
+
* Create Revenue instance (shorthand)
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```typescript
|
|
538
|
+
* const revenue = createRevenue({
|
|
539
|
+
* models: { Transaction, Subscription },
|
|
540
|
+
* providers: { manual: new ManualProvider() },
|
|
541
|
+
* });
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
function createRevenue(config) {
|
|
545
|
+
let builder = Revenue.create(config.options);
|
|
546
|
+
builder = builder.withModels(config.models);
|
|
547
|
+
builder = builder.withProviders(config.providers);
|
|
548
|
+
if (config.plugins) builder = builder.withPlugins(config.plugins);
|
|
549
|
+
return builder.build();
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
//#endregion
|
|
553
|
+
export { Container as i, RevenueBuilder as n, createRevenue as r, Revenue as t };
|